From f5912f84b4fac4b5213693c9136055503f879529 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 2 Oct 2015 08:23:02 +0100 Subject: [PATCH] V38 --- Makefile | 12 +- command.c | 18 +- pig2vcd.1 | 15 +- pigpio.3 | 273 ++++++++++++++++++++-- pigpio.c | 613 ++++++++++++++++++++++++++++++++++++++----------- pigpio.h | 211 +++++++++++++++-- pigpio.py | 17 +- pigpiod.1 | 16 +- pigpiod.c | 52 +++-- pigpiod_if.3 | 16 +- pigpiod_if.c | 13 +- pigpiod_if.h | 17 +- pigs.1 | 28 ++- setup.py | 2 +- x_pigpio.py | 23 +- x_pigpiod_if.c | 2 +- x_pigs | 2 +- 17 files changed, 1087 insertions(+), 243 deletions(-) diff --git a/Makefile b/Makefile index 5bbe2af..bf8155e 100644 --- a/Makefile +++ b/Makefile @@ -63,8 +63,8 @@ install: $(ALL) install -m 0755 -s pig2vcd /usr/local/bin install -m 0755 -s pigpiod /usr/local/bin install -m 0755 -s pigs /usr/local/bin - python2 setup.py install - python3 setup.py install + if which python2; then python2 setup.py install; fi + if which python3; then python3 setup.py install; fi install -m 0755 -d /usr/local/man/man1 install -m 0644 *.1 /usr/local/man/man1 install -m 0755 -d /usr/local/man/man3 @@ -79,12 +79,8 @@ uninstall: rm -f /usr/local/bin/pig2vcd rm -f /usr/local/bin/pigpiod rm -f /usr/local/bin/pigs - echo removing python2 files - python2 setup.py install --record /tmp/pigpio >/dev/null - xargs rm -f < /tmp/pigpio >/dev/null - echo removing python3 files - python3 setup.py install --record /tmp/pigpio >/dev/null - xargs rm -f < /tmp/pigpio >/dev/null + if which python2; then python2 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi + if which python3; then python3 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi rm -f /usr/local/man/man1/pig*.1 rm -f /usr/local/man/man3/pig*.3 ldconfig diff --git a/command.c b/command.c index 1981fa5..4a81543 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 37+ +This version is for pigpio version 38+ */ #include @@ -58,6 +58,9 @@ cmdInfo_t cmdInfo[]= {PI_CMD_CF1, "CF1", 195, 2}, // gpioCustom1 {PI_CMD_CF2, "CF2", 195, 6}, // gpioCustom2 + {PI_CMD_CGI, "CGI", 101, 4}, // gpioCfgGetInternals + {PI_CMD_CSI, "CSI", 111, 1}, // gpioCfgSetInternals + {PI_CMD_GDC, "GDC", 112, 2}, // gpioGetPWMdutycycle {PI_CMD_GPW, "GPW", 112, 2}, // gpioGetServoPulsewidth @@ -241,6 +244,9 @@ BS2 bits Set gpios in bank 2\n\ CF1 ... Custom function 1\n\ CF2 ... Custom function 2\n\ \n\ +CGI Configuration get internals\n\ +CSI v Configuration set internals\n\ +\n\ GDC g Get PWM dutycycle for gpio\n\ GPW g Get servo pulsewidth for gpio\n\ \n\ @@ -450,6 +456,7 @@ static errInfo_t errInfo[]= {PI_BAD_HCLK_PASS , "need password to use hardware clock 1"}, {PI_HPWM_ILLEGAL , "illegal, PWM in use for main clock"}, {PI_BAD_DATABITS , "serial data bits not 1-32"}, + {PI_BAD_STOPBITS , "serial (half) stop bits not 2-8"}, {PI_MSG_TOOBIG , "socket/pipe message too big"}, {PI_BAD_MALLOC_MODE , "bad memory allocation mode"}, {PI_TOO_MANY_SEGS , "too many I2C transaction segments"}, @@ -469,6 +476,9 @@ static errInfo_t errInfo[]= {PI_CHAIN_TOO_BIG , "chain is too long"}, {PI_DEPRECATED , "deprecated function removed"}, {PI_BAD_SER_INVERT , "bit bang serial invert not 0 or 1"}, + {PI_BAD_EDGE , "bad ISR edge, not 1, 1, or 2"}, + {PI_BAD_ISR_INIT , "bad ISR initialisation"}, + {PI_BAD_FOREVER , "loop forever must be last chain command"}, }; @@ -567,7 +577,7 @@ int cmdParse( switch (cmdInfo[idx].vt) { - case 101: /* BR1 BR2 H HELP HWVER + case 101: /* BR1 BR2 CGI H HELP HWVER DCRA HALT INRA NO PIGPV POPA PUSHA RET T TICK WVBSY WVCLR WVCRE WVGO WVGOR WVHLT WVNEW @@ -578,8 +588,8 @@ int cmdParse( break; - case 111: /* BC1 BC2 BS1 BS2 - ADD AND CMP DIV LDA LDAB MLT + case 111: /* ADD AND BC1 BC2 BS1 BS2 + CMP CSI DIV LDA LDAB MLT MOD OR RLA RRA STAB SUB WAIT XOR One parameter, any value. diff --git a/pig2vcd.1 b/pig2vcd.1 index 52c5a93..65fab37 100644 --- a/pig2vcd.1 +++ b/pig2vcd.1 @@ -53,29 +53,22 @@ typedef struct .br .br -seqno starts at 0 each time the handle is opened and then increments -by one for each report. +seqno: starts at 0 each time the handle is opened and then increments by one for each report. .br .br -flags, if bit 5 is set then bits 0-4 of the flags indicate a gpio which -has had a watchdog timeout. +flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE. If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags indicate a gpio which has had a watchdog timeout; if bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive signal on the pipe/socket and is sent once a minute in the absence of other notification activity. .br .br -tick is the number of microseconds since system boot. +tick: the number of microseconds since system boot. It wraps around after 1h12m. .br .br -level indicates the level of each gpio. - -.br - -.br -pig2vcd takes these notifications and outputs a text format VCD. +level: indicates the level of each gpio. If bit 1<0 timeout after specified milliseconds +.br + +.EE + +.br + .br .IP "\fBtimer\fP" 0 @@ -7360,6 +7585,12 @@ A 16-bit word value. #define PI_CMD_SLRI 94 .br +.br +#define PI_CMD_CGI 95 +.br +#define PI_CMD_CSI 96 +.br + .br #define PI_CMD_NOIB 99 .br @@ -7618,6 +7849,12 @@ A 16-bit word value. .br #define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1 .br +#define PI_BAD_EDGE -122 // bad ISR edge value, not 0-2 +.br +#define PI_BAD_ISR_INIT -123 // bad ISR initialisation +.br +#define PI_BAD_FOREVER -124 // loop forever must be last chain command +.br .br #define PI_PIGIF_ERR_0 -2000 @@ -7672,6 +7909,10 @@ A 16-bit word value. #define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO .br +.br +#define PI_DEFAULT_CFG_INTERNALS 0 +.br + .br .EE diff --git a/pigpio.c b/pigpio.c index f330ef0..191226a 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 37 */ +/* pigpio version 38 */ /* include ------------------------------------------------------- */ @@ -867,36 +867,48 @@ typedef struct { callbk_t func; unsigned ex; - void * userdata; - int timeout; + void *userdata; + int timeout; uint32_t tick; } gpioAlert_t; +typedef struct +{ + unsigned gpio; + pthread_t *pth; + callbk_t func; + unsigned edge; + int timeout; + unsigned ex; + void *userdata; + int inited; +} gpioISR_t; + typedef struct { callbk_t func; unsigned ex; - void * userdata; + void *userdata; } gpioSignal_t; typedef struct { callbk_t func; unsigned ex; - void * userdata; + void *userdata; uint32_t bits; } gpioGetSamples_t; typedef struct { - callbk_t func; - unsigned ex; - void * userdata; - unsigned id; - unsigned running; - unsigned millis; + callbk_t func; + unsigned ex; + void *userdata; + unsigned id; + unsigned running; + unsigned millis; struct timespec nextTick; - pthread_t pthId; + pthread_t pthId; } gpioTimer_t; typedef struct @@ -928,6 +940,7 @@ typedef struct uint32_t lastReportTick; int fd; int pipe; + int max_emits; } gpioNotify_t; typedef struct @@ -955,8 +968,9 @@ typedef struct typedef struct { - uint32_t startTick; uint32_t alertTicks; + uint32_t lateTicks; + uint32_t moreToDo; uint32_t diffTick[TICKSLOTS]; uint32_t cbTicks; uint32_t cbCalls; @@ -966,6 +980,9 @@ typedef struct uint32_t numSamples; uint32_t DMARestarts; uint32_t dmaInitCbsCount; + uint32_t goodPipeWrite; + uint32_t shortPipeWrite; + uint32_t wouldBlockPipeWrite; } gpioStats_t; typedef struct @@ -977,9 +994,14 @@ typedef struct unsigned DMAsecondaryChannel; unsigned socketPort; unsigned ifFlags; - int dbgLevel; - unsigned showStats; unsigned memAllocMode; + unsigned dbgLevel; + unsigned alertFreq; + uint32_t internals; + /* + 0-3: dbgLevel + 4-7: alertFreq + */ } gpioCfg_t; typedef struct @@ -1131,6 +1153,8 @@ static int pthSocketRunning = 0; static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1]; +static gpioISR_t gpioISR [PI_MAX_USER_GPIO+1]; + static gpioGetSamples_t gpioGetSamples; static gpioInfo_t gpioInfo [PI_MAX_GPIO+1]; @@ -1199,9 +1223,10 @@ static volatile gpioCfg_t gpioCfg = PI_DEFAULT_DMA_SECONDARY_CHANNEL, PI_DEFAULT_SOCKET_PORT, PI_DEFAULT_IF_FLAGS, - DBG_MIN_LEVEL, - 0, PI_DEFAULT_MEM_ALLOC_MODE, + 0, /* dbgLevel */ + 0, /* alertFreq */ + 0, /* internals */ }; /* no initialisation required */ @@ -1413,6 +1438,14 @@ static void myGpioSetMode(unsigned gpio, unsigned mode) } +/* ----------------------------------------------------------------------- */ + +static int myGpioRead(unsigned gpio) +{ + if ((*(gpioReg + GPLEV0 + BANK) & BIT) != 0) return PI_ON; + else return PI_OFF; +} + /* ----------------------------------------------------------------------- */ @@ -1552,11 +1585,12 @@ static uint32_t myGetTick(int pos) static int myPermit(unsigned gpio) { - if ((gpio <= PI_MAX_GPIO) && - (gpioMask & ((uint64_t)(1)< bufSize) p[2] = bufSize; @@ -1697,6 +1730,10 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf) if (res > p[2]) res = p[2]; break; + case PI_CMD_CGI: res = gpioCfgGetInternals(); break; + + case PI_CMD_CSI: res = gpioCfgSetInternals(p[1]); break; + case PI_CMD_GDC: res = gpioGetPWMdutycycle(p[1]); break; case PI_CMD_GPW: res = gpioGetServoPulsewidth(p[1]); break; @@ -2226,14 +2263,11 @@ static void myGpioSetPwm(unsigned gpio, int oldVal, int newVal) static void myGpioSetServo(unsigned gpio, int oldVal, int newVal) { - int switchGpioOff; int newOff, oldOff, realRange, cycles, i; DBG(DBG_INTERNAL, "myGpioSetServo %d from %d to %d", gpio, oldVal, newVal); - switchGpioOff = 0; - realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx]; cycles = pwmCycles [clkCfg[gpioCfg.clockMicros].servoIdx]; @@ -2267,16 +2301,14 @@ static void myGpioSetServo(unsigned gpio, int oldVal, int newVal) for (i=0; i>PI_CFG_ALERT_FREQ)&15]; + while (1) { - - if (dmaIn[DMA_CONBLK_AD]) - { - if (stopped) - { - DBG(DBG_STARTUP, "****** GOING ******"); - stopped = 0; - } - } - else - { - stopped = 1; - - myGpioDelay(5000); - - if (runState == PI_RUNNING) - { - /* should never be executed, leave code just in case */ - - gpioCfg.showStats = 1; - - dmaInitCbs(); - flushMemory(); - initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]); - myGpioDelay(5000); /* let DMA run for a while */ - oldSlot = dmaCurrentSlot(dmaNowAtICB()); - gpioStats.DMARestarts++; - } - } - - gpioStats.alertTicks++; - - req.tv_nsec = 850000; - - while (nanosleep(&req, &rem)) - { - req.tv_sec = rem.tv_sec; - req.tv_nsec = rem.tv_nsec; - } - newSlot = dmaCurrentSlot(dmaNowAtICB()); numSamples = 0; @@ -5086,19 +5094,11 @@ static void * pthAlertThread(void *x) if (diff < 0) { - /* shouldn't happen */ - - //gpioCfg.showStats = 1; - gpioStats.diffTick[0]++; } else if (diff >= TICKSLOTS) { - /* shouldn't happen */ - - //gpioCfg.showStats = 1; - gpioStats.diffTick[TICKSLOTS-1]++; } @@ -5106,6 +5106,8 @@ static void * pthAlertThread(void *x) } } + if (oldSlot == newSlot) moreToDo = 0; else moreToDo = 1; + /* should gpioGetSamples be called */ if (changedBits) @@ -5318,6 +5320,7 @@ static void * pthAlertThread(void *x) if (emit) { gpioNotify[n].lastReportTick = tick; + max_emits = gpioNotify[n].max_emits; if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit; @@ -5325,15 +5328,15 @@ static void * pthAlertThread(void *x) while (emit > 0) { - if (emit > MAX_EMITS) + if (emit > max_emits) { gpioStats.emitFrags++; err = write(gpioNotify[n].fd, gpioReport+emitted, - MAX_EMITS*sizeof(gpioReport_t)); + max_emits*sizeof(gpioReport_t)); - if (err != (MAX_EMITS*sizeof(gpioReport_t))) + if (err != (max_emits*sizeof(gpioReport_t))) { if (err < 0) { @@ -5351,11 +5354,20 @@ static void * pthAlertThread(void *x) intNotifyBits(); break; } + else gpioStats.wouldBlockPipeWrite++; + } + else + { + gpioCfg.internals |= PI_CFG_STATS; + gpioStats.shortPipeWrite++; + DBG(DBG_ALWAYS, "emitted %d, asked for %d", + err/sizeof(gpioReport_t), max_emits); } } + else gpioStats.goodPipeWrite++; - emitted += MAX_EMITS; - emit -= MAX_EMITS; + emitted += max_emits; + emit -= max_emits; } else { @@ -5380,8 +5392,17 @@ static void * pthAlertThread(void *x) intNotifyBits(); break; } + else gpioStats.wouldBlockPipeWrite++; + } + else + { + gpioCfg.internals |= PI_CFG_STATS; + gpioStats.shortPipeWrite++; + DBG(DBG_ALWAYS, "emitted %d, asked for %d", + err/sizeof(gpioReport_t), emit); } } + else gpioStats.goodPipeWrite++; emitted += emit; emit = 0; @@ -5423,6 +5444,91 @@ static void * pthAlertThread(void *x) gpioStats.maxSamples = numSamples; gpioStats.numSamples += numSamples; + + /* Check that DMA is running okay */ + + if (dmaIn[DMA_CONBLK_AD]) + { + if (stopped) + { + DBG(DBG_STARTUP, "****** GOING ******"); + stopped = 0; + } + } + else + { + stopped = 1; + + myGpioDelay(5000); + + if (runState == PI_RUNNING) + { + /* should never be executed, leave code just in case */ + + gpioCfg.internals |= PI_CFG_STATS; + + dmaInitCbs(); + flushMemory(); + initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]); + myGpioDelay(5000); /* let DMA run for a while */ + oldSlot = dmaCurrentSlot(dmaNowAtICB()); + gpioStats.DMARestarts++; + } + } + + nowTick = systReg[SYST_CLO]; + + if (moreToDo) + { + gpioStats.moreToDo++; + + /* rebase wake up time */ + + nextWakeTick = nowTick + + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15]; + + req.tv_nsec = 0; + } + else + { + delayTicks = nextWakeTick - nowTick; + + if (delayTicks < 0) + { + gpioStats.lateTicks++; + + /* rebase wake up time */ + + nextWakeTick = nowTick + + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15]; + + req.tv_nsec = 0; + } + else + { + gpioStats.alertTicks++; + + nextWakeTick += + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15]; + + req.tv_nsec = (delayTicks * 1000); + } + } + + if (req.tv_nsec) + { + req.tv_sec = 0; + + while (nanosleep(&req, &rem)) + { + req.tv_sec = rem.tv_sec; + req.tv_nsec = rem.tv_nsec; + } + } + + nextWakeTick += + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15]; + } return 0; @@ -5960,12 +6066,14 @@ static void *pthSocketThreadHandler(void *fdC) switch (p[0]) { case PI_CMD_NOIB: + p[3] = gpioNotifyOpenInBand(sock); - /* Enable the Nagle algorithm. */ + /* Enable the Nagle algorithm. */ opt = 0; setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int)); + break; case PI_CMD_PROCP: @@ -7041,7 +7149,8 @@ int initInitialise(void) param.sched_priority = sched_get_priority_max(SCHED_FIFO); - sched_setscheduler(0, SCHED_FIFO, ¶m); + if (gpioCfg.internals & PI_CFG_RT_PRIORITY) + sched_setscheduler(0, SCHED_FIFO, ¶m); initClock(1); /* initialise main clock */ @@ -7350,12 +7459,17 @@ void gpioTerminate(void) if (dmaReg != MAP_FAILED) dmaOut[DMA_CS] = DMA_CHANNEL_RESET; #ifndef EMBEDDED_IN_VM - if (gpioCfg.showStats) + if (gpioCfg.internals & PI_CFG_STATS) { + fprintf(stderr, + "\n#####################################################\n"); fprintf(stderr, "If you didn't request stats please cut & paste the\n" "following and e-mail to pigpio@abyz.co.uk\n"); + fprintf(stderr, "pigpio version=%d internals=%X\n", + PIGPIO_VERSION, gpioCfg.internals); + fprintf(stderr, "micros=%d allocMode=%d dmaInitCbs=%d DMARestarts=%d\n", gpioCfg.clockMicros, gpioCfg.memAllocMode, @@ -7366,18 +7480,21 @@ void gpioTerminate(void) gpioStats.numSamples, gpioStats.maxSamples, gpioStats.maxEmit, gpioStats.emitFrags); - fprintf(stderr, "cbTicks %d, cbCalls %u alertTicks %u\n", - gpioStats.cbTicks, gpioStats.cbCalls, gpioStats.alertTicks); + fprintf(stderr, "cbTicks %d, cbCalls %u\n", + gpioStats.cbTicks, gpioStats.cbCalls); + + fprintf(stderr, "pipe: good %u, short %u, would block %u\n", + gpioStats.goodPipeWrite, gpioStats.shortPipeWrite, + gpioStats.wouldBlockPipeWrite); + + fprintf(stderr, "alertTicks %u, lateTicks %u, moreToDo %u\n", + gpioStats.alertTicks, gpioStats.lateTicks, gpioStats.moreToDo); for (i=0; i< TICKSLOTS; i++) fprintf(stderr, "%9u ", gpioStats.diffTick[i]); - fprintf(stderr, "\n"); - - fprintf(stderr, "\n"); - fprintf(stderr, - "#####################################################\n"); + "\n#####################################################\n\n\n"); } #endif @@ -8637,6 +8754,7 @@ int gpioWaveChain(char *buf, unsigned bufSize) "chain counters nested too deep (at %d)", i); stk_pos[stk_lev++] = cb; + i += 2; } else if (cmd == 1) /* loop end */ @@ -8708,7 +8826,6 @@ int gpioWaveChain(char *buf, unsigned bufSize) counters++; } - loop = -1; } else if (cmd == 2) /* delay us */ { @@ -8751,6 +8868,34 @@ int gpioWaveChain(char *buf, unsigned bufSize) p->next = waveCbPOadr(chainGetCB(cb)); } } + else if (cmd == 3) /* repeat loop forever */ + { + i += 2; + + loop = 0; + if (--stk_lev >= 0) loop = stk_pos[stk_lev]; + + if ((loop < 1) || (loop == cb)) + SOFT_ERROR(PI_BAD_CHAIN_LOOP, + "empty chain loop (at %d)", i); + + chaincb = chainGetCB(cb++); + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); + + if (i < bufSize) + SOFT_ERROR(PI_BAD_FOREVER, + "loop forever must be last command"); + + p = rawWaveCBAdr(chaincb); + + /* dummy src and dest */ + p->info = NORMAL_DMA; + p->src = (uint32_t) (&dmaOBus[0]->periphData); + p->dst = (uint32_t) (&dmaOBus[0]->periphData); + p->length = 4; + p->next = waveCbPOadr(chainGetCB(loop)); + } else SOFT_ERROR(PI_BAD_CHAIN_CMD, "unknown chain command (255 %d)", cmd); @@ -9495,6 +9640,212 @@ int gpioSetAlertFuncEx(unsigned gpio, gpioAlertFuncEx_t f, void *userdata) return 0; } +static void *pthISRThread(void *x) +{ + gpioISR_t *isr = x; + int fd; + int retval; + uint32_t tick; + int level; + uint32_t levels; + struct pollfd pfd; + char buf[64]; + + DBG(DBG_USER, "gpio=%d edge=%d timeout=%d f=%x u=%d data=%x", + isr->gpio, isr->edge, isr->timeout, (uint32_t)isr->func, + isr->ex, (uint32_t)isr->userdata); + + sprintf(buf, "/sys/class/gpio/gpio%d/value", isr->gpio); + + if ((fd = open(buf, O_RDONLY)) < 0) + { + DBG(DBG_ALWAYS, "gpio %d not exported", isr->gpio); + return NULL; + } + + pfd.fd = fd; + + pfd.events = POLLPRI; + + lseek(fd, 0, SEEK_SET); /* consume any prior interrupt */ + read(fd, buf, sizeof buf); + + while (1) + { + retval = poll(&pfd, 1, isr->timeout); /* wait for interrupt */ + + tick = systReg[SYST_CLO]; + + levels = *(gpioReg + GPLEV0); + + if (retval >= 0) + { + lseek(fd, 0, SEEK_SET); /* consume interrupt */ + read(fd, buf, sizeof buf); + if (retval) + { + if (levels & (1<gpio)) level = PI_ON; else level = PI_OFF; + } + else level = PI_TIMEOUT; + + if (isr->ex) (isr->func)(isr->gpio, level, tick, isr->userdata); + else (isr->func)(isr->gpio, level, tick); + } + } + + return NULL; +} + + +/* ----------------------------------------------------------------------- */ + +static int intGpioSetISRFunc( + unsigned gpio, + unsigned edge, + int timeout, + void *f, + int user, + void *userdata) +{ + char buf[64]; + + char *edge_str[]={"rising\n", "falling\n", "both\n"}; + int fd; + int err; + + DBG(DBG_INTERNAL, + "gpio=%d edge=%d timeout=%d function=%08X user=%d userdata=%08X", + gpio, edge, timeout, (uint32_t)f, user, (uint32_t)userdata); + + if (f) + { + if (!gpioISR[gpio].inited) /* export gpio if unexported */ + { + fd = open("/sys/class/gpio/export", O_WRONLY); + if (fd < 0) return PI_BAD_ISR_INIT; + + /* ignore write fail if already exported */ + sprintf(buf, "%d\n", gpio); + err = write(fd, buf, strlen(buf)); + close(fd); + + sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio); + fd = open(buf, O_WRONLY); + if (fd < 0) return PI_BAD_ISR_INIT; + + err = write(fd, "in\n", 3); + close(fd); + if (err != 3) return PI_BAD_ISR_INIT; + + gpioISR[gpio].gpio = gpio; + gpioISR[gpio].edge = -1; + gpioISR[gpio].timeout = -1; + + gpioISR[gpio].inited = 1; + } + + if (gpioISR[gpio].edge != edge) + { + sprintf(buf, "/sys/class/gpio/gpio%d/edge", gpio); + fd = open(buf, O_WRONLY); + if (fd < 0) return PI_BAD_ISR_INIT; + + err = write(fd, edge_str[edge], strlen(edge_str[edge])); + close(fd); + if (err != strlen(edge_str[edge])) return PI_BAD_ISR_INIT; + + gpioISR[gpio].edge = edge; + + if (gpioISR[gpio].pth != NULL) + pthread_kill(*gpioISR[gpio].pth, SIGCHLD); + } + + if (timeout <= 0) timeout = -1; + if (gpioISR[gpio].timeout != timeout) + { + gpioISR[gpio].timeout = timeout; + + if (gpioISR[gpio].pth != NULL) + pthread_kill(*gpioISR[gpio].pth, SIGCHLD); + } + + gpioISR[gpio].func = f; + gpioISR[gpio].ex = user; + gpioISR[gpio].userdata = userdata; + + if (gpioISR[gpio].pth == NULL) + gpioISR[gpio].pth = gpioStartThread(pthISRThread, &gpioISR[gpio]); + } + else /* null function, delete ISR, unexport gpio */ + { + if (gpioISR[gpio].pth) /* delete any existing ISR */ + { + gpioStopThread(gpioISR[gpio].pth); + gpioISR[gpio].func = NULL; + gpioISR[gpio].pth = NULL; + } + + if (gpioISR[gpio].inited) /* unexport any gpio */ + { + fd = open("/sys/class/gpio/unexport", O_WRONLY); + if (fd < 0) return PI_BAD_ISR_INIT; + sprintf(buf, "%d\n", gpio); + err = write(fd, buf, strlen(buf)); + close(fd); + if (err != sizeof(buf)) return PI_BAD_ISR_INIT; + gpioISR[gpio].inited = 0; + } + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int gpioSetISRFunc( + unsigned gpio, + unsigned edge, + int timeout, + gpioISRFunc_t f) +{ + DBG(DBG_USER, "gpio=%d edge=%d timeout=%d function=%08X", + gpio, edge, timeout, (uint32_t)f); + + CHECK_INITED; + + if (gpio > PI_MAX_USER_GPIO) + SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio); + + if (edge > EITHER_EDGE) + SOFT_ERROR(PI_BAD_EDGE, "bad ISR edge (%d)", edge); + + return intGpioSetISRFunc(gpio, edge, timeout, f, 0, NULL); +} + + +/* ----------------------------------------------------------------------- */ + +int gpioSetISRFuncEx( + unsigned gpio, + unsigned edge, + int timeout, + gpioAlertFuncEx_t f, + void *userdata) +{ + DBG(DBG_USER, "gpio=%d edge=%d timeout=%d function=%08X userdata=%08X", + gpio, edge, timeout, (uint32_t)f, (uint32_t)userdata); + + CHECK_INITED; + + if (gpio > PI_MAX_USER_GPIO) + SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio); + + if (edge > EITHER_EDGE) + SOFT_ERROR(PI_BAD_EDGE, "bad ISR edge (%d)", edge); + + return intGpioSetISRFunc(gpio, edge, timeout, f, 1, userdata); +} + /* ----------------------------------------------------------------------- */ @@ -9538,6 +9889,7 @@ int gpioNotifyOpen(void) gpioNotify[slot].bits = 0; gpioNotify[slot].fd = fd; gpioNotify[slot].pipe = 1; + gpioNotify[slot].max_emits = MAX_EMITS; gpioNotify[slot].lastReportTick = gpioTick(); return slot; @@ -9572,6 +9924,7 @@ static int gpioNotifyOpenInBand(int fd) gpioNotify[slot].bits = 0; gpioNotify[slot].fd = fd; gpioNotify[slot].pipe = 0; + gpioNotify[slot].max_emits = MAX_EMITS; gpioNotify[slot].lastReportTick = gpioTick(); return slot; @@ -9940,6 +10293,7 @@ void gpioStopThread(pthread_t *pth) { pthread_cancel(*pth); pthread_join(*pth, NULL); + free(pth); } } @@ -10793,34 +11147,33 @@ int gpioCfgMemAlloc(unsigned memAllocMode) /* ----------------------------------------------------------------------- */ -int gpioCfgInternals(unsigned cfgWhat, int cfgVal) +uint32_t gpioCfgGetInternals(void) +{ + return gpioCfg.internals; +} + +int gpioCfgSetInternals(uint32_t cfgVal) +{ + gpioCfg.internals = cfgVal; + gpioCfg.dbgLevel = cfgVal & 0xF; + gpioCfg.alertFreq = (cfgVal>>4) & 0xF; + return 0; +} + +int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal) { int retVal = PI_BAD_CFG_INTERNAL; DBG(DBG_USER, "cfgWhat=%u, cfgVal=%d", cfgWhat, cfgVal); - /* - 133084774 - 207081315 - 293640712 - 394342930 - 472769257 - 430873902 - 635370313 - 684442696 - 786301093 - 816051706 - 858202631 - 997413601 - */ - switch(cfgWhat) { case 562484977: - gpioCfg.showStats = cfgVal; + if (cfgVal) gpioCfg.internals |= PI_CFG_STATS; + else gpioCfg.internals &= (~PI_CFG_STATS); - DBG(DBG_ALWAYS, "showStats is %u", cfgVal); + DBG(DBG_ALWAYS, "show stats is %u", cfgVal); retVal = 0; @@ -10828,15 +11181,16 @@ int gpioCfgInternals(unsigned cfgWhat, int cfgVal) case 984762879: - if (cfgVal < DBG_ALWAYS) cfgVal = DBG_ALWAYS; + if ((cfgVal >= DBG_ALWAYS) && (cfgVal <= DBG_MAX_LEVEL)) + { + + gpioCfg.dbgLevel = cfgVal; + gpioCfg.internals = (gpioCfg.internals & (~0xF)) | cfgVal; - if (cfgVal > DBG_MAX_LEVEL) cfgVal = DBG_MAX_LEVEL; + DBG(DBG_ALWAYS, "Debug level is %u", cfgVal); - gpioCfg.dbgLevel = cfgVal; - - DBG(DBG_ALWAYS, "Debug level is %u", cfgVal); - - retVal = 0; + retVal = 0; + } break; } @@ -10844,6 +11198,7 @@ int gpioCfgInternals(unsigned cfgWhat, int cfgVal) return retVal; } + /* include any user customisations */ #include "custom.cext" diff --git a/pigpio.h b/pigpio.h index bbeb710..2d77003 100644 --- a/pigpio.h +++ b/pigpio.h @@ -31,7 +31,7 @@ For more information, please refer to #include #include -#define PIGPIO_VERSION 37 +#define PIGPIO_VERSION 38 /*TEXT @@ -160,6 +160,9 @@ gpioGetPWMrealRange Get underlying PWM range for a gpio gpioSetAlertFuncEx Request a gpio change callback, extended +gpioSetISRFunc Request a gpio interrupt callback +gpioSetISRFuncEx Request a gpio interrupt callback, extended + gpioSetSignalFunc Request a signal callback gpioSetSignalFuncEx Request a signal callback, extended @@ -281,10 +284,14 @@ gpioCfgDMAchannel Configure the DMA channel (DEPRECATED) gpioCfgDMAchannels Configure the DMA channels gpioCfgPermissions Configure the gpio access permissions gpioCfgInterfaces Configure user interfaces -gpioCfgInternals Configure miscellaneous internals gpioCfgSocketPort Configure socket port gpioCfgMemAlloc Configure DMA memory allocation mode +gpioCfgInternals Configure miscellaneous internals (DEPRECATED) + +gpioCfgGetInternals Get internal configuration settings +gpioCfgSetInternals Set internal configuration settings + CUSTOM gpioCustom1 User custom function 1 @@ -448,6 +455,15 @@ typedef void (*gpioAlertFuncEx_t) (int gpio, uint32_t tick, void *userdata); +typedef void (*gpioISRFunc_t) (int gpio, + int level, + uint32_t tick); + +typedef void (*gpioISRFuncEx_t) (int gpio, + int level, + uint32_t tick, + void *userdata); + typedef void (*gpioTimerFunc_t) (void); typedef void (*gpioTimerFuncEx_t) (void *userdata); @@ -720,6 +736,22 @@ typedef void *(gpioThreadFunc_t) (void *); #define PI_MEM_ALLOC_PAGEMAP 1 #define PI_MEM_ALLOC_MAILBOX 2 +/* gpioCfgInternals */ + +#define PI_CFG_DBG_LEVEL 0 /* bits 0-3 */ +#define PI_CFG_ALERT_FREQ 4 /* bits 4-7 */ +#define PI_CFG_RT_PRIORITY (1<<8) +#define PI_CFG_STATS (1<<9) + +#define PI_CFG_ILLEGAL_VAL (1<<10) + +/* gpioISR */ + +#define RISING_EDGE 0 +#define FALLING_EDGE 1 +#define EITHER_EDGE 2 + + /*F*/ int gpioInitialise(void); /*D @@ -1212,7 +1244,7 @@ void aFunction(int gpio, int level, uint32_t tick) // call aFunction whenever gpio 4 changes state -gpioSetAlertFunc(4, aFunction); +gpioSetAlertFunc(4F, aFunction); ... D*/ @@ -1244,6 +1276,89 @@ See [*gpioSetAlertFunc*] for further details. D*/ +/*F*/ +int gpioSetISRFunc( + unsigned user_gpio, unsigned edge, int timeout, gpioISRFunc_t f); +/*D +Registers a function to be called (a callback) whenever the specified +gpio interrupt occurs. + +. . +user_gpio: 0-31 + edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE + timeout: interrupt timeout in milliseconds (<=0 to cancel) + f: the callback function +. . + +Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE, +or PI_BAD_ISR_INIT. + +One function may be registered per gpio. + +The function is passed the gpio, the current level, and the +current tick. The level will be PI_TIMEOUT if the optional +interrupt timeout expires. + +The underlying Linux sysfs gpio interface is used to provide +the interrupt services. + +The first time the function is called, with a non-NULL f, the +gpio is exported, set to be an input, and set to interrupt +on the given edge and timeout. + +Subsequent calls, with a non-NULL f, can vary one or more of the +edge, timeout, or function. + +The ISR may be cancelled by passing a NULL f, in which case the +gpio is unexported. + +The tick is that read at the time the process was informed of +the interrupt. This will be a variable number of microseconds +after the interrupt occurred. Typically the latency will be of +the order of 50 microseconds. The latency is not guaranteed +and will vary with system load. + +The level is that read at the time the process was informed of +the interrupt, or PI_TIMEOUT if the optional interrupt timeout +expired. It may not be the same as the expected edge as +interrupts happening in rapid succession may be missed by the +kernel (i.e. this mechanism can not be used to capture several +interrupts only a few microseconds apart). +D*/ + + +/*F*/ +int gpioSetISRFuncEx( + unsigned user_gpio, + unsigned edge, + int timeout, + gpioISRFuncEx_t f, + void *userdata); +/*D +Registers a function to be called (a callback) whenever the specified +gpio interrupt occurs. + +. . +user_gpio: 0-31 + edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE + timeout: interrupt timeout in milliseconds (<=0 to cancel) + f: the callback function + userdata: pointer to arbitrary user data +. . + +Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE, +or PI_BAD_ISR_INIT. + +The function is passed the gpio, the current level, the +current tick, and the userdata pointer. + +Only one of [*gpioSetISRFunc*] or [*gpioSetISRFuncEx*] can be +registered per gpio. + +See [*gpioSetISRFunc*] for further details. +D*/ + + /*F*/ int gpioNotifyOpen(void); /*D @@ -1654,10 +1769,13 @@ Delays between waves may be added with the delay command. The following command codes are supported: -Name @ Cmd & Data @ Meaning -Loop Start @ 255 0 @ Identify start of a wave block -Loop Repeat @ 255 1 x y @ loop x + y*256 times -Delay @ 255 2 x y @ delay x + y*256 microseconds +Name @ Cmd & Data @ Meaning +Loop Start @ 255 0 @ Identify start of a wave block +Loop Repeat @ 255 1 x y @ loop x + y*256 times +Delay @ 255 2 x y @ delay x + y*256 microseconds +Loop Forever @ 255 3 @ loop forever + +If present Loop Forever must be the last entry in the chain. The code is currently dimensioned to support a chain with roughly 600 entries and 20 loop counters. @@ -3540,7 +3658,7 @@ size is requested with [*gpioCfgBufferSize*]. D*/ /*F*/ -int gpioCfgInternals(unsigned cfgWhat, int cfgVal); +int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal); /*D Used to tune internal settings. @@ -3550,6 +3668,25 @@ cfgWhat: see source code . . D*/ +/*F*/ +uint32_t gpioCfgGetInternals(void); +/*D +This function returns the current library internal configuration +settings. +D*/ + +/*F*/ +int gpioCfgSetInternals(uint32_t cfgVal); +/*D +This function sets the current library internal configuration +settings. + +. . +cfgVal: see source code +. . +D*/ + + /*F*/ int gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc); /*D @@ -3904,8 +4041,8 @@ clkfreq::4689-250M The hardware clock frequency. . . -#define PI_HW_CLK_MIN_FREQ 4689 -#define PI_HW_CLK_MAX_FREQ 250000000 +PI_HW_CLK_MIN_FREQ 4689 +PI_HW_CLK_MAX_FREQ 250000000 . . count:: @@ -3919,8 +4056,8 @@ The number of data bits to be used when adding serial data to a waveform. . . -#define PI_MIN_WAVE_DATABITS 1 -#define PI_MAX_WAVE_DATABITS 32 +PI_MIN_WAVE_DATABITS 1 +PI_MAX_WAVE_DATABITS 32 . . DMAchannel::0-14 @@ -3940,6 +4077,16 @@ A number representing the ratio of on time to off time for PWM. The number may vary between 0 and range (default 255) where 0 is off and range is fully on. +edge::0-2 +The type of gpio edge to generate an intrrupt. See[*gpioSetISRFunc*], +and [*gpioSetISRFuncEx*]. + +. . +RISING_EDGE 0 +FALLING_EDGE 1 +EITHER_EDGE 2 +. . + f:: A function. @@ -4018,6 +4165,18 @@ typedef void (*gpioGetSamplesFuncEx_t) (const gpioSample_t *samples, int numSamples, void *userdata); . . +gpioISRFunc_t:: +. . +typedef void (*gpioISRFunc_t) + (int gpio, int level, uint32_t tick); +. . + +gpioISRFuncEx_t:: +. . +typedef void (*gpioISRFuncEx_t) + (int gpio, int level, uint32_t tick, void *userdata); +. . + gpioPulse_t:: . . typedef struct @@ -4264,15 +4423,15 @@ PWMduty::0-1000000 (1M) The hardware PWM dutycycle. . . -#define PI_HW_PWM_RANGE 1000000 +PI_HW_PWM_RANGE 1000000 . . PWMfreq::5-250K The hardware PWM frequency. . . -#define PI_HW_PWM_MIN_FREQ 1 -#define PI_HW_PWM_MAX_FREQ 125000000 +PI_HW_PWM_MIN_FREQ 1 +PI_HW_PWM_MAX_FREQ 125000000 . . range::25-40000 @@ -4426,20 +4585,28 @@ The number of (half) stop bits to be used when adding serial data to a waveform. . . -#define PI_MIN_WAVE_HALFSTOPBITS 2 -#define PI_MAX_WAVE_HALFSTOPBITS 8 +PI_MIN_WAVE_HALFSTOPBITS 2 +PI_MAX_WAVE_HALFSTOPBITS 8 . . *str:: An array of characters. timeout:: -A gpio watchdog timeout in milliseconds. +A gpio level change timeout in milliseconds. + +[*gpioSetWatchdog*] . . PI_MIN_WDOG_TIMEOUT 0 PI_MAX_WDOG_TIMEOUT 60000 . . +[*gpioSetISRFunc*] and [*gpioSetISRFuncEx*] +. . +<=0 cancel timeout +>0 timeout after specified milliseconds +. . + timer:: . . PI_MIN_TIMER 0 @@ -4616,6 +4783,9 @@ PARAMS*/ #define PI_CMD_SLRI 94 +#define PI_CMD_CGI 95 +#define PI_CMD_CSI 96 + #define PI_CMD_NOIB 99 /*DEF_E*/ @@ -4802,6 +4972,9 @@ after this command is issued. #define PI_CHAIN_TOO_BIG -119 // chain is too long #define PI_DEPRECATED -120 // deprecated function removed #define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1 +#define PI_BAD_EDGE -122 // bad ISR edge value, not 0-2 +#define PI_BAD_ISR_INIT -123 // bad ISR initialisation +#define PI_BAD_FOREVER -124 // loop forever must be last chain command #define PI_PIGIF_ERR_0 -2000 #define PI_PIGIF_ERR_99 -2099 @@ -4830,6 +5003,8 @@ after this command is issued. #define PI_DEFAULT_UPDATE_MASK_COMPUTE 0x00FFFFFFFFFFFFLL #define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO +#define PI_DEFAULT_CFG_INTERNALS 0 + /*DEF_E*/ #endif diff --git a/pigpio.py b/pigpio.py index a1b3544..2771dfb 100644 --- a/pigpio.py +++ b/pigpio.py @@ -264,7 +264,7 @@ import threading import os import atexit -VERSION = "1.21" +VERSION = "1.22" exceptions = True @@ -433,7 +433,7 @@ _PI_CMD_I2CZ =92 _PI_CMD_WVCHA=93 -_PI_CMD_SLRI= 94 +_PI_CMD_SLRI =94 # pigpio error numbers @@ -899,7 +899,7 @@ class _callback_thread(threading.Thread): def run(self): """Runs the notification thread.""" - lastLevel = 0 + lastLevel = _pigpio_command(self.control, _PI_CMD_BR1, 0, 0) MSG_SIZ = 12 @@ -2014,10 +2014,13 @@ class pi(): The following command codes are supported: - Name @ Cmd & Data @ Meaning - Loop Start @ 255 0 @ Identify start of a wave block - Loop Repeat @ 255 1 x y @ loop x + y*256 times - Delay @ 255 2 x y @ delay x + y*256 microseconds + Name @ Cmd & Data @ Meaning + Loop Start @ 255 0 @ Identify start of a wave block + Loop Repeat @ 255 1 x y @ loop x + y*256 times + Delay @ 255 2 x y @ delay x + y*256 microseconds + Loop Forever @ 255 3 @ loop forever + + If present Loop Forever must be the last entry in the chain. The code is currently dimensioned to support a chain with roughly 600 entries and 20 loop counters. diff --git a/pigpiod.1 b/pigpiod.1 index 3152b16..a54d7b6 100644 --- a/pigpiod.1 +++ b/pigpiod.1 @@ -39,6 +39,11 @@ gpio sample buffer in milliseconds 100-10000 default 120 +.IP "\fB-c value\fP" +library internal settings + +default 0 + .IP "\fB-d value\fP" primary DMA channel 0-14 @@ -158,13 +163,18 @@ affect updateable gpios. .br .br -There are two special cases. +There are several special cases. .br .br -The activity LED may be written (gpio 16 for type 1 and 2 -boards, gpio 47 for type 3 boards). +The activity LED (green) may be written (gpio 16 for type 1 and 2 +boards, gpio 47 for type 3 boards) + +.br + +.br +The power LED (red) may be written on type 3 boards (gpio 35). .br diff --git a/pigpiod.c b/pigpiod.c index da4fb8a..015b0d5 100644 --- a/pigpiod.c +++ b/pigpiod.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 30+ +This version is for pigpio version 38+ */ #include @@ -59,6 +59,8 @@ static unsigned socketPort = PI_DEFAULT_SOCKET_PORT; static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE; static uint64_t updateMask = -1; +static uint32_t cfgInternals = PI_DEFAULT_CFG_INTERNALS; + static int updateMaskSet = 0; static FILE * errFifo; @@ -85,6 +87,7 @@ void usage() "Usage: sudo pigpiod [OPTION] ...\n" \ " -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \ " -b value, gpio sample buffer in milliseconds, default 120\n" \ + " -c value, library internal settings, default 0\n" \ " -d value, primary DMA channel, 0-14, default 14\n" \ " -e value, secondary DMA channel, 0-6, default 5\n" \ " -f, disable fifo interface, default enabled\n" \ @@ -100,41 +103,56 @@ void usage() "\n"); } +static uint64_t getNum(char *str, int *err) +{ + uint64_t val; + char *endptr; + + *err = 0; + val = strtoll(str, &endptr, 0); + if (*endptr) {*err = 1; val = -1;} + return val; +} + static void initOpts(int argc, char *argv[]) { - int i, opt; - uint64_t mask; - char * endptr; + int opt, err, i; + int64_t mask; - while ((opt = getopt(argc, argv, "a:b:d:e:fkp:s:t:x:")) != -1) + while ((opt = getopt(argc, argv, "a:b:c:d:e:fkp:s:t:x:")) != -1) { - i = -1; - switch (opt) { case 'a': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_MEM_ALLOC_AUTO) && (i <= PI_MEM_ALLOC_MAILBOX)) memAllocMode = i; else fatal("invalid -a option (%d)", i); break; case 'b': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX)) bufferSizeMilliseconds = i; else fatal("invalid -b option (%d)", i); break; + case 'c': + i = getNum(optarg, &err); + if ((i >= 0) && (i < PI_CFG_ILLEGAL_VAL)) + cfgInternals = i; + else fatal("invalid -c option (%x)", i); + break; + case 'd': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL)) DMAprimaryChannel = i; else fatal("invalid -d option (%d)", i); break; case 'e': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL)) DMAsecondaryChannel = i; else fatal("invalid -e option (%d)", i); @@ -149,14 +167,14 @@ static void initOpts(int argc, char *argv[]) break; case 'p': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT)) socketPort = i; else fatal("invalid -p option (%d)", i); break; case 's': - i = atoi(optarg); + i = getNum(optarg, &err); switch(i) { @@ -176,15 +194,15 @@ static void initOpts(int argc, char *argv[]) break; case 't': - i = atoi(optarg); + i = getNum(optarg, &err); if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM)) clockPeripheral = i; else fatal("invalid -t option (%d)", i); break; case 'x': - mask = strtoll(optarg, &endptr, 0); - if (!*endptr) + mask = getNum(optarg, &err); + if (!err) { updateMask = mask; updateMaskSet = 1; @@ -273,6 +291,8 @@ int main(int argc, char **argv) if (updateMaskSet) gpioCfgPermissions(updateMask); + gpioCfgSetInternals(cfgInternals); + /* start library */ if (gpioInitialise()< 0) fatal("Can't initialise pigpio library"); diff --git a/pigpiod_if.3 b/pigpiod_if.3 index 77eddcf..3e29b50 100644 --- a/pigpiod_if.3 +++ b/pigpiod_if.3 @@ -1735,18 +1735,26 @@ The following command codes are supported: .br .br -Name Cmd & Data Meaning +Name Cmd & Data Meaning .br -Loop Start 255 0 Identify start of a wave block +Loop Start 255 0 Identify start of a wave block .br -Loop Repeat 255 1 x y loop x + y*256 times +Loop Repeat 255 1 x y loop x + y*256 times .br -Delay 255 2 x y delay x + y*256 microseconds +Delay 255 2 x y delay x + y*256 microseconds .br +Loop Forever 255 3 loop forever + +.br + +.br + +.br +If present Loop Forever must be the last entry in the chain. .br diff --git a/pigpiod_if.c b/pigpiod_if.c index 93b83e4..e36a0fd 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 18 */ +/* PIGPIOD_IF_VERSION 19 */ #include #include @@ -80,6 +80,7 @@ static int gPigHandle = -1; static int gPigNotify = -1; static uint32_t gNotifyBits; +static uint32_t gLastLevel; callback_t *gCallBackFirst = 0; callback_t *gCallBackLast = 0; @@ -220,8 +221,6 @@ static int pigpioOpenSocket(char *addr, char *port) static void dispatch_notification(gpioReport_t *r) { - static uint32_t lastLevel = 0; - callback_t *p; uint32_t changed; int l, g; @@ -233,9 +232,9 @@ static void dispatch_notification(gpioReport_t *r) if (r->flags == 0) { - changed = (r->level ^ lastLevel) & gNotifyBits; + changed = (r->level ^ gLastLevel) & gNotifyBits; - lastLevel = r->level; + gLastLevel = r->level; p = gCallBackFirst; @@ -487,6 +486,7 @@ void stop_thread(pthread_t *pth) { pthread_cancel(*pth); pthread_join(*pth, NULL); + free(pth); } } @@ -507,6 +507,8 @@ int pigpio_start(char *addrStr, char *portStr) if (gPigHandle < 0) return pigif_bad_noib; else { + gLastLevel = read_bank_1(); + pthNotify = start_thread(pthNotifyThread, 0); if (pthNotify) { @@ -1540,3 +1542,4 @@ int wait_for_edge(unsigned user_gpio, unsigned edge, double timeout) return triggered; } + diff --git a/pigpiod_if.h b/pigpiod_if.h index ed68a99..7d6a630 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 18 +#define PIGPIOD_IF_VERSION 20 /*TEXT @@ -283,10 +283,6 @@ typedef void (*CBFuncEx_t) typedef struct callback_s callback_t; -#define RISING_EDGE 0 -#define FALLING_EDGE 1 -#define EITHER_EDGE 2 - /*F*/ double time_time(void); /*D @@ -1207,10 +1203,13 @@ Delays between waves may be added with the delay command. The following command codes are supported: -Name @ Cmd & Data @ Meaning -Loop Start @ 255 0 @ Identify start of a wave block -Loop Repeat @ 255 1 x y @ loop x + y*256 times -Delay @ 255 2 x y @ delay x + y*256 microseconds +Name @ Cmd & Data @ Meaning +Loop Start @ 255 0 @ Identify start of a wave block +Loop Repeat @ 255 1 x y @ loop x + y*256 times +Delay @ 255 2 x y @ delay x + y*256 microseconds +Loop Forever @ 255 3 @ loop forever + +If present Loop Forever must be the last entry in the chain. The code is currently dimensioned to support a chain with roughly 600 entries and 20 loop counters. diff --git a/pigs.1 b/pigs.1 index 544d52e..061255a 100644 --- a/pigs.1 +++ b/pigs.1 @@ -500,6 +500,20 @@ customiser. .br +.IP "\fBCGI \fP - Configuration get internals" +.IP "" 4 +This command returns the value of the internal library +configuration settings. + +.br + +.IP "\fBCSI v\fP - Configuration set internals" +.IP "" 4 +This command sets the value of the internal library +configuration settings to \fBv\fP. + +.br + .IP "\fBGDC u\fP - Get gpio PWM dutycycle" .IP "" 4 @@ -2584,6 +2598,8 @@ will be returned. .br The invert parameter \fBv\fP is 1 for inverted signal, 0 for normal. +.br + \fBExample\fP .br @@ -3170,13 +3186,17 @@ The following command codes are supported: .br .EX -Name Cmd & Data Meaning -Loop Start 255 0 Identify start of a wave block -Loop Repeat 255 1 x y loop x + y*256 times -Delay 255 2 x y delay x + y*256 microseconds +Name Cmd & Data Meaning +Loop Start 255 0 Identify start of a wave block +Loop Repeat 255 1 x y loop x + y*256 times +Delay 255 2 x y delay x + y*256 microseconds +Loop Forever 255 3 loop forever .EE +.br +If present Loop Forever must be the last entry in the chain. + .br The code is currently dimensioned to support a chain with roughly 600 entries and 20 loop counters. diff --git a/setup.py b/setup.py index 19a1a32..958444e 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ from distutils.core import setup setup(name='pigpio', - version='1.21', + version='1.22', author='joan', author_email='joan@abyz.co.uk', maintainer='joan', diff --git a/x_pigpio.py b/x_pigpio.py index 6435370..6cb8aef 100755 --- a/x_pigpio.py +++ b/x_pigpio.py @@ -592,18 +592,27 @@ def t9(): t9cb = pi.callback(GPIO) + old_exceptions = pigpio.exceptions + + pigpio.exceptions = False + s = pi.store_script(script) # Ensure the script has finished initing. while True: - time.sleep(0.1) e, p = pi.script_status(s) if e != pigpio.PI_SCRIPT_INITING: break + time.sleep(0.1) oc = t9cb.tally() pi.run_script(s, [99, GPIO]) - time.sleep(2) + while True: + e, p = pi.script_status(s) + if e != pigpio.PI_SCRIPT_RUNNING: + break + time.sleep(0.1) + time.sleep(0.3) c = t9cb.tally() - oc CHECK(9, 1, c, 100, 0, "store/run script") @@ -613,9 +622,9 @@ def t9(): e, p = pi.script_status(s) if e != pigpio.PI_SCRIPT_RUNNING: break - time.sleep(0.5) + time.sleep(0.1) + time.sleep(0.3) c = t9cb.tally() - oc - time.sleep(0.1) CHECK(9, 2, c, 201, 0, "run script/script status") oc = t9cb.tally() @@ -627,13 +636,15 @@ def t9(): if p[9] < 1900: pi.stop_script(s) time.sleep(0.1) + time.sleep(0.3) c = t9cb.tally() - oc - time.sleep(0.1) - CHECK(9, 3, c, 110, 10, "run/stop script/script status") + CHECK(9, 3, c, 110, 20, "run/stop script/script status") e = pi.delete_script(s) CHECK(9, 4, e, 0, 0, "delete script") + pigpio.exceptions = old_exceptions + def ta(): print("Serial link tests.") diff --git a/x_pigpiod_if.c b/x_pigpiod_if.c index 750b697..2effc32 100644 --- a/x_pigpiod_if.c +++ b/x_pigpiod_if.c @@ -362,7 +362,7 @@ To the lascivious pleasing of a lute.\n\ oc = t5_count; time_sleep(5.05); c = t5_count - oc; - CHECK(5, 4, c, 50, 1, "callback"); + CHECK(5, 4, c, 50, 2, "callback"); e = wave_tx_stop(); CHECK(5, 5, e, 0, 0, "wave tx stop"); diff --git a/x_pigs b/x_pigs index 923734a..a8b8d21 100755 --- a/x_pigs +++ b/x_pigs @@ -49,7 +49,7 @@ s=$(pigs bs2 0) if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi s=$(pigs h) -if [[ ${#s} = 4321 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi +if [[ ${#s} = 4412 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi s=$(pigs hwver) if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi