This commit is contained in:
joan 2015-10-02 08:23:02 +01:00
parent 294eac0916
commit f5912f84b4
17 changed files with 1087 additions and 243 deletions

View File

@ -63,8 +63,8 @@ install: $(ALL)
install -m 0755 -s pig2vcd /usr/local/bin install -m 0755 -s pig2vcd /usr/local/bin
install -m 0755 -s pigpiod /usr/local/bin install -m 0755 -s pigpiod /usr/local/bin
install -m 0755 -s pigs /usr/local/bin install -m 0755 -s pigs /usr/local/bin
python2 setup.py install if which python2; then python2 setup.py install; fi
python3 setup.py install if which python3; then python3 setup.py install; fi
install -m 0755 -d /usr/local/man/man1 install -m 0755 -d /usr/local/man/man1
install -m 0644 *.1 /usr/local/man/man1 install -m 0644 *.1 /usr/local/man/man1
install -m 0755 -d /usr/local/man/man3 install -m 0755 -d /usr/local/man/man3
@ -79,12 +79,8 @@ uninstall:
rm -f /usr/local/bin/pig2vcd rm -f /usr/local/bin/pig2vcd
rm -f /usr/local/bin/pigpiod rm -f /usr/local/bin/pigpiod
rm -f /usr/local/bin/pigs rm -f /usr/local/bin/pigs
echo removing python2 files if which python2; then python2 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
python2 setup.py install --record /tmp/pigpio >/dev/null if which python3; then python3 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
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
rm -f /usr/local/man/man1/pig*.1 rm -f /usr/local/man/man1/pig*.1
rm -f /usr/local/man/man3/pig*.3 rm -f /usr/local/man/man3/pig*.3
ldconfig ldconfig

View File

