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