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 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

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>
@ -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.

View File

@ -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<<x is set then gpio x is high. pig2vcd takes these notifications and outputs a text format VCD.
.br

273
pigpio.3
View File

@ -1104,7 +1104,7 @@ void aFunction(int gpio, int level, uint32_t tick)
.br
.br
gpioSetAlertFunc(4, aFunction);
gpioSetAlertFunc(4F, aFunction);
.br
.EE
@ -1155,6 +1155,135 @@ registered per gpio.
.br
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 "" 4
This function requests a free notification handle.
@ -1905,18 +2034,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
@ -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
size is requested with \fBgpioCfgBufferSize\fP.
.IP "\fBint gpioCfgInternals(unsigned cfgWhat, int cfgVal)\fP"
.IP "\fBint gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal)\fP"
.IP "" 4
Used to tune internal settings.
@ -5080,6 +5217,26 @@ cfgWhat: see source code
.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 "" 4
This function is available for user customisation.
@ -5698,9 +5855,9 @@ The hardware clock frequency.
.br
.EX
#define PI_HW_CLK_MIN_FREQ 4689
PI_HW_CLK_MIN_FREQ 4689
.br
#define PI_HW_CLK_MAX_FREQ 250000000
PI_HW_CLK_MAX_FREQ 250000000
.br
.EE
@ -5734,9 +5891,9 @@ waveform.
.br
.EX
#define PI_MIN_WAVE_DATABITS 1
PI_MIN_WAVE_DATABITS 1
.br
#define PI_MAX_WAVE_DATABITS 32
PI_MAX_WAVE_DATABITS 32
.br
.EE
@ -5787,6 +5944,28 @@ The number may vary between 0 and range (default 255) where
.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
.br
@ -5964,6 +6143,34 @@ typedef void (*gpioGetSamplesFuncEx_t)
.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
.EX
@ -6551,7 +6758,7 @@ The hardware PWM dutycycle.
.br
.EX
#define PI_HW_PWM_RANGE 1000000
PI_HW_PWM_RANGE 1000000
.br
.EE
@ -6568,9 +6775,9 @@ The hardware PWM frequency.
.br
.EX
#define PI_HW_PWM_MIN_FREQ 1
PI_HW_PWM_MIN_FREQ 1
.br
#define PI_HW_PWM_MAX_FREQ 125000000
PI_HW_PWM_MAX_FREQ 125000000
.br
.EE
@ -6940,9 +7147,9 @@ to a waveform.
.br
.EX
#define PI_MIN_WAVE_HALFSTOPBITS 2
PI_MIN_WAVE_HALFSTOPBITS 2
.br
#define PI_MAX_WAVE_HALFSTOPBITS 8
PI_MAX_WAVE_HALFSTOPBITS 8
.br
.EE
@ -6959,7 +7166,12 @@ An array of characters.
.br
.IP "\fBtimeout\fP" 0
A gpio watchdog timeout in milliseconds.
A gpio level change timeout in milliseconds.
.br
.br
\fBgpioSetWatchdog\fP
.EX
PI_MIN_WDOG_TIMEOUT 0
@ -6971,6 +7183,19 @@ PI_MAX_WDOG_TIMEOUT 60000
.br
.br
\fBgpioSetISRFunc\fP and \fBgpioSetISRFuncEx\fP
.EX
<=0 cancel timeout
.br
>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

613
pigpio.c
View File

@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
/* 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)<<gpio)))
return 1;
else
return 0;
if (gpio <= PI_MAX_GPIO)
{
if (gpioMask & ((uint64_t)(1)<<gpio)) return 1;
else return 0;
}
return 1; /* will fail for bad gpio number */
}
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]);
break;
case PI_CMD_CF2:
/* a couple of extra precautions for untrusted code */
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];
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<SUPERCYCLE; i+=cycles)
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)
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;
case SIGPIPE:
case SIGCHLD:
case SIGWINCH:
DBG(DBG_USER, "signal %d ignored", signum);
break;
case SIGCHLD:
/* Used to notify threads of events */
break;
default:
DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
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)
@ -4966,7 +5007,7 @@ static void * pthAlertThread(void *x)
struct timespec req, rem;
uint32_t oldLevel, newLevel, level, reportedLevel;
uint32_t oldSlot, newSlot;
uint32_t tick, expected;
uint32_t tick, expected, nowTick;
int32_t diff;
int cycle, pulse;
int emit, seqno, emitted;
@ -4975,6 +5016,10 @@ static void * pthAlertThread(void *x)
int b, n, v;
int err;
int stopped;
int delayTicks;
uint32_t nextWakeTick;
int moreToDo;
int max_emits;
char fifo[32];
req.tv_sec = 0;
@ -4985,10 +5030,6 @@ static void * pthAlertThread(void *x)
reportedLevel = gpioReg[GPLEV0];
tick = systReg[SYST_CLO];
gpioStats.startTick = tick;
oldSlot = dmaCurrentSlot(dmaNowAtICB());
cycle = (oldSlot/PULSE_PER_CYCLE);
@ -4996,48 +5037,15 @@ static void * pthAlertThread(void *x)
stopped = 0;
moreToDo = 0;
tick = systReg[SYST_CLO];
nextWakeTick =
tick + alert_delays[(gpioCfg.internals>>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, &param);
if (gpioCfg.internals & PI_CFG_RT_PRIORITY)
sched_setscheduler(0, SCHED_FIFO, &param);
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<<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].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"

211
pigpio.h
View File

@ -31,7 +31,7 @@ For more information, please refer to <http://unlicense.org/>
#include <stdint.h>
#include <pthread.h>
#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

View File

@ -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.

View File

@ -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

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>
@ -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");

View File

@ -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

View File

@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
/* PIGPIOD_IF_VERSION 18 */
/* PIGPIOD_IF_VERSION 19 */
#include <stdio.h>
#include <stdlib.h>
@ -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;
}

View File

@ -30,7 +30,7 @@ For more information, please refer to <http://unlicense.org/>
#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.

28
pigs.1
View File

@ -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.

View File

@ -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',

View File

@ -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.")

View File

@ -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");

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
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