@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
*/ */
/* /*
This version is for pigpio version 37+ This version is for pigpio version 38+
*/ */
#include <stdio.h> #include <stdio.h>
@ -58,6 +58,9 @@ cmdInfo_t cmdInfo[]=
{PI_CMD_CF1, "CF1", 195, 2}, // gpioCustom1 {PI_CMD_CF1, "CF1", 195, 2}, // gpioCustom1
{PI_CMD_CF2, "CF2", 195, 6}, // gpioCustom2 {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_GDC, "GDC", 112, 2}, // gpioGetPWMdutycycle
{PI_CMD_GPW, "GPW", 112, 2}, // gpioGetServoPulsewidth {PI_CMD_GPW, "GPW", 112, 2}, // gpioGetServoPulsewidth
@ -241,6 +244,9 @@ BS2 bits Set gpios in bank 2\n\
CF1 ... Custom function 1\n\ CF1 ... Custom function 1\n\
CF2 ... Custom function 2\n\ CF2 ... Custom function 2\n\
\n\ \n\
CGI Configuration get internals\n\
CSI v Configuration set internals\n\
\n\
GDC g Get PWM dutycycle for gpio\n\ GDC g Get PWM dutycycle for gpio\n\
GPW g Get servo pulsewidth for gpio\n\ GPW g Get servo pulsewidth for gpio\n\
\n\ \n\
@ -450,6 +456,7 @@ static errInfo_t errInfo[]=
{PI_BAD_HCLK_PASS , "need password to use hardware clock 1"}, {PI_BAD_HCLK_PASS , "need password to use hardware clock 1"},
{PI_HPWM_ILLEGAL , "illegal, PWM in use for main clock"}, {PI_HPWM_ILLEGAL , "illegal, PWM in use for main clock"},
{PI_BAD_DATABITS , "serial data bits not 1-32"}, {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_MSG_TOOBIG , "socket/pipe message too big"},
{PI_BAD_MALLOC_MODE , "bad memory allocation mode"}, {PI_BAD_MALLOC_MODE , "bad memory allocation mode"},
{PI_TOO_MANY_SEGS , "too many I2C transaction segments"}, {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_CHAIN_TOO_BIG , "chain is too long"},
{PI_DEPRECATED , "deprecated function removed"}, {PI_DEPRECATED , "deprecated function removed"},
{PI_BAD_SER_INVERT , "bit bang serial invert not 0 or 1"}, {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) switch (cmdInfo[idx].vt)
{ {
case 101: /* BR1 BR2 H HELP HWVER case 101: /* BR1 BR2 CGI H HELP HWVER
DCRA HALT INRA NO DCRA HALT INRA NO
PIGPV POPA PUSHA RET T TICK WVBSY WVCLR PIGPV POPA PUSHA RET T TICK WVBSY WVCLR
WVCRE WVGO WVGOR WVHLT WVNEW WVCRE WVGO WVGOR WVHLT WVNEW
@ -578,8 +588,8 @@ int cmdParse(
break; break;
case 111: /* BC1 BC2 BS1 BS2 case 111: /* ADD AND BC1 BC2 BS1 BS2
ADD AND CMP DIV LDA LDAB MLT CMP CSI DIV LDA LDAB MLT
MOD OR RLA RRA STAB SUB WAIT XOR MOD OR RLA RRA STAB SUB WAIT XOR
One parameter, any value. One parameter, any value.

View File

@ -53,29 +53,22 @@ typedef struct
.br .br
.br .br
seqno starts at 0 each time the handle is opened and then increments seqno: starts at 0 each time the handle is opened and then increments by one for each report.
by one for each report.
.br .br
.br .br
flags, if bit 5 is set then bits 0-4 of the flags indicate a gpio which 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.
has had a watchdog timeout.
.br .br
.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
.br .br
level indicates the level of each gpio. level: indicates the level of each gpio. If bit 1<<x is set then gpio x is high. pig2vcd takes these notifications and outputs a text format VCD.
.br
.br
pig2vcd takes these notifications and outputs a text format VCD.
.br .br

265
pigpio.3
View File

@ -1104,7 +1104,7 @@ void aFunction(int gpio, int level, uint32_t tick)
.br .br
.br .br
gpioSetAlertFunc(4, aFunction); gpioSetAlertFunc(4F, aFunction);
.br .br
.EE .EE
@ -1155,6 +1155,135 @@ registered per gpio.
.br .br
See \fBgpioSetAlertFunc\fP for further details. See \fBgpioSetAlertFunc\fP for further details.
.IP "\fBint gpioSetISRFunc(unsigned user_gpio, unsigned edge, int timeout, gpioISRFunc_t f)\fP"
.IP "" 4
Registers a function to be called (a callback) whenever the specified
gpio interrupt occurs.
.br
.br
.EX
user_gpio: 0-31
.br
edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
.br
timeout: interrupt timeout in milliseconds (<=0 to cancel)
.br
f: the callback function
.br
.EE
.br
.br
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
or PI_BAD_ISR_INIT.
.br
.br
One function may be registered per gpio.
.br
.br
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.
.br
.br
The underlying Linux sysfs gpio interface is used to provide
the interrupt services.
.br
.br
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.
.br
.br
Subsequent calls, with a non-NULL f, can vary one or more of the
edge, timeout, or function.
.br
.br
The ISR may be cancelled by passing a NULL f, in which case the
gpio is unexported.
.br
.br
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.
.br
.br
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).
.IP "\fBint gpioSetISRFuncEx(unsigned user_gpio, unsigned edge, int timeout, gpioISRFuncEx_t f, void *userdata)\fP"
.IP "" 4
Registers a function to be called (a callback) whenever the specified
gpio interrupt occurs.
.br
.br
.EX
user_gpio: 0-31
.br
edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE
.br
timeout: interrupt timeout in milliseconds (<=0 to cancel)
.br
f: the callback function
.br
userdata: pointer to arbitrary user data
.br
.EE
.br
.br
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_EDGE,
or PI_BAD_ISR_INIT.
.br
.br
The function is passed the gpio, the current level, the
current tick, and the userdata pointer.
.br
.br
Only one of \fBgpioSetISRFunc\fP or \fBgpioSetISRFuncEx\fP can be
registered per gpio.
.br
.br
See \fBgpioSetISRFunc\fP for further details.
.IP "\fBint gpioNotifyOpen(void)\fP" .IP "\fBint gpioNotifyOpen(void)\fP"
.IP "" 4 .IP "" 4
This function requests a free notification handle. This function requests a free notification handle.
@ -1917,6 +2046,14 @@ Loop Repeat 255 1 x y loop x + y*256 times
Delay 255 2 x y delay x + y*256 microseconds Delay 255 2 x y delay x + y*256 microseconds
.br .br
Loop Forever 255 3 loop forever
.br
.br
.br
If present Loop Forever must be the last entry in the chain.
.br .br
@ -5064,7 +5201,7 @@ method uses the mailbox property interface to allocate bus memory.
Auto will use the mailbox method unless a larger than default buffer Auto will use the mailbox method unless a larger than default buffer
size is requested with \fBgpioCfgBufferSize\fP. size is requested with \fBgpioCfgBufferSize\fP.
.IP "\fBint gpioCfgInternals(unsigned cfgWhat, int cfgVal)\fP" .IP "\fBint gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal)\fP"
.IP "" 4 .IP "" 4
Used to tune internal settings. Used to tune internal settings.
@ -5080,6 +5217,26 @@ cfgWhat: see source code
.EE .EE
.IP "\fBuint32_t gpioCfgGetInternals(void)\fP"
.IP "" 4
This function returns the current library internal configuration
settings.
.IP "\fBint gpioCfgSetInternals(uint32_t cfgVal)\fP"
.IP "" 4
This function sets the current library internal configuration
settings.
.br
.br
.EX
cfgVal: see source code
.br
.EE
.IP "\fBint gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc)\fP" .IP "\fBint gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc)\fP"
.IP "" 4 .IP "" 4
This function is available for user customisation. This function is available for user customisation.
@ -5698,9 +5855,9 @@ The hardware clock frequency.
.br .br
.EX .EX
#define PI_HW_CLK_MIN_FREQ 4689 PI_HW_CLK_MIN_FREQ 4689
.br .br
#define PI_HW_CLK_MAX_FREQ 250000000 PI_HW_CLK_MAX_FREQ 250000000
.br .br
.EE .EE
@ -5734,9 +5891,9 @@ waveform.
.br .br
.EX .EX
#define PI_MIN_WAVE_DATABITS 1 PI_MIN_WAVE_DATABITS 1
.br .br
#define PI_MAX_WAVE_DATABITS 32 PI_MAX_WAVE_DATABITS 32
.br .br
.EE .EE
@ -5787,6 +5944,28 @@ The number may vary between 0 and range (default 255) where
.br .br
.IP "\fBedge\fP: 0-2" 0
The type of gpio edge to generate an intrrupt. See\fBgpioSetISRFunc\fP,
and \fBgpioSetISRFuncEx\fP.
.br
.br
.EX
RISING_EDGE 0
.br
FALLING_EDGE 1
.br
EITHER_EDGE 2
.br
.EE
.br
.br
.IP "\fBf\fP" 0 .IP "\fBf\fP" 0
.br .br
@ -5964,6 +6143,34 @@ typedef void (*gpioGetSamplesFuncEx_t)
.br .br
.IP "\fBgpioISRFunc_t\fP" 0
.EX
typedef void (*gpioISRFunc_t)
.br
(int gpio, int level, uint32_t tick);
.br
.EE
.br
.br
.IP "\fBgpioISRFuncEx_t\fP" 0
.EX
typedef void (*gpioISRFuncEx_t)
.br
(int gpio, int level, uint32_t tick, void *userdata);
.br
.EE
.br
.br
.IP "\fBgpioPulse_t\fP" 0 .IP "\fBgpioPulse_t\fP" 0
.EX .EX
@ -6551,7 +6758,7 @@ The hardware PWM dutycycle.
.br .br
.EX .EX
#define PI_HW_PWM_RANGE 1000000 PI_HW_PWM_RANGE 1000000
.br .br
.EE .EE
@ -6568,9 +6775,9 @@ The hardware PWM frequency.
.br .br
.EX .EX
#define PI_HW_PWM_MIN_FREQ 1 PI_HW_PWM_MIN_FREQ 1
.br .br
#define PI_HW_PWM_MAX_FREQ 125000000 PI_HW_PWM_MAX_FREQ 125000000
.br .br
.EE .EE
@ -6940,9 +7147,9 @@ to a waveform.
.br .br
.EX .EX
#define PI_MIN_WAVE_HALFSTOPBITS 2 PI_MIN_WAVE_HALFSTOPBITS 2
.br .br
#define PI_MAX_WAVE_HALFSTOPBITS 8 PI_MAX_WAVE_HALFSTOPBITS 8
.br .br
.EE .EE
@ -6959,7 +7166,12 @@ An array of characters.
.br .br
.IP "\fBtimeout\fP" 0 .IP "\fBtimeout\fP" 0
A gpio watchdog timeout in milliseconds. A gpio level change timeout in milliseconds.
.br
.br
\fBgpioSetWatchdog\fP
.EX .EX
PI_MIN_WDOG_TIMEOUT 0 PI_MIN_WDOG_TIMEOUT 0
@ -6971,6 +7183,19 @@ PI_MAX_WDOG_TIMEOUT 60000
.br .br
.br
\fBgpioSetISRFunc\fP and \fBgpioSetISRFuncEx\fP
.EX
<=0 cancel timeout
.br
>0 timeout after specified milliseconds
.br
.EE
.br
.br .br
.IP "\fBtimer\fP" 0 .IP "\fBtimer\fP" 0
@ -7360,6 +7585,12 @@ A 16-bit word value.
#define PI_CMD_SLRI 94 #define PI_CMD_SLRI 94
.br .br
.br
#define PI_CMD_CGI 95
.br
#define PI_CMD_CSI 96
.br
.br .br
#define PI_CMD_NOIB 99 #define PI_CMD_NOIB 99
.br .br
@ -7618,6 +7849,12 @@ A 16-bit word value.
.br .br
#define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1 #define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1
.br .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 .br
#define PI_PIGIF_ERR_0 -2000 #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 #define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO
.br .br
.br
#define PI_DEFAULT_CFG_INTERNALS 0
.br
.br .br
.EE .EE

579
pigpio.c
View File

@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/> For more information, please refer to <http://unlicense.org/>
*/ */
/* pigpio version 37 */ /* pigpio version 38 */
/* include ------------------------------------------------------- */ /* include ------------------------------------------------------- */
@ -872,6 +872,18 @@ typedef struct
uint32_t tick; uint32_t tick;
} gpioAlert_t; } 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 typedef struct
{ {
callbk_t func; callbk_t func;
@ -928,6 +940,7 @@ typedef struct
uint32_t lastReportTick; uint32_t lastReportTick;
int fd; int fd;
int pipe; int pipe;
int max_emits;
} gpioNotify_t; } gpioNotify_t;
typedef struct typedef struct
@ -955,8 +968,9 @@ typedef struct
typedef struct typedef struct
{ {
uint32_t startTick;
uint32_t alertTicks; uint32_t alertTicks;
uint32_t lateTicks;
uint32_t moreToDo;
uint32_t diffTick[TICKSLOTS]; uint32_t diffTick[TICKSLOTS];
uint32_t cbTicks; uint32_t cbTicks;
uint32_t cbCalls; uint32_t cbCalls;
@ -966,6 +980,9 @@ typedef struct
uint32_t numSamples; uint32_t numSamples;
uint32_t DMARestarts; uint32_t DMARestarts;
uint32_t dmaInitCbsCount; uint32_t dmaInitCbsCount;
uint32_t goodPipeWrite;
uint32_t shortPipeWrite;
uint32_t wouldBlockPipeWrite;
} gpioStats_t; } gpioStats_t;
typedef struct typedef struct
@ -977,9 +994,14 @@ typedef struct
unsigned DMAsecondaryChannel; unsigned DMAsecondaryChannel;
unsigned socketPort; unsigned socketPort;
unsigned ifFlags; unsigned ifFlags;
int dbgLevel;
unsigned showStats;
unsigned memAllocMode; unsigned memAllocMode;
unsigned dbgLevel;
unsigned alertFreq;
uint32_t internals;
/*
0-3: dbgLevel
4-7: alertFreq
*/
} gpioCfg_t; } gpioCfg_t;
typedef struct typedef struct
@ -1131,6 +1153,8 @@ static int pthSocketRunning = 0;
static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1]; static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1];
static gpioISR_t gpioISR [PI_MAX_USER_GPIO+1];
static gpioGetSamples_t gpioGetSamples; static gpioGetSamples_t gpioGetSamples;
static gpioInfo_t gpioInfo [PI_MAX_GPIO+1]; static gpioInfo_t gpioInfo [PI_MAX_GPIO+1];
@ -1199,9 +1223,10 @@ static volatile gpioCfg_t gpioCfg =
PI_DEFAULT_DMA_SECONDARY_CHANNEL, PI_DEFAULT_DMA_SECONDARY_CHANNEL,
PI_DEFAULT_SOCKET_PORT, PI_DEFAULT_SOCKET_PORT,
PI_DEFAULT_IF_FLAGS, PI_DEFAULT_IF_FLAGS,
DBG_MIN_LEVEL,
0,
PI_DEFAULT_MEM_ALLOC_MODE, PI_DEFAULT_MEM_ALLOC_MODE,
0, /* dbgLevel */
0, /* alertFreq */
0, /* internals */
}; };
/* no initialisation required */ /* 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) static int myPermit(unsigned gpio)
{ {
if ((gpio <= PI_MAX_GPIO) && if (gpio <= PI_MAX_GPIO)
(gpioMask & ((uint64_t)(1)<<gpio))) {
return 1; if (gpioMask & ((uint64_t)(1)<<gpio)) return 1;
else else return 0;
return 0; }
return 1; /* will fail for bad gpio number */
} }
static void flushMemory(void) static void flushMemory(void)
@ -1689,7 +1723,6 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
res = gpioCustom1(p[1], p[2], buf, p[3]); res = gpioCustom1(p[1], p[2], buf, p[3]);
break; break;
case PI_CMD_CF2: case PI_CMD_CF2:
/* a couple of extra precautions for untrusted code */ /* a couple of extra precautions for untrusted code */
if (p[2] > bufSize) p[2] = bufSize; if (p[2] > 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]; if (res > p[2]) res = p[2];
break; 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_GDC: res = gpioGetPWMdutycycle(p[1]); break;
case PI_CMD_GPW: res = gpioGetServoPulsewidth(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) static void myGpioSetServo(unsigned gpio, int oldVal, int newVal)
{ {
int switchGpioOff;
int newOff, oldOff, realRange, cycles, i; int newOff, oldOff, realRange, cycles, i;
DBG(DBG_INTERNAL, DBG(DBG_INTERNAL,
"myGpioSetServo %d from %d to %d", gpio, oldVal, newVal); "myGpioSetServo %d from %d to %d", gpio, oldVal, newVal);
switchGpioOff = 0;
realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx]; realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx];
cycles = pwmCycles [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<SUPERCYCLE; i+=cycles) for (i=0; i<SUPERCYCLE; i+=cycles)
myClearGpioOn(gpio, i); myClearGpioOn(gpio, i);
/* if in pulse then delay for the last cycle to complete */
if (myGpioRead(gpio)) myGpioDelay(PI_MAX_SERVO_PULSEWIDTH);
/* deschedule gpio off */
for (i=0; i<SUPERLEVEL; i+=realRange) for (i=0; i<SUPERLEVEL; i+=realRange)
myClearGpioOff(gpio, i+oldOff); myClearGpioOff(gpio, i+oldOff);
switchGpioOff = 1;
}
if (switchGpioOff)
{
*(gpioReg + GPCLR0) = (1<<gpio);
*(gpioReg + GPCLR0) = (1<<gpio);
} }
} }
} }
@ -4920,11 +4952,14 @@ static void sigHandler(int signum)
break; break;
case SIGPIPE: case SIGPIPE:
case SIGCHLD:
case SIGWINCH: case SIGWINCH:
DBG(DBG_USER, "signal %d ignored", signum); DBG(DBG_USER, "signal %d ignored", signum);
break; break;
case SIGCHLD:
/* Used to notify threads of events */
break;
default: default:
DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum); DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
gpioTerminate(); gpioTerminate();
@ -4959,6 +4994,12 @@ static void sigSetHandler(void)
} }
} }
unsigned alert_delays[]={
1000, 1068, 1145, 1235,
1339, 1463, 1613, 1796,
2027, 2326, 2727, 3297,
4167, 5660, 8823, 20000};
/* ======================================================================= */ /* ======================================================================= */
static void * pthAlertThread(void *x) static void * pthAlertThread(void *x)
@ -4966,7 +5007,7 @@ static void * pthAlertThread(void *x)
struct timespec req, rem; struct timespec req, rem;
uint32_t oldLevel, newLevel, level, reportedLevel; uint32_t oldLevel, newLevel, level, reportedLevel;
uint32_t oldSlot, newSlot; uint32_t oldSlot, newSlot;
uint32_t tick, expected; uint32_t tick, expected, nowTick;
int32_t diff; int32_t diff;
int cycle, pulse; int cycle, pulse;
int emit, seqno, emitted; int emit, seqno, emitted;
@ -4975,6 +5016,10 @@ static void * pthAlertThread(void *x)
int b, n, v; int b, n, v;
int err; int err;
int stopped; int stopped;
int delayTicks;
uint32_t nextWakeTick;
int moreToDo;
int max_emits;
char fifo[32]; char fifo[32];
req.tv_sec = 0; req.tv_sec = 0;
@ -4985,10 +5030,6 @@ static void * pthAlertThread(void *x)
reportedLevel = gpioReg[GPLEV0]; reportedLevel = gpioReg[GPLEV0];
tick = systReg[SYST_CLO];
gpioStats.startTick = tick;
oldSlot = dmaCurrentSlot(dmaNowAtICB()); oldSlot = dmaCurrentSlot(dmaNowAtICB());
cycle = (oldSlot/PULSE_PER_CYCLE); cycle = (oldSlot/PULSE_PER_CYCLE);
@ -4996,48 +5037,15 @@ static void * pthAlertThread(void *x)
stopped = 0; stopped = 0;
moreToDo = 0;
tick = systReg[SYST_CLO];
nextWakeTick =
tick + alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15];
while (1) 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()); newSlot = dmaCurrentSlot(dmaNowAtICB());
numSamples = 0; numSamples = 0;
@ -5086,19 +5094,11 @@ static void * pthAlertThread(void *x)
if (diff < 0) if (diff < 0)
{ {
/* shouldn't happen */
//gpioCfg.showStats = 1;
gpioStats.diffTick[0]++; gpioStats.diffTick[0]++;
} }
else if (diff >= TICKSLOTS) else if (diff >= TICKSLOTS)
{ {
/* shouldn't happen */
//gpioCfg.showStats = 1;
gpioStats.diffTick[TICKSLOTS-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 */ /* should gpioGetSamples be called */
if (changedBits) if (changedBits)
@ -5318,6 +5320,7 @@ static void * pthAlertThread(void *x)
if (emit) if (emit)
{ {
gpioNotify[n].lastReportTick = tick; gpioNotify[n].lastReportTick = tick;
max_emits = gpioNotify[n].max_emits;
if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit; if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit;
@ -5325,15 +5328,15 @@ static void * pthAlertThread(void *x)
while (emit > 0) while (emit > 0)
{ {
if (emit > MAX_EMITS) if (emit > max_emits)
{ {
gpioStats.emitFrags++; gpioStats.emitFrags++;
err = write(gpioNotify[n].fd, err = write(gpioNotify[n].fd,
gpioReport+emitted, 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) if (err < 0)
{ {
@ -5351,11 +5354,20 @@ static void * pthAlertThread(void *x)
intNotifyBits(); intNotifyBits();
break; 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; emitted += max_emits;
emit -= MAX_EMITS; emit -= max_emits;
} }
else else
{ {
@ -5380,8 +5392,17 @@ static void * pthAlertThread(void *x)
intNotifyBits(); intNotifyBits();
break; 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; emitted += emit;
emit = 0; emit = 0;
@ -5423,6 +5444,91 @@ static void * pthAlertThread(void *x)
gpioStats.maxSamples = numSamples; gpioStats.maxSamples = numSamples;
gpioStats.numSamples += 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; return 0;
@ -5960,12 +6066,14 @@ static void *pthSocketThreadHandler(void *fdC)
switch (p[0]) switch (p[0])
{ {
case PI_CMD_NOIB: case PI_CMD_NOIB:
p[3] = gpioNotifyOpenInBand(sock); p[3] = gpioNotifyOpenInBand(sock);
/* Enable the Nagle algorithm. */ /* Enable the Nagle algorithm. */
opt = 0; opt = 0;
setsockopt( setsockopt(
sock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int)); sock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int));
break; break;
case PI_CMD_PROCP: case PI_CMD_PROCP:
@ -7041,6 +7149,7 @@ int initInitialise(void)
param.sched_priority = sched_get_priority_max(SCHED_FIFO); param.sched_priority = sched_get_priority_max(SCHED_FIFO);
if (gpioCfg.internals & PI_CFG_RT_PRIORITY)
sched_setscheduler(0, SCHED_FIFO, &param); sched_setscheduler(0, SCHED_FIFO, &param);
initClock(1); /* initialise main clock */ initClock(1); /* initialise main clock */
@ -7350,12 +7459,17 @@ void gpioTerminate(void)
if (dmaReg != MAP_FAILED) dmaOut[DMA_CS] = DMA_CHANNEL_RESET; if (dmaReg != MAP_FAILED) dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
#ifndef EMBEDDED_IN_VM #ifndef EMBEDDED_IN_VM
if (gpioCfg.showStats) if (gpioCfg.internals & PI_CFG_STATS)
{ {
fprintf(stderr,
"\n#####################################################\n");
fprintf(stderr, fprintf(stderr,
"If you didn't request stats please cut & paste the\n" "If you didn't request stats please cut & paste the\n"
"following and e-mail to pigpio@abyz.co.uk\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, fprintf(stderr,
"micros=%d allocMode=%d dmaInitCbs=%d DMARestarts=%d\n", "micros=%d allocMode=%d dmaInitCbs=%d DMARestarts=%d\n",
gpioCfg.clockMicros, gpioCfg.memAllocMode, gpioCfg.clockMicros, gpioCfg.memAllocMode,
@ -7366,18 +7480,21 @@ void gpioTerminate(void)
gpioStats.numSamples, gpioStats.maxSamples, gpioStats.numSamples, gpioStats.maxSamples,
gpioStats.maxEmit, gpioStats.emitFrags); gpioStats.maxEmit, gpioStats.emitFrags);
fprintf(stderr, "cbTicks %d, cbCalls %u alertTicks %u\n", fprintf(stderr, "cbTicks %d, cbCalls %u\n",
gpioStats.cbTicks, gpioStats.cbCalls, gpioStats.alertTicks); 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++) for (i=0; i< TICKSLOTS; i++)
fprintf(stderr, "%9u ", gpioStats.diffTick[i]); fprintf(stderr, "%9u ", gpioStats.diffTick[i]);
fprintf(stderr, "\n");
fprintf(stderr, "\n");
fprintf(stderr, fprintf(stderr,
"#####################################################\n"); "\n#####################################################\n\n\n");
} }
#endif #endif
@ -8637,6 +8754,7 @@ int gpioWaveChain(char *buf, unsigned bufSize)
"chain counters nested too deep (at %d)", i); "chain counters nested too deep (at %d)", i);
stk_pos[stk_lev++] = cb; stk_pos[stk_lev++] = cb;
i += 2; i += 2;
} }
else if (cmd == 1) /* loop end */ else if (cmd == 1) /* loop end */
@ -8708,7 +8826,6 @@ int gpioWaveChain(char *buf, unsigned bufSize)
counters++; counters++;
} }
loop = -1;
} }
else if (cmd == 2) /* delay us */ else if (cmd == 2) /* delay us */
{ {
@ -8751,6 +8868,34 @@ int gpioWaveChain(char *buf, unsigned bufSize)
p->next = waveCbPOadr(chainGetCB(cb)); 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 else
SOFT_ERROR(PI_BAD_CHAIN_CMD, SOFT_ERROR(PI_BAD_CHAIN_CMD,
"unknown chain command (255 %d)", cmd); "unknown chain command (255 %d)", cmd);
@ -9495,6 +9640,212 @@ int gpioSetAlertFuncEx(unsigned gpio, gpioAlertFuncEx_t f, void *userdata)
return 0; 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<<isr->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].bits = 0;
gpioNotify[slot].fd = fd; gpioNotify[slot].fd = fd;
gpioNotify[slot].pipe = 1; gpioNotify[slot].pipe = 1;
gpioNotify[slot].max_emits = MAX_EMITS;
gpioNotify[slot].lastReportTick = gpioTick(); gpioNotify[slot].lastReportTick = gpioTick();
return slot; return slot;
@ -9572,6 +9924,7 @@ static int gpioNotifyOpenInBand(int fd)
gpioNotify[slot].bits = 0; gpioNotify[slot].bits = 0;
gpioNotify[slot].fd = fd; gpioNotify[slot].fd = fd;
gpioNotify[slot].pipe = 0; gpioNotify[slot].pipe = 0;
gpioNotify[slot].max_emits = MAX_EMITS;
gpioNotify[slot].lastReportTick = gpioTick(); gpioNotify[slot].lastReportTick = gpioTick();
return slot; return slot;
@ -9940,6 +10293,7 @@ void gpioStopThread(pthread_t *pth)
{ {
pthread_cancel(*pth); pthread_cancel(*pth);
pthread_join(*pth, NULL); 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; int retVal = PI_BAD_CFG_INTERNAL;
DBG(DBG_USER, "cfgWhat=%u, cfgVal=%d", cfgWhat, cfgVal); DBG(DBG_USER, "cfgWhat=%u, cfgVal=%d", cfgWhat, cfgVal);
/*
133084774
207081315
293640712
394342930
472769257
430873902
635370313
684442696
786301093
816051706
858202631
997413601
*/
switch(cfgWhat) switch(cfgWhat)
{ {
case 562484977: 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; retVal = 0;
@ -10828,15 +11181,16 @@ int gpioCfgInternals(unsigned cfgWhat, int cfgVal)
case 984762879: case 984762879:
if (cfgVal < DBG_ALWAYS) cfgVal = DBG_ALWAYS; if ((cfgVal >= DBG_ALWAYS) && (cfgVal <= DBG_MAX_LEVEL))
{
if (cfgVal > DBG_MAX_LEVEL) cfgVal = DBG_MAX_LEVEL;
gpioCfg.dbgLevel = cfgVal; gpioCfg.dbgLevel = cfgVal;
gpioCfg.internals = (gpioCfg.internals & (~0xF)) | cfgVal;
DBG(DBG_ALWAYS, "Debug level is %u", cfgVal); DBG(DBG_ALWAYS, "Debug level is %u", cfgVal);
retVal = 0; retVal = 0;
}
break; break;
} }
@ -10844,6 +11198,7 @@ int gpioCfgInternals(unsigned cfgWhat, int cfgVal)
return retVal; return retVal;
} }
/* include any user customisations */ /* include any user customisations */
#include "custom.cext" #include "custom.cext"

203
pigpio.h
View File

@ -31,7 +31,7 @@ For more information, please refer to <http://unlicense.org/>
#include <stdint.h> #include <stdint.h>
#include <pthread.h> #include <pthread.h>
#define PIGPIO_VERSION 37 #define PIGPIO_VERSION 38
/*TEXT /*TEXT
@ -160,6 +160,9 @@ gpioGetPWMrealRange Get underlying PWM range for a gpio
gpioSetAlertFuncEx Request a gpio change callback, extended 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 gpioSetSignalFunc Request a signal callback
gpioSetSignalFuncEx Request a signal callback, extended gpioSetSignalFuncEx Request a signal callback, extended
@ -281,10 +284,14 @@ gpioCfgDMAchannel Configure the DMA channel (DEPRECATED)
gpioCfgDMAchannels Configure the DMA channels gpioCfgDMAchannels Configure the DMA channels
gpioCfgPermissions Configure the gpio access permissions gpioCfgPermissions Configure the gpio access permissions
gpioCfgInterfaces Configure user interfaces gpioCfgInterfaces Configure user interfaces
gpioCfgInternals Configure miscellaneous internals
gpioCfgSocketPort Configure socket port gpioCfgSocketPort Configure socket port
gpioCfgMemAlloc Configure DMA memory allocation mode gpioCfgMemAlloc Configure DMA memory allocation mode
gpioCfgInternals Configure miscellaneous internals (DEPRECATED)
gpioCfgGetInternals Get internal configuration settings
gpioCfgSetInternals Set internal configuration settings
CUSTOM CUSTOM
gpioCustom1 User custom function 1 gpioCustom1 User custom function 1
@ -448,6 +455,15 @@ typedef void (*gpioAlertFuncEx_t) (int gpio,
uint32_t tick, uint32_t tick,
void *userdata); 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 (*gpioTimerFunc_t) (void);
typedef void (*gpioTimerFuncEx_t) (void *userdata); 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_PAGEMAP 1
#define PI_MEM_ALLOC_MAILBOX 2 #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*/ /*F*/
int gpioInitialise(void); int gpioInitialise(void);
/*D /*D
@ -1212,7 +1244,7 @@ void aFunction(int gpio, int level, uint32_t tick)
// call aFunction whenever gpio 4 changes state // call aFunction whenever gpio 4 changes state
gpioSetAlertFunc(4, aFunction); gpioSetAlertFunc(4F, aFunction);
... ...
D*/ D*/
@ -1244,6 +1276,89 @@ See [*gpioSetAlertFunc*] for further details.
D*/ 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*/ /*F*/
int gpioNotifyOpen(void); int gpioNotifyOpen(void);
/*D /*D
@ -1658,6 +1773,9 @@ Name @ Cmd & Data @ Meaning
Loop Start @ 255 0 @ Identify start of a wave block Loop Start @ 255 0 @ Identify start of a wave block
Loop Repeat @ 255 1 x y @ loop x + y*256 times Loop Repeat @ 255 1 x y @ loop x + y*256 times
Delay @ 255 2 x y @ delay x + y*256 microseconds 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 The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters. 600 entries and 20 loop counters.
@ -3540,7 +3658,7 @@ size is requested with [*gpioCfgBufferSize*].
D*/ D*/
/*F*/ /*F*/
int gpioCfgInternals(unsigned cfgWhat, int cfgVal); int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal);
/*D /*D
Used to tune internal settings. Used to tune internal settings.
@ -3550,6 +3668,25 @@ cfgWhat: see source code
. . . .
D*/ 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*/ /*F*/
int gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc); int gpioCustom1(unsigned arg1, unsigned arg2, char *argx, unsigned argc);
/*D /*D
@ -3904,8 +4041,8 @@ clkfreq::4689-250M
The hardware clock frequency. The hardware clock frequency.
. . . .
#define PI_HW_CLK_MIN_FREQ 4689 PI_HW_CLK_MIN_FREQ 4689
#define PI_HW_CLK_MAX_FREQ 250000000 PI_HW_CLK_MAX_FREQ 250000000
. . . .
count:: count::
@ -3919,8 +4056,8 @@ The number of data bits to be used when adding serial data to a
waveform. waveform.
. . . .
#define PI_MIN_WAVE_DATABITS 1 PI_MIN_WAVE_DATABITS 1
#define PI_MAX_WAVE_DATABITS 32 PI_MAX_WAVE_DATABITS 32
. . . .
DMAchannel::0-14 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 The number may vary between 0 and range (default 255) where
0 is off and range is fully on. 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:: f::
A function. A function.
@ -4018,6 +4165,18 @@ typedef void (*gpioGetSamplesFuncEx_t)
(const gpioSample_t *samples, int numSamples, void *userdata); (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:: gpioPulse_t::
. . . .
typedef struct typedef struct
@ -4264,15 +4423,15 @@ PWMduty::0-1000000 (1M)
The hardware PWM dutycycle. The hardware PWM dutycycle.
. . . .
#define PI_HW_PWM_RANGE 1000000 PI_HW_PWM_RANGE 1000000
. . . .
PWMfreq::5-250K PWMfreq::5-250K
The hardware PWM frequency. The hardware PWM frequency.
. . . .
#define PI_HW_PWM_MIN_FREQ 1 PI_HW_PWM_MIN_FREQ 1
#define PI_HW_PWM_MAX_FREQ 125000000 PI_HW_PWM_MAX_FREQ 125000000
. . . .
range::25-40000 range::25-40000
@ -4426,20 +4585,28 @@ The number of (half) stop bits to be used when adding serial data
to a waveform. to a waveform.
. . . .
#define PI_MIN_WAVE_HALFSTOPBITS 2 PI_MIN_WAVE_HALFSTOPBITS 2
#define PI_MAX_WAVE_HALFSTOPBITS 8 PI_MAX_WAVE_HALFSTOPBITS 8
. . . .
*str:: *str::
An array of characters. An array of characters.
timeout:: timeout::
A gpio watchdog timeout in milliseconds. A gpio level change timeout in milliseconds.
[*gpioSetWatchdog*]
. . . .
PI_MIN_WDOG_TIMEOUT 0 PI_MIN_WDOG_TIMEOUT 0
PI_MAX_WDOG_TIMEOUT 60000 PI_MAX_WDOG_TIMEOUT 60000
. . . .
[*gpioSetISRFunc*] and [*gpioSetISRFuncEx*]
. .
<=0 cancel timeout
>0 timeout after specified milliseconds
. .
timer:: timer::
. . . .
PI_MIN_TIMER 0 PI_MIN_TIMER 0
@ -4616,6 +4783,9 @@ PARAMS*/
#define PI_CMD_SLRI 94 #define PI_CMD_SLRI 94
#define PI_CMD_CGI 95
#define PI_CMD_CSI 96
#define PI_CMD_NOIB 99 #define PI_CMD_NOIB 99
/*DEF_E*/ /*DEF_E*/
@ -4802,6 +4972,9 @@ after this command is issued.
#define PI_CHAIN_TOO_BIG -119 // chain is too long #define PI_CHAIN_TOO_BIG -119 // chain is too long
#define PI_DEPRECATED -120 // deprecated function removed #define PI_DEPRECATED -120 // deprecated function removed
#define PI_BAD_SER_INVERT -121 // bit bang serial invert not 0 or 1 #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_0 -2000
#define PI_PIGIF_ERR_99 -2099 #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_UPDATE_MASK_COMPUTE 0x00FFFFFFFFFFFFLL
#define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO #define PI_DEFAULT_MEM_ALLOC_MODE PI_MEM_ALLOC_AUTO
#define PI_DEFAULT_CFG_INTERNALS 0
/*DEF_E*/ /*DEF_E*/
#endif #endif

View File

@ -264,7 +264,7 @@ import threading
import os import os
import atexit import atexit
VERSION = "1.21" VERSION = "1.22"
exceptions = True exceptions = True
@ -899,7 +899,7 @@ class _callback_thread(threading.Thread):
def run(self): def run(self):
"""Runs the notification thread.""" """Runs the notification thread."""
lastLevel = 0 lastLevel = _pigpio_command(self.control, _PI_CMD_BR1, 0, 0)
MSG_SIZ = 12 MSG_SIZ = 12
@ -2018,6 +2018,9 @@ class pi():
Loop Start @ 255 0 @ Identify start of a wave block Loop Start @ 255 0 @ Identify start of a wave block
Loop Repeat @ 255 1 x y @ loop x + y*256 times Loop Repeat @ 255 1 x y @ loop x + y*256 times
Delay @ 255 2 x y @ delay x + y*256 microseconds 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 The code is currently dimensioned to support a chain with
roughly 600 entries and 20 loop counters. roughly 600 entries and 20 loop counters.

View File

@ -39,6 +39,11 @@ gpio sample buffer in milliseconds
100-10000 100-10000
default 120 default 120
.IP "\fB-c value\fP"
library internal settings
default 0
.IP "\fB-d value\fP" .IP "\fB-d value\fP"
primary DMA channel primary DMA channel
0-14 0-14
@ -158,13 +163,18 @@ affect updateable gpios.
.br .br
.br .br
There are two special cases. There are several special cases.
.br .br
.br .br
The activity LED may be written (gpio 16 for type 1 and 2 The activity LED (green) may be written (gpio 16 for type 1 and 2
boards, gpio 47 for type 3 boards). boards, gpio 47 for type 3 boards)
.br
.br
The power LED (red) may be written on type 3 boards (gpio 35).
.br .br

View File

@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
*/ */
/* /*
This version is for pigpio version 30+ This version is for pigpio version 38+
*/ */
#include <sys/types.h> #include <sys/types.h>
@ -59,6 +59,8 @@ static unsigned socketPort = PI_DEFAULT_SOCKET_PORT;
static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE; static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE;
static uint64_t updateMask = -1; static uint64_t updateMask = -1;
static uint32_t cfgInternals = PI_DEFAULT_CFG_INTERNALS;
static int updateMaskSet = 0; static int updateMaskSet = 0;
static FILE * errFifo; static FILE * errFifo;
@ -85,6 +87,7 @@ void usage()
"Usage: sudo pigpiod [OPTION] ...\n" \ "Usage: sudo pigpiod [OPTION] ...\n" \
" -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \ " -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \
" -b value, gpio sample buffer in milliseconds, default 120\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" \ " -d value, primary DMA channel, 0-14, default 14\n" \
" -e value, secondary DMA channel, 0-6, default 5\n" \ " -e value, secondary DMA channel, 0-6, default 5\n" \
" -f, disable fifo interface, default enabled\n" \ " -f, disable fifo interface, default enabled\n" \
@ -100,41 +103,56 @@ void usage()
"\n"); "\n");
} }
static void initOpts(int argc, char *argv[]) static uint64_t getNum(char *str, int *err)
{ {
int i, opt; uint64_t val;
uint64_t mask;
char *endptr; char *endptr;
while ((opt = getopt(argc, argv, "a:b:d:e:fkp:s:t:x:")) != -1) *err = 0;
{ val = strtoll(str, &endptr, 0);
i = -1; if (*endptr) {*err = 1; val = -1;}
return val;
}
static void initOpts(int argc, char *argv[])
{
int opt, err, i;
int64_t mask;
while ((opt = getopt(argc, argv, "a:b:c:d:e:fkp:s:t:x:")) != -1)
{
switch (opt) switch (opt)
{ {
case 'a': case 'a':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_MEM_ALLOC_AUTO) && (i <= PI_MEM_ALLOC_MAILBOX)) if ((i >= PI_MEM_ALLOC_AUTO) && (i <= PI_MEM_ALLOC_MAILBOX))
memAllocMode = i; memAllocMode = i;
else fatal("invalid -a option (%d)", i); else fatal("invalid -a option (%d)", i);
break; break;
case 'b': case 'b':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX)) if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX))
bufferSizeMilliseconds = i; bufferSizeMilliseconds = i;
else fatal("invalid -b option (%d)", i); else fatal("invalid -b option (%d)", i);
break; 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': case 'd':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL)) if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL))
DMAprimaryChannel = i; DMAprimaryChannel = i;
else fatal("invalid -d option (%d)", i); else fatal("invalid -d option (%d)", i);
break; break;
case 'e': case 'e':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL)) if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL))
DMAsecondaryChannel = i; DMAsecondaryChannel = i;
else fatal("invalid -e option (%d)", i); else fatal("invalid -e option (%d)", i);
@ -149,14 +167,14 @@ static void initOpts(int argc, char *argv[])
break; break;
case 'p': case 'p':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT)) if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT))
socketPort = i; socketPort = i;
else fatal("invalid -p option (%d)", i); else fatal("invalid -p option (%d)", i);
break; break;
case 's': case 's':
i = atoi(optarg); i = getNum(optarg, &err);
switch(i) switch(i)
{ {
@ -176,15 +194,15 @@ static void initOpts(int argc, char *argv[])
break; break;
case 't': case 't':
i = atoi(optarg); i = getNum(optarg, &err);
if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM)) if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
clockPeripheral = i; clockPeripheral = i;
else fatal("invalid -t option (%d)", i); else fatal("invalid -t option (%d)", i);
break; break;
case 'x': case 'x':
mask = strtoll(optarg, &endptr, 0); mask = getNum(optarg, &err);
if (!*endptr) if (!err)
{ {
updateMask = mask; updateMask = mask;
updateMaskSet = 1; updateMaskSet = 1;
@ -273,6 +291,8 @@ int main(int argc, char **argv)
if (updateMaskSet) gpioCfgPermissions(updateMask); if (updateMaskSet) gpioCfgPermissions(updateMask);
gpioCfgSetInternals(cfgInternals);
/* start library */ /* start library */
if (gpioInitialise()< 0) fatal("Can't initialise pigpio library"); if (gpioInitialise()< 0) fatal("Can't initialise pigpio library");

View File

@ -1747,6 +1747,14 @@ Loop Repeat 255 1 x y loop x + y*256 times
Delay 255 2 x y delay x + y*256 microseconds Delay 255 2 x y delay x + y*256 microseconds
.br .br
Loop Forever 255 3 loop forever
.br
.br
.br
If present Loop Forever must be the last entry in the chain.
.br .br

View File

@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/> For more information, please refer to <http://unlicense.org/>
*/ */
/* PIGPIOD_IF_VERSION 18 */ /* PIGPIOD_IF_VERSION 19 */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -80,6 +80,7 @@ static int gPigHandle = -1;
static int gPigNotify = -1; static int gPigNotify = -1;
static uint32_t gNotifyBits; static uint32_t gNotifyBits;
static uint32_t gLastLevel;
callback_t *gCallBackFirst = 0; callback_t *gCallBackFirst = 0;
callback_t *gCallBackLast = 0; callback_t *gCallBackLast = 0;
@ -220,8 +221,6 @@ static int pigpioOpenSocket(char *addr, char *port)
static void dispatch_notification(gpioReport_t *r) static void dispatch_notification(gpioReport_t *r)
{ {
static uint32_t lastLevel = 0;
callback_t *p; callback_t *p;
uint32_t changed; uint32_t changed;
int l, g; int l, g;
@ -233,9 +232,9 @@ static void dispatch_notification(gpioReport_t *r)
if (r->flags == 0) if (r->flags == 0)
{ {
changed = (r->level ^ lastLevel) & gNotifyBits; changed = (r->level ^ gLastLevel) & gNotifyBits;
lastLevel = r->level; gLastLevel = r->level;
p = gCallBackFirst; p = gCallBackFirst;
@ -487,6 +486,7 @@ void stop_thread(pthread_t *pth)
{ {
pthread_cancel(*pth); pthread_cancel(*pth);
pthread_join(*pth, NULL); pthread_join(*pth, NULL);
free(pth);
} }
} }
@ -507,6 +507,8 @@ int pigpio_start(char *addrStr, char *portStr)
if (gPigHandle < 0) return pigif_bad_noib; if (gPigHandle < 0) return pigif_bad_noib;
else else
{ {
gLastLevel = read_bank_1();
pthNotify = start_thread(pthNotifyThread, 0); pthNotify = start_thread(pthNotifyThread, 0);
if (pthNotify) if (pthNotify)
{ {
@ -1540,3 +1542,4 @@ int wait_for_edge(unsigned user_gpio, unsigned edge, double timeout)
return triggered; return triggered;
} }

View File

@ -30,7 +30,7 @@ For more information, please refer to <http://unlicense.org/>
#include "pigpio.h" #include "pigpio.h"
#define PIGPIOD_IF_VERSION 18 #define PIGPIOD_IF_VERSION 20
/*TEXT /*TEXT
@ -283,10 +283,6 @@ typedef void (*CBFuncEx_t)
typedef struct callback_s callback_t; typedef struct callback_s callback_t;
#define RISING_EDGE 0
#define FALLING_EDGE 1
#define EITHER_EDGE 2
/*F*/ /*F*/
double time_time(void); double time_time(void);
/*D /*D
@ -1211,6 +1207,9 @@ Name @ Cmd & Data @ Meaning
Loop Start @ 255 0 @ Identify start of a wave block Loop Start @ 255 0 @ Identify start of a wave block
Loop Repeat @ 255 1 x y @ loop x + y*256 times Loop Repeat @ 255 1 x y @ loop x + y*256 times
Delay @ 255 2 x y @ delay x + y*256 microseconds 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 The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters. 600 entries and 20 loop counters.

20
pigs.1
View File

@ -500,6 +500,20 @@ customiser.
.br .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 "\fBGDC u\fP - Get gpio PWM dutycycle"
.IP "" 4 .IP "" 4
@ -2584,6 +2598,8 @@ will be returned.
.br .br
The invert parameter \fBv\fP is 1 for inverted signal, 0 for normal. The invert parameter \fBv\fP is 1 for inverted signal, 0 for normal.
.br
\fBExample\fP \fBExample\fP
.br .br
@ -3174,9 +3190,13 @@ Name Cmd & Data Meaning
Loop Start 255 0 Identify start of a wave block Loop Start 255 0 Identify start of a wave block
Loop Repeat 255 1 x y loop x + y*256 times Loop Repeat 255 1 x y loop x + y*256 times
Delay 255 2 x y delay x + y*256 microseconds Delay 255 2 x y delay x + y*256 microseconds
Loop Forever 255 3 loop forever
.EE .EE
.br
If present Loop Forever must be the last entry in the chain.
.br .br
The code is currently dimensioned to support a chain with roughly The code is currently dimensioned to support a chain with roughly
600 entries and 20 loop counters. 600 entries and 20 loop counters.

View File

@ -3,7 +3,7 @@
from distutils.core import setup from distutils.core import setup
setup(name='pigpio', setup(name='pigpio',
version='1.21', version='1.22',
author='joan', author='joan',
author_email='joan@abyz.co.uk', author_email='joan@abyz.co.uk',
maintainer='joan', maintainer='joan',

View File

@ -592,18 +592,27 @@ def t9():
t9cb = pi.callback(GPIO) t9cb = pi.callback(GPIO)
old_exceptions = pigpio.exceptions
pigpio.exceptions = False
s = pi.store_script(script) s = pi.store_script(script)
# Ensure the script has finished initing. # Ensure the script has finished initing.
while True: while True:
time.sleep(0.1)
e, p = pi.script_status(s) e, p = pi.script_status(s)
if e != pigpio.PI_SCRIPT_INITING: if e != pigpio.PI_SCRIPT_INITING:
break break
time.sleep(0.1)
oc = t9cb.tally() oc = t9cb.tally()
pi.run_script(s, [99, GPIO]) 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 c = t9cb.tally() - oc
CHECK(9, 1, c, 100, 0, "store/run script") CHECK(9, 1, c, 100, 0, "store/run script")
@ -613,9 +622,9 @@ def t9():
e, p = pi.script_status(s) e, p = pi.script_status(s)
if e != pigpio.PI_SCRIPT_RUNNING: if e != pigpio.PI_SCRIPT_RUNNING:
break break
time.sleep(0.5)
c = t9cb.tally() - oc
time.sleep(0.1) time.sleep(0.1)
time.sleep(0.3)
c = t9cb.tally() - oc
CHECK(9, 2, c, 201, 0, "run script/script status") CHECK(9, 2, c, 201, 0, "run script/script status")
oc = t9cb.tally() oc = t9cb.tally()
@ -627,13 +636,15 @@ def t9():
if p[9] < 1900: if p[9] < 1900:
pi.stop_script(s) pi.stop_script(s)
time.sleep(0.1) time.sleep(0.1)
time.sleep(0.3)
c = t9cb.tally() - oc c = t9cb.tally() - oc
time.sleep(0.1) CHECK(9, 3, c, 110, 20, "run/stop script/script status")
CHECK(9, 3, c, 110, 10, "run/stop script/script status")
e = pi.delete_script(s) e = pi.delete_script(s)
CHECK(9, 4, e, 0, 0, "delete script") CHECK(9, 4, e, 0, 0, "delete script")
pigpio.exceptions = old_exceptions
def ta(): def ta():
print("Serial link tests.") print("Serial link tests.")

View File

@ -362,7 +362,7 @@ To the lascivious pleasing of a lute.\n\
oc = t5_count; oc = t5_count;
time_sleep(5.05); time_sleep(5.05);
c = t5_count - oc; c = t5_count - oc;
CHECK(5, 4, c, 50, 1, "callback"); CHECK(5, 4, c, 50, 2, "callback");
e = wave_tx_stop(); e = wave_tx_stop();
CHECK(5, 5, e, 0, 0, "wave tx stop"); CHECK(5, 5, e, 0, 0, "wave tx stop");

2
x_pigs
View File

@ -49,7 +49,7 @@ s=$(pigs bs2 0)
if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
s=$(pigs h) 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) s=$(pigs hwver)
if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi