diff --git a/MakeRemote b/MakeRemote index e0f6361..c27fc64 100644 --- a/MakeRemote +++ b/MakeRemote @@ -5,11 +5,11 @@ SIZE = size CFLAGS = -O3 -Wall -ALL = libpigpiod_if.a pigs +ALL = libpigpiod_if.a pigs pigpio.py setup.py all: $(ALL) -pigs: command.o +pigs: command.o pigs.o $(CC) -o pigs pigs.c command.c clean: @@ -41,7 +41,7 @@ $(LIB): $(OBJ) # generated using gcc -MM *.c command.o: command.c pigpio.h command.h -pigpiod.o: pigpiod.c pigpio.h command.h -pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h +pigpiod.o: pigpiod.c pigpio.h +pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h command.h pigs.o: pigs.c pigpio.h command.h diff --git a/Makefile b/Makefile index 6ce0b3d..9b1e561 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ checklib.o: checklib.c pigpio.h command.o: command.c pigpio.h command.h pig2vcd.o: pig2vcd.c pigpio.h pigpio.o: pigpio.c pigpio.h command.h -pigpiod.o: pigpiod.c pigpio.h command.h +pigpiod.o: pigpiod.c pigpio.h pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h pigs.o: pigs.c pigpio.h command.h diff --git a/README b/README index ba15cb6..8737d36 100644 --- a/README +++ b/README @@ -31,8 +31,7 @@ EXAMPLE CODE checklib.c, pig2vcd.c, and pigpiod.c show examples of interfacing with the pigpio library. -pigs.c, pigpio.py, and test_pigpiod_if.c -show examples of interfacing with the pigpiod daemon. +pigs.c and pigpio.py show examples of interfacing with the pigpiod daemon. DAEMON diff --git a/command.c b/command.c index 80b3801..a128a9d 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 10+ +This version is for pigpio version 11+ */ #include @@ -38,79 +38,144 @@ This version is for pigpio version 10+ #include "pigpio.h" #include "command.h" +/* retv + pigs pipe +0 "" <0 ERR %d +1 "" <0 ERR %d +2 %d <0 ERR %d +3 %08X %08X +4 %u %u +5 HELP HELP +*/ + +/* vfyt + 1 cmd + 2 cmd %d + 3 cmd %d %d + 4 cmd %d %x + 6 HELP + 7 cmd %x + 8 MODES %d %c + 9 PUD %d %c +10 PROG %s +*/ + cmdInfo_t cmdInfo[]= { - {PI_CMD_BR1, "BR1", 1, 3}, - {PI_CMD_BR2, "BR2", 1, 3}, - {PI_CMD_BC1, "BC1", 7, 1}, - {PI_CMD_BC2, "BC2", 7, 1}, - {PI_CMD_BS1, "BS1", 7, 1}, - {PI_CMD_BS2, "BS2", 7, 1}, - {PI_CMD_HWVER, "HWVER", 1, 4}, - {PI_CMD_MODES, "MODES", 8, 0}, - {PI_CMD_MODES, "M", 8, 0}, - {PI_CMD_MODEG, "MODEG", 2, 2}, - {PI_CMD_MODEG, "MG" , 2, 2}, - {PI_CMD_NO, "NO", 1, 2}, - {PI_CMD_NB, "NB", 4, 0}, - {PI_CMD_NP, "NP", 2, 0}, - {PI_CMD_NC, "NC", 2, 0}, - {PI_CMD_PWM, "PWM", 3, 0}, - {PI_CMD_PWM, "P", 3, 0}, - {PI_CMD_PFS, "PFS", 3, 2}, - {PI_CMD_PFG, "PFG", 2, 2}, - {PI_CMD_PRS, "PRS", 3, 2}, - {PI_CMD_PRG, "PRG", 2, 2}, - {PI_CMD_PRRG, "PRRG", 2, 2}, - {PI_CMD_PUD, "PUD", 9, 0}, - {PI_CMD_READ, "READ", 2, 2}, - {PI_CMD_READ, "R", 2, 2}, - {PI_CMD_SERVO, "SERVO", 3, 0}, - {PI_CMD_SERVO, "S", 3, 0}, - {PI_CMD_WRITE, "WRITE", 3, 0}, - {PI_CMD_WRITE, "W", 3, 0}, - {PI_CMD_WDOG, "WDOG", 3, 0}, - {PI_CMD_TICK, "TICK", 1, 4}, - {PI_CMD_TICK, "T", 1, 4}, - {PI_CMD_HELP, "HELP", 6, 5}, - {PI_CMD_HELP, "H", 6, 5}, - {PI_CMD_PIGPV, "PIGPV", 1, 4}, + /* num str vfyt retv ext */ + + {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_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 = "\ -BR1 read gpios bank 1\n\ -BR2 read gpios bank 2\n\ BC1 x clear gpios in bank 1\n\ BC2 x clear gpios in bank 2\n\ +BR1 read gpios bank 1\n\ +BR2 read gpios bank 2\n\ BS1 x set gpios in bank 1\n\ BS2 x set gpios in bank 2\n\ +H displays command help\n\ +HELP displays command help\n\ HWVER return hardware version\n\ -MODES/M g m set gpio mode\n\ -MODEG/MG g get gpio mode\n\ -NO request notification handle\n\ +M g m set gpio mode\n\ +MG g get gpio mode\n\ +MODEG g get gpio mode\n\ +MODES g m set gpio mode\n\ NB h x start notification\n\ -NP h pause notification\n\ NC h close notification\n\ -PWM/P u d set PWM value for gpio\n\ -PFS u d set PWM frequency for gpio\n\ +NO request notification handle\n\ +NP h pause notification\n\ +P u d set PWM value for gpio\n\ PFG u get PWM frequency for gpio\n\ +PFS u d set PWM frequency for gpio\n\ PIGPV return pigpio version\n\ -PRS u d set PWM range for gpio\n\ PRG u get PWM range for gpio\n\ +PROC t validate and store script\n\ +PROCD s delete script\n\ +PROCR s run script\n\ +PROCS s stop script\n\ PRRG u get PWM real range for gpio\n\ +PRS u d set PWM range for gpio\n\ PUD g p set gpio pull up/down\n\ -READ/R g read gpio\n\ -SERVO/S u d set servo value for gpio\n\ -WRITE/W g d write value to gpio\n\ +PWM u d set PWM value for gpio\n\ +R g read gpio\n\ +READ g read gpio\n\ +S u d set servo value for gpio\n\ +SERVO u d set servo value for gpio\n\ +T return current tick\n\ +TICK return current tick\n\ +TRIG u pl l trigger level l for pl micros on gpio\n\ +W g l write level to gpio\n\ WDOG u d set watchdog on gpio\n\ -TICK/T return current tick\n\ -HELP/H displays command help\n\ +WRITE g l write level to gpio\n\ +WVAS u b t wave add serial data\n\ +WVBSY check if wave busy\n\ +WVCLR wave clear\n\ +WVGO wave transmit\n\ +WVGOR wave transmit repeat\n\ +WVHLT wave stop\n\ +WVSC ws wave get cbs 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\ h = handle (0-31)\n\ +l = level (0-1)\n\ m = mode (RW540123)\n\ p = pud (ODU)\n\ +pl = pulse length (0-100)\n\ +s = script id\n\ +t = text\n\ u = user gpio (0-31)\n\ x = hex value\n\ "; @@ -130,7 +195,7 @@ static errInfo_t errInfo[]= {PI_BAD_LEVEL , "level not 0-1"}, {PI_BAD_PUD , "pud not 0-2"}, {PI_BAD_PULSEWIDTH , "pulsewidth not 0 or 500-2500"}, - {PI_BAD_DUTYCYCLE , "dutycycle not 0-255"}, + {PI_BAD_DUTYCYCLE , "dutycycle outside set range"}, {PI_BAD_TIMER , "timer not 0-9"}, {PI_BAD_MS , "ms not 10-60000"}, {PI_BAD_TIMETYPE , "timetype not 0-1"}, @@ -165,6 +230,13 @@ static errInfo_t errInfo[]= {PI_BAD_SERIAL_BUF , "bad (null) serial buf parameter"}, {PI_NOT_PERMITTED , "no permission to update gpio"}, {PI_SOME_PERMITTED , "no permission to update one or more gpios"}, + {PI_BAD_WVSC_COMMND , "bad WVSC subcommand"}, + {PI_BAD_WVSM_COMMND , "bad WVSM subcommand"}, + {PI_BAD_WVSP_COMMND , "bad WVSP subcommand"}, + {PI_BAD_PULSELEN , "trigger pulse > 100 microseconds"}, + {PI_BAD_SCRIPT , "invalid script"}, + {PI_BAD_SCRIPT_ID , "unknown script id"}, + {PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"}, }; static char * fmtMdeStr="RW540123"; @@ -181,11 +253,11 @@ static int cmdMatch(char * str) return -1; } -int cmdParse(char * buf, cmdCmd_t * cmd) +int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext) { char str[8]; int f, valid, idx, val; - char * ptr; + char *ptr; char c, t; sscanf(buf, " %7s", str); @@ -204,36 +276,57 @@ int cmdParse(char * buf, cmdCmd_t * cmd) switch (cmdInfo[idx].vt) { - case 1: /* BR1 BR2 HWVER PIGPV NO TICK */ + 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; break; - case 2: /* MODEG READ NC NP PFG PRG PRRG */ + case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG READ + WVSC WVSM WVSP + */ f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t); if (f == 2) valid = 1; break; - - case 3: /* WRITE PWM PRS PFS SERVO WDOG */ + + case 3: /* PFS PRS PWM SERVO WDOG WRITE + */ f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t); if (f == 3) valid = 1; break; - - case 4: /* NB */ + + case 4: /* NB + */ f = sscanf(buf, " %7s %d %x %c", str, &cmd->p1, &cmd->p2, &t); if (f == 3) valid = 1; break; - - case 6: /* HELP */ + + 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].n = sizeof(unsigned); + ext[0].ptr = &ext[0].data; + valid = 1; + } + break; + + case 6: /* HELP + */ valid = 1; break; - - case 7: /* BC1 BC2 BS1 BS2 */ + + case 7: /* BC1 BC2 BS1 BS2 + */ f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t); if (f == 2) valid = 1; break; - - case 8: /* MODES */ + + case 8: /* MODES + */ f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t); if (f == 3) { @@ -248,7 +341,8 @@ int cmdParse(char * buf, cmdCmd_t * cmd) } break; - case 9: /* PUD */ + case 9: /* PUD + */ f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t); if (f == 3) { @@ -262,28 +356,43 @@ int cmdParse(char * buf, cmdCmd_t * cmd) } } break; + + case 10: /* PROC + */ + if (argc == 3) + { + cmd->p1 = strlen(argv[2]); + ext[0].n = cmd->p1; + ext[0].ptr = argv[2]; + valid = 1; + } + break; + + case 11: /* WVAS + */ + if (argc == 6) + { + f = sscanf(buf, " %7s %d %d %d ", + str, &cmd->p1, &ext[0].data, &ext[1].data); + if (f == 4) + { + ext[0].n = sizeof(unsigned); + ext[0].ptr = &ext[0].data; + ext[1].n = sizeof(unsigned); + ext[1].ptr = &ext[1].data; + cmd->p2 = strlen(argv[5]); + ext[2].n = cmd->p2; + ext[2].ptr = argv[5]; + valid = 1; + } + } + break; } if (valid) return idx; else return -1; } -void cmdFatal(char *fmt, ...) -{ - char buf[128]; - va_list ap; - - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - fprintf(stderr, "%s\n", buf); - - fflush(stderr); - - exit(EXIT_FAILURE); -} - char * cmdErrStr(int error) { int i; diff --git a/command.h b/command.h index 6ace8c7..bdffefb 100644 --- a/command.h +++ b/command.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 7+ +This version is for pigpio version 11+ */ #ifndef COMMAND_H @@ -43,16 +43,17 @@ typedef struct char * name; /* command name */ int vt; /* command verification type */ int rv; /* command return value type */ + int ext; /* command has extensions */ } cmdInfo_t; extern cmdInfo_t cmdInfo[]; extern char * cmdUsage; -int cmdParse(char * buf, cmdCmd_t * cmd); +int cmdParse + (char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t * ext); char * cmdErrStr(int error); -void cmdFatal(char *fmt, ...); - #endif + diff --git a/pigpio.c b/pigpio.c index 510b45a..2c37817 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 10 */ +/* pigpio version 11 */ #include #include @@ -752,7 +752,7 @@ static int wfcur=0; static wfStats_t wfStats= { - 0, 0, -1, + 0, 0, PI_WAVE_MAX_MICROS, 0, 0, PI_WAVE_MAX_PULSES, 0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE) }; @@ -765,7 +765,7 @@ static volatile uint32_t notifyBits = 0; static volatile int DMAstarted = 0; -static int libInitialised = 0; +static int libInitialised = 0; static int pthAlertRunning = 0; static int pthFifoRunning = 0; @@ -881,7 +881,7 @@ static uint32_t myGpioDelay(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 myGpioSleep(micros/MILLION, micros%MILLION); @@ -977,104 +977,19 @@ static uint32_t myGetTick(int pos) /* ----------------------------------------------------------------------- */ -static void myDoCommand(cmdCmd_t * cmd) +static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext) { - int p1, p2, res; - uint32_t mask; + int p1, p2, res, i; + uint32_t mask, tmp; + gpioPulse_t *pulse; + int masked; p1 = cmd->p1; p2 = cmd->p2; - - res = 0; + res = cmd->res; switch (cmd->cmd) { - case PI_CMD_MODES: - if (gpioMask & (uint64_t)(1<= 0)) res = PI_SOME_PERMITTED; + break; - case PI_CMD_PIGPV: - res = gpioVersion(); + case PI_CMD_WVAS: + if (gpioMask & (uint64_t)(1<res = res; + case PI_CMD_WVCLR: res = gpioWaveClear(); break; + + case PI_CMD_WVGO: res = gpioWaveTxStart(PI_WAVE_MODE_ONE_SHOT); break; + + case PI_CMD_WVGOR: res = gpioWaveTxStart(PI_WAVE_MODE_REPEAT); break; + + case PI_CMD_WVHLT: res = gpioWaveTxStop(); break; + + case PI_CMD_WVSC: + switch(p1) + { + case 0: res = gpioWaveGetCbs(); break; + case 1: res = gpioWaveGetHighCbs(); break; + case 2: res = gpioWaveGetMaxCbs(); break; + default: res = -9999; + } + break; + + case PI_CMD_WVSM: + switch(p1) + { + case 0: res = gpioWaveGetMicros(); break; + case 1: res = gpioWaveGetHighMicros(); break; + case 2: res = gpioWaveGetMaxMicros(); break; + default: res = -9999; + } + break; + + case PI_CMD_WVSP: + switch(p1) + { + case 0: res = gpioWaveGetPulses(); break; + case 1: res = gpioWaveGetHighPulses(); break; + case 2: res = gpioWaveGetMaxPulses(); break; + default: res = -9999; + } + break; + } + cmd->res = res; } /* ----------------------------------------------------------------------- */ @@ -2545,9 +2621,10 @@ static void * pthTimerTick(void *x) static void * pthFifoThread(void *x) { - char inBuf[128]; + char inBuf[256]; int idx, flags; cmdCmd_t cmd; + gpioExtent_t ext[3]; myCreatePipe(PI_INPFIFO, 0662); @@ -2569,9 +2646,9 @@ static void * pthFifoThread(void *x) if (fgets(inBuf, sizeof(inBuf), inpFifo) == NULL) SOFT_ERROR((void*)PI_INIT_FAILED, "fifo fgets failed (%m)"); - if ((idx=cmdParse(inBuf, &cmd)) >= 0) + if ((idx=cmdParse(inBuf, &cmd, 0, NULL, ext)) >= 0) { - myDoCommand(&cmd); + myDoCommand(&cmd, NULL); switch (cmdInfo[idx].rv) { @@ -2611,24 +2688,150 @@ static void * pthFifoThread(void *x) /* ----------------------------------------------------------------------- */ -static void * pthSocketThreadHandler(void *fdC) +static void *pthSocketThreadHandler(void *fdC) { int sock = *(int*)fdC; cmdCmd_t cmd; - + unsigned bytes; + char *memPtr; + gpioExtent_t ext[3]; + unsigned tmp; + free(fdC); while(1) { - if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) + if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) == sizeof(cmdCmd_t)) { - if (cmd.cmd != PI_CMD_NOIB) + if (cmd.cmd == PI_CMD_NOIB) { - myDoCommand(&cmd); + cmd.res = gpioNotifyOpenInBand(sock); + } + else if (cmd.cmd == PI_CMD_WVAG) + { + /* + p1=numPulses + p2=0 + ## extension ## + gpioPulse_t[] pulses + */ + + bytes = cmd.p1 * sizeof(gpioPulse_t); + + memPtr = malloc(bytes); + if (memPtr) + { + if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes) + { + ext[0].n = bytes; + ext[0].ptr = memPtr; + myDoCommand(&cmd, ext); + free(memPtr); + } + else + { + free(memPtr); + break; + } + } + else break; + + } + else if (cmd.cmd == PI_CMD_WVAS) + { + /* + p1=user_gpio + p2=numChar + ## extension ## + unsigned baud + unsigned offset + char[] str + */ + + bytes = sizeof(unsigned) + sizeof(unsigned) + cmd.p2; + + memPtr = malloc(bytes+1); /* add 1 for a nul terminator */ + + if (memPtr) + { + if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes) + { + ext[0].n = sizeof(unsigned); + ext[0].ptr = memPtr; + ext[1].n = sizeof(unsigned); + ext[1].ptr = memPtr + sizeof(unsigned); + ext[2].n = cmd.p2; + ext[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned); + memPtr[bytes] = 0; /* may be duplicate terminator */ + myDoCommand(&cmd, ext); + free(memPtr); + } + else + { + free(memPtr); + break; + } + } + else break; + + } + else if (cmd.cmd == PI_CMD_PROC) + { + /* + p1=script length + p2=0 + ## extension ## + char[] script + */ + + bytes = cmd.p1; + + memPtr = malloc(bytes+1); /* add 1 for a nul terminator */ + if (memPtr) + { + if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes) + { + ext[0].n = bytes; + ext[0].ptr = memPtr; + memPtr[bytes] = 0; /* may be duplicate terminator */ + myDoCommand(&cmd, ext); + free(memPtr); + } + else + { + free(memPtr); + break; + } + } + else break; + } else { - cmd.res = gpioNotifyOpenInBand(sock); + switch (cmd.cmd) + { + case PI_CMD_TRIG: + /* + p1=user_gpio + p2=pulseLen + ## extension ## + unsigned level + */ + ext[0].n = 4; + ext[0].ptr = &tmp; + + if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) != + sizeof(unsigned)) + { + close(sock); + return 0; + } + break; + + default: + break; + } + myDoCommand(&cmd, ext); } write(sock, &cmd, sizeof(cmdCmd_t)); @@ -2647,10 +2850,8 @@ static void * pthSocketThreadHandler(void *fdC) static void * pthSocketThread(void *x) { int fdC, c, *sock; - struct sockaddr_in server, client; + struct sockaddr_in client; pthread_attr_t attr; - char * portStr; - unsigned port; if (pthread_attr_init(&attr)) SOFT_ERROR((void*)PI_INIT_FAILED, @@ -2664,21 +2865,8 @@ static void * pthSocketThread(void *x) SOFT_ERROR((void*)PI_INIT_FAILED, "pthread_attr_setdetachstate failed (%m)"); - fdSock = socket(AF_INET , SOCK_STREAM , 0); - - if (fdSock == -1) - SOFT_ERROR((void*)PI_INIT_FAILED, "socket failed (%m)"); - - portStr = getenv(PI_ENVPORT); - - if (portStr) port = atoi(portStr); else port = gpioCfg.socketPort; - - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(port); - - if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0) - SOFT_ERROR((void*)PI_INIT_FAILED, "bind failed (%m)"); + /* fdSock opened in gpioInitialise so that we can treat + failure to bind as fatal. */ listen(fdSock, 100); @@ -3264,7 +3452,7 @@ static void initClearGlobals(void) wfStats.micros = 0; wfStats.highMicros = 0; - wfStats.maxMicros = -1; + wfStats.maxMicros = PI_WAVE_MAX_MICROS; wfStats.pulses = 0; wfStats.highPulses = 0; @@ -3406,7 +3594,8 @@ static void initReleaseResources(void) munmap(dmaVirt[i], PAGE_SIZE); } - munmap(dmaVirt, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *)); + munmap(dmaVirt, + PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *)); } dmaVirt = MAP_FAILED; @@ -3418,7 +3607,8 @@ static void initReleaseResources(void) munmap(dmaPhys[i], PAGE_SIZE); } - munmap(dmaPhys, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *)); + munmap(dmaPhys, + PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *)); } dmaPhys = MAP_FAILED; @@ -3474,6 +3664,9 @@ static void initReleaseResources(void) int gpioInitialise(void) { int i; + struct sockaddr_in server; + char * portStr; + unsigned port; clock_gettime(CLOCK_REALTIME, &libStarted); @@ -3542,6 +3735,22 @@ int gpioInitialise(void) if (!(gpioCfg.ifFlags & PI_DISABLE_SOCK_IF)) { + fdSock = socket(AF_INET , SOCK_STREAM , 0); + + if (fdSock == -1) + SOFT_ERROR(PI_INIT_FAILED, "socket failed (%m)"); + + portStr = getenv(PI_ENVPORT); + + if (portStr) port = atoi(portStr); else port = gpioCfg.socketPort; + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(port); + + if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0) + SOFT_ERROR(PI_INIT_FAILED, "bind to port %d failed (%m)", port); + if (pthread_create(&pthSocket, &pthAttr, pthSocketThread, &i)) SOFT_ERROR(PI_INIT_FAILED, "pthread_create socket failed (%m)"); @@ -4127,15 +4336,16 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses) int gpioWaveAddSerial(unsigned gpio, unsigned baud, + unsigned offset, unsigned numChar, - char * str) + char *str) { int i, b, p, lev, c, v; unsigned bitDelay[10]; - DBG(DBG_USER, "gpio=%d baud=%d numChar=%d str*=%08X", - gpio, baud, numChar, (uint32_t)str); + DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s", + gpio, baud, offset, numChar, str); CHECK_INITED; @@ -4149,6 +4359,9 @@ int gpioWaveAddSerial(unsigned gpio, if (numChar > PI_WAVE_MAX_CHARS) SOFT_ERROR(PI_TOO_MANY_CHARS, "too many chars (%d)", numChar); + if (offset > PI_WAVE_MAX_MICROS) + SOFT_ERROR(PI_BAD_SER_OFFSET, "offset too large (%d)", offset); + if (!numChar) return 0; waveBitDelay(baud, bitDelay); @@ -4157,7 +4370,9 @@ int gpioWaveAddSerial(unsigned gpio, wf[2][p].gpioOn = (1< bitDelay[0]) wf[2][p].usDelay = offset; + else wf[2][p].usDelay = bitDelay[0]; for (i=0; i PI_MAX_USER_GPIO) + SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio); + + if (level > PI_ON) + SOFT_ERROR(PI_BAD_LEVEL, "gpio %d, bad level (%d)", gpio, level); + + if (pulseLen > PI_MAX_PULSELEN) + SOFT_ERROR(PI_BAD_PULSELEN, + "gpio %d, bad pulseLen (%d)", gpio, pulseLen); + + if (level == PI_OFF) *(gpioReg + GPCLR0 + BANK) = BIT; + else *(gpioReg + GPSET0 + BANK) = BIT; + + myGpioDelay(pulseLen); + + if (level != PI_OFF) *(gpioReg + GPCLR0 + BANK) = BIT; + else *(gpioReg + GPSET0 + BANK) = BIT; + + return 0; +} + /* ----------------------------------------------------------------------- */ @@ -4769,7 +5013,7 @@ int gpioSetTimerFuncEx(unsigned id, unsigned ms, gpioTimerFuncEx_t f, /* ----------------------------------------------------------------------- */ -pthread_t *gpioStartThread(ThreadFunc_t func, void *arg) +pthread_t *gpioStartThread(gpioThreadFunc_t func, void *arg) { pthread_t *pth; pthread_attr_t pthAttr; @@ -4818,6 +5062,58 @@ void gpioStopThread(pthread_t *pth) } } +/* ----------------------------------------------------------------------- */ + +int gpioStoreScript(char *script) +{ + DBG(DBG_USER, "script=%s", script); + + CHECK_INITED; + + return PI_BAD_SCRIPT; +} + + + +/* ----------------------------------------------------------------------- */ + +int gpioRunScript(int script_id) +{ + DBG(DBG_USER, "script_id=%d", script_id); + + CHECK_INITED; + + return PI_BAD_SCRIPT_ID; +} + + + +/* ----------------------------------------------------------------------- */ + +int gpioStopScript(int script_id) +{ + DBG(DBG_USER, "script_id=%d", script_id); + + CHECK_INITED; + + return PI_BAD_SCRIPT_ID; +} + + + +/* ----------------------------------------------------------------------- */ + +int gpioDeleteScript(int script_id) +{ + DBG(DBG_USER, "script_id=%d", script_id); + + CHECK_INITED; + + return PI_BAD_SCRIPT_ID; +} + + + /* ----------------------------------------------------------------------- */ int gpioSetSignalFunc(unsigned signum, gpioSignalFunc_t f) diff --git a/pigpio.h b/pigpio.h index f4faaa0..cf91696 100644 --- a/pigpio.h +++ b/pigpio.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 10 +This version is for pigpio version 11 */ #ifndef PIGPIO_H @@ -86,7 +86,7 @@ This version is for pigpio version 10 #include #include -#define PIGPIO_VERSION 10 +#define PIGPIO_VERSION 11 /*-------------------------------------------------------------------------*/ @@ -148,6 +148,8 @@ gpioWaveGetCbs Length in cbs of the current waveform. gpioWaveGetHighCbs Length of longest waveform so far. gpioWaveGetMaxCbs Absolute maximum allowed cbs. +gpioTrigger Send a trigger pulse to a gpio. + gpioSetWatchdog Set a watchdog on a gpio. gpioSetGetSamplesFunc Requests a gpio samples callback. @@ -159,6 +161,11 @@ gpioSetTimerFuncEx Request a regular timed callback, extended. gpioStartThread Start a new thread. gpioStopThread Stop a previously started thread. +gpioStoreScript Store a script. +gpioRunScript Run a stored script. +gpioStopScript Stop a running script. +gpioDeleteScript Delete a stored script. + gpioSetSignalFunc Request a signal callback. gpioSetSignalFuncEx Request a signal callback, extended. @@ -217,6 +224,13 @@ typedef struct uint32_t res; } cmdCmd_t; +typedef struct +{ + size_t n; + void *ptr; + int data; +} gpioExtent_t; + typedef struct { uint32_t tick; @@ -271,8 +285,7 @@ typedef void (*gpioGetSamplesFuncEx_t) (const gpioSample_t * samples, int numSamples, void * userdata); -typedef void *(ThreadFunc_t) (void *); - +typedef void *(gpioThreadFunc_t) (void *); /* @@ -881,7 +894,6 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses); If the added waveform is intended to start after or within the existing waveform then the first pulse should consist of a delay. - */ @@ -889,15 +901,17 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses); /*-------------------------------------------------------------------------*/ int gpioWaveAddSerial(unsigned user_gpio, unsigned baud, + unsigned offset, unsigned numChar, char * str); /*-------------------------------------------------------------------------*/ /* This function adds a waveform representing serial data to the - existing waveform (if any). + existing waveform (if any). The serial data starts offset microseconds + from the start of the waveform. Returns the new total number of pulses in the current waveform if OK, - otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS, or - PI_TOO_MANY_PULSES. + otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS, + PI_BAD_SER_OFFSET, or PI_TOO_MANY_PULSES. NOTES: @@ -915,6 +929,8 @@ int gpioWaveAddSerial(unsigned user_gpio, #define PI_WAVE_MIN_BAUD 100 #define PI_WAVE_MAX_BAUD 250000 +#define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */ + /*-------------------------------------------------------------------------*/ @@ -923,7 +939,8 @@ int gpioWaveTxStart(unsigned mode); /* This function transmits the current waveform. The mode determines whether the waveform is sent once or cycles endlessly. - Returns 0 if OK, otherwise PI_BAD_WAVE_MODE. + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_MODE. */ #define PI_WAVE_MODE_ONE_SHOT 0 @@ -1112,6 +1129,19 @@ int gpioWaveGetMaxCbs(void); +/*-------------------------------------------------------------------------*/ +int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level); +/*-------------------------------------------------------------------------*/ +/* This function sends a trigger pulse to a gpio. The gpio is set to + level for pulseLen microseconds and then reset to not level. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL, + or PI_BAD_PULSELEN. +*/ + +#define PI_MAX_PULSELEN 100 + + /*-------------------------------------------------------------------------*/ int gpioSetWatchdog(unsigned user_gpio, unsigned timeout); @@ -1267,7 +1297,7 @@ int gpioSetTimerFuncEx(unsigned timer, /* ----------------------------------------------------------------------- */ -pthread_t *gpioStartThread(ThreadFunc_t func, void *arg); +pthread_t *gpioStartThread(gpioThreadFunc_t func, void *arg); /*-------------------------------------------------------------------------*/ /* Starts a new thread of execution with func as the main routine. @@ -1327,6 +1357,46 @@ void gpioStopThread(pthread_t *pth); */ +/* ----------------------------------------------------------------------- */ +int gpioStoreScript(char *script); +/* ----------------------------------------------------------------------- */ +/* This function stores a null terminated script for later execution. + + The function returns a script id if the script is valid, + otherwise PI_BAD_SCRIPT. +*/ + + + +/* ----------------------------------------------------------------------- */ +int gpioRunScript(int script_id); +/* ----------------------------------------------------------------------- */ +/* This function runs a stored script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + + + +/* ----------------------------------------------------------------------- */ +int gpioStopScript(int script_id); +/* ----------------------------------------------------------------------- */ +/* This function stops a running script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + + + +/* ----------------------------------------------------------------------- */ +int gpioDeleteScript(int script_id); +/* ----------------------------------------------------------------------- */ +/* This function deletes a stored script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + + /*-------------------------------------------------------------------------*/ int gpioSetSignalFunc(unsigned signum, @@ -1816,6 +1886,21 @@ void gpioWaveDump(void); #define PI_CMD_PRRG 24 #define PI_CMD_HELP 25 #define PI_CMD_PIGPV 26 +#define PI_CMD_WVCLR 27 +#define PI_CMD_WVAG 28 +#define PI_CMD_WVAS 29 +#define PI_CMD_WVGO 30 +#define PI_CMD_WVGOR 31 +#define PI_CMD_WVBSY 32 +#define PI_CMD_WVHLT 33 +#define PI_CMD_WVSM 34 +#define PI_CMD_WVSP 35 +#define PI_CMD_WVSC 36 +#define PI_CMD_TRIG 37 +#define PI_CMD_PROC 38 +#define PI_CMD_PROCD 39 +#define PI_CMD_PROCR 40 +#define PI_CMD_PROCS 41 /* The following command only works on the socket interface. @@ -1841,7 +1926,7 @@ after this command is issued. #define PI_BAD_LEVEL -5 /* level not 0-1 */ #define PI_BAD_PUD -6 /* pud not 0-2 */ #define PI_BAD_PULSEWIDTH -7 /* pulsewidth not 0 or 500-2500 */ -#define PI_BAD_DUTYCYCLE -8 /* dutycycle not 0-255 */ +#define PI_BAD_DUTYCYCLE -8 /* dutycycle outside set range */ #define PI_BAD_TIMER -9 /* timer not 0-9 */ #define PI_BAD_MS -10 /* ms not 10-60000 */ #define PI_BAD_TIMETYPE -11 /* timetype not 0-1 */ @@ -1878,6 +1963,13 @@ after this command is issued. #define PI_BAD_SERIAL_BUF -40 /* bad (null) serial buf parameter */ #define PI_NOT_PERMITTED -41 /* gpio operation not permitted */ #define PI_SOME_PERMITTED -42 /* one or more gpios not permitted */ +#define PI_BAD_WVSC_COMMND -43 /* bad WVSC subcommand */ +#define PI_BAD_WVSM_COMMND -44 /* bad WVSM subcommand */ +#define PI_BAD_WVSP_COMMND -45 /* bad WVSP subcommand */ +#define PI_BAD_PULSELEN -46 /* trigger pulse length > 100 */ +#define PI_BAD_SCRIPT -47 /* invalid script */ +#define PI_BAD_SCRIPT_ID -48 /* unknown script id */ +#define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */ /*-------------------------------------------------------------------------*/ diff --git a/pigpio.py b/pigpio.py index c9e4be5..0b40af8 100644 --- a/pigpio.py +++ b/pigpio.py @@ -76,7 +76,7 @@ import threading import os import atexit -VERSION = "1.1" +VERSION = "1.2" # gpio levels @@ -140,8 +140,28 @@ _PI_CMD_NC= 21 _PI_CMD_PRG= 22 _PI_CMD_PFG= 23 _PI_CMD_PRRG= 24 +_PI_CMD_HELP= 25 +_PI_CMD_PIGPV=26 +_PI_CMD_WVCLR=27 +_PI_CMD_WVAG= 28 +_PI_CMD_WVAS= 29 +_PI_CMD_WVGO= 30 +_PI_CMD_WVGOR=31 +_PI_CMD_WVBSY=32 +_PI_CMD_WVHLT=33 +_PI_CMD_WVSM= 34 +_PI_CMD_WVSP= 35 +_PI_CMD_WVSC= 36 +_PI_CMD_TRIG= 37 +_PI_CMD_PROC= 38 +_PI_CMD_PROCD=39 +_PI_CMD_PROCR=40 +_PI_CMD_PROCS=41 + + _PI_CMD_NOIB= 99 + # pigpio error numbers _PI_INIT_FAILED =-1 @@ -179,14 +199,21 @@ _PI_NOT_INITIALISED =-31 _PI_INITIALISED =-32 _PI_BAD_WAVE_MODE =-33 _PI_BAD_CFG_INTERNAL=-34 -_PI_BAD_WAVE_BAUD =-35 -_PI_TOO_MANY_PULSES =-36 -_PI_TOO_MANY_CHARS =-37 +PI_BAD_WAVE_BAUD =-35 +PI_TOO_MANY_PULSES =-36 +PI_TOO_MANY_CHARS =-37 _PI_NOT_SERIAL_GPIO =-38 _PI_BAD_SERIAL_STRUC=-39 _PI_BAD_SERIAL_BUF =-40 PI_NOT_PERMITTED =-41 PI_SOME_PERMITTED =-42 +PI_BAD_WVSC_COMMND =-43 +PI_BAD_WVSM_COMMND =-44 +PI_BAD_WVSP_COMMND =-45 +PI_BAD_PULSELEN =-46 +PI_BAD_SCRIPT =-47 +PI_BAD_SCRIPT_ID =-48 +PI_BAD_SER_OFFSET =-49 # pigpio error text @@ -225,12 +252,19 @@ _errors=[ [_PI_INITIALISED , "function called after gpioInitialise"], [_PI_BAD_WAVE_MODE , "waveform mode not 0-1"], [_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"], - [_PI_BAD_WAVE_BAUD , "baud rate not 100-250000"], - [_PI_TOO_MANY_PULSES , "waveform has too many pulses"], - [_PI_TOO_MANY_CHARS , "waveform has too many chars"], + [PI_BAD_WAVE_BAUD , "baud rate not 100-250000"], + [PI_TOO_MANY_PULSES , "waveform has too many pulses"], + [PI_TOO_MANY_CHARS , "waveform has too many chars"], [_PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"], [PI_NOT_PERMITTED , "no permission to update gpio"], - [PI_SOME_PERMITTED , "no permission to update one or more gpios"] + [PI_SOME_PERMITTED , "no permission to update one or more gpios"], + [PI_BAD_WVSC_COMMND , "bad WVSC subcommand"], + [PI_BAD_WVSM_COMMND , "bad WVSM subcommand"], + [PI_BAD_WVSP_COMMND , "bad WVSP subcommand"], + [PI_BAD_PULSELEN , "trigger pulse length > 100"], + [PI_BAD_SCRIPT , "invalid script"], + [PI_BAD_SCRIPT_ID , "unknown script id"], + [PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"], ] _control = None @@ -262,7 +296,7 @@ def error(pigpio_error): for e in _errors: if e[0] == pigpio_error: return e[1] - return "unknown error" + return "unknown error ({})".format(pigpio_error) def tickDiff(tStart, tEnd): """Calculate the time difference between two ticks. @@ -304,7 +338,8 @@ def _u2i(number): return v def _pigpio_command(sock, cmd, p1, p2): - """Executes a pigpio socket command. + """ + Executes a pigpio socket command. sock: command socket. cmd: the command to be executed. @@ -318,6 +353,27 @@ def _pigpio_command(sock, cmd, p1, p2): else: raise _pigpioError("*** Module not started, call pigpio.start() ***") +def _pigpio_command_ext(sock, cmd, p1, p2, extents): + """ + Executes an extended pigpio socket command. + + sock: command socket. + cmd: the command to be executed. + p1: command paramter 1 (if applicable). + p2: command paramter 2 (if applicable). + extents: additional data blocks + """ + if sock is not None: + sock.send(struct.pack('IIII', cmd, p1, p2, 0)) + + for ext in extents: + sock.sendall(ext) + + x, y, z, res = struct.unpack('IIII', sock.recv(16)) + return res + else: + raise _pigpioError("*** Module not started, call pigpio.start() ***") + class _callback: """An ADT class to hold callback information.""" @@ -462,8 +518,7 @@ def set_mode(gpio, mode): pigpio.set_mode(10, pigpio.ALT2) # gpio 10 as ALT2 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_MODES, gpio, mode)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_MODES, gpio, mode)) def get_mode(gpio): """Get the gpio mode. @@ -482,8 +537,7 @@ def get_mode(gpio): 6 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_MODEG, gpio, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_MODEG, gpio, 0)) def set_pull_up_down(gpio, pud): """Set or clear the gpio pull-up/down resistor. @@ -516,8 +570,7 @@ def set_pull_up_down(gpio, pud): 1 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PUD, gpio, pud)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PUD, gpio, pud)) def read(gpio): """Read the gpio level. @@ -545,8 +598,7 @@ def read(gpio): 1 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_READ, gpio, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_READ, gpio, 0)) def write(gpio, level): """Write the gpio level. @@ -578,8 +630,7 @@ def write(gpio, level): 1 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_WRITE, gpio, level)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_WRITE, gpio, level)) def set_PWM_dutycycle(user_gpio, dutycycle): """Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio. @@ -609,8 +660,7 @@ def set_PWM_dutycycle(user_gpio, dutycycle): set_PWM_dutycycle(4, 255) # PWM full on ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PWM, user_gpio, dutycycle)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PWM, user_gpio, dutycycle)) def set_PWM_range(user_gpio, range_): """Set the range of PWM values to be used on the gpio. @@ -645,8 +695,7 @@ def set_PWM_range(user_gpio, range_): pigpio.set_PWM_range(9, 3000) # now 750 1/4, 1500 1/2, 2250 3/4 on ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PRS, user_gpio, range_)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PRS, user_gpio, range_)) def get_PWM_range(user_gpio): """Get the range of PWM values being used on the gpio. @@ -674,8 +723,7 @@ def get_PWM_range(user_gpio): 3000 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PRG, user_gpio, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PRG, user_gpio, 0)) def get_PWM_real_range(user_gpio): """Get the real underlying range of PWM values being used on the gpio. @@ -701,8 +749,7 @@ def get_PWM_real_range(user_gpio): 25 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PRRG, user_gpio, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PRRG, user_gpio, 0)) def set_PWM_frequency(user_gpio, frequency): """Set the frequency (in Hz) of the PWM to be used on the gpio. @@ -759,8 +806,7 @@ def set_PWM_frequency(user_gpio, frequency): 8000 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PFS, user_gpio, frequency)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PFS, user_gpio, frequency)) def get_PWM_frequency(user_gpio): """Get the frequency of PWM being used on the gpio. @@ -788,8 +834,7 @@ def get_PWM_frequency(user_gpio): 8000 ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_PFG, user_gpio, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_PFG, user_gpio, 0)) def set_servo_pulsewidth(user_gpio, pulsewidth): """Start (500-2500) or stop (0) servo pulses on the gpio. @@ -845,8 +890,8 @@ def set_servo_pulsewidth(user_gpio, pulsewidth): for m in moves: pigpio.set_servo_pulsewidth(24, m[0]); time.sleep(m[1]) - message = str(m[1]) + " seconds @ " + str(m[0]) + " us" - print(message) + s = str(m[1]) + " seconds @ " + str(m[0]) + " us" + print(s) pigpio.stop() @@ -875,8 +920,8 @@ def set_servo_pulsewidth(user_gpio, pulsewidth): for m in moves: pigpio.set_PWM_dutycycle(25, m[0]); time.sleep(m[1]) - message = str(m[1]) + " seconds @ " + str(m[0]) + " us" - print(message) + s = str(m[1]) + " seconds @ " + str(m[0]) + " us" + print(s) pigpio.stop() @@ -888,8 +933,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth): 5 seconds @ 2000 us 0 seconds @ 1000 us """ - r=_u2i(_pigpio_command(_control, _PI_CMD_SERVO, user_gpio, pulsewidth)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_SERVO, user_gpio, pulsewidth)) def notify_open(): """Get a free notification handle. @@ -917,8 +961,7 @@ def notify_open(): pigpio.notify_begin(h, 1234) ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0)) def notify_begin(handle, bits): """Start notifications on a previously opened handle. @@ -951,8 +994,7 @@ def notify_begin(handle, bits): I (32 bit) level """ - r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits)) def notify_pause(handle): """Pause notifications on a previously opened handle. @@ -976,8 +1018,7 @@ def notify_pause(handle): ... ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0)) def notify_close(handle): """Stop notifications on a previously opened handle and @@ -997,8 +1038,7 @@ def notify_close(handle): ... ... """ - r=_u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0)) def set_watchdog(user_gpio, timeout): """Sets a watchdog for a gpio. @@ -1030,8 +1070,8 @@ def set_watchdog(user_gpio, timeout): import time def cbf(g, L, t): - message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t) - print(message) + s = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t) + print(s) pigpio.start() @@ -1068,8 +1108,7 @@ def set_watchdog(user_gpio, timeout): gpio=22 level=2 at 3551411622 watchdog cancelled, 5 second delay """ - r=_u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout)) def read_bank_1(): """Read the levels of the bank 1 gpios (gpios 0-31). @@ -1148,8 +1187,7 @@ def clear_bank_1(levels): 0b1111110010000 """ - r=_u2i(_pigpio_command(_control, _PI_CMD_BC1, levels, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_BC1, levels, 0)) def clear_bank_2(levels): """Clears gpios 32-53 if the corresponding bit (0-21) in levels is set. @@ -1164,8 +1202,7 @@ def clear_bank_2(levels): See clear_bank_1() for an example. """ - r=_u2i(_pigpio_command(_control, _PI_CMD_BC2, levels, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_BC2, levels, 0)) def set_bank_1(levels): """Sets gpios 0-31 if the corresponding bit in levels is set. @@ -1215,8 +1252,7 @@ def set_bank_1(levels): 0b1111111011111 0b1111110010000 """ - r=_u2i(_pigpio_command(_control, _PI_CMD_BS1, levels, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_BS1, levels, 0)) def set_bank_2(levels): """Sets gpios 32-53 if the corresponding bit (0-21) in levels is set. @@ -1231,8 +1267,7 @@ def set_bank_2(levels): See set_bank_1() for an example. """ - r=_u2i(_pigpio_command(_control, _PI_CMD_BS2, levels, 0)) - return r + return _u2i(_pigpio_command(_control, _PI_CMD_BS2, levels, 0)) def get_current_tick(): """Gets the current system tick. @@ -1257,9 +1292,9 @@ def get_current_tick(): t2 = pigpio.get_current_tick() - message = "5 seconds is " + str(pigpio.tickDiff(t1, t2)) + " ticks" + s = "5 seconds is " + str(pigpio.tickDiff(t1, t2)) + " ticks" - print(message) + print(s) pigpio.stop() @@ -1308,6 +1343,365 @@ def get_hardware_revision(): """ return _pigpio_command(_control, _PI_CMD_HWVER, 0, 0) +def get_pigpio_version(): + """ + Returns the pigpio software version. + """ + return _pigpio_command(_control, _PI_CMD_PIGPV, 0, 0) + +class pulse: + """ + An ADT class to hold pulse information. + """ + + def __init__(self, gpio_on, gpio_off, delay): + """ + Initialises a pulse ADT. + + gpio_on: the gpios to switch on at the start of the pulse. + gpio_off: the gpios to switch off at the start of the pulse. + delay: the delay in microseconds before the next pulse. + """ + self.gpio_on = gpio_on + self.gpio_off = gpio_off + self.delay = delay + +def wave_clear(): + """ + Initialises a new waveform. + + Returns 0 if OK. + + A waveform comprises one of more pulses. + + A pulse specifies + + 1) the gpios to be switched on at the start of the pulse. + 2) the gpios to be switched off at the start of the pulse. + 3) the delay in microseconds before the next pulse. + + Any or all the fields can be zero. It doesn't make any sense + to set all the fields to zero (the pulse will be ignored). + + When a waveform is started each pulse is executed in order with + the specified delay between the pulse and the next. + """ + return _u2i(_pigpio_command(_control, _PI_CMD_WVCLR, 0, 0)) + +def wave_add_generic(pulses): + """ + Adds a list of pulses to the current waveform. + + Returns the new total number of pulses in the current waveform + if OK, otherwise PI_TOO_MANY_PULSES. + + pulses: list of pulses to add to the waveform. + + The pulses are interleaved in time order within the existing + waveform (if any). + + Merging allows the waveform to be built in parts, that is the + settings for gpio#1 can be added, and then gpio#2 etc. + + If the added waveform is intended to start after or within + the existing waveform then the first pulse should consist + solely of a delay. + + Example + + #!/usr/bin/env python + + import time + import pigpio + + class stepper: + + def __init__(self, g1, g2, g3, g4): + self.g1 = g1 + self.g2 = g2 + self.g3 = g3 + self.g4 = g4 + self.all = (1< */ /* -This version is for pigpio version 7+ +This version is for pigpio version 11+ */ #include @@ -34,6 +34,7 @@ This version is for pigpio version 7+ #include #include #include +#include #include #include #include @@ -43,7 +44,6 @@ This version is for pigpio version 7+ #include #include "pigpio.h" -#include "command.h" /* This program starts the pigpio library as a daemon. @@ -61,6 +61,22 @@ static uint64_t updateMask = -1; static FILE * errFifo; +void fatal(char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + fprintf(stderr, "%s\n", buf); + + fflush(stderr); + + exit(EXIT_FAILURE); +} + void usage() { fprintf(stderr, "\n" \ @@ -98,21 +114,21 @@ static void initOpts(int argc, char *argv[]) i = atoi(optarg); if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX)) bufferSizeMilliseconds = i; - else cmdFatal("invalid -b option (%d)", i); + else fatal("invalid -b option (%d)", i); break; case 'd': i = atoi(optarg); if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL)) DMAprimaryChannel = i; - else cmdFatal("invalid -d option (%d)", i); + else fatal("invalid -d option (%d)", i); break; case 'e': i = atoi(optarg); if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL)) DMAsecondaryChannel = i; - else cmdFatal("invalid -e option (%d)", i); + else fatal("invalid -e option (%d)", i); break; case 'f': @@ -127,7 +143,7 @@ static void initOpts(int argc, char *argv[]) i = atoi(optarg); if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT)) socketPort = i; - else cmdFatal("invalid -p option (%d)", i); + else fatal("invalid -p option (%d)", i); break; case 's': @@ -145,7 +161,7 @@ static void initOpts(int argc, char *argv[]) break; default: - cmdFatal("invalid -s option (%d)", i); + fatal("invalid -s option (%d)", i); break; } break; @@ -154,21 +170,21 @@ static void initOpts(int argc, char *argv[]) i = atoi(optarg); if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM)) clockPeripheral = i; - else cmdFatal("invalid -t option (%d)", i); + else fatal("invalid -t option (%d)", i); break; case 'u': i = atoi(optarg); if ((i >= PI_CLOCK_OSC) && (i <= PI_CLOCK_PLLD)) clockSource = i; - else cmdFatal("invalid -u option (%d)", i); + else fatal("invalid -u option (%d)", i); break; case 'x': mask = strtoll(optarg, &endptr, 0); printf("mask=%llx\n", mask); if (!*endptr) updateMask = mask; - else cmdFatal("invalid -x option (%s)", optarg); + else fatal("invalid -x option (%s)", optarg); break; default: /* '?' */ @@ -221,11 +237,11 @@ int main(int argc, char **argv) /* Create a new SID for the child process */ - if (setsid() < 0) cmdFatal("setsid failed (%m)"); + if (setsid() < 0) fatal("setsid failed (%m)"); /* Change the current working directory */ - if ((chdir("/")) < 0) cmdFatal("chdir failed (%m)"); + if ((chdir("/")) < 0) fatal("chdir failed (%m)"); /* check command line parameters */ @@ -252,7 +268,7 @@ int main(int argc, char **argv) /* start library */ - if (gpioInitialise()< 0) cmdFatal("Can't initialise pigpio library"); + if (gpioInitialise()< 0) fatal("Can't initialise pigpio library"); /* create pipe for error reporting */ @@ -261,7 +277,7 @@ int main(int argc, char **argv) mkfifo(PI_ERRFIFO, 0664); if (chmod(PI_ERRFIFO, 0664) < 0) - cmdFatal("chmod %s failed (%m)", PI_ERRFIFO); + fatal("chmod %s failed (%m)", PI_ERRFIFO); errFifo = freopen(PI_ERRFIFO, "w+", stderr); diff --git a/pigpiod_if.c b/pigpiod_if.c index 6f095cb..e6884fd 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 1 */ +/* PIGPIOD_IF_VERSION 2 */ #include #include @@ -97,10 +97,34 @@ static int pigpio_command(int fd, int command, int p1, int p2) cmd.p2 = p2; cmd.res = 0; - if (send(fd, &cmd, sizeof(cmdCmd_t), 0) != sizeof(cmdCmd_t)) - return pigif_bad_send; + if (send(fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) return pigif_bad_send; - if (recv(fd, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) != sizeof(cmdCmd_t)) + if (recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd)) + return pigif_bad_recv; + + return cmd.res; +} + +static int pigpio_command_ext + (int fd, int command, int p1, int p2, int extents, gpioExtent_t *ext) +{ + int i; + cmdCmd_t cmd; + + cmd.cmd = command; + cmd.p1 = p1; + cmd.p2 = p2; + cmd.res = 0; + + if (send(fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) return pigif_bad_send; + + for (i=0; i #include "pigpio.h" -#define PIGPIOD_IF_VERSION 1 +#define PIGPIOD_IF_VERSION 2 typedef enum { @@ -70,7 +70,7 @@ const char *pigpio_error(int error); unsigned pigpiod_if_version(void); /* Return the pigpiod_if version. */ -pthread_t *start_thread(ThreadFunc_t func, void *arg); +pthread_t *start_thread(gpioThreadFunc_t func, void *arg); /* Starts a new thread of execution with func as the main routine. Returns a pointer to pthread_t if OK, otherwise NULL. @@ -198,7 +198,6 @@ int set_PWM_range(int user_gpio, int range_); The real value set by set_PWM_range is (dutycycle * real range) / range. - */ int get_PWM_range(int user_gpio); @@ -507,20 +506,213 @@ uint32_t get_hardware_revision(void); hexadecimal number the function returns 0. */ +int wave_clear(void); +/* This function initialises a new waveform. + + Returns 0 if OK. + + A waveform comprises one of more pulses. Each pulse consists of a + gpioPulse_t structure. + + typedef struct + { + uint32_t gpioOn; + uint32_t gpioOff; + uint32_t usDelay; + } gpioPulse_t; + + The fields specify + + 1) the gpios to be switched on at the start of the pulse. + 2) the gpios to be switched off at the start of the pulse. + 3) the delay in microseconds before the next pulse. + + Any or all the fields can be zero. It doesn't make any sense to + set all the fields to zero (the pulse will be ignored). + + When a waveform is started each pulse is executed in order with the + specified delay between the pulse and the next. +*/ + +int wave_tx_busy(void); +/* This function checks to see if a waveform is currently being + transmitted. + + Returns 1 if a waveform is currently being transmitted, otherwise 0. +*/ + +int wave_tx_stop(void); +/* This function stops the transmission of the current waveform. + + Returns 0 if OK. + + This function is intended to stop a waveform started with the repeat mode. +*/ + +int wave_tx_start(void); +/* This function transmits the current waveform. The waveform is + sent once. + + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_MODE. +*/ + +int wave_tx_repeat(void); +/* This function transmits the current waveform. The waveform repeats + endlessly until wave_tx_stop is called. + + Returns the number of DMA control blocks in the waveform if OK, + otherwise PI_BAD_WAVE_MODE. +*/ + +int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses); +/* This function adds a number of pulses to the current waveform. + + Returns the new total number of pulses in the current waveform if OK, + otherwise PI_TOO_MANY_PULSES. + + The pulses are interleaved in time order within the existing waveform + (if any). + + Merging allows the waveform to be built in parts, that is the settings + for gpio#1 can be added, and then gpio#2 etc. + + If the added waveform is intended to start after or within the existing + waveform then the first pulse should consist solely of a delay. +*/ + +int wave_add_serial + (unsigned gpio, unsigned baud, unsigned offset, unsigned numChar, char *str); +/* This function adds a waveform representing serial data to the + existing waveform (if any). The serial data starts offset microseconds + from the start of the waveform. + + Returns the new total number of pulses in the current waveform if OK, + otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS, or + PI_TOO_MANY_PULSES. + + NOTES: + + The serial data is formatted as one start bit, eight data bits, and one + stop bit. + + It is legal to add serial data streams with different baud rates to + the same waveform. +*/ + +int wave_get_micros(void); +/* This function returns the length in microseconds of the current + waveform. +*/ + +int wave_get_high_micros(void); +/* This function returns the length in microseconds of the longest waveform + created since the pigpio daemon was started.. +*/ + +int wave_get_max_micros(void); +/* This function returns the maximum possible size of a waveform in + microseconds. +*/ + +int wave_get_pulses(void); +/* This function returns the length in pulses of the current waveform. +*/ + +int wave_get_high_pulses(void); +/* This function returns the length in pulses of the longest waveform + created since the pigpio daemon was started.. +*/ + +int wave_get_max_pulses(void); +/* This function returns the maximum possible size of a waveform in pulses. +*/ + +int wave_get_cbs(void); +/* This function returns the length in DMA control blocks of the current + waveform. +*/ + +int wave_get_high_cbs(void); +/* This function returns the length in DMA control blocks of the longest + waveform created since the pigpio daemon was started.. +*/ + +int wave_get_max_cbs(void); +/* This function returns the maximum possible size of a waveform in DMA + control blocks. +*/ + +int gpio_trigger(unsigned gpio, unsigned pulseLen, unsigned level); +/* This function sends a trigger pulse to a gpio. The gpio is set to + level for pulseLen microseconds and then reset to not level. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL, + PI_BAD_PULSELEN, or PI_NOT_PERMITTED. +*/ + +int store_script(char *script); +/* This function stores a script for later execution. + + The function returns a script id if the script is valid, + otherwise PI_BAD_SCRIPT. +*/ + +int run_script(int script_id); +/* This function runs a stored script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + +int stop_script(int script_id); +/* This function stops a running script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + +int delete_script(int script_id); +/* This function deletes a stored script. + + The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID. +*/ + int callback(int gpio, int edge, CBFunc_t f); /* + This function initialises a new callback. + + The function returns a callback id if OK, otherwise pigif_bad_malloc, + pigif_duplicate_callback, or pigif_bad_callback. + + The callback is called with the gpio, edge, and tick, whenever the + gpio has the identified edge. */ int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user); /* + This function initialises a new callback. + + The function returns a callback id if OK, otherwise pigif_bad_malloc, + pigif_duplicate_callback, or pigif_bad_callback. + + The callback is called with the gpio, edge, tick, and user, whenever + the gpio has the identified edge. */ int callback_cancel(int id); /* + This function cancels a callback identified by its id. + + The function returns 0 if OK, otherwise pigif_callback_not_found. */ int wait_for_edge(int gpio, int edge, double timeout); /* + This function waits for edge on the gpio for up to timeout + seconds. + + The function returns 1 if the edge occurred, otherwise 0. + + The function returns when the edge occurs or after the timeout. */ #endif diff --git a/pigs.c b/pigs.c index 7115304..4cd84c2 100644 --- a/pigs.c +++ b/pigs.c @@ -26,11 +26,12 @@ For more information, please refer to */ /* -This version is for pigpio version 7+ +This version is for pigpio version 11+ */ #include #include +#include #include #include #include @@ -42,10 +43,26 @@ This version is for pigpio version 7+ #include "command.h" /* -This program provides a socket interface -to the commands available from pigpio. +This program provides a socket interface to some of +the commands available from pigpio. */ +void fatal(char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + fprintf(stderr, "%s\n", buf); + + fflush(stderr); + + exit(EXIT_FAILURE); +} + static int openSocket(void) { int sock, err; @@ -88,9 +105,10 @@ static int openSocket(void) int main(int argc , char *argv[]) { - int sock, r, idx; + int sock, r, idx, i; cmdCmd_t cmd; - char buf[128]; + gpioExtent_t ext[3]; + char buf[1024]; sock = openSocket(); @@ -113,31 +131,48 @@ int main(int argc , char *argv[]) sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]); break; + case 5: + sprintf(buf, "%10s %10s %10s %10s", + argv[1], argv[2], argv[3], argv[4]); + break; + + case 6: + sprintf(buf, "%10s %10s %10s %10s %10s", + argv[1], argv[2], argv[3], argv[4], argv[5]); + break; + default: - cmdFatal("what?"); + fatal("what? 'pigs h' for help"); } - if ((idx=cmdParse(buf, &cmd)) >= 0) + if ((idx=cmdParse(buf, &cmd, argc, argv, ext)) >= 0) { if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t)) { + /* send extensions */ + + for (i=0; i