mirror of https://github.com/joan2937/pigpio
V38
This commit is contained in:
parent
294eac0916
commit
f5912f84b4
12
Makefile
12
Makefile
|
@ -63,8 +63,8 @@ install: $(ALL)
|
|||
install -m 0755 -s pig2vcd /usr/local/bin
|
||||
install -m 0755 -s pigpiod /usr/local/bin
|
||||
install -m 0755 -s pigs /usr/local/bin
|
||||
python2 setup.py install
|
||||
python3 setup.py install
|
||||
if which python2; then python2 setup.py install; fi
|
||||
if which python3; then python3 setup.py install; fi
|
||||
install -m 0755 -d /usr/local/man/man1
|
||||
install -m 0644 *.1 /usr/local/man/man1
|
||||
install -m 0755 -d /usr/local/man/man3
|
||||
|
@ -79,12 +79,8 @@ uninstall:
|
|||
rm -f /usr/local/bin/pig2vcd
|
||||
rm -f /usr/local/bin/pigpiod
|
||||
rm -f /usr/local/bin/pigs
|
||||
echo removing python2 files
|
||||
python2 setup.py install --record /tmp/pigpio >/dev/null
|
||||
xargs rm -f < /tmp/pigpio >/dev/null
|
||||
echo removing python3 files
|
||||
python3 setup.py install --record /tmp/pigpio >/dev/null
|
||||
xargs rm -f < /tmp/pigpio >/dev/null
|
||||
if which python2; then python2 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
|
||||
if which python3; then python3 setup.py install --record /tmp/pigpio >/dev/null; xargs rm -f < /tmp/pigpio >/dev/null; fi
|
||||
rm -f /usr/local/man/man1/pig*.1
|
||||
rm -f /usr/local/man/man3/pig*.3
|
||||
ldconfig
|
||||
|
|
18
command.c
18
command.c
|
@ -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.
|
||||
|
|
15
pig2vcd.1
15
pig2vcd.1
|
@ -53,29 +53,22 @@ typedef struct
|
|||
.br
|
||||
|
||||
.br
|
||||
seqno starts at 0 each time the handle is opened and then increments
|
||||
by one for each report.
|
||||
seqno: starts at 0 each time the handle is opened and then increments by one for each report.
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
flags, if bit 5 is set then bits 0-4 of the flags indicate a gpio which
|
||||
has had a watchdog timeout.
|
||||
flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE. If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags indicate a gpio which has had a watchdog timeout; if bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive signal on the pipe/socket and is sent once a minute in the absence of other notification activity.
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
tick is the number of microseconds since system boot.
|
||||
tick: the number of microseconds since system boot. It wraps around after 1h12m.
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
level indicates the level of each gpio.
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
pig2vcd takes these notifications and outputs a text format VCD.
|
||||
level: indicates the level of each gpio. If bit 1<<x is set then gpio x is high. pig2vcd takes these notifications and outputs a text format VCD.
|
||||
|
||||
.br
|
||||
|
||||
|
|
273
pigpio.3
273
pigpio.3
|
@ -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
613
pigpio.c
|
@ -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, ¶m);
|
||||
if (gpioCfg.internals & PI_CFG_RT_PRIORITY)
|
||||
sched_setscheduler(0, SCHED_FIFO, ¶m);
|
||||
|
||||
initClock(1); /* initialise main clock */
|
||||
|
||||
|
@ -7350,12 +7459,17 @@ void gpioTerminate(void)
|
|||
if (dmaReg != MAP_FAILED) dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
|
||||
|
||||
#ifndef EMBEDDED_IN_VM
|
||||
if (gpioCfg.showStats)
|
||||
if (gpioCfg.internals & PI_CFG_STATS)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"\n#####################################################\n");
|
||||
fprintf(stderr,
|
||||
"If you didn't request stats please cut & paste the\n"
|
||||
"following and e-mail to pigpio@abyz.co.uk\n");
|
||||
|
||||
fprintf(stderr, "pigpio version=%d internals=%X\n",
|
||||
PIGPIO_VERSION, gpioCfg.internals);
|
||||
|
||||
fprintf(stderr,
|
||||
"micros=%d allocMode=%d dmaInitCbs=%d DMARestarts=%d\n",
|
||||
gpioCfg.clockMicros, gpioCfg.memAllocMode,
|
||||
|
@ -7366,18 +7480,21 @@ void gpioTerminate(void)
|
|||
gpioStats.numSamples, gpioStats.maxSamples,
|
||||
gpioStats.maxEmit, gpioStats.emitFrags);
|
||||
|
||||
fprintf(stderr, "cbTicks %d, cbCalls %u alertTicks %u\n",
|
||||
gpioStats.cbTicks, gpioStats.cbCalls, gpioStats.alertTicks);
|
||||
fprintf(stderr, "cbTicks %d, cbCalls %u\n",
|
||||
gpioStats.cbTicks, gpioStats.cbCalls);
|
||||
|
||||
fprintf(stderr, "pipe: good %u, short %u, would block %u\n",
|
||||
gpioStats.goodPipeWrite, gpioStats.shortPipeWrite,
|
||||
gpioStats.wouldBlockPipeWrite);
|
||||
|
||||
fprintf(stderr, "alertTicks %u, lateTicks %u, moreToDo %u\n",
|
||||
gpioStats.alertTicks, gpioStats.lateTicks, gpioStats.moreToDo);
|
||||
|
||||
for (i=0; i< TICKSLOTS; i++)
|
||||
fprintf(stderr, "%9u ", gpioStats.diffTick[i]);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr,
|
||||
"#####################################################\n");
|
||||
"\n#####################################################\n\n\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -8637,6 +8754,7 @@ int gpioWaveChain(char *buf, unsigned bufSize)
|
|||
"chain counters nested too deep (at %d)", i);
|
||||
|
||||
stk_pos[stk_lev++] = cb;
|
||||
|
||||
i += 2;
|
||||
}
|
||||
else if (cmd == 1) /* loop end */
|
||||
|
@ -8708,7 +8826,6 @@ int gpioWaveChain(char *buf, unsigned bufSize)
|
|||
|
||||
counters++;
|
||||
}
|
||||
loop = -1;
|
||||
}
|
||||
else if (cmd == 2) /* delay us */
|
||||
{
|
||||
|
@ -8751,6 +8868,34 @@ int gpioWaveChain(char *buf, unsigned bufSize)
|
|||
p->next = waveCbPOadr(chainGetCB(cb));
|
||||
}
|
||||
}
|
||||
else if (cmd == 3) /* repeat loop forever */
|
||||
{
|
||||
i += 2;
|
||||
|
||||
loop = 0;
|
||||
if (--stk_lev >= 0) loop = stk_pos[stk_lev];
|
||||
|
||||
if ((loop < 1) || (loop == cb))
|
||||
SOFT_ERROR(PI_BAD_CHAIN_LOOP,
|
||||
"empty chain loop (at %d)", i);
|
||||
|
||||
chaincb = chainGetCB(cb++);
|
||||
if (chaincb < 0)
|
||||
SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb);
|
||||
|
||||
if (i < bufSize)
|
||||
SOFT_ERROR(PI_BAD_FOREVER,
|
||||
"loop forever must be last command");
|
||||
|
||||
p = rawWaveCBAdr(chaincb);
|
||||
|
||||
/* dummy src and dest */
|
||||
p->info = NORMAL_DMA;
|
||||
p->src = (uint32_t) (&dmaOBus[0]->periphData);
|
||||
p->dst = (uint32_t) (&dmaOBus[0]->periphData);
|
||||
p->length = 4;
|
||||
p->next = waveCbPOadr(chainGetCB(loop));
|
||||
}
|
||||
else
|
||||
SOFT_ERROR(PI_BAD_CHAIN_CMD,
|
||||
"unknown chain command (255 %d)", cmd);
|
||||
|
@ -9495,6 +9640,212 @@ int gpioSetAlertFuncEx(unsigned gpio, gpioAlertFuncEx_t f, void *userdata)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void *pthISRThread(void *x)
|
||||
{
|
||||
gpioISR_t *isr = x;
|
||||
int fd;
|
||||
int retval;
|
||||
uint32_t tick;
|
||||
int level;
|
||||
uint32_t levels;
|
||||
struct pollfd pfd;
|
||||
char buf[64];
|
||||
|
||||
DBG(DBG_USER, "gpio=%d edge=%d timeout=%d f=%x u=%d data=%x",
|
||||
isr->gpio, isr->edge, isr->timeout, (uint32_t)isr->func,
|
||||
isr->ex, (uint32_t)isr->userdata);
|
||||
|
||||
sprintf(buf, "/sys/class/gpio/gpio%d/value", isr->gpio);
|
||||
|
||||
if ((fd = open(buf, O_RDONLY)) < 0)
|
||||
{
|
||||
DBG(DBG_ALWAYS, "gpio %d not exported", isr->gpio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pfd.fd = fd;
|
||||
|
||||
pfd.events = POLLPRI;
|
||||
|
||||
lseek(fd, 0, SEEK_SET); /* consume any prior interrupt */
|
||||
read(fd, buf, sizeof buf);
|
||||
|
||||
while (1)
|
||||
{
|
||||
retval = poll(&pfd, 1, isr->timeout); /* wait for interrupt */
|
||||
|
||||
tick = systReg[SYST_CLO];
|
||||
|
||||
levels = *(gpioReg + GPLEV0);
|
||||
|
||||
if (retval >= 0)
|
||||
{
|
||||
lseek(fd, 0, SEEK_SET); /* consume interrupt */
|
||||
read(fd, buf, sizeof buf);
|
||||
if (retval)
|
||||
{
|
||||
if (levels & (1<<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
211
pigpio.h
|
@ -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
|
||||
|
|
17
pigpio.py
17
pigpio.py
|
@ -264,7 +264,7 @@ import threading
|
|||
import os
|
||||
import atexit
|
||||
|
||||
VERSION = "1.21"
|
||||
VERSION = "1.22"
|
||||
|
||||
exceptions = True
|
||||
|
||||
|
@ -433,7 +433,7 @@ _PI_CMD_I2CZ =92
|
|||
|
||||
_PI_CMD_WVCHA=93
|
||||
|
||||
_PI_CMD_SLRI= 94
|
||||
_PI_CMD_SLRI =94
|
||||
|
||||
# pigpio error numbers
|
||||
|
||||
|
@ -899,7 +899,7 @@ class _callback_thread(threading.Thread):
|
|||
def run(self):
|
||||
"""Runs the notification thread."""
|
||||
|
||||
lastLevel = 0
|
||||
lastLevel = _pigpio_command(self.control, _PI_CMD_BR1, 0, 0)
|
||||
|
||||
MSG_SIZ = 12
|
||||
|
||||
|
@ -2014,10 +2014,13 @@ class pi():
|
|||
|
||||
The following command codes are supported:
|
||||
|
||||
Name @ Cmd & Data @ Meaning
|
||||
Loop Start @ 255 0 @ Identify start of a wave block
|
||||
Loop Repeat @ 255 1 x y @ loop x + y*256 times
|
||||
Delay @ 255 2 x y @ delay x + y*256 microseconds
|
||||
Name @ Cmd & Data @ Meaning
|
||||
Loop Start @ 255 0 @ Identify start of a wave block
|
||||
Loop Repeat @ 255 1 x y @ loop x + y*256 times
|
||||
Delay @ 255 2 x y @ delay x + y*256 microseconds
|
||||
Loop Forever @ 255 3 @ loop forever
|
||||
|
||||
If present Loop Forever must be the last entry in the chain.
|
||||
|
||||
The code is currently dimensioned to support a chain with
|
||||
roughly 600 entries and 20 loop counters.
|
||||
|
|
16
pigpiod.1
16
pigpiod.1
|
@ -39,6 +39,11 @@ gpio sample buffer in milliseconds
|
|||
100-10000
|
||||
default 120
|
||||
|
||||
.IP "\fB-c value\fP"
|
||||
library internal settings
|
||||
|
||||
default 0
|
||||
|
||||
.IP "\fB-d value\fP"
|
||||
primary DMA channel
|
||||
0-14
|
||||
|
@ -158,13 +163,18 @@ affect updateable gpios.
|
|||
.br
|
||||
|
||||
.br
|
||||
There are two special cases.
|
||||
There are several special cases.
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
The activity LED may be written (gpio 16 for type 1 and 2
|
||||
boards, gpio 47 for type 3 boards).
|
||||
The activity LED (green) may be written (gpio 16 for type 1 and 2
|
||||
boards, gpio 47 for type 3 boards)
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
The power LED (red) may be written on type 3 boards (gpio 35).
|
||||
|
||||
.br
|
||||
|
||||
|
|
52
pigpiod.c
52
pigpiod.c
|
@ -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");
|
||||
|
|
16
pigpiod_if.3
16
pigpiod_if.3
|
@ -1735,18 +1735,26 @@ The following command codes are supported:
|
|||
.br
|
||||
|
||||
.br
|
||||
Name Cmd & Data Meaning
|
||||
Name Cmd & Data Meaning
|
||||
|
||||
.br
|
||||
Loop Start 255 0 Identify start of a wave block
|
||||
Loop Start 255 0 Identify start of a wave block
|
||||
|
||||
.br
|
||||
Loop Repeat 255 1 x y loop x + y*256 times
|
||||
Loop Repeat 255 1 x y loop x + y*256 times
|
||||
|
||||
.br
|
||||
Delay 255 2 x y delay x + y*256 microseconds
|
||||
Delay 255 2 x y delay x + y*256 microseconds
|
||||
|
||||
.br
|
||||
Loop Forever 255 3 loop forever
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
|
||||
.br
|
||||
If present Loop Forever must be the last entry in the chain.
|
||||
|
||||
.br
|
||||
|
||||
|
|
13
pigpiod_if.c
13
pigpiod_if.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
17
pigpiod_if.h
17
pigpiod_if.h
|
@ -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
28
pigs.1
|
@ -500,6 +500,20 @@ customiser.
|
|||
|
||||
.br
|
||||
|
||||
.IP "\fBCGI \fP - Configuration get internals"
|
||||
.IP "" 4
|
||||
This command returns the value of the internal library
|
||||
configuration settings.
|
||||
|
||||
.br
|
||||
|
||||
.IP "\fBCSI v\fP - Configuration set internals"
|
||||
.IP "" 4
|
||||
This command sets the value of the internal library
|
||||
configuration settings to \fBv\fP.
|
||||
|
||||
.br
|
||||
|
||||
.IP "\fBGDC u\fP - Get gpio PWM dutycycle"
|
||||
.IP "" 4
|
||||
|
||||
|
@ -2584,6 +2598,8 @@ will be returned.
|
|||
.br
|
||||
The invert parameter \fBv\fP is 1 for inverted signal, 0 for normal.
|
||||
|
||||
.br
|
||||
|
||||
\fBExample\fP
|
||||
.br
|
||||
|
||||
|
@ -3170,13 +3186,17 @@ The following command codes are supported:
|
|||
.br
|
||||
|
||||
.EX
|
||||
Name Cmd & Data Meaning
|
||||
Loop Start 255 0 Identify start of a wave block
|
||||
Loop Repeat 255 1 x y loop x + y*256 times
|
||||
Delay 255 2 x y delay x + y*256 microseconds
|
||||
Name Cmd & Data Meaning
|
||||
Loop Start 255 0 Identify start of a wave block
|
||||
Loop Repeat 255 1 x y loop x + y*256 times
|
||||
Delay 255 2 x y delay x + y*256 microseconds
|
||||
Loop Forever 255 3 loop forever
|
||||
|
||||
.EE
|
||||
|
||||
.br
|
||||
If present Loop Forever must be the last entry in the chain.
|
||||
|
||||
.br
|
||||
The code is currently dimensioned to support a chain with roughly
|
||||
600 entries and 20 loop counters.
|
||||
|
|
2
setup.py
2
setup.py
|
@ -3,7 +3,7 @@
|
|||
from distutils.core import setup
|
||||
|
||||
setup(name='pigpio',
|
||||
version='1.21',
|
||||
version='1.22',
|
||||
author='joan',
|
||||
author_email='joan@abyz.co.uk',
|
||||
maintainer='joan',
|
||||
|
|
23
x_pigpio.py
23
x_pigpio.py
|
@ -592,18 +592,27 @@ def t9():
|
|||
|
||||
t9cb = pi.callback(GPIO)
|
||||
|
||||
old_exceptions = pigpio.exceptions
|
||||
|
||||
pigpio.exceptions = False
|
||||
|
||||
s = pi.store_script(script)
|
||||
|
||||
# Ensure the script has finished initing.
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
e, p = pi.script_status(s)
|
||||
if e != pigpio.PI_SCRIPT_INITING:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
|
||||
oc = t9cb.tally()
|
||||
pi.run_script(s, [99, GPIO])
|
||||
time.sleep(2)
|
||||
while True:
|
||||
e, p = pi.script_status(s)
|
||||
if e != pigpio.PI_SCRIPT_RUNNING:
|
||||
break
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.3)
|
||||
c = t9cb.tally() - oc
|
||||
CHECK(9, 1, c, 100, 0, "store/run script")
|
||||
|
||||
|
@ -613,9 +622,9 @@ def t9():
|
|||
e, p = pi.script_status(s)
|
||||
if e != pigpio.PI_SCRIPT_RUNNING:
|
||||
break
|
||||
time.sleep(0.5)
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.3)
|
||||
c = t9cb.tally() - oc
|
||||
time.sleep(0.1)
|
||||
CHECK(9, 2, c, 201, 0, "run script/script status")
|
||||
|
||||
oc = t9cb.tally()
|
||||
|
@ -627,13 +636,15 @@ def t9():
|
|||
if p[9] < 1900:
|
||||
pi.stop_script(s)
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.3)
|
||||
c = t9cb.tally() - oc
|
||||
time.sleep(0.1)
|
||||
CHECK(9, 3, c, 110, 10, "run/stop script/script status")
|
||||
CHECK(9, 3, c, 110, 20, "run/stop script/script status")
|
||||
|
||||
e = pi.delete_script(s)
|
||||
CHECK(9, 4, e, 0, 0, "delete script")
|
||||
|
||||
pigpio.exceptions = old_exceptions
|
||||
|
||||
def ta():
|
||||
print("Serial link tests.")
|
||||
|
||||
|
|
|
@ -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
2
x_pigs
|
@ -49,7 +49,7 @@ s=$(pigs bs2 0)
|
|||
if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
|
||||
|
||||
s=$(pigs h)
|
||||
if [[ ${#s} = 4321 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
|
||||
if [[ ${#s} = 4412 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
|
||||
|
||||
s=$(pigs hwver)
|
||||
if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi
|
||||
|
|
Loading…
Reference in New Issue