diff --git a/Makefile b/Makefile index 9b1e561..bfb0beb 100644 --- a/Makefile +++ b/Makefile @@ -13,17 +13,22 @@ OBJ2 = pigpiod_if.o command.o LIB = $(LIB1) $(LIB2) -ALL = $(LIB) checklib pig2vcd pigpiod pigs +ALL = $(LIB) x_pigpio x_pigpiod_if pig2vcd pigpiod pigs -LL = -L. -lpigpio -lpthread -lrt +LL1 = -L. -lpigpio -lpthread -lrt + +LL2 = -L. -lpigpiod_if -lpthread -lrt all: $(ALL) -checklib: checklib.o $(LIB1) - $(CC) -o checklib checklib.c $(LL) +x_pigpio: x_pigpio.o $(LIB1) + $(CC) -o x_pigpio x_pigpio.c $(LL1) + +x_pigpiod_if: x_pigpiod_if.o $(LIB2) + $(CC) -o x_pigpiod_if x_pigpiod_if.c $(LL2) pigpiod: pigpiod.o $(LIB1) - $(CC) -o pigpiod pigpiod.c $(LL) + $(CC) -o pigpiod pigpiod.c $(LL1) pigs: pigs.o command.o $(CC) -o pigs pigs.c command.c @@ -35,6 +40,7 @@ clean: rm -f *.o *.i *.s *~ $(ALL) install: $(LIB) + sudo install -m 0755 -d /opt/pigpio/cgi sudo install -m 0755 -d /usr/local/include sudo install -m 0644 pigpio.h /usr/local/include sudo install -m 0644 pigpiod_if.h /usr/local/include @@ -68,7 +74,8 @@ $(LIB2): $(OBJ2) # generated using gcc -MM *.c -checklib.o: checklib.c pigpio.h +x_pigpio.o: x_pigpio.c pigpio.h +x_pigpiod_if.o: x_pigpiod_if.c command.o: command.c pigpio.h command.h pig2vcd.o: pig2vcd.c pigpio.h pigpio.o: pigpio.c pigpio.h command.h diff --git a/README b/README index 8737d36..d04da3c 100644 --- a/README +++ b/README @@ -20,18 +20,28 @@ o the socket interface (pigs) in /usr/local/bin o the utility pig2vcd in /usr/local/bin o the Python module pigpio.py -TEST +TEST (optional) To test the library do -sudo ./checklib +sudo ./x_pigpio + +To text the pigpio daemon do + +sudo pigpiod + +./x_pigpiod_if # test the C I/F to the pigpio daemon +./x_pigpio.py # test the Python I/F to the pigpio daemon +./x_pigs # test the socket I/F to the pigpio daemon +./x_pipe # test the pipe I/F to the pigpio daemon EXAMPLE CODE -checklib.c, pig2vcd.c, and pigpiod.c -show examples of interfacing with the pigpio library. +x_pigpio.c, pig2vcd.c, and pigpiod.c show examples of interfacing +with the pigpio library. -pigs.c and pigpio.py show examples of interfacing with the pigpiod daemon. +pigs.c, pigpio.py, x_pigpiod_if.c, x_pigpio.py, x_pigs, and x_pipe +show examples of interfacing with the pigpiod daemon. DAEMON @@ -77,25 +87,6 @@ pythonx.y setup.py install where x.y is the Python version. -If the pigpiod daemon is running you can test the Python module -by entering the following commands. - -python - -import pigpio - -pigpio.start() - -print(pigpio.get_current_tick()) - -print(hex(pigpio.read_bank_1())) - -pigpio.stop() - -help(pigpio) - -quit() - STOP DAEMON To stop the pigpiod daemon @@ -105,7 +96,7 @@ sudo killall pigpiod RUNNING ON NON Pi's You can access the pigpiod daemon running on the Pi from any machine which -can access it over the network. This access is via the socket interface. +is connected to it over the network. This access is via the socket interface. In particular this allows you to use the following on non-Pi's. diff --git a/command.c b/command.c index 757b082..9bf8f9b 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 12+ +This version is for pigpio version 13+ */ #include @@ -58,135 +58,204 @@ This version is for pigpio version 12+ 7 cmd %x 8 MODES %d %c 9 PUD %d %c -10 PROG %s +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 ext */ + /* 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_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_BC1, "BC1", 7, 1, 0}, - {PI_CMD_BC2, "BC2", 7, 1, 0}, - {PI_CMD_BR1, "BR1", 1, 3, 0}, - {PI_CMD_BR2, "BR2", 1, 3, 0}, - {PI_CMD_BS1, "BS1", 7, 1, 0}, - {PI_CMD_BS2, "BS2", 7, 1, 0}, - {PI_CMD_HELP, "H", 6, 5, 0}, - {PI_CMD_HELP, "HELP", 6, 5, 0}, - {PI_CMD_HWVER, "HWVER", 1, 4, 0}, - {PI_CMD_MODEG, "MG" , 2, 2, 0}, - {PI_CMD_MODEG, "MODEG", 2, 2, 0}, - {PI_CMD_MODES, "M", 8, 0, 0}, - {PI_CMD_MODES, "MODES", 8, 0, 0}, - {PI_CMD_NB, "NB", 4, 0, 0}, - {PI_CMD_NC, "NC", 2, 0, 0}, - {PI_CMD_NO, "NO", 1, 2, 0}, - {PI_CMD_NP, "NP", 2, 0, 0}, - {PI_CMD_PFG, "PFG", 2, 2, 0}, - {PI_CMD_PFS, "PFS", 3, 2, 0}, - {PI_CMD_PIGPV, "PIGPV", 1, 4, 0}, - {PI_CMD_PRG, "PRG", 2, 2, 0}, - {PI_CMD_PROC, "PROC", 10, 2, 1}, - {PI_CMD_PROCD, "PROCD", 2, 2, 0}, - {PI_CMD_PROCR, "PROCR", 2, 2, 0}, - {PI_CMD_PROCS, "PROCS", 2, 2, 0}, - {PI_CMD_PRRG, "PRRG", 2, 2, 0}, - {PI_CMD_PRS, "PRS", 3, 2, 0}, - {PI_CMD_PUD, "PUD", 9, 0, 0}, - {PI_CMD_PWM, "P", 3, 0, 0}, - {PI_CMD_PWM, "PWM", 3, 0, 0}, - {PI_CMD_READ, "R", 2, 2, 0}, - {PI_CMD_READ, "READ", 2, 2, 0}, - {PI_CMD_SERVO, "S", 3, 0, 0}, - {PI_CMD_SERVO, "SERVO", 3, 0, 0}, - {PI_CMD_SLR, "SLR", 3, 6, 0}, - {PI_CMD_SLRC, "SLRC", 2, 2, 0}, - {PI_CMD_SLRO, "SLRO", 3, 2, 0}, - {PI_CMD_WDOG, "WDOG", 3, 0, 0}, - {PI_CMD_WRITE, "W", 3, 0, 0}, - {PI_CMD_WRITE, "WRITE", 3, 0, 0}, - {PI_CMD_TICK, "T", 1, 4, 0}, - {PI_CMD_TICK, "TICK", 1, 4, 0}, - {PI_CMD_TRIG, "TRIG", 5, 0, 1}, - {PI_CMD_WVAS, "WVAS", 11, 2, 3}, - {PI_CMD_WVBSY, "WVBSY", 1, 2, 0}, - {PI_CMD_WVCLR, "WVCLR", 1, 2, 0}, - {PI_CMD_WVGO, "WVGO" , 1, 2, 0}, - {PI_CMD_WVGOR, "WVGOR", 1, 2, 0}, - {PI_CMD_WVHLT, "WVHLT", 1, 2, 0}, - {PI_CMD_WVSC, "WVSC", 2, 2, 0}, - {PI_CMD_WVSM, "WVSM", 2, 2, 0}, - {PI_CMD_WVSP, "WVSP", 2, 2, 0}, }; char * cmdUsage = "\ -BC1 x Clear gpios x in bank 1.\n\ -BC2 x Clear gpios x in bank 2.\n\ -BR1 Read gpios bank 1.\n\ -BR2 Read gpios bank 2.\n\ -BS1 x Set gpios x in bank 1.\n\ -BS2 x Set gpios x 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\ -MODEG g Get gpio g mode.\n\ -MODES g m Set gpio g to mode m.\n\ -NB h x Start notifications on handle h with x.\n\ -NC h Close notification handle h.\n\ -NO Request notification handle.\n\ -NP h Pause notifications on handle h.\n\ -P u d Set PWM value for user gpio u to d.\n\ -PFG u Get PWM frequency for user gpio u.\n\ -PFS u d Set PWM frequency for user gpio u to d.\n\ -PIGPV Return pigpio version.\n\ -PRG u Get PWM range for user gpio u.\n\ -PROC t Store text t of script.\n\ -PROCD s Delete script s.\n\ -PROCR s Run script s.\n\ -PROCS s Stop script s.\n\ -PRRG u Get PWM real range for user gpio u.\n\ -PRS u d Set PWM range for user gpio u to d.\n\ -PUD g p Set gpio pull up/down for gpio g to p.\n\ -PWM u d Set PWM value for user gpio u to d.\n\ -R g Read gpio g.\n\ -READ g Read gpio g.\n\ -S u d Set servo value for user gpio u to d microseconds.\n\ -SERVO u d Set servo value for user gpio u to d microseconds.\n\ -SLR u d 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\ -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 d Set watchdog of d milliseconds on user gpio u.\n\ -WRITE g L Write level L to gpio g.\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\ -WVHLT Wave stop.\n\ -WVSC ws Wave get DMA control block stats.\n\ -WVSM ws Wave get micros stats.\n\ -WVSP ws Wave get pulses stats.\n\ -.\n\ +BC1 v Clear gpios defined by mask v in bank 1.\n\ +BC2 v Clear gpios defined 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\ +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\ +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\ +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\ +PFG u Get PWM frequency for user gpio u.\n\ +PFS u v Set PWM frequency for user gpio u to d.\n\ +PIGPV Return pigpio version.\n\ +PRG u Get PWM range for user gpio u.\n\ +PROC t Store text t of script.\n\ +PROCD s Delete script s.\n\ +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\ +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\ +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\ +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\ +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\ +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\ +WVHLT Wave stop.\n\ +WVSC ws Wave get DMA control block stats.\n\ +WVSM ws Wave get micros stats.\n\ +WVSP ws Wave get pulses stats.\n\ +\n\ b = baud rate.\n\ -d = decimal value.\n\ -g = gpio (0-53).\n\ +g = any gpio (0-53).\n\ h = handle (0-31).\n\ L = level (0-1).\n\ m = mode (RW540123).\n\ +mask = a bit mask where (1< 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_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"}, + {PI_NO_MEMORY , "can't allocate temporary memory"}, + {PI_SOCK_READ_FAILED , "socket read failed"}, + {PI_SOCK_WRIT_FAILED , "socket write failed"}, + {PI_TOO_MANY_PARAM , "too many script parameters > 10"}, + {PI_NOT_HALTED , "script already running or failed"}, + }; static char * fmtMdeStr="RW540123"; static char * fmtPudStr="ODU"; -static int cmdMatch(char * str) +static int cmdMatch(char *str) { int i; @@ -264,65 +345,117 @@ static int cmdMatch(char * str) return -1; } -int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext) +static int getNum(char *str, unsigned *val, uint8_t *opt, int flags) { - char str[8]; - int f, valid, idx, val, p; + int f, n, v; + + *opt = 0; + + f = sscanf(str, " %i %n", &v, &n); + + if (f == 1) + { + *val = v; + *opt = CMD_NUMERIC; + return n; + } + + if (flags & PARSE_FLAGS_PARAMS) + { + f = sscanf(str, " p%i %n", &v, &n); + + if (f == 1) + { + *val = v; + *opt = CMD_PARAM; + return n; + } + } + + if (flags & PARSE_FLAGS_VARS) + { + f = sscanf(str, " v%i %n", &v, &n); + + if (f == 1) + { + *val = v; + *opt = CMD_VAR; + return n; + } + } + + return 0; +} + +static char intCmdStr[32]; + +char *cmdStr(void) +{ + return intCmdStr; +} + +int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl) +{ + int f, valid, idx, val, pp, pars, n, n2, i; char *ptr; - char c, t; + char c; + int param[MAX_PARAM]; - sscanf(buf, " %7s", str); + bzero(&ctl->opt, sizeof(ctl->opt)); - cmd->cmd = -1; + sscanf(buf+ctl->eaten, " %31s", intCmdStr); - idx = cmdMatch(str); + p[0] = -1; + + idx = cmdMatch(intCmdStr); if (idx < 0) return idx; + sscanf(buf+ctl->eaten, " %*31s %n", &pp); + + ctl->eaten += pp; + valid = 0; - cmd->cmd = cmdInfo[idx].cmd; - cmd->p1 = 0; - cmd->p2 = 0; + p[0] = cmdInfo[idx].cmd; + p[1] = 0; + p[2] = 0; switch (cmdInfo[idx].vt) { - case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO + case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO WVGOR WVHLT */ - f = sscanf(buf, " %7s %c", str, &t); - if (f == 1) valid = 1; + valid = 1; break; - case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG + case 2: /* MODEG NC NP PFG PRG PROCD PROCS PRRG SLRC READ WVSC WVSM WVSP */ - f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t); - if (f == 2) valid = 1; + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); + if (ctl->opt[0]) valid = 1; break; case 3: /* PFS PRS PWM SERVO SLR SLRO WDOG WRITE */ - f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t); - if (f == 3) valid = 1; + 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; break; case 4: /* NB */ - f = sscanf(buf, " %7s %d %x %c", str, &cmd->p1, &cmd->p2, &t); - if (f == 3) valid = 1; + 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; break; case 5: /* TRIG */ - f = sscanf(buf, " %7s %d %d %d %c", - str, &cmd->p1, &cmd->p2, &ext[0].data, &t); - if (f == 4) - { - ext[0].size = sizeof(unsigned); - ext[0].ptr = &ext[0].data; - valid = 1; - } + 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; break; case 6: /* HELP @@ -332,21 +465,23 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext case 7: /* BC1 BC2 BS1 BS2 */ - f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t); - if (f == 2) valid = 1; + ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags); + if (ctl->opt[0]) valid = 1; break; case 8: /* MODES */ - f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t); - if (f == 3) + 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; - cmd->p2 = val; + p[2] = val; valid = 1; } } @@ -354,15 +489,17 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext case 9: /* PUD */ - f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t); - if (f == 3) + 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; - cmd->p2 = val; + p[2] = val; valid = 1; } } @@ -370,51 +507,167 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext case 10: /* PROC */ - if ((argc == 0) || (argc == 3)) - { - if (argc == 3) - { - cmd->p1 = strlen(argv[2]); - ext[0].ptr = argv[2]; - } - else /* pipe i/f */ - { - sscanf(buf, "%*s %n", &p); - cmd->p1 = strlen(buf+p); - ext[0].ptr = buf+p; - } - ext[0].size = cmd->p1; - valid = 1; - } + p[1] = strlen(buf+ctl->eaten); + v[1] = buf+ctl->eaten; + ctl->eaten += p[1]; + valid = 1; break; case 11: /* WVAS */ - if ((argc == 0) || (argc == 6)) + 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]) { - f = sscanf(buf, " %*s %d %d %d %n", - &cmd->p1, &ext[0].data, &ext[1].data, &p); - if (f == 3) + 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: /* + */ + f = sscanf(buf+ctl->eaten, " %*s%n %n", &n, &n2); + if ((f >= 0) && n) + { + valid = 1; + + for (i=0; ieaten+i]; - if (argc) /* pigs */ + if ((!isalnum(c)) && (c != '_') && (c != '-')) { - cmd->p2 = strlen(argv[5]); - ext[2].ptr = argv[5]; + valid = 0; + break; } - else /* pipe i/f */ - { - cmd->p2 = strlen(buf+p); - ext[2].ptr = buf+p; - } - - ext[2].size = cmd->p2; - valid = 1; } + + if (valid) + { + p[1] = n; + ctl->opt[0] = CMD_NUMERIC; + v[1]=buf+ctl->eaten; + 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)) + { + ctl->eaten += n; + valid = 1; } break; } @@ -432,3 +685,4 @@ char * cmdErrStr(int error) } return "unknown error"; } + diff --git a/command.h b/command.h index bdffefb..7e62405 100644 --- a/command.h +++ b/command.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 11+ +This version is for pigpio version 13+ */ #ifndef COMMAND_H @@ -37,23 +37,39 @@ This version is for pigpio version 11+ #include "pigpio.h" +#define MAX_PARAM 512 + +#define PARSE_FLAGS_PARAMS 1 +#define PARSE_FLAGS_VARS 2 + +#define CMD_NUMERIC 1 +#define CMD_PARAM 2 +#define CMD_VAR 3 + typedef struct { - int cmd; /* command number */ - char * name; /* command name */ - int vt; /* command verification type */ - int rv; /* command return value type */ - int ext; /* command has extensions */ + int flags; + int eaten; + uint8_t opt[8]; +} gpioCtlParse_t; + +typedef struct +{ + int cmd; /* command number */ + char *name; /* command name */ + int vt; /* command verification type */ + int rv; /* command return value type */ } cmdInfo_t; extern cmdInfo_t cmdInfo[]; -extern char * cmdUsage; +extern char *cmdUsage; -int cmdParse - (char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t * ext); +int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctlParse); -char * cmdErrStr(int error); +char *cmdErrStr(int error); + +char *cmdStr(void); #endif diff --git a/pigpio.c b/pigpio.c index cde0e58..b9cdb29 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 12 */ +/* pigpio version 13 */ #include #include @@ -254,13 +254,6 @@ bit 0 READ_LAST_NOT_SET_ERROR } \ while (0) -#define PERM_ERROR(format, arg...) \ - do \ - { \ - fprintf(stderr, "%s " format "\n", myTimeStamp(), ## arg); \ - } \ - while (0) - #define TIMER_ADD(a, b, result) \ do \ { \ @@ -491,20 +484,20 @@ bit 0 READ_LAST_NOT_SET_ERROR #define TIMED_DMA(x) (DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(x)) #define DBG_MIN_LEVEL 0 +#define DBG_ALWAYS 0 #define DBG_STARTUP 1 #define DBG_DMACBS 2 -#define DBG_USER 3 -#define DBG_INTERNAL 4 -#define DBG_SLOW_TICK 5 -#define DBG_FAST_TICK 6 -#define DBG_MAX_LEVEL 6 +#define DBG_SCRIPT 3 +#define DBG_USER 4 +#define DBG_INTERNAL 5 +#define DBG_SLOW_TICK 6 +#define DBG_FAST_TICK 7 +#define DBG_MAX_LEVEL 8 #define GPIO_UNDEFINED 0 -#define GPIO_INPUT 1 -#define GPIO_OUTPUT 2 -#define GPIO_PWM 3 -#define GPIO_SERVO 4 -#define GPIO_ALTERNATE 5 +#define GPIO_WRITE 1 +#define GPIO_PWM 2 +#define GPIO_SERVO 3 #define STACK_SIZE (256*1024) @@ -515,16 +508,17 @@ bit 0 READ_LAST_NOT_SET_ERROR #define CYCLES_PER_BLOCK 80 #define PULSE_PER_CYCLE 25 -#define PAGES_PER_BLOCK 53 +#define PAGES_PER_BLOCK 53 -#define CBS_PER_IPAGE 117 -#define LVS_PER_IPAGE 38 -#define OFF_PER_IPAGE 38 -#define TCK_PER_IPAGE 2 -#define ON_PER_IPAGE 2 +#define CBS_PER_IPAGE 117 +#define LVS_PER_IPAGE 38 +#define OFF_PER_IPAGE 38 +#define TCK_PER_IPAGE 2 +#define ON_PER_IPAGE 2 +#define PAD_PER_IPAGE 7 -#define CBS_PER_OPAGE 118 -#define ONOFF_PER_OPAGE 79 +#define CBS_PER_OPAGE 118 +#define OOL_PER_OPAGE 79 #define CBS_PER_CYCLE ((PULSE_PER_CYCLE*3)+2) @@ -535,12 +529,14 @@ bit 0 READ_LAST_NOT_SET_ERROR #define BLOCK_SIZE (PAGES_PER_BLOCK*PAGE_SIZE) -#define DMA_PAGES (PAGES_PER_BLOCK * bufferBlocks) +#define DMAI_PAGES (PAGES_PER_BLOCK * bufferBlocks) + +#define DMAO_PAGES (PAGES_PER_BLOCK * PI_WAVE_BLOCKS) + +#define NUM_OOL (DMAO_PAGES * OOL_PER_OPAGE) #define TICKSLOTS 50 -#define PI_NOTIFY_SLOTS 32 - #define PI_NOTIFY_CLOSED 0 #define PI_NOTIFY_CLOSING 1 #define PI_NOTIFY_OPENED 2 @@ -549,7 +545,7 @@ bit 0 READ_LAST_NOT_SET_ERROR #define PI_WFRX_NONE 0 #define PI_WFRX_SERIAL 1 -#define PI_WF_MICROS 2 +#define PI_WF_MICROS 1 #define DATUMS 2000 @@ -558,7 +554,7 @@ bit 0 READ_LAST_NOT_SET_ERROR #define MAX_EMITS (PIPE_BUF / sizeof(gpioReport_t)) #define SRX_BUF_SIZE 8192 -#define CMD_BUF_SIZE 2048 +#define CMD_BUF_SIZE 4096 /* --------------------------------------------------------------- */ @@ -587,13 +583,13 @@ typedef struct uint32_t tick [TCK_PER_IPAGE]; uint32_t gpioOn [ON_PER_IPAGE]; uint32_t periphData; - uint32_t pad[7]; + uint32_t pad [PAD_PER_IPAGE]; } dmaIPage_t; typedef struct { - dmaCbs_t cb [CBS_PER_OPAGE]; - uint32_t gpioOnOff [ONOFF_PER_OPAGE]; + dmaCbs_t cb [CBS_PER_OPAGE]; + uint32_t OOL [OOL_PER_OPAGE]; uint32_t periphData; } dmaOPage_t; @@ -630,6 +626,12 @@ typedef struct uint32_t bits; } gpioGetSamples_t; +typedef struct +{ + uint32_t label; + int step; +} gpioLabelStep_t; + typedef struct { callbk_t func; @@ -642,6 +644,51 @@ typedef struct pthread_t pthId; } gpioTimer_t; +#define PI_SCRIPT_FREE 0 +#define PI_SCRIPT_RESERVED 1 +#define PI_SCRIPT_IN_USE 2 +#define PI_SCRIPT_DYING 3 + +#define PI_SCRIPT_HALT 0 +#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; + unsigned state; + unsigned request; + unsigned run_state; + uint32_t waitBits; + uint32_t changedBits; + 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; +} gpioScript_t; + + typedef struct { uint16_t valid; @@ -752,7 +799,7 @@ static struct timespec libStarted; static uint64_t gpioMask; -static gpioPulse_t wf[3][PI_WAVE_MAX_PULSES]; +static gpioWave_t wf[3][PI_WAVE_MAX_PULSES]; static int wfc[3]={0, 0, 0}; @@ -762,14 +809,15 @@ static wfStats_t wfStats= { 0, 0, PI_WAVE_MAX_MICROS, 0, 0, PI_WAVE_MAX_PULSES, - 0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE) + 0, 0, (DMAO_PAGES * CBS_PER_OPAGE) }; static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1]; -static volatile uint32_t alertBits = 0; -static volatile uint32_t monitorBits = 0; -static volatile uint32_t notifyBits = 0; +static volatile uint32_t alertBits = 0; +static volatile uint32_t monitorBits = 0; +static volatile uint32_t notifyBits = 0; +static volatile uint32_t scriptBits = 0; static volatile int DMAstarted = 0; @@ -787,6 +835,8 @@ static gpioInfo_t gpioInfo [PI_MAX_USER_GPIO+1]; static gpioNotify_t gpioNotify [PI_NOTIFY_SLOTS]; +static gpioScript_t gpioScript [PI_SCRIPT_SLOTS]; + static gpioSignal_t gpioSignal [PI_MAX_SIGNUM+1]; static gpioTimer_t gpioTimer [PI_MAX_TIMER+1]; @@ -864,10 +914,15 @@ static const uint16_t pwmRealRange[PWM_FREQS]= /* ======================================================================= */ -static void intNotifyBits(void); +/* Internal prototypes. +*/ +static void intNotifyBits(void); +static void intScriptBits(void); static int gpioNotifyOpenInBand(int fd); +/* ======================================================================= */ + static void myGpioSleep(int seconds, int micros) { struct timespec ts, rem; @@ -878,11 +933,12 @@ static void myGpioSleep(int seconds, int micros) while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem)) { /* copy remaining time to ts */ - ts.tv_sec = rem.tv_sec; - ts.tv_nsec = rem.tv_nsec; + ts = rem; } } +/* ----------------------------------------------------------------------- */ + static uint32_t myGpioDelay(uint32_t micros) { uint32_t start; @@ -896,6 +952,8 @@ static uint32_t myGpioDelay(uint32_t micros) return (systReg[SYST_CLO] - start); } +/* ----------------------------------------------------------------------- */ + static char * myTimeStamp() { static struct timeval last; @@ -926,7 +984,7 @@ static void myCreatePipe(char * name, int perm) if (chmod(name, perm) < 0) { - DBG(DBG_MIN_LEVEL, "Can't set permissions (%d) for %s, %m", perm, name); + DBG(DBG_ALWAYS, "Can't set permissions (%d) for %s, %m", perm, name); return; } } @@ -985,30 +1043,176 @@ static uint32_t myGetTick(int pos) /* ----------------------------------------------------------------------- */ -static void myDoCommand - (cmdCmd_t *cmd, gpioExtent_t *iExt, gpioExtent_t *oExt) +static int myParseScript(char *script, gpioScript_t *s) { - int p1, p2, res, i; - uint32_t mask, tmp; + 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; +} + +/* ----------------------------------------------------------------------- */ + +static int myDoCommand(uint32_t *p, gpioExtent_t *oExt) +{ + int res, i, tmp; + uint32_t mask; gpioPulse_t *pulse; int masked; - p1 = cmd->p1; - p2 = cmd->p2; - res = cmd->res; + res = 0; - switch (cmd->cmd) + switch (p[0]) { case PI_CMD_BC1: mask = gpioMask; - res = gpioWrite_Bits_0_31_Clear(p1&mask); + res = gpioWrite_Bits_0_31_Clear(p[1]&mask); - if ((mask | p1) != mask) + if ((mask | p[1]) != mask) { - PERM_ERROR( + DBG(DBG_USER, "gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)", - p1, mask); + p[1], mask); res = PI_SOME_PERMITTED; } break; @@ -1016,13 +1220,13 @@ static void myDoCommand case PI_CMD_BC2: mask = gpioMask>>32; - res = gpioWrite_Bits_32_53_Clear(p1&mask); + res = gpioWrite_Bits_32_53_Clear(p[1]&mask); - if ((mask | p1) != mask) + if ((mask | p[1]) != mask) { - PERM_ERROR( + DBG(DBG_USER, "gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)", - p1, mask); + p[1], mask); res = PI_SOME_PERMITTED; } break; @@ -1034,13 +1238,13 @@ static void myDoCommand case PI_CMD_BS1: mask = gpioMask; - res = gpioWrite_Bits_0_31_Set(p1&mask); + res = gpioWrite_Bits_0_31_Set(p[1]&mask); - if ((mask | p1) != mask) + if ((mask | p[1]) != mask) { - PERM_ERROR( + DBG(DBG_USER, "gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)", - p1, mask); + p[1], mask); res = PI_SOME_PERMITTED; } break; @@ -1048,13 +1252,13 @@ static void myDoCommand case PI_CMD_BS2: mask = gpioMask>>32; - res = gpioWrite_Bits_32_53_Set(p1&mask); + res = gpioWrite_Bits_32_53_Set(p[1]&mask); - if ((mask | p1) != mask) + if ((mask | p[1]) != mask) { - PERM_ERROR( + DBG(DBG_USER, "gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)", - p1, mask); + p[1], mask); res = PI_SOME_PERMITTED; } break; @@ -1063,121 +1267,129 @@ static void myDoCommand case PI_CMD_HWVER: res = gpioHardwareRevision(); break; - case PI_CMD_MODEG: res = gpioGetMode(p1); break; + case PI_CMD_MICRO: myGpioDelay(p[1]); break; + + case PI_CMD_MILLI: myGpioDelay(p[1] * 1000); break; + + case PI_CMD_MODEG: res = gpioGetMode(p[1]); break; case PI_CMD_MODES: - if (gpioMask & (uint64_t)(1<= 0)) res = PI_SOME_PERMITTED; @@ -1215,17 +1429,13 @@ static void myDoCommand break; case PI_CMD_WVAS: - if (gpioMask & (uint64_t)(1<res = res; + return (res); } /* ----------------------------------------------------------------------- */ @@ -1390,8 +1600,8 @@ static void myGpioSetServo(unsigned gpio, int oldVal, int newVal) switchGpioOff = 0; - realRange = pwmRealRange[gpioInfo[gpio].freqIdx]; - cycles = pwmCycles [gpioInfo[gpio].freqIdx]; + realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx]; + cycles = pwmCycles [clkCfg[gpioCfg.clockMicros].servoIdx]; newOff = (newVal * realRange)/20000; oldOff = (oldVal * realRange)/20000; @@ -1462,17 +1672,35 @@ static uint32_t waveCbPOadr(int pos) return (uint32_t) &dmaOPhys[page]->cb[slot]; } +/* ----------------------------------------------------------------------- */ + +static void waveOOLPageSlot(int pos, int *page, int *slot) +{ + *page = pos/OOL_PER_OPAGE; + *slot = pos%OOL_PER_OPAGE; +} + /* ----------------------------------------------------------------------- */ -static uint32_t waveOnOffPOadr(int pos) +static void waveSetOOL(int pos, uint32_t OOL) { int page, slot; - page = pos/ONOFF_PER_OPAGE; - slot = pos%ONOFF_PER_OPAGE; + waveOOLPageSlot(pos, &page, &slot); - return (uint32_t) &dmaOPhys[page]->gpioOnOff[slot]; + dmaOVirt[page]->OOL[slot] = OOL; +} + +/* ----------------------------------------------------------------------- */ + +static uint32_t waveOOLPOadr(int pos) +{ + int page, slot; + + waveOOLPageSlot(pos, &page, &slot); + + return (uint32_t) &dmaOPhys[page]->OOL[slot]; } @@ -1491,7 +1719,7 @@ static void waveCbOPrint(int pos) /* ----------------------------------------------------------------------- */ -void waveBitDelay(unsigned baud, unsigned * bitDelay) +static void waveBitDelay(unsigned baud, unsigned * bitDelay) { unsigned fullBit, halfBit, s, e, d, m, i, err; @@ -1528,47 +1756,22 @@ void waveBitDelay(unsigned baud, unsigned * bitDelay) bitDelay[9] = (e-s)/100; } -/* ----------------------------------------------------------------------- */ - -void gpioWaveDump(void) -{ - int i; - - unsigned numPulses, t; - - gpioPulse_t * pulses; - - numPulses = wfc[wfcur]; - pulses = wf [wfcur]; - - t = 0; - - for (i=0; igpioOnOff[onoff%ONOFF_PER_OPAGE] = - pulses[i].gpioOn; + waveSetOOL(onoff, waves[i].gpioOn); p = waveCbVOadr(cb++); p->info = NORMAL_DMA; - p->src = waveOnOffPOadr(onoff++) | DMA_BUS_ADR; + p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR; p->dst = ((GPIO_BASE + (GPSET0*4)) & 0x00ffffff) | 0x7e000000; p->length = 4; p->next = waveCbPOadr(cb) | DMA_BUS_ADR; } - if (pulses[i].gpioOff) + if (waves[i].gpioOff) { - dmaOVirt[onoff/ONOFF_PER_OPAGE]->gpioOnOff[onoff%ONOFF_PER_OPAGE] = - pulses[i].gpioOff; + waveSetOOL(onoff, waves[i].gpioOff); p = waveCbVOadr(cb++); p->info = NORMAL_DMA; - p->src = waveOnOffPOadr(onoff++) | DMA_BUS_ADR; + p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR; p->dst = ((GPIO_BASE + (GPCLR0*4)) & 0x00ffffff) | 0x7e000000; p->length = 4; p->next = waveCbPOadr(cb) | DMA_BUS_ADR; } - if (pulses[i].usDelay) + if (waves[i].flags & WAVE_FLAG_READ) + { + p = waveCbVOadr(cb++); + + p->info = NORMAL_DMA; + p->src = ((GPIO_BASE + (GPLEV0*4)) & 0x00ffffff) | 0x7e000000; + p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR; + p->length = 4; + p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + } + + if (waves[i].flags & WAVE_FLAG_TICK) + { + p = waveCbVOadr(cb++); + + p->info = NORMAL_DMA; + p->src = ((SYST_BASE + (SYST_CLO*4)) & 0x00ffffff) | 0x7e000000; + p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR; + p->length = 4; + p->next = waveCbPOadr(cb) | DMA_BUS_ADR; + } + + if (waves[i].usDelay) { p = waveCbVOadr(cb++); @@ -1655,7 +1878,7 @@ static int wave2Cbs(unsigned mode) } p->src = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR; - p->length = 4 * ((pulses[i].usDelay+half)/PI_WF_MICROS); + p->length = 4 * ((waves[i].usDelay+half)/PI_WF_MICROS); p->next = waveCbPOadr(cb) | DMA_BUS_ADR; } } @@ -1755,9 +1978,9 @@ static void waveRxBit(int gpio, int level, uint32_t tick) /* ----------------------------------------------------------------------- */ -static int waveMerge(unsigned numIn1, gpioPulse_t * in1) +static int waveMerge(unsigned numIn1, gpioWave_t *in1) { - unsigned inPos1=0, inPos2=0, outPos=0; + unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_OOL; unsigned cbs=0; @@ -1765,7 +1988,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) uint32_t tNow, tNext1, tNext2, tDelay; - gpioPulse_t * in2, * out; + gpioWave_t *in2, *out; numIn2 = wfc[wfcur]; in2 = wf[wfcur]; @@ -1793,6 +2016,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) out[outPos].gpioOn = in1[inPos1].gpioOn; out[outPos].gpioOff = in1[inPos1].gpioOff; + out[outPos].flags = in1[inPos1].flags; tNext1 = tNow + in1[inPos1].usDelay; ++inPos1; } @@ -1809,6 +2033,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) out[outPos].gpioOn = in2[inPos2].gpioOn; out[outPos].gpioOff = in2[inPos2].gpioOff; + out[outPos].flags = in2[inPos2].flags; tNext2 = tNow + in2[inPos2].usDelay; ++inPos2; } @@ -1825,6 +2050,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) out[outPos].gpioOn = in1[inPos1].gpioOn | in2[inPos2].gpioOn; out[outPos].gpioOff = in1[inPos1].gpioOff | in2[inPos2].gpioOff; + out[outPos].flags = in1[inPos1].flags | in2[inPos2].flags; tNext1 = tNow + in1[inPos1].usDelay; ++inPos1; tNext2 = tNow + in2[inPos2].usDelay; ++inPos2; @@ -1841,6 +2067,18 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) if (out[outPos].gpioOff) cbs++; /* one cb if gpio off */ + if (out[outPos].flags & WAVE_FLAG_READ) + { + cbs++; /* one cb if read */ + --level; + } + + if (out[outPos].flags & WAVE_FLAG_TICK) + { + cbs++; /* one cb if tick */ + --level; + } + outPos++; if (inPos1 >= numIn1) tNext1 = -1; @@ -1848,7 +2086,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1) } - if (outPos < numOut) + if ((outPos < numOut) && (outPos < level)) { wfStats.micros = tNow; @@ -1897,7 +2135,7 @@ static void dmaCbPrint(int pos) /* ----------------------------------------------------------------------- */ -static unsigned dmaCurrentCb(void) +static unsigned dmaNowAtICB(void) { unsigned cb; static unsigned lastPage=0; @@ -1932,7 +2170,43 @@ static unsigned dmaCurrentCb(void) return (page*CBS_PER_IPAGE) + cb; } - if (page++ >= DMA_PAGES) page=0; + if (page++ >= DMAI_PAGES) page=0; + + if (page == lastPage) break; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +unsigned dmaNowAtOCB(void) +{ + unsigned cb; + static unsigned lastPage=0; + unsigned page; + uint32_t cbAddr; + + cbAddr = dmaOut[DMA_CONBLK_AD]; + + if (!cbAddr) return -1; + + page = lastPage; + + /* which page are we dma'ing? */ + + while (1) + { + cb = (cbAddr - ((int)dmaOPhys[page] | DMA_BUS_ADR)) / 32; + + if (cb < CBS_PER_OPAGE) + { + lastPage = page; + + return (page*CBS_PER_OPAGE) + cb; + } + + if (page++ >= DMAO_PAGES) page=0; if (page == lastPage) break; } @@ -1961,6 +2235,8 @@ static uint32_t dmaPwmDataAdr(int pos) return (uint32_t) &dmaIPhys[pos]->periphData; } +/* ----------------------------------------------------------------------- */ + static uint32_t dmaGpioOnAdr(int pos) { int page, slot; @@ -2095,7 +2371,7 @@ static void dmaDelayCb(int b) p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000; } - p->src = dmaPwmDataAdr(b%DMA_PAGES) | DMA_BUS_ADR; + p->src = dmaPwmDataAdr(b%DMAI_PAGES) | DMA_BUS_ADR; p->length = 4; p->next = dmaCbAdr(b+1) | DMA_BUS_ADR; } @@ -2186,13 +2462,19 @@ static void sigHandler(int signum) } else if (signum == SIGPIPE) { + /* can happen when pipe/socket is remote closed */ DBG(DBG_USER, "SIGPIPE received"); } + else if (signum == SIGCHLD) + { + /* happens when system call is made */ + DBG(DBG_USER, "SIGCHLD received"); + } else { /* exit */ - DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum); + DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum); exit(-1); } @@ -2202,7 +2484,7 @@ static void sigHandler(int signum) { /* exit */ - DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum); + DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum); exit(-1); } @@ -2256,7 +2538,7 @@ static void * pthAlertThread(void *x) gpioStats.startTick = tick; - oldSlot = dmaCurrentSlot(dmaCurrentCb()); + oldSlot = dmaCurrentSlot(dmaNowAtICB()); cycle = (oldSlot/PULSE_PER_CYCLE); pulse = (oldSlot%PULSE_PER_CYCLE); @@ -2273,7 +2555,7 @@ static void * pthAlertThread(void *x) req.tv_nsec = rem.tv_nsec; } - newSlot = dmaCurrentSlot(dmaCurrentCb()); + newSlot = dmaCurrentSlot(dmaNowAtICB()); numSamples = 0; @@ -2581,6 +2863,28 @@ static void * pthAlertThread(void *x) } } + if (changedBits & scriptBits) + { + for (n=0; n 0) + { + return S[--(*SP)]; + } + else + { + s->run_state = PI_SCRIPT_FAILED; + DBG(DBG_ALWAYS, "script %d too many pops", s->id); + return 0; + } +} + +/* ----------------------------------------------------------------------- */ + +static void scrPush(gpioScript_t *s, int *SP, int *S, int val) +{ + if ((*SP) < PI_SCRIPT_STACK_SIZE) + { + S[(*SP)++] = val; + } + else + { + s->run_state = PI_SCRIPT_FAILED; + DBG(DBG_ALWAYS, "script %d too many pushes", s->id); + } +} + +/* ----------------------------------------------------------------------- */ + +static void scrSwap(int *v1, int *v2) +{ + int t; + + t=*v1; *v1=*v2; *v2= t; +} + +/* ----------------------------------------------------------------------- */ + +static int scrWait(gpioScript_t *s, uint32_t bits) +{ + pthread_mutex_lock(&s->pthMutex); + + if (s->request == PI_SCRIPT_RUN) + { + s->run_state = PI_SCRIPT_WAITING; + s->waitBits = bits; + intScriptBits(); + + pthread_cond_wait(&s->pthCond, &s->pthMutex); + + s->waitBits = 0; + intScriptBits(); + s->run_state = PI_SCRIPT_RUNNING; + } + + pthread_mutex_unlock(&s->pthMutex); + + return s->changedBits; +} + +/* ----------------------------------------------------------------------- */ + +static int scrSys(char *cmd, int param) +{ + char buf[256]; + char par[16]; + + sprintf(par, " %d", param); + strcpy(buf, "/opt/pigpio/cgi/"); + strncat(buf, cmd, 200); + strcat(buf, par); + + DBG(DBG_USER, "sys %s", buf); + + return system(buf); +} + +/* ----------------------------------------------------------------------- */ + +static void *pthScript(void *x) +{ + gpioScript_t *s; + gpioExtent_t oExt[3]; + char buf[CMD_BUF_SIZE]; + gpioInstr_t instr; + int p1, p2; + + int PC, A, F, SP; + int S[PI_SCRIPT_STACK_SIZE]; + + S[0] = 0; /* to prevent compiler warning */ + + s = x; + + s->run_state = PI_SCRIPT_HALTED; + + while (s->request != PI_SCRIPT_DELETE) + { + pthread_mutex_lock(&s->pthMutex); + pthread_cond_wait(&s->pthCond, &s->pthMutex); + pthread_mutex_unlock(&s->pthMutex); + + s->run_state = PI_SCRIPT_RUNNING; + + A = 0; + F = 0; + PC = 0; + SP = 0; + + while ((s->request == PI_SCRIPT_RUN ) && + (s->run_state == PI_SCRIPT_RUNNING)) + { + instr = s->instr[PC]; + + p1 = instr.p[1]; + p2 = instr.p[2]; + + 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; + + PC++; + } + else + { + switch (instr.p[0]) + { + case PI_CMD_ADDI: A+=p1; F=A; PC++; break; + + case PI_CMD_ADDV: A+=s->var[p1]; F=A; PC++; break; + + case PI_CMD_ANDI: A&=p1; F=A; PC++; break; + + case PI_CMD_ANDV: A&=s->var[p1]; F=A; PC++; break; + + case PI_CMD_CALL: scrPush(s, S, &SP, PC+1); PC = p1; break; + + case PI_CMD_CMPI: F=A-p1; PC++; break; + + case PI_CMD_CMPV: F=A-s->var[p1]; PC++; break; + + case PI_CMD_DCRA: --A; F=A; PC++; break; + + case PI_CMD_DCRV: --s->var[p1]; F=s->var[p1]; 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_INRV: ++s->var[p1]; F=s->var[p1]; PC++; break; + + case PI_CMD_JM: if (F<0) PC=p1; else PC++; break; + + case PI_CMD_JMP: PC=p1; break; + + case PI_CMD_JNZ: if (F) PC=p1; else PC++; break; + + case PI_CMD_JP: if (F>=0) PC=p1; else PC++; break; + + case PI_CMD_JZ: if (!F) PC=p1; else PC++; break; + + case PI_CMD_LABEL: PC++; break; + + case PI_CMD_LDAI: A=p1; PC++; break; + + case PI_CMD_LDAP: A=s->param[p1]; PC++; break; + + case PI_CMD_LDAV: A=s->var[p1]; PC++; break; + + case PI_CMD_LDPA: s->param[p1]=A; PC++; break; + + case PI_CMD_LDVA: s->var[p1]=A; PC++; break; + + case PI_CMD_LDVI: s->var[p1] = p2; PC++; break; + + case PI_CMD_LDVV: s->var[p1]=s->var[p2]; PC++; break; + + case PI_CMD_ORI: A|=p1; F=A; PC++; break; + + case PI_CMD_ORV: A|=s->var[p1]; F=A; PC++; break; + + case PI_CMD_POPA: A=scrPop(s, S, &SP); PC++; break; + + case PI_CMD_POPV: s->var[p1]=scrPop(s, S, &SP); PC++; break; + + case PI_CMD_PUSHA: scrPush(s, S, &SP, A); PC++; break; + + case PI_CMD_PUSHV: scrPush(s, S, &SP, s->var[p1]); PC++; break; + + case PI_CMD_RET: PC=scrPop(s, S, &SP); break; + + case PI_CMD_RAL: A<<=p1; F=A; PC++; break; + + case PI_CMD_RAR: A>>=p1; F=A; PC++; break; + + case PI_CMD_SUBI: A-=p1; F=A; PC++; break; + + case PI_CMD_SUBV: A-=s->var[p1]; F=A; PC++; break; + + case PI_CMD_SWAPA: scrSwap(&s->var[p1], &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; + + } + } + + if (PC >= s->instrs) s->run_state = PI_SCRIPT_HALTED; + + } + + if (s->request == PI_SCRIPT_HALT) s->run_state = PI_SCRIPT_HALTED; + + } + + return 0; +} + /* ----------------------------------------------------------------------- */ static void * pthTimerTick(void *x) @@ -2652,11 +3210,15 @@ static void * pthTimerTick(void *x) static void * pthFifoThread(void *x) { char buf[CMD_BUF_SIZE]; - int idx, flags, len; - cmdCmd_t cmd; - gpioExtent_t iExt[3]; + int idx, flags, len, res, i; + uint32_t p[10]; + void *v[10]; gpioExtent_t oExt[3]; - char *p; + gpioCtlParse_t ctl; + char *pp; + uint32_t *param; + + ctl.flags = 0; myCreatePipe(PI_INPFIFO, 0662); @@ -2686,53 +3248,79 @@ static void * pthFifoThread(void *x) buf[len] = 0; /* replace terminating */ } - if ((idx=cmdParse(buf, &cmd, 0, NULL, iExt)) >= 0) + ctl.eaten = 0; + idx = 0; + + while (((ctl.eaten)= 0)) { - oExt[0].ptr = buf; - oExt[0].size = CMD_BUF_SIZE-1; - - myDoCommand(&cmd, iExt, oExt); - - switch (cmdInfo[idx].rv) + if ((idx=cmdParse(buf, p, v, &ctl)) >= 0) { - case 0: - fprintf(outFifo, "%d\n", cmd.res); - break; + oExt[0].ptr = buf; + oExt[0].size = CMD_BUF_SIZE-1; - case 1: - fprintf(outFifo, "%d\n", cmd.res); - break; + switch (p[0]) + { + case PI_CMD_PROC: p[2] = (uint32_t)v[1]; break; + case PI_CMD_PROCR: p[3] = (uint32_t)v[1]; break; + case PI_CMD_WVAG: p[2] = (uint32_t)v[1]; break; + case PI_CMD_WVAS: p[5] = (uint32_t)v[1]; break; + } - case 2: - fprintf(outFifo, "%d\n", cmd.res); - break; + res = myDoCommand(p, oExt); - case 3: - fprintf(outFifo, "%08X\n", cmd.res); - break; + switch (cmdInfo[idx].rv) + { + case 0: + fprintf(outFifo, "%d\n", res); + break; - case 4: - fprintf(outFifo, "%u\n", cmd.res); - break; + case 1: + fprintf(outFifo, "%d\n", res); + break; - case 5: - fprintf(outFifo, cmdUsage); - break; + case 2: + fprintf(outFifo, "%d\n", res); + break; - case 6: - if (cmd.res < 0) fprintf(outFifo, "%d\n", cmd.res); - else if (cmd.res > 0) - { - p = oExt[0].ptr; - p[cmd.res] = 0; - fprintf(outFifo, "%s", (char *)oExt[0].ptr); - } - break; + case 3: + fprintf(outFifo, "%08X\n", res); + break; + case 4: + fprintf(outFifo, "%u\n", res); + break; + + case 5: + fprintf(outFifo, cmdUsage); + break; + + case 6: + if (res < 0) fprintf(outFifo, "%d\n", res); + else if (res > 0) + { + pp = oExt[0].ptr; + pp[res] = 0; + fprintf(outFifo, "%s", (char *)oExt[0].ptr); + } + break; + + case 7: + if (res < 0) fprintf(outFifo, "%d\n", res); + else + { + fprintf(outFifo, "%d", res); + param = oExt[0].ptr; + for (i=0; i 0) - { - write(sock, oExt[0].ptr, cmd.res); - } - break; - - default: - break; - } - + else res = PI_NO_MEMORY; + break; + default: + res = myDoCommand(p, oExt); + break; + } + + p[3] = res; + + write(sock, p, 16); + + switch (p[0]) + { + case PI_CMD_SLR: /* extension */ + + if (res > 0) + { + write(sock, oExt[0].ptr, res); + } + break; + + case PI_CMD_PROCP: /* extension */ + + if (res >= 0) + { + write(sock, oExt[0].ptr, sizeof(uint32_t)*MAX_SCRIPT_PARAMS); + } + break; + + default: + break; } - else break; } close(sock); @@ -3291,7 +3913,7 @@ static int initDMAcbs(void) (uint32_t)gpioReg, (uint32_t)pwmReg, (uint32_t)pcmReg, (uint32_t)clkReg); - for (i=0; i= 0) && (pos < NUM_OOL)) + { + waveOOLPageSlot(pos, &page, &slot); + return (dmaOVirt[page]->OOL[slot]); + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +void waveSetRawOut(int pos, uint32_t value) +{ + int page, slot; + + if ((pos >= 0) && (pos < NUM_OOL)) + { + waveOOLPageSlot(pos, &page, &slot); + dmaOVirt[page]->OOL[slot] = value; + } +} + + +/* ----------------------------------------------------------------------- */ + +uint32_t waveGetRawIn(int pos) +{ + int page, slot; + + if ((pos >= 0) && (pos < NUM_OOL)) + { + waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot); + return (dmaOVirt[page]->OOL[slot]); + } + + return -1; +} + +/* ----------------------------------------------------------------------- */ + +void waveSetRawIn(int pos, uint32_t value) +{ + int page, slot; + + if ((pos >= 0) && (pos < NUM_OOL)) + { + waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot); + dmaOVirt[page]->OOL[slot] = value; + } +} + +/* ----------------------------------------------------------------------- */ + +double time_time(void) +{ + struct timeval tv; + double t; + + gettimeofday(&tv, 0); + + t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6); + + return t; +} + +/* ----------------------------------------------------------------------- */ + +void time_sleep(double seconds) +{ + struct timespec ts, rem; + + if (seconds > 0.0) + { + ts.tv_sec = seconds; + ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9; + + while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem)) + { + /* copy remaining time to ts */ + ts.tv_sec = rem.tv_sec; + ts.tv_nsec = rem.tv_nsec; + } + } +} + +/* ----------------------------------------------------------------------- */ + +void gpioDumpWave(void) +{ + int i; + + unsigned numWaves, t; + + gpioWave_t *waves; + + numWaves = wfc[wfcur]; + waves = wf [wfcur]; + + t = 0; + + for (i=0; i PI_WAVE_MAX_PULSES) SOFT_ERROR(PI_TOO_MANY_PULSES, "bad number of pulses (%d)", numPulses); - return waveMerge(numPulses, pulses); + for (p=0; p bitDelay[0]) wf[2][p].usDelay = offset; else wf[2][p].usDelay = bitDelay[0]; @@ -4461,6 +5269,7 @@ int gpioWaveAddSerial(unsigned gpio, wf[2][p].gpioOn = 0; wf[2][p].gpioOff = (1< PI_MAX_USER_GPIO) + SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", ss); + + /* + CPOL CPHA + 0 0 read rising/write falling + 0 1 read falling/write rising + 1 0 read falling/write rising + 1 1 read rising/write falling + */ + + if (spi->clk_pol) {rising_edge[0] = 0; rising_edge[1] = 1;} + else {rising_edge[0] = 1; rising_edge[1] = 0;} + + if (spi->clk_pha) {read_cycle[0] = 0; read_cycle[1] = 1;} + else {read_cycle[0] = 1; read_cycle[1] = 0;} + + p = 0; + + if (offset) + { + wf[2][p].gpioOn = 0; + wf[2][p].gpioOff = 0; + wf[2][p].flags = 0; + wf[2][p].usDelay = offset; + p++; + } + + /* preset initial mosi bit in case it's read at leading clock bit */ + + on_bits = 0; + off_bits = 0; + + tx_bit_pos = 0; + + if (getBitInBytes(tx_bit_pos, tx_bits, num_tx_bits)) + { + dbv = 1; + on_bits |= (1<<(spi->mosi)); + } + else + { + dbv = 0; + off_bits |= (1<<(spi->mosi)); + } + + if (spi->ss_pol) off_bits |= (1<clk_us > spi->ss_us) wf[2][p].usDelay = spi->clk_us; + else wf[2][p].usDelay = spi->ss_us; + + p++; + + for (bit=1; bit<=bits; bit++) + { + for (halfbit=0; halfbit<2; halfbit++) + { + wf[2][p].usDelay = spi->clk_us; + wf[2][p].flags = 0; + + on_bits = 0; + off_bits = 0; + + if (read_cycle[halfbit]) + { + if ((bit>=rx_bit_first) && (bit<=rx_bit_last)) + wf[2][p].flags = WAVE_FLAG_READ; + +; + } + else + { + if (getBitInBytes(tx_bit_pos, tx_bits, num_tx_bits)) + { + if (!dbv) on_bits |= (1<<(spi->mosi)); + dbv = 1; + } + else + { + if (dbv) off_bits |= (1<<(spi->mosi)); + dbv = 0; + } + + ++tx_bit_pos; + } + + if (rising_edge[halfbit]) on_bits |= (1<<(spi->clk)); + else off_bits |= (1<<(spi->clk)); + + wf[2][p].gpioOn = on_bits; + wf[2][p].gpioOff = off_bits; + + p++; + } + } + + on_bits = 0; + off_bits = 0; + + if (spi->ss_pol) on_bits |= (1<= DBG_SLOW_TICK) @@ -4727,7 +5683,7 @@ static int intGpioSetAlertFunc( alertBits &= ~BIT; } - monitorBits = alertBits | notifyBits | gpioGetSamples.bits; + monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits; return 0; } @@ -4784,6 +5740,7 @@ int gpioNotifyOpen(void) { if (gpioNotify[i].state == PI_NOTIFY_CLOSED) { + gpioNotify[i].state = PI_NOTIFY_OPENED; slot = i; break; } @@ -4799,9 +5756,11 @@ int gpioNotifyOpen(void) fd = open(name, O_RDWR|O_NONBLOCK); if (fd < 0) + { + gpioNotify[slot].state = PI_NOTIFY_CLOSED; SOFT_ERROR(PI_BAD_PATHNAME, "open %s failed (%m)", name); + } - gpioNotify[slot].state = PI_NOTIFY_OPENED; gpioNotify[slot].seqno = 0; gpioNotify[slot].bits = 0; gpioNotify[slot].fd = fd; @@ -4846,6 +5805,27 @@ static int gpioNotifyOpenInBand(int fd) /* ----------------------------------------------------------------------- */ +static void intScriptBits(void) +{ + int i; + uint32_t bits; + + bits = 0; + + for (i=0; irequest = PI_SCRIPT_HALT; + s->run_state = PI_SCRIPT_HALTED; + + pthread_cond_init(&s->pthCond, NULL); + pthread_mutex_init(&s->pthMutex, NULL); + + s->id = slot; + + gpioScript[slot].state = PI_SCRIPT_IN_USE; + + s->pthIdp = gpioStartThread(pthScript, s); + + status = slot; + + } + else + { + if (s->param) free(s->param); + s->param = NULL; + gpioScript[slot].state = PI_SCRIPT_FREE; + } + + return status; +} /* ----------------------------------------------------------------------- */ -int gpioRunScript(int script_id) +int gpioRunScript(int script_id, unsigned numParam, uint32_t *param) { - DBG(DBG_USER, "script_id=%d", script_id); + int status = 0; + + DBG(DBG_USER, "script_id=%d numParam=%d param=%08X", + script_id, numParam, (uint32_t)param); CHECK_INITED; - return PI_BAD_SCRIPT_ID; + if (numParam > MAX_SCRIPT_PARAMS) + SOFT_ERROR(PI_TOO_MANY_PARAM, "bad number of parameters(%d)", numParam); + + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) + { + pthread_mutex_lock(&gpioScript[script_id].pthMutex); + + if (gpioScript[script_id].run_state == PI_SCRIPT_HALTED) + { + if ((numParam > 0) && (param != 0)) + { + memcpy(gpioScript[script_id].param, param, + sizeof(uint32_t) * numParam); + } + + gpioScript[script_id].request = PI_SCRIPT_RUN; + + pthread_cond_signal(&gpioScript[script_id].pthCond); + } + else + { + status = PI_NOT_HALTED; + } + + pthread_mutex_unlock(&gpioScript[script_id].pthMutex); + + return status; + } + else return PI_BAD_SCRIPT_ID; } +/* ----------------------------------------------------------------------- */ + +int gpioScriptStatus(int script_id, uint32_t *param) +{ + DBG(DBG_USER, "script_id=%d param=%08X", script_id, (uint32_t)param); + + CHECK_INITED; + + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) + { + if (param != 0) + { + memcpy(param, gpioScript[script_id].param, + sizeof(uint32_t) * MAX_SCRIPT_PARAMS); + } + + return gpioScript[script_id].run_state; + } + else return PI_BAD_SCRIPT_ID; +} + /* ----------------------------------------------------------------------- */ @@ -5214,11 +6289,24 @@ int gpioStopScript(int script_id) CHECK_INITED; - return PI_BAD_SCRIPT_ID; + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) + { + pthread_mutex_lock(&gpioScript[script_id].pthMutex); + + gpioScript[script_id].request = PI_SCRIPT_HALT; + + if (gpioScript[script_id].run_state == PI_SCRIPT_WAITING) + { + pthread_cond_signal(&gpioScript[script_id].pthCond); + } + + pthread_mutex_unlock(&gpioScript[script_id].pthMutex); + + return 0; + } + else return PI_BAD_SCRIPT_ID; } - - /* ----------------------------------------------------------------------- */ int gpioDeleteScript(int script_id) @@ -5227,7 +6315,37 @@ int gpioDeleteScript(int script_id) CHECK_INITED; - return PI_BAD_SCRIPT_ID; + if (gpioScript[script_id].state == PI_SCRIPT_IN_USE) + { + gpioScript[script_id].state = PI_SCRIPT_DYING; + + pthread_mutex_lock(&gpioScript[script_id].pthMutex); + + gpioScript[script_id].request = PI_SCRIPT_HALT; + + if (gpioScript[script_id].run_state == PI_SCRIPT_WAITING) + { + pthread_cond_signal(&gpioScript[script_id].pthCond); + } + + pthread_mutex_unlock(&gpioScript[script_id].pthMutex); + + while (gpioScript[script_id].run_state == PI_SCRIPT_RUNNING) + { + myGpioSleep(0, 5000); /* give script time to halt */ + } + + gpioStopThread(gpioScript[script_id].pthIdp); + + if (gpioScript[script_id].param) free(gpioScript[script_id].param); + + gpioScript[script_id].param = NULL; + + gpioScript[script_id].state = PI_SCRIPT_FREE; + + return 0; + } + else return PI_BAD_SCRIPT_ID; } @@ -5441,7 +6559,7 @@ uint32_t gpioDelay(uint32_t micros) start = systReg[SYST_CLO]; - if (micros < 100) while ((systReg[SYST_CLO] - start) <= micros) ; + if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ; else gpioSleep(PI_TIME_RELATIVE, (micros/MILLION), (micros%MILLION)); @@ -5672,7 +6790,7 @@ int gpioCfgInternals(unsigned what, int value) gpioCfg.showStats = value; - DBG(DBG_MIN_LEVEL, "showStats is %u", value); + DBG(DBG_ALWAYS, "showStats is %u", value); retVal = 0; @@ -5680,13 +6798,13 @@ int gpioCfgInternals(unsigned what, int value) case 984762879: - if (value < DBG_MIN_LEVEL) value = DBG_MIN_LEVEL; + if (value < DBG_ALWAYS) value = DBG_ALWAYS; if (value > DBG_MAX_LEVEL) value = DBG_MAX_LEVEL; gpioCfg.dbgLevel = value; - DBG(DBG_MIN_LEVEL, "Debug level is %u", value); + DBG(DBG_ALWAYS, "Debug level is %u", value); retVal = 0; diff --git a/pigpio.h b/pigpio.h index bf5fa89..0ddac32 100644 --- a/pigpio.h +++ b/pigpio.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 12 +This version is for pigpio version 13 */ #ifndef PIGPIO_H @@ -86,7 +86,7 @@ This version is for pigpio version 12 #include #include -#define PIGPIO_VERSION 12 +#define PIGPIO_VERSION 13 /*-------------------------------------------------------------------------*/ @@ -164,6 +164,7 @@ gpioStopThread Stop a previously started thread. gpioStoreScript Store a script. gpioRunScript Run a stored script. +gpioScriptStatus Get script status and parameters. gpioStopScript Stop a running script. gpioDeleteScript Delete a stored script. @@ -217,6 +218,12 @@ gpioCfgSocketPort Configure socket port. extern "C" { #endif +typedef struct +{ + uint16_t func; + uint16_t size; +} gpioHeader_t; + typedef struct { uint32_t cmd; @@ -229,7 +236,7 @@ typedef struct { size_t size; void *ptr; - int data; + uint32_t data; } gpioExtent_t; typedef struct @@ -253,6 +260,29 @@ typedef struct uint32_t usDelay; } gpioPulse_t; +#define WAVE_FLAG_READ 1 +#define WAVE_FLAG_TICK 2 + +typedef struct +{ + uint32_t gpioOn; + uint32_t gpioOff; + uint32_t usDelay; + uint32_t flags; +} gpioWave_t; + +typedef struct +{ + int clk; /* gpio for clock */ + int mosi; /* gpio for MOSI */ + int miso; /* gpio for MISO */ + int ss_pol; /* slave select off state */ + int ss_us; /* delay after slave select */ + int clk_pol; /* clock off state */ + int clk_pha; /* clock phase */ + int clk_us; /* clock micros */ +} gpioSPI_t; + typedef void (*gpioAlertFunc_t) (int gpio, int level, uint32_t tick); @@ -768,6 +798,8 @@ int gpioNotifyOpen(void); handle. */ +#define PI_NOTIFY_SLOTS 32 + /*-------------------------------------------------------------------------*/ @@ -915,7 +947,7 @@ int gpioWaveAddSerial(unsigned user_gpio, the same waveform. */ -#define PI_WAVE_BLOCKS 3 +#define PI_WAVE_BLOCKS 4 #define PI_WAVE_MAX_PULSES (PI_WAVE_BLOCKS * 3000) #define PI_WAVE_MAX_CHARS (PI_WAVE_BLOCKS * 256) @@ -924,8 +956,6 @@ int gpioWaveAddSerial(unsigned user_gpio, #define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */ - - /*-------------------------------------------------------------------------*/ int gpioWaveTxStart(unsigned mode); /*-------------------------------------------------------------------------*/ @@ -1321,18 +1351,53 @@ int gpioStoreScript(char *script); otherwise PI_BAD_SCRIPT. */ +#define MAX_SCRIPT_LABELS 50 +#define MAX_SCRIPT_VARS 150 +#define MAX_SCRIPT_PARAMS 10 /* ----------------------------------------------------------------------- */ -int gpioRunScript(int script_id); +int gpioRunScript(int script_id, unsigned numParam, uint32_t *param); /* ----------------------------------------------------------------------- */ /* This function runs a stored script. - The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or + PI_TOO_MANY_PARAM. + + param is an array of up to 10 parameters which may be referenced in + the script as param 0 to param 9. */ +/* ----------------------------------------------------------------------- */ +int gpioScriptStatus(int 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. + + The function returns greater than or equal to 0 if OK, + otherwise PI_BAD_SCRIPT_ID. + + The run status may be + + PI_SCRIPT_HALTED + PI_SCRIPT_RUNNING + PI_SCRIPT_WAITING + PI_SCRIPT_FAILED + + The current value of script parameters 0 to 9 are returned in param. +*/ + +/* script status */ + +#define PI_SCRIPT_HALTED 0 +#define PI_SCRIPT_RUNNING 1 +#define PI_SCRIPT_WAITING 2 +#define PI_SCRIPT_FAILED 3 + + + /* ----------------------------------------------------------------------- */ int gpioStopScript(int script_id); /* ----------------------------------------------------------------------- */ @@ -1798,12 +1863,98 @@ int gpioCfgInternals(unsigned what, Not intended for general use. */ +/*-------------------------------------------------------------------------*/ +int gpioWaveAddSPI( + gpioSPI_t *spi, + unsigned offset, + unsigned ss, + uint8_t *tx_bits, + unsigned num_tx_bits, + unsigned rx_bit_first, + unsigned rx_bit_last, + unsigned bits); +/*-------------------------------------------------------------------------*/ +/* This function adds a waveform representing SPI data to the + existing waveform (if any). The SPI data starts offset microseconds + from the start of the waveform. ss is the slave select gpio. bits bits + are transferred. num_tx_bits are transmitted starting at the first bit. + The bits to transmit are read, most significant bit first, from tx_bits. + Gpio reads are made from rx_bit_first to rx_bit_last. + + 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. +*/ + + +/* ----------------------------------------------------------------------- */ +uint32_t waveGetRawOut(int pos); +/* ----------------------------------------------------------------------- */ +/* Gets the wave output parameter stored at pos. + Not intended for general use. +*/ + + +/* ----------------------------------------------------------------------- */ +void waveSetRawOut(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); +/* ----------------------------------------------------------------------- */ +/* Gets the wave input value parameter stored at pos. + Not intended for general use. +*/ + + +/* ----------------------------------------------------------------------- */ +void waveSetRawIn(int pos, uint32_t value); +/* ----------------------------------------------------------------------- */ +/* Sets the wave input value stored at pos to value. + Not intended for general use. +*/ + +/*-------------------------------------------------------------------------*/ +int getBitInBytes(int bitPos, uint8_t *buf, int numBits); +/*-------------------------------------------------------------------------*/ +/* Returns the value of the bit bitPos bits from the start of buf. Returns + 0 if bitPos is greater than or equal to numBits. +*/ + +/* ----------------------------------------------------------------------- */ +void putBitInBytes(int bitPos, uint8_t *buf, int val); +/*-------------------------------------------------------------------------*/ +/* Sets the bit bitPos bits from the start of buf to val. +*/ + +/*-------------------------------------------------------------------------*/ +double time_time(void); +/*-------------------------------------------------------------------------*/ +/* Return the current time in seconds since the Epoch. +*/ /*-------------------------------------------------------------------------*/ -void gpioWaveDump(void); +void time_sleep(double seconds); /*-------------------------------------------------------------------------*/ -/* Used to print a readable version of the current waveform to stdout. +/* Delay execution for a given number of seconds +*/ + + +/*-------------------------------------------------------------------------*/ +void gpioDumpWave(void); +/*-------------------------------------------------------------------------*/ +/* Used to print a readable version of the current waveform to stderr. + Not intended for general use. +*/ + + +/*-------------------------------------------------------------------------*/ +void gpioDumpScript(int s); +/*-------------------------------------------------------------------------*/ +/* Used to print a readable version of a script to stderr. Not intended for general use. */ @@ -1859,6 +2010,10 @@ void gpioWaveDump(void); #define PI_CMD_SLRO 42 #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 + /* The following command only works on the socket interface. @@ -1872,6 +2027,53 @@ after this command is issued. #define PI_CMD_NOIB 99 +/* pseudo commands */ + +#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 /*-------------------------------------------------------------------------*/ @@ -1930,7 +2132,17 @@ after this command is issued. #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_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 */ +#define PI_NO_MEMORY -58 /* can't allocate temporary memory */ +#define PI_SOCK_READ_FAILED -59 /* socket read failed */ +#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 */ /*-------------------------------------------------------------------------*/ diff --git a/pigpio.py b/pigpio.py index dd74105..f5591ca 100644 --- a/pigpio.py +++ b/pigpio.py @@ -76,7 +76,7 @@ import threading import os import atexit -VERSION = "1.3" +VERSION = "1.4" # gpio levels @@ -113,6 +113,13 @@ PUD_OFF = 0 PUD_DOWN = 1 PUD_UP = 2 +# script run status + +PI_SCRIPT_HALTED =0 +PI_SCRIPT_RUNNING=1 +PI_SCRIPT_WAITING=2 +PI_SCRIPT_FAILED =3 + # pigpio command numbers _PI_CMD_MODES= 0 @@ -160,6 +167,7 @@ _PI_CMD_PROCS=41 _PI_CMD_SLRO= 42 _PI_CMD_SLR= 43 _PI_CMD_SLRC= 44 +_PI_CMD_PROCP=45 _PI_CMD_NOIB= 99 @@ -205,7 +213,7 @@ _PI_BAD_CFG_INTERNAL=-34 PI_BAD_WAVE_BAUD =-35 PI_TOO_MANY_PULSES =-36 PI_TOO_MANY_CHARS =-37 -PI_NOT_SERIAL_GPIO =-38 +PI_NOT_SERIAL_GPIO =-38 _PI_BAD_SERIAL_STRUC=-39 _PI_BAD_SERIAL_BUF =-40 PI_NOT_PERMITTED =-41 @@ -218,6 +226,18 @@ PI_BAD_SCRIPT =-47 PI_BAD_SCRIPT_ID =-48 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_BAD_SCRIPT_CMD =-55 +PI_BAD_VAR_NUM =-56 +PI_NO_SCRIPT_ROOM =-57 +PI_NO_MEMORY =-58 +PI_SOCK_READ_FAILED =-59 +PI_SOCK_WRIT_FAILED =-60 +PI_TOO_MANY_PARAM =-61 +PI_NOT_HALTED =-62 # pigpio error text @@ -270,6 +290,19 @@ _errors=[ [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_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"], + [PI_NO_MEMORY , "can't allocate temporary memory"], + [PI_SOCK_READ_FAILED , "socket read failed"], + [PI_SOCK_WRIT_FAILED , "socket write failed"], + [PI_TOO_MANY_PARAM , "too many script parameters (> 10)"], + [PI_NOT_HALTED , "script already running or failed"], + ] _control = None @@ -348,8 +381,8 @@ def _pigpio_command(sock, cmd, p1, p2): sock: command socket. cmd: the command to be executed. - p1: command paramter 1 (if applicable). - p2: command paramter 2 (if applicable). + p1: command parameter 1 (if applicable). + p2: command parameter 2 (if applicable). """ if sock is not None: sock.send(struct.pack('IIII', cmd, p1, p2, 0)) @@ -364,8 +397,8 @@ def _pigpio_command_ext(sock, cmd, p1, p2, extents): sock: command socket. cmd: the command to be executed. - p1: command paramter 1 (if applicable). - p2: command paramter 2 (if applicable). + p1: command parameter 1 (if applicable). + p2: command parameter 2 (if applicable). extents: additional data blocks """ if sock is not None: @@ -1676,15 +1709,57 @@ def store_script(script): return _u2i(_pigpio_command_ext( _control, _PI_CMD_PROC, len(script), 0, script)) -def run_script(script_id): +def run_script(script_id, params=None): """ Runs a stored script. Returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. script_id: script_id of stored script. + params: up to 10 parameters required by the script. """ - return _u2i(_pigpio_command(_control, _PI_CMD_PROCR, script_id, 0)) + # I p1 script id + # I p2 number of parameters (0-10) + ## (optional) extension ## + # I[] params + + if params is not None: + msg = "" + for p in params: + msg += struct.pack("I", p) + nump = len(params) + extents = [msg] + else: + nump = 0 + extents = [] + + return _u2i(_pigpio_command_ext( + _control, _PI_CMD_PROCR, script_id, nump, extents)) + +def script_status(script_id): + """ + This function returns the run status of a stored script as well as + the current values of parameters 0 to 9. + + The function returns greater than or equal to 0 if OK, + otherwise PI_BAD_SCRIPT_ID. + + The run status may be + + PI_SCRIPT_HALTED + PI_SCRIPT_RUNNING + PI_SCRIPT_WAITING + PI_SCRIPT_FAILED + + It returns a tuple of run status and a parameter list tuple. If the script + does not exist a negative error code will be returned in which + case the parameter tuple will be empty. + """ + status = _u2i(_pigpio_command(_control, _PI_CMD_PROCP, script_id, 0)) + if status >= 0: + param = struct.unpack('IIIIIIIIII', _control.recv(40)) + return status, param + return status, () def stop_script(script_id): """ @@ -2015,7 +2090,8 @@ def start(host = os.getenv("PIGPIO_ADDR", ''), print("Did you specify the correct Pi host/port in the") print("pigpio.start() function? E.g. pigpio.start('soft', 8888))") print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") - raise + return False + return True def stop(): """Release pigpio resources. diff --git a/pigpiod_if.c b/pigpiod_if.c index 4960150..2fab6d0 100644 --- a/pigpiod_if.c +++ b/pigpiod_if.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* PIGPIOD_IF_VERSION 3 */ +/* PIGPIOD_IF_VERSION 4 */ #include #include @@ -534,10 +534,10 @@ int get_mode(unsigned gpio) int set_pull_up_down(unsigned gpio, unsigned pud) {return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);} -int read_gpio(unsigned gpio) +int gpio_read(unsigned gpio) {return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);} -int write_gpio(unsigned gpio, unsigned level) +int gpio_write(unsigned gpio, unsigned level) {return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);} int set_PWM_dutycycle(unsigned user_gpio, unsigned dutycycle) @@ -600,7 +600,7 @@ uint32_t get_current_tick(void) uint32_t get_hardware_revision(void) {return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);} -unsigned get_pigpio_version(void) +uint32_t get_pigpio_version(void) {return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);} int wave_clear(void) @@ -725,8 +725,41 @@ int store_script(char *script) return pigpio_command_ext(gPigCommand, PI_CMD_PROC, len, 0, 1, ext); } -int run_script(unsigned script_id) - {return pigpio_command(gPigCommand, PI_CMD_PROCR, script_id, 0);} +int run_script(unsigned script_id, unsigned numPar, uint32_t *param) +{ + gpioExtent_t ext[1]; + + /* + p1=script id + p2=number of parameters + ## extension ## + uint32_t[] parameters + */ + + ext[0].size = sizeof(uint32_t)*numPar; + ext[0].ptr = param; + + return pigpio_command_ext + (gPigCommand, PI_CMD_PROCR, script_id, numPar, 1, ext); +} + +int script_status(int script_id, uint32_t *param) +{ + int status; + uint32_t p[MAX_SCRIPT_PARAMS]; + + status = pigpio_command(gPigCommand, PI_CMD_PROCP, script_id, 0); + + if (status >= 0) + { + /* get the data */ + recv(gPigCommand, p, sizeof(p), MSG_WAITALL); + + if (param) memcpy(param, p, sizeof(p)); + } + + return status; +} int stop_script(unsigned script_id) {return pigpio_command(gPigCommand, PI_CMD_PROCS, script_id, 0);} diff --git a/pigpiod_if.h b/pigpiod_if.h index c8e8fc5..809800c 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 3 +#define PIGPIOD_IF_VERSION 4 typedef enum { @@ -79,7 +79,7 @@ pthread_t *start_thread(gpioThreadFunc_t func, void *arg); The function is passed the single argument arg. The thread can be cancelled by passing the pointer to pthread_t to - gpioStopThread(). + stop_thread(). */ void stop_thread(pthread_t *pth); @@ -87,7 +87,7 @@ void stop_thread(pthread_t *pth); No value is returned. - The thread to be stopped should have been started with gpioStartThread(). + The thread to be stopped should have been started with start_thread(). */ int pigpio_start(char *addrStr, char *portStr); @@ -139,7 +139,7 @@ int set_pull_up_down(unsigned gpio, unsigned pud); pud: PUD_UP, PUD_DOWN, PUD_OFF. */ -int read_gpio(unsigned gpio); +int gpio_read(unsigned gpio); /* Read the gpio level. Returns the gpio level if OK, otherwise PI_BAD_GPIO. @@ -147,7 +147,7 @@ int read_gpio(unsigned gpio); gpio:0-53. */ -int write_gpio(unsigned gpio, unsigned level); +int gpio_write(unsigned gpio, unsigned level); /* Write the gpio level. @@ -507,6 +507,12 @@ uint32_t get_hardware_revision(void); hexadecimal number the function returns 0. */ +uint32_t get_pigpio_version(void); +/* + Returns the pigpio version. +*/ + + int wave_clear(void); /* This function initialises a new waveform. @@ -659,10 +665,31 @@ int store_script(char *script); otherwise PI_BAD_SCRIPT. */ -int run_script(unsigned script_id); +int run_script(unsigned script_id, unsigned numPar, uint32_t *param); /* This function runs a stored script. - The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or + PI_TOO_MANY_PARAM + + param is an array of up to 10 parameters which may be referenced in + the script as param 0 to param 9.. +*/ + +int script_status(int 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. + + The function returns greater than or equal to 0 if OK, + otherwise PI_BAD_SCRIPT_ID. + + The run status may be + + PI_SCRIPT_HALTED + PI_SCRIPT_RUNNING + PI_SCRIPT_WAITING + PI_SCRIPT_FAILED + + The current value of script parameters 0 to 9 are returned in param. */ int stop_script(unsigned script_id); @@ -684,7 +711,7 @@ int serial_read_open(unsigned user_gpio, unsigned baud); or PI_GPIO_IN_USE. The serial data is returned in a cyclic buffer and is read using - gpioSerialRead(). + serial_read(). It is the caller's responsibility to read data from the cyclic buffer in a timely fashion. diff --git a/pigs.c b/pigs.c index 4043c70..35c47e4 100644 --- a/pigs.c +++ b/pigs.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 12+ +This version is for pigpio version 13+ */ #include @@ -47,6 +47,9 @@ This program provides a socket interface to some of the commands available from pigpio. */ +char command_buf[8192]; +char response_buf[8192]; + void fatal(char *fmt, ...) { char buf[128]; @@ -103,109 +106,226 @@ static int openSocket(void) return sock; } +void print_result(int sock, int rv, cmdCmd_t cmd) +{ + int i, r; + uint32_t *p; + + r = cmd.res; + + switch (rv) + { + case 0: + if (r < 0) fatal("ERROR: %s", cmdErrStr(r)); + break; + + case 1: + if (r < 0) fatal("ERROR: %s", cmdErrStr(r)); + break; + + case 2: + if (r < 0) fatal("ERROR: %s", cmdErrStr(r)); + else printf("%d\n", r); + break; + + case 3: + printf("%08X\n", cmd.res); + break; + + case 4: + printf("%u\n", cmd.res); + break; + + case 5: + printf(cmdUsage); + break; + + case 6: /* SLR */ + if (r < 0) fatal("ERROR: %s", cmdErrStr(r)); + else if (r > 0) + { + printf("%s", response_buf); + } + break; + + case 7: /* PROCP */ + if (r < 0) fatal("ERROR: %s", cmdErrStr(r)); + else + { + printf("%d", r); + + p = (uint32_t *)response_buf; + + for (i=0; i= 0) + { + recv(sock, + response_buf, + sizeof(uint32_t)*MAX_SCRIPT_PARAMS, + MSG_WAITALL); + } + break; + + case PI_CMD_SLR: /* SLR */ + if (res > 0) + { + recv(sock, response_buf, res, MSG_WAITALL); + response_buf[res] = 0; + } + break; + } +} + +void put_extensions(int sock, int command, uint32_t *p, void *v[]) +{ + switch (command) + { + case PI_CMD_PROC: + /* + p1=script length w[1] + p2=0 + ## extension ## + char[] script v[1] + */ + send(sock, v[1], p[1], 0); + break; + + case PI_CMD_PROCR: + /* + p1=script id w[1] + p2=numParam w[2] + ## extension ## + int[] param v[1] + */ + if (p[2]) send(sock, v[1], p[2]*sizeof(uint32_t), 0); + break; + + case PI_CMD_TRIG: + /* + p1=user_gpio w[1] + p2=pulseLen w[2] + ## extension ## + unsigned level w[3] + */ + send(sock, &p[3], 4, 0); + break; + + case PI_CMD_WVAG: + /* + p1=pulses w[1] + p2=0 + ## extension ## + int[] param v[1] + */ + if (p[1]) send(sock, v[1], p[1]*sizeof(gpioPulse_t), 0); + break; + + case PI_CMD_WVAS: + /* + p1=user_gpio w[1] + p2=numChar w[4] + ## extension ## + unsigned baud w[2] + unsigned offset w[3] + char[] str v[1] + */ + send(sock, &p[2], 4, 0); + send(sock, &p[3], 4, 0); + send(sock, v[1], p[4], 0); + break; + } + +} + int main(int argc , char *argv[]) { - int sock, r, idx, i; + int sock, command; + int idx, i, pp, l, len; cmdCmd_t cmd; - gpioExtent_t ext[3]; - char buf[1024]; + uint32_t p[10]; + void *v[10]; + gpioCtlParse_t ctl; sock = openSocket(); if (sock != -1) { - switch(argc) + command_buf[0] = 0; + l = 0; + pp = 0; + + for (i=1; i= 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 (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) + if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0) { - /* send extensions */ + command = p[0]; - for (i=0; i 0) - { - recv(sock, &buf, r, MSG_WAITALL); - buf[r] = 0; - printf("%s", buf); - } + case PI_CMD_PROC: + cmd.p2 = 0; break; } + + if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) + { + put_extensions(sock, command, p, v); + + 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("send failed, %m"); } - else fatal("recv failed, %m"); + else fatal("%s only allowed within a script", cmdInfo[idx].name); } - else fatal("send failed, %m"); + else fatal("%s? pigs h for help", cmdStr()); } - else fatal("what? 'pigs h' for help"); } else fatal("connect failed, %m"); diff --git a/setup.py b/setup.py index 3a8ea36..dc6e304 100644 --- a/setup.py +++ b/setup.py @@ -3,15 +3,15 @@ from distutils.core import setup setup(name='pigpio', - version='1.3', + version='1.4', author='joan', - author_email='joan@abyz.me.uk', + author_email='joan@abyz.co.uk', maintainer='joan', - maintainer_email='joan@abyz.me.uk', + maintainer_email='joan@abyz.co.uk', url='http://abyz.co.uk/rpi/pigpio/python.html/', description='Raspberry Pi gpio module', - long_description='Raspberry Pi Python module for access to the pigpio daemon', + long_description='Raspberry Pi Python module to access the pigpio daemon', download_url='http://abyz.co.uk/rpi/pigpio/pigpio.zip', - license='TBD', + license='unlicense.org', py_modules=['pigpio'] ) diff --git a/x_pigpio.c b/x_pigpio.c new file mode 100644 index 0000000..d884f4d --- /dev/null +++ b/x_pigpio.c @@ -0,0 +1,638 @@ +/* +gcc -o x_pigpio x_pigpio.c -lpigpio -lrt -lpthread +sudo ./x_pigpio +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "pigpio.h" + +#define USERDATA 18249013 + +#define GPIO 4 + +void CHECK(int t, int st, int got, int expect, int pc, char *desc) +{ + if ((got >= (((1E2-pc)*expect)/1E2)) && (got <= (((1E2+pc)*expect)/1E2))) + { + printf("TEST %2d.%-2d PASS (%s: %d)\n", t, st, desc, expect); + } + else + { + fprintf(stderr, + "TEST %2d.%-2d FAILED got %d (%s: %d)\n", + t, st, got, desc, expect); + } +} + +void t0() +{ + printf("Version.\n"); + + printf("pigpio version %d.\n", gpioVersion()); + + printf("Hardware revision %d.\n", gpioHardwareRevision()); +} + +void t1() +{ + int v; + + printf("Mode/PUD/read/write tests.\n"); + + gpioSetMode(GPIO, PI_INPUT); + v = gpioGetMode(GPIO); + CHECK(1, 1, v, 0, 0, "set mode, get mode"); + + gpioSetPullUpDown(GPIO, PI_PUD_UP); + v = gpioRead(GPIO); + CHECK(1, 2, v, 1, 0, "set pull up down, read"); + + gpioSetPullUpDown(GPIO, PI_PUD_DOWN); + v = gpioRead(GPIO); + CHECK(1, 3, v, 0, 0, "set pull up down, read"); + + gpioWrite(GPIO, PI_LOW); + v = gpioGetMode(GPIO); + CHECK(1, 4, v, 1, 0, "write, get mode"); + + v = gpioRead(GPIO); + CHECK(1, 5, v, 0, 0, "read"); + + gpioWrite(GPIO, PI_HIGH); + v = gpioRead(GPIO); + CHECK(1, 6, v, 1, 0, "write, read"); +} + +int t2_count=0; + +void t2cb(int gpio, int level, uint32_t tick) +{ + t2_count++; +} + +void t2() +{ + int f, r, rr, oc; + + printf("PWM dutycycle/range/frequency tests.\n"); + + gpioSetPWMrange(GPIO, 255); + gpioSetPWMfrequency(GPIO, 0); + f = gpioGetPWMfrequency(GPIO); + CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency"); + + gpioSetAlertFunc(GPIO, t2cb); + + gpioPWM(GPIO, 0); + time_sleep(0.5); /* allow old notifications to flush */ + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback"); + + gpioPWM(GPIO, 128); + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback"); + + gpioSetPWMfrequency(GPIO, 100); + f = gpioGetPWMfrequency(GPIO); + CHECK(2, 4, f, 100, 0, "set/get PWM frequency"); + + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 5, f, 400, 1, "callback"); + + gpioSetPWMfrequency(GPIO, 1000); + f = gpioGetPWMfrequency(GPIO); + CHECK(2, 6, f, 1000, 0, "set/get PWM frequency"); + + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 7, f, 4000, 1, "callback"); + + r = gpioGetPWMrange(GPIO); + CHECK(2, 8, r, 255, 0, "get PWM range"); + + rr = gpioGetPWMrealRange(GPIO); + CHECK(2, 9, rr, 200, 0, "get PWM real range"); + + gpioSetPWMrange(GPIO, 2000); + r = gpioGetPWMrange(GPIO); + CHECK(2, 10, r, 2000, 0, "set/get PWM range"); + + rr = gpioGetPWMrealRange(GPIO); + CHECK(2, 11, rr, 200, 0, "get PWM real range"); + + gpioPWM(GPIO, 0); +} + +int t3_val = USERDATA; +int t3_reset=1; +int t3_count=0; +uint32_t t3_tick=0; +float t3_on=0.0; +float t3_off=0.0; + +void t3cbf(int gpio, int level, uint32_t tick, void *userdata) +{ + static int unreported = 1; + + uint32_t td; + int *val; + + val = userdata; + + if (*val != USERDATA) + { + if (unreported) + { + fprintf + ( + stderr, + "unexpected userdata %d (expected %d)\n", + *val, USERDATA + ); + } + unreported = 0; + } + + if (t3_reset) + { + t3_count = 0; + t3_on = 0.0; + t3_off = 0.0; + t3_reset = 0; + } + else + { + td = tick - t3_tick; + + if (level == 0) t3_on += td; + else t3_off += td; + } + + t3_count ++; + t3_tick = tick; +} + +void t3() +{ + int f, rr; + + float on, off; + + int t; + + int pw[3]={500, 1500, 2500}; + int dc[4]={20, 40, 60, 80}; + + printf("PWM/Servo pulse accuracy tests.\n"); + + gpioSetAlertFuncEx(GPIO, t3cbf, &t3_val); /* test extended alert */ + + for (t=0; t<3; t++) + { + gpioServo(GPIO, pw[t]); + time_sleep(1); + t3_reset = 1; + time_sleep(4); + on = t3_on; + off = t3_off; + CHECK(3, 1+t, (1E3*(on+off))/on, 2E7/pw[t], 1, + "set servo pulsewidth"); + } + + gpioServo(GPIO, 0); + gpioSetPWMfrequency(GPIO, 1000); + f = gpioGetPWMfrequency(GPIO); + CHECK(3, 4, f, 1000, 0, "set/get PWM frequency"); + + rr = gpioSetPWMrange(GPIO, 100); + CHECK(3, 5, rr, 200, 0, "set PWM range"); + + for (t=0; t<4; t++) + { + gpioPWM(GPIO, dc[t]); + time_sleep(1); + t3_reset = 1; + time_sleep(2); + on = t3_on; + off = t3_off; + CHECK(3, 6+t, (1E3*on)/(on+off), 1E1*dc[t], 1, + "set PWM dutycycle"); + } + + gpioPWM(GPIO, 0); +} + +void t4() +{ + int h, e, f, n, s, b, l, seq_ok, toggle_ok; + gpioReport_t r; + char p[32]; + + printf("Pipe notification tests.\n"); + + gpioSetPWMfrequency(GPIO, 0); + gpioPWM(GPIO, 0); + gpioSetPWMrange(GPIO, 100); + + h = gpioNotifyOpen(); + e = gpioNotifyBegin(h, (1<<4)); + CHECK(4, 1, e, 0, 0, "notify open/begin"); + + time_sleep(1); + + sprintf(p, "/dev/pigpio%d", h); + + f = open(p, O_RDONLY); + + gpioPWM(GPIO, 50); + time_sleep(4); + gpioPWM(GPIO, 0); + + e = gpioNotifyPause(h); + CHECK(4, 2, e, 0, 0, "notify pause"); + + e = gpioNotifyClose(h); + CHECK(4, 3, e, 0, 0, "notify close"); + + n = 0; + s = 0; + l = 0; + seq_ok = 1; + toggle_ok = 1; + + while (1) + { + b = read(f, &r, 12); + if (b == 12) + { + if (s != r.seqno) seq_ok = 0; + + if (n) if (l != (r.level&(1<<4))) toggle_ok = 0; + + if (r.level&(1<<4)) l = 0; + else l = (1<<4); + + s++; + n++; + + // printf("%d %d %d %X\n", r.seqno, r.flags, r.tick, r.level); + } + else break; + } + + close(f); + + CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok"); + + CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok"); + + CHECK(4, 6, n, 80, 10, "number of notifications"); +} + +int t5_count = 0; + +void t5cbf(int gpio, int level, uint32_t tick) +{ + if (level == 0) t5_count++; /* falling edges */ +} + +void t5() +{ + int BAUD=4800; + + char *TEXT= +"\n\ +Now is the winter of our discontent\n\ +Made glorious summer by this sun of York;\n\ +And all the clouds that lour'd upon our house\n\ +In the deep bosom of the ocean buried.\n\ +Now are our brows bound with victorious wreaths;\n\ +Our bruised arms hung up for monuments;\n\ +Our stern alarums changed to merry meetings,\n\ +Our dreadful marches to delightful measures.\n\ +Grim-visaged war hath smooth'd his wrinkled front;\n\ +And now, instead of mounting barded steeds\n\ +To fright the souls of fearful adversaries,\n\ +He capers nimbly in a lady's chamber\n\ +To the lascivious pleasing of a lute.\n\ +"; + + gpioPulse_t wf[] = + { + {1< 0) text[c] = 0; + CHECK(5, 11, strcmp(TEXT, text), 0, 0, "wave tx busy, serial read"); + + e = gpioSerialReadClose(GPIO); + CHECK(5, 12, e, 0, 0, "serial read close"); + + c = gpioWaveGetMicros(); + CHECK(5, 13, c, 6158704, 0, "wave get micros"); + + c = gpioWaveGetHighMicros(); + CHECK(5, 14, c, 6158704, 0, "wave get high micros"); + + c = gpioWaveGetMaxMicros(); + CHECK(5, 15, c, 1800000000, 0, "wave get max micros"); + + c = gpioWaveGetPulses(); + CHECK(5, 16, c, 3405, 0, "wave get pulses"); + + c = gpioWaveGetHighPulses(); + CHECK(5, 17, c, 3405, 0, "wave get high pulses"); + + c = gpioWaveGetMaxPulses(); + CHECK(5, 18, c, 12000, 0, "wave get max pulses"); + + c = gpioWaveGetCbs(); + CHECK(5, 19, c, 6810, 0, "wave get cbs"); + + c = gpioWaveGetHighCbs(); + CHECK(5, 20, c, 6810, 0, "wave get high cbs"); + + c = gpioWaveGetMaxCbs(); + CHECK(5, 21, c, 25016, 0, "wave get max cbs"); +} + +int t6_count=0; +int t6_on=0; +uint32_t t6_on_tick=0; + +void t6cbf(int gpio, int level, uint32_t tick) +{ + if (level == 1) + { + t6_on_tick = tick; + t6_count++; + } + else + { + if (t6_on_tick) t6_on += (tick - t6_on_tick); + } +} + +void t6() +{ + int tp, t, p; + + printf("Trigger tests\n"); + + gpioWrite(GPIO, PI_LOW); + + tp = 0; + + gpioSetAlertFunc(GPIO, t6cbf); + + for (t=0; t<10; t++) + { + time_sleep(0.1); + p = 10 + (t*10); + tp += p; + gpioTrigger(4, p, 1); + } + + time_sleep(0.2); + + CHECK(6, 1, t6_count, 10, 0, "gpio trigger count"); + + CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length"); +} + +int t7_count=0; + +void t7cbf(int gpio, int level, uint32_t tick) +{ + if (level == PI_TIMEOUT) t7_count++; +} + +void t7() +{ + int c, oc; + + printf("Watchdog tests.\n"); + + /* type of edge shouldn't matter for watchdogs */ + gpioSetAlertFunc(GPIO, t7cbf); + + gpioSetWatchdog(GPIO, 10); /* 10 ms, 100 per second */ + time_sleep(0.5); + oc = t7_count; + time_sleep(2); + c = t7_count - oc; + CHECK(7, 1, c, 200, 1, "set watchdog on count"); + + gpioSetWatchdog(GPIO, 0); /* 0 switches watchdog off */ + time_sleep(0.5); + oc = t7_count; + time_sleep(2); + c = t7_count - oc; + CHECK(7, 2, c, 0, 1, "set watchdog off count"); +} + +void t8() +{ + int v, t, i; + + printf("Bank read/write tests.\n"); + + gpioWrite(GPIO, 0); + v = gpioRead_Bits_0_31() & (1<= (((1E2-pc)*expect)/1E2) and got <= (((1E2+pc)*expect)/1E2): + print("TEST {:2d}.{:<2d} PASS ({}: {:d})".format(t, st, desc, expect)) + else: + print("TEST {:2d}.{:<2d} FAILED got {:d} ({}: {:d})". + format(t, st, got, desc, expect)) + +def t0(): + print("Version.") + + print("pigpio version {}.".format(pigpio.get_pigpio_version())) + + print("Hardware revision {}.".format(pigpio.get_hardware_revision())) + +def t1(): + + print("Mode/PUD/read/write tests.") + + pigpio.set_mode(GPIO, pigpio.INPUT) + v = pigpio.get_mode(GPIO) + CHECK(1, 1, v, 0, 0, "set mode, get mode") + + pigpio.set_pull_up_down(GPIO, pigpio.PUD_UP) + v = pigpio.read(GPIO) + CHECK(1, 2, v, 1, 0, "set pull up down, read") + + pigpio.set_pull_up_down(GPIO, pigpio.PUD_DOWN) + v = pigpio.read(GPIO) + CHECK(1, 3, v, 0, 0, "set pull up down, read") + + pigpio.write(GPIO, pigpio.LOW) + v = pigpio.get_mode(GPIO) + CHECK(1, 4, v, 1, 0, "write, get mode") + + v = pigpio.read(GPIO) + CHECK(1, 5, v, 0, 0, "read") + + pigpio.write(GPIO, pigpio.HIGH) + v = pigpio.read(GPIO) + CHECK(1, 6, v, 1, 0, "write, read") + +t2_count=0 + +def t2cbf(gpio, level, tick): + global t2_count + t2_count += 1 + +def t2(): + global t2_count + + print("PWM dutycycle/range/frequency tests.") + + pigpio.set_PWM_range(GPIO, 255) + pigpio.set_PWM_frequency(GPIO,0) + f = pigpio.get_PWM_frequency(GPIO) + CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency") + + t2cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t2cbf) + + pigpio.set_PWM_dutycycle(GPIO, 0) + time.sleep(0.5) # allow old notifications to flush + oc = t2_count + time.sleep(2) + f = t2_count - oc + CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback") + + pigpio.set_PWM_dutycycle(GPIO, 128) + time.sleep(1) + oc = t2_count + time.sleep(2) + f = t2_count - oc + CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback") + + pigpio.set_PWM_frequency(GPIO,100) + f = pigpio.get_PWM_frequency(GPIO) + CHECK(2, 4, f, 100, 0, "set/get PWM frequency") + + time.sleep(1) + oc = t2_count + time.sleep(2) + f = t2_count - oc + CHECK(2, 5, f, 400, 1, "callback") + + pigpio.set_PWM_frequency(GPIO,1000) + f = pigpio.get_PWM_frequency(GPIO) + CHECK(2, 6, f, 1000, 0, "set/get PWM frequency") + + time.sleep(1) + oc = t2_count + time.sleep(2) + f = t2_count - oc + CHECK(2, 7, f, 4000, 1, "callback") + + r = pigpio.get_PWM_range(GPIO) + CHECK(2, 8, r, 255, 0, "get PWM range") + + rr = pigpio.get_PWM_real_range(GPIO) + CHECK(2, 9, rr, 200, 0, "get PWM real range") + + pigpio.set_PWM_range(GPIO, 2000) + r = pigpio.get_PWM_range(GPIO) + CHECK(2, 10, r, 2000, 0, "set/get PWM range") + + rr = pigpio.get_PWM_real_range(GPIO) + CHECK(2, 11, rr, 200, 0, "get PWM real range") + + pigpio.set_PWM_dutycycle(GPIO, 0) + +t3_reset=True +t3_count=0 +t3_tick=0 +t3_on=0.0 +t3_off=0.0 + +def t3cbf(gpio, level, tick): + global t3_reset, t3_count, t3_tick, t3_on, t3_off + + if t3_reset: + t3_count = 0 + t3_on = 0.0 + t3_off = 0.0 + t3_reset = False + else: + td = pigpio.tickDiff(t3_tick, tick) + + if level == 0: + t3_on += td + else: + t3_off += td + + t3_count += 1 + t3_tick = tick + +def t3(): + global t3_reset, t3_count, t3_on, t3_off + + pw=[500.0, 1500.0, 2500.0] + dc=[0.2, 0.4, 0.6, 0.8] + + print("PWM/Servo pulse accuracy tests.") + + t3cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t3cbf) + + t = 0 + for x in pw: + t += 1 + pigpio.set_servo_pulsewidth(GPIO, x) + time.sleep(1) + t3_reset = True + time.sleep(4) + c = t3_count + on = t3_on + off = t3_off + CHECK(3, t, int((1E3*(on+off))/on), int(2E7/x), 1, "set servo pulsewidth") + + + pigpio.set_servo_pulsewidth(GPIO, 0) + pigpio.set_PWM_frequency(GPIO, 1000) + f = pigpio.get_PWM_frequency(GPIO) + CHECK(3, 4, f, 1000, 0, "set/get PWM frequency") + + rr = pigpio.set_PWM_range(GPIO, 100) + CHECK(3, 5, rr, 200, 0, "set PWM range") + + t = 5 + for x in dc: + t += 1 + pigpio.set_PWM_dutycycle(GPIO, x*100) + time.sleep(1) + t3_reset = True + time.sleep(2) + c = t3_count + on = t3_on + off = t3_off + CHECK(3, t, int((1E3*on)/(on+off)), int(1E3*x), 1, "set PWM dutycycle") + + pigpio.set_PWM_dutycycle(GPIO, 0) + +def t4(): + + print("Pipe notification tests.") + + pigpio.set_PWM_frequency(GPIO, 0) + pigpio.set_PWM_dutycycle(GPIO, 0) + pigpio.set_PWM_range(GPIO, 100) + + h = pigpio.notify_open() + e = pigpio.notify_begin(h, (1<<4)) + CHECK(4, 1, e, 0, 0, "notify open/begin") + + time.sleep(1) + + with open("/dev/pigpio"+ str(h), "rb") as f: + + pigpio.set_PWM_dutycycle(GPIO, 50) + time.sleep(4) + pigpio.set_PWM_dutycycle(GPIO, 0) + + e = pigpio.notify_pause(h) + CHECK(4, 2, e, 0, 0, "notify pause") + + e = pigpio.notify_close(h) + CHECK(4, 3, e, 0, 0, "notify close") + + n = 0 + s = 0 + + seq_ok = 1 + toggle_ok = 1 + + while True: + + chunk = f.read(12) + + if len(chunk) == 12: + + S, fl, t, v = struct.unpack('HHII', chunk) + if s != S: + seq_ok = 0 + + + L = v & (1<<4) + + if n: + if l != L: + toggle_ok = 0 + + if L: + l = 0 + else: + l = (1<<4) + + s += 1 + n += 1 + + # print(S, fl, t, hex(v)) + + else: + break + + f.close() + + CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok") + + CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok") + + CHECK(4, 6, n, 80, 10, "number of notifications") + +t5_count = 0 + +def t5cbf(gpio, level, tick): + global t5_count + t5_count += 1 + +def t5(): + global t5_count + + BAUD=4800 + + TEXT=""" +Now is the winter of our discontent +Made glorious summer by this sun of York; +And all the clouds that lour'd upon our house +In the deep bosom of the ocean buried. +Now are our brows bound with victorious wreaths; +Our bruised arms hung up for monuments; +Our stern alarums changed to merry meetings, +Our dreadful marches to delightful measures. +Grim-visaged war hath smooth'd his wrinkled front; +And now, instead of mounting barded steeds +To fright the souls of fearful adversaries, +He capers nimbly in a lady's chamber +To the lascivious pleasing of a lute. +""" + + print("Waveforms & serial read/write tests.") + + t5cb = pigpio.callback(GPIO, pigpio.FALLING_EDGE, t5cbf) + + pigpio.set_mode(GPIO, pigpio.OUTPUT) + + e = pigpio.wave_clear() + CHECK(5, 1, e, 0, 0, "callback, set mode, wave clear") + + wf = [] + + wf.append(pigpio.pulse(1< +#include +#include +#include +#include +#include + +#include "pigpiod_if.h" + +#define GPIO 4 + +void CHECK(int t, int st, int got, int expect, int pc, char *desc) +{ + if ((got >= (((1E2-pc)*expect)/1E2)) && (got <= (((1E2+pc)*expect)/1E2))) + { + printf("TEST %2d.%-2d PASS (%s: %d)\n", t, st, desc, expect); + } + else + { + fprintf(stderr, + "TEST %2d.%-2d FAILED got %d (%s: %d)\n", + t, st, got, desc, expect); + } +} + +void t0() +{ + printf("Version.\n"); + + printf("pigpio version %d.\n", get_pigpio_version()); + + printf("Hardware revision %d.\n", get_hardware_revision()); +} + +void t1() +{ + int v; + + printf("Mode/PUD/read/write tests.\n"); + + set_mode(GPIO, PI_INPUT); + v = get_mode(GPIO); + CHECK(1, 1, v, 0, 0, "set mode, get mode"); + + set_pull_up_down(GPIO, PI_PUD_UP); + v = gpio_read(GPIO); + CHECK(1, 2, v, 1, 0, "set pull up down, read"); + + set_pull_up_down(GPIO, PI_PUD_DOWN); + v = gpio_read(GPIO); + CHECK(1, 3, v, 0, 0, "set pull up down, read"); + + gpio_write(GPIO, PI_LOW); + v = get_mode(GPIO); + CHECK(1, 4, v, 1, 0, "write, get mode"); + + v = gpio_read(GPIO); + CHECK(1, 5, v, 0, 0, "read"); + + gpio_write(GPIO, PI_HIGH); + v = gpio_read(GPIO); + CHECK(1, 6, v, 1, 0, "write, read"); +} + +int t2_count=0; + +void t2cb(unsigned gpio, unsigned level, uint32_t tick) +{ + t2_count++; +} + +void t2() +{ + int f, r, rr, oc; + + printf("PWM dutycycle/range/frequency tests.\n"); + + set_PWM_range(GPIO, 255); + set_PWM_frequency(GPIO, 0); + f = get_PWM_frequency(GPIO); + CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency"); + + callback(GPIO, EITHER_EDGE, t2cb); + + set_PWM_dutycycle(GPIO, 0); + time_sleep(0.5); /* allow old notifications to flush */ + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback"); + + set_PWM_dutycycle(GPIO, 128); + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback"); + + set_PWM_frequency(GPIO, 100); + f = get_PWM_frequency(GPIO); + CHECK(2, 4, f, 100, 0, "set/get PWM frequency"); + + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 5, f, 400, 1, "callback"); + + set_PWM_frequency(GPIO, 1000); + f = get_PWM_frequency(GPIO); + CHECK(2, 6, f, 1000, 0, "set/get PWM frequency"); + + oc = t2_count; + time_sleep(2); + f = t2_count - oc; + CHECK(2, 7, f, 4000, 1, "callback"); + + r = get_PWM_range(GPIO); + CHECK(2, 8, r, 255, 0, "get PWM range"); + + rr = get_PWM_real_range(GPIO); + CHECK(2, 9, rr, 200, 0, "get PWM real range"); + + set_PWM_range(GPIO, 2000); + r = get_PWM_range(GPIO); + CHECK(2, 10, r, 2000, 0, "set/get PWM range"); + + rr = get_PWM_real_range(GPIO); + CHECK(2, 11, rr, 200, 0, "get PWM real range"); + + set_PWM_dutycycle(GPIO, 0); +} + +int t3_reset=1; +int t3_count=0; +uint32_t t3_tick=0; +float t3_on=0.0; +float t3_off=0.0; + +void t3cbf(unsigned gpio, unsigned level, uint32_t tick) +{ + uint32_t td; + + if (t3_reset) + { + t3_count = 0; + t3_on = 0.0; + t3_off = 0.0; + t3_reset = 0; + } + else + { + td = tick - t3_tick; + + if (level == 0) t3_on += td; + else t3_off += td; + } + + t3_count ++; + t3_tick = tick; +} + +void t3() +{ + int pw[3]={500, 1500, 2500}; + int dc[4]={20, 40, 60, 80}; + + int f, rr; + float on, off; + + int t; + + printf("PWM/Servo pulse accuracy tests.\n"); + + callback(GPIO, EITHER_EDGE, t3cbf); + + for (t=0; t<3; t++) + { + set_servo_pulsewidth(GPIO, pw[t]); + time_sleep(1); + t3_reset = 1; + time_sleep(4); + on = t3_on; + off = t3_off; + CHECK(3, 1+t, (1000.0*(on+off))/on, 20000000.0/pw[t], 1, + "set servo pulsewidth"); + } + + set_servo_pulsewidth(GPIO, 0); + set_PWM_frequency(GPIO, 1000); + f = get_PWM_frequency(GPIO); + CHECK(3, 4, f, 1000, 0, "set/get PWM frequency"); + + rr = set_PWM_range(GPIO, 100); + CHECK(3, 5, rr, 200, 0, "set PWM range"); + + for (t=0; t<4; t++) + { + set_PWM_dutycycle(GPIO, dc[t]); + time_sleep(1); + t3_reset = 1; + time_sleep(2); + on = t3_on; + off = t3_off; + CHECK(3, 6+t, (1000.0*on)/(on+off), 10.0*dc[t], 1, + "set PWM dutycycle"); + } + + set_PWM_dutycycle(GPIO, 0); + +} + +void t4() +{ + int h, e, f, n, s, b, l, seq_ok, toggle_ok; + gpioReport_t r; + char p[32]; + + printf("Pipe notification tests.\n"); + + set_PWM_frequency(GPIO, 0); + set_PWM_dutycycle(GPIO, 0); + set_PWM_range(GPIO, 100); + + h = notify_open(); + e = notify_begin(h, (1<<4)); + CHECK(4, 1, e, 0, 0, "notify open/begin"); + + time_sleep(1); + + sprintf(p, "/dev/pigpio%d", h); + + f = open(p, O_RDONLY); + + set_PWM_dutycycle(GPIO, 50); + time_sleep(4); + set_PWM_dutycycle(GPIO, 0); + + e = notify_pause(h); + CHECK(4, 2, e, 0, 0, "notify pause"); + + e = notify_close(h); + CHECK(4, 3, e, 0, 0, "notify close"); + + n = 0; + s = 0; + l = 0; + seq_ok = 1; + toggle_ok = 1; + + while (1) + { + b = read(f, &r, 12); + if (b == 12) + { + if (s != r.seqno) seq_ok = 0; + + if (n) if (l != (r.level&(1<<4))) toggle_ok = 0; + + if (r.level&(1<<4)) l = 0; + else l = (1<<4); + + s++; + n++; + + // printf("%d %d %d %X\n", r.seqno, r.flags, r.tick, r.level); + } + else break; + } + close(f); + + CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok"); + + CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok"); + + CHECK(4, 6, n, 80, 10, "number of notifications"); +} + +int t5_count = 0; + +void t5cbf(unsigned gpio, unsigned level, uint32_t tick) +{ + t5_count++; +} + +void t5() +{ + int BAUD=4800; + + char *TEXT= +"\n\ +Now is the winter of our discontent\n\ +Made glorious summer by this sun of York;\n\ +And all the clouds that lour'd upon our house\n\ +In the deep bosom of the ocean buried.\n\ +Now are our brows bound with victorious wreaths;\n\ +Our bruised arms hung up for monuments;\n\ +Our stern alarums changed to merry meetings,\n\ +Our dreadful marches to delightful measures.\n\ +Grim-visaged war hath smooth'd his wrinkled front;\n\ +And now, instead of mounting barded steeds\n\ +To fright the souls of fearful adversaries,\n\ +He capers nimbly in a lady's chamber\n\ +To the lascivious pleasing of a lute.\n\ +"; + + gpioPulse_t wf[] = + { + {1< 0) text[c] = 0; /* null terminate string */ + CHECK(5, 11, strcmp(TEXT, text), 0, 0, "wave tx busy, serial read"); + + e = serial_read_close(GPIO); + CHECK(5, 12, e, 0, 0, "serial read close"); + + c = wave_get_micros(); + CHECK(5, 13, c, 6158704, 0, "wave get micros"); + + c = wave_get_high_micros(); + CHECK(5, 14, c, 6158704, 0, "wave get high micros"); + + c = wave_get_max_micros(); + CHECK(5, 15, c, 1800000000, 0, "wave get max micros"); + + c = wave_get_pulses(); + CHECK(5, 16, c, 3405, 0, "wave get pulses"); + + c = wave_get_high_pulses(); + CHECK(5, 17, c, 3405, 0, "wave get high pulses"); + + c = wave_get_max_pulses(); + CHECK(5, 18, c, 12000, 0, "wave get max pulses"); + + c = wave_get_cbs(); + CHECK(5, 19, c, 6810, 0, "wave get cbs"); + + c = wave_get_high_cbs(); + CHECK(5, 20, c, 6810, 0, "wave get high cbs"); + + c = wave_get_max_cbs(); + CHECK(5, 21, c, 25016, 0, "wave get max cbs"); +} + +int t6_count=0; +int t6_on=0; +uint32_t t6_on_tick=0; + +void t6cbf(unsigned gpio, unsigned level, uint32_t tick) +{ + if (level == 1) + { + t6_on_tick = tick; + t6_count++; + } + else + { + if (t6_on_tick) t6_on += (tick - t6_on_tick); + } +} + +void t6() +{ + int tp, t, p; + + printf("Trigger tests.\n"); + + gpio_write(GPIO, PI_LOW); + + tp = 0; + + callback(GPIO, EITHER_EDGE, t6cbf); + + time_sleep(0.2); + + for (t=0; t<10; t++) + { + time_sleep(0.1); + p = 10 + (t*10); + tp += p; + gpio_trigger(4, p, 1); + } + + time_sleep(0.5); + + CHECK(6, 1, t6_count, 10, 0, "gpio trigger count"); + + CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length"); +} + +int t7_count=0; + +void t7cbf(unsigned gpio, unsigned level, uint32_t tick) +{ + if (level == PI_TIMEOUT) t7_count++; +} + +void t7() +{ + int c, oc; + + printf("Watchdog tests.\n"); + + /* type of edge shouldn't matter for watchdogs */ + callback(GPIO, FALLING_EDGE, t7cbf); + + set_watchdog(GPIO, 10); /* 10 ms, 100 per second */ + time_sleep(0.5); + oc = t7_count; + time_sleep(2); + c = t7_count - oc; + CHECK(7, 1, c, 200, 1, "set watchdog on count"); + + set_watchdog(GPIO, 0); /* 0 switches watchdog off */ + time_sleep(0.5); + oc = t7_count; + time_sleep(2); + c = t7_count - oc; + CHECK(7, 2, c, 0, 1, "set watchdog off count"); +} + +void t8() +{ + int v, t, i; + + printf("Bank read/write tests.\n"); + + gpio_write(GPIO, 0); + v = read_bank_1() & (1</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 +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 +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 +read -t 1 h /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 +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 +read -t 1 p /dev/pigpio +read -t 1 s /dev/pigpio +read -t 1 -a v /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 +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 +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 +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 +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 +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 +read -t 1 -d ¬ s /dev/pigpio +read -t 1 s /dev/pigpio +echo "tick" >/dev/pigpio +read -t 1 t1 /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 +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 +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 +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 +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 +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 +read -t 1 s