diff --git a/MakeRemote b/MakeRemote index c27fc64..0e3f83a 100644 --- a/MakeRemote +++ b/MakeRemote @@ -5,9 +5,9 @@ SIZE = size CFLAGS = -O3 -Wall -ALL = libpigpiod_if.a pigs pigpio.py setup.py +ALL = libpigpiod_if.a pigs -all: $(ALL) +all: $(ALL) pigpio.py setup.py pigs: command.o pigs.o $(CC) -o pigs pigs.c command.c diff --git a/command.c b/command.c index a128a9d..757b082 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 11+ +This version is for pigpio version 12+ */ #include @@ -46,6 +46,7 @@ This version is for pigpio version 11+ 3 %08X %08X 4 %u %u 5 HELP HELP +6 %s <0 ERR */ /* vfyt @@ -58,6 +59,7 @@ This version is for pigpio version 11+ 8 MODES %d %c 9 PUD %d %c 10 PROG %s +11 WVAS %d %d %d %s */ cmdInfo_t cmdInfo[]= @@ -98,6 +100,9 @@ cmdInfo_t cmdInfo[]= {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}, @@ -116,68 +121,72 @@ cmdInfo_t cmdInfo[]= }; char * cmdUsage = "\ -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\ -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\ -NC h close notification\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\ -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\ -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\ -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\ +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\ +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\ +o = offset (0-).\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\ "; typedef struct @@ -237,6 +246,8 @@ static errInfo_t errInfo[]= {PI_BAD_SCRIPT , "invalid script"}, {PI_BAD_SCRIPT_ID , "unknown script id"}, {PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"}, + {PI_GPIO_IN_USE , "gpio already in use"}, + {PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"}, }; static char * fmtMdeStr="RW540123"; @@ -256,7 +267,7 @@ static int cmdMatch(char * str) int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext) { char str[8]; - int f, valid, idx, val; + int f, valid, idx, val, p; char *ptr; char c, t; @@ -276,21 +287,21 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext switch (cmdInfo[idx].vt) { - case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO WVGOR - WVHLT + 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 NC NP PFG PRG PROCD PROCR PROCS PRRG READ - WVSC WVSM WVSP + case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG + SLRC READ WVSC WVSM WVSP */ f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t); if (f == 2) valid = 1; break; - case 3: /* PFS PRS PWM SERVO WDOG WRITE + 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; @@ -308,7 +319,7 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext str, &cmd->p1, &cmd->p2, &ext[0].data, &t); if (f == 4) { - ext[0].n = sizeof(unsigned); + ext[0].size = sizeof(unsigned); ext[0].ptr = &ext[0].data; valid = 1; } @@ -319,7 +330,7 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext 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; @@ -359,38 +370,56 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext case 10: /* PROC */ - if (argc == 3) + if ((argc == 0) || (argc == 3)) { - cmd->p1 = strlen(argv[2]); - ext[0].n = cmd->p1; - ext[0].ptr = argv[2]; + 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; } break; case 11: /* WVAS */ - if (argc == 6) + if ((argc == 0) || (argc == 6)) { - f = sscanf(buf, " %7s %d %d %d ", - str, &cmd->p1, &ext[0].data, &ext[1].data); - if (f == 4) + f = sscanf(buf, " %*s %d %d %d %n", + &cmd->p1, &ext[0].data, &ext[1].data, &p); + if (f == 3) { - ext[0].n = sizeof(unsigned); + ext[0].size = sizeof(unsigned); ext[0].ptr = &ext[0].data; - ext[1].n = sizeof(unsigned); + ext[1].size = sizeof(unsigned); ext[1].ptr = &ext[1].data; - cmd->p2 = strlen(argv[5]); - ext[2].n = cmd->p2; - ext[2].ptr = argv[5]; + + if (argc) /* pigs */ + { + cmd->p2 = strlen(argv[5]); + ext[2].ptr = argv[5]; + } + else /* pipe i/f */ + { + cmd->p2 = strlen(buf+p); + ext[2].ptr = buf+p; + } + + ext[2].size = cmd->p2; valid = 1; } } break; } - if (valid) return idx; - else return -1; + if (valid) return idx; else return -1; } char * cmdErrStr(int error) diff --git a/pigpio.c b/pigpio.c index 2c37817..cde0e58 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 11 */ +/* pigpio version 12 */ #include #include @@ -557,6 +557,9 @@ 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 + /* --------------------------------------------------------------- */ typedef void (*callbk_t) (); @@ -701,16 +704,21 @@ typedef struct typedef struct { - gpioRx_t * rxp; - uint32_t baud; - uint32_t fullBit; - uint32_t halfBit; - uint32_t startBitTick; - uint32_t nextBitDiff; - int bit; - int byte; - int level; - int mode; + int gpio; + char * buf; + uint32_t bufSize; + int readPos; + int writePos; + uint32_t baud; + uint32_t fullBit; + uint32_t halfBit; + int timeout; + uint32_t startBitTick; + uint32_t nextBitDiff; + int bit; + int byte; + int level; + int mode; } wfRx_t; @@ -757,7 +765,7 @@ static wfStats_t wfStats= 0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE) }; -static wfRx_t wfRx[PI_MAX_USER_GPIO+1]; +static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1]; static volatile uint32_t alertBits = 0; static volatile uint32_t monitorBits = 0; @@ -977,7 +985,8 @@ static uint32_t myGetTick(int pos) /* ----------------------------------------------------------------------- */ -static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext) +static void myDoCommand + (cmdCmd_t *cmd, gpioExtent_t *iExt, gpioExtent_t *oExt) { int p1, p2, res, i; uint32_t mask, tmp; @@ -1090,7 +1099,7 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext) case PI_CMD_PRG: res = gpioGetPWMrange(p1); break; case PI_CMD_PROC: - res = gpioStoreScript(ext[0].ptr); + res = gpioStoreScript(iExt[0].ptr); break; case PI_CMD_PROCD: res = gpioDeleteScript(p1); break; @@ -1132,6 +1141,36 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext) case PI_CMD_READ: res = gpioRead(p1); break; + case PI_CMD_SERVO: + if (gpioMask & (uint64_t)(1<bit >= 0) { @@ -1680,9 +1699,15 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick) if (s->bit == 9) { - s->rxp->buf[s->rxp->writePos] = s->byte; + s->buf[s->writePos] = s->byte; - if (++s->rxp->writePos >= s->rxp->bufSize) s->rxp->writePos = 0; + /* don't let writePos catch readPos */ + + newWritePos = s->writePos; + + if (++newWritePos >= s->bufSize) newWritePos = 0; + + if (newWritePos != s->readPos) s->writePos = newWritePos; if (level == 0) /* true transition high->low, not a timeout */ { @@ -1690,7 +1715,11 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick) s->startBitTick = tick; s->nextBitDiff = s->halfBit; } - else s->bit = -1; + else + { + s->bit = -1; + gpioSetWatchdog(s->gpio, 0); + } } } else @@ -1699,6 +1728,7 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick) if (level == 0) { + gpioSetWatchdog(s->gpio, s->timeout); s->level = 0; s->bit = 0; s->startBitTick = tick; @@ -2621,10 +2651,12 @@ static void * pthTimerTick(void *x) static void * pthFifoThread(void *x) { - char inBuf[256]; - int idx, flags; + char buf[CMD_BUF_SIZE]; + int idx, flags, len; cmdCmd_t cmd; - gpioExtent_t ext[3]; + gpioExtent_t iExt[3]; + gpioExtent_t oExt[3]; + char *p; myCreatePipe(PI_INPFIFO, 0662); @@ -2643,12 +2675,23 @@ static void * pthFifoThread(void *x) while (1) { - if (fgets(inBuf, sizeof(inBuf), inpFifo) == NULL) + if (fgets(buf, sizeof(buf), inpFifo) == NULL) SOFT_ERROR((void*)PI_INIT_FAILED, "fifo fgets failed (%m)"); - if ((idx=cmdParse(inBuf, &cmd, 0, NULL, ext)) >= 0) + len = strlen(buf); + + if (len) { - myDoCommand(&cmd, NULL); + --len; + buf[len] = 0; /* replace terminating */ + } + + if ((idx=cmdParse(buf, &cmd, 0, NULL, iExt)) >= 0) + { + oExt[0].ptr = buf; + oExt[0].size = CMD_BUF_SIZE-1; + + myDoCommand(&cmd, iExt, oExt); switch (cmdInfo[idx].rv) { @@ -2675,6 +2718,17 @@ static void * pthFifoThread(void *x) case 5: fprintf(outFifo, cmdUsage); 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; + } } @@ -2694,8 +2748,13 @@ static void *pthSocketThreadHandler(void *fdC) cmdCmd_t cmd; unsigned bytes; char *memPtr; - gpioExtent_t ext[3]; + gpioExtent_t iExt[3]; + gpioExtent_t oExt[3]; unsigned tmp; + char buf[CMD_BUF_SIZE]; + + oExt[0].size = CMD_BUF_SIZE-1; + oExt[0].ptr = buf; free(fdC); @@ -2719,13 +2778,14 @@ static void *pthSocketThreadHandler(void *fdC) 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); + iExt[0].size = bytes; + iExt[0].ptr = memPtr; + myDoCommand(&cmd, iExt, oExt); free(memPtr); } else @@ -2756,14 +2816,14 @@ static void *pthSocketThreadHandler(void *fdC) { 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); + iExt[0].size = sizeof(unsigned); + iExt[0].ptr = memPtr; + iExt[1].size = sizeof(unsigned); + iExt[1].ptr = memPtr + sizeof(unsigned); + iExt[2].size = cmd.p2; + iExt[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned); memPtr[bytes] = 0; /* may be duplicate terminator */ - myDoCommand(&cmd, ext); + myDoCommand(&cmd, iExt, oExt); free(memPtr); } else @@ -2787,24 +2847,24 @@ static void *pthSocketThreadHandler(void *fdC) bytes = cmd.p1; memPtr = malloc(bytes+1); /* add 1 for a nul terminator */ + if (memPtr) { - if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes) + if (bytes) /* script appended */ { - ext[0].n = bytes; - ext[0].ptr = memPtr; - memPtr[bytes] = 0; /* may be duplicate terminator */ - myDoCommand(&cmd, ext); - free(memPtr); - } - else - { - free(memPtr); - break; + if (recv(sock, memPtr, bytes, MSG_WAITALL) != bytes) + { + free(memPtr); + break; + } } + iExt[0].size = bytes; + iExt[0].ptr = memPtr; + memPtr[bytes] = 0; /* may be duplicate terminator */ + myDoCommand(&cmd, iExt, oExt); + free(memPtr); } else break; - } else { @@ -2817,8 +2877,8 @@ static void *pthSocketThreadHandler(void *fdC) ## extension ## unsigned level */ - ext[0].n = 4; - ext[0].ptr = &tmp; + iExt[0].size = 4; + iExt[0].ptr = &tmp; if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) != sizeof(unsigned)) @@ -2831,11 +2891,26 @@ static void *pthSocketThreadHandler(void *fdC) default: break; } - myDoCommand(&cmd, ext); + myDoCommand(&cmd, iExt, oExt); } write(sock, &cmd, sizeof(cmdCmd_t)); + switch (cmd.cmd) + { + case PI_CMD_SLR: /* extension */ + + if (cmd.res > 0) + { + write(sock, oExt[0].ptr, cmd.res); + } + break; + + default: + break; + } + + } else break; } @@ -4347,6 +4422,9 @@ int gpioWaveAddSerial(unsigned gpio, DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s", gpio, baud, offset, numChar, str); + DBG(DBG_USER, "l=%d s=%X e=%X", + strlen(str), str[0], str[strlen(str)-1]); + CHECK_INITED; if (gpio > PI_MAX_USER_GPIO) @@ -4439,13 +4517,11 @@ int gpioWaveAddSerial(unsigned gpio, /*-------------------------------------------------------------------------*/ -int gpioWaveSerialReadStart(unsigned gpio, - unsigned baud, - gpioRx_t *rxp) +int gpioSerialReadOpen(unsigned gpio, unsigned baud) { - int bitTime, timeoutMs; + int bitTime, timeout; - DBG(DBG_USER, "gpio=%d baud=%d rxp*=%08X", gpio, baud, (uint32_t)rxp); + DBG(DBG_USER, "gpio=%d baud=%d", gpio, baud); CHECK_INITED; @@ -4456,37 +4532,75 @@ int gpioWaveSerialReadStart(unsigned gpio, SOFT_ERROR(PI_BAD_WAVE_BAUD, "gpio %d, bad baud rate (%d)", gpio, baud); - if (rxp == NULL) - SOFT_ERROR(PI_BAD_SERIAL_STRUC, "Null structure pointer"); - - if (rxp->buf == NULL) - SOFT_ERROR(PI_BAD_SERIAL_BUF, "Null buffer pointer"); + if (wfRx[gpio].mode != PI_WFRX_NONE) + SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used", gpio); bitTime = MILLION / baud; - timeoutMs = ((12 * bitTime)+1000)/1000; + timeout = (10 * bitTime)/1000; + if (timeout < 1) timeout = 1; + wfRx[gpio].gpio = gpio; + wfRx[gpio].buf = malloc(SRX_BUF_SIZE); + wfRx[gpio].bufSize = SRX_BUF_SIZE; wfRx[gpio].mode = PI_WFRX_SERIAL; wfRx[gpio].baud = baud; - wfRx[gpio].rxp = rxp; - wfRx[gpio].baud = baud; + wfRx[gpio].timeout = timeout; wfRx[gpio].fullBit = bitTime; wfRx[gpio].halfBit = bitTime/2; - wfRx[gpio].rxp->readPos = 0; - wfRx[gpio].rxp->writePos = 0; + wfRx[gpio].readPos = 0; + wfRx[gpio].writePos = 0; wfRx[gpio].bit = -1; - gpioSetWatchdog(gpio, timeoutMs); /* get a nudge if no change */ - gpioSetAlertFunc(gpio, waveRxBit); return 0; } +/*-------------------------------------------------------------------------*/ + +int gpioSerialRead(unsigned gpio, void *buf, size_t bufSize) +{ + unsigned bytes=0, wpos; + volatile wfRx_t *p; + + DBG(DBG_USER, "gpio=%d buf=%08X bufSize=%d", gpio, (int)buf, bufSize); + + CHECK_INITED; + + if (gpio > PI_MAX_USER_GPIO) + SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio); + + if (bufSize == 0) + SOFT_ERROR(PI_BAD_SERIAL_COUNT, "buffer size can't be zero"); + + if (wfRx[gpio].mode != PI_WFRX_SERIAL) + SOFT_ERROR(PI_NOT_SERIAL_GPIO, "no serial read on gpio (%d)", gpio); + + p = &wfRx[gpio]; + + if (p->readPos != p->writePos) + { + wpos = p->writePos; + + if (wpos > p->readPos) bytes = wpos - p->readPos; + else bytes = p->bufSize - p->readPos; + + if (bytes > bufSize) bytes = bufSize; + + memcpy(buf, p->buf+p->readPos, bytes); + + p->readPos += bytes; + + if (p->readPos >= p->bufSize) p->readPos = 0; + } + return bytes; +} + /*-------------------------------------------------------------------------*/ -int gpioWaveSerialReadStop(unsigned gpio) +int gpioSerialReadClose(unsigned gpio) { DBG(DBG_USER, "gpio=%d", gpio); @@ -4505,6 +4619,8 @@ int gpioWaveSerialReadStop(unsigned gpio) case PI_WFRX_SERIAL: + free(wfRx[gpio].buf); + gpioSetWatchdog(gpio, 0); /* switch off timeouts */ gpioSetAlertFunc(gpio, NULL); /* cancel alert */ @@ -5067,6 +5183,8 @@ void gpioStopThread(pthread_t *pth) int gpioStoreScript(char *script) { DBG(DBG_USER, "script=%s", script); + DBG(DBG_USER, "l=%d s=%X e=%X", + strlen(script), script[0], script[strlen(script)-1]); CHECK_INITED; diff --git a/pigpio.h b/pigpio.h index cf91696..bf5fa89 100644 --- a/pigpio.h +++ b/pigpio.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 11 +This version is for pigpio version 12 */ #ifndef PIGPIO_H @@ -86,7 +86,7 @@ This version is for pigpio version 11 #include #include -#define PIGPIO_VERSION 11 +#define PIGPIO_VERSION 12 /*-------------------------------------------------------------------------*/ @@ -133,8 +133,9 @@ gpioWaveTxStart Transmits the waveform. gpioWaveTxBusy Checks to see if the waveform has ended. gpioWaveTxStop Aborts the current waveform. -gpioWaveSerialReadStart Reads serial data from a user gpio. -gpioWaveSerialReadStop Stops reading serial data from a user gpio. +gpioSerialReadOpen Opens a gpio for reading serial data. +gpioSerialRead Reads serial data from a gpio. +gpioSerialReadClose Closes a gpio for reading serial data. gpioWaveGetMicros Length in microseconds of the current waveform. gpioWaveGetHighMicros Length of longest waveform so far. @@ -226,7 +227,7 @@ typedef struct typedef struct { - size_t n; + size_t size; void *ptr; int data; } gpioExtent_t; @@ -252,14 +253,6 @@ typedef struct uint32_t usDelay; } gpioPulse_t; -typedef struct -{ - char * buf; - uint32_t bufSize; - int readPos; - int writePos; -} gpioRx_t; - typedef void (*gpioAlertFunc_t) (int gpio, int level, uint32_t tick); @@ -974,76 +967,38 @@ int gpioWaveTxStop(void); /*-------------------------------------------------------------------------*/ -int gpioWaveSerialReadStart(unsigned user_gpio, - unsigned baud, - gpioRx_t * rxp); +int gpioSerialReadOpen(unsigned user_gpio, unsigned baud); /*-------------------------------------------------------------------------*/ -/* This function starts the reception of serial data with the - specified baud rate on a gpio. +/* This function opens a gpio for reading serial data. Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, - PI_BAD_SERIAL_STRUC, or PI_BAD_SERIAL_BUF. + or PI_GPIO_IN_USE. - NOTES: - - typedef struct - { - char * buf; - uint32_t bufSize; - int readPos; - int writePos; - } gpioRx_t; - - The serial data is returned in a cyclic buffer which MUST be allocated - by the caller. The caller specifies the location and size of the - buffer in buf and bufSize. + The serial data is returned in a cyclic buffer and is read using + gpioSerialRead(). It is the caller's responsibility to read data from the cyclic buffer - in a timely fashion. Data is available when readPos is not equal to - writePos. - - EXAMPLE: - - #define BUFSIZE 1000 - - char buf[BUFSIZE]; - int bytes, wpos; - FILE * outFile; - - gpioRx_t rx; - - ... - - rx.buf = buf; - rx.bufSize = sizeof(buf); - - if (gpioWaveSerialReadStart(4, 38400, &rx) == 0) - { - ... - - while (rx.readPos != rx.writePos) - { - wpos = rx.writePos; - - if (wpos > rx.readPos) bytes = wpos - rx.readPos; - else bytes = rx.bufSize - rx.readPos; - - fwrite(rx.buf+rx.readPos, 1, bytes, outFile); - - rx.readPos += bytes; - - if (rx.readPos >= rx.bufSize) rx.readPos = 0; - } - ... - } + in a timely fashion. */ /*-------------------------------------------------------------------------*/ -int gpioWaveSerialReadStop(unsigned user_gpio); +int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize); /*-------------------------------------------------------------------------*/ -/* This function stops reading serial data from a gpio. +/* This function copies up to bufSize bytes of data read from the + serial cyclic buffer to the buffer starting at buf. + + Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO + or PI_NOT_SERIAL_GPIO. +*/ + + + +/*-------------------------------------------------------------------------*/ +int gpioSerialReadClose(unsigned user_gpio); +/*-------------------------------------------------------------------------*/ +/* This function closes a gpio for reading serial data. Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO. */ @@ -1901,6 +1856,9 @@ void gpioWaveDump(void); #define PI_CMD_PROCD 39 #define PI_CMD_PROCR 40 #define PI_CMD_PROCS 41 +#define PI_CMD_SLRO 42 +#define PI_CMD_SLR 43 +#define PI_CMD_SLRC 44 /* The following command only works on the socket interface. @@ -1970,6 +1928,8 @@ after this command is issued. #define PI_BAD_SCRIPT -47 /* invalid script */ #define PI_BAD_SCRIPT_ID -48 /* unknown script id */ #define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */ +#define PI_GPIO_IN_USE -50 /* gpio already in use */ +#define PI_BAD_SERIAL_COUNT -51 /* must read at least a byte at a time */ /*-------------------------------------------------------------------------*/ diff --git a/pigpio.py b/pigpio.py index 0b40af8..dd74105 100644 --- a/pigpio.py +++ b/pigpio.py @@ -76,7 +76,7 @@ import threading import os import atexit -VERSION = "1.2" +VERSION = "1.3" # gpio levels @@ -157,6 +157,9 @@ _PI_CMD_PROC= 38 _PI_CMD_PROCD=39 _PI_CMD_PROCR=40 _PI_CMD_PROCS=41 +_PI_CMD_SLRO= 42 +_PI_CMD_SLR= 43 +_PI_CMD_SLRC= 44 _PI_CMD_NOIB= 99 @@ -202,7 +205,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 @@ -214,6 +217,7 @@ PI_BAD_PULSELEN =-46 PI_BAD_SCRIPT =-47 PI_BAD_SCRIPT_ID =-48 PI_BAD_SER_OFFSET =-49 +PI_GPIO_IN_USE =-50 # pigpio error text @@ -252,10 +256,10 @@ _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_NOT_SERIAL_GPIO , "no serial read in progress on gpio"], + [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_BAD_WVSC_COMMND , "bad WVSC subcommand"], @@ -265,6 +269,7 @@ _errors=[ [PI_BAD_SCRIPT , "invalid script"], [PI_BAD_SCRIPT_ID , "unknown script id"], [PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"], + [PI_GPIO_IN_USE , "gpio already in use"], ] _control = None @@ -1701,6 +1706,46 @@ def delete_script(script_id): """ return _u2i(_pigpio_command(_control, _PI_CMD_PROCD, script_id, 0)) +def serial_read_open(user_gpio, baud): + """ + This function opens a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, + or PI_GPIO_IN_USE. + + The serial data is held in a cyclic buffer and is read using + gpioSerialRead(). + + It is the caller's responsibility to read data from the cyclic buffer + in a timely fashion. + """ + return _u2i(_pigpio_command(_control, _PI_CMD_SLRO, user_gpio, baud)) + +def serial_read(user_gpio): + """ + This function returns data from the serial cyclic buffer. + + It returns a tuple of status and string. The status will be the + length, possibly 0, of the returned string if OK. Otherwise a + negative error code will be returned in which case the string + will be null. + """ + bytes = _u2i(_pigpio_command(_control, _PI_CMD_SLR, user_gpio, 10000)) + if bytes > 0: + buf = "" + while len(buf) < bytes: buf += _control.recv(bytes-len(buf)) + return bytes, buf + return bytes, "" + + +def serial_read_close(user_gpio): + """ + This function closes a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO. + """ + return _u2i(_pigpio_command(_control, _PI_CMD_SLRC, user_gpio, 0)) + class callback: """A class to provide gpio level change callbacks.""" diff --git a/pigpiod_if.c b/pigpiod_if.c index e6884fd..4960150 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 2 */ +/* PIGPIOD_IF_VERSION 3 */ #include #include @@ -59,6 +59,7 @@ typedef void (*CBF_t) (); struct callback_s { + int id; int gpio; int edge; @@ -120,7 +121,7 @@ static int pigpio_command_ext for (i=0; i 0) + { + /* get the data */ + recv(gPigCommand, buf, bytes, MSG_WAITALL); + } + return bytes; +} + +int serial_read_close(unsigned gpio) + {return pigpio_command(gPigCommand, PI_CMD_SLRC, gpio, 0);} + +int callback(unsigned gpio, unsigned edge, CBFunc_t f) {return intCallback(gpio, edge, f, 0, 0);} -int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user) +int callback_ex(unsigned gpio, unsigned edge, CBFuncEx_t f, void *user) {return intCallback(gpio, edge, f, user, 1);} -int callback_cancel(int id) +int callback_cancel(unsigned id) { callback_t *p; @@ -766,7 +787,7 @@ int callback_cancel(int id) return pigif_callback_not_found; } -int wait_for_edge(int gpio, int edge, double timeout) +int wait_for_edge(unsigned gpio, unsigned edge, double timeout) { int triggered = 0; int id; diff --git a/pigpiod_if.h b/pigpiod_if.h index 6c009e2..c8e8fc5 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 2 +#define PIGPIOD_IF_VERSION 3 typedef enum { @@ -45,12 +45,13 @@ typedef enum pigif_bad_callback = -2008, pigif_notify_failed = -2009, pigif_callback_not_found = -2010, -} piscopeError_t; +} pigifError_t; -typedef void (*CBFunc_t) (int gpio, int level, uint32_t tick); +typedef void (*CBFunc_t) (unsigned gpio, unsigned level, uint32_t tick); -typedef void (*CBFuncEx_t)(int gpio, int level, uint32_t tick, void * user); +typedef void (*CBFuncEx_t) + (unsigned gpio, unsigned level, uint32_t tick, void * user); typedef struct callback_s callback_t; @@ -110,7 +111,7 @@ void pigpio_stop(void); resources used by the library. */ -int set_mode(int gpio, int mode); +int set_mode(unsigned gpio, unsigned mode); /* Set the gpio mode. gpio: 0-53. @@ -120,7 +121,7 @@ int set_mode(int gpio, int mode); or PI_NOT_PERMITTED. */ -int get_mode(int gpio); +int get_mode(unsigned gpio); /* Get the gpio mode. Returns the gpio mode if OK, otherwise PI_BAD_GPIO. @@ -128,7 +129,7 @@ int get_mode(int gpio); gpio: 0-53. */ -int set_pull_up_down(int gpio, int pud); +int set_pull_up_down(unsigned gpio, unsigned pud); /* Set or clear the gpio pull-up/down resistor. Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD, @@ -138,7 +139,7 @@ int set_pull_up_down(int gpio, int pud); pud: PUD_UP, PUD_DOWN, PUD_OFF. */ -int read_gpio(int gpio); +int read_gpio(unsigned gpio); /* Read the gpio level. Returns the gpio level if OK, otherwise PI_BAD_GPIO. @@ -146,7 +147,7 @@ int read_gpio(int gpio); gpio:0-53. */ -int write_gpio(int gpio, int level); +int write_gpio(unsigned gpio, unsigned level); /* Write the gpio level. @@ -161,7 +162,7 @@ int write_gpio(int gpio, int level); If PWM or servo pulses are active on the gpio they are switched off. */ -int set_PWM_dutycycle(int user_gpio, int dutycycle); +int set_PWM_dutycycle(unsigned user_gpio, unsigned dutycycle); /* Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio. Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE, @@ -175,7 +176,7 @@ int set_PWM_dutycycle(int user_gpio, int dutycycle); The set_PWM_range() function can change the default range of 255. */ -int set_PWM_range(int user_gpio, int range_); +int set_PWM_range(unsigned user_gpio, unsigned range_); /* Set the range of PWM values to be used on the gpio. Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE, @@ -200,7 +201,7 @@ int set_PWM_range(int user_gpio, int range_); (dutycycle * real range) / range. */ -int get_PWM_range(int user_gpio); +int get_PWM_range(unsigned user_gpio); /* Get the range of PWM values being used on the gpio. Returns the dutycycle range used for the gpio if OK, @@ -209,7 +210,7 @@ int get_PWM_range(int user_gpio); user_gpio: 0-31. */ -int get_PWM_real_range(int user_gpio); +int get_PWM_real_range(unsigned user_gpio); /* Get the real underlying range of PWM values being used on the gpio. Returns the real range used for the gpio if OK, @@ -218,7 +219,7 @@ int get_PWM_real_range(int user_gpio); user_gpio: 0-31. */ -int set_PWM_frequency(int user_gpio, int frequency); +int set_PWM_frequency(unsigned user_gpio, unsigned frequency); /* Set the frequency (in Hz) of the PWM to be used on the gpio. @@ -257,7 +258,7 @@ int set_PWM_frequency(int user_gpio, int frequency); 125, 100, 80, 50, 40, 25, 20, 10, 5 */ -int get_PWM_frequency(int user_gpio); +int get_PWM_frequency(unsigned user_gpio); /* Get the frequency of PWM being used on the gpio. @@ -267,7 +268,7 @@ int get_PWM_frequency(int user_gpio); user_gpio: 0-31. */ -int set_servo_pulsewidth(int user_gpio, int pulsewidth); +int set_servo_pulsewidth(unsigned user_gpio, unsigned pulsewidth); /* Start (500-2500) or stop (0) servo pulses on the gpio. @@ -330,7 +331,7 @@ int notify_open(void); read from /dev/pigpio15. */ -int notify_begin(int handle, uint32_t bits); +int notify_begin(unsigned handle, uint32_t bits); /* Start notifications on a previously opened handle. @@ -352,7 +353,7 @@ int notify_begin(int handle, uint32_t bits); I (32 bit) level */ -int notify_pause(int handle); +int notify_pause(unsigned handle); /* Pause notifications on a previously opened handle. @@ -364,7 +365,7 @@ int notify_pause(int handle); notify_begin() is called again. */ -int notify_close(int handle); +int notify_close(unsigned handle); /* Stop notifications on a previously opened handle and release the handle for reuse. @@ -374,7 +375,7 @@ int notify_close(int handle); handle: 0-31 (as returned by notify_open()) */ -int set_watchdog(int user_gpio, int timeout); +int set_watchdog(unsigned user_gpio, unsigned timeout); /* Sets a watchdog for a gpio. @@ -658,25 +659,52 @@ int store_script(char *script); otherwise PI_BAD_SCRIPT. */ -int run_script(int script_id); +int run_script(unsigned 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); +int stop_script(unsigned 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); +int delete_script(unsigned 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); +int serial_read_open(unsigned user_gpio, unsigned baud); +/* This function opens a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, + or PI_GPIO_IN_USE. + + The serial data is returned in a cyclic buffer and is read using + gpioSerialRead(). + + It is the caller's responsibility to read data from the cyclic buffer + in a timely fashion. +*/ + +int serial_read(unsigned user_gpio, void *buf, size_t bufSize); +/* This function copies up to bufSize bytes of data read from the + serial cyclic buffer to the buffer starting at buf. + + Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO + or PI_NOT_SERIAL_GPIO. +*/ + +int serial_read_close(unsigned user_gpio); +/* This function closes a gpio for reading serial data. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO. +*/ + +int callback(unsigned gpio, unsigned edge, CBFunc_t f); /* This function initialises a new callback. @@ -687,7 +715,7 @@ int callback(int gpio, int edge, CBFunc_t f); gpio has the identified edge. */ -int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user); +int callback_ex(unsigned gpio, unsigned edge, CBFuncEx_t f, void *user); /* This function initialises a new callback. @@ -698,14 +726,14 @@ int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user); the gpio has the identified edge. */ -int callback_cancel(int id); +int callback_cancel(unsigned 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); +int wait_for_edge(unsigned gpio, unsigned edge, double timeout); /* This function waits for edge on the gpio for up to timeout seconds. diff --git a/pigs.c b/pigs.c index 4cd84c2..4043c70 100644 --- a/pigs.c +++ b/pigs.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 11+ +This version is for pigpio version 12+ */ #include @@ -153,10 +153,11 @@ int main(int argc , char *argv[]) for (i=0; i 0) + { + recv(sock, &buf, r, MSG_WAITALL); + buf[r] = 0; + printf("%s", buf); + } + break; } } else fatal("recv failed, %m"); diff --git a/setup.py b/setup.py index 270786b..3a8ea36 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from distutils.core import setup setup(name='pigpio', - version='1.2', + version='1.3', author='joan', author_email='joan@abyz.me.uk', maintainer='joan',