From 306b9ad30bd9f6b5919c05ece909ced9749beae8 Mon Sep 17 00:00:00 2001 From: joan Date: Sat, 19 Apr 2014 12:19:29 +0100 Subject: [PATCH] V14 --- README | 11 +- command.c | 949 ++++++++++++++++++++++---------------- command.h | 49 +- pigpio.c | 1191 +++++++++++++++++++++++++----------------------- pigpio.h | 409 +++++++++++------ pigpio.py | 322 ++++++++----- pigpiod.c | 12 +- pigpiod_if.c | 35 +- pigpiod_if.h | 164 ++++--- pigs.c | 107 +++-- setup.py | 2 +- tarball | 29 ++ x_pigpio.c | 29 +- x_pigpio.py | 73 ++- x_pigpiod_if.c | 29 +- x_pigs | 22 +- x_pipe | 16 +- 17 files changed, 2069 insertions(+), 1380 deletions(-) create mode 100755 tarball diff --git a/README b/README index d04da3c..a9993b5 100644 --- a/README +++ b/README @@ -22,11 +22,18 @@ o the Python module pigpio.py TEST (optional) +*** WARNING ************************************************ +* * +* All the tests make extensive use of gpio 4 (pin P1-7). * +* Ensure that either nothing or just a LED is connected to * +* gpio 4 before running any of the tests. * +************************************************************ + To test the library do sudo ./x_pigpio -To text the pigpio daemon do +To test the pigpio daemon do sudo pigpiod @@ -41,7 +48,7 @@ x_pigpio.c, pig2vcd.c, and pigpiod.c show examples of interfacing with the pigpio library. pigs.c, pigpio.py, x_pigpiod_if.c, x_pigpio.py, x_pigs, and x_pipe -show examples of interfacing with the pigpiod daemon. +show examples of interfacing with the pigpio daemon. DAEMON diff --git a/command.c b/command.c index 9bf8f9b..683b587 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 13+ +This version is for pigpio version 14+ */ #include @@ -38,170 +38,137 @@ This version is for pigpio version 13+ #include "pigpio.h" #include "command.h" -/* retv - pigs pipe -0 "" <0 ERR %d -1 "" <0 ERR %d -2 %d <0 ERR %d -3 %08X %08X -4 %u %u -5 HELP HELP -6 %s <0 ERR -*/ - -/* vfyt - 1 cmd - 2 cmd %d - 3 cmd %d %d - 4 cmd %d %x - 6 HELP - 7 cmd %x - 8 MODES %d %c - 9 PUD %d %c -10 PROC %s -11 WVAS %d %d %d %s -12 PROCR %d [%d]*10 -13 WVAG %d %d %d [%d %d %d]*160 - - -20 cmd m(0-150) -21 cmd v -22 cmd L -23 cmd -24 cmd m1(0-150) m2(0-150) -25 cmd p(0-9) -*/ - cmdInfo_t cmdInfo[]= { /* num str vfyt retv */ - {PI_CMD_BC1, "BC1", 7, 1}, - {PI_CMD_BC2, "BC2", 7, 1}, - {PI_CMD_BR1, "BR1", 1, 3}, - {PI_CMD_BR2, "BR2", 1, 3}, - {PI_CMD_BS1, "BS1", 7, 1}, - {PI_CMD_BS2, "BS2", 7, 1}, - {PI_CMD_HELP, "H", 6, 5}, - {PI_CMD_HELP, "HELP", 6, 5}, - {PI_CMD_HWVER, "HWVER", 1, 4}, - {PI_CMD_MICRO, "MICRO", 21, 0}, - {PI_CMD_MILLI, "MILLI", 21, 0}, - {PI_CMD_MODEG, "MG" , 2, 2}, - {PI_CMD_MODEG, "MODEG", 2, 2}, - {PI_CMD_MODES, "M", 8, 0}, - {PI_CMD_MODES, "MODES", 8, 0}, - {PI_CMD_NB, "NB", 4, 0}, - {PI_CMD_NC, "NC", 2, 0}, - {PI_CMD_NO, "NO", 1, 2}, - {PI_CMD_NP, "NP", 2, 0}, - {PI_CMD_PFG, "PFG", 2, 2}, - {PI_CMD_PFS, "PFS", 3, 2}, - {PI_CMD_PIGPV, "PIGPV", 1, 4}, - {PI_CMD_PRG, "PRG", 2, 2}, - {PI_CMD_PROC, "PROC", 10, 2}, - {PI_CMD_PROCD, "PROCD", 2, 2}, - {PI_CMD_PROCP, "PROCP", 2, 7}, - {PI_CMD_PROCR, "PROCR",12, 2}, - {PI_CMD_PROCS, "PROCS", 2, 2}, - {PI_CMD_PRRG, "PRRG", 2, 2}, - {PI_CMD_PRS, "PRS", 3, 2}, - {PI_CMD_PUD, "PUD", 9, 0}, - {PI_CMD_PWM, "P", 3, 0}, - {PI_CMD_PWM, "PWM", 3, 0}, - {PI_CMD_READ, "R", 2, 2}, - {PI_CMD_READ, "READ", 2, 2}, - {PI_CMD_SERVO, "S", 3, 0}, - {PI_CMD_SERVO, "SERVO", 3, 0}, - {PI_CMD_SLR, "SLR", 3, 6}, - {PI_CMD_SLRC, "SLRC", 2, 2}, - {PI_CMD_SLRO, "SLRO", 3, 2}, - {PI_CMD_TICK, "T", 1, 4}, - {PI_CMD_TICK, "TICK", 1, 4}, - {PI_CMD_TRIG, "TRIG", 5, 0}, - {PI_CMD_WDOG, "WDOG", 3, 0}, - {PI_CMD_WRITE, "W", 3, 0}, - {PI_CMD_WRITE, "WRITE", 3, 0}, - {PI_CMD_WVAG, "WVAG", 13, 2}, - {PI_CMD_WVAS, "WVAS", 11, 2}, - {PI_CMD_WVBSY, "WVBSY", 1, 2}, - {PI_CMD_WVCLR, "WVCLR", 1, 2}, - {PI_CMD_WVGO, "WVGO" , 1, 2}, - {PI_CMD_WVGOR, "WVGOR", 1, 2}, - {PI_CMD_WVHLT, "WVHLT", 1, 2}, - {PI_CMD_WVSC, "WVSC", 2, 2}, - {PI_CMD_WVSM, "WVSM", 2, 2}, - {PI_CMD_WVSP, "WVSP", 2, 2}, + {PI_CMD_BC1, "BC1", 111, 1}, + {PI_CMD_BC2, "BC2", 111, 1}, + {PI_CMD_BR1, "BR1", 101, 3}, + {PI_CMD_BR2, "BR2", 101, 3}, + {PI_CMD_BS1, "BS1", 111, 1}, + {PI_CMD_BS2, "BS2", 111, 1}, + {PI_CMD_HELP, "H", 101, 5}, + {PI_CMD_HELP, "HELP", 101, 5}, + {PI_CMD_HWVER, "HWVER", 101, 4}, + {PI_CMD_MICS, "MICS", 112, 0}, + {PI_CMD_MILS, "MILS", 112, 0}, + {PI_CMD_MODEG, "MG" , 112, 2}, + {PI_CMD_MODEG, "MODEG", 112, 2}, + {PI_CMD_MODES, "M", 125, 0}, + {PI_CMD_MODES, "MODES", 125, 0}, + {PI_CMD_NB, "NB", 122, 0}, + {PI_CMD_NC, "NC", 112, 0}, + {PI_CMD_NO, "NO", 101, 2}, + {PI_CMD_NP, "NP", 112, 0}, + {PI_CMD_PARSE, "PARSE", 115, 2}, + {PI_CMD_PFG, "PFG", 112, 2}, + {PI_CMD_PFS, "PFS", 121, 2}, + {PI_CMD_PIGPV, "PIGPV", 101, 4}, + {PI_CMD_PRG, "PRG", 112, 2}, + {PI_CMD_PROC, "PROC", 115, 2}, + {PI_CMD_PROCD, "PROCD", 112, 2}, + {PI_CMD_PROCP, "PROCP", 112, 7}, + {PI_CMD_PROCR, "PROCR", 191, 2}, + {PI_CMD_PROCS, "PROCS", 112, 2}, + {PI_CMD_PRRG, "PRRG", 112, 2}, + {PI_CMD_PRS, "PRS", 121, 2}, + {PI_CMD_PUD, "PUD", 126, 0}, + {PI_CMD_PWM, "P", 121, 0}, + {PI_CMD_PWM, "PWM", 121, 0}, + {PI_CMD_READ, "R", 112, 2}, + {PI_CMD_READ, "READ", 112, 2}, + {PI_CMD_SERVO, "S", 121, 0}, + {PI_CMD_SERVO, "SERVO", 121, 0}, + {PI_CMD_SLR, "SLR", 121, 6}, + {PI_CMD_SLRC, "SLRC", 112, 2}, + {PI_CMD_SLRO, "SLRO", 121, 2}, + {PI_CMD_TICK, "T", 101, 4}, + {PI_CMD_TICK, "TICK", 101, 4}, + {PI_CMD_TRIG, "TRIG", 131, 0}, + {PI_CMD_WDOG, "WDOG", 121, 0}, + {PI_CMD_WRITE, "W", 121, 0}, + {PI_CMD_WRITE, "WRITE", 121, 0}, + {PI_CMD_WVAG, "WVAG", 192, 2}, + {PI_CMD_WVAS, "WVAS", 141, 2}, + {PI_CMD_WVBSY, "WVBSY", 101, 2}, + {PI_CMD_WVCLR, "WVCLR", 101, 2}, + {PI_CMD_WVCRE, "WVCRE", 101, 2}, + {PI_CMD_WVDEL, "WVDEL", 112, 2}, + {PI_CMD_WVGO, "WVGO" , 101, 2}, + {PI_CMD_WVGOR, "WVGOR", 101, 2}, + {PI_CMD_WVHLT, "WVHLT", 101, 2}, + {PI_CMD_WVNEW, "WVNEW", 101, 2}, + {PI_CMD_WVSC, "WVSC", 112, 2}, + {PI_CMD_WVSM, "WVSM", 112, 2}, + {PI_CMD_WVSP, "WVSP", 112, 2}, + {PI_CMD_WVTX, "WVTX", 112, 2}, + {PI_CMD_WVTXR, "WVTXR", 112, 2}, - {PI_CMD_ADDI , "ADDI" , 21, 0}, - {PI_CMD_ADDV , "ADDV" , 20, 0}, - {PI_CMD_ANDI , "ANDI" , 21, 0}, - {PI_CMD_ANDV , "ANDV" , 20, 0}, - {PI_CMD_CALL , "CALL" , 22, 0}, - {PI_CMD_CMPI , "CMPI" , 21, 0}, - {PI_CMD_CMPV , "CMPV" , 20, 0}, - {PI_CMD_DCRA , "DCRA" , 23, 0}, - {PI_CMD_DCRV , "DCRV" , 20, 0}, - {PI_CMD_HALT , "HALT" , 23, 0}, - {PI_CMD_INRA , "INRA" , 23, 0}, - {PI_CMD_INRV , "INRV" , 20, 0}, - {PI_CMD_JM , "JM" , 22, 0}, - {PI_CMD_JMP , "JMP" , 22, 0}, - {PI_CMD_JNZ , "JNZ" , 22, 0}, - {PI_CMD_JP , "JP" , 22, 0}, - {PI_CMD_JZ , "JZ" , 22, 0}, - {PI_CMD_LABEL, "LABEL", 22, 0}, - {PI_CMD_LDAI , "LDAI" , 21, 0}, - {PI_CMD_LDAP , "LDAP" , 25, 0}, - {PI_CMD_LDAV , "LDAV" , 20, 0}, - {PI_CMD_LDPA , "LDPA" , 25, 0}, - {PI_CMD_LDVA , "LDVA" , 20, 0}, - {PI_CMD_LDVI , "LDVI" , 28, 0}, - {PI_CMD_LDVV , "LDVV" , 24, 0}, - {PI_CMD_ORI , "ORI" , 21, 0}, - {PI_CMD_ORV , "ORV" , 20, 0}, - {PI_CMD_POPA , "POPA" , 23, 0}, - {PI_CMD_POPV , "POPV" , 20, 0}, - {PI_CMD_PUSHA, "PUSHA", 23, 0}, - {PI_CMD_PUSHV, "PUSHV", 20, 0}, - {PI_CMD_RET , "RET" , 23, 0}, - {PI_CMD_RAL , "RAL" , 21, 0}, - {PI_CMD_RAR , "RAR" , 21, 0}, - {PI_CMD_SUBI , "SUBI" , 21, 0}, - {PI_CMD_SUBV , "SUBV" , 20, 0}, - {PI_CMD_SWAPA, "SWAPA", 20, 0}, - {PI_CMD_SWAPV, "SWAPV", 24, 0}, - {PI_CMD_SYS , "SYS" , 27, 0}, - {PI_CMD_WAITI, "WAITI", 21, 0}, - {PI_CMD_WAITV, "WAITV", 20, 0}, - {PI_CMD_XORI , "XORI" , 21, 0}, - {PI_CMD_XORV , "XORV" , 20, 0}, + {PI_CMD_ADD , "ADD" , 111, 0}, + {PI_CMD_AND , "AND" , 111, 0}, + {PI_CMD_CALL , "CALL" , 114, 0}, + {PI_CMD_CMP , "CMP" , 111, 0}, + {PI_CMD_DCR , "DCR" , 113, 0}, + {PI_CMD_DCRA , "DCRA" , 101, 0}, + {PI_CMD_DIV , "DIV" , 111, 0}, + {PI_CMD_HALT , "HALT" , 101, 0}, + {PI_CMD_INR , "INR" , 113, 0}, + {PI_CMD_INRA , "INRA" , 101, 0}, + {PI_CMD_JM , "JM" , 114, 0}, + {PI_CMD_JMP , "JMP" , 114, 0}, + {PI_CMD_JNZ , "JNZ" , 114, 0}, + {PI_CMD_JP , "JP" , 114, 0}, + {PI_CMD_JZ , "JZ" , 114, 0}, + {PI_CMD_LD , "LD" , 123, 0}, + {PI_CMD_LDA , "LDA" , 111, 0}, + {PI_CMD_MLT , "MLT" , 111, 0}, + {PI_CMD_MOD , "MOD" , 111, 0}, + {PI_CMD_OR , "OR" , 111, 0}, + {PI_CMD_POP , "POP" , 113, 0}, + {PI_CMD_POPA , "POPA" , 101, 0}, + {PI_CMD_PUSH , "PUSH" , 113, 0}, + {PI_CMD_PUSHA, "PUSHA", 101, 0}, + {PI_CMD_RET , "RET" , 101, 0}, + {PI_CMD_RL , "RL" , 123, 0}, + {PI_CMD_RLA , "RLA" , 111, 0}, + {PI_CMD_RR , "RR" , 123, 0}, + {PI_CMD_RRA , "RRA" , 111, 0}, + {PI_CMD_STA , "STA" , 113, 0}, + {PI_CMD_SUB , "SUB" , 111, 0}, + {PI_CMD_SYS , "SYS" , 116, 0}, + {PI_CMD_TAG , "TAG" , 114, 0}, + {PI_CMD_WAIT , "WAIT" , 111, 0}, + {PI_CMD_X , "X" , 124, 0}, + {PI_CMD_XA , "XA" , 113, 0}, + {PI_CMD_XOR , "XOR" , 111, 0}, }; char * cmdUsage = "\ -BC1 v Clear gpios defined by mask v in bank 1.\n\ -BC2 v Clear gpios defined by mask v in bank 2.\n\ +BC1 v Clear gpios specified by mask v in bank 1.\n\ +BC2 v Clear gpios specified by mask v in bank 2.\n\ BR1 Read gpios bank 1.\n\ BR2 Read gpios bank 2.\n\ -BS1 v Set gpios defined by mask v in bank 1.\n\ -BS2 v Set gpios defined by mask v in bank 2.\n\ +BS1 v Set gpios specified by mask v in bank 1.\n\ +BS2 v Set gpios specified by mask v in bank 2.\n\ H Displays command help.\n\ HELP Displays command help.\n\ HWVER Return hardware version.\n\ M g m Set gpio g to mode m.\n\ MG g Get gpio g mode.\n\ -MICRO v Delay for v microseconds.\n\ -MILLI v Delay for v milliseconds.\n\ +MICS v Delay for v microseconds.\n\ +MILS v Delay for v milliseconds.\n\ MODEG g Get gpio g mode.\n\ MODES g m Set gpio g to mode m.\n\ -NB h v Start notifications on handle h for gpios defined by mask v.\n\ +NB h v Start notifications on handle h for gpios specified by mask v.\n\ NC h Close notification handle h.\n\ NO Request notification handle.\n\ NP h Pause notifications on handle h.\n\ -P u v Set PWM value for user gpio u to d.\n\ +P u v Set PWM value for user gpio u to v.\n\ +PARSE t Validate script text t without storing.\n\ PFG u Get PWM frequency for user gpio u.\n\ -PFS u v Set PWM frequency for user gpio u to d.\n\ +PFS u v Set PWM frequency for user gpio u to v.\n\ PIGPV Return pigpio version.\n\ PRG u Get PWM range for user gpio u.\n\ PROC t Store text t of script.\n\ @@ -210,13 +177,13 @@ PROCP s Get current status and parameter values for script s.\n\ PROCR s pars Run script s with up to 10 optional parameters.\n\ PROCS s Stop script s.\n\ PRRG u Get PWM real range for user gpio u.\n\ -PRS u v Set PWM range for user gpio u to d.\n\ +PRS u v Set PWM range for user gpio u to v.\n\ PUD g p Set gpio pull up/down for gpio g to p.\n\ -PWM u v Set PWM value for user gpio u to d.\n\ +PWM u v Set PWM value for user gpio u to v.\n\ R g Read gpio g.\n\ READ g Read gpio g.\n\ -S u v Set servo value for user gpio u to d microseconds.\n\ -SERVO u v Set servo value for user gpio u to d microseconds.\n\ +S u v Set servo value for user gpio u to v microseconds.\n\ +SERVO u v Set servo value for user gpio u to v microseconds.\n\ SLR u v Read up to d bytes of serial data from user gpio u.\n\ SLRC u Close user gpio u for serial data.\n\ SLRO u b Open user gpio u for serial data at b baud.\n\ @@ -224,34 +191,40 @@ T Return current tick.\n\ TICK Return current tick.\n\ TRIG u pl L Trigger level L for pl micros on user gpio u.\n\ W g L Write level L to gpio g.\n\ -WDOG u v Set watchdog of d milliseconds on user gpio u.\n\ +WDOG u v Set watchdog of v milliseconds on user gpio u.\n\ WRITE g L Write level L to gpio g.\n\ WVAG pulses Wave add generic pulses.\n\ WVAS u b o t Wave add serial data t to user gpio u at b baud.\n\ WVBSY Check if wave busy.\n\ WVCLR Wave clear.\n\ -WVGO Wave transmit.\n\ -WVGOR Wave transmit repeatedly.\n\ +WVCRE Create wave from added pulses.\n\ +WVDEL w Delete waves w and higher.\n\ +WVGO Wave transmit (DEPRECATED).\n\ +WVGOR Wave transmit repeatedly (DEPRECATED).\n\ WVHLT Wave stop.\n\ +WVNEW Start a new empty wave.\n\ WVSC ws Wave get DMA control block stats.\n\ WVSM ws Wave get micros stats.\n\ WVSP ws Wave get pulses stats.\n\ +WVTX w Transmit wave w as one-shot.\n\ +WVTXR w Transmit wave w repeatedly.\n\ \n\ b = baud rate.\n\ g = any gpio (0-53).\n\ -h = handle (0-31).\n\ +h = handle (>=0).\n\ L = level (0-1).\n\ m = mode (RW540123).\n\ mask = a bit mask where (1<=0).\n\ p = pud (ODU).\n\ pars = 0 to 10 parameters for script.\n\ -pl = pulse length (0-100).\n\ +pl = pulse length (1-50).\n\ pulses = 1 or more triplets of gpios on, gpios off, delay.\n\ -s = script id (0-31).\n\ +s = script id (>=0).\n\ t = text.\n\ u = user gpio (0-31).\n\ v = value.\n\ +w = wave id (>=0).\n\ ws = 0=now, 1=high, 2=max.\n\ \n\ Numbers may be entered as hex (prefix 0x), octal (prefix 0),\n\ @@ -311,15 +284,15 @@ static errInfo_t errInfo[]= {PI_BAD_WVSC_COMMND , "bad WVSC subcommand"}, {PI_BAD_WVSM_COMMND , "bad WVSM subcommand"}, {PI_BAD_WVSP_COMMND , "bad WVSP subcommand"}, - {PI_BAD_PULSELEN , "trigger pulse > 100 microseconds"}, + {PI_BAD_PULSELEN , "trigger pulse > 50 microseconds"}, {PI_BAD_SCRIPT , "invalid script"}, {PI_BAD_SCRIPT_ID , "unknown script id"}, {PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"}, {PI_GPIO_IN_USE , "gpio already in use"}, {PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"}, {PI_BAD_PARAM_NUM , "script parameter must be 0-9"}, - {PI_DUP_LABEL , "script has duplicate label"}, - {PI_TOO_MANY_LABELS , "script has too many labels"}, + {PI_DUP_TAG , "script has duplicate tag"}, + {PI_TOO_MANY_TAGS , "script has too many tags"}, {PI_BAD_SCRIPT_CMD , "illegal script command"}, {PI_BAD_VAR_NUM , "script variable must be 0-149"}, {PI_NO_SCRIPT_ROOM , "no more room for scripts"}, @@ -328,6 +301,14 @@ static errInfo_t errInfo[]= {PI_SOCK_WRIT_FAILED , "socket write failed"}, {PI_TOO_MANY_PARAM , "too many script parameters > 10"}, {PI_NOT_HALTED , "script already running or failed"}, + {PI_BAD_TAG , "script has unresolved tag"}, + {PI_BAD_MICS_DELAY , "bad MICS delay (too large)"}, + {PI_BAD_MILS_DELAY , "bad MILS delay (too large)"}, + {PI_BAD_WAVE_ID , "non existent wave id"}, + {PI_TOO_MANY_CBS , "No more CBs for waveform"}, + {PI_TOO_MANY_OOL , "No more OOL for waveform"}, + {PI_EMPTY_WAVEFORM , "attempt to create an empty waveform"}, + {PI_NO_WAVEFORM_ID , "no more waveform ids"}, }; @@ -342,12 +323,13 @@ static int cmdMatch(char *str) { if (strcasecmp(str, cmdInfo[i].name) == 0) return i; } - return -1; + return CMD_UNKNOWN_CMD; } -static int getNum(char *str, unsigned *val, uint8_t *opt, int flags) +static int getNum(char *str, unsigned *val, int8_t *opt) { - int f, n, v; + int f, n; + unsigned v; *opt = 0; @@ -360,28 +342,24 @@ static int getNum(char *str, unsigned *val, uint8_t *opt, int flags) return n; } - if (flags & PARSE_FLAGS_PARAMS) - { - f = sscanf(str, " p%i %n", &v, &n); + f = sscanf(str, " v%i %n", &v, &n); - if (f == 1) - { - *val = v; - *opt = CMD_PARAM; - return n; - } + if (f == 1) + { + *val = v; + if (v < PI_MAX_SCRIPT_VARS) *opt = CMD_VAR; + else *opt = -CMD_VAR; + return n; } - if (flags & PARSE_FLAGS_VARS) - { - f = sscanf(str, " v%i %n", &v, &n); + f = sscanf(str, " p%i %n", &v, &n); - if (f == 1) - { - *val = v; - *opt = CMD_VAR; - return n; - } + if (f == 1) + { + *val = v; + if (v < PI_MAX_SCRIPT_PARAMS) *opt = CMD_PAR; + else *opt = -CMD_PAR; + return n; } return 0; @@ -394,16 +372,18 @@ char *cmdStr(void) return intCmdStr; } -int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl) +int cmdParse(char *buf, uint32_t *p, void **v, cmdCtlParse_t *ctl) { int f, valid, idx, val, pp, pars, n, n2, i; char *ptr; char c; - int param[MAX_PARAM]; + int32_t param[MAX_PARAM]; bzero(&ctl->opt, sizeof(ctl->opt)); - sscanf(buf+ctl->eaten, " %31s", intCmdStr); + sscanf(buf+ctl->eaten, " %31s %n", intCmdStr, &pp); + + ctl->eaten += pp; p[0] = -1; @@ -411,10 +391,6 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl) if (idx < 0) return idx; - sscanf(buf+ctl->eaten, " %*31s %n", &pp); - - ctl->eaten += pp; - valid = 0; p[0] = cmdInfo[idx].cmd; @@ -423,218 +399,74 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl) switch (cmdInfo[idx].vt) { - case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO - WVGOR WVHLT - */ + case 101: /* BR1 BR2 DCRA H HALT HELP HWVER INRA NO + PIGPV POPA PUSHA RET T TICK WVBSY WVCLR + WVCRE WVGO WVGOR WVHLT WVNEW + + No parameters, always valid. + */ valid = 1; + break; - case 2: /* MODEG NC NP PFG PRG PROCD PROCS PRRG - SLRC READ WVSC WVSM WVSP - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - if (ctl->opt[0]) valid = 1; + case 111: /* ADD AND BC1 BC2 BS1 BS2 CMP DIV LDA MLT + MOD OR RLA RRA SUB WAIT XOR + + One parameter, any value. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + if (ctl->opt[0] > 0) valid = 1; + break; - case 3: /* PFS PRS PWM SERVO SLR SLRO WDOG WRITE - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags); - if (ctl->opt[0] && ctl->opt[1]) valid = 1; + case 112: /* MG MICS MILS MODEG NC NP PFG PRG + PROCD PROCP PROCS PRRG R READ SLRC + WVDEL WVSC WVSM WVSP WVTX WVTXR + + One positive parameter. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0)) valid = 1; + break; - case 4: /* NB - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags); - if (ctl->opt[0] && ctl->opt[1]) valid = 1; + case 113: /* DCR INR POP PUSH STA XA + + One register parameter. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + if ((ctl->opt[0] > 0) && (p[1] < PI_MAX_SCRIPT_VARS)) valid = 1; + break; - case 5: /* TRIG - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2], ctl->flags); - if (ctl->opt[0] && ctl->opt[1] && ctl->opt[2]) valid = 1; + case 114: /* CALL JM JMP JNZ JP JZ TAG + + One numeric parameter, any value. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + if (ctl->opt[0] == CMD_NUMERIC) valid = 1; + break; - case 6: /* HELP - */ - valid = 1; - break; + case 115: /* PARSE PROC - case 7: /* BC1 BC2 BS1 BS2 - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - if (ctl->opt[0]) valid = 1; - break; - - case 8: /* MODES - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - f = sscanf(buf+ctl->eaten, " %c %n", &c, &n); - if (ctl->opt[0] && (f >= 1)) - { - ctl->eaten += n; - val = toupper(c); - ptr = strchr(fmtMdeStr, val); - if (ptr != NULL) - { - val = ptr - fmtMdeStr; - p[2] = val; - valid = 1; - } - } - break; - - case 9: /* PUD - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - f = sscanf(buf+ctl->eaten, " %c %n", &c, &n); - if (ctl->opt[0] && (f >= 1)) - { - ctl->eaten += n; - val = toupper(c); - ptr = strchr(fmtPudStr, val); - if (ptr != NULL) - { - val = ptr - fmtPudStr; - p[2] = val; - valid = 1; - } - } - break; - - case 10: /* PROC - */ + One parameter, string (rest of input). + */ p[1] = strlen(buf+ctl->eaten); v[1] = buf+ctl->eaten; ctl->eaten += p[1]; + valid = 1; + break; - case 11: /* WVAS - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags); - ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2], ctl->flags); + case 116: /* SYS - if (ctl->opt[0] && ctl->opt[1] && ctl->opt[2]) - { - p[4] = strlen(buf+ctl->eaten); - v[1] = buf+ctl->eaten; - ctl->eaten += p[4]; - valid = 1; - } - break; - - case 12: /* PROCR - */ - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], 0); - - pars = 0; - - while (pars < 10) - { - ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], 0); - if (ctl->opt[1]) param[pars++] = p[2]; - else break; - } - - p[2] = pars; - - v[1] = param; - - if (ctl->opt[0]) valid = 1; - break; - - case 13: /* WVAG - */ - pars = 0; - - while (pars < MAX_PARAM) - { - ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], 0); - if (ctl->opt[0]) param[pars++] = p[1]; - else break; - } - - p[1] = pars/3; - - v[1] = param; - - if (pars && ((pars%3)==0)) valid = 1; - break; - - case 20: /* - */ - f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n); - if ((f >= 1) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS)) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 21: /* - */ - f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n); - if (f == 1) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 22: /* - */ - f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n); - if (f == 1) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 23: /* - */ - valid = 1; - break; - - case 24: /* - */ - f = sscanf(buf+ctl->eaten, " %d %d %n", &p[1], &p[2], &n); - if ((f >= 2) && - (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS) && - (p[2] >= 0) && (p[2] < MAX_SCRIPT_VARS)) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 25: /* - */ - f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n); - if ((f >= 1) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_PARAMS)) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 26: /* - */ - f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n); - if (f >= 1) - { - ctl->eaten += n; - valid = 1; - } - break; - - case 27: /* - */ + One parameter, a string of letters, digits, '-' and '_'. + */ f = sscanf(buf+ctl->eaten, " %*s%n %n", &n, &n2); if ((f >= 0) && n) { @@ -659,20 +491,194 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl) ctl->eaten += n2; } } + break; - case 28: /* - */ - f = sscanf(buf+ctl->eaten, " %d %d %n", &p[1], &p[2], &n); - if ((f >= 2) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS)) + case 121: /* P PFS PRS PWM S SERVO SLR SLRO W WDOG WRITE + + Two positive parameters. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && + (ctl->opt[1] > 0) && ((int)p[2] >= 0)) valid = 1; + + break; + + case 122: /* NB + + Two parameters, first positive, second any value. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && + (ctl->opt[1] > 0)) valid = 1; + + break; + + case 123: /* LD RL RR + + Two parameters, first register, second any value. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + + if ((ctl->opt[0] > 0) && + (p[1] < PI_MAX_SCRIPT_VARS) && + (ctl->opt[1] > 0)) valid = 1; + + break; + + case 124: /* X + + Two register parameters. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + + if ((ctl->opt[0] > 0) && (p[1] < PI_MAX_SCRIPT_VARS) && + (ctl->opt[1] > 0) && (p[2] < PI_MAX_SCRIPT_VARS)) valid = 1; + + break; + + case 125: /* M MODES + + Two parameters, first positive, second in 'RW540123'. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + f = sscanf(buf+ctl->eaten, " %c %n", &c, &n); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && (f >= 1)) { ctl->eaten += n; + val = toupper(c); + ptr = strchr(fmtMdeStr, val); + + if (ptr != NULL) + { + val = ptr - fmtMdeStr; + p[2] = val; + valid = 1; + } + } + + break; + + case 126: /* PUD + + Two parameters, first positive, second in 'ODU'. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + f = sscanf(buf+ctl->eaten, " %c %n", &c, &n); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && (f >= 1)) + { + ctl->eaten += n; + val = toupper(c); + ptr = strchr(fmtPudStr, val); + if (ptr != NULL) + { + val = ptr - fmtPudStr; + p[2] = val; + valid = 1; + } + } + + break; + + case 131: /* TRIG + + Three positive parameters. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2]); + + if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && + (ctl->opt[1] > 0) && ((int)p[2] >= 0) && + (ctl->opt[2] == CMD_NUMERIC) && ((int)p[3] >= 0)) + valid = 1; + + break; + + case 141: /* WVAS + + Four parameters, first two positive, third any value, + last string (rest of input). + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2]); + + if ((ctl->opt[0] == CMD_NUMERIC) && ((int)p[1] >= 0) && + (ctl->opt[1] == CMD_NUMERIC) && ((int)p[2] >= 0) && + (ctl->opt[2] == CMD_NUMERIC)) + { + p[4] = strlen(buf+ctl->eaten); + v[1] = buf+ctl->eaten; + ctl->eaten += p[4]; valid = 1; } + break; + + case 191: /* PROCR + + One to 11 parameters, first positive, + optional remainder, any value. + */ + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + + if ((ctl->opt[0] == CMD_NUMERIC) && ((int)p[1] >= 0)) + { + pars = 0; + + while (pars < PI_MAX_SCRIPT_PARAMS) + { + ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]); + if (ctl->opt[1] == CMD_NUMERIC) param[pars++] = p[2]; + else break; + } + + p[2] = pars; + + v[1] = param; + + valid = 1; + } + + break; + + case 192: /* WVAG + + One or more triplets (gpios on, gpios off, delay), + any value. + */ + pars = 0; + + while (pars < MAX_PARAM) + { + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]); + if (ctl->opt[0] == CMD_NUMERIC) param[pars++] = p[1]; + else break; + } + + p[1] = pars / 3; + + v[1] = param; + + if (pars && ((pars % 3) == 0)) valid = 1; + + break; + + } - if (valid) return idx; else return -1; + if (valid) return idx; else return CMD_BAD_PARAMETER; } char * cmdErrStr(int error) @@ -686,3 +692,180 @@ char * cmdErrStr(int error) return "unknown error"; } +int cmdParseScript(char *script, cmdScript_t *s, int diags) +{ + int idx, len, b, i, j, tags, resolved; + int status; + uint32_t p[10]; + void *v[10]; + cmdInstr_t instr; + cmdCtlParse_t ctl; + + ctl.eaten = 0; + + status = 0; + + cmdTagStep_t tag_step[PI_MAX_SCRIPT_TAGS]; + + len = strlen(script); + + /* calloc space for PARAMS, VARS, CMDS, and STRINGS */ + + b = (sizeof(int) * (PI_MAX_SCRIPT_PARAMS + PI_MAX_SCRIPT_VARS)) + + (sizeof(cmdInstr_t) * (len + 2) / 2) + len; + + s->par = calloc(b, 1); + + if (s->par == NULL) return -1; + + s->var = s->par + PI_MAX_SCRIPT_PARAMS; + + s->instr = (cmdInstr_t *)(s->var + PI_MAX_SCRIPT_VARS); + + s->str_area = (char *)(s->instr + ((len + 2) / 2)); + + s->str_area_len = len; + s->str_area_pos = 0; + + s->instrs = 0; + + tags = 0; + + idx = 0; + + while (ctl.eaten= 0) + { + switch (instr.p[0]) + { + case PI_CMD_HELP: + case PI_CMD_PARSE: + case PI_CMD_PROC: + case PI_CMD_PROCD: + case PI_CMD_PROCP: + case PI_CMD_PROCR: + case PI_CMD_PROCS: + case PI_CMD_SLR: + case PI_CMD_SLRC: + case PI_CMD_SLRO: + case PI_CMD_WVAG: + case PI_CMD_WVAS: + + if (diags) + { + fprintf(stderr, "Illegal command: %s\n", cmdStr()); + } + + if (!status) status = PI_BAD_SCRIPT_CMD; + idx = -1; + + break; + + case PI_CMD_TAG: + + if (tags < PI_MAX_SCRIPT_TAGS) + { + /* check tag not already used */ + for (j=0; jinstrs; + tags++; + } + else + { + if (diags) + { + fprintf(stderr, "Too many tags: %d\n", instr.p[1]); + } + if (!status) status = PI_TOO_MANY_TAGS; + idx = -1; + } + + break; + + case PI_CMD_SYS: + + strncpy(s->str_area+s->str_area_pos, v[1], p[1]); + s->str_area[s->str_area_pos+p[1]] = 0; + instr.p[1] = (intptr_t) s->str_area+s->str_area_pos; + s->str_area_pos += (p[1] + 1); + + break; + + } + } + else + { + if (diags) + { + if (idx == CMD_UNKNOWN_CMD) + fprintf(stderr, "Unknown command: %s\n", cmdStr()); + else + fprintf(stderr, "Bad parameter to %s\n", cmdStr()); + } + if (!status) status = PI_BAD_SCRIPT_CMD; + } + + if (idx >= 0) + { + if (instr.p[0] != PI_CMD_TAG) + { + memcpy(instr.opt, &ctl.opt, sizeof(instr.opt)); + s->instr[s->instrs++] = instr; + } + } + } + + for (i=0; iinstrs; i++) + { + instr = s->instr[i]; + + /* resolve jumps */ + + if ((instr.p[0] == PI_CMD_JMP) || (instr.p[0] == PI_CMD_CALL) || + (instr.p[0] == PI_CMD_JZ) || (instr.p[0] == PI_CMD_JNZ) || + (instr.p[0] == PI_CMD_JM) || (instr.p[0] == PI_CMD_JP)) + { + resolved = 0; + + for (j=0; jinstr[i].p[1] = tag_step[j].step; + resolved = 1; + break; + } + } + + if (!resolved) + { + if (diags) + { + fprintf(stderr, "Can't resolve tag %d\n", instr.p[1]); + } + if (!status) status = PI_BAD_TAG; + } + } + } + return status; +} + diff --git a/command.h b/command.h index 7e62405..06d0fef 100644 --- a/command.h +++ b/command.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 13+ +This version is for pigpio version 14+ */ #ifndef COMMAND_H @@ -39,19 +39,18 @@ This version is for pigpio version 13+ #define MAX_PARAM 512 -#define PARSE_FLAGS_PARAMS 1 -#define PARSE_FLAGS_VARS 2 +#define CMD_UNKNOWN_CMD -1 +#define CMD_BAD_PARAMETER -2 #define CMD_NUMERIC 1 -#define CMD_PARAM 2 -#define CMD_VAR 3 +#define CMD_VAR 2 +#define CMD_PAR 3 typedef struct { - int flags; - int eaten; - uint8_t opt[8]; -} gpioCtlParse_t; + int eaten; + int8_t opt[4]; +} cmdCtlParse_t; typedef struct { @@ -61,11 +60,41 @@ typedef struct int rv; /* command return value type */ } cmdInfo_t; +typedef struct +{ + uint32_t tag; + int step; +} cmdTagStep_t; + +typedef struct +{ + uint32_t p[7]; + int8_t opt[4]; +} cmdInstr_t; + +typedef struct +{ + /* + +-----------+---------+---------+----------------+ + | PARAMS... | VARS... | CMDS... | STRING AREA... | + +-----------+---------+---------+----------------+ + */ + int *par; + int *var; + cmdInstr_t *instr; + int instrs; + char *str_area; + int str_area_len; + int str_area_pos; +} cmdScript_t; + extern cmdInfo_t cmdInfo[]; extern char *cmdUsage; -int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctlParse); +int cmdParse(char *buf, uint32_t *p, void **v, cmdCtlParse_t *ctl); + +int cmdParseScript(char *script, cmdScript_t *s, int diags); char *cmdErrStr(int error); diff --git a/pigpio.c b/pigpio.c index b9cdb29..0c540d2 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 13 */ +/* pigpio version 14 */ #include #include @@ -533,7 +533,8 @@ bit 0 READ_LAST_NOT_SET_ERROR #define DMAO_PAGES (PAGES_PER_BLOCK * PI_WAVE_BLOCKS) -#define NUM_OOL (DMAO_PAGES * OOL_PER_OPAGE) +#define NUM_WAVE_OOL (DMAO_PAGES * OOL_PER_OPAGE) +#define NUM_WAVE_CBS (DMAO_PAGES * CBS_PER_OPAGE) #define TICKSLOTS 50 @@ -556,28 +557,20 @@ bit 0 READ_LAST_NOT_SET_ERROR #define SRX_BUF_SIZE 8192 #define CMD_BUF_SIZE 4096 +#define MAX_DELAY 50 + /* --------------------------------------------------------------- */ typedef void (*callbk_t) (); -typedef struct { /* linux/arch/arm/mach-bcm2708/include/mach/dma.h */ - unsigned long info; - unsigned long src; - unsigned long dst; - unsigned long length; - unsigned long stride; - unsigned long next; - unsigned long pad[2]; -} dmaCbs_t; - typedef struct { - dmaCbs_t cb [128]; + rawCbs_t cb [128]; } dmaPage_t; typedef struct { - dmaCbs_t cb [CBS_PER_IPAGE]; + rawCbs_t cb [CBS_PER_IPAGE]; uint32_t level [LVS_PER_IPAGE]; uint32_t gpioOff [OFF_PER_IPAGE]; uint32_t tick [TCK_PER_IPAGE]; @@ -588,7 +581,7 @@ typedef struct typedef struct { - dmaCbs_t cb [CBS_PER_OPAGE]; + rawCbs_t cb [CBS_PER_OPAGE]; uint32_t OOL [OOL_PER_OPAGE]; uint32_t periphData; } dmaOPage_t; @@ -626,12 +619,6 @@ typedef struct uint32_t bits; } gpioGetSamples_t; -typedef struct -{ - uint32_t label; - int step; -} gpioLabelStep_t; - typedef struct { callbk_t func; @@ -653,16 +640,8 @@ typedef struct #define PI_SCRIPT_RUN 1 #define PI_SCRIPT_DELETE 2 -#define PI_SCRIPT_SLOTS 32 - #define PI_SCRIPT_STACK_SIZE 256 -typedef struct -{ - uint32_t p[6]; - uint8_t opt[8]; -} gpioInstr_t; - typedef struct { unsigned id; @@ -674,18 +653,7 @@ typedef struct pthread_t *pthIdp; pthread_mutex_t pthMutex; pthread_cond_t pthCond; -/* - +-----------+---------+---------+----------------+ - | PARAMS... | VARS... | CMDS... | STRING AREA... | - +-----------+---------+---------+----------------+ -*/ - int *param; - int *var; - gpioInstr_t *instr; - int instrs; - char *str_area; - int str_area_len; - int str_area_pos; + cmdScript_t script; } gpioScript_t; @@ -768,6 +736,13 @@ typedef struct int mode; } wfRx_t; +typedef struct +{ + int botCB; /* first CB used by wave */ + int topCB; /* last CB used by wave */ + int botOOL; + int topOOL; +} waveInfo_t; /* --------------------------------------------------------------- */ @@ -812,8 +787,16 @@ static wfStats_t wfStats= 0, 0, (DMAO_PAGES * CBS_PER_OPAGE) }; +static waveInfo_t waveInfo[PI_MAX_WAVES]; + static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1]; +static int waveOutBotCB = 0; +static int waveOutTopCB = NUM_WAVE_CBS; +static int waveOutBotOOL = 0; +static int waveOutTopOOL = NUM_WAVE_OOL; +static int waveOutCount = 0; + static volatile uint32_t alertBits = 0; static volatile uint32_t monitorBits = 0; static volatile uint32_t notifyBits = 0; @@ -835,7 +818,7 @@ static gpioInfo_t gpioInfo [PI_MAX_USER_GPIO+1]; static gpioNotify_t gpioNotify [PI_NOTIFY_SLOTS]; -static gpioScript_t gpioScript [PI_SCRIPT_SLOTS]; +static gpioScript_t gpioScript [PI_MAX_SCRIPTS]; static gpioSignal_t gpioSignal [PI_MAX_SIGNUM+1]; @@ -945,7 +928,7 @@ static uint32_t myGpioDelay(uint32_t micros) start = systReg[SYST_CLO]; - if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ; + if (micros <= MAX_DELAY) while ((systReg[SYST_CLO] - start) <= micros) ; else myGpioSleep(micros/MILLION, micros%MILLION); @@ -1041,153 +1024,9 @@ static uint32_t myGetTick(int pos) return tick; } -/* ----------------------------------------------------------------------- */ - -static int myParseScript(char *script, gpioScript_t *s) +static int myPermit(unsigned gpio) { - int idx, len, b, i, j, labels, resolved, pos; - int status; - uint32_t p[10]; - void *v[10]; - gpioInstr_t instr; - gpioCtlParse_t ctl; - - ctl.flags = PARSE_FLAGS_PARAMS | PARSE_FLAGS_VARS; - ctl.eaten = 0; - - status = 0; - - gpioLabelStep_t label_step[MAX_SCRIPT_LABELS]; - - len = strlen(script); - - /* calloc space for PARAMS, VARS, CMDS, and STRINGS */ - - b = (sizeof(int) * (MAX_SCRIPT_PARAMS + MAX_SCRIPT_VARS)) + - (sizeof(gpioInstr_t) * (len + 2) / 2) + len; - - s->param = calloc(b, 1); - - if (s->param == NULL) return -1; - - s->var = s->param + MAX_SCRIPT_PARAMS; - - s->instr = (gpioInstr_t *)(s->var + MAX_SCRIPT_VARS); - - s->str_area = (char *)(s->instr + ((len + 2) / 2)); - - s->str_area_len = len; - s->str_area_pos = 0; - - s->instrs = 0; - - labels = 0; - - idx = 0; - - while (!status && ((ctl.eaten)= 0)) - { - pos = ctl.eaten; - - idx = cmdParse(script, p, v, &ctl); - - memcpy(&instr.p, p, sizeof(instr.p)); - - if (idx >= 0) - { - switch (instr.p[0]) - { - case PI_CMD_LABEL: - - if (labels < MAX_SCRIPT_LABELS) - { - /* check label not already used */ - for (j=0; jinstrs; - labels++; - } - else - { - DBG(DBG_USER, "too many labels: %s", script+pos); - status = PI_TOO_MANY_LABELS; - idx = -1; - } - - break; - - case PI_CMD_SYS: - - strncpy(s->str_area+s->str_area_pos, v[1], p[1]); - s->str_area[s->str_area_pos+p[1]] = 0; - instr.p[1] = (int) s->str_area+s->str_area_pos; - s->str_area_pos += (p[1] + 1); - - break; - - case PI_CMD_TRIG: - break; - - } - } - else - { - DBG(DBG_USER, "invalid command: %s", script+pos); - status = PI_BAD_SCRIPT_CMD; - } - - if (idx >= 0) - { - if (instr.p[0] != PI_CMD_LABEL) - { - memcpy(instr.opt, &ctl.opt, sizeof(instr.opt)); - s->instr[s->instrs++] = instr; - } - } - } - - DBG(DBG_SCRIPT, "status=%d eaten=%d len=%d idx=%d", - status, ctl.eaten, len, idx); - - for (i=0; iinstrs; i++) - { - instr = s->instr[i]; - - /* resolve jumps */ - - if ((instr.p[0] == PI_CMD_JMP) || (instr.p[0] == PI_CMD_CALL) || - (instr.p[0] == PI_CMD_JZ) || (instr.p[0] == PI_CMD_JNZ) || - (instr.p[0] == PI_CMD_JM) || (instr.p[0] == PI_CMD_JP)) - { - resolved = 0; - - for (j=0; jinstr[i].p[1] = label_step[j].step; - resolved = 1; - break; - } - } - - if (!resolved) - { - DBG(DBG_USER, "can't resolve label %d\n", instr.p[1]); - status = PI_BAD_SCRIPT; - } - } - } - return status; + if (gpioMask & ((uint64_t)(1)<cb[slot]; } @@ -1708,9 +1565,9 @@ static uint32_t waveOOLPOadr(int pos) static void waveCbOPrint(int pos) { - dmaCbs_t * p; + rawCbs_t * p; - p = waveCbVOadr(pos); + p = rawWaveCBAdr(pos); fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n", p->info, p->src, p->dst, p->length, p->stride, p->next); @@ -1756,15 +1613,26 @@ static void waveBitDelay(unsigned baud, unsigned * bitDelay) bitDelay[9] = (e-s)/100; } +static int errCBsOOL(int cb, int botOOL, int topOOL) +{ + if (cb >= waveOutTopCB) return PI_TOO_MANY_CBS; + + if (botOOL >= topOOL) return PI_TOO_MANY_OOL; + + return 0; +} + /* ----------------------------------------------------------------------- */ static int wave2Cbs(unsigned mode) { - int cb=0, onoff=0, level=NUM_OOL; + int botCB=waveOutBotCB, botOOL=waveOutBotOOL, topOOL=waveOutTopOOL; - dmaCbs_t *p=NULL; + int status; - unsigned i, half, repeatCb; + rawCbs_t *p=NULL; + + unsigned i, half, repeatCB; unsigned numWaves; @@ -1775,9 +1643,11 @@ static int wave2Cbs(unsigned mode) half = PI_WF_MICROS/2; + if ((status = errCBsOOL(botCB+1, botOOL, topOOL))) return status; + /* add delay cb at start of DMA */ - p = waveCbVOadr(cb++); + p = rawWaveCBAdr(botCB++); /* use the secondary clock */ @@ -1786,7 +1656,6 @@ static int wave2Cbs(unsigned mode) p->info = NORMAL_DMA | DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(2); - p->dst = ((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | 0x7e000000; } else @@ -1794,69 +1663,78 @@ static int wave2Cbs(unsigned mode) p->info = NORMAL_DMA | DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(5); - p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000; } p->src = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR; - p->length = 4 * 50 / PI_WF_MICROS; /* 50 micros delay */ - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->length = 4 * 20 / PI_WF_MICROS; /* 20 micros delay */ + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; - repeatCb = cb; + repeatCB = botCB; for (i=0; iinfo = NORMAL_DMA; - p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR; + p->src = waveOOLPOadr(botOOL++) | DMA_BUS_ADR; p->dst = ((GPIO_BASE + (GPSET0*4)) & 0x00ffffff) | 0x7e000000; p->length = 4; - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; } if (waves[i].gpioOff) { - waveSetOOL(onoff, waves[i].gpioOff); + if ((status = errCBsOOL(botCB+1, botOOL+1, topOOL))) return status; - p = waveCbVOadr(cb++); + waveSetOOL(botOOL, waves[i].gpioOff); + + p = rawWaveCBAdr(botCB++); p->info = NORMAL_DMA; - p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR; + p->src = waveOOLPOadr(botOOL++) | DMA_BUS_ADR; p->dst = ((GPIO_BASE + (GPCLR0*4)) & 0x00ffffff) | 0x7e000000; p->length = 4; - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; } if (waves[i].flags & WAVE_FLAG_READ) { - p = waveCbVOadr(cb++); + if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status; + + p = rawWaveCBAdr(botCB++); p->info = NORMAL_DMA; p->src = ((GPIO_BASE + (GPLEV0*4)) & 0x00ffffff) | 0x7e000000; - p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR; + p->dst = waveOOLPOadr(--topOOL) | DMA_BUS_ADR; p->length = 4; - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; } if (waves[i].flags & WAVE_FLAG_TICK) { - p = waveCbVOadr(cb++); + if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status; + + p = rawWaveCBAdr(botCB++); p->info = NORMAL_DMA; p->src = ((SYST_BASE + (SYST_CLO*4)) & 0x00ffffff) | 0x7e000000; - p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR; + p->dst = waveOOLPOadr(--topOOL) | DMA_BUS_ADR; p->length = 4; - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; } if (waves[i].usDelay) { - p = waveCbVOadr(cb++); + if ((status = errCBsOOL(botCB+1, botOOL, topOOL))) return status; + + p = rawWaveCBAdr(botCB++); /* use the secondary clock */ @@ -1879,7 +1757,7 @@ static int wave2Cbs(unsigned mode) p->src = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR; p->length = 4 * ((waves[i].usDelay+half)/PI_WF_MICROS); - p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + p->next = waveCbPOadr(botCB) | DMA_BUS_ADR; } } @@ -1887,10 +1765,16 @@ static int wave2Cbs(unsigned mode) { if (mode == PI_WAVE_MODE_ONE_SHOT) p->next = 0; - else p->next = waveCbPOadr(repeatCb) | DMA_BUS_ADR; + else p->next = waveCbPOadr(repeatCB) | DMA_BUS_ADR; } - return cb; + status = botCB - waveOutBotCB; + + waveOutBotCB = botCB; + waveOutBotOOL = botOOL; + waveOutTopOOL = topOOL; + + return status; } @@ -1980,7 +1864,7 @@ static void waveRxBit(int gpio, int level, uint32_t tick) static int waveMerge(unsigned numIn1, gpioWave_t *in1) { - unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_OOL; + unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_WAVE_OOL; unsigned cbs=0; @@ -2111,7 +1995,7 @@ static int waveMerge(unsigned numIn1, gpioWave_t *in1) /* ======================================================================= */ -static dmaCbs_t * dmaCB2adr(int pos) +static rawCbs_t * dmaCB2adr(int pos) { int page, slot; @@ -2125,7 +2009,7 @@ static dmaCbs_t * dmaCB2adr(int pos) static void dmaCbPrint(int pos) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(pos); @@ -2180,7 +2064,7 @@ static unsigned dmaNowAtICB(void) /* ----------------------------------------------------------------------- */ -unsigned dmaNowAtOCB(void) +unsigned rawWaveCB(void) { unsigned cb; static unsigned lastPage=0; @@ -2296,7 +2180,7 @@ static uint32_t dmaCbAdr(int pos) static void dmaGpioOnCb(int b, int pos) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(b); @@ -2311,7 +2195,7 @@ static void dmaGpioOnCb(int b, int pos) static void dmaTickCb(int b, int pos) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(b); @@ -2326,7 +2210,7 @@ static void dmaTickCb(int b, int pos) static void dmaGpioOffCb(int b, int pos) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(b); @@ -2341,7 +2225,7 @@ static void dmaGpioOffCb(int b, int pos) static void dmaReadLevelsCb(int b, int pos) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(b); @@ -2356,7 +2240,7 @@ static void dmaReadLevelsCb(int b, int pos) static void dmaDelayCb(int b) { - dmaCbs_t * p; + rawCbs_t * p; p = dmaCB2adr(b); @@ -2382,7 +2266,7 @@ static void dmaInitCbs(void) { int b, pulse, level, cycle; - dmaCbs_t * p; + rawCbs_t * p; /* set up the DMA control blocks */ @@ -2816,16 +2700,22 @@ static void * pthAlertThread(void *x) if (err != (MAX_EMITS*sizeof(gpioReport_t))) { - DBG(0, "fd=%d err=%d errno=%d", - gpioNotify[n].fd, err, errno); - if (err < 0) DBG(0, "%s", strerror(errno)); - if ((err != EAGAIN) && (err != EWOULDBLOCK)) + if (err < 0) { - /* serious error, no point continuing */ - gpioNotify[n].bits = 0; - gpioNotify[n].state = PI_NOTIFY_CLOSING; - intNotifyBits(); - break; + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + /* serious error, no point continuing */ + + DBG(0, "fd=%d err=%d errno=%d", + gpioNotify[n].fd, err, errno); + + DBG(0, "%s", strerror(errno)); + + gpioNotify[n].bits = 0; + gpioNotify[n].state = PI_NOTIFY_CLOSING; + intNotifyBits(); + break; + } } } @@ -2840,16 +2730,21 @@ static void * pthAlertThread(void *x) if (err != (emit*sizeof(gpioReport_t))) { - DBG(0, "fd=%d err=%d errno=%d", - gpioNotify[n].fd, err, errno); - if (err < 0) DBG(0, "%s", strerror(errno)); - if ((err != EAGAIN) && (err != EWOULDBLOCK)) + if (err < 0) { - /* serious error, no point continuing */ - gpioNotify[n].bits = 0; - gpioNotify[n].state = PI_NOTIFY_CLOSING; - intNotifyBits(); - break; + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + DBG(0, "fd=%d err=%d errno=%d", + gpioNotify[n].fd, err, errno); + + DBG(0, "%s", strerror(errno)); + + /* serious error, no point continuing */ + gpioNotify[n].bits = 0; + gpioNotify[n].state = PI_NOTIFY_CLOSING; + intNotifyBits(); + break; + } } } @@ -2865,7 +2760,7 @@ static void * pthAlertThread(void *x) if (changedBits & scriptBits) { - for (n=0; nrequest == PI_SCRIPT_RUN ) && (s->run_state == PI_SCRIPT_RUNNING)) { - instr = s->instr[PC]; + instr = s->script.instr[PC]; - p1 = instr.p[1]; - p2 = instr.p[2]; + p1o = instr.p[1]; + p2o = instr.p[2]; + + if (instr.opt[0] == CMD_VAR) instr.p[1] = s->script.var[p1o]; + else if (instr.opt[0] == CMD_PAR) instr.p[1] = s->script.par[p1o]; + + if (instr.opt[1] == CMD_VAR) instr.p[2] = s->script.var[p2o]; + else if (instr.opt[1] == CMD_PAR) instr.p[2] = s->script.par[p2o]; if (instr.p[0] < 100) { oExt[0].ptr = buf; oExt[0].size = CMD_BUF_SIZE-1; - if (instr.opt[0] == CMD_PARAM) - { - instr.p[1] = s->param[p1]; - } - else if (instr.opt[0] == CMD_VAR) - { - instr.p[1] = s->var[p1]; - } - - if (instr.opt[1] == CMD_PARAM) - { - instr.p[2] = s->param[p2]; - } - else if (instr.opt[1] == CMD_VAR) - { - instr.p[2] = s->var[p2]; - } - A = myDoCommand(instr.p, oExt); F = A; @@ -3050,98 +2933,146 @@ static void *pthScript(void *x) } else { + p1 = instr.p[1]; + p2 = instr.p[2]; + switch (instr.p[0]) { - case PI_CMD_ADDI: A+=p1; F=A; PC++; break; + case PI_CMD_ADD: A+=p1; F=A; PC++; break; - case PI_CMD_ADDV: A+=s->var[p1]; F=A; PC++; break; + case PI_CMD_AND: A&=p1; F=A; PC++; break; - case PI_CMD_ANDI: A&=p1; F=A; PC++; break; + case PI_CMD_CALL: scrPush(s, &SP, S, PC+1); PC = p1; break; - case PI_CMD_ANDV: A&=s->var[p1]; F=A; PC++; break; + case PI_CMD_CMP: F=A-p1; PC++; break; - case PI_CMD_CALL: scrPush(s, S, &SP, PC+1); PC = p1; break; + case PI_CMD_DCR: + if (instr.opt[0] == CMD_PAR) + {--s->script.par[p1o]; F=s->script.par[p1o];} + else + {--s->script.var[p1o]; F=s->script.var[p1o];} + PC++; + break; - case PI_CMD_CMPI: F=A-p1; PC++; break; + case PI_CMD_DCRA: --A; F=A; PC++; break; - case PI_CMD_CMPV: F=A-s->var[p1]; PC++; break; + case PI_CMD_DIV: A/=p1; F=A; PC++; break; - case PI_CMD_DCRA: --A; F=A; PC++; break; + case PI_CMD_HALT: s->run_state = PI_SCRIPT_HALTED; break; - case PI_CMD_DCRV: --s->var[p1]; F=s->var[p1]; PC++; break; + case PI_CMD_INR: + if (instr.opt[0] == CMD_PAR) + {++s->script.par[p1o]; F=s->script.par[p1o];} + else + {++s->script.var[p1o]; F=s->script.var[p1o];} + PC++; + break; - case PI_CMD_HALT: s->run_state = PI_SCRIPT_HALTED; break; + case PI_CMD_INRA: ++A; F=A; PC++; break; - case PI_CMD_INRA: ++A; F=A; PC++; break; + case PI_CMD_JM: if (F<0) PC=p1; else PC++; break; - case PI_CMD_INRV: ++s->var[p1]; F=s->var[p1]; PC++; break; + case PI_CMD_JMP: PC=p1; break; - case PI_CMD_JM: if (F<0) PC=p1; else PC++; break; + case PI_CMD_JNZ: if (F) PC=p1; else PC++; break; - case PI_CMD_JMP: PC=p1; break; + case PI_CMD_JP: if (F>=0) PC=p1; else PC++; break; - case PI_CMD_JNZ: if (F) PC=p1; else PC++; break; + case PI_CMD_JZ: if (!F) PC=p1; else PC++; break; - case PI_CMD_JP: if (F>=0) PC=p1; else PC++; break; + case PI_CMD_LD: + if (instr.opt[0] == CMD_PAR) s->script.par[p1o]=p2; + else s->script.var[p1o]=p2; + PC++; + break; - case PI_CMD_JZ: if (!F) PC=p1; else PC++; break; + case PI_CMD_LDA: A=p1; PC++; break; - case PI_CMD_LABEL: PC++; break; + case PI_CMD_MLT: A*=p1; F=A; PC++; break; - case PI_CMD_LDAI: A=p1; PC++; break; + case PI_CMD_MOD: A%=p1; F=A; PC++; break; - case PI_CMD_LDAP: A=s->param[p1]; PC++; break; + case PI_CMD_OR: A|=p1; F=A; PC++; break; - case PI_CMD_LDAV: A=s->var[p1]; PC++; break; + case PI_CMD_POP: + if (instr.opt[0] == CMD_PAR) + s->script.par[p1o]=scrPop(s, &SP, S); + else + s->script.var[p1o]=scrPop(s, &SP, S); + PC++; + break; - case PI_CMD_LDPA: s->param[p1]=A; PC++; break; + case PI_CMD_POPA: A=scrPop(s, &SP, S); PC++; break; - case PI_CMD_LDVA: s->var[p1]=A; PC++; break; + case PI_CMD_PUSH: + if (instr.opt[0] == CMD_PAR) + scrPush(s, &SP, S, s->script.par[p1o]); + else + scrPush(s, &SP, S, s->script.var[p1o]); + PC++; + break; - case PI_CMD_LDVI: s->var[p1] = p2; PC++; break; + case PI_CMD_PUSHA: scrPush(s, &SP, S, A); PC++; break; - case PI_CMD_LDVV: s->var[p1]=s->var[p2]; PC++; break; + case PI_CMD_RET: PC=scrPop(s, &SP, S); break; - case PI_CMD_ORI: A|=p1; F=A; PC++; break; + case PI_CMD_RL: + if (instr.opt[0] == CMD_PAR) + {s->script.par[p1o]<<=p2; F=s->script.par[p1o];} + else + {s->script.var[p1o]<<=p2; F=s->script.var[p1o];} + PC++; + break; - case PI_CMD_ORV: A|=s->var[p1]; F=A; PC++; break; + case PI_CMD_RLA: A<<=p1; F=A; PC++; break; - case PI_CMD_POPA: A=scrPop(s, S, &SP); PC++; break; + case PI_CMD_RR: + if (instr.opt[0] == CMD_PAR) + {s->script.par[p1o]>>=p2; F=s->script.par[p1o];} + else + {s->script.var[p1o]>>=p2; F=s->script.var[p1o];} + PC++; + break; - case PI_CMD_POPV: s->var[p1]=scrPop(s, S, &SP); PC++; break; + case PI_CMD_RRA: A>>=p1; F=A; PC++; break; - case PI_CMD_PUSHA: scrPush(s, S, &SP, A); PC++; break; + case PI_CMD_STA: + if (instr.opt[0] == CMD_PAR) s->script.par[p1o]=A; + else s->script.var[p1o]=A; + PC++; + break; - case PI_CMD_PUSHV: scrPush(s, S, &SP, s->var[p1]); PC++; break; + case PI_CMD_SUB: A-=p1; F=A; PC++; break; - case PI_CMD_RET: PC=scrPop(s, S, &SP); break; + case PI_CMD_X: + if (instr.opt[0] == CMD_PAR) t1 = &s->script.par[p1o]; + else t1 = &s->script.var[p1o]; - case PI_CMD_RAL: A<<=p1; F=A; PC++; break; + if (instr.opt[1] == CMD_PAR) t2 = &s->script.par[p2o]; + else t2 = &s->script.var[p2o]; - case PI_CMD_RAR: A>>=p1; F=A; PC++; break; + scrSwap(t1, t2); + PC++; + break; - case PI_CMD_SUBI: A-=p1; F=A; PC++; break; + case PI_CMD_XA: + if (instr.opt[0] == CMD_PAR) + scrSwap(&s->script.par[p1o], &A); + else + scrSwap(&s->script.var[p1o], &A); + PC++; + break; - case PI_CMD_SUBV: A-=s->var[p1]; F=A; PC++; break; + case PI_CMD_SYS: A=scrSys((char*)p1, A); F=A; PC++; break; - case PI_CMD_SWAPA: scrSwap(&s->var[p1], &A); PC++; break; + case PI_CMD_WAIT: A=scrWait(s, p1); F=A; PC++; break; - case PI_CMD_SWAPV: scrSwap(&s->var[p1], &s->var[p2]);PC++; break; - - case PI_CMD_SYS: A=scrSys((char*)p1, A); F=A; PC++; break; - - case PI_CMD_WAITI: A=scrWait(s, p1); F=A; PC++; break; - - case PI_CMD_WAITV: A=scrWait(s, s->var[p1]); F=A; PC++; break; - - case PI_CMD_XORI: A^=p1; F=A; PC++; break; - - case PI_CMD_XORV: A^=s->var[p1]; F=A; PC++; break; + case PI_CMD_XOR: A^=p1; F=A; PC++; break; } } - if (PC >= s->instrs) s->run_state = PI_SCRIPT_HALTED; + if (PC >= s->script.instrs) s->run_state = PI_SCRIPT_HALTED; } @@ -3214,12 +3145,10 @@ static void * pthFifoThread(void *x) uint32_t p[10]; void *v[10]; gpioExtent_t oExt[3]; - gpioCtlParse_t ctl; + cmdCtlParse_t ctl; char *pp; uint32_t *param; - ctl.flags = 0; - myCreatePipe(PI_INPFIFO, 0662); if ((inpFifo = fopen(PI_INPFIFO, "r+")) == NULL) @@ -3310,7 +3239,7 @@ static void * pthFifoThread(void *x) { fprintf(outFifo, "%d", res); param = oExt[0].ptr; - for (i=0; i= 0) { - write(sock, oExt[0].ptr, sizeof(uint32_t)*MAX_SCRIPT_PARAMS); + write(sock, oExt[0].ptr, sizeof(uint32_t)*PI_MAX_SCRIPT_PARAMS); } break; @@ -4390,11 +4319,11 @@ void putBitInBytes(int bitPos, uint8_t *buf, int val) /* ----------------------------------------------------------------------- */ -uint32_t waveGetRawOut(int pos) +uint32_t rawWaveGetOut(int pos) { int page, slot; - if ((pos >= 0) && (pos < NUM_OOL)) + if ((pos >= 0) && (pos < NUM_WAVE_OOL)) { waveOOLPageSlot(pos, &page, &slot); return (dmaOVirt[page]->OOL[slot]); @@ -4409,7 +4338,7 @@ void waveSetRawOut(int pos, uint32_t value) { int page, slot; - if ((pos >= 0) && (pos < NUM_OOL)) + if ((pos >= 0) && (pos < NUM_WAVE_OOL)) { waveOOLPageSlot(pos, &page, &slot); dmaOVirt[page]->OOL[slot] = value; @@ -4419,13 +4348,13 @@ void waveSetRawOut(int pos, uint32_t value) /* ----------------------------------------------------------------------- */ -uint32_t waveGetRawIn(int pos) +uint32_t rawWaveGetIn(int pos) { int page, slot; - if ((pos >= 0) && (pos < NUM_OOL)) + if ((pos >= 0) && (pos < NUM_WAVE_OOL)) { - waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot); + waveOOLPageSlot((NUM_WAVE_OOL-1)-pos, &page, &slot); return (dmaOVirt[page]->OOL[slot]); } @@ -4434,13 +4363,13 @@ uint32_t waveGetRawIn(int pos) /* ----------------------------------------------------------------------- */ -void waveSetRawIn(int pos, uint32_t value) +void rawWaveSetIn(int pos, uint32_t value) { int page, slot; - if ((pos >= 0) && (pos < NUM_OOL)) + if ((pos >= 0) && (pos < NUM_WAVE_OOL)) { - waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot); + waveOOLPageSlot((NUM_WAVE_OOL-1)-pos, &page, &slot); dmaOVirt[page]->OOL[slot] = value; } } @@ -4481,7 +4410,7 @@ void time_sleep(double seconds) /* ----------------------------------------------------------------------- */ -void gpioDumpWave(void) +void rawDumpWave(void) { int i; @@ -4505,30 +4434,30 @@ void gpioDumpWave(void) /* ----------------------------------------------------------------------- */ -void gpioDumpScript(int s) +void rawDumpScript(int s) { int i; - for (i=0; i= waveOutCount) + SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id); + + waveOutBotCB = waveInfo[wave_id].botCB; + waveOutBotOOL = waveInfo[wave_id].botOOL; + waveOutTopOOL = waveInfo[wave_id].topOOL; + + waveOutCount = wave_id; + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveTxStart(unsigned mode) +{ + /* This function is deprecated and will be removed. */ + + static int secondaryClockInited = 0; + + int cb, i; + + DBG(DBG_USER, "mode=%d", mode); + + CHECK_INITED; + + if (mode > PI_WAVE_MODE_REPEAT) + SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode); + + if (wfc[wfcur] == 0) return 0; + + if (!secondaryClockInited) + { + initClock(0); /* initialise secondary clock */ + secondaryClockInited = 1; + } + + dmaOut[DMA_CS] = DMA_CHANNEL_RESET; + + dmaOut[DMA_CONBLK_AD] = 0; + + waveOutBotCB = 0; + waveOutTopCB = NUM_WAVE_CBS; + waveOutBotOOL = 0; + waveOutTopOOL = NUM_WAVE_OOL; + + waveOutCount = 0; + + cb = wave2Cbs(mode); + + if (gpioCfg.dbgLevel >= DBG_SLOW_TICK) + { + fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n"); + for (i=0; i= waveOutCount) + SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id); + + if (mode > PI_WAVE_MODE_REPEAT) + SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode); + + if (!secondaryClockInited) + { + initClock(0); /* initialise secondary clock */ + secondaryClockInited = 1; + } + + p = rawWaveCBAdr(waveInfo[wave_id].topCB); + + if (mode == PI_WAVE_MODE_ONE_SHOT) p->next = 0; + else p->next = waveCbPOadr(waveInfo[wave_id].botCB+1) | DMA_BUS_ADR; + + dmaOut[DMA_CS] = DMA_CHANNEL_RESET; + + dmaOut[DMA_CONBLK_AD] = 0; + + initDMAgo((uint32_t *)dmaOut, waveCbPOadr(waveInfo[wave_id].botCB)); + + /* for compatability with the deprecated gpioWaveTxStart return the + number of cbs + */ + return (waveInfo[wave_id].topCB - waveInfo[wave_id].botCB) + 1; +} + +/*-------------------------------------------------------------------------*/ + +int gpioWaveTxBusy(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + if (dmaOut[DMA_CONBLK_AD]) + return 1; + else + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveTxStop(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + dmaOut[DMA_CS] = DMA_CHANNEL_RESET; + + dmaOut[DMA_CONBLK_AD] = 0; + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetMicros(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.micros; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetHighMicros(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.highMicros; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetMaxMicros(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.maxMicros; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetPulses(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.pulses; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetHighPulses(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.highPulses; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetMaxPulses(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.maxPulses; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetCbs(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.cbs; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetHighCbs(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.highCbs; +} + +/* ----------------------------------------------------------------------- */ + +int gpioWaveGetMaxCbs(void) +{ + DBG(DBG_USER, ""); + + CHECK_INITED; + + return wfStats.maxCbs; +} + /*-------------------------------------------------------------------------*/ int gpioSerialReadOpen(unsigned gpio, unsigned baud) @@ -5540,7 +5656,7 @@ int gpioSerialRead(unsigned gpio, void *buf, size_t bufSize) if (bytes > bufSize) bytes = bufSize; - memcpy(buf, p->buf+p->readPos, bytes); + if (buf) memcpy(buf, p->buf+p->readPos, bytes); p->readPos += bytes; @@ -5586,78 +5702,6 @@ int gpioSerialReadClose(unsigned gpio) } -/*-------------------------------------------------------------------------*/ - -int gpioWaveTxBusy(void) -{ - DBG(DBG_USER, ""); - - CHECK_INITED; - - if (dmaOut[DMA_CONBLK_AD]) - return 1; - else - return 0; -} - - -/* ----------------------------------------------------------------------- */ - -int gpioWaveTxStart(unsigned mode) -{ - static int secondaryClockInited = 0; - - int cb, i; - - DBG(DBG_USER, "mode=%d", mode); - - CHECK_INITED; - - if (mode > PI_WAVE_MODE_REPEAT) - SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode); - - if (wfc[wfcur] == 0) return 0; - - if (!secondaryClockInited) - { - initClock(0); /* initialise secondary clock */ - secondaryClockInited = 1; - } - - dmaOut[DMA_CS] = DMA_CHANNEL_RESET; - - dmaOut[DMA_CONBLK_AD] = 0; - - cb = wave2Cbs(mode); - - if (gpioCfg.dbgLevel >= DBG_SLOW_TICK) - { - fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n"); - for (i=0; i PI_NOTIFY_SLOTS) + if (handle >= PI_NOTIFY_SLOTS) SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle); if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING) @@ -5879,7 +5923,7 @@ int gpioNotifyPause (unsigned handle) CHECK_INITED; - if (handle > PI_NOTIFY_SLOTS) + if (handle >= PI_NOTIFY_SLOTS) SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle); if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING) @@ -5903,7 +5947,7 @@ int gpioNotifyClose(unsigned handle) CHECK_INITED; - if (handle > PI_NOTIFY_SLOTS) + if (handle >= PI_NOTIFY_SLOTS) SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle); if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING) @@ -6171,7 +6215,7 @@ int gpioStoreScript(char *script) slot = -1; - for (i=0; iscript, 0); if (status == 0) { @@ -6207,8 +6251,8 @@ int gpioStoreScript(char *script) } else { - if (s->param) free(s->param); - s->param = NULL; + if (s->script.par) free(s->script.par); + s->script.par = NULL; gpioScript[slot].state = PI_SCRIPT_FREE; } @@ -6218,7 +6262,7 @@ int gpioStoreScript(char *script) /* ----------------------------------------------------------------------- */ -int gpioRunScript(int script_id, unsigned numParam, uint32_t *param) +int gpioRunScript(unsigned script_id, unsigned numParam, uint32_t *param) { int status = 0; @@ -6227,7 +6271,10 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param) CHECK_INITED; - if (numParam > MAX_SCRIPT_PARAMS) + if (script_id >= PI_MAX_SCRIPTS) + SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id); + + if (numParam > PI_MAX_SCRIPT_PARAMS) SOFT_ERROR(PI_TOO_MANY_PARAM, "bad number of parameters(%d)", numParam); if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) @@ -6238,7 +6285,7 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param) { if ((numParam > 0) && (param != 0)) { - memcpy(gpioScript[script_id].param, param, + memcpy(gpioScript[script_id].script.par, param, sizeof(uint32_t) * numParam); } @@ -6255,24 +6302,30 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param) return status; } - else return PI_BAD_SCRIPT_ID; + else + { + return PI_BAD_SCRIPT_ID; + } } /* ----------------------------------------------------------------------- */ -int gpioScriptStatus(int script_id, uint32_t *param) +int gpioScriptStatus(unsigned script_id, uint32_t *param) { DBG(DBG_USER, "script_id=%d param=%08X", script_id, (uint32_t)param); CHECK_INITED; + if (script_id >= PI_MAX_SCRIPTS) + SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id); + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) { if (param != 0) { - memcpy(param, gpioScript[script_id].param, - sizeof(uint32_t) * MAX_SCRIPT_PARAMS); + memcpy(param, gpioScript[script_id].script.par, + sizeof(uint32_t) * PI_MAX_SCRIPT_PARAMS); } return gpioScript[script_id].run_state; @@ -6283,12 +6336,15 @@ int gpioScriptStatus(int script_id, uint32_t *param) /* ----------------------------------------------------------------------- */ -int gpioStopScript(int script_id) +int gpioStopScript(unsigned script_id) { DBG(DBG_USER, "script_id=%d", script_id); CHECK_INITED; + if (script_id >= PI_MAX_SCRIPTS) + SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id); + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) { pthread_mutex_lock(&gpioScript[script_id].pthMutex); @@ -6309,12 +6365,15 @@ int gpioStopScript(int script_id) /* ----------------------------------------------------------------------- */ -int gpioDeleteScript(int script_id) +int gpioDeleteScript(unsigned script_id) { DBG(DBG_USER, "script_id=%d", script_id); CHECK_INITED; + if (script_id >= PI_MAX_SCRIPTS) + SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id); + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) { gpioScript[script_id].state = PI_SCRIPT_DYING; @@ -6337,9 +6396,9 @@ int gpioDeleteScript(int script_id) gpioStopThread(gpioScript[script_id].pthIdp); - if (gpioScript[script_id].param) free(gpioScript[script_id].param); + if (gpioScript[script_id].script.par) free(gpioScript[script_id].script.par); - gpioScript[script_id].param = NULL; + gpioScript[script_id].script.par = NULL; gpioScript[script_id].state = PI_SCRIPT_FREE; @@ -6559,7 +6618,7 @@ uint32_t gpioDelay(uint32_t micros) start = systReg[SYST_CLO]; - if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ; + if (micros <= MAX_DELAY) while ((systReg[SYST_CLO] - start) <= micros) ; else gpioSleep(PI_TIME_RELATIVE, (micros/MILLION), (micros%MILLION)); diff --git a/pigpio.h b/pigpio.h index 0ddac32..6b163dd 100644 --- a/pigpio.h +++ b/pigpio.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 13 +This version is for pigpio version 14 */ #ifndef PIGPIO_H @@ -86,7 +86,7 @@ This version is for pigpio version 13 #include #include -#define PIGPIO_VERSION 13 +#define PIGPIO_VERSION 14 /*-------------------------------------------------------------------------*/ @@ -125,18 +125,21 @@ gpioNotifyBegin Begin a gpio(s) changed notification. gpioNotifyPause Pause a gpio(s) changed notification. gpioNotifyClose Close a gpio(s) changed notification. -gpioWaveClear Initialises a new waveform. +gpioWaveClear Deletes all waveforms. + +gpioWaveAddNew Starts a new waveform. gpioWaveAddGeneric Adds a series of pulses to the waveform. gpioWaveAddSerial Adds serial data to the waveform. -gpioWaveTxStart Transmits the waveform. +gpioWaveCreate Creates a waveform from added data. +gpioWaveDelete Deletes one or more waveforms. + +gpioWaveTxStart Creates/transmits a waveform (DEPRECATED). + +gpioWaveTxSend Transmits a waveform. gpioWaveTxBusy Checks to see if the waveform has ended. gpioWaveTxStop Aborts the current waveform. -gpioSerialReadOpen Opens a gpio for reading serial data. -gpioSerialRead Reads serial data from a gpio. -gpioSerialReadClose Closes a gpio for reading serial data. - gpioWaveGetMicros Length in microseconds of the current waveform. gpioWaveGetHighMicros Length of longest waveform so far. gpioWaveGetMaxMicros Absolute maximum allowed micros. @@ -149,6 +152,10 @@ gpioWaveGetCbs Length in cbs of the current waveform. gpioWaveGetHighCbs Length of longest waveform so far. gpioWaveGetMaxCbs Absolute maximum allowed cbs. +gpioSerialReadOpen Opens a gpio for reading serial data. +gpioSerialRead Reads serial data from a gpio. +gpioSerialReadClose Closes a gpio for reading serial data. + gpioTrigger Send a trigger pulse to a gpio. gpioSetWatchdog Set a watchdog on a gpio. @@ -281,7 +288,17 @@ typedef struct int clk_pol; /* clock off state */ int clk_pha; /* clock phase */ int clk_us; /* clock micros */ -} gpioSPI_t; +} rawSPI_t; + +typedef struct { /* linux/arch/arm/mach-bcm2708/include/mach/dma.h */ + unsigned long info; + unsigned long src; + unsigned long dst; + unsigned long length; + unsigned long stride; + unsigned long next; + unsigned long pad[2]; +} rawCbs_t; typedef void (*gpioAlertFunc_t) (int gpio, int level, @@ -873,34 +890,26 @@ int gpioNotifyClose(unsigned handle); /*-------------------------------------------------------------------------*/ int gpioWaveClear(void); /*-------------------------------------------------------------------------*/ -/* This function initialises a new waveform. +/* This function clears all waveforms and any data added by calls to the + gpioWaveAdd* functions. Returns 0 if OK. - - A waveform comprises one of more pulses. Each pulse consists of a - gpioPulse_t structure. - - typedef struct - { - uint32_t gpioOn; - uint32_t gpioOff; - uint32_t usDelay; - } gpioPulse_t; - - The fields specify - - 1) the gpios to be switched on at the start of the pulse. - 2) the gpios to be switched off at the start of the pulse. - 3) the delay in microseconds before the next pulse. - - Any or all the fields can be zero. It doesn't make any sense to - set all the fields to zero (the pulse will be ignored). - - When a waveform is started each pulse is executed in order with the - specified delay between the pulse and the next. */ + +/*-------------------------------------------------------------------------*/ +int gpioWaveAddNew(void); +/*-------------------------------------------------------------------------*/ +/* This function starts a new empty waveform. You wouldn't normally need + to call this function as it is automatically called after a waveform is + created with the gpioWaveCreate function. + + Returns 0 if OK. +*/ + + + /*-------------------------------------------------------------------------*/ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses); /*-------------------------------------------------------------------------*/ @@ -911,7 +920,7 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses); NOTES: - The pulses are interleaved in time order within the existing waveform + The pulses are interleaved in time order within the existing waveform (if any). Merging allows the waveform to be built in parts, that is the settings @@ -956,16 +965,97 @@ int gpioWaveAddSerial(unsigned user_gpio, #define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */ +#define PI_MAX_WAVES 100 + + + /*-------------------------------------------------------------------------*/ -int gpioWaveTxStart(unsigned mode); +int gpioWaveCreate(void); /*-------------------------------------------------------------------------*/ -/* This function transmits the current waveform. The mode determines - whether the waveform is sent once or cycles endlessly. +/* This function creates a waveform from the data provided by the prior + calls to the gpioWaveAdd* functions. Upon success a positive wave id + is returned. + + The data provided by the gpioWaveAdd* functions is consumed by this + function. + + As many waveforms may be created as there is space available. The + wave id is passed to gpioWaveTxSend to specify the waveform to transmit. + + Normal usage would be + + Step 1. gpioWaveClear to clear all waveforms and added data. + + Step 2. gpioWaveAdd* calls to supply the waveform data. + + Step 3. gpioWaveCreate to create the waveform and get a unique id + + Repeat steps 2 and 3 as needed. + + Step 4. gpioWaveTxSend with the id of the waveform to transmit. + + A waveform comprises one of more pulses. Each pulse consists of a + gpioPulse_t structure. + + typedef struct + { + uint32_t gpioOn; + uint32_t gpioOff; + uint32_t usDelay; + } gpioPulse_t; + + The fields specify + + 1) the gpios to be switched on at the start of the pulse. + 2) the gpios to be switched off at the start of the pulse. + 3) the delay in microseconds before the next pulse. + + Any or all the fields can be zero. It doesn't make any sense to + set all the fields to zero (the pulse will be ignored). + + When a waveform is started each pulse is executed in order with the + specified delay between the pulse and the next. + + Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM, + PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL. +*/ + + +/*-------------------------------------------------------------------------*/ +int gpioWaveDelete(unsigned wave_id); +/*-------------------------------------------------------------------------*/ +/* This function deletes all created waveforms with ids greater than or + equal to wave_id. + + Wave ids are allocated in order, 0, 1, 2, etc. + + Returns 0 if OK, otherwise PI_BAD_WAVE_ID. +*/ + + +/*-------------------------------------------------------------------------*/ +int gpioWaveTxStart(unsigned mode); /* DEPRECATED */ +/*-------------------------------------------------------------------------*/ +/* This function creates and then transmits a waveform. The mode + determines whether the waveform is sent once or cycles endlessly. + + This function is deprecated and should no longer be used. Use + gpioWaveCreate/gpioWaveTxSend instead. Returns the number of DMA control blocks in the waveform if OK, otherwise PI_BAD_WAVE_MODE. */ +/*-------------------------------------------------------------------------*/ +int gpioWaveTxSend(unsigned wave_id, unsigned mode); +/*-------------------------------------------------------------------------*/ +/* This function transmits the waveform with id wave_id. The mode + determines whether the waveform is sent once or cycles endlessly. + + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE. +*/ + #define PI_WAVE_MODE_ONE_SHOT 0 #define PI_WAVE_MODE_REPEAT 1 @@ -991,46 +1081,7 @@ int gpioWaveTxStop(void); NOTES: - This function is intended to stop a waveform started with the repeat mode. -*/ - - - -/*-------------------------------------------------------------------------*/ -int gpioSerialReadOpen(unsigned user_gpio, unsigned baud); -/*-------------------------------------------------------------------------*/ -/* This function opens a gpio for reading serial data. - - Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, - or PI_GPIO_IN_USE. - - The serial data is returned in a cyclic buffer and is read using - gpioSerialRead(). - - It is the caller's responsibility to read data from the cyclic buffer - in a timely fashion. -*/ - - - -/*-------------------------------------------------------------------------*/ -int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize); -/*-------------------------------------------------------------------------*/ -/* This function copies up to bufSize bytes of data read from the - serial cyclic buffer to the buffer starting at buf. - - Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO - or PI_NOT_SERIAL_GPIO. -*/ - - - -/*-------------------------------------------------------------------------*/ -int gpioSerialReadClose(unsigned user_gpio); -/*-------------------------------------------------------------------------*/ -/* This function closes a gpio for reading serial data. - - Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO. + This function is intended to stop a waveform started in repeat mode. */ @@ -1114,6 +1165,45 @@ int gpioWaveGetMaxCbs(void); +/*-------------------------------------------------------------------------*/ +int gpioSerialReadOpen(unsigned user_gpio, unsigned baud); +/*-------------------------------------------------------------------------*/ +/* This function opens a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, + or PI_GPIO_IN_USE. + + The serial data is returned in a cyclic buffer and is read using + gpioSerialRead(). + + It is the caller's responsibility to read data from the cyclic buffer + in a timely fashion. +*/ + + + +/*-------------------------------------------------------------------------*/ +int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize); +/*-------------------------------------------------------------------------*/ +/* This function copies up to bufSize bytes of data read from the + serial cyclic buffer to the buffer starting at buf. + + Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO + or PI_NOT_SERIAL_GPIO. +*/ + + + +/*-------------------------------------------------------------------------*/ +int gpioSerialReadClose(unsigned user_gpio); +/*-------------------------------------------------------------------------*/ +/* This function closes a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO. +*/ + + + /*-------------------------------------------------------------------------*/ int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level); /*-------------------------------------------------------------------------*/ @@ -1124,7 +1214,7 @@ int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level); or PI_BAD_PULSELEN. */ -#define PI_MAX_PULSELEN 100 +#define PI_MAX_PULSELEN 50 /*-------------------------------------------------------------------------*/ @@ -1351,13 +1441,15 @@ int gpioStoreScript(char *script); otherwise PI_BAD_SCRIPT. */ -#define MAX_SCRIPT_LABELS 50 -#define MAX_SCRIPT_VARS 150 -#define MAX_SCRIPT_PARAMS 10 +#define PI_MAX_SCRIPTS 32 + +#define PI_MAX_SCRIPT_TAGS 50 +#define PI_MAX_SCRIPT_VARS 150 +#define PI_MAX_SCRIPT_PARAMS 10 /* ----------------------------------------------------------------------- */ -int gpioRunScript(int script_id, unsigned numParam, uint32_t *param); +int gpioRunScript(unsigned script_id, unsigned numParam, uint32_t *param); /* ----------------------------------------------------------------------- */ /* This function runs a stored script. @@ -1371,7 +1463,7 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param); /* ----------------------------------------------------------------------- */ -int gpioScriptStatus(int script_id, uint32_t *param); +int gpioScriptStatus(unsigned script_id, uint32_t *param); /* ----------------------------------------------------------------------- */ /* This function returns the run status of a stored script as well as the current values of parameters 0 to 9. @@ -1399,7 +1491,7 @@ int gpioScriptStatus(int script_id, uint32_t *param); /* ----------------------------------------------------------------------- */ -int gpioStopScript(int script_id); +int gpioStopScript(unsigned script_id); /* ----------------------------------------------------------------------- */ /* This function stops a running script. @@ -1409,7 +1501,7 @@ int gpioStopScript(int script_id); /* ----------------------------------------------------------------------- */ -int gpioDeleteScript(int script_id); +int gpioDeleteScript(unsigned script_id); /* ----------------------------------------------------------------------- */ /* This function deletes a stored script. @@ -1615,7 +1707,8 @@ uint32_t gpioDelay(uint32_t micros); Returns the actual length of the delay in microseconds. */ - +#define PI_MAX_MICS_DELAY 1000000 /* 1 second */ +#define PI_MAX_MILS_DELAY 60000 /* 60 seconds */ /*-------------------------------------------------------------------------*/ uint32_t gpioTick(void); @@ -1860,12 +1953,13 @@ int gpioCfgInternals(unsigned what, int value); /*-------------------------------------------------------------------------*/ /* Used to tune internal settings. + Not intended for general use. */ /*-------------------------------------------------------------------------*/ -int gpioWaveAddSPI( - gpioSPI_t *spi, +int rawWaveAddSPI( + rawSPI_t *spi, unsigned offset, unsigned ss, uint8_t *tx_bits, @@ -1883,36 +1977,59 @@ int gpioWaveAddSPI( Returns the new total number of pulses in the current waveform if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SER_OFFSET, or PI_TOO_MANY_PULSES. + + Not intended for general use. */ +/* ----------------------------------------------------------------------- */ +unsigned rawWaveCB(void); +/* ----------------------------------------------------------------------- */ +/* + Returns the number of the cb being currently output. + + Not intended for general use. +*/ /* ----------------------------------------------------------------------- */ -uint32_t waveGetRawOut(int pos); +rawCbs_t * rawWaveCBAdr(int n); +/* ----------------------------------------------------------------------- */ +/* + Return the Linux address of contol block n. + + Not intended for general use. +*/ + +/* ----------------------------------------------------------------------- */ +uint32_t rawWaveGetOut(int pos); /* ----------------------------------------------------------------------- */ /* Gets the wave output parameter stored at pos. + Not intended for general use. */ /* ----------------------------------------------------------------------- */ -void waveSetRawOut(int pos, uint32_t value); +void rawWaveSetOut(int pos, uint32_t value); /* ----------------------------------------------------------------------- */ /* Sets the wave output parameter stored at pos to value. + Not intended for general use. */ /* ----------------------------------------------------------------------- */ -uint32_t waveGetRawIn(int pos); +uint32_t rawWaveGetIn(int pos); /* ----------------------------------------------------------------------- */ /* Gets the wave input value parameter stored at pos. + Not intended for general use. */ /* ----------------------------------------------------------------------- */ -void waveSetRawIn(int pos, uint32_t value); +void rawWaveSetIn(int pos, uint32_t value); /* ----------------------------------------------------------------------- */ /* Sets the wave input value stored at pos to value. + Not intended for general use. */ @@ -1944,17 +2061,19 @@ void time_sleep(double seconds); /*-------------------------------------------------------------------------*/ -void gpioDumpWave(void); +void rawDumpWave(void); /*-------------------------------------------------------------------------*/ /* Used to print a readable version of the current waveform to stderr. + Not intended for general use. */ /*-------------------------------------------------------------------------*/ -void gpioDumpScript(int s); +void rawDumpScript(int s); /*-------------------------------------------------------------------------*/ /* Used to print a readable version of a script to stderr. + Not intended for general use. */ @@ -2011,8 +2130,14 @@ void gpioDumpScript(int s); #define PI_CMD_SLR 43 #define PI_CMD_SLRC 44 #define PI_CMD_PROCP 45 -#define PI_CMD_MICRO 46 -#define PI_CMD_MILLI 47 +#define PI_CMD_MICS 46 +#define PI_CMD_MILS 47 +#define PI_CMD_PARSE 48 +#define PI_CMD_WVCRE 49 +#define PI_CMD_WVDEL 50 +#define PI_CMD_WVTX 51 +#define PI_CMD_WVTXR 52 +#define PI_CMD_WVNEW 53 /* @@ -2031,49 +2156,43 @@ after this command is issued. #define PI_CMD_SCRIPT 800 -#define PI_CMD_ADDI 800 -#define PI_CMD_ADDV 801 -#define PI_CMD_ANDI 802 -#define PI_CMD_ANDV 803 -#define PI_CMD_CALL 804 -#define PI_CMD_CMPI 805 -#define PI_CMD_CMPV 806 -#define PI_CMD_DCRA 807 -#define PI_CMD_DCRV 808 -#define PI_CMD_HALT 809 -#define PI_CMD_INRA 810 -#define PI_CMD_INRV 811 -#define PI_CMD_JM 812 -#define PI_CMD_JMP 813 -#define PI_CMD_JNZ 814 -#define PI_CMD_JP 815 -#define PI_CMD_JZ 816 -#define PI_CMD_LABEL 817 -#define PI_CMD_LDAI 818 -#define PI_CMD_LDAP 819 -#define PI_CMD_LDAV 820 -#define PI_CMD_LDPA 821 -#define PI_CMD_LDVA 822 -#define PI_CMD_LDVI 823 -#define PI_CMD_LDVV 824 -#define PI_CMD_ORI 827 -#define PI_CMD_ORV 828 -#define PI_CMD_POPA 829 -#define PI_CMD_POPV 830 -#define PI_CMD_PUSHA 831 -#define PI_CMD_PUSHV 832 -#define PI_CMD_RET 833 -#define PI_CMD_RAL 834 -#define PI_CMD_RAR 835 -#define PI_CMD_SUBI 836 -#define PI_CMD_SUBV 837 -#define PI_CMD_SWAPA 838 -#define PI_CMD_SWAPV 839 -#define PI_CMD_SYS 840 -#define PI_CMD_WAITI 841 -#define PI_CMD_WAITV 842 -#define PI_CMD_XORI 843 -#define PI_CMD_XORV 844 +#define PI_CMD_ADD 800 +#define PI_CMD_AND 801 +#define PI_CMD_CALL 802 +#define PI_CMD_CMP 803 +#define PI_CMD_DCR 804 +#define PI_CMD_DCRA 805 +#define PI_CMD_DIV 806 +#define PI_CMD_HALT 807 +#define PI_CMD_INR 808 +#define PI_CMD_INRA 809 +#define PI_CMD_JM 810 +#define PI_CMD_JMP 811 +#define PI_CMD_JNZ 812 +#define PI_CMD_JP 813 +#define PI_CMD_JZ 814 +#define PI_CMD_TAG 815 +#define PI_CMD_LD 816 +#define PI_CMD_LDA 817 +#define PI_CMD_MLT 818 +#define PI_CMD_MOD 819 +#define PI_CMD_OR 820 +#define PI_CMD_POP 821 +#define PI_CMD_POPA 822 +#define PI_CMD_PUSH 823 +#define PI_CMD_PUSHA 824 +#define PI_CMD_RET 825 +#define PI_CMD_RL 826 +#define PI_CMD_RLA 827 +#define PI_CMD_RR 828 +#define PI_CMD_RRA 829 +#define PI_CMD_STA 830 +#define PI_CMD_SUB 831 +#define PI_CMD_SYS 832 +#define PI_CMD_WAIT 833 +#define PI_CMD_X 834 +#define PI_CMD_XA 835 +#define PI_CMD_XOR 836 /*-------------------------------------------------------------------------*/ @@ -2126,15 +2245,15 @@ after this command is issued. #define PI_BAD_WVSC_COMMND -43 /* bad WVSC subcommand */ #define PI_BAD_WVSM_COMMND -44 /* bad WVSM subcommand */ #define PI_BAD_WVSP_COMMND -45 /* bad WVSP subcommand */ -#define PI_BAD_PULSELEN -46 /* trigger pulse length > 100 */ +#define PI_BAD_PULSELEN -46 /* trigger pulse length > 50 */ #define PI_BAD_SCRIPT -47 /* invalid script */ #define PI_BAD_SCRIPT_ID -48 /* unknown script id */ #define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */ #define PI_GPIO_IN_USE -50 /* gpio already in use */ #define PI_BAD_SERIAL_COUNT -51 /* must read at least a byte at a time */ #define PI_BAD_PARAM_NUM -52 /* script parameter must be 0-9 */ -#define PI_DUP_LABEL -53 /* script has duplicate label */ -#define PI_TOO_MANY_LABELS -54 /* script has too many labels */ +#define PI_DUP_TAG -53 /* script has duplicate tag */ +#define PI_TOO_MANY_TAGS -54 /* script has too many tags */ #define PI_BAD_SCRIPT_CMD -55 /* illegal script command */ #define PI_BAD_VAR_NUM -56 /* script variable must be 0-149 */ #define PI_NO_SCRIPT_ROOM -57 /* no more room for scripts */ @@ -2143,6 +2262,14 @@ after this command is issued. #define PI_SOCK_WRIT_FAILED -60 /* socket write failed */ #define PI_TOO_MANY_PARAM -61 /* too many script parameters > 10 */ #define PI_NOT_HALTED -62 /* script already running or failed */ +#define PI_BAD_TAG -63 /* script has unresolved tag */ +#define PI_BAD_MICS_DELAY -64 /* bad MICS delay (too large) */ +#define PI_BAD_MILS_DELAY -65 /* bad MILS delay (too large) */ +#define PI_BAD_WAVE_ID -66 /* non existent wave id */ +#define PI_TOO_MANY_CBS -67 /* No more CBs for waveform */ +#define PI_TOO_MANY_OOL -68 /* No more OOL for waveform */ +#define PI_EMPTY_WAVEFORM -69 /* attempt to create an empty waveform */ +#define PI_NO_WAVEFORM_ID -70 /* no more waveforms */ /*-------------------------------------------------------------------------*/ diff --git a/pigpio.py b/pigpio.py index f5591ca..3124ecd 100644 --- a/pigpio.py +++ b/pigpio.py @@ -26,7 +26,8 @@ The pigpio module's main features are: - provision of servo pulses on any number of gpios 0-31 simultaneously. -- callbacks when any of gpios 0-31 change state. +- callbacks when any of gpios 0-31 change state (callbacks receive the + time of the event accurate to a few microseconds). - reading/writing gpios and setting their modes (typically input or output). @@ -34,6 +35,11 @@ The pigpio module's main features are: - reading/writing all of the gpios in a bank (0-31, 32-53) as a single operation. +- creating and transmitting precisely timed waveforms (accurate + to a few microseconds). + +- creating and running scripts on the pigpio daemon. + Notes ALL gpios are identified by their Broadcom number. @@ -76,7 +82,7 @@ import threading import os import atexit -VERSION = "1.4" +VERSION = "1.5" # gpio levels @@ -168,11 +174,16 @@ _PI_CMD_SLRO= 42 _PI_CMD_SLR= 43 _PI_CMD_SLRC= 44 _PI_CMD_PROCP=45 - +_PI_CMD_MICRO=46 +_PI_CMD_MILLI=47 +_PI_CMD_PARSE=48 +_PI_CMD_WVCRE=49 +_PI_CMD_WVDEL=50 +_PI_CMD_WVTX =51 +_PI_CMD_WVTXR=52 _PI_CMD_NOIB= 99 - # pigpio error numbers _PI_INIT_FAILED =-1 @@ -228,8 +239,8 @@ PI_BAD_SER_OFFSET =-49 PI_GPIO_IN_USE =-50 PI_BAD_SERIAL_COUNT =-51 PI_BAD_PARAM_NUM =-52 -PI_DUP_LABEL =-53 -PI_TOO_MANY_LABELS =-54 +PI_DUP_TAG =-53 +PI_TOO_MANY_TAGS =-54 PI_BAD_SCRIPT_CMD =-55 PI_BAD_VAR_NUM =-56 PI_NO_SCRIPT_ROOM =-57 @@ -238,6 +249,14 @@ PI_SOCK_READ_FAILED =-59 PI_SOCK_WRIT_FAILED =-60 PI_TOO_MANY_PARAM =-61 PI_NOT_HALTED =-62 +PI_BAD_TAG =-63 +PI_BAD_MICS_DELAY =-64 +PI_BAD_MILS_DELAY =-65 +PI_BAD_WAVE_ID =-66 +PI_TOO_MANY_CBS =-67 +PI_TOO_MANY_OOL =-68 +PI_EMPTY_WAVEFORM =-69 +PI_NO_WAVEFORM_ID =-70 # pigpio error text @@ -285,15 +304,15 @@ _errors=[ [PI_BAD_WVSC_COMMND , "bad WVSC subcommand"], [PI_BAD_WVSM_COMMND , "bad WVSM subcommand"], [PI_BAD_WVSP_COMMND , "bad WVSP subcommand"], - [PI_BAD_PULSELEN , "trigger pulse length > 100"], + [PI_BAD_PULSELEN , "trigger pulse length > 50"], [PI_BAD_SCRIPT , "invalid script"], [PI_BAD_SCRIPT_ID , "unknown script id"], [PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"], [PI_GPIO_IN_USE , "gpio already in use"], [PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"], [PI_BAD_PARAM_NUM , "script parameter must be 0-9"], - [PI_DUP_LABEL , "script has duplicate label"], - [PI_TOO_MANY_LABELS , "script has too many labels"], + [PI_DUP_TAG , "script has duplicate tag"], + [PI_TOO_MANY_TAGS , "script has too many tags"], [PI_BAD_SCRIPT_CMD , "illegal script command"], [PI_BAD_VAR_NUM , "script variable must be 0-149"], [PI_NO_SCRIPT_ROOM , "no more room for scripts"], @@ -302,6 +321,14 @@ _errors=[ [PI_SOCK_WRIT_FAILED , "socket write failed"], [PI_TOO_MANY_PARAM , "too many script parameters (> 10)"], [PI_NOT_HALTED , "script already running or failed"], + [PI_BAD_TAG , "script has unresolved tag"], + [PI_BAD_MICS_DELAY , "bad MICS delay (too large)"], + [PI_BAD_MILS_DELAY , "bad MILS delay (too large)"], + [PI_BAD_WAVE_ID , "non existent wave id"], + [PI_TOO_MANY_CBS , "No more CBs for waveform"], + [PI_TOO_MANY_OOL , "No more OOL for waveform"], + [PI_EMPTY_WAVEFORM , "attempt to create an empty waveform"], + [PI_NO_WAVEFORM_ID , "No more waveform ids"], ] @@ -402,11 +429,9 @@ def _pigpio_command_ext(sock, cmd, p1, p2, extents): extents: additional data blocks """ if sock is not None: - sock.send(struct.pack('IIII', cmd, p1, p2, 0)) - - for ext in extents: - sock.sendall(ext) - + msg = struct.pack('IIII', cmd, p1, p2, 0) + for ext in extents: msg += ext + sock.sendall(msg) x, y, z, res = struct.unpack('IIII', sock.recv(16)) return res else: @@ -523,7 +548,7 @@ class _wait_for_edge: _notify.append(self.callb) self.start = time.time() while (self.trigger == False) and ((time.time()-self.start) < timeout): - time.sleep(0.1) + time.sleep(0.05) _notify.remove(self.callb) def func(self, gpio, level, tick): @@ -916,7 +941,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth): Example 1: standard 50 Hz hobby servo updates - #!/usr/bin/python + #!/usr/bin/env python import pigpio import time @@ -943,7 +968,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth): Example 2: 400 Hz ESC type servo updates - #!/usr/bin/python + #!/usr/bin/env python import pigpio import time @@ -1102,7 +1127,7 @@ def set_watchdog(user_gpio, timeout): Example - #!/usr/bin/python + #!/usr/bin/env python import pigpio import time @@ -1189,7 +1214,7 @@ def clear_bank_1(levels): Example - #!/usr/bin/python + #!/usr/bin/env python import pigpio @@ -1255,7 +1280,7 @@ def set_bank_1(levels): Example - #!/usr/bin/python + #!/usr/bin/env python import pigpio @@ -1317,7 +1342,7 @@ def get_current_tick(): Example - #!/usr/bin/python + #!/usr/bin/env python import pigpio import time @@ -1406,26 +1431,19 @@ class pulse: def wave_clear(): """ - Initialises a new waveform. - - Returns 0 if OK. - - A waveform comprises one of more pulses. - - A pulse specifies - - 1) the gpios to be switched on at the start of the pulse. - 2) the gpios to be switched off at the start of the pulse. - 3) the delay in microseconds before the next pulse. - - Any or all the fields can be zero. It doesn't make any sense - to set all the fields to zero (the pulse will be ignored). - - When a waveform is started each pulse is executed in order with - the specified delay between the pulse and the next. + Clears all waveforms and any data added by calls to the + wave_add_* functions. """ return _u2i(_pigpio_command(_control, _PI_CMD_WVCLR, 0, 0)) +def wave_add_new(): + """ + Starts a new empty waveform. You wouldn't normally need + to call this function as it is automatically called after a + waveform is created with the wave_create function. + """ + return _u2i(_pigpio_command(_control, _PI_CMD_WVNEW, 0, 0)) + def wave_add_generic(pulses): """ Adds a list of pulses to the current waveform. @@ -1447,62 +1465,54 @@ def wave_add_generic(pulses): Example - #!/usr/bin/env python - import time + import pigpio - class stepper: - - def __init__(self, g1, g2, g3, g4): - self.g1 = g1 - self.g2 = g2 - self.g3 = g3 - self.g4 = g4 - self.all = (1< */ /* -This version is for pigpio version 11+ +This version is for pigpio version 14+ */ #include @@ -59,6 +59,8 @@ static unsigned DMAsecondaryChannel = PI_DEFAULT_DMA_SECONDARY_CHANNEL; static unsigned socketPort = PI_DEFAULT_SOCKET_PORT; static uint64_t updateMask = -1; +static int updateMaskSet = 0; + static FILE * errFifo; void fatal(char *fmt, ...) @@ -183,7 +185,11 @@ static void initOpts(int argc, char *argv[]) case 'x': mask = strtoll(optarg, &endptr, 0); printf("mask=%llx\n", mask); - if (!*endptr) updateMask = mask; + if (!*endptr) + { + updateMask = mask; + updateMaskSet = 1; + } else fatal("invalid -x option (%s)", optarg); break; @@ -264,7 +270,7 @@ int main(int argc, char **argv) gpioCfgSocketPort(socketPort); - if (updateMask != -1) gpioCfgPermissions(updateMask); + if (updateMaskSet) gpioCfgPermissions(updateMask); /* start library */ diff --git a/pigpiod_if.c b/pigpiod_if.c index 2fab6d0..b5cc3e7 100644 --- a/pigpiod_if.c +++ b/pigpiod_if.c @@ -606,6 +606,9 @@ uint32_t get_pigpio_version(void) int wave_clear(void) {return pigpio_command(gPigCommand, PI_CMD_WVCLR, 0, 0);} +int wave_add_new(void) + {return pigpio_command(gPigCommand, PI_CMD_WVNEW, 0, 0);} + int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses) { gpioExtent_t ext[1]; @@ -617,6 +620,8 @@ int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses) gpioPulse_t[] pulses */ + if (!numPulses) return 0; + ext[0].size = numPulses * sizeof(gpioPulse_t); ext[0].ptr = pulses; @@ -637,6 +642,8 @@ int wave_add_serial( char[] str */ + if (!numChar) return 0; + ext[0].size = sizeof(unsigned); ext[0].ptr = &baud; @@ -649,18 +656,30 @@ int wave_add_serial( return pigpio_command_ext(gPigCommand, PI_CMD_WVAS, gpio, numChar, 3, ext); } +int wave_create(void) + {return pigpio_command(gPigCommand, PI_CMD_WVCRE, 0, 0);} + +int wave_delete(unsigned wave_id) + {return pigpio_command(gPigCommand, PI_CMD_WVDEL, wave_id, 0);} + +int wave_tx_start(void) /* DEPRECATED */ + {return pigpio_command(gPigCommand, PI_CMD_WVGO, 0, 0);} + +int wave_tx_repeat(void) /* DEPRECATED */ + {return pigpio_command(gPigCommand, PI_CMD_WVGOR, 0, 0);} + +int wave_send_once(unsigned wave_id) + {return pigpio_command(gPigCommand, PI_CMD_WVTX, 0, 0);} + +int wave_send_repeat(unsigned wave_id) + {return pigpio_command(gPigCommand, PI_CMD_WVTXR, 0, 0);} + int wave_tx_busy(void) {return pigpio_command(gPigCommand, PI_CMD_WVBSY, 0, 0);} int wave_tx_stop(void) {return pigpio_command(gPigCommand, PI_CMD_WVHLT, 0, 0);} -int wave_tx_start(void) - {return pigpio_command(gPigCommand, PI_CMD_WVGO, 0, 0);} - -int wave_tx_repeat(void) - {return pigpio_command(gPigCommand, PI_CMD_WVGOR, 0, 0);} - int wave_get_micros(void) {return pigpio_command(gPigCommand, PI_CMD_WVSM, 0, 0);} @@ -743,10 +762,10 @@ int run_script(unsigned script_id, unsigned numPar, uint32_t *param) (gPigCommand, PI_CMD_PROCR, script_id, numPar, 1, ext); } -int script_status(int script_id, uint32_t *param) +int script_status(unsigned script_id, uint32_t *param) { int status; - uint32_t p[MAX_SCRIPT_PARAMS]; + uint32_t p[PI_MAX_SCRIPT_PARAMS]; status = pigpio_command(gPigCommand, PI_CMD_PROCP, script_id, 0); diff --git a/pigpiod_if.h b/pigpiod_if.h index 809800c..ef01ca8 100644 --- a/pigpiod_if.h +++ b/pigpiod_if.h @@ -30,7 +30,7 @@ For more information, please refer to #include "pigpio.h" -#define PIGPIOD_IF_VERSION 4 +#define PIGPIOD_IF_VERSION 5 typedef enum { @@ -514,62 +514,18 @@ uint32_t get_pigpio_version(void); int wave_clear(void); -/* This function initialises a new waveform. +/* This function clears all waveforms and any data added by calls to the + wave_add_* functions. Returns 0 if OK. - - A waveform comprises one of more pulses. Each pulse consists of a - gpioPulse_t structure. - - typedef struct - { - uint32_t gpioOn; - uint32_t gpioOff; - uint32_t usDelay; - } gpioPulse_t; - - The fields specify - - 1) the gpios to be switched on at the start of the pulse. - 2) the gpios to be switched off at the start of the pulse. - 3) the delay in microseconds before the next pulse. - - Any or all the fields can be zero. It doesn't make any sense to - set all the fields to zero (the pulse will be ignored). - - When a waveform is started each pulse is executed in order with the - specified delay between the pulse and the next. */ -int wave_tx_busy(void); -/* This function checks to see if a waveform is currently being - transmitted. - - Returns 1 if a waveform is currently being transmitted, otherwise 0. -*/ - -int wave_tx_stop(void); -/* This function stops the transmission of the current waveform. +int wave_add_new(void); +/* This function starts a new empty waveform. You wouldn't normally need + to call this function as it is automatically called after a waveform is + created with the wave_create function. Returns 0 if OK. - - This function is intended to stop a waveform started with the repeat mode. -*/ - -int wave_tx_start(void); -/* This function transmits the current waveform. The waveform is - sent once. - - Returns the number of DMA control blocks in the waveform if OK, - otherwise PI_BAD_WAVE_MODE. -*/ - -int wave_tx_repeat(void); -/* This function transmits the current waveform. The waveform repeats - endlessly until wave_tx_stop is called. - - Returns the number of DMA control blocks in the waveform if OK, - otherwise PI_BAD_WAVE_MODE. */ int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses); @@ -578,7 +534,7 @@ int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses); Returns the new total number of pulses in the current waveform if OK, otherwise PI_TOO_MANY_PULSES. - The pulses are interleaved in time order within the existing waveform + The pulses are interleaved in time order within the existing waveform (if any). Merging allows the waveform to be built in parts, that is the settings @@ -607,6 +563,108 @@ int wave_add_serial the same waveform. */ +int wave_create(void); +/* This function creates a waveform from the data provided by the prior + calls to the wave_add_* functions. Upon success a positive wave id + is returned. + + The data provided by the wave_add_* functions is consumed by this + function. + + As many waveforms may be created as there is space available. The + wave id is passed to wave_send_* to specify the waveform to transmit. + + Normal usage would be + + Step 1. wave_clear to clear all waveforms and added data. + + Step 2. wave_add_* calls to supply the waveform data. + + Step 3. wave_create to create the waveform and get a unique id + + Repeat steps 2 and 3 as needed. + + Step 4. wave_send_* with the id of the waveform to transmit. + + A waveform comprises one or more pulses. Each pulse consists of a + gpioPulse_t structure. + + typedef struct + { + uint32_t gpioOn; + uint32_t gpioOff; + uint32_t usDelay; + } gpioPulse_t; + + The fields specify + + 1) the gpios to be switched on at the start of the pulse. + 2) the gpios to be switched off at the start of the pulse. + 3) the delay in microseconds before the next pulse. + + Any or all the fields can be zero. It doesn't make any sense to + set all the fields to zero (the pulse will be ignored). + + When a waveform is started each pulse is executed in order with the + specified delay between the pulse and the next. + + Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM, + PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL. +*/ + + +int wave_delete(unsigned wave_id); +/* This function deletes all created waveforms with ids greater than or + equal to wave_id. + + Wave ids are allocated in order, 0, 1, 2, etc. + + Returns 0 if OK, otherwise PI_BAD_WAVE_ID. +*/ + +int wave_tx_start(void); +/* This function is deprecated and should no longer be used. Use + wave_create/wave_send_* instead. +*/ + +int wave_tx_repeat(void); +/* This function is deprecated and should no longer be used. Use + wave_create/wave_send_* instead. +*/ + +int wave_send_once(unsigned wave_id); +/* This function transmits the waveform with id wave_id. The waveform + is sent once. + + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE. +*/ + +int wave_send_repeat(unsigned wave_id); +/* This function transmits the waveform with id wave_id. The waveform + cycles until cancelled (either by the sending of a new waveform or + by wave_tx_stop). + + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE. +*/ + + +int wave_tx_busy(void); +/* This function checks to see if a waveform is currently being + transmitted. + + Returns 1 if a waveform is currently being transmitted, otherwise 0. +*/ + +int wave_tx_stop(void); +/* This function stops the transmission of the current waveform. + + Returns 0 if OK. + + This function is intended to stop a waveform started with the repeat mode. +*/ + int wave_get_micros(void); /* This function returns the length in microseconds of the current waveform. @@ -675,7 +733,7 @@ int run_script(unsigned script_id, unsigned numPar, uint32_t *param); the script as param 0 to param 9.. */ -int script_status(int script_id, uint32_t *param); +int script_status(unsigned script_id, uint32_t *param); /* This function returns the run status of a stored script as well as the current values of parameters 0 to 9. diff --git a/pigs.c b/pigs.c index 35c47e4..3cce611 100644 --- a/pigs.c +++ b/pigs.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 13+ +This version is for pigpio version 14+ */ #include @@ -50,6 +50,8 @@ the commands available from pigpio. char command_buf[8192]; char response_buf[8192]; +#define SOCKET_OPEN_FAILED -1 + void fatal(char *fmt, ...) { char buf[128]; @@ -88,7 +90,7 @@ static int openSocket(void) err = getaddrinfo(addrStr, portStr, &hints, &res); - if (err) return -1; + if (err) return SOCKET_OPEN_FAILED; for (rp=res; rp!=NULL; rp=rp->ai_next) { @@ -101,7 +103,7 @@ static int openSocket(void) freeaddrinfo(res); - if (rp == NULL) return -1; + if (rp == NULL) return SOCKET_OPEN_FAILED; return sock; } @@ -156,7 +158,7 @@ void print_result(int sock, int rv, cmdCmd_t cmd) p = (uint32_t *)response_buf; - for (i=0; i= 0) && (ctl.eaten < len)) + { + if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0) { - l += (strlen(argv[i]) + 1); - if (l < sizeof(command_buf)) - {sprintf(command_buf+pp, "%s ", argv[i]); pp=l;} - } + command = p[0]; - if (pp) {command_buf[--pp] = 0;} - - ctl.flags = 0; - ctl.eaten = 0; - - len = strlen(command_buf); - idx = 0; - - while ((idx >= 0) && (ctl.eaten < len)) - { - if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0) + if (command < PI_CMD_SCRIPT) { - command = p[0]; - - if (command < PI_CMD_SCRIPT) + if (command == PI_CMD_HELP) + { + printf(cmdUsage); + } + else if (command == PI_CMD_PARSE) + { + cmdParseScript(v[1], &s, 1); + if (s.par) free (s.par); + } + else { cmd.cmd = command; cmd.p1 = p[1]; @@ -300,36 +311,46 @@ int main(int argc , char *argv[]) { case PI_CMD_WVAS: cmd.p2 = p[4]; - break; + break; case PI_CMD_PROC: cmd.p2 = 0; break; } - if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) + if (sock != SOCKET_OPEN_FAILED) { - put_extensions(sock, command, p, v); - - if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) == + if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) { - get_extensions(sock, command, cmd.res); + put_extensions(sock, command, p, v); - print_result(sock, cmdInfo[idx].rv, cmd); + if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) == + sizeof(cmdCmd_t)) + { + get_extensions(sock, command, cmd.res); + + print_result(sock, cmdInfo[idx].rv, cmd); + } + else fatal("recv failed, %m"); } - else fatal("recv failed, %m"); + else fatal("send failed, %m"); } - else fatal("send failed, %m"); + else fatal("connect failed"); } - else fatal("%s only allowed within a script", cmdInfo[idx].name); } - else fatal("%s? pigs h for help", cmdStr()); + else fatal("%s only allowed within a script", cmdInfo[idx].name); + } + else + { + if (idx == CMD_UNKNOWN_CMD) + fatal("%s? unknown command, pigs h for help", cmdStr()); + else + fatal("%s: bad parameter, pigs h for help", cmdStr()); } } - else fatal("connect failed, %m"); - close(sock); + if (sock >= 0) close(sock); return 0; } diff --git a/setup.py b/setup.py index dc6e304..14465f1 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from distutils.core import setup setup(name='pigpio', - version='1.4', + version='1.5', author='joan', author_email='joan@abyz.co.uk', maintainer='joan', diff --git a/tarball b/tarball new file mode 100755 index 0000000..aab4ff7 --- /dev/null +++ b/tarball @@ -0,0 +1,29 @@ +#!/bin/bash +# +rm -rf PIGPIO +mkdir PIGPIO +# +cp command.c PIGPIO +cp command.h PIGPIO +cp Makefile PIGPIO +cp MakeRemote PIGPIO +cp pig2vcd.c PIGPIO +cp pigpio.c PIGPIO +cp pigpio.h PIGPIO +cp pigpiod.c PIGPIO +cp pigpiod_if.c PIGPIO +cp pigpiod_if.h PIGPIO +cp pigpio.py PIGPIO +cp pigs.c PIGPIO +cp README PIGPIO +cp setup.py PIGPIO +cp UNLICENCE PIGPIO +cp x_pigpio.c PIGPIO +cp x_pigpio.py PIGPIO +cp x_pigpiod_if.c PIGPIO +cp x_pigs PIGPIO +cp x_pipe PIGPIO +# +zip -r pigpio-$1.zip PIGPIO +tar cvf pigpio-$1.tar PIGPIO + diff --git a/x_pigpio.c b/x_pigpio.c index d884f4d..c827a7b 100644 --- a/x_pigpio.c +++ b/x_pigpio.c @@ -1,6 +1,13 @@ /* gcc -o x_pigpio x_pigpio.c -lpigpio -lrt -lpthread sudo ./x_pigpio + +*** WARNING ************************************************ +* * +* All the tests make extensive use of gpio 4 (pin P1-7). * +* Ensure that either nothing or just a LED is connected to * +* gpio 4 before running any of the tests. * +************************************************************ */ #include @@ -448,17 +455,17 @@ void t6() gpioSetAlertFunc(GPIO, t6cbf); - for (t=0; t<10; t++) + for (t=0; t<5; t++) { time_sleep(0.1); p = 10 + (t*10); tp += p; - gpioTrigger(4, p, 1); + gpioTrigger(GPIO, p, 1); } time_sleep(0.2); - CHECK(6, 1, t6_count, 10, 0, "gpio trigger count"); + CHECK(6, 1, t6_count, 5, 0, "gpio trigger count"); CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length"); } @@ -553,16 +560,16 @@ void t9() p1 GPIO */ char *script="\ - ldap 0\ - ldva 0\ - label 0\ + lda p0\ + sta v0\ + tag 0\ w p1 1\ - milli 5\ + mils 5\ w p1 0\ - milli 5\ - dcrv 0\ - ldav 0\ - ldpa 9\ + mils 5\ + dcr v0\ + lda v0\ + sta p9\ jp 0"; printf("Script store/run/status/stop/delete tests.\n"); diff --git a/x_pigpio.py b/x_pigpio.py index 7b09908..55a63e3 100755 --- a/x_pigpio.py +++ b/x_pigpio.py @@ -1,5 +1,12 @@ #!/usr/bin/env python +#*** WARNING ************************************************ +#* * +#* All the tests make extensive use of gpio 4 (pin P1-7). * +#* Ensure that either nothing or just a LED is connected to * +#* gpio 4 before running any of the tests. * +#************************************************************ + import time import struct @@ -364,6 +371,50 @@ To the lascivious pleasing of a lute. c = pigpio.wave_get_max_cbs() CHECK(5, 21, c, 25016, 0, "wave get max cbs") + e = pigpio.wave_clear() + CHECK(5, 22, e, 0, 0, "wave clear") + + e = pigpio.wave_add_generic(wf) + CHECK(5, 23, e, 4, 0, "pulse, wave add generic") + + w1 = pigpio.wave_create() + CHECK(5, 24, w1, 0, 0, "wave create") + + e = pigpio.wave_send_repeat(w1) + CHECK(5, 25, e, 9, 0, "wave send repeat") + + oc = t5_count + time.sleep(5) + c = t5_count - oc + CHECK(5, 26, c, 50, 1, "callback") + + e = pigpio.wave_tx_stop() + CHECK(5, 27, e, 0, 0, "wave tx stop") + + e = pigpio.wave_add_serial(GPIO, BAUD, 5000000, TEXT) + CHECK(5, 28, e, 3405, 0, "wave add serial") + + w2 = pigpio.wave_create() + CHECK(5, 29, w2, 1, 0, "wave create") + + e = pigpio.wave_send_once(w2) + CHECK(5, 30, e, 6811, 0, "wave send once") + + oc = t5_count + time.sleep(3) + c = t5_count - oc + CHECK(5, 31, c, 0, 0, "callback") + + oc = t5_count + while pigpio.wave_tx_busy(): + time.sleep(0.1) + time.sleep(0.1) + c = t5_count - oc + CHECK(5, 32, c, 1702, 0, "wave tx busy, callback") + + e = pigpio.wave_delete(0) + CHECK(5, 33, e, 0, 0, "wave delete") + t6_count=0 t6_on=0 t6_on_tick=None @@ -388,15 +439,15 @@ def t6(): t6cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t6cbf) - for t in range(10): + for t in range(5): time.sleep(0.1) p = 10 + (t*10) tp += p; - pigpio.gpio_trigger(4, p, 1) + pigpio.gpio_trigger(GPIO, p, 1) time.sleep(0.5) - CHECK(6, 1, t6_count, 10, 0, "gpio trigger count") + CHECK(6, 1, t6_count, 5, 0, "gpio trigger count") CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length") @@ -480,16 +531,16 @@ def t9(): # p0 number of loops # p1 GPIO script=""" - ldap 0 - ldva 0 - label 0 + lda p0 + sta v0 + tag 0 w p1 1 - milli 5 + mils 5 w p1 0 - milli 5 - dcrv 0 - ldav 0 - ldpa 9 + mils 5 + dcr v0 + lda v0 + sta p9 jp 0""" t9cb = pigpio.callback(GPIO) diff --git a/x_pigpiod_if.c b/x_pigpiod_if.c index 9ae3229..787c6d4 100644 --- a/x_pigpiod_if.c +++ b/x_pigpiod_if.c @@ -1,6 +1,13 @@ /* gcc -o x_pigpiod_if x_pigpiod_if.c -lpigpiod_if -lrt -lpthread sudo ./x_pigpiod_if + +*** WARNING ************************************************ +* * +* All the tests make extensive use of gpio 4 (pin P1-7). * +* Ensure that either nothing or just a LED is connected to * +* gpio 4 before running any of the tests. * +************************************************************ */ #include @@ -429,17 +436,17 @@ void t6() time_sleep(0.2); - for (t=0; t<10; t++) + for (t=0; t<5; t++) { time_sleep(0.1); p = 10 + (t*10); tp += p; - gpio_trigger(4, p, 1); + gpio_trigger(GPIO, p, 1); } time_sleep(0.5); - CHECK(6, 1, t6_count, 10, 0, "gpio trigger count"); + CHECK(6, 1, t6_count, 5, 0, "gpio trigger count"); CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length"); } @@ -540,16 +547,16 @@ void t9() p1 GPIO */ char *script="\ - ldap 0\ - ldva 0\ - label 0\ + lda p0\ + sta v0\ + tag 0\ w p1 1\ - milli 5\ + mils 5\ w p1 0\ - milli 5\ - dcrv 0\ - ldav 0\ - ldpa 9\ + mils 5\ + dcr v0\ + lda v0\ + sta p9\ jp 0"; callback(GPIO, RISING_EDGE, t9cbf); diff --git a/x_pigs b/x_pigs index 82d9124..9b1bc56 100755 --- a/x_pigs +++ b/x_pigs @@ -40,16 +40,16 @@ s=$(pigs bs2 0) if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi s=$(pigs h) -if [[ ${#s} = 2999 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi +if [[ ${#s} = 3315 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi s=$(pigs hwver) if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi -s=$(pigs micro 1000) -if [[ $s = "" ]]; then echo "MICRO ok"; else echo "MICRO fail ($s)"; fi +s=$(pigs mics 1000) +if [[ $s = "" ]]; then echo "MICS ok"; else echo "MICS fail ($s)"; fi -s=$(pigs milli 10) -if [[ $s = "" ]]; then echo "MILLI ok"; else echo "MILLI fail ($s)"; fi +s=$(pigs mils 10) +if [[ $s = "" ]]; then echo "MILS ok"; else echo "MILS fail ($s)"; fi s=$(pigs modes $GPIO 0) s=$(pigs modeg $GPIO) @@ -86,14 +86,14 @@ s=$(pigs pfs $GPIO 800) if [[ $s = 800 ]]; then echo "PFS-b ok"; else echo "PFS-b fail ($s)"; fi s=$(pigs pigpv) -if [[ $s = 13 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi +if [[ $s = 14 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi s=$(pigs prs $GPIO 255) if [[ $s = 250 ]]; then echo "PRG-a ok"; else echo "PRG-a fail ($s)"; fi s=$(pigs prg $GPIO) if [[ $s = 255 ]]; then echo "PRG-b ok"; else echo "PRG-b fail ($s)"; fi -p=$(pigs proc ldap 0 ldpa 1 ldai 1234 ldpa 0 label 999 milli 1000 jmp 999) +p=$(pigs proc ld p1 p0 ld p0 1234 tag 999 mils 1000 jmp 999) if [[ $p -ge 0 && $p -le 31 ]] then echo "PROC($p) ok" else echo "PROC($p) fail ($s)" @@ -186,10 +186,10 @@ fi s=$(pigs slrc $GPIO) if [[ $s = 0 ]]; then echo "SLR-g ok"; else echo "SLR-g fail ($s)"; fi -t1=$(pigs t) -t2=$(pigs tick) -s=$(($t2-$t1)) -if [[ $s -gt 0 && $s -lt 20000 ]] +t=$(pigs t tick) +v=(${t// / }) +s=$((v[1]-v[0])) +if [[ $s -gt 0 && $s -lt 2000 ]] then echo "TICK ok" else echo "TICK fail($s)" fi diff --git a/x_pipe b/x_pipe index 16eb209..0dfb534 100755 --- a/x_pipe +++ b/x_pipe @@ -46,14 +46,14 @@ if [[ $s = 0 ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi echo "h" >/dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio +echo "mics 1000" >/dev/pigpio read -t 1 s /dev/pigpio +echo "mils 10" >/dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio +echo "proc ld p1 p0 ld p0 29 tag 9 mils 1000 jmp 9" >/dev/pigpio read -t 1 p