LIB = $(LIB1) $(LIB2)
-ALL = $(LIB) checklib pig2vcd pigpiod pigs
+ALL = $(LIB) x_pigpio x_pigpiod_if pig2vcd pigpiod pigs
-LL = -L. -lpigpio -lpthread -lrt
+LL1 = -L. -lpigpio -lpthread -lrt
+
+LL2 = -L. -lpigpiod_if -lpthread -lrt
all: $(ALL)
-checklib: checklib.o $(LIB1)
- $(CC) -o checklib checklib.c $(LL)
+x_pigpio: x_pigpio.o $(LIB1)
+ $(CC) -o x_pigpio x_pigpio.c $(LL1)
+
+x_pigpiod_if: x_pigpiod_if.o $(LIB2)
+ $(CC) -o x_pigpiod_if x_pigpiod_if.c $(LL2)
pigpiod: pigpiod.o $(LIB1)
- $(CC) -o pigpiod pigpiod.c $(LL)
+ $(CC) -o pigpiod pigpiod.c $(LL1)
pigs: pigs.o command.o
$(CC) -o pigs pigs.c command.c
rm -f *.o *.i *.s *~ $(ALL)
install: $(LIB)
+ sudo install -m 0755 -d /opt/pigpio/cgi
sudo install -m 0755 -d /usr/local/include
sudo install -m 0644 pigpio.h /usr/local/include
sudo install -m 0644 pigpiod_if.h /usr/local/include
# generated using gcc -MM *.c
-checklib.o: checklib.c pigpio.h
+x_pigpio.o: x_pigpio.c pigpio.h
+x_pigpiod_if.o: x_pigpiod_if.c
command.o: command.c pigpio.h command.h
pig2vcd.o: pig2vcd.c pigpio.h
pigpio.o: pigpio.c pigpio.h command.h
o the utility pig2vcd in /usr/local/bin
o the Python module pigpio.py
-TEST
+TEST (optional)
To test the library do
-sudo ./checklib
+sudo ./x_pigpio
+
+To text the pigpio daemon do
+
+sudo pigpiod
+
+./x_pigpiod_if # test the C I/F to the pigpio daemon
+./x_pigpio.py # test the Python I/F to the pigpio daemon
+./x_pigs # test the socket I/F to the pigpio daemon
+./x_pipe # test the pipe I/F to the pigpio daemon
EXAMPLE CODE
-checklib.c, pig2vcd.c, and pigpiod.c
-show examples of interfacing with the pigpio library.
+x_pigpio.c, pig2vcd.c, and pigpiod.c show examples of interfacing
+with the pigpio library.
-pigs.c and pigpio.py show examples of interfacing with the pigpiod daemon.
+pigs.c, pigpio.py, x_pigpiod_if.c, x_pigpio.py, x_pigs, and x_pipe
+show examples of interfacing with the pigpiod daemon.
DAEMON
where x.y is the Python version.
-If the pigpiod daemon is running you can test the Python module
-by entering the following commands.
-
-python
-
-import pigpio
-
-pigpio.start()
-
-print(pigpio.get_current_tick())
-
-print(hex(pigpio.read_bank_1()))
-
-pigpio.stop()
-
-help(pigpio)
-
-quit()
-
STOP DAEMON
To stop the pigpiod daemon
RUNNING ON NON Pi's
You can access the pigpiod daemon running on the Pi from any machine which
-can access it over the network. This access is via the socket interface.
+is connected to it over the network. This access is via the socket interface.
In particular this allows you to use the following on non-Pi's.
*/
/*
-This version is for pigpio version 12+
+This version is for pigpio version 13+
*/
#include <stdio.h>
7 cmd %x
8 MODES %d %c
9 PUD %d %c
-10 PROG %s
+10 PROC %s
11 WVAS %d %d %d %s
+12 PROCR %d [%d]*10
+13 WVAG %d %d %d [%d %d %d]*160
+
+
+20 cmd m(0-150)
+21 cmd v
+22 cmd L
+23 cmd
+24 cmd m1(0-150) m2(0-150)
+25 cmd p(0-9)
*/
cmdInfo_t cmdInfo[]=
{
- /* num str vfyt retv ext */
-
- {PI_CMD_BC1, "BC1", 7, 1, 0},
- {PI_CMD_BC2, "BC2", 7, 1, 0},
- {PI_CMD_BR1, "BR1", 1, 3, 0},
- {PI_CMD_BR2, "BR2", 1, 3, 0},
- {PI_CMD_BS1, "BS1", 7, 1, 0},
- {PI_CMD_BS2, "BS2", 7, 1, 0},
- {PI_CMD_HELP, "H", 6, 5, 0},
- {PI_CMD_HELP, "HELP", 6, 5, 0},
- {PI_CMD_HWVER, "HWVER", 1, 4, 0},
- {PI_CMD_MODEG, "MG" , 2, 2, 0},
- {PI_CMD_MODEG, "MODEG", 2, 2, 0},
- {PI_CMD_MODES, "M", 8, 0, 0},
- {PI_CMD_MODES, "MODES", 8, 0, 0},
- {PI_CMD_NB, "NB", 4, 0, 0},
- {PI_CMD_NC, "NC", 2, 0, 0},
- {PI_CMD_NO, "NO", 1, 2, 0},
- {PI_CMD_NP, "NP", 2, 0, 0},
- {PI_CMD_PFG, "PFG", 2, 2, 0},
- {PI_CMD_PFS, "PFS", 3, 2, 0},
- {PI_CMD_PIGPV, "PIGPV", 1, 4, 0},
- {PI_CMD_PRG, "PRG", 2, 2, 0},
- {PI_CMD_PROC, "PROC", 10, 2, 1},
- {PI_CMD_PROCD, "PROCD", 2, 2, 0},
- {PI_CMD_PROCR, "PROCR", 2, 2, 0},
- {PI_CMD_PROCS, "PROCS", 2, 2, 0},
- {PI_CMD_PRRG, "PRRG", 2, 2, 0},
- {PI_CMD_PRS, "PRS", 3, 2, 0},
- {PI_CMD_PUD, "PUD", 9, 0, 0},
- {PI_CMD_PWM, "P", 3, 0, 0},
- {PI_CMD_PWM, "PWM", 3, 0, 0},
- {PI_CMD_READ, "R", 2, 2, 0},
- {PI_CMD_READ, "READ", 2, 2, 0},
- {PI_CMD_SERVO, "S", 3, 0, 0},
- {PI_CMD_SERVO, "SERVO", 3, 0, 0},
- {PI_CMD_SLR, "SLR", 3, 6, 0},
- {PI_CMD_SLRC, "SLRC", 2, 2, 0},
- {PI_CMD_SLRO, "SLRO", 3, 2, 0},
- {PI_CMD_WDOG, "WDOG", 3, 0, 0},
- {PI_CMD_WRITE, "W", 3, 0, 0},
- {PI_CMD_WRITE, "WRITE", 3, 0, 0},
- {PI_CMD_TICK, "T", 1, 4, 0},
- {PI_CMD_TICK, "TICK", 1, 4, 0},
- {PI_CMD_TRIG, "TRIG", 5, 0, 1},
- {PI_CMD_WVAS, "WVAS", 11, 2, 3},
- {PI_CMD_WVBSY, "WVBSY", 1, 2, 0},
- {PI_CMD_WVCLR, "WVCLR", 1, 2, 0},
- {PI_CMD_WVGO, "WVGO" , 1, 2, 0},
- {PI_CMD_WVGOR, "WVGOR", 1, 2, 0},
- {PI_CMD_WVHLT, "WVHLT", 1, 2, 0},
- {PI_CMD_WVSC, "WVSC", 2, 2, 0},
- {PI_CMD_WVSM, "WVSM", 2, 2, 0},
- {PI_CMD_WVSP, "WVSP", 2, 2, 0},
+ /* num str vfyt retv */
+
+ {PI_CMD_BC1, "BC1", 7, 1},
+ {PI_CMD_BC2, "BC2", 7, 1},
+ {PI_CMD_BR1, "BR1", 1, 3},
+ {PI_CMD_BR2, "BR2", 1, 3},
+ {PI_CMD_BS1, "BS1", 7, 1},
+ {PI_CMD_BS2, "BS2", 7, 1},
+ {PI_CMD_HELP, "H", 6, 5},
+ {PI_CMD_HELP, "HELP", 6, 5},
+ {PI_CMD_HWVER, "HWVER", 1, 4},
+ {PI_CMD_MICRO, "MICRO", 21, 0},
+ {PI_CMD_MILLI, "MILLI", 21, 0},
+ {PI_CMD_MODEG, "MG" , 2, 2},
+ {PI_CMD_MODEG, "MODEG", 2, 2},
+ {PI_CMD_MODES, "M", 8, 0},
+ {PI_CMD_MODES, "MODES", 8, 0},
+ {PI_CMD_NB, "NB", 4, 0},
+ {PI_CMD_NC, "NC", 2, 0},
+ {PI_CMD_NO, "NO", 1, 2},
+ {PI_CMD_NP, "NP", 2, 0},
+ {PI_CMD_PFG, "PFG", 2, 2},
+ {PI_CMD_PFS, "PFS", 3, 2},
+ {PI_CMD_PIGPV, "PIGPV", 1, 4},
+ {PI_CMD_PRG, "PRG", 2, 2},
+ {PI_CMD_PROC, "PROC", 10, 2},
+ {PI_CMD_PROCD, "PROCD", 2, 2},
+ {PI_CMD_PROCP, "PROCP", 2, 7},
+ {PI_CMD_PROCR, "PROCR",12, 2},
+ {PI_CMD_PROCS, "PROCS", 2, 2},
+ {PI_CMD_PRRG, "PRRG", 2, 2},
+ {PI_CMD_PRS, "PRS", 3, 2},
+ {PI_CMD_PUD, "PUD", 9, 0},
+ {PI_CMD_PWM, "P", 3, 0},
+ {PI_CMD_PWM, "PWM", 3, 0},
+ {PI_CMD_READ, "R", 2, 2},
+ {PI_CMD_READ, "READ", 2, 2},
+ {PI_CMD_SERVO, "S", 3, 0},
+ {PI_CMD_SERVO, "SERVO", 3, 0},
+ {PI_CMD_SLR, "SLR", 3, 6},
+ {PI_CMD_SLRC, "SLRC", 2, 2},
+ {PI_CMD_SLRO, "SLRO", 3, 2},
+ {PI_CMD_TICK, "T", 1, 4},
+ {PI_CMD_TICK, "TICK", 1, 4},
+ {PI_CMD_TRIG, "TRIG", 5, 0},
+ {PI_CMD_WDOG, "WDOG", 3, 0},
+ {PI_CMD_WRITE, "W", 3, 0},
+ {PI_CMD_WRITE, "WRITE", 3, 0},
+ {PI_CMD_WVAG, "WVAG", 13, 2},
+ {PI_CMD_WVAS, "WVAS", 11, 2},
+ {PI_CMD_WVBSY, "WVBSY", 1, 2},
+ {PI_CMD_WVCLR, "WVCLR", 1, 2},
+ {PI_CMD_WVGO, "WVGO" , 1, 2},
+ {PI_CMD_WVGOR, "WVGOR", 1, 2},
+ {PI_CMD_WVHLT, "WVHLT", 1, 2},
+ {PI_CMD_WVSC, "WVSC", 2, 2},
+ {PI_CMD_WVSM, "WVSM", 2, 2},
+ {PI_CMD_WVSP, "WVSP", 2, 2},
+
+ {PI_CMD_ADDI , "ADDI" , 21, 0},
+ {PI_CMD_ADDV , "ADDV" , 20, 0},
+ {PI_CMD_ANDI , "ANDI" , 21, 0},
+ {PI_CMD_ANDV , "ANDV" , 20, 0},
+ {PI_CMD_CALL , "CALL" , 22, 0},
+ {PI_CMD_CMPI , "CMPI" , 21, 0},
+ {PI_CMD_CMPV , "CMPV" , 20, 0},
+ {PI_CMD_DCRA , "DCRA" , 23, 0},
+ {PI_CMD_DCRV , "DCRV" , 20, 0},
+ {PI_CMD_HALT , "HALT" , 23, 0},
+ {PI_CMD_INRA , "INRA" , 23, 0},
+ {PI_CMD_INRV , "INRV" , 20, 0},
+ {PI_CMD_JM , "JM" , 22, 0},
+ {PI_CMD_JMP , "JMP" , 22, 0},
+ {PI_CMD_JNZ , "JNZ" , 22, 0},
+ {PI_CMD_JP , "JP" , 22, 0},
+ {PI_CMD_JZ , "JZ" , 22, 0},
+ {PI_CMD_LABEL, "LABEL", 22, 0},
+ {PI_CMD_LDAI , "LDAI" , 21, 0},
+ {PI_CMD_LDAP , "LDAP" , 25, 0},
+ {PI_CMD_LDAV , "LDAV" , 20, 0},
+ {PI_CMD_LDPA , "LDPA" , 25, 0},
+ {PI_CMD_LDVA , "LDVA" , 20, 0},
+ {PI_CMD_LDVI , "LDVI" , 28, 0},
+ {PI_CMD_LDVV , "LDVV" , 24, 0},
+ {PI_CMD_ORI , "ORI" , 21, 0},
+ {PI_CMD_ORV , "ORV" , 20, 0},
+ {PI_CMD_POPA , "POPA" , 23, 0},
+ {PI_CMD_POPV , "POPV" , 20, 0},
+ {PI_CMD_PUSHA, "PUSHA", 23, 0},
+ {PI_CMD_PUSHV, "PUSHV", 20, 0},
+ {PI_CMD_RET , "RET" , 23, 0},
+ {PI_CMD_RAL , "RAL" , 21, 0},
+ {PI_CMD_RAR , "RAR" , 21, 0},
+ {PI_CMD_SUBI , "SUBI" , 21, 0},
+ {PI_CMD_SUBV , "SUBV" , 20, 0},
+ {PI_CMD_SWAPA, "SWAPA", 20, 0},
+ {PI_CMD_SWAPV, "SWAPV", 24, 0},
+ {PI_CMD_SYS , "SYS" , 27, 0},
+ {PI_CMD_WAITI, "WAITI", 21, 0},
+ {PI_CMD_WAITV, "WAITV", 20, 0},
+ {PI_CMD_XORI , "XORI" , 21, 0},
+ {PI_CMD_XORV , "XORV" , 20, 0},
+
};
char * cmdUsage = "\
-BC1 x Clear gpios x in bank 1.\n\
-BC2 x Clear gpios x in bank 2.\n\
-BR1 Read gpios bank 1.\n\
-BR2 Read gpios bank 2.\n\
-BS1 x Set gpios x in bank 1.\n\
-BS2 x Set gpios x in bank 2.\n\
-H Displays command help.\n\
-HELP Displays command help.\n\
-HWVER Return hardware version.\n\
-M g m Set gpio g to mode m.\n\
-MG g Get gpio g mode.\n\
-MODEG g Get gpio g mode.\n\
-MODES g m Set gpio g to mode m.\n\
-NB h x Start notifications on handle h with x.\n\
-NC h Close notification handle h.\n\
-NO Request notification handle.\n\
-NP h Pause notifications on handle h.\n\
-P u d Set PWM value for user gpio u to d.\n\
-PFG u Get PWM frequency for user gpio u.\n\
-PFS u d Set PWM frequency for user gpio u to d.\n\
-PIGPV Return pigpio version.\n\
-PRG u Get PWM range for user gpio u.\n\
-PROC t Store text t of script.\n\
-PROCD s Delete script s.\n\
-PROCR s Run script s.\n\
-PROCS s Stop script s.\n\
-PRRG u Get PWM real range for user gpio u.\n\
-PRS u d Set PWM range for user gpio u to d.\n\
-PUD g p Set gpio pull up/down for gpio g to p.\n\
-PWM u d Set PWM value for user gpio u to d.\n\
-R g Read gpio g.\n\
-READ g Read gpio g.\n\
-S u d Set servo value for user gpio u to d microseconds.\n\
-SERVO u d Set servo value for user gpio u to d microseconds.\n\
-SLR u d Read up to d bytes of serial data from user gpio u.\n\
-SLRC u Close user gpio u for serial data.\n\
-SLRO u b Open user gpio u for serial data at b baud.\n\
-T Return current tick.\n\
-TICK Return current tick.\n\
-TRIG u pl L Trigger level L for pl micros on user gpio u.\n\
-W g L Write level L to gpio g.\n\
-WDOG u d Set watchdog of d milliseconds on user gpio u.\n\
-WRITE g L Write level L to gpio g.\n\
-WVAS u b o t Wave add serial data t to user gpio u at b baud.\n\
-WVBSY Check if wave busy.\n\
-WVCLR Wave clear.\n\
-WVGO Wave transmit.\n\
-WVGOR Wave transmit repeatedly.\n\
-WVHLT Wave stop.\n\
-WVSC ws Wave get DMA control block stats.\n\
-WVSM ws Wave get micros stats.\n\
-WVSP ws Wave get pulses stats.\n\
-.\n\
+BC1 v Clear gpios defined by mask v in bank 1.\n\
+BC2 v Clear gpios defined by mask v in bank 2.\n\
+BR1 Read gpios bank 1.\n\
+BR2 Read gpios bank 2.\n\
+BS1 v Set gpios defined by mask v in bank 1.\n\
+BS2 v Set gpios defined by mask v in bank 2.\n\
+H Displays command help.\n\
+HELP Displays command help.\n\
+HWVER Return hardware version.\n\
+M g m Set gpio g to mode m.\n\
+MG g Get gpio g mode.\n\
+MICRO v Delay for v microseconds.\n\
+MILLI v Delay for v milliseconds.\n\
+MODEG g Get gpio g mode.\n\
+MODES g m Set gpio g to mode m.\n\
+NB h v Start notifications on handle h for gpios defined by mask v.\n\
+NC h Close notification handle h.\n\
+NO Request notification handle.\n\
+NP h Pause notifications on handle h.\n\
+P u v Set PWM value for user gpio u to d.\n\
+PFG u Get PWM frequency for user gpio u.\n\
+PFS u v Set PWM frequency for user gpio u to d.\n\
+PIGPV Return pigpio version.\n\
+PRG u Get PWM range for user gpio u.\n\
+PROC t Store text t of script.\n\
+PROCD s Delete script s.\n\
+PROCP s Get current status and parameter values for script s.\n\
+PROCR s pars Run script s with up to 10 optional parameters.\n\
+PROCS s Stop script s.\n\
+PRRG u Get PWM real range for user gpio u.\n\
+PRS u v Set PWM range for user gpio u to d.\n\
+PUD g p Set gpio pull up/down for gpio g to p.\n\
+PWM u v Set PWM value for user gpio u to d.\n\
+R g Read gpio g.\n\
+READ g Read gpio g.\n\
+S u v Set servo value for user gpio u to d microseconds.\n\
+SERVO u v Set servo value for user gpio u to d microseconds.\n\
+SLR u v Read up to d bytes of serial data from user gpio u.\n\
+SLRC u Close user gpio u for serial data.\n\
+SLRO u b Open user gpio u for serial data at b baud.\n\
+T Return current tick.\n\
+TICK Return current tick.\n\
+TRIG u pl L Trigger level L for pl micros on user gpio u.\n\
+W g L Write level L to gpio g.\n\
+WDOG u v Set watchdog of d milliseconds on user gpio u.\n\
+WRITE g L Write level L to gpio g.\n\
+WVAG pulses Wave add generic pulses.\n\
+WVAS u b o t Wave add serial data t to user gpio u at b baud.\n\
+WVBSY Check if wave busy.\n\
+WVCLR Wave clear.\n\
+WVGO Wave transmit.\n\
+WVGOR Wave transmit repeatedly.\n\
+WVHLT Wave stop.\n\
+WVSC ws Wave get DMA control block stats.\n\
+WVSM ws Wave get micros stats.\n\
+WVSP ws Wave get pulses stats.\n\
+\n\
b = baud rate.\n\
-d = decimal value.\n\
-g = gpio (0-53).\n\
+g = any gpio (0-53).\n\
h = handle (0-31).\n\
L = level (0-1).\n\
m = mode (RW540123).\n\
+mask = a bit mask where (1<<g) is set for each gpio g of interest.\n\
o = offset (0-).\n\
p = pud (ODU).\n\
+pars = 0 to 10 parameters for script.\n\
pl = pulse length (0-100).\n\
-s = script id.\n\
+pulses = 1 or more triplets of gpios on, gpios off, delay.\n\
+s = script id (0-31).\n\
t = text.\n\
u = user gpio (0-31).\n\
-x = hex value.\n\
+v = value.\n\
+ws = 0=now, 1=high, 2=max.\n\
+\n\
+Numbers may be entered as hex (prefix 0x), octal (prefix 0),\n\
+otherwise they are assumed to be decimal.\n\
";
typedef struct
{PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"},
{PI_GPIO_IN_USE , "gpio already in use"},
{PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"},
+ {PI_BAD_PARAM_NUM , "script parameter must be 0-9"},
+ {PI_DUP_LABEL , "script has duplicate label"},
+ {PI_TOO_MANY_LABELS , "script has too many labels"},
+ {PI_BAD_SCRIPT_CMD , "illegal script command"},
+ {PI_BAD_VAR_NUM , "script variable must be 0-149"},
+ {PI_NO_SCRIPT_ROOM , "no more room for scripts"},
+ {PI_NO_MEMORY , "can't allocate temporary memory"},
+ {PI_SOCK_READ_FAILED , "socket read failed"},
+ {PI_SOCK_WRIT_FAILED , "socket write failed"},
+ {PI_TOO_MANY_PARAM , "too many script parameters > 10"},
+ {PI_NOT_HALTED , "script already running or failed"},
+
};
static char * fmtMdeStr="RW540123";
static char * fmtPudStr="ODU";
-static int cmdMatch(char * str)
+static int cmdMatch(char *str)
{
int i;
return -1;
}
-int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext)
+static int getNum(char *str, unsigned *val, uint8_t *opt, int flags)
{
- char str[8];
- int f, valid, idx, val, p;
+ int f, n, v;
+
+ *opt = 0;
+
+ f = sscanf(str, " %i %n", &v, &n);
+
+ if (f == 1)
+ {
+ *val = v;
+ *opt = CMD_NUMERIC;
+ return n;
+ }
+
+ if (flags & PARSE_FLAGS_PARAMS)
+ {
+ f = sscanf(str, " p%i %n", &v, &n);
+
+ if (f == 1)
+ {
+ *val = v;
+ *opt = CMD_PARAM;
+ return n;
+ }
+ }
+
+ if (flags & PARSE_FLAGS_VARS)
+ {
+ f = sscanf(str, " v%i %n", &v, &n);
+
+ if (f == 1)
+ {
+ *val = v;
+ *opt = CMD_VAR;
+ return n;
+ }
+ }
+
+ return 0;
+}
+
+static char intCmdStr[32];
+
+char *cmdStr(void)
+{
+ return intCmdStr;
+}
+
+int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
+{
+ int f, valid, idx, val, pp, pars, n, n2, i;
char *ptr;
- char c, t;
+ char c;
+ int param[MAX_PARAM];
+
+ bzero(&ctl->opt, sizeof(ctl->opt));
- sscanf(buf, " %7s", str);
+ sscanf(buf+ctl->eaten, " %31s", intCmdStr);
- cmd->cmd = -1;
+ p[0] = -1;
- idx = cmdMatch(str);
+ idx = cmdMatch(intCmdStr);
if (idx < 0) return idx;
+ sscanf(buf+ctl->eaten, " %*31s %n", &pp);
+
+ ctl->eaten += pp;
+
valid = 0;
- cmd->cmd = cmdInfo[idx].cmd;
- cmd->p1 = 0;
- cmd->p2 = 0;
+ p[0] = cmdInfo[idx].cmd;
+ p[1] = 0;
+ p[2] = 0;
switch (cmdInfo[idx].vt)
{
- case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO
+ case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO
WVGOR WVHLT
*/
- f = sscanf(buf, " %7s %c", str, &t);
- if (f == 1) valid = 1;
+ valid = 1;
break;
- case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG
+ case 2: /* MODEG NC NP PFG PRG PROCD PROCS PRRG
SLRC READ WVSC WVSM WVSP
*/
- f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t);
- if (f == 2) valid = 1;
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ if (ctl->opt[0]) valid = 1;
break;
case 3: /* PFS PRS PWM SERVO SLR SLRO WDOG WRITE
*/
- f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t);
- if (f == 3) valid = 1;
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags);
+ if (ctl->opt[0] && ctl->opt[1]) valid = 1;
break;
case 4: /* NB
*/
- f = sscanf(buf, " %7s %d %x %c", str, &cmd->p1, &cmd->p2, &t);
- if (f == 3) valid = 1;
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags);
+ if (ctl->opt[0] && ctl->opt[1]) valid = 1;
break;
case 5: /* TRIG
*/
- f = sscanf(buf, " %7s %d %d %d %c",
- str, &cmd->p1, &cmd->p2, &ext[0].data, &t);
- if (f == 4)
- {
- ext[0].size = sizeof(unsigned);
- ext[0].ptr = &ext[0].data;
- valid = 1;
- }
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2], ctl->flags);
+ if (ctl->opt[0] && ctl->opt[1] && ctl->opt[2]) valid = 1;
break;
case 6: /* HELP
case 7: /* BC1 BC2 BS1 BS2
*/
- f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t);
- if (f == 2) valid = 1;
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ if (ctl->opt[0]) valid = 1;
break;
case 8: /* MODES
*/
- f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t);
- if (f == 3)
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ f = sscanf(buf+ctl->eaten, " %c %n", &c, &n);
+ if (ctl->opt[0] && (f >= 1))
{
+ ctl->eaten += n;
val = toupper(c);
ptr = strchr(fmtMdeStr, val);
if (ptr != NULL)
{
val = ptr - fmtMdeStr;
- cmd->p2 = val;
+ p[2] = val;
valid = 1;
}
}
case 9: /* PUD
*/
- f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t);
- if (f == 3)
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ f = sscanf(buf+ctl->eaten, " %c %n", &c, &n);
+ if (ctl->opt[0] && (f >= 1))
{
+ ctl->eaten += n;
val = toupper(c);
ptr = strchr(fmtPudStr, val);
if (ptr != NULL)
{
val = ptr - fmtPudStr;
- cmd->p2 = val;
+ p[2] = val;
valid = 1;
}
}
case 10: /* PROC
*/
- if ((argc == 0) || (argc == 3))
+ p[1] = strlen(buf+ctl->eaten);
+ v[1] = buf+ctl->eaten;
+ ctl->eaten += p[1];
+ valid = 1;
+ break;
+
+ case 11: /* WVAS
+ */
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags);
+ ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2], ctl->flags);
+
+ if (ctl->opt[0] && ctl->opt[1] && ctl->opt[2])
{
- if (argc == 3)
- {
- cmd->p1 = strlen(argv[2]);
- ext[0].ptr = argv[2];
- }
- else /* pipe i/f */
- {
- sscanf(buf, "%*s %n", &p);
- cmd->p1 = strlen(buf+p);
- ext[0].ptr = buf+p;
- }
- ext[0].size = cmd->p1;
+ p[4] = strlen(buf+ctl->eaten);
+ v[1] = buf+ctl->eaten;
+ ctl->eaten += p[4];
valid = 1;
}
break;
- case 11: /* WVAS
+ case 12: /* PROCR
+ */
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], 0);
+
+ pars = 0;
+
+ while (pars < 10)
+ {
+ ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], 0);
+ if (ctl->opt[1]) param[pars++] = p[2];
+ else break;
+ }
+
+ p[2] = pars;
+
+ v[1] = param;
+
+ if (ctl->opt[0]) valid = 1;
+ break;
+
+ case 13: /* WVAG
*/
- if ((argc == 0) || (argc == 6))
+ pars = 0;
+
+ while (pars < MAX_PARAM)
+ {
+ ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], 0);
+ if (ctl->opt[0]) param[pars++] = p[1];
+ else break;
+ }
+
+ p[1] = pars/3;
+
+ v[1] = param;
+
+ if (pars && ((pars%3)==0)) valid = 1;
+ break;
+
+ case 20: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
+ if ((f >= 1) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS))
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 21: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
+ if (f == 1)
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 22: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
+ if (f == 1)
{
- f = sscanf(buf, " %*s %d %d %d %n",
- &cmd->p1, &ext[0].data, &ext[1].data, &p);
- if (f == 3)
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 23: /*
+ */
+ valid = 1;
+ break;
+
+ case 24: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %d %n", &p[1], &p[2], &n);
+ if ((f >= 2) &&
+ (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS) &&
+ (p[2] >= 0) && (p[2] < MAX_SCRIPT_VARS))
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 25: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
+ if ((f >= 1) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_PARAMS))
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 26: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
+ if (f >= 1)
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
+
+ case 27: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %*s%n %n", &n, &n2);
+ if ((f >= 0) && n)
+ {
+ valid = 1;
+
+ for (i=0; i<n; i++)
{
- ext[0].size = sizeof(unsigned);
- ext[0].ptr = &ext[0].data;
- ext[1].size = sizeof(unsigned);
- ext[1].ptr = &ext[1].data;
+ c = buf[ctl->eaten+i];
- if (argc) /* pigs */
- {
- cmd->p2 = strlen(argv[5]);
- ext[2].ptr = argv[5];
- }
- else /* pipe i/f */
+ if ((!isalnum(c)) && (c != '_') && (c != '-'))
{
- cmd->p2 = strlen(buf+p);
- ext[2].ptr = buf+p;
+ valid = 0;
+ break;
}
+ }
- ext[2].size = cmd->p2;
- valid = 1;
+ if (valid)
+ {
+ p[1] = n;
+ ctl->opt[0] = CMD_NUMERIC;
+ v[1]=buf+ctl->eaten;
+ ctl->eaten += n2;
}
}
break;
+
+ case 28: /*
+ */
+ f = sscanf(buf+ctl->eaten, " %d %d %n", &p[1], &p[2], &n);
+ if ((f >= 2) && (p[1] >= 0) && (p[1] < MAX_SCRIPT_VARS))
+ {
+ ctl->eaten += n;
+ valid = 1;
+ }
+ break;
}
if (valid) return idx; else return -1;
}
return "unknown error";
}
+
*/
/*
-This version is for pigpio version 11+
+This version is for pigpio version 13+
*/
#ifndef COMMAND_H
#include "pigpio.h"
+#define MAX_PARAM 512
+
+#define PARSE_FLAGS_PARAMS 1
+#define PARSE_FLAGS_VARS 2
+
+#define CMD_NUMERIC 1
+#define CMD_PARAM 2
+#define CMD_VAR 3
+
typedef struct
{
- int cmd; /* command number */
- char * name; /* command name */
- int vt; /* command verification type */
- int rv; /* command return value type */
- int ext; /* command has extensions */
+ int flags;
+ int eaten;
+ uint8_t opt[8];
+} gpioCtlParse_t;
+
+typedef struct
+{
+ int cmd; /* command number */
+ char *name; /* command name */
+ int vt; /* command verification type */
+ int rv; /* command return value type */
} cmdInfo_t;
extern cmdInfo_t cmdInfo[];
-extern char * cmdUsage;
+extern char *cmdUsage;
+
+int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctlParse);
-int cmdParse
- (char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t * ext);
+char *cmdErrStr(int error);
-char * cmdErrStr(int error);
+char *cmdStr(void);
#endif
For more information, please refer to <http://unlicense.org/>
*/
-/* pigpio version 12 */
+/* pigpio version 13 */
#include <stdio.h>
#include <string.h>
} \
while (0)
-#define PERM_ERROR(format, arg...) \
- do \
- { \
- fprintf(stderr, "%s " format "\n", myTimeStamp(), ## arg); \
- } \
- while (0)
-
#define TIMER_ADD(a, b, result) \
do \
{ \
#define TIMED_DMA(x) (DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(x))
#define DBG_MIN_LEVEL 0
+#define DBG_ALWAYS 0
#define DBG_STARTUP 1
#define DBG_DMACBS 2
-#define DBG_USER 3
-#define DBG_INTERNAL 4
-#define DBG_SLOW_TICK 5
-#define DBG_FAST_TICK 6
-#define DBG_MAX_LEVEL 6
+#define DBG_SCRIPT 3
+#define DBG_USER 4
+#define DBG_INTERNAL 5
+#define DBG_SLOW_TICK 6
+#define DBG_FAST_TICK 7
+#define DBG_MAX_LEVEL 8
#define GPIO_UNDEFINED 0
-#define GPIO_INPUT 1
-#define GPIO_OUTPUT 2
-#define GPIO_PWM 3
-#define GPIO_SERVO 4
-#define GPIO_ALTERNATE 5
+#define GPIO_WRITE 1
+#define GPIO_PWM 2
+#define GPIO_SERVO 3
#define STACK_SIZE (256*1024)
#define CYCLES_PER_BLOCK 80
#define PULSE_PER_CYCLE 25
-#define PAGES_PER_BLOCK 53
+#define PAGES_PER_BLOCK 53
-#define CBS_PER_IPAGE 117
-#define LVS_PER_IPAGE 38
-#define OFF_PER_IPAGE 38
-#define TCK_PER_IPAGE 2
-#define ON_PER_IPAGE 2
+#define CBS_PER_IPAGE 117
+#define LVS_PER_IPAGE 38
+#define OFF_PER_IPAGE 38
+#define TCK_PER_IPAGE 2
+#define ON_PER_IPAGE 2
+#define PAD_PER_IPAGE 7
-#define CBS_PER_OPAGE 118
-#define ONOFF_PER_OPAGE 79
+#define CBS_PER_OPAGE 118
+#define OOL_PER_OPAGE 79
#define CBS_PER_CYCLE ((PULSE_PER_CYCLE*3)+2)
#define BLOCK_SIZE (PAGES_PER_BLOCK*PAGE_SIZE)
-#define DMA_PAGES (PAGES_PER_BLOCK * bufferBlocks)
+#define DMAI_PAGES (PAGES_PER_BLOCK * bufferBlocks)
-#define TICKSLOTS 50
+#define DMAO_PAGES (PAGES_PER_BLOCK * PI_WAVE_BLOCKS)
-#define PI_NOTIFY_SLOTS 32
+#define NUM_OOL (DMAO_PAGES * OOL_PER_OPAGE)
+
+#define TICKSLOTS 50
#define PI_NOTIFY_CLOSED 0
#define PI_NOTIFY_CLOSING 1
#define PI_WFRX_NONE 0
#define PI_WFRX_SERIAL 1
-#define PI_WF_MICROS 2
+#define PI_WF_MICROS 1
#define DATUMS 2000
#define MAX_EMITS (PIPE_BUF / sizeof(gpioReport_t))
#define SRX_BUF_SIZE 8192
-#define CMD_BUF_SIZE 2048
+#define CMD_BUF_SIZE 4096
/* --------------------------------------------------------------- */
uint32_t tick [TCK_PER_IPAGE];
uint32_t gpioOn [ON_PER_IPAGE];
uint32_t periphData;
- uint32_t pad[7];
+ uint32_t pad [PAD_PER_IPAGE];
} dmaIPage_t;
typedef struct
{
- dmaCbs_t cb [CBS_PER_OPAGE];
- uint32_t gpioOnOff [ONOFF_PER_OPAGE];
+ dmaCbs_t cb [CBS_PER_OPAGE];
+ uint32_t OOL [OOL_PER_OPAGE];
uint32_t periphData;
} dmaOPage_t;
uint32_t bits;
} gpioGetSamples_t;
+typedef struct
+{
+ uint32_t label;
+ int step;
+} gpioLabelStep_t;
+
typedef struct
{
callbk_t func;
pthread_t pthId;
} gpioTimer_t;
+#define PI_SCRIPT_FREE 0
+#define PI_SCRIPT_RESERVED 1
+#define PI_SCRIPT_IN_USE 2
+#define PI_SCRIPT_DYING 3
+
+#define PI_SCRIPT_HALT 0
+#define PI_SCRIPT_RUN 1
+#define PI_SCRIPT_DELETE 2
+
+#define PI_SCRIPT_SLOTS 32
+
+#define PI_SCRIPT_STACK_SIZE 256
+
+typedef struct
+{
+ uint32_t p[6];
+ uint8_t opt[8];
+} gpioInstr_t;
+
+typedef struct
+{
+ unsigned id;
+ unsigned state;
+ unsigned request;
+ unsigned run_state;
+ uint32_t waitBits;
+ uint32_t changedBits;
+ pthread_t *pthIdp;
+ pthread_mutex_t pthMutex;
+ pthread_cond_t pthCond;
+/*
+ +-----------+---------+---------+----------------+
+ | PARAMS... | VARS... | CMDS... | STRING AREA... |
+ +-----------+---------+---------+----------------+
+*/
+ int *param;
+ int *var;
+ gpioInstr_t *instr;
+ int instrs;
+ char *str_area;
+ int str_area_len;
+ int str_area_pos;
+} gpioScript_t;
+
+
typedef struct
{
uint16_t valid;
static uint64_t gpioMask;
-static gpioPulse_t wf[3][PI_WAVE_MAX_PULSES];
+static gpioWave_t wf[3][PI_WAVE_MAX_PULSES];
static int wfc[3]={0, 0, 0};
{
0, 0, PI_WAVE_MAX_MICROS,
0, 0, PI_WAVE_MAX_PULSES,
- 0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE)
+ 0, 0, (DMAO_PAGES * CBS_PER_OPAGE)
};
static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1];
-static volatile uint32_t alertBits = 0;
-static volatile uint32_t monitorBits = 0;
-static volatile uint32_t notifyBits = 0;
+static volatile uint32_t alertBits = 0;
+static volatile uint32_t monitorBits = 0;
+static volatile uint32_t notifyBits = 0;
+static volatile uint32_t scriptBits = 0;
static volatile int DMAstarted = 0;
static gpioNotify_t gpioNotify [PI_NOTIFY_SLOTS];
+static gpioScript_t gpioScript [PI_SCRIPT_SLOTS];
+
static gpioSignal_t gpioSignal [PI_MAX_SIGNUM+1];
static gpioTimer_t gpioTimer [PI_MAX_TIMER+1];
/* ======================================================================= */
-static void intNotifyBits(void);
+/* Internal prototypes.
+*/
+static void intNotifyBits(void);
+static void intScriptBits(void);
static int gpioNotifyOpenInBand(int fd);
+/* ======================================================================= */
+
static void myGpioSleep(int seconds, int micros)
{
struct timespec ts, rem;
while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem))
{
/* copy remaining time to ts */
- ts.tv_sec = rem.tv_sec;
- ts.tv_nsec = rem.tv_nsec;
+ ts = rem;
}
}
+/* ----------------------------------------------------------------------- */
+
static uint32_t myGpioDelay(uint32_t micros)
{
uint32_t start;
return (systReg[SYST_CLO] - start);
}
+/* ----------------------------------------------------------------------- */
+
static char * myTimeStamp()
{
static struct timeval last;
if (chmod(name, perm) < 0)
{
- DBG(DBG_MIN_LEVEL, "Can't set permissions (%d) for %s, %m", perm, name);
+ DBG(DBG_ALWAYS, "Can't set permissions (%d) for %s, %m", perm, name);
return;
}
}
/* ----------------------------------------------------------------------- */
-static void myDoCommand
- (cmdCmd_t *cmd, gpioExtent_t *iExt, gpioExtent_t *oExt)
+static int myParseScript(char *script, gpioScript_t *s)
+{
+ int idx, len, b, i, j, labels, resolved, pos;
+ int status;
+ uint32_t p[10];
+ void *v[10];
+ gpioInstr_t instr;
+ gpioCtlParse_t ctl;
+
+ ctl.flags = PARSE_FLAGS_PARAMS | PARSE_FLAGS_VARS;
+ ctl.eaten = 0;
+
+ status = 0;
+
+ gpioLabelStep_t label_step[MAX_SCRIPT_LABELS];
+
+ len = strlen(script);
+
+ /* calloc space for PARAMS, VARS, CMDS, and STRINGS */
+
+ b = (sizeof(int) * (MAX_SCRIPT_PARAMS + MAX_SCRIPT_VARS)) +
+ (sizeof(gpioInstr_t) * (len + 2) / 2) + len;
+
+ s->param = calloc(b, 1);
+
+ if (s->param == NULL) return -1;
+
+ s->var = s->param + MAX_SCRIPT_PARAMS;
+
+ s->instr = (gpioInstr_t *)(s->var + MAX_SCRIPT_VARS);
+
+ s->str_area = (char *)(s->instr + ((len + 2) / 2));
+
+ s->str_area_len = len;
+ s->str_area_pos = 0;
+
+ s->instrs = 0;
+
+ labels = 0;
+
+ idx = 0;
+
+ while (!status && ((ctl.eaten)<len) && (idx >= 0))
+ {
+ pos = ctl.eaten;
+
+ idx = cmdParse(script, p, v, &ctl);
+
+ memcpy(&instr.p, p, sizeof(instr.p));
+
+ if (idx >= 0)
+ {
+ switch (instr.p[0])
+ {
+ case PI_CMD_LABEL:
+
+ if (labels < MAX_SCRIPT_LABELS)
+ {
+ /* check label not already used */
+ for (j=0; j<labels; j++)
+ {
+ if (label_step[j].label == instr.p[1])
+ {
+ DBG(DBG_USER, "duplicate label: %s", script+pos);
+ status = PI_DUP_LABEL;
+ idx = -1;
+ }
+ }
+
+ label_step[labels].label = instr.p[1];
+ label_step[labels].step = s->instrs;
+ labels++;
+ }
+ else
+ {
+ DBG(DBG_USER, "too many labels: %s", script+pos);
+ status = PI_TOO_MANY_LABELS;
+ idx = -1;
+ }
+
+ break;
+
+ case PI_CMD_SYS:
+
+ strncpy(s->str_area+s->str_area_pos, v[1], p[1]);
+ s->str_area[s->str_area_pos+p[1]] = 0;
+ instr.p[1] = (int) s->str_area+s->str_area_pos;
+ s->str_area_pos += (p[1] + 1);
+
+ break;
+
+ case PI_CMD_TRIG:
+ break;
+
+ }
+ }
+ else
+ {
+ DBG(DBG_USER, "invalid command: %s", script+pos);
+ status = PI_BAD_SCRIPT_CMD;
+ }
+
+ if (idx >= 0)
+ {
+ if (instr.p[0] != PI_CMD_LABEL)
+ {
+ memcpy(instr.opt, &ctl.opt, sizeof(instr.opt));
+ s->instr[s->instrs++] = instr;
+ }
+ }
+ }
+
+ DBG(DBG_SCRIPT, "status=%d eaten=%d len=%d idx=%d",
+ status, ctl.eaten, len, idx);
+
+ for (i=0; i<s->instrs; i++)
+ {
+ instr = s->instr[i];
+
+ /* resolve jumps */
+
+ if ((instr.p[0] == PI_CMD_JMP) || (instr.p[0] == PI_CMD_CALL) ||
+ (instr.p[0] == PI_CMD_JZ) || (instr.p[0] == PI_CMD_JNZ) ||
+ (instr.p[0] == PI_CMD_JM) || (instr.p[0] == PI_CMD_JP))
+ {
+ resolved = 0;
+
+ for (j=0; j<labels; j++)
+ {
+ if (instr.p[1] == label_step[j].label)
+ {
+ s->instr[i].p[1] = label_step[j].step;
+ resolved = 1;
+ break;
+ }
+ }
+
+ if (!resolved)
+ {
+ DBG(DBG_USER, "can't resolve label %d\n", instr.p[1]);
+ status = PI_BAD_SCRIPT;
+ }
+ }
+ }
+ return status;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
{
- int p1, p2, res, i;
- uint32_t mask, tmp;
+ int res, i, tmp;
+ uint32_t mask;
gpioPulse_t *pulse;
int masked;
- p1 = cmd->p1;
- p2 = cmd->p2;
- res = cmd->res;
+ res = 0;
- switch (cmd->cmd)
+ switch (p[0])
{
case PI_CMD_BC1:
mask = gpioMask;
- res = gpioWrite_Bits_0_31_Clear(p1&mask);
+ res = gpioWrite_Bits_0_31_Clear(p[1]&mask);
- if ((mask | p1) != mask)
+ if ((mask | p[1]) != mask)
{
- PERM_ERROR(
+ DBG(DBG_USER,
"gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
- p1, mask);
+ p[1], mask);
res = PI_SOME_PERMITTED;
}
break;
case PI_CMD_BC2:
mask = gpioMask>>32;
- res = gpioWrite_Bits_32_53_Clear(p1&mask);
+ res = gpioWrite_Bits_32_53_Clear(p[1]&mask);
- if ((mask | p1) != mask)
+ if ((mask | p[1]) != mask)
{
- PERM_ERROR(
+ DBG(DBG_USER,
"gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
- p1, mask);
+ p[1], mask);
res = PI_SOME_PERMITTED;
}
break;
case PI_CMD_BS1:
mask = gpioMask;
- res = gpioWrite_Bits_0_31_Set(p1&mask);
+ res = gpioWrite_Bits_0_31_Set(p[1]&mask);
- if ((mask | p1) != mask)
+ if ((mask | p[1]) != mask)
{
- PERM_ERROR(
+ DBG(DBG_USER,
"gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
- p1, mask);
+ p[1], mask);
res = PI_SOME_PERMITTED;
}
break;
case PI_CMD_BS2:
mask = gpioMask>>32;
- res = gpioWrite_Bits_32_53_Set(p1&mask);
+ res = gpioWrite_Bits_32_53_Set(p[1]&mask);
- if ((mask | p1) != mask)
+ if ((mask | p[1]) != mask)
{
- PERM_ERROR(
+ DBG(DBG_USER,
"gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
- p1, mask);
+ p[1], mask);
res = PI_SOME_PERMITTED;
}
break;
case PI_CMD_HWVER: res = gpioHardwareRevision(); break;
- case PI_CMD_MODEG: res = gpioGetMode(p1); break;
+ case PI_CMD_MICRO: myGpioDelay(p[1]); break;
+
+ case PI_CMD_MILLI: myGpioDelay(p[1] * 1000); break;
+
+ case PI_CMD_MODEG: res = gpioGetMode(p[1]); break;
case PI_CMD_MODES:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetMode(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetMode(p[1], p[2]);
else
{
- PERM_ERROR("gpioSetMode: gpio %d, no permission to update", p1);
+ DBG(DBG_USER, "gpioSetMode: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
- case PI_CMD_NB: res = gpioNotifyBegin(p1, p2); break;
+ case PI_CMD_NB: res = gpioNotifyBegin(p[1], p[2]); break;
- case PI_CMD_NC: res = gpioNotifyClose(p1); break;
+ case PI_CMD_NC: res = gpioNotifyClose(p[1]); break;
case PI_CMD_NO: res = gpioNotifyOpen(); break;
- case PI_CMD_NP: res = gpioNotifyPause(p1); break;
+ case PI_CMD_NP: res = gpioNotifyPause(p[1]); break;
- case PI_CMD_PFG: res = gpioGetPWMfrequency(p1); break;
+ case PI_CMD_PFG: res = gpioGetPWMfrequency(p[1]); break;
case PI_CMD_PFS:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMfrequency(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPWMfrequency(p[1], p[2]);
else
{
- PERM_ERROR(
- "gpioSetPWMfrequency: gpio %d, no permission to update", p1);
+ DBG(DBG_USER,
+ "gpioSetPWMfrequency: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
case PI_CMD_PIGPV: res = gpioVersion(); break;
- case PI_CMD_PRG: res = gpioGetPWMrange(p1); break;
+ case PI_CMD_PRG: res = gpioGetPWMrange(p[1]); break;
case PI_CMD_PROC:
- res = gpioStoreScript(iExt[0].ptr);
+ res = gpioStoreScript((char *)p[2]);
break;
- case PI_CMD_PROCD: res = gpioDeleteScript(p1); break;
+ case PI_CMD_PROCD: res = gpioDeleteScript(p[1]); break;
- case PI_CMD_PROCR: res = gpioRunScript(p1); break;
+ case PI_CMD_PROCP: res = gpioScriptStatus(p[1], oExt[0].ptr); break;
+
+ case PI_CMD_PROCR:
+ res = gpioRunScript(p[1], p[2], (uint32_t *)p[3]);
+ break;
- case PI_CMD_PROCS: res = gpioStopScript(p1); break;
+ case PI_CMD_PROCS: res = gpioStopScript(p[1]); break;
- case PI_CMD_PRRG: res = gpioGetPWMrealRange(p1); break;
+ case PI_CMD_PRRG: res = gpioGetPWMrealRange(p[1]); break;
case PI_CMD_PRS:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMrange(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPWMrange(p[1], p[2]);
else
{
- PERM_ERROR(
- "gpioSetPWMrange: gpio %d, no permission to update", p1);
+ DBG(DBG_USER,
+ "gpioSetPWMrange: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
case PI_CMD_PUD:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPullUpDown(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPullUpDown(p[1], p[2]);
else
{
- PERM_ERROR(
- "gpioSetPullUpDown: gpio %d, no permission to update", p1);
+ DBG(DBG_USER,
+ "gpioSetPullUpDown: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
case PI_CMD_PWM:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioPWM(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioPWM(p[1], p[2]);
else
{
- PERM_ERROR("gpioPWM: gpio %d, no permission to update", p1);
+ DBG(DBG_USER, "gpioPWM: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
- case PI_CMD_READ: res = gpioRead(p1); break;
+ case PI_CMD_READ: res = gpioRead(p[1]); break;
case PI_CMD_SERVO:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioServo(p[1], p[2]);
else
{
- PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
+ DBG(DBG_USER, "gpioServo: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
- case PI_CMD_SLRO: res = gpioSerialReadOpen(p1, p2); break;
+ case PI_CMD_SLRO: res = gpioSerialReadOpen(p[1], p[2]); break;
case PI_CMD_SLR:
- if (p2 < oExt[0].size) oExt[0].size = p2;
- res = gpioSerialRead(p1, oExt[0].ptr, oExt[0].size);
+ if (p[2] < oExt[0].size) oExt[0].size = p[2];
+ res = gpioSerialRead(p[1], oExt[0].ptr, oExt[0].size);
break;
- case PI_CMD_SLRC: res = gpioSerialReadClose(p1); break;
+ case PI_CMD_SLRC: res = gpioSerialReadClose(p[1]); break;
case PI_CMD_TICK: res = gpioTick(); break;
case PI_CMD_TRIG:
- if (gpioMask & (uint64_t)(1<<p1))
- res = gpioTrigger(p1, p2, *(int *) (iExt[0].ptr));
+ if (gpioMask & (uint64_t)(1<<p[1]))
+ res = gpioTrigger(p[1], p[2], p[3]);
else
{
- PERM_ERROR("gpioTrigger: gpio %d, no permission to update", p1);
+ DBG(DBG_USER, "gpioTrigger: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
- case PI_CMD_WDOG: res = gpioSetWatchdog(p1, p2); break;
+ case PI_CMD_WDOG: res = gpioSetWatchdog(p[1], p[2]); break;
case PI_CMD_WRITE:
- if (gpioMask & (uint64_t)(1<<p1)) res = gpioWrite(p1, p2);
+ if (gpioMask & (uint64_t)(1<<p[1])) res = gpioWrite(p[1], p[2]);
else
{
- PERM_ERROR("gpioWrite: gpio %d, no permission to update", p1);
+ DBG(DBG_USER, "gpioWrite: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
/* need to mask off any non permitted gpios */
mask = gpioMask;
- pulse = iExt[0].ptr;
+ pulse = (gpioPulse_t *)p[2];
masked = 0;
- for (i=0; i<p1; i++)
+ for (i=0; i<p[1]; i++)
{
tmp = pulse[i].gpioOn & mask;
if (tmp != pulse[i].gpioOn)
pulse[i].gpioOff = tmp;
masked = 1;
}
+ DBG(DBG_SCRIPT, "on=%X off=%X delay=%d",
+ pulse[i].gpioOn, pulse[i].gpioOff, pulse[i].usDelay);
}
- res = gpioWaveAddGeneric(p1, pulse);
+ res = gpioWaveAddGeneric(p[1], pulse);
/* report permission error unless another error occurred */
if (masked && (res >= 0)) res = PI_SOME_PERMITTED;
break;
case PI_CMD_WVAS:
- if (gpioMask & (uint64_t)(1<<p1))
- res = gpioWaveAddSerial
- (p1,
- *(int *)(iExt[0].ptr),
- *(int *)(iExt[1].ptr),
- p2,
- iExt[2].ptr);
+ if (gpioMask & (uint64_t)(1<<p[1]))
+ res = gpioWaveAddSerial(p[1], p[2], p[3], p[4], (char *)p[5]);
else
{
- PERM_ERROR
- ("gpioWaveAddSerial: gpio %d, no permission to update", p1);
+ DBG(
+ DBG_USER,
+ "gpioWaveAddSerial: gpio %d, no permission to update", p[1]);
res = PI_NOT_PERMITTED;
}
break;
case PI_CMD_WVHLT: res = gpioWaveTxStop(); break;
case PI_CMD_WVSC:
- switch(p1)
+ switch(p[1])
{
case 0: res = gpioWaveGetCbs(); break;
case 1: res = gpioWaveGetHighCbs(); break;
break;
case PI_CMD_WVSM:
- switch(p1)
+ switch(p[1])
{
case 0: res = gpioWaveGetMicros(); break;
case 1: res = gpioWaveGetHighMicros(); break;
break;
case PI_CMD_WVSP:
- switch(p1)
+ switch(p[1])
{
case 0: res = gpioWaveGetPulses(); break;
case 1: res = gpioWaveGetHighPulses(); break;
}
break;
}
- cmd->res = res;
+ return (res);
}
/* ----------------------------------------------------------------------- */
switchGpioOff = 0;
- realRange = pwmRealRange[gpioInfo[gpio].freqIdx];
- cycles = pwmCycles [gpioInfo[gpio].freqIdx];
+ realRange = pwmRealRange[clkCfg[gpioCfg.clockMicros].servoIdx];
+ cycles = pwmCycles [clkCfg[gpioCfg.clockMicros].servoIdx];
newOff = (newVal * realRange)/20000;
oldOff = (oldVal * realRange)/20000;
return (uint32_t) &dmaOPhys[page]->cb[slot];
}
+/* ----------------------------------------------------------------------- */
+
+static void waveOOLPageSlot(int pos, int *page, int *slot)
+{
+ *page = pos/OOL_PER_OPAGE;
+ *slot = pos%OOL_PER_OPAGE;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static void waveSetOOL(int pos, uint32_t OOL)
+{
+ int page, slot;
+
+ waveOOLPageSlot(pos, &page, &slot);
+
+ dmaOVirt[page]->OOL[slot] = OOL;
+}
/* ----------------------------------------------------------------------- */
-static uint32_t waveOnOffPOadr(int pos)
+static uint32_t waveOOLPOadr(int pos)
{
int page, slot;
- page = pos/ONOFF_PER_OPAGE;
- slot = pos%ONOFF_PER_OPAGE;
+ waveOOLPageSlot(pos, &page, &slot);
- return (uint32_t) &dmaOPhys[page]->gpioOnOff[slot];
+ return (uint32_t) &dmaOPhys[page]->OOL[slot];
}
/* ----------------------------------------------------------------------- */
-void waveBitDelay(unsigned baud, unsigned * bitDelay)
+static void waveBitDelay(unsigned baud, unsigned * bitDelay)
{
unsigned fullBit, halfBit, s, e, d, m, i, err;
bitDelay[9] = (e-s)/100;
}
-/* ----------------------------------------------------------------------- */
-
-void gpioWaveDump(void)
-{
- int i;
-
- unsigned numPulses, t;
-
- gpioPulse_t * pulses;
-
- numPulses = wfc[wfcur];
- pulses = wf [wfcur];
-
- t = 0;
-
- for (i=0; i<numPulses; i++)
- {
- printf("%10u %08X %08X %10u\n",
- t, pulses[i].gpioOn, pulses[i].gpioOff, pulses[i].usDelay);
- t += pulses[i].usDelay;
- }
-}
-
-
-
/* ----------------------------------------------------------------------- */
static int wave2Cbs(unsigned mode)
{
- int cb=0, onoff=0;
+ int cb=0, onoff=0, level=NUM_OOL;
- dmaCbs_t * p=NULL;
+ dmaCbs_t *p=NULL;
unsigned i, half, repeatCb;
- unsigned numPulses;
+ unsigned numWaves;
- gpioPulse_t * pulses;
+ gpioWave_t * waves;
- numPulses = wfc[wfcur];
- pulses = wf [wfcur];
+ numWaves = wfc[wfcur];
+ waves = wf [wfcur];
half = PI_WF_MICROS/2;
repeatCb = cb;
- for (i=0; i<numPulses; i++)
+ for (i=0; i<numWaves; i++)
{
- if (pulses[i].gpioOn)
+ if (waves[i].gpioOn)
{
- dmaOVirt[onoff/ONOFF_PER_OPAGE]->gpioOnOff[onoff%ONOFF_PER_OPAGE] =
- pulses[i].gpioOn;
+ waveSetOOL(onoff, waves[i].gpioOn);
p = waveCbVOadr(cb++);
p->info = NORMAL_DMA;
- p->src = waveOnOffPOadr(onoff++) | DMA_BUS_ADR;
+ p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR;
p->dst = ((GPIO_BASE + (GPSET0*4)) & 0x00ffffff) | 0x7e000000;
p->length = 4;
p->next = waveCbPOadr(cb) | DMA_BUS_ADR;
}
- if (pulses[i].gpioOff)
+ if (waves[i].gpioOff)
{
- dmaOVirt[onoff/ONOFF_PER_OPAGE]->gpioOnOff[onoff%ONOFF_PER_OPAGE] =
- pulses[i].gpioOff;
+ waveSetOOL(onoff, waves[i].gpioOff);
p = waveCbVOadr(cb++);
p->info = NORMAL_DMA;
- p->src = waveOnOffPOadr(onoff++) | DMA_BUS_ADR;
+ p->src = waveOOLPOadr(onoff++) | DMA_BUS_ADR;
p->dst = ((GPIO_BASE + (GPCLR0*4)) & 0x00ffffff) | 0x7e000000;
p->length = 4;
p->next = waveCbPOadr(cb) | DMA_BUS_ADR;
}
- if (pulses[i].usDelay)
+ if (waves[i].flags & WAVE_FLAG_READ)
+ {
+ p = waveCbVOadr(cb++);
+
+ p->info = NORMAL_DMA;
+ p->src = ((GPIO_BASE + (GPLEV0*4)) & 0x00ffffff) | 0x7e000000;
+ p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR;
+ p->length = 4;
+ p->next = waveCbPOadr(cb) | DMA_BUS_ADR;
+ }
+
+ if (waves[i].flags & WAVE_FLAG_TICK)
+ {
+ p = waveCbVOadr(cb++);
+
+ p->info = NORMAL_DMA;
+ p->src = ((SYST_BASE + (SYST_CLO*4)) & 0x00ffffff) | 0x7e000000;
+ p->dst = waveOOLPOadr(--level) | DMA_BUS_ADR;
+ p->length = 4;
+ p->next = waveCbPOadr(cb) | DMA_BUS_ADR;
+ }
+
+ if (waves[i].usDelay)
{
p = waveCbVOadr(cb++);
}
p->src = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR;
- p->length = 4 * ((pulses[i].usDelay+half)/PI_WF_MICROS);
+ p->length = 4 * ((waves[i].usDelay+half)/PI_WF_MICROS);
p->next = waveCbPOadr(cb) | DMA_BUS_ADR;
}
}
/* ----------------------------------------------------------------------- */
-static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
+static int waveMerge(unsigned numIn1, gpioWave_t *in1)
{
- unsigned inPos1=0, inPos2=0, outPos=0;
+ unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_OOL;
unsigned cbs=0;
uint32_t tNow, tNext1, tNext2, tDelay;
- gpioPulse_t * in2, * out;
+ gpioWave_t *in2, *out;
numIn2 = wfc[wfcur];
in2 = wf[wfcur];
out[outPos].gpioOn = in1[inPos1].gpioOn;
out[outPos].gpioOff = in1[inPos1].gpioOff;
+ out[outPos].flags = in1[inPos1].flags;
tNext1 = tNow + in1[inPos1].usDelay; ++inPos1;
}
out[outPos].gpioOn = in2[inPos2].gpioOn;
out[outPos].gpioOff = in2[inPos2].gpioOff;
+ out[outPos].flags = in2[inPos2].flags;
tNext2 = tNow + in2[inPos2].usDelay; ++inPos2;
}
out[outPos].gpioOn = in1[inPos1].gpioOn | in2[inPos2].gpioOn;
out[outPos].gpioOff = in1[inPos1].gpioOff | in2[inPos2].gpioOff;
+ out[outPos].flags = in1[inPos1].flags | in2[inPos2].flags;
tNext1 = tNow + in1[inPos1].usDelay; ++inPos1;
tNext2 = tNow + in2[inPos2].usDelay; ++inPos2;
if (out[outPos].gpioOff) cbs++; /* one cb if gpio off */
+ if (out[outPos].flags & WAVE_FLAG_READ)
+ {
+ cbs++; /* one cb if read */
+ --level;
+ }
+
+ if (out[outPos].flags & WAVE_FLAG_TICK)
+ {
+ cbs++; /* one cb if tick */
+ --level;
+ }
+
outPos++;
if (inPos1 >= numIn1) tNext1 = -1;
}
- if (outPos < numOut)
+ if ((outPos < numOut) && (outPos < level))
{
wfStats.micros = tNow;
/* ----------------------------------------------------------------------- */
-static unsigned dmaCurrentCb(void)
+static unsigned dmaNowAtICB(void)
{
unsigned cb;
static unsigned lastPage=0;
return (page*CBS_PER_IPAGE) + cb;
}
- if (page++ >= DMA_PAGES) page=0;
+ if (page++ >= DMAI_PAGES) page=0;
+
+ if (page == lastPage) break;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+unsigned dmaNowAtOCB(void)
+{
+ unsigned cb;
+ static unsigned lastPage=0;
+ unsigned page;
+ uint32_t cbAddr;
+
+ cbAddr = dmaOut[DMA_CONBLK_AD];
+
+ if (!cbAddr) return -1;
+
+ page = lastPage;
+
+ /* which page are we dma'ing? */
+
+ while (1)
+ {
+ cb = (cbAddr - ((int)dmaOPhys[page] | DMA_BUS_ADR)) / 32;
+
+ if (cb < CBS_PER_OPAGE)
+ {
+ lastPage = page;
+
+ return (page*CBS_PER_OPAGE) + cb;
+ }
+
+ if (page++ >= DMAO_PAGES) page=0;
if (page == lastPage) break;
}
return (uint32_t) &dmaIPhys[pos]->periphData;
}
+/* ----------------------------------------------------------------------- */
+
static uint32_t dmaGpioOnAdr(int pos)
{
int page, slot;
p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
}
- p->src = dmaPwmDataAdr(b%DMA_PAGES) | DMA_BUS_ADR;
+ p->src = dmaPwmDataAdr(b%DMAI_PAGES) | DMA_BUS_ADR;
p->length = 4;
p->next = dmaCbAdr(b+1) | DMA_BUS_ADR;
}
}
else if (signum == SIGPIPE)
{
+ /* can happen when pipe/socket is remote closed */
DBG(DBG_USER, "SIGPIPE received");
}
+ else if (signum == SIGCHLD)
+ {
+ /* happens when system call is made */
+ DBG(DBG_USER, "SIGCHLD received");
+ }
else
{
/* exit */
- DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
+ DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
exit(-1);
}
{
/* exit */
- DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
+ DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
exit(-1);
}
gpioStats.startTick = tick;
- oldSlot = dmaCurrentSlot(dmaCurrentCb());
+ oldSlot = dmaCurrentSlot(dmaNowAtICB());
cycle = (oldSlot/PULSE_PER_CYCLE);
pulse = (oldSlot%PULSE_PER_CYCLE);
req.tv_nsec = rem.tv_nsec;
}
- newSlot = dmaCurrentSlot(dmaCurrentCb());
+ newSlot = dmaCurrentSlot(dmaNowAtICB());
numSamples = 0;
}
}
+ if (changedBits & scriptBits)
+ {
+ for (n=0; n<PI_SCRIPT_SLOTS; n++)
+ {
+ if ((gpioScript[n].state == PI_SCRIPT_IN_USE) &&
+ (gpioScript[n].run_state == PI_SCRIPT_WAITING) &&
+ (gpioScript[n].waitBits & changedBits))
+ {
+ pthread_mutex_lock(&gpioScript[n].pthMutex);
+
+ if (gpioScript[n].run_state == PI_SCRIPT_WAITING)
+ {
+ gpioScript[n].changedBits =
+ gpioScript[n].waitBits & changedBits;
+ pthread_cond_signal(&gpioScript[n].pthCond);
+ }
+
+ pthread_mutex_unlock(&gpioScript[n].pthMutex);
+ }
+ }
+ }
+
/* once all outputs have been emitted set reported level */
if (numSamples) reportedLevel = gpioSample[numSamples-1].level;
return 0;
}
+/* ======================================================================= */
+
+static int scrPop(gpioScript_t *s, int *SP, int *S)
+{
+ if ((*SP) > 0)
+ {
+ return S[--(*SP)];
+ }
+ else
+ {
+ s->run_state = PI_SCRIPT_FAILED;
+ DBG(DBG_ALWAYS, "script %d too many pops", s->id);
+ return 0;
+ }
+}
+
/* ----------------------------------------------------------------------- */
-static void * pthTimerTick(void *x)
+static void scrPush(gpioScript_t *s, int *SP, int *S, int val)
{
- gpioTimer_t * tp;
- struct timespec req, rem, period;
- char buf[256];
+ if ((*SP) < PI_SCRIPT_STACK_SIZE)
+ {
+ S[(*SP)++] = val;
+ }
+ else
+ {
+ s->run_state = PI_SCRIPT_FAILED;
+ DBG(DBG_ALWAYS, "script %d too many pushes", s->id);
+ }
+}
- tp = x;
+/* ----------------------------------------------------------------------- */
- clock_gettime(CLOCK_REALTIME, &tp->nextTick);
+static void scrSwap(int *v1, int *v2)
+{
+ int t;
- while (1)
+ t=*v1; *v1=*v2; *v2= t;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int scrWait(gpioScript_t *s, uint32_t bits)
+{
+ pthread_mutex_lock(&s->pthMutex);
+
+ if (s->request == PI_SCRIPT_RUN)
{
- clock_gettime(CLOCK_REALTIME, &rem);
+ s->run_state = PI_SCRIPT_WAITING;
+ s->waitBits = bits;
+ intScriptBits();
- period.tv_sec = tp->millis / THOUSAND;
- period.tv_nsec = (tp->millis % THOUSAND) * THOUSAND * THOUSAND;
+ pthread_cond_wait(&s->pthCond, &s->pthMutex);
- do
- {
- TIMER_ADD(&tp->nextTick, &period, &tp->nextTick);
+ s->waitBits = 0;
+ intScriptBits();
+ s->run_state = PI_SCRIPT_RUNNING;
+ }
- TIMER_SUB(&tp->nextTick, &rem, &req);
- }
- while (req.tv_sec < 0);
+ pthread_mutex_unlock(&s->pthMutex);
- while (nanosleep(&req, &rem))
+ return s->changedBits;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int scrSys(char *cmd, int param)
+{
+ char buf[256];
+ char par[16];
+
+ sprintf(par, " %d", param);
+ strcpy(buf, "/opt/pigpio/cgi/");
+ strncat(buf, cmd, 200);
+ strcat(buf, par);
+
+ DBG(DBG_USER, "sys %s", buf);
+
+ return system(buf);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void *pthScript(void *x)
+{
+ gpioScript_t *s;
+ gpioExtent_t oExt[3];
+ char buf[CMD_BUF_SIZE];
+ gpioInstr_t instr;
+ int p1, p2;
+
+ int PC, A, F, SP;
+ int S[PI_SCRIPT_STACK_SIZE];
+
+ S[0] = 0; /* to prevent compiler warning */
+
+ s = x;
+
+ s->run_state = PI_SCRIPT_HALTED;
+
+ while (s->request != PI_SCRIPT_DELETE)
+ {
+ pthread_mutex_lock(&s->pthMutex);
+ pthread_cond_wait(&s->pthCond, &s->pthMutex);
+ pthread_mutex_unlock(&s->pthMutex);
+
+ s->run_state = PI_SCRIPT_RUNNING;
+
+ A = 0;
+ F = 0;
+ PC = 0;
+ SP = 0;
+
+ while ((s->request == PI_SCRIPT_RUN ) &&
+ (s->run_state == PI_SCRIPT_RUNNING))
+ {
+ instr = s->instr[PC];
+
+ p1 = instr.p[1];
+ p2 = instr.p[2];
+
+ if (instr.p[0] < 100)
+ {
+ oExt[0].ptr = buf;
+ oExt[0].size = CMD_BUF_SIZE-1;
+
+ if (instr.opt[0] == CMD_PARAM)
+ {
+ instr.p[1] = s->param[p1];
+ }
+ else if (instr.opt[0] == CMD_VAR)
+ {
+ instr.p[1] = s->var[p1];
+ }
+
+ if (instr.opt[1] == CMD_PARAM)
+ {
+ instr.p[2] = s->param[p2];
+ }
+ else if (instr.opt[1] == CMD_VAR)
+ {
+ instr.p[2] = s->var[p2];
+ }
+
+ A = myDoCommand(instr.p, oExt);
+
+ F = A;
+
+ PC++;
+ }
+ else
+ {
+ switch (instr.p[0])
+ {
+ case PI_CMD_ADDI: A+=p1; F=A; PC++; break;
+
+ case PI_CMD_ADDV: A+=s->var[p1]; F=A; PC++; break;
+
+ case PI_CMD_ANDI: A&=p1; F=A; PC++; break;
+
+ case PI_CMD_ANDV: A&=s->var[p1]; F=A; PC++; break;
+
+ case PI_CMD_CALL: scrPush(s, S, &SP, PC+1); PC = p1; break;
+
+ case PI_CMD_CMPI: F=A-p1; PC++; break;
+
+ case PI_CMD_CMPV: F=A-s->var[p1]; PC++; break;
+
+ case PI_CMD_DCRA: --A; F=A; PC++; break;
+
+ case PI_CMD_DCRV: --s->var[p1]; F=s->var[p1]; PC++; break;
+
+ case PI_CMD_HALT: s->run_state = PI_SCRIPT_HALTED; break;
+
+ case PI_CMD_INRA: ++A; F=A; PC++; break;
+
+ case PI_CMD_INRV: ++s->var[p1]; F=s->var[p1]; PC++; break;
+
+ case PI_CMD_JM: if (F<0) PC=p1; else PC++; break;
+
+ case PI_CMD_JMP: PC=p1; break;
+
+ case PI_CMD_JNZ: if (F) PC=p1; else PC++; break;
+
+ case PI_CMD_JP: if (F>=0) PC=p1; else PC++; break;
+
+ case PI_CMD_JZ: if (!F) PC=p1; else PC++; break;
+
+ case PI_CMD_LABEL: PC++; break;
+
+ case PI_CMD_LDAI: A=p1; PC++; break;
+
+ case PI_CMD_LDAP: A=s->param[p1]; PC++; break;
+
+ case PI_CMD_LDAV: A=s->var[p1]; PC++; break;
+
+ case PI_CMD_LDPA: s->param[p1]=A; PC++; break;
+
+ case PI_CMD_LDVA: s->var[p1]=A; PC++; break;
+
+ case PI_CMD_LDVI: s->var[p1] = p2; PC++; break;
+
+ case PI_CMD_LDVV: s->var[p1]=s->var[p2]; PC++; break;
+
+ case PI_CMD_ORI: A|=p1; F=A; PC++; break;
+
+ case PI_CMD_ORV: A|=s->var[p1]; F=A; PC++; break;
+
+ case PI_CMD_POPA: A=scrPop(s, S, &SP); PC++; break;
+
+ case PI_CMD_POPV: s->var[p1]=scrPop(s, S, &SP); PC++; break;
+
+ case PI_CMD_PUSHA: scrPush(s, S, &SP, A); PC++; break;
+
+ case PI_CMD_PUSHV: scrPush(s, S, &SP, s->var[p1]); PC++; break;
+
+ case PI_CMD_RET: PC=scrPop(s, S, &SP); break;
+
+ case PI_CMD_RAL: A<<=p1; F=A; PC++; break;
+
+ case PI_CMD_RAR: A>>=p1; F=A; PC++; break;
+
+ case PI_CMD_SUBI: A-=p1; F=A; PC++; break;
+
+ case PI_CMD_SUBV: A-=s->var[p1]; F=A; PC++; break;
+
+ case PI_CMD_SWAPA: scrSwap(&s->var[p1], &A); PC++; break;
+
+ case PI_CMD_SWAPV: scrSwap(&s->var[p1], &s->var[p2]);PC++; break;
+
+ case PI_CMD_SYS: A=scrSys((char*)p1, A); F=A; PC++; break;
+
+ case PI_CMD_WAITI: A=scrWait(s, p1); F=A; PC++; break;
+
+ case PI_CMD_WAITV: A=scrWait(s, s->var[p1]); F=A; PC++; break;
+
+ case PI_CMD_XORI: A^=p1; F=A; PC++; break;
+
+ case PI_CMD_XORV: A^=s->var[p1]; F=A; PC++; break;
+
+ }
+ }
+
+ if (PC >= s->instrs) s->run_state = PI_SCRIPT_HALTED;
+
+ }
+
+ if (s->request == PI_SCRIPT_HALT) s->run_state = PI_SCRIPT_HALTED;
+
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void * pthTimerTick(void *x)
+{
+ gpioTimer_t * tp;
+ struct timespec req, rem, period;
+ char buf[256];
+
+ tp = x;
+
+ clock_gettime(CLOCK_REALTIME, &tp->nextTick);
+
+ while (1)
+ {
+ clock_gettime(CLOCK_REALTIME, &rem);
+
+ period.tv_sec = tp->millis / THOUSAND;
+ period.tv_nsec = (tp->millis % THOUSAND) * THOUSAND * THOUSAND;
+
+ do
+ {
+ TIMER_ADD(&tp->nextTick, &period, &tp->nextTick);
+
+ TIMER_SUB(&tp->nextTick, &rem, &req);
+ }
+ while (req.tv_sec < 0);
+
+ while (nanosleep(&req, &rem))
{
req.tv_sec = rem.tv_sec;
req.tv_nsec = rem.tv_nsec;
static void * pthFifoThread(void *x)
{
char buf[CMD_BUF_SIZE];
- int idx, flags, len;
- cmdCmd_t cmd;
- gpioExtent_t iExt[3];
+ int idx, flags, len, res, i;
+ uint32_t p[10];
+ void *v[10];
gpioExtent_t oExt[3];
- char *p;
+ gpioCtlParse_t ctl;
+ char *pp;
+ uint32_t *param;
+
+ ctl.flags = 0;
myCreatePipe(PI_INPFIFO, 0662);
buf[len] = 0; /* replace terminating */
}
- if ((idx=cmdParse(buf, &cmd, 0, NULL, iExt)) >= 0)
+ ctl.eaten = 0;
+ idx = 0;
+
+ while (((ctl.eaten)<len) && (idx >= 0))
{
- oExt[0].ptr = buf;
- oExt[0].size = CMD_BUF_SIZE-1;
+ if ((idx=cmdParse(buf, p, v, &ctl)) >= 0)
+ {
+ oExt[0].ptr = buf;
+ oExt[0].size = CMD_BUF_SIZE-1;
- myDoCommand(&cmd, iExt, oExt);
+ switch (p[0])
+ {
+ case PI_CMD_PROC: p[2] = (uint32_t)v[1]; break;
+ case PI_CMD_PROCR: p[3] = (uint32_t)v[1]; break;
+ case PI_CMD_WVAG: p[2] = (uint32_t)v[1]; break;
+ case PI_CMD_WVAS: p[5] = (uint32_t)v[1]; break;
+ }
- switch (cmdInfo[idx].rv)
- {
- case 0:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ res = myDoCommand(p, oExt);
- case 1:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ switch (cmdInfo[idx].rv)
+ {
+ case 0:
+ fprintf(outFifo, "%d\n", res);
+ break;
- case 2:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ case 1:
+ fprintf(outFifo, "%d\n", res);
+ break;
- case 3:
- fprintf(outFifo, "%08X\n", cmd.res);
- break;
+ case 2:
+ fprintf(outFifo, "%d\n", res);
+ break;
- case 4:
- fprintf(outFifo, "%u\n", cmd.res);
- break;
+ case 3:
+ fprintf(outFifo, "%08X\n", res);
+ break;
- case 5:
- fprintf(outFifo, cmdUsage);
- break;
+ case 4:
+ fprintf(outFifo, "%u\n", res);
+ break;
- case 6:
- if (cmd.res < 0) fprintf(outFifo, "%d\n", cmd.res);
- else if (cmd.res > 0)
- {
- p = oExt[0].ptr;
- p[cmd.res] = 0;
- fprintf(outFifo, "%s", (char *)oExt[0].ptr);
- }
- break;
+ case 5:
+ fprintf(outFifo, cmdUsage);
+ break;
- }
+ case 6:
+ if (res < 0) fprintf(outFifo, "%d\n", res);
+ else if (res > 0)
+ {
+ pp = oExt[0].ptr;
+ pp[res] = 0;
+ fprintf(outFifo, "%s", (char *)oExt[0].ptr);
+ }
+ break;
+ case 7:
+ if (res < 0) fprintf(outFifo, "%d\n", res);
+ else
+ {
+ fprintf(outFifo, "%d", res);
+ param = oExt[0].ptr;
+ for (i=0; i<MAX_SCRIPT_PARAMS; i++)
+ {
+ fprintf(outFifo, " %d", param[i]);
+ }
+ fprintf(outFifo, "\n");
+ }
+ break;
+ }
+ }
+ else fprintf(outFifo, "%d\n", PI_BAD_FIFO_COMMAND);
}
- else fprintf(outFifo, "%d\n", PI_BAD_FIFO_COMMAND);
fflush(outFifo);
}
static void *pthSocketThreadHandler(void *fdC)
{
int sock = *(int*)fdC;
- cmdCmd_t cmd;
+ int res;
+ uint32_t p[10];
unsigned bytes;
char *memPtr;
- gpioExtent_t iExt[3];
gpioExtent_t oExt[3];
- unsigned tmp;
char buf[CMD_BUF_SIZE];
oExt[0].size = CMD_BUF_SIZE-1;
free(fdC);
- while(1)
+ while (1)
{
- if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) == sizeof(cmdCmd_t))
+ res = 0;
+
+ if (recv(sock, p, 16, MSG_WAITALL) != 16) break;
+
+ switch (p[0])
{
- if (cmd.cmd == PI_CMD_NOIB)
- {
- cmd.res = gpioNotifyOpenInBand(sock);
- }
- else if (cmd.cmd == PI_CMD_WVAG)
- {
+ case PI_CMD_NOIB:
+ res = gpioNotifyOpenInBand(sock);
+ break;
+
+ case PI_CMD_PROC:
+ /*
+ p1=script length
+ p2=0
+ ## extension ##
+ char[] script
+ */
+ if (p[1]) /* script appended */
+ {
+ memPtr = malloc(p[1]+1); /* add null terminator */
+
+ if (memPtr)
+ {
+ if (recv(sock, memPtr, p[1], MSG_WAITALL) == p[1])
+ {
+ p[2] = (uint32_t)memPtr;
+ memPtr[p[1]] = 0;
+ res = myDoCommand(p, oExt);
+ free(memPtr);
+ }
+ else
+ {
+ free(memPtr);
+ close(sock);
+ return 0;
+ }
+ }
+ }
+ else res = PI_BAD_SCRIPT_CMD;
+ break;
+
+ case PI_CMD_PROCR:
+ /*
+ p1=script id
+ p2=numParam
+ ## extension ##
+ int[] param
+ */
+ if (p[2]) /* parameters appended */
+ {
+ memPtr = malloc(p[2]*sizeof(uint32_t));
+
+ if (memPtr)
+ {
+ if (recv(sock, memPtr, p[2]*sizeof(uint32_t), MSG_WAITALL) ==
+ p[2]*sizeof(uint32_t))
+ {
+ p[3] = (uint32_t)memPtr;
+ res = myDoCommand(p, oExt);
+ free(memPtr);
+ }
+ else
+ {
+ free(memPtr);
+ close(sock);
+ return 0;
+ }
+ }
+ }
+ else res = myDoCommand(p, oExt);
+ break;
+
+ case PI_CMD_TRIG:
+ /*
+ p1=user_gpio
+ p2=pulseLen
+ ## extension ##
+ unsigned level
+ */
+ if (recv(sock, &p[3], sizeof(unsigned), MSG_WAITALL) ==
+ sizeof(unsigned))
+ {
+ res = myDoCommand(p, oExt);
+ }
+ else
+ {
+ close(sock);
+ return 0;
+ }
+ break;
+
+ case PI_CMD_WVAG:
/*
p1=numPulses
p2=0
gpioPulse_t[] pulses
*/
- bytes = cmd.p1 * sizeof(gpioPulse_t);
+ bytes = p[1] * sizeof(gpioPulse_t);
memPtr = malloc(bytes);
{
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
{
- iExt[0].size = bytes;
- iExt[0].ptr = memPtr;
- myDoCommand(&cmd, iExt, oExt);
+ p[2] = (uint32_t)memPtr;
+ res = myDoCommand(p, oExt);
free(memPtr);
}
else
{
free(memPtr);
- break;
+ close(sock);
+ return 0;
}
}
- else break;
+ else res = PI_NO_MEMORY;
+ break;
- }
- else if (cmd.cmd == PI_CMD_WVAS)
- {
+ case PI_CMD_WVAS:
/*
p1=user_gpio
p2=numChar
char[] str
*/
- bytes = sizeof(unsigned) + sizeof(unsigned) + cmd.p2;
+ bytes = sizeof(unsigned) + sizeof(unsigned) + p[2];
memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
{
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
{
- iExt[0].size = sizeof(unsigned);
- iExt[0].ptr = memPtr;
- iExt[1].size = sizeof(unsigned);
- iExt[1].ptr = memPtr + sizeof(unsigned);
- iExt[2].size = cmd.p2;
- iExt[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned);
+ p[4] = p[2];
+ memcpy(&p[2], memPtr, 4);
+ memcpy(&p[3], memPtr+4, 4);
+ p[5] =
+ (uint32_t)(memPtr + sizeof(unsigned) + sizeof(unsigned));
memPtr[bytes] = 0; /* may be duplicate terminator */
- myDoCommand(&cmd, iExt, oExt);
+ res = myDoCommand(p, oExt);
free(memPtr);
}
else
{
free(memPtr);
- break;
+ close(sock);
+ return 0;
}
}
- else break;
+ else res = PI_NO_MEMORY;
+ break;
- }
- else if (cmd.cmd == PI_CMD_PROC)
- {
- /*
- p1=script length
- p2=0
- ## extension ##
- char[] script
- */
+ default:
+ res = myDoCommand(p, oExt);
+ break;
+ }
- bytes = cmd.p1;
+ p[3] = res;
- memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
+ write(sock, p, 16);
- if (memPtr)
- {
- if (bytes) /* script appended */
- {
- if (recv(sock, memPtr, bytes, MSG_WAITALL) != bytes)
- {
- free(memPtr);
- break;
- }
- }
- iExt[0].size = bytes;
- iExt[0].ptr = memPtr;
- memPtr[bytes] = 0; /* may be duplicate terminator */
- myDoCommand(&cmd, iExt, oExt);
- free(memPtr);
- }
- else break;
- }
- else
- {
- switch (cmd.cmd)
- {
- case PI_CMD_TRIG:
- /*
- p1=user_gpio
- p2=pulseLen
- ## extension ##
- unsigned level
- */
- iExt[0].size = 4;
- iExt[0].ptr = &tmp;
-
- if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) !=
- sizeof(unsigned))
- {
- close(sock);
- return 0;
- }
- break;
+ switch (p[0])
+ {
+ case PI_CMD_SLR: /* extension */
- default:
- break;
+ if (res > 0)
+ {
+ write(sock, oExt[0].ptr, res);
}
- myDoCommand(&cmd, iExt, oExt);
- }
+ break;
- write(sock, &cmd, sizeof(cmdCmd_t));
-
- switch (cmd.cmd)
- {
- case PI_CMD_SLR: /* extension */
-
- if (cmd.res > 0)
- {
- write(sock, oExt[0].ptr, cmd.res);
- }
- break;
-
- default:
- break;
- }
+ case PI_CMD_PROCP: /* extension */
+ if (res >= 0)
+ {
+ write(sock, oExt[0].ptr, sizeof(uint32_t)*MAX_SCRIPT_PARAMS);
+ }
+ break;
+ default:
+ break;
}
- else break;
}
close(sock);
(uint32_t)gpioReg, (uint32_t)pwmReg,
(uint32_t)pcmReg, (uint32_t)clkReg);
- for (i=0; i<DMA_PAGES; i++)
+ for (i=0; i<DMAI_PAGES; i++)
DBG(DBG_STARTUP, "dmaIPhys[%d]=%08X", i, (uint32_t)dmaIPhys[i]);
dmaInitCbs();
static void initClock(int mainClock)
{
+ int clockPWM;
unsigned clkCtl, clkDiv, clkSrc, clkDivI, clkDivF, clkMash, clkBits;
char * per, * src;
unsigned micros;
if (mainClock) micros = gpioCfg.clockMicros;
else micros = PI_WF_MICROS;
- if ((gpioCfg.clockPeriph == PI_CLOCK_PCM) && mainClock)
- {
- clkCtl = CLK_PCMCTL;
- clkDiv = CLK_PCMDIV;
- per = "PCM";
- }
- else
+ clockPWM = mainClock ^ (gpioCfg.clockPeriph == PI_CLOCK_PCM);
+
+ if (clockPWM)
{
clkCtl = CLK_PWMCTL;
clkDiv = CLK_PWMDIV;
per = "PWM";
}
+ else
+ {
+ clkCtl = CLK_PCMCTL;
+ clkDiv = CLK_PCMDIV;
+ per = "PCM";
+ }
if (gpioCfg.clockSource == PI_CLOCK_PLLD)
{
myGpioDelay(10);
- if ((gpioCfg.clockPeriph == PI_CLOCK_PCM) && mainClock)
- initPCM(clkBits);
- else initPWM(clkBits);
+ if (clockPWM) initPWM(clkBits);
+ else initPCM(clkBits);
myGpioDelay(2000);
}
/* ----------------------------------------------------------------------- */
-static void initDMAgo(volatile uint32_t * dmaAddr, uint32_t cbAddr)
+static void initDMAgo(volatile uint32_t *dmaAddr, uint32_t cbAddr)
{
DBG(DBG_STARTUP, "");
DBG(DBG_STARTUP, "");
- alertBits = 0;
- monitorBits = 0;
- notifyBits = 0;
+ alertBits = 0;
+ monitorBits = 0;
+ notifyBits = 0;
+ scriptBits = 0;
libInitialised = 0;
DMAstarted = 0;
wfStats.cbs = 0;
wfStats.highCbs = 0;
- wfStats.maxCbs = (PAGES_PER_BLOCK * CBS_PER_OPAGE);
+ wfStats.maxCbs = (PI_WAVE_BLOCKS * PAGES_PER_BLOCK * CBS_PER_OPAGE);
gpioGetSamples.func = NULL;
gpioGetSamples.ex = 0;
pthSocketRunning = 0;
}
- /* release mmap'd memory */
+ /* release mmap'd memory */
+
+ if (clkReg != MAP_FAILED) munmap((void *)clkReg, CLK_LEN);
+ if (dmaReg != MAP_FAILED) munmap((void *)dmaReg, DMA_LEN);
+ if (gpioReg != MAP_FAILED) munmap((void *)gpioReg, GPIO_LEN);
+ if (pcmReg != MAP_FAILED) munmap((void *)pcmReg, PCM_LEN);
+ if (pwmReg != MAP_FAILED) munmap((void *)pwmReg, PWM_LEN);
+ if (systReg != MAP_FAILED) munmap((void *)systReg, SYST_LEN);
+
+ clkReg = MAP_FAILED;
+ dmaReg = MAP_FAILED;
+ gpioReg = MAP_FAILED;
+ pcmReg = MAP_FAILED;
+ pwmReg = MAP_FAILED;
+ systReg = MAP_FAILED;
+
+ if (dmaVirt != MAP_FAILED)
+ {
+ for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
+ {
+ munmap(dmaVirt[i], PAGE_SIZE);
+ }
+
+ munmap(dmaVirt,
+ PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
+ }
+
+ dmaVirt = MAP_FAILED;
+
+ if (dmaPhys != MAP_FAILED)
+ {
+ for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
+ {
+ munmap(dmaPhys[i], PAGE_SIZE);
+ }
+
+ munmap(dmaPhys,
+ PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
+ }
+
+ dmaPhys = MAP_FAILED;
+
+ if (dmaBloc != MAP_FAILED)
+ {
+ for (i=0; i<(bufferBlocks+PI_WAVE_BLOCKS); i++)
+ {
+ munmap(dmaBloc[i], PAGES_PER_BLOCK*PAGE_SIZE);
+ }
+
+ munmap(dmaBloc, (bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
+ }
+
+ dmaBloc = MAP_FAILED;
+
+ if (inpFifo != NULL)
+ {
+ fclose(inpFifo);
+ unlink(PI_INPFIFO);
+ inpFifo = NULL;
+ }
+
+ if (outFifo != NULL)
+ {
+ fclose(outFifo);
+ unlink(PI_OUTFIFO);
+ outFifo = NULL;
+ }
+
+ if (fdMem != -1)
+ {
+ close(fdMem);
+ fdMem = -1;
+ }
+
+ if (fdLock != -1)
+ {
+ close(fdLock);
+ unlink(PI_LOCKFILE);
+ fdLock = -1;
+ }
+
+ if (fdSock != -1)
+ {
+ close(fdSock);
+ fdSock = -1;
+ }
+}
+
+/* ======================================================================= */
+
+int getBitInBytes(int bitPos, uint8_t *buf, int numBits)
+{
+ int bitp, bufp;
+
+ if (bitPos < numBits)
+ {
+ bufp = bitPos / 8;
+ bitp = 7 - (bitPos % 8);
+ if (buf[bufp] & (1<<bitp)) return 1;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void putBitInBytes(int bitPos, uint8_t *buf, int val)
+{
+ int bitp, bufp;
+
+ bufp = bitPos / 8;
+ bitp = 7 - (bitPos % 8);
+
+ if (val) buf[bufp] |= (1<<bitp);
+ else buf[bufp] &= (~(1<<bitp));
+}
+
+/* ----------------------------------------------------------------------- */
+
+uint32_t waveGetRawOut(int pos)
+{
+ int page, slot;
+
+ if ((pos >= 0) && (pos < NUM_OOL))
+ {
+ waveOOLPageSlot(pos, &page, &slot);
+ return (dmaOVirt[page]->OOL[slot]);
+ }
+
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void waveSetRawOut(int pos, uint32_t value)
+{
+ int page, slot;
+
+ if ((pos >= 0) && (pos < NUM_OOL))
+ {
+ waveOOLPageSlot(pos, &page, &slot);
+ dmaOVirt[page]->OOL[slot] = value;
+ }
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+uint32_t waveGetRawIn(int pos)
+{
+ int page, slot;
+
+ if ((pos >= 0) && (pos < NUM_OOL))
+ {
+ waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot);
+ return (dmaOVirt[page]->OOL[slot]);
+ }
+
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void waveSetRawIn(int pos, uint32_t value)
+{
+ int page, slot;
+
+ if ((pos >= 0) && (pos < NUM_OOL))
+ {
+ waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot);
+ dmaOVirt[page]->OOL[slot] = value;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+double time_time(void)
+{
+ struct timeval tv;
+ double t;
- if (clkReg != MAP_FAILED) munmap((void *)clkReg, CLK_LEN);
- if (dmaReg != MAP_FAILED) munmap((void *)dmaReg, DMA_LEN);
- if (gpioReg != MAP_FAILED) munmap((void *)gpioReg, GPIO_LEN);
- if (pcmReg != MAP_FAILED) munmap((void *)pcmReg, PCM_LEN);
- if (pwmReg != MAP_FAILED) munmap((void *)pwmReg, PWM_LEN);
- if (systReg != MAP_FAILED) munmap((void *)systReg, SYST_LEN);
+ gettimeofday(&tv, 0);
- clkReg = MAP_FAILED;
- dmaReg = MAP_FAILED;
- gpioReg = MAP_FAILED;
- pcmReg = MAP_FAILED;
- pwmReg = MAP_FAILED;
- systReg = MAP_FAILED;
+ t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6);
- if (dmaVirt != MAP_FAILED)
- {
- for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
- {
- munmap(dmaVirt[i], PAGE_SIZE);
- }
+ return t;
+}
- munmap(dmaVirt,
- PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
- }
+/* ----------------------------------------------------------------------- */
- dmaVirt = MAP_FAILED;
+void time_sleep(double seconds)
+{
+ struct timespec ts, rem;
- if (dmaPhys != MAP_FAILED)
+ if (seconds > 0.0)
{
- for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
+ ts.tv_sec = seconds;
+ ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9;
+
+ while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem))
{
- munmap(dmaPhys[i], PAGE_SIZE);
+ /* copy remaining time to ts */
+ ts.tv_sec = rem.tv_sec;
+ ts.tv_nsec = rem.tv_nsec;
}
-
- munmap(dmaPhys,
- PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
}
+}
- dmaPhys = MAP_FAILED;
+/* ----------------------------------------------------------------------- */
- if (dmaBloc != MAP_FAILED)
- {
- for (i=0; i<(bufferBlocks+PI_WAVE_BLOCKS); i++)
- {
- munmap(dmaBloc[i], PAGES_PER_BLOCK*PAGE_SIZE);
- }
+void gpioDumpWave(void)
+{
+ int i;
- munmap(dmaBloc, (bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
- }
+ unsigned numWaves, t;
- dmaBloc = MAP_FAILED;
+ gpioWave_t *waves;
- if (inpFifo != NULL)
- {
- fclose(inpFifo);
- unlink(PI_INPFIFO);
- inpFifo = NULL;
- }
+ numWaves = wfc[wfcur];
+ waves = wf [wfcur];
- if (outFifo != NULL)
+ t = 0;
+
+ for (i=0; i<numWaves; i++)
{
- fclose(outFifo);
- unlink(PI_OUTFIFO);
- outFifo = NULL;
+ fprintf(stderr, "%10u %08X %08X %08X %10u\n",
+ t, waves[i].gpioOn, waves[i].gpioOff,
+ waves[i].flags, waves[i].usDelay);
+ t += waves[i].usDelay;
}
+}
- if (fdMem != -1)
+/* ----------------------------------------------------------------------- */
+
+void gpioDumpScript(int s)
+{
+ int i;
+
+ for (i=0; i<MAX_SCRIPT_PARAMS; i++)
{
- close(fdMem);
- fdMem = -1;
+ fprintf(stderr, "p%d=%d ", i, gpioScript[s].param[i]);
}
- if (fdLock != -1)
+ fprintf(stderr, "\n");
+
+ for (i=0; i<MAX_SCRIPT_VARS; i++)
{
- close(fdLock);
- unlink(PI_LOCKFILE);
- fdLock = -1;
+ fprintf(stderr, "v%d=%d ", i, gpioScript[s].var[i]);
}
- if (fdSock != -1)
+ fprintf(stderr, "\n");
+
+ for (i=0; i<gpioScript[s].instrs; i++)
{
- close(fdSock);
- fdSock = -1;
+ fprintf(stderr, "c%d=[%d, %d(%d), %d(%d)]\n",
+ i, gpioScript[s].instr[i].p[0],
+ gpioScript[s].instr[i].p[1], gpioScript[s].instr[i].opt[0],
+ gpioScript[s].instr[i].p[2], gpioScript[s].instr[i].opt[1]);
}
}
/* switch pwm off */
myGpioSetPwm(gpio, gpioInfo[gpio].width, 0);
break;
-
}
gpioInfo[gpio].is = GPIO_UNDEFINED;
if (gpio <= PI_MAX_USER_GPIO)
{
- if (gpioInfo[gpio].is != GPIO_OUTPUT)
+ if (gpioInfo[gpio].is != GPIO_WRITE)
{
if (gpioInfo[gpio].is == GPIO_UNDEFINED)
{
+ if (level == PI_OFF) *(gpioReg + GPCLR0 + BANK) = BIT;
+ else *(gpioReg + GPSET0 + BANK) = BIT;
gpioSetMode(gpio, PI_OUTPUT);
}
else if (gpioInfo[gpio].is == GPIO_PWM)
gpio, gpioInfo[gpio].width/gpioCfg.clockMicros, 0);
}
- gpioInfo[gpio].is=GPIO_OUTPUT;
+ gpioInfo[gpio].is=GPIO_WRITE;
gpioInfo[gpio].width=0;
}
}
/* switch servo off */
myGpioSetServo(gpio, gpioInfo[gpio].width, 0);
gpioInfo[gpio].width = 0;
- gpioInfo[gpio].freqIdx = DEFAULT_PWM_IDX; /* default frequency */
}
gpioInfo[gpio].is = GPIO_PWM;
}
gpioInfo[gpio].width=0;
}
gpioInfo[gpio].is = GPIO_SERVO;
- gpioInfo[gpio].freqIdx = clkCfg[gpioCfg.clockMicros].servoIdx;
}
myGpioSetServo(gpio, gpioInfo[gpio].width, val);
/* ----------------------------------------------------------------------- */
-int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses)
+int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t *pulses)
{
+ int p;
+
DBG(DBG_USER, "numPulses=%u pulses=%08X", numPulses, (uint32_t)pulses);
CHECK_INITED;
if (numPulses > PI_WAVE_MAX_PULSES)
SOFT_ERROR(PI_TOO_MANY_PULSES, "bad number of pulses (%d)", numPulses);
- return waveMerge(numPulses, pulses);
+ for (p=0; p<numPulses; p++)
+ {
+ wf[2][p].gpioOff = pulses[p].gpioOff;
+ wf[2][p].gpioOn = pulses[p].gpioOn;
+ wf[2][p].usDelay = pulses[p].usDelay;
+ wf[2][p].flags = 0;
+ }
+
+ return waveMerge(numPulses, wf[2]);
}
unsigned bitDelay[10];
- DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s",
+ DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=[%s]",
gpio, baud, offset, numChar, str);
DBG(DBG_USER, "l=%d s=%X e=%X",
wf[2][p].gpioOn = (1<<gpio);
wf[2][p].gpioOff = 0;
+ wf[2][p].flags = 0;
if (offset > bitDelay[0]) wf[2][p].usDelay = offset;
else wf[2][p].usDelay = bitDelay[0];
wf[2][p].gpioOn = 0;
wf[2][p].gpioOff = (1<<gpio);
wf[2][p].usDelay = bitDelay[0];
+ wf[2][p].flags = 0;
lev = 0;
if (lev)
{
- wf[2][p].gpioOn = (1<<gpio);
+ wf[2][p].gpioOn = (1<<gpio);
wf[2][p].gpioOff = 0;
+ wf[2][p].flags = 0;
}
else
{
- wf[2][p].gpioOn = 0;
+ wf[2][p].gpioOn = 0;
wf[2][p].gpioOff = (1<<gpio);
+ wf[2][p].flags = 0;
}
wf[2][p].usDelay = bitDelay[b+1];
{
p++;
- wf[2][p].gpioOn = (1<<gpio);
+ wf[2][p].gpioOn = (1<<gpio);
wf[2][p].gpioOff = 0;
wf[2][p].usDelay = bitDelay[9];
+ wf[2][p].flags = 0;
}
}
wf[2][p].gpioOn = (1<<gpio);
wf[2][p].gpioOff = 0;
wf[2][p].usDelay = bitDelay[0];
+ wf[2][p].flags = 0;
return waveMerge(p, wf[2]);
}
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveAddSPI(
+ gpioSPI_t *spi,
+ unsigned offset,
+ unsigned ss,
+ uint8_t *tx_bits,
+ unsigned num_tx_bits,
+ unsigned rx_bit_first,
+ unsigned rx_bit_last,
+ unsigned bits)
+{
+ int p, dbv, bit, halfbit;
+ int rising_edge[2], read_cycle[2];
+ uint32_t on_bits, off_bits;
+ int tx_bit_pos;
+
+ DBG(DBG_USER, "spi=%08X off=%d ss=%d tx=%08X, num=%d fb=%d lb=%d bits=%d",
+ (uint32_t)spi, offset, ss, (uint32_t)tx_bits, num_tx_bits,
+ rx_bit_first, rx_bit_last, bits);
+
+ CHECK_INITED;
+
+ if (ss > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", ss);
+
+ /*
+ CPOL CPHA
+ 0 0 read rising/write falling
+ 0 1 read falling/write rising
+ 1 0 read falling/write rising
+ 1 1 read rising/write falling
+ */
+
+ if (spi->clk_pol) {rising_edge[0] = 0; rising_edge[1] = 1;}
+ else {rising_edge[0] = 1; rising_edge[1] = 0;}
+
+ if (spi->clk_pha) {read_cycle[0] = 0; read_cycle[1] = 1;}
+ else {read_cycle[0] = 1; read_cycle[1] = 0;}
+
+ p = 0;
+
+ if (offset)
+ {
+ wf[2][p].gpioOn = 0;
+ wf[2][p].gpioOff = 0;
+ wf[2][p].flags = 0;
+ wf[2][p].usDelay = offset;
+ p++;
+ }
+
+ /* preset initial mosi bit in case it's read at leading clock bit */
+
+ on_bits = 0;
+ off_bits = 0;
+
+ tx_bit_pos = 0;
+
+ if (getBitInBytes(tx_bit_pos, tx_bits, num_tx_bits))
+ {
+ dbv = 1;
+ on_bits |= (1<<(spi->mosi));
+ }
+ else
+ {
+ dbv = 0;
+ off_bits |= (1<<(spi->mosi));
+ }
+
+ if (spi->ss_pol) off_bits |= (1<<ss);
+ else on_bits |= (1<<ss);
+
+ wf[2][p].gpioOn = on_bits;
+ wf[2][p].gpioOff = off_bits;
+ wf[2][p].flags = 0;
+
+ if (spi->clk_us > spi->ss_us) wf[2][p].usDelay = spi->clk_us;
+ else wf[2][p].usDelay = spi->ss_us;
+
+ p++;
+
+ for (bit=1; bit<=bits; bit++)
+ {
+ for (halfbit=0; halfbit<2; halfbit++)
+ {
+ wf[2][p].usDelay = spi->clk_us;
+ wf[2][p].flags = 0;
+
+ on_bits = 0;
+ off_bits = 0;
+
+ if (read_cycle[halfbit])
+ {
+ if ((bit>=rx_bit_first) && (bit<=rx_bit_last))
+ wf[2][p].flags = WAVE_FLAG_READ;
+
+;
+ }
+ else
+ {
+ if (getBitInBytes(tx_bit_pos, tx_bits, num_tx_bits))
+ {
+ if (!dbv) on_bits |= (1<<(spi->mosi));
+ dbv = 1;
+ }
+ else
+ {
+ if (dbv) off_bits |= (1<<(spi->mosi));
+ dbv = 0;
+ }
+
+ ++tx_bit_pos;
+ }
+
+ if (rising_edge[halfbit]) on_bits |= (1<<(spi->clk));
+ else off_bits |= (1<<(spi->clk));
+
+ wf[2][p].gpioOn = on_bits;
+ wf[2][p].gpioOff = off_bits;
+
+ p++;
+ }
+ }
+
+ on_bits = 0;
+ off_bits = 0;
+
+ if (spi->ss_pol) on_bits |= (1<<ss);
+ else off_bits |= (1<<ss);
+
+ wf[2][p].gpioOn = on_bits;
+ wf[2][p].gpioOff = off_bits;
+ wf[2][p].flags = 0;
+ wf[2][p].usDelay = 0;
+
+ p++;
+
+ return waveMerge(p, wf[2]);
+}
/*-------------------------------------------------------------------------*/
secondaryClockInited = 1;
}
+ dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
+
+ dmaOut[DMA_CONBLK_AD] = 0;
+
cb = wave2Cbs(mode);
if (gpioCfg.dbgLevel >= DBG_SLOW_TICK)
alertBits &= ~BIT;
}
- monitorBits = alertBits | notifyBits | gpioGetSamples.bits;
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
return 0;
}
{
if (gpioNotify[i].state == PI_NOTIFY_CLOSED)
{
+ gpioNotify[i].state = PI_NOTIFY_OPENED;
slot = i;
break;
}
fd = open(name, O_RDWR|O_NONBLOCK);
if (fd < 0)
+ {
+ gpioNotify[slot].state = PI_NOTIFY_CLOSED;
SOFT_ERROR(PI_BAD_PATHNAME, "open %s failed (%m)", name);
+ }
- gpioNotify[slot].state = PI_NOTIFY_OPENED;
gpioNotify[slot].seqno = 0;
gpioNotify[slot].bits = 0;
gpioNotify[slot].fd = fd;
/* ----------------------------------------------------------------------- */
+static void intScriptBits(void)
+{
+ int i;
+ uint32_t bits;
+
+ bits = 0;
+
+ for (i=0; i<PI_SCRIPT_SLOTS; i++)
+ {
+ if (gpioScript[i].state == PI_SCRIPT_IN_USE)
+ {
+ bits |= gpioScript[i].waitBits;
+ }
+ }
+
+ scriptBits = bits;
+
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
+}
+
+
static void intNotifyBits(void)
{
int i;
notifyBits = bits;
- monitorBits = alertBits | notifyBits | gpioGetSamples.bits;
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
}
if (f) gpioGetSamples.bits = bits;
else gpioGetSamples.bits = 0;
- monitorBits = alertBits | notifyBits | gpioGetSamples.bits;
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
return 0;
}
if (f) gpioGetSamples.bits = bits;
else gpioGetSamples.bits = 0;
- monitorBits = alertBits | notifyBits | gpioGetSamples.bits;
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
return 0;
}
int gpioStoreScript(char *script)
{
- DBG(DBG_USER, "script=%s", script);
- DBG(DBG_USER, "l=%d s=%X e=%X",
- strlen(script), script[0], script[strlen(script)-1]);
+ gpioScript_t *s;
+ int status, slot, i;
+
+ DBG(DBG_USER, "script=[%s]", script);
CHECK_INITED;
- return PI_BAD_SCRIPT;
-}
+ slot = -1;
+
+ for (i=0; i<PI_SCRIPT_SLOTS; i++)
+ {
+ if (gpioScript[i].state == PI_SCRIPT_FREE)
+ {
+ gpioScript[i].state = PI_SCRIPT_RESERVED;
+ slot = i;
+ break;
+ }
+ }
+
+ if (slot < 0)
+ SOFT_ERROR(PI_NO_SCRIPT_ROOM, "no room for scripts");
+
+ s = &gpioScript[slot];
+
+ status = myParseScript(script, s);
+
+ if (status == 0)
+ {
+ s->request = PI_SCRIPT_HALT;
+ s->run_state = PI_SCRIPT_HALTED;
+
+ pthread_cond_init(&s->pthCond, NULL);
+ pthread_mutex_init(&s->pthMutex, NULL);
+
+ s->id = slot;
+
+ gpioScript[slot].state = PI_SCRIPT_IN_USE;
+
+ s->pthIdp = gpioStartThread(pthScript, s);
+
+ status = slot;
+ }
+ else
+ {
+ if (s->param) free(s->param);
+ s->param = NULL;
+ gpioScript[slot].state = PI_SCRIPT_FREE;
+ }
+
+ return status;
+}
/* ----------------------------------------------------------------------- */
-int gpioRunScript(int script_id)
+int gpioRunScript(int script_id, unsigned numParam, uint32_t *param)
{
- DBG(DBG_USER, "script_id=%d", script_id);
+ int status = 0;
+
+ DBG(DBG_USER, "script_id=%d numParam=%d param=%08X",
+ script_id, numParam, (uint32_t)param);
CHECK_INITED;
- return PI_BAD_SCRIPT_ID;
+ if (numParam > MAX_SCRIPT_PARAMS)
+ SOFT_ERROR(PI_TOO_MANY_PARAM, "bad number of parameters(%d)", numParam);
+
+ if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
+ {
+ pthread_mutex_lock(&gpioScript[script_id].pthMutex);
+
+ if (gpioScript[script_id].run_state == PI_SCRIPT_HALTED)
+ {
+ if ((numParam > 0) && (param != 0))
+ {
+ memcpy(gpioScript[script_id].param, param,
+ sizeof(uint32_t) * numParam);
+ }
+
+ gpioScript[script_id].request = PI_SCRIPT_RUN;
+
+ pthread_cond_signal(&gpioScript[script_id].pthCond);
+ }
+ else
+ {
+ status = PI_NOT_HALTED;
+ }
+
+ pthread_mutex_unlock(&gpioScript[script_id].pthMutex);
+
+ return status;
+ }
+ else return PI_BAD_SCRIPT_ID;
}
+/* ----------------------------------------------------------------------- */
+
+int gpioScriptStatus(int script_id, uint32_t *param)
+{
+ DBG(DBG_USER, "script_id=%d param=%08X", script_id, (uint32_t)param);
+
+ CHECK_INITED;
+
+ if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
+ {
+ if (param != 0)
+ {
+ memcpy(param, gpioScript[script_id].param,
+ sizeof(uint32_t) * MAX_SCRIPT_PARAMS);
+ }
+
+ return gpioScript[script_id].run_state;
+ }
+ else return PI_BAD_SCRIPT_ID;
+}
+
/* ----------------------------------------------------------------------- */
CHECK_INITED;
- return PI_BAD_SCRIPT_ID;
-}
+ if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
+ {
+ pthread_mutex_lock(&gpioScript[script_id].pthMutex);
+
+ gpioScript[script_id].request = PI_SCRIPT_HALT;
+ if (gpioScript[script_id].run_state == PI_SCRIPT_WAITING)
+ {
+ pthread_cond_signal(&gpioScript[script_id].pthCond);
+ }
+ pthread_mutex_unlock(&gpioScript[script_id].pthMutex);
+
+ return 0;
+ }
+ else return PI_BAD_SCRIPT_ID;
+}
/* ----------------------------------------------------------------------- */
CHECK_INITED;
- return PI_BAD_SCRIPT_ID;
+ if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
+ {
+ gpioScript[script_id].state = PI_SCRIPT_DYING;
+
+ pthread_mutex_lock(&gpioScript[script_id].pthMutex);
+
+ gpioScript[script_id].request = PI_SCRIPT_HALT;
+
+ if (gpioScript[script_id].run_state == PI_SCRIPT_WAITING)
+ {
+ pthread_cond_signal(&gpioScript[script_id].pthCond);
+ }
+
+ pthread_mutex_unlock(&gpioScript[script_id].pthMutex);
+
+ while (gpioScript[script_id].run_state == PI_SCRIPT_RUNNING)
+ {
+ myGpioSleep(0, 5000); /* give script time to halt */
+ }
+
+ gpioStopThread(gpioScript[script_id].pthIdp);
+
+ if (gpioScript[script_id].param) free(gpioScript[script_id].param);
+
+ gpioScript[script_id].param = NULL;
+
+ gpioScript[script_id].state = PI_SCRIPT_FREE;
+
+ return 0;
+ }
+ else return PI_BAD_SCRIPT_ID;
}
start = systReg[SYST_CLO];
- if (micros < 100) while ((systReg[SYST_CLO] - start) <= micros) ;
+ if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ;
else gpioSleep(PI_TIME_RELATIVE, (micros/MILLION), (micros%MILLION));
gpioCfg.showStats = value;
- DBG(DBG_MIN_LEVEL, "showStats is %u", value);
+ DBG(DBG_ALWAYS, "showStats is %u", value);
retVal = 0;
case 984762879:
- if (value < DBG_MIN_LEVEL) value = DBG_MIN_LEVEL;
+ if (value < DBG_ALWAYS) value = DBG_ALWAYS;
if (value > DBG_MAX_LEVEL) value = DBG_MAX_LEVEL;
gpioCfg.dbgLevel = value;
- DBG(DBG_MIN_LEVEL, "Debug level is %u", value);
+ DBG(DBG_ALWAYS, "Debug level is %u", value);
retVal = 0;
*/
/*
-This version is for pigpio version 12
+This version is for pigpio version 13
*/
#ifndef PIGPIO_H
#include <stdint.h>
#include <pthread.h>
-#define PIGPIO_VERSION 12
+#define PIGPIO_VERSION 13
/*-------------------------------------------------------------------------*/
gpioStoreScript Store a script.
gpioRunScript Run a stored script.
+gpioScriptStatus Get script status and parameters.
gpioStopScript Stop a running script.
gpioDeleteScript Delete a stored script.
extern "C" {
#endif
+typedef struct
+{
+ uint16_t func;
+ uint16_t size;
+} gpioHeader_t;
+
typedef struct
{
uint32_t cmd;
{
size_t size;
void *ptr;
- int data;
+ uint32_t data;
} gpioExtent_t;
typedef struct
uint32_t usDelay;
} gpioPulse_t;
+#define WAVE_FLAG_READ 1
+#define WAVE_FLAG_TICK 2
+
+typedef struct
+{
+ uint32_t gpioOn;
+ uint32_t gpioOff;
+ uint32_t usDelay;
+ uint32_t flags;
+} gpioWave_t;
+
+typedef struct
+{
+ int clk; /* gpio for clock */
+ int mosi; /* gpio for MOSI */
+ int miso; /* gpio for MISO */
+ int ss_pol; /* slave select off state */
+ int ss_us; /* delay after slave select */
+ int clk_pol; /* clock off state */
+ int clk_pha; /* clock phase */
+ int clk_us; /* clock micros */
+} gpioSPI_t;
+
typedef void (*gpioAlertFunc_t) (int gpio,
int level,
uint32_t tick);
handle.
*/
+#define PI_NOTIFY_SLOTS 32
+
/*-------------------------------------------------------------------------*/
the same waveform.
*/
-#define PI_WAVE_BLOCKS 3
+#define PI_WAVE_BLOCKS 4
#define PI_WAVE_MAX_PULSES (PI_WAVE_BLOCKS * 3000)
#define PI_WAVE_MAX_CHARS (PI_WAVE_BLOCKS * 256)
#define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */
-
-
/*-------------------------------------------------------------------------*/
int gpioWaveTxStart(unsigned mode);
/*-------------------------------------------------------------------------*/
otherwise PI_BAD_SCRIPT.
*/
+#define MAX_SCRIPT_LABELS 50
+#define MAX_SCRIPT_VARS 150
+#define MAX_SCRIPT_PARAMS 10
/* ----------------------------------------------------------------------- */
-int gpioRunScript(int script_id);
+int gpioRunScript(int script_id, unsigned numParam, uint32_t *param);
/* ----------------------------------------------------------------------- */
/* This function runs a stored script.
- The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+ The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or
+ PI_TOO_MANY_PARAM.
+
+ param is an array of up to 10 parameters which may be referenced in
+ the script as param 0 to param 9.
+*/
+
+
+
+/* ----------------------------------------------------------------------- */
+int gpioScriptStatus(int script_id, uint32_t *param);
+/* ----------------------------------------------------------------------- */
+/* This function returns the run status of a stored script as well as
+ the current values of parameters 0 to 9.
+
+ The function returns greater than or equal to 0 if OK,
+ otherwise PI_BAD_SCRIPT_ID.
+
+ The run status may be
+
+ PI_SCRIPT_HALTED
+ PI_SCRIPT_RUNNING
+ PI_SCRIPT_WAITING
+ PI_SCRIPT_FAILED
+
+ The current value of script parameters 0 to 9 are returned in param.
*/
+/* script status */
+
+#define PI_SCRIPT_HALTED 0
+#define PI_SCRIPT_RUNNING 1
+#define PI_SCRIPT_WAITING 2
+#define PI_SCRIPT_FAILED 3
+
/* ----------------------------------------------------------------------- */
Not intended for general use.
*/
+/*-------------------------------------------------------------------------*/
+int gpioWaveAddSPI(
+ gpioSPI_t *spi,
+ unsigned offset,
+ unsigned ss,
+ uint8_t *tx_bits,
+ unsigned num_tx_bits,
+ unsigned rx_bit_first,
+ unsigned rx_bit_last,
+ unsigned bits);
+/*-------------------------------------------------------------------------*/
+/* This function adds a waveform representing SPI data to the
+ existing waveform (if any). The SPI data starts offset microseconds
+ from the start of the waveform. ss is the slave select gpio. bits bits
+ are transferred. num_tx_bits are transmitted starting at the first bit.
+ The bits to transmit are read, most significant bit first, from tx_bits.
+ Gpio reads are made from rx_bit_first to rx_bit_last.
+ Returns the new total number of pulses in the current waveform if OK,
+ otherwise PI_BAD_USER_GPIO, PI_BAD_SER_OFFSET, or PI_TOO_MANY_PULSES.
+*/
+
+
+/* ----------------------------------------------------------------------- */
+uint32_t waveGetRawOut(int pos);
+/* ----------------------------------------------------------------------- */
+/* Gets the wave output parameter stored at pos.
+ Not intended for general use.
+*/
+
+/* ----------------------------------------------------------------------- */
+void waveSetRawOut(int pos, uint32_t value);
+/* ----------------------------------------------------------------------- */
+/* Sets the wave output parameter stored at pos to value.
+ Not intended for general use.
+*/
+
+/* ----------------------------------------------------------------------- */
+uint32_t waveGetRawIn(int pos);
+/* ----------------------------------------------------------------------- */
+/* Gets the wave input value parameter stored at pos.
+ Not intended for general use.
+*/
+
+
+/* ----------------------------------------------------------------------- */
+void waveSetRawIn(int pos, uint32_t value);
+/* ----------------------------------------------------------------------- */
+/* Sets the wave input value stored at pos to value.
+ Not intended for general use.
+*/
+
+/*-------------------------------------------------------------------------*/
+int getBitInBytes(int bitPos, uint8_t *buf, int numBits);
/*-------------------------------------------------------------------------*/
-void gpioWaveDump(void);
+/* Returns the value of the bit bitPos bits from the start of buf. Returns
+ 0 if bitPos is greater than or equal to numBits.
+*/
+
+/* ----------------------------------------------------------------------- */
+void putBitInBytes(int bitPos, uint8_t *buf, int val);
/*-------------------------------------------------------------------------*/
-/* Used to print a readable version of the current waveform to stdout.
+/* Sets the bit bitPos bits from the start of buf to val.
+*/
+
+/*-------------------------------------------------------------------------*/
+double time_time(void);
+/*-------------------------------------------------------------------------*/
+/* Return the current time in seconds since the Epoch.
+*/
+
+
+/*-------------------------------------------------------------------------*/
+void time_sleep(double seconds);
+/*-------------------------------------------------------------------------*/
+/* Delay execution for a given number of seconds
+*/
+
+
+/*-------------------------------------------------------------------------*/
+void gpioDumpWave(void);
+/*-------------------------------------------------------------------------*/
+/* Used to print a readable version of the current waveform to stderr.
+ Not intended for general use.
+*/
+
+
+/*-------------------------------------------------------------------------*/
+void gpioDumpScript(int s);
+/*-------------------------------------------------------------------------*/
+/* Used to print a readable version of a script to stderr.
Not intended for general use.
*/
#define PI_CMD_SLRO 42
#define PI_CMD_SLR 43
#define PI_CMD_SLRC 44
+#define PI_CMD_PROCP 45
+#define PI_CMD_MICRO 46
+#define PI_CMD_MILLI 47
+
/*
The following command only works on the socket interface.
#define PI_CMD_NOIB 99
+/* pseudo commands */
+
+#define PI_CMD_SCRIPT 800
+
+#define PI_CMD_ADDI 800
+#define PI_CMD_ADDV 801
+#define PI_CMD_ANDI 802
+#define PI_CMD_ANDV 803
+#define PI_CMD_CALL 804
+#define PI_CMD_CMPI 805
+#define PI_CMD_CMPV 806
+#define PI_CMD_DCRA 807
+#define PI_CMD_DCRV 808
+#define PI_CMD_HALT 809
+#define PI_CMD_INRA 810
+#define PI_CMD_INRV 811
+#define PI_CMD_JM 812
+#define PI_CMD_JMP 813
+#define PI_CMD_JNZ 814
+#define PI_CMD_JP 815
+#define PI_CMD_JZ 816
+#define PI_CMD_LABEL 817
+#define PI_CMD_LDAI 818
+#define PI_CMD_LDAP 819
+#define PI_CMD_LDAV 820
+#define PI_CMD_LDPA 821
+#define PI_CMD_LDVA 822
+#define PI_CMD_LDVI 823
+#define PI_CMD_LDVV 824
+#define PI_CMD_ORI 827
+#define PI_CMD_ORV 828
+#define PI_CMD_POPA 829
+#define PI_CMD_POPV 830
+#define PI_CMD_PUSHA 831
+#define PI_CMD_PUSHV 832
+#define PI_CMD_RET 833
+#define PI_CMD_RAL 834
+#define PI_CMD_RAR 835
+#define PI_CMD_SUBI 836
+#define PI_CMD_SUBV 837
+#define PI_CMD_SWAPA 838
+#define PI_CMD_SWAPV 839
+#define PI_CMD_SYS 840
+#define PI_CMD_WAITI 841
+#define PI_CMD_WAITV 842
+#define PI_CMD_XORI 843
+#define PI_CMD_XORV 844
/*-------------------------------------------------------------------------*/
#define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */
#define PI_GPIO_IN_USE -50 /* gpio already in use */
#define PI_BAD_SERIAL_COUNT -51 /* must read at least a byte at a time */
-
+#define PI_BAD_PARAM_NUM -52 /* script parameter must be 0-9 */
+#define PI_DUP_LABEL -53 /* script has duplicate label */
+#define PI_TOO_MANY_LABELS -54 /* script has too many labels */
+#define PI_BAD_SCRIPT_CMD -55 /* illegal script command */
+#define PI_BAD_VAR_NUM -56 /* script variable must be 0-149 */
+#define PI_NO_SCRIPT_ROOM -57 /* no more room for scripts */
+#define PI_NO_MEMORY -58 /* can't allocate temporary memory */
+#define PI_SOCK_READ_FAILED -59 /* socket read failed */
+#define PI_SOCK_WRIT_FAILED -60 /* socket write failed */
+#define PI_TOO_MANY_PARAM -61 /* too many script parameters > 10 */
+#define PI_NOT_HALTED -62 /* script already running or failed */
/*-------------------------------------------------------------------------*/
import os
import atexit
-VERSION = "1.3"
+VERSION = "1.4"
# gpio levels
PUD_DOWN = 1
PUD_UP = 2
+# script run status
+
+PI_SCRIPT_HALTED =0
+PI_SCRIPT_RUNNING=1
+PI_SCRIPT_WAITING=2
+PI_SCRIPT_FAILED =3
+
# pigpio command numbers
_PI_CMD_MODES= 0
_PI_CMD_SLRO= 42
_PI_CMD_SLR= 43
_PI_CMD_SLRC= 44
+_PI_CMD_PROCP=45
_PI_CMD_NOIB= 99
PI_BAD_WAVE_BAUD =-35
PI_TOO_MANY_PULSES =-36
PI_TOO_MANY_CHARS =-37
-PI_NOT_SERIAL_GPIO =-38
+PI_NOT_SERIAL_GPIO =-38
_PI_BAD_SERIAL_STRUC=-39
_PI_BAD_SERIAL_BUF =-40
PI_NOT_PERMITTED =-41
PI_BAD_SCRIPT_ID =-48
PI_BAD_SER_OFFSET =-49
PI_GPIO_IN_USE =-50
+PI_BAD_SERIAL_COUNT =-51
+PI_BAD_PARAM_NUM =-52
+PI_DUP_LABEL =-53
+PI_TOO_MANY_LABELS =-54
+PI_BAD_SCRIPT_CMD =-55
+PI_BAD_VAR_NUM =-56
+PI_NO_SCRIPT_ROOM =-57
+PI_NO_MEMORY =-58
+PI_SOCK_READ_FAILED =-59
+PI_SOCK_WRIT_FAILED =-60
+PI_TOO_MANY_PARAM =-61
+PI_NOT_HALTED =-62
# pigpio error text
[PI_BAD_SCRIPT_ID , "unknown script id"],
[PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"],
[PI_GPIO_IN_USE , "gpio already in use"],
+ [PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"],
+ [PI_BAD_PARAM_NUM , "script parameter must be 0-9"],
+ [PI_DUP_LABEL , "script has duplicate label"],
+ [PI_TOO_MANY_LABELS , "script has too many labels"],
+ [PI_BAD_SCRIPT_CMD , "illegal script command"],
+ [PI_BAD_VAR_NUM , "script variable must be 0-149"],
+ [PI_NO_SCRIPT_ROOM , "no more room for scripts"],
+ [PI_NO_MEMORY , "can't allocate temporary memory"],
+ [PI_SOCK_READ_FAILED , "socket read failed"],
+ [PI_SOCK_WRIT_FAILED , "socket write failed"],
+ [PI_TOO_MANY_PARAM , "too many script parameters (> 10)"],
+ [PI_NOT_HALTED , "script already running or failed"],
+
]
_control = None
sock: command socket.
cmd: the command to be executed.
- p1: command paramter 1 (if applicable).
- p2: command paramter 2 (if applicable).
+ p1: command parameter 1 (if applicable).
+ p2: command parameter 2 (if applicable).
"""
if sock is not None:
sock.send(struct.pack('IIII', cmd, p1, p2, 0))
sock: command socket.
cmd: the command to be executed.
- p1: command paramter 1 (if applicable).
- p2: command paramter 2 (if applicable).
+ p1: command parameter 1 (if applicable).
+ p2: command parameter 2 (if applicable).
extents: additional data blocks
"""
if sock is not None:
return _u2i(_pigpio_command_ext(
_control, _PI_CMD_PROC, len(script), 0, script))
-def run_script(script_id):
+def run_script(script_id, params=None):
"""
Runs a stored script.
Returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
script_id: script_id of stored script.
+ params: up to 10 parameters required by the script.
+ """
+ # I p1 script id
+ # I p2 number of parameters (0-10)
+ ## (optional) extension ##
+ # I[] params
+
+ if params is not None:
+ msg = ""
+ for p in params:
+ msg += struct.pack("I", p)
+ nump = len(params)
+ extents = [msg]
+ else:
+ nump = 0
+ extents = []
+
+ return _u2i(_pigpio_command_ext(
+ _control, _PI_CMD_PROCR, script_id, nump, extents))
+
+def script_status(script_id):
+ """
+ This function returns the run status of a stored script as well as
+ the current values of parameters 0 to 9.
+
+ The function returns greater than or equal to 0 if OK,
+ otherwise PI_BAD_SCRIPT_ID.
+
+ The run status may be
+
+ PI_SCRIPT_HALTED
+ PI_SCRIPT_RUNNING
+ PI_SCRIPT_WAITING
+ PI_SCRIPT_FAILED
+
+ It returns a tuple of run status and a parameter list tuple. If the script
+ does not exist a negative error code will be returned in which
+ case the parameter tuple will be empty.
"""
- return _u2i(_pigpio_command(_control, _PI_CMD_PROCR, script_id, 0))
+ status = _u2i(_pigpio_command(_control, _PI_CMD_PROCP, script_id, 0))
+ if status >= 0:
+ param = struct.unpack('IIIIIIIIII', _control.recv(40))
+ return status, param
+ return status, ()
def stop_script(script_id):
"""
print("Did you specify the correct Pi host/port in the")
print("pigpio.start() function? E.g. pigpio.start('soft', 8888))")
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
- raise
+ return False
+ return True
def stop():
"""Release pigpio resources.
For more information, please refer to <http://unlicense.org/>
*/
-/* PIGPIOD_IF_VERSION 3 */
+/* PIGPIOD_IF_VERSION 4 */
#include <stdio.h>
#include <stdlib.h>
int set_pull_up_down(unsigned gpio, unsigned pud)
{return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);}
-int read_gpio(unsigned gpio)
+int gpio_read(unsigned gpio)
{return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);}
-int write_gpio(unsigned gpio, unsigned level)
+int gpio_write(unsigned gpio, unsigned level)
{return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);}
int set_PWM_dutycycle(unsigned user_gpio, unsigned dutycycle)
uint32_t get_hardware_revision(void)
{return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);}
-unsigned get_pigpio_version(void)
+uint32_t get_pigpio_version(void)
{return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);}
int wave_clear(void)
return pigpio_command_ext(gPigCommand, PI_CMD_PROC, len, 0, 1, ext);
}
-int run_script(unsigned script_id)
- {return pigpio_command(gPigCommand, PI_CMD_PROCR, script_id, 0);}
+int run_script(unsigned script_id, unsigned numPar, uint32_t *param)
+{
+ gpioExtent_t ext[1];
+
+ /*
+ p1=script id
+ p2=number of parameters
+ ## extension ##
+ uint32_t[] parameters
+ */
+
+ ext[0].size = sizeof(uint32_t)*numPar;
+ ext[0].ptr = param;
+
+ return pigpio_command_ext
+ (gPigCommand, PI_CMD_PROCR, script_id, numPar, 1, ext);
+}
+
+int script_status(int script_id, uint32_t *param)
+{
+ int status;
+ uint32_t p[MAX_SCRIPT_PARAMS];
+
+ status = pigpio_command(gPigCommand, PI_CMD_PROCP, script_id, 0);
+
+ if (status >= 0)
+ {
+ /* get the data */
+ recv(gPigCommand, p, sizeof(p), MSG_WAITALL);
+
+ if (param) memcpy(param, p, sizeof(p));
+ }
+
+ return status;
+}
int stop_script(unsigned script_id)
{return pigpio_command(gPigCommand, PI_CMD_PROCS, script_id, 0);}
#include "pigpio.h"
-#define PIGPIOD_IF_VERSION 3
+#define PIGPIOD_IF_VERSION 4
typedef enum
{
The function is passed the single argument arg.
The thread can be cancelled by passing the pointer to pthread_t to
- gpioStopThread().
+ stop_thread().
*/
void stop_thread(pthread_t *pth);
No value is returned.
- The thread to be stopped should have been started with gpioStartThread().
+ The thread to be stopped should have been started with start_thread().
*/
int pigpio_start(char *addrStr, char *portStr);
pud: PUD_UP, PUD_DOWN, PUD_OFF.
*/
-int read_gpio(unsigned gpio);
+int gpio_read(unsigned gpio);
/* Read the gpio level.
Returns the gpio level if OK, otherwise PI_BAD_GPIO.
gpio:0-53.
*/
-int write_gpio(unsigned gpio, unsigned level);
+int gpio_write(unsigned gpio, unsigned level);
/*
Write the gpio level.
hexadecimal number the function returns 0.
*/
+uint32_t get_pigpio_version(void);
+/*
+ Returns the pigpio version.
+*/
+
+
int wave_clear(void);
/* This function initialises a new waveform.
otherwise PI_BAD_SCRIPT.
*/
-int run_script(unsigned script_id);
+int run_script(unsigned script_id, unsigned numPar, uint32_t *param);
/* This function runs a stored script.
- The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+ The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or
+ PI_TOO_MANY_PARAM
+
+ param is an array of up to 10 parameters which may be referenced in
+ the script as param 0 to param 9..
+*/
+
+int script_status(int script_id, uint32_t *param);
+/* This function returns the run status of a stored script as well
+ as the current values of parameters 0 to 9.
+
+ The function returns greater than or equal to 0 if OK,
+ otherwise PI_BAD_SCRIPT_ID.
+
+ The run status may be
+
+ PI_SCRIPT_HALTED
+ PI_SCRIPT_RUNNING
+ PI_SCRIPT_WAITING
+ PI_SCRIPT_FAILED
+
+ The current value of script parameters 0 to 9 are returned in param.
*/
int stop_script(unsigned script_id);
or PI_GPIO_IN_USE.
The serial data is returned in a cyclic buffer and is read using
- gpioSerialRead().
+ serial_read().
It is the caller's responsibility to read data from the cyclic buffer
in a timely fashion.
*/
/*
-This version is for pigpio version 12+
+This version is for pigpio version 13+
*/
#include <stdio.h>
the commands available from pigpio.
*/
+char command_buf[8192];
+char response_buf[8192];
+
void fatal(char *fmt, ...)
{
char buf[128];
return sock;
}
+void print_result(int sock, int rv, cmdCmd_t cmd)
+{
+ int i, r;
+ uint32_t *p;
+
+ r = cmd.res;
+
+ switch (rv)
+ {
+ case 0:
+ if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
+ break;
+
+ case 1:
+ if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
+ break;
+
+ case 2:
+ if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
+ else printf("%d\n", r);
+ break;
+
+ case 3:
+ printf("%08X\n", cmd.res);
+ break;
+
+ case 4:
+ printf("%u\n", cmd.res);
+ break;
+
+ case 5:
+ printf(cmdUsage);
+ break;
+
+ case 6: /* SLR */
+ if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
+ else if (r > 0)
+ {
+ printf("%s", response_buf);
+ }
+ break;
+
+ case 7: /* PROCP */
+ if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
+ else
+ {
+ printf("%d", r);
+
+ p = (uint32_t *)response_buf;
+
+ for (i=0; i<MAX_SCRIPT_PARAMS; i++)
+ {
+ printf(" %d", p[i]);
+ }
+
+ printf("\n");
+ }
+ break;
+ }
+}
+
+void get_extensions(int sock, int command, int res)
+{
+ switch (command)
+ {
+ case PI_CMD_PROCP: /* PROCP */
+ if (res >= 0)
+ {
+ recv(sock,
+ response_buf,
+ sizeof(uint32_t)*MAX_SCRIPT_PARAMS,
+ MSG_WAITALL);
+ }
+ break;
+
+ case PI_CMD_SLR: /* SLR */
+ if (res > 0)
+ {
+ recv(sock, response_buf, res, MSG_WAITALL);
+ response_buf[res] = 0;
+ }
+ break;
+ }
+}
+
+void put_extensions(int sock, int command, uint32_t *p, void *v[])
+{
+ switch (command)
+ {
+ case PI_CMD_PROC:
+ /*
+ p1=script length w[1]
+ p2=0
+ ## extension ##
+ char[] script v[1]
+ */
+ send(sock, v[1], p[1], 0);
+ break;
+
+ case PI_CMD_PROCR:
+ /*
+ p1=script id w[1]
+ p2=numParam w[2]
+ ## extension ##
+ int[] param v[1]
+ */
+ if (p[2]) send(sock, v[1], p[2]*sizeof(uint32_t), 0);
+ break;
+
+ case PI_CMD_TRIG:
+ /*
+ p1=user_gpio w[1]
+ p2=pulseLen w[2]
+ ## extension ##
+ unsigned level w[3]
+ */
+ send(sock, &p[3], 4, 0);
+ break;
+
+ case PI_CMD_WVAG:
+ /*
+ p1=pulses w[1]
+ p2=0
+ ## extension ##
+ int[] param v[1]
+ */
+ if (p[1]) send(sock, v[1], p[1]*sizeof(gpioPulse_t), 0);
+ break;
+
+ case PI_CMD_WVAS:
+ /*
+ p1=user_gpio w[1]
+ p2=numChar w[4]
+ ## extension ##
+ unsigned baud w[2]
+ unsigned offset w[3]
+ char[] str v[1]
+ */
+ send(sock, &p[2], 4, 0);
+ send(sock, &p[3], 4, 0);
+ send(sock, v[1], p[4], 0);
+ break;
+ }
+
+}
+
int main(int argc , char *argv[])
{
- int sock, r, idx, i;
+ int sock, command;
+ int idx, i, pp, l, len;
cmdCmd_t cmd;
- gpioExtent_t ext[3];
- char buf[1024];
+ uint32_t p[10];
+ void *v[10];
+ gpioCtlParse_t ctl;
sock = openSocket();
if (sock != -1)
{
- switch(argc)
- {
- case 1:
- exit(0);
-
- case 2:
- sprintf(buf, "%10s", argv[1]);
- break;
+ command_buf[0] = 0;
+ l = 0;
+ pp = 0;
- case 3:
- sprintf(buf, "%10s %10s", argv[1], argv[2]);
- break;
-
- case 4:
- sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
- break;
+ for (i=1; i<argc; i++)
+ {
+ l += (strlen(argv[i]) + 1);
+ if (l < sizeof(command_buf))
+ {sprintf(command_buf+pp, "%s ", argv[i]); pp=l;}
+ }
- case 5:
- sprintf(buf, "%10s %10s %10s %10s",
- argv[1], argv[2], argv[3], argv[4]);
- break;
+ if (pp) {command_buf[--pp] = 0;}
- case 6:
- sprintf(buf, "%10s %10s %10s %10s %10s",
- argv[1], argv[2], argv[3], argv[4], argv[5]);
- break;
+ ctl.flags = 0;
+ ctl.eaten = 0;
- default:
- fatal("what? 'pigs h' for help");
- }
+ len = strlen(command_buf);
+ idx = 0;
- if ((idx=cmdParse(buf, &cmd, argc, argv, ext)) >= 0)
+ while ((idx >= 0) && (ctl.eaten < len))
{
- if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+ if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0)
{
- /* send extensions */
+ command = p[0];
- for (i=0; i<cmdInfo[idx].ext; i++)
+ if (command < PI_CMD_SCRIPT)
{
- send(sock, ext[i].ptr, ext[i].size, 0);
- }
+ cmd.cmd = command;
+ cmd.p1 = p[1];
+ cmd.p2 = p[2];
- if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) ==
- sizeof(cmdCmd_t))
- {
- switch (cmdInfo[idx].rv)
+ switch (command)
{
- case 0:
- r = cmd.res;
- if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
- break;
+ case PI_CMD_WVAS:
+ cmd.p2 = p[4];
+ break;
- case 1:
- r = cmd.res;
- if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
- break;
-
- case 2:
- r = cmd.res;
- if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
- else printf("%d\n", r);
- break;
-
- case 3:
- printf("%08X\n", cmd.res);
+ case PI_CMD_PROC:
+ cmd.p2 = 0;
break;
+ }
- case 4:
- printf("%u\n", cmd.res);
- break;
+ if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+ {
+ put_extensions(sock, command, p, v);
- case 5:
- printf(cmdUsage);
- break;
+ if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) ==
+ sizeof(cmdCmd_t))
+ {
+ get_extensions(sock, command, cmd.res);
- case 6:
- r = cmd.res;
- if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
- else if (r > 0)
- {
- recv(sock, &buf, r, MSG_WAITALL);
- buf[r] = 0;
- printf("%s", buf);
- }
- break;
+ print_result(sock, cmdInfo[idx].rv, cmd);
+ }
+ else fatal("recv failed, %m");
}
+ else fatal("send failed, %m");
}
- else fatal("recv failed, %m");
+ else fatal("%s only allowed within a script", cmdInfo[idx].name);
}
- else fatal("send failed, %m");
+ else fatal("%s? pigs h for help", cmdStr());
}
- else fatal("what? 'pigs h' for help");
}
else fatal("connect failed, %m");
from distutils.core import setup
setup(name='pigpio',
- version='1.3',
+ version='1.4',
author='joan',
- author_email='joan@abyz.me.uk',
+ author_email='joan@abyz.co.uk',
maintainer='joan',
- maintainer_email='joan@abyz.me.uk',
+ maintainer_email='joan@abyz.co.uk',
url='http://abyz.co.uk/rpi/pigpio/python.html/',
description='Raspberry Pi gpio module',
- long_description='Raspberry Pi Python module for access to the pigpio daemon',
+ long_description='Raspberry Pi Python module to access the pigpio daemon',
download_url='http://abyz.co.uk/rpi/pigpio/pigpio.zip',
- license='TBD',
+ license='unlicense.org',
py_modules=['pigpio']
)
--- /dev/null
+/*
+gcc -o x_pigpio x_pigpio.c -lpigpio -lrt -lpthread
+sudo ./x_pigpio
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pigpio.h"
+
+#define USERDATA 18249013
+
+#define GPIO 4
+
+void CHECK(int t, int st, int got, int expect, int pc, char *desc)
+{
+ if ((got >= (((1E2-pc)*expect)/1E2)) && (got <= (((1E2+pc)*expect)/1E2)))
+ {
+ printf("TEST %2d.%-2d PASS (%s: %d)\n", t, st, desc, expect);
+ }
+ else
+ {
+ fprintf(stderr,
+ "TEST %2d.%-2d FAILED got %d (%s: %d)\n",
+ t, st, got, desc, expect);
+ }
+}
+
+void t0()
+{
+ printf("Version.\n");
+
+ printf("pigpio version %d.\n", gpioVersion());
+
+ printf("Hardware revision %d.\n", gpioHardwareRevision());
+}
+
+void t1()
+{
+ int v;
+
+ printf("Mode/PUD/read/write tests.\n");
+
+ gpioSetMode(GPIO, PI_INPUT);
+ v = gpioGetMode(GPIO);
+ CHECK(1, 1, v, 0, 0, "set mode, get mode");
+
+ gpioSetPullUpDown(GPIO, PI_PUD_UP);
+ v = gpioRead(GPIO);
+ CHECK(1, 2, v, 1, 0, "set pull up down, read");
+
+ gpioSetPullUpDown(GPIO, PI_PUD_DOWN);
+ v = gpioRead(GPIO);
+ CHECK(1, 3, v, 0, 0, "set pull up down, read");
+
+ gpioWrite(GPIO, PI_LOW);
+ v = gpioGetMode(GPIO);
+ CHECK(1, 4, v, 1, 0, "write, get mode");
+
+ v = gpioRead(GPIO);
+ CHECK(1, 5, v, 0, 0, "read");
+
+ gpioWrite(GPIO, PI_HIGH);
+ v = gpioRead(GPIO);
+ CHECK(1, 6, v, 1, 0, "write, read");
+}
+
+int t2_count=0;
+
+void t2cb(int gpio, int level, uint32_t tick)
+{
+ t2_count++;
+}
+
+void t2()
+{
+ int f, r, rr, oc;
+
+ printf("PWM dutycycle/range/frequency tests.\n");
+
+ gpioSetPWMrange(GPIO, 255);
+ gpioSetPWMfrequency(GPIO, 0);
+ f = gpioGetPWMfrequency(GPIO);
+ CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency");
+
+ gpioSetAlertFunc(GPIO, t2cb);
+
+ gpioPWM(GPIO, 0);
+ time_sleep(0.5); /* allow old notifications to flush */
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback");
+
+ gpioPWM(GPIO, 128);
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback");
+
+ gpioSetPWMfrequency(GPIO, 100);
+ f = gpioGetPWMfrequency(GPIO);
+ CHECK(2, 4, f, 100, 0, "set/get PWM frequency");
+
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 5, f, 400, 1, "callback");
+
+ gpioSetPWMfrequency(GPIO, 1000);
+ f = gpioGetPWMfrequency(GPIO);
+ CHECK(2, 6, f, 1000, 0, "set/get PWM frequency");
+
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 7, f, 4000, 1, "callback");
+
+ r = gpioGetPWMrange(GPIO);
+ CHECK(2, 8, r, 255, 0, "get PWM range");
+
+ rr = gpioGetPWMrealRange(GPIO);
+ CHECK(2, 9, rr, 200, 0, "get PWM real range");
+
+ gpioSetPWMrange(GPIO, 2000);
+ r = gpioGetPWMrange(GPIO);
+ CHECK(2, 10, r, 2000, 0, "set/get PWM range");
+
+ rr = gpioGetPWMrealRange(GPIO);
+ CHECK(2, 11, rr, 200, 0, "get PWM real range");
+
+ gpioPWM(GPIO, 0);
+}
+
+int t3_val = USERDATA;
+int t3_reset=1;
+int t3_count=0;
+uint32_t t3_tick=0;
+float t3_on=0.0;
+float t3_off=0.0;
+
+void t3cbf(int gpio, int level, uint32_t tick, void *userdata)
+{
+ static int unreported = 1;
+
+ uint32_t td;
+ int *val;
+
+ val = userdata;
+
+ if (*val != USERDATA)
+ {
+ if (unreported)
+ {
+ fprintf
+ (
+ stderr,
+ "unexpected userdata %d (expected %d)\n",
+ *val, USERDATA
+ );
+ }
+ unreported = 0;
+ }
+
+ if (t3_reset)
+ {
+ t3_count = 0;
+ t3_on = 0.0;
+ t3_off = 0.0;
+ t3_reset = 0;
+ }
+ else
+ {
+ td = tick - t3_tick;
+
+ if (level == 0) t3_on += td;
+ else t3_off += td;
+ }
+
+ t3_count ++;
+ t3_tick = tick;
+}
+
+void t3()
+{
+ int f, rr;
+
+ float on, off;
+
+ int t;
+
+ int pw[3]={500, 1500, 2500};
+ int dc[4]={20, 40, 60, 80};
+
+ printf("PWM/Servo pulse accuracy tests.\n");
+
+ gpioSetAlertFuncEx(GPIO, t3cbf, &t3_val); /* test extended alert */
+
+ for (t=0; t<3; t++)
+ {
+ gpioServo(GPIO, pw[t]);
+ time_sleep(1);
+ t3_reset = 1;
+ time_sleep(4);
+ on = t3_on;
+ off = t3_off;
+ CHECK(3, 1+t, (1E3*(on+off))/on, 2E7/pw[t], 1,
+ "set servo pulsewidth");
+ }
+
+ gpioServo(GPIO, 0);
+ gpioSetPWMfrequency(GPIO, 1000);
+ f = gpioGetPWMfrequency(GPIO);
+ CHECK(3, 4, f, 1000, 0, "set/get PWM frequency");
+
+ rr = gpioSetPWMrange(GPIO, 100);
+ CHECK(3, 5, rr, 200, 0, "set PWM range");
+
+ for (t=0; t<4; t++)
+ {
+ gpioPWM(GPIO, dc[t]);
+ time_sleep(1);
+ t3_reset = 1;
+ time_sleep(2);
+ on = t3_on;
+ off = t3_off;
+ CHECK(3, 6+t, (1E3*on)/(on+off), 1E1*dc[t], 1,
+ "set PWM dutycycle");
+ }
+
+ gpioPWM(GPIO, 0);
+}
+
+void t4()
+{
+ int h, e, f, n, s, b, l, seq_ok, toggle_ok;
+ gpioReport_t r;
+ char p[32];
+
+ printf("Pipe notification tests.\n");
+
+ gpioSetPWMfrequency(GPIO, 0);
+ gpioPWM(GPIO, 0);
+ gpioSetPWMrange(GPIO, 100);
+
+ h = gpioNotifyOpen();
+ e = gpioNotifyBegin(h, (1<<4));
+ CHECK(4, 1, e, 0, 0, "notify open/begin");
+
+ time_sleep(1);
+
+ sprintf(p, "/dev/pigpio%d", h);
+
+ f = open(p, O_RDONLY);
+
+ gpioPWM(GPIO, 50);
+ time_sleep(4);
+ gpioPWM(GPIO, 0);
+
+ e = gpioNotifyPause(h);
+ CHECK(4, 2, e, 0, 0, "notify pause");
+
+ e = gpioNotifyClose(h);
+ CHECK(4, 3, e, 0, 0, "notify close");
+
+ n = 0;
+ s = 0;
+ l = 0;
+ seq_ok = 1;
+ toggle_ok = 1;
+
+ while (1)
+ {
+ b = read(f, &r, 12);
+ if (b == 12)
+ {
+ if (s != r.seqno) seq_ok = 0;
+
+ if (n) if (l != (r.level&(1<<4))) toggle_ok = 0;
+
+ if (r.level&(1<<4)) l = 0;
+ else l = (1<<4);
+
+ s++;
+ n++;
+
+ // printf("%d %d %d %X\n", r.seqno, r.flags, r.tick, r.level);
+ }
+ else break;
+ }
+
+ close(f);
+
+ CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok");
+
+ CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok");
+
+ CHECK(4, 6, n, 80, 10, "number of notifications");
+}
+
+int t5_count = 0;
+
+void t5cbf(int gpio, int level, uint32_t tick)
+{
+ if (level == 0) t5_count++; /* falling edges */
+}
+
+void t5()
+{
+ int BAUD=4800;
+
+ char *TEXT=
+"\n\
+Now is the winter of our discontent\n\
+Made glorious summer by this sun of York;\n\
+And all the clouds that lour'd upon our house\n\
+In the deep bosom of the ocean buried.\n\
+Now are our brows bound with victorious wreaths;\n\
+Our bruised arms hung up for monuments;\n\
+Our stern alarums changed to merry meetings,\n\
+Our dreadful marches to delightful measures.\n\
+Grim-visaged war hath smooth'd his wrinkled front;\n\
+And now, instead of mounting barded steeds\n\
+To fright the souls of fearful adversaries,\n\
+He capers nimbly in a lady's chamber\n\
+To the lascivious pleasing of a lute.\n\
+";
+
+ gpioPulse_t wf[] =
+ {
+ {1<<GPIO, 0, 10000},
+ {0, 1<<GPIO, 30000},
+ {1<<GPIO, 0, 60000},
+ {0, 1<<GPIO, 100000},
+ };
+
+ int e, oc, c;
+
+ char text[2048];
+
+ printf("Waveforms & serial read/write tests.\n");
+
+ gpioSetAlertFunc(GPIO, t5cbf);
+
+ gpioSetMode(GPIO, PI_OUTPUT);
+
+ e = gpioWaveClear();
+ CHECK(5, 1, e, 0, 0, "callback, set mode, wave clear");
+
+ e = gpioWaveAddGeneric(4, wf);
+ CHECK(5, 2, e, 4, 0, "pulse, wave add generic");
+
+ e = gpioWaveTxStart(PI_WAVE_MODE_REPEAT);
+ CHECK(5, 3, e, 9, 0, "wave tx repeat");
+
+ oc = t5_count;
+ time_sleep(5);
+ c = t5_count - oc;
+ CHECK(5, 4, c, 50, 1, "callback");
+
+ e = gpioWaveTxStop();
+ CHECK(5, 5, e, 0, 0, "wave tx stop");
+
+ /* gpioSerialReadOpen changes the alert function */
+
+ e = gpioSerialReadOpen(GPIO, BAUD);
+ CHECK(5, 6, e, 0, 0, "serial read open");
+
+ gpioWaveClear();
+ e = gpioWaveAddSerial(GPIO, BAUD, 5000000, strlen(TEXT), TEXT);
+ CHECK(5, 7, e, 3405, 0, "wave clear, wave add serial");
+
+ e = gpioWaveTxStart(PI_WAVE_MODE_ONE_SHOT);
+ CHECK(5, 8, e, 6811, 0, "wave tx start");
+
+ CHECK(5, 9, 0, 0, 0, "NOT APPLICABLE");
+
+ CHECK(5, 10, 0, 0, 0, "NOT APPLICABLE");
+
+ while (gpioWaveTxBusy()) time_sleep(0.1);
+ time_sleep(0.1);
+ c = gpioSerialRead(GPIO, text, sizeof(text)-1);
+ if (c > 0) text[c] = 0;
+ CHECK(5, 11, strcmp(TEXT, text), 0, 0, "wave tx busy, serial read");
+
+ e = gpioSerialReadClose(GPIO);
+ CHECK(5, 12, e, 0, 0, "serial read close");
+
+ c = gpioWaveGetMicros();
+ CHECK(5, 13, c, 6158704, 0, "wave get micros");
+
+ c = gpioWaveGetHighMicros();
+ CHECK(5, 14, c, 6158704, 0, "wave get high micros");
+
+ c = gpioWaveGetMaxMicros();
+ CHECK(5, 15, c, 1800000000, 0, "wave get max micros");
+
+ c = gpioWaveGetPulses();
+ CHECK(5, 16, c, 3405, 0, "wave get pulses");
+
+ c = gpioWaveGetHighPulses();
+ CHECK(5, 17, c, 3405, 0, "wave get high pulses");
+
+ c = gpioWaveGetMaxPulses();
+ CHECK(5, 18, c, 12000, 0, "wave get max pulses");
+
+ c = gpioWaveGetCbs();
+ CHECK(5, 19, c, 6810, 0, "wave get cbs");
+
+ c = gpioWaveGetHighCbs();
+ CHECK(5, 20, c, 6810, 0, "wave get high cbs");
+
+ c = gpioWaveGetMaxCbs();
+ CHECK(5, 21, c, 25016, 0, "wave get max cbs");
+}
+
+int t6_count=0;
+int t6_on=0;
+uint32_t t6_on_tick=0;
+
+void t6cbf(int gpio, int level, uint32_t tick)
+{
+ if (level == 1)
+ {
+ t6_on_tick = tick;
+ t6_count++;
+ }
+ else
+ {
+ if (t6_on_tick) t6_on += (tick - t6_on_tick);
+ }
+}
+
+void t6()
+{
+ int tp, t, p;
+
+ printf("Trigger tests\n");
+
+ gpioWrite(GPIO, PI_LOW);
+
+ tp = 0;
+
+ gpioSetAlertFunc(GPIO, t6cbf);
+
+ for (t=0; t<10; t++)
+ {
+ time_sleep(0.1);
+ p = 10 + (t*10);
+ tp += p;
+ gpioTrigger(4, p, 1);
+ }
+
+ time_sleep(0.2);
+
+ CHECK(6, 1, t6_count, 10, 0, "gpio trigger count");
+
+ CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length");
+}
+
+int t7_count=0;
+
+void t7cbf(int gpio, int level, uint32_t tick)
+{
+ if (level == PI_TIMEOUT) t7_count++;
+}
+
+void t7()
+{
+ int c, oc;
+
+ printf("Watchdog tests.\n");
+
+ /* type of edge shouldn't matter for watchdogs */
+ gpioSetAlertFunc(GPIO, t7cbf);
+
+ gpioSetWatchdog(GPIO, 10); /* 10 ms, 100 per second */
+ time_sleep(0.5);
+ oc = t7_count;
+ time_sleep(2);
+ c = t7_count - oc;
+ CHECK(7, 1, c, 200, 1, "set watchdog on count");
+
+ gpioSetWatchdog(GPIO, 0); /* 0 switches watchdog off */
+ time_sleep(0.5);
+ oc = t7_count;
+ time_sleep(2);
+ c = t7_count - oc;
+ CHECK(7, 2, c, 0, 1, "set watchdog off count");
+}
+
+void t8()
+{
+ int v, t, i;
+
+ printf("Bank read/write tests.\n");
+
+ gpioWrite(GPIO, 0);
+ v = gpioRead_Bits_0_31() & (1<<GPIO);
+ CHECK(8, 1, v, 0, 0, "read bank 1");
+
+ gpioWrite(GPIO, 1);
+ v = gpioRead_Bits_0_31() & (1<<GPIO);
+ CHECK(8, 2, v, (1<<GPIO), 0, "read bank 1");
+
+ gpioWrite_Bits_0_31_Clear(1<<GPIO);
+ v = gpioRead(GPIO);
+ CHECK(8, 3, v, 0, 0, "clear bank 1");
+
+ gpioWrite_Bits_0_31_Set(1<<GPIO);
+ v = gpioRead(GPIO);
+ CHECK(8, 4, v, 1, 0, "set bank 1");
+
+ t = 0;
+ v = (1<<16);
+ for (i=0; i<100; i++)
+ {
+ if (gpioRead_Bits_32_53() & v) t++;
+ };
+ CHECK(8, 5, t, 60, 75, "read bank 2");
+
+ v = gpioWrite_Bits_32_53_Clear(0);
+ CHECK(8, 6, v, 0, 0, "clear bank 2");
+
+ CHECK(8, 7, 0, 0, 0, "NOT APPLICABLE");
+
+ v = gpioWrite_Bits_32_53_Set(0);
+ CHECK(8, 8, v, 0, 0, "set bank 2");
+
+ CHECK(8, 9, 0, 0, 0, "NOT APPLICABLE");
+}
+
+int t9_count = 0;
+
+void t9cbf(int gpio, int level, uint32_t tick)
+{
+ if (level == 1) t9_count++;
+}
+
+void t9()
+{
+ int s, oc, c, e;
+ uint32_t p[10];
+
+ /*
+ 100 loops per second
+ p0 number of loops
+ p1 GPIO
+ */
+ char *script="\
+ ldap 0\
+ ldva 0\
+ label 0\
+ w p1 1\
+ milli 5\
+ w p1 0\
+ milli 5\
+ dcrv 0\
+ ldav 0\
+ ldpa 9\
+ jp 0";
+
+ printf("Script store/run/status/stop/delete tests.\n");
+
+ gpioWrite(GPIO, 0); /* need known state */
+
+ gpioSetAlertFunc(GPIO, t9cbf);
+
+ s = gpioStoreScript(script);
+ time_sleep(0.1);
+ oc = t9_count;
+ p[0] = 99;
+ p[1] = GPIO;
+ gpioRunScript(s, 2, p);
+ time_sleep(2);
+ c = t9_count - oc;
+ CHECK(9, 1, c, 100, 0, "store/run script");
+
+ oc = t9_count;
+ p[0] = 200;
+ p[1] = GPIO;
+ gpioRunScript(s, 2, p);
+ time_sleep(0.1);
+ while (1)
+ {
+ e = gpioScriptStatus(s, p);
+ if (e != PI_SCRIPT_RUNNING) break;
+ time_sleep(0.5);
+ }
+ c = t9_count - oc;
+ time_sleep(0.1);
+ CHECK(9, 2, c, 201, 0, "run script/script status");
+
+ oc = t9_count;
+ p[0] = 2000;
+ p[1] = GPIO;
+ gpioRunScript(s, 2, p);
+ time_sleep(0.1);
+ while (1)
+ {
+ e = gpioScriptStatus(s, p);
+ if (e != PI_SCRIPT_RUNNING) break;
+ if (p[9] < 1900) gpioStopScript(s);
+ time_sleep(0.1);
+ }
+ c = t9_count - oc;
+ time_sleep(0.1);
+ CHECK(9, 3, c, 110, 10, "run/stop script/script status");
+
+ e = gpioDeleteScript(s);
+ CHECK(9, 4, e, 0, 0, "delete script");
+}
+
+int main(int argc, char *argv[])
+{
+ int t, status;
+ void (*test[])(void) = {t0, t1, t2, t3, t4, t5, t6, t7, t8, t9};
+
+ status = gpioInitialise();
+
+ if (status < 0)
+ {
+ fprintf(stderr, "pigpio initialisation failed.\n");
+ return 1;
+ }
+
+ for (t=0; t<10; t++) test[t]();
+
+ gpioTerminate();
+
+ return 0;
+}
+
--- /dev/null
+#!/usr/bin/env python
+
+import time
+import struct
+
+import pigpio
+
+GPIO=4
+
+def CHECK(t, st, got, expect, pc, desc):
+ if got >= (((1E2-pc)*expect)/1E2) and got <= (((1E2+pc)*expect)/1E2):
+ print("TEST {:2d}.{:<2d} PASS ({}: {:d})".format(t, st, desc, expect))
+ else:
+ print("TEST {:2d}.{:<2d} FAILED got {:d} ({}: {:d})".
+ format(t, st, got, desc, expect))
+
+def t0():
+ print("Version.")
+
+ print("pigpio version {}.".format(pigpio.get_pigpio_version()))
+
+ print("Hardware revision {}.".format(pigpio.get_hardware_revision()))
+
+def t1():
+
+ print("Mode/PUD/read/write tests.")
+
+ pigpio.set_mode(GPIO, pigpio.INPUT)
+ v = pigpio.get_mode(GPIO)
+ CHECK(1, 1, v, 0, 0, "set mode, get mode")
+
+ pigpio.set_pull_up_down(GPIO, pigpio.PUD_UP)
+ v = pigpio.read(GPIO)
+ CHECK(1, 2, v, 1, 0, "set pull up down, read")
+
+ pigpio.set_pull_up_down(GPIO, pigpio.PUD_DOWN)
+ v = pigpio.read(GPIO)
+ CHECK(1, 3, v, 0, 0, "set pull up down, read")
+
+ pigpio.write(GPIO, pigpio.LOW)
+ v = pigpio.get_mode(GPIO)
+ CHECK(1, 4, v, 1, 0, "write, get mode")
+
+ v = pigpio.read(GPIO)
+ CHECK(1, 5, v, 0, 0, "read")
+
+ pigpio.write(GPIO, pigpio.HIGH)
+ v = pigpio.read(GPIO)
+ CHECK(1, 6, v, 1, 0, "write, read")
+
+t2_count=0
+
+def t2cbf(gpio, level, tick):
+ global t2_count
+ t2_count += 1
+
+def t2():
+ global t2_count
+
+ print("PWM dutycycle/range/frequency tests.")
+
+ pigpio.set_PWM_range(GPIO, 255)
+ pigpio.set_PWM_frequency(GPIO,0)
+ f = pigpio.get_PWM_frequency(GPIO)
+ CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency")
+
+ t2cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t2cbf)
+
+ pigpio.set_PWM_dutycycle(GPIO, 0)
+ time.sleep(0.5) # allow old notifications to flush
+ oc = t2_count
+ time.sleep(2)
+ f = t2_count - oc
+ CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback")
+
+ pigpio.set_PWM_dutycycle(GPIO, 128)
+ time.sleep(1)
+ oc = t2_count
+ time.sleep(2)
+ f = t2_count - oc
+ CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback")
+
+ pigpio.set_PWM_frequency(GPIO,100)
+ f = pigpio.get_PWM_frequency(GPIO)
+ CHECK(2, 4, f, 100, 0, "set/get PWM frequency")
+
+ time.sleep(1)
+ oc = t2_count
+ time.sleep(2)
+ f = t2_count - oc
+ CHECK(2, 5, f, 400, 1, "callback")
+
+ pigpio.set_PWM_frequency(GPIO,1000)
+ f = pigpio.get_PWM_frequency(GPIO)
+ CHECK(2, 6, f, 1000, 0, "set/get PWM frequency")
+
+ time.sleep(1)
+ oc = t2_count
+ time.sleep(2)
+ f = t2_count - oc
+ CHECK(2, 7, f, 4000, 1, "callback")
+
+ r = pigpio.get_PWM_range(GPIO)
+ CHECK(2, 8, r, 255, 0, "get PWM range")
+
+ rr = pigpio.get_PWM_real_range(GPIO)
+ CHECK(2, 9, rr, 200, 0, "get PWM real range")
+
+ pigpio.set_PWM_range(GPIO, 2000)
+ r = pigpio.get_PWM_range(GPIO)
+ CHECK(2, 10, r, 2000, 0, "set/get PWM range")
+
+ rr = pigpio.get_PWM_real_range(GPIO)
+ CHECK(2, 11, rr, 200, 0, "get PWM real range")
+
+ pigpio.set_PWM_dutycycle(GPIO, 0)
+
+t3_reset=True
+t3_count=0
+t3_tick=0
+t3_on=0.0
+t3_off=0.0
+
+def t3cbf(gpio, level, tick):
+ global t3_reset, t3_count, t3_tick, t3_on, t3_off
+
+ if t3_reset:
+ t3_count = 0
+ t3_on = 0.0
+ t3_off = 0.0
+ t3_reset = False
+ else:
+ td = pigpio.tickDiff(t3_tick, tick)
+
+ if level == 0:
+ t3_on += td
+ else:
+ t3_off += td
+
+ t3_count += 1
+ t3_tick = tick
+
+def t3():
+ global t3_reset, t3_count, t3_on, t3_off
+
+ pw=[500.0, 1500.0, 2500.0]
+ dc=[0.2, 0.4, 0.6, 0.8]
+
+ print("PWM/Servo pulse accuracy tests.")
+
+ t3cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t3cbf)
+
+ t = 0
+ for x in pw:
+ t += 1
+ pigpio.set_servo_pulsewidth(GPIO, x)
+ time.sleep(1)
+ t3_reset = True
+ time.sleep(4)
+ c = t3_count
+ on = t3_on
+ off = t3_off
+ CHECK(3, t, int((1E3*(on+off))/on), int(2E7/x), 1, "set servo pulsewidth")
+
+
+ pigpio.set_servo_pulsewidth(GPIO, 0)
+ pigpio.set_PWM_frequency(GPIO, 1000)
+ f = pigpio.get_PWM_frequency(GPIO)
+ CHECK(3, 4, f, 1000, 0, "set/get PWM frequency")
+
+ rr = pigpio.set_PWM_range(GPIO, 100)
+ CHECK(3, 5, rr, 200, 0, "set PWM range")
+
+ t = 5
+ for x in dc:
+ t += 1
+ pigpio.set_PWM_dutycycle(GPIO, x*100)
+ time.sleep(1)
+ t3_reset = True
+ time.sleep(2)
+ c = t3_count
+ on = t3_on
+ off = t3_off
+ CHECK(3, t, int((1E3*on)/(on+off)), int(1E3*x), 1, "set PWM dutycycle")
+
+ pigpio.set_PWM_dutycycle(GPIO, 0)
+
+def t4():
+
+ print("Pipe notification tests.")
+
+ pigpio.set_PWM_frequency(GPIO, 0)
+ pigpio.set_PWM_dutycycle(GPIO, 0)
+ pigpio.set_PWM_range(GPIO, 100)
+
+ h = pigpio.notify_open()
+ e = pigpio.notify_begin(h, (1<<4))
+ CHECK(4, 1, e, 0, 0, "notify open/begin")
+
+ time.sleep(1)
+
+ with open("/dev/pigpio"+ str(h), "rb") as f:
+
+ pigpio.set_PWM_dutycycle(GPIO, 50)
+ time.sleep(4)
+ pigpio.set_PWM_dutycycle(GPIO, 0)
+
+ e = pigpio.notify_pause(h)
+ CHECK(4, 2, e, 0, 0, "notify pause")
+
+ e = pigpio.notify_close(h)
+ CHECK(4, 3, e, 0, 0, "notify close")
+
+ n = 0
+ s = 0
+
+ seq_ok = 1
+ toggle_ok = 1
+
+ while True:
+
+ chunk = f.read(12)
+
+ if len(chunk) == 12:
+
+ S, fl, t, v = struct.unpack('HHII', chunk)
+ if s != S:
+ seq_ok = 0
+
+
+ L = v & (1<<4)
+
+ if n:
+ if l != L:
+ toggle_ok = 0
+
+ if L:
+ l = 0
+ else:
+ l = (1<<4)
+
+ s += 1
+ n += 1
+
+ # print(S, fl, t, hex(v))
+
+ else:
+ break
+
+ f.close()
+
+ CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok")
+
+ CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok")
+
+ CHECK(4, 6, n, 80, 10, "number of notifications")
+
+t5_count = 0
+
+def t5cbf(gpio, level, tick):
+ global t5_count
+ t5_count += 1
+
+def t5():
+ global t5_count
+
+ BAUD=4800
+
+ TEXT="""
+Now is the winter of our discontent
+Made glorious summer by this sun of York;
+And all the clouds that lour'd upon our house
+In the deep bosom of the ocean buried.
+Now are our brows bound with victorious wreaths;
+Our bruised arms hung up for monuments;
+Our stern alarums changed to merry meetings,
+Our dreadful marches to delightful measures.
+Grim-visaged war hath smooth'd his wrinkled front;
+And now, instead of mounting barded steeds
+To fright the souls of fearful adversaries,
+He capers nimbly in a lady's chamber
+To the lascivious pleasing of a lute.
+"""
+
+ print("Waveforms & serial read/write tests.")
+
+ t5cb = pigpio.callback(GPIO, pigpio.FALLING_EDGE, t5cbf)
+
+ pigpio.set_mode(GPIO, pigpio.OUTPUT)
+
+ e = pigpio.wave_clear()
+ CHECK(5, 1, e, 0, 0, "callback, set mode, wave clear")
+
+ wf = []
+
+ wf.append(pigpio.pulse(1<<GPIO, 0, 10000))
+ wf.append(pigpio.pulse(0, 1<<GPIO, 30000))
+ wf.append(pigpio.pulse(1<<GPIO, 0, 60000))
+ wf.append(pigpio.pulse(0, 1<<GPIO, 100000))
+
+ e = pigpio.wave_add_generic(wf)
+ CHECK(5, 2, e, 4, 0, "pulse, wave add generic")
+
+ e = pigpio.wave_tx_repeat()
+ CHECK(5, 3, e, 9, 0, "wave tx repeat")
+
+ oc = t5_count
+ time.sleep(5)
+ c = t5_count - oc
+ CHECK(5, 4, c, 50, 1, "callback")
+
+ e = pigpio.wave_tx_stop()
+ CHECK(5, 5, e, 0, 0, "wave tx stop")
+
+ e = pigpio.serial_read_open(GPIO, BAUD)
+ CHECK(5, 6, e, 0, 0, "serial read open")
+
+ pigpio.wave_clear()
+ e = pigpio.wave_add_serial(GPIO, BAUD, 5000000, TEXT)
+ CHECK(5, 7, e, 3405, 0, "wave clear, wave add serial")
+
+ e = pigpio.wave_tx_start()
+ CHECK(5, 8, e, 6811, 0, "wave tx start")
+
+ oc = t5_count
+ time.sleep(3)
+ c = t5_count - oc
+ CHECK(5, 9, c, 0, 0, "callback")
+
+ oc = t5_count
+ while pigpio.wave_tx_busy():
+ time.sleep(0.1)
+ time.sleep(0.1)
+ c = t5_count - oc
+ CHECK(5, 10, c, 1702, 0, "wave tx busy, callback")
+
+ c, text = pigpio.serial_read(GPIO)
+ CHECK(5, 11, TEXT == text, True, 0, "wave tx busy, serial read");
+
+ e = pigpio.serial_read_close(GPIO)
+ CHECK(5, 12, e, 0, 0, "serial read close")
+
+ c = pigpio.wave_get_micros()
+ CHECK(5, 13, c, 6158704, 0, "wave get micros")
+
+ CHECK(5, 14, 0, 0, 0, "NOT APPLICABLE")
+
+ c = pigpio.wave_get_max_micros()
+ CHECK(5, 15, c, 1800000000, 0, "wave get max micros")
+
+ c = pigpio.wave_get_pulses()
+ CHECK(5, 16, c, 3405, 0, "wave get pulses")
+
+ CHECK(5, 17, 0, 0, 0, "NOT APPLICABLE")
+
+ c = pigpio.wave_get_max_pulses()
+ CHECK(5, 18, c, 12000, 0, "wave get max pulses")
+
+ c = pigpio.wave_get_cbs()
+ CHECK(5, 19, c, 6810, 0, "wave get cbs")
+
+ CHECK(5, 20, 0, 0, 0, "NOT APPLICABLE")
+
+ c = pigpio.wave_get_max_cbs()
+ CHECK(5, 21, c, 25016, 0, "wave get max cbs")
+
+t6_count=0
+t6_on=0
+t6_on_tick=None
+
+def t6cbf(gpio, level, tick):
+ global t6_count, t6_on, t6_on_tick
+ if level == 1:
+ t6_on_tick = tick
+ t6_count += 1
+ else:
+ if t6_on_tick is not None:
+ t6_on += pigpio.tickDiff(t6_on_tick, tick)
+
+def t6():
+ global t6_count, t6_on
+
+ print("Trigger tests.")
+
+ pigpio.write(GPIO, pigpio.LOW)
+
+ tp = 0
+
+ t6cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t6cbf)
+
+ for t in range(10):
+ time.sleep(0.1)
+ p = 10 + (t*10)
+ tp += p;
+ pigpio.gpio_trigger(4, p, 1)
+
+ time.sleep(0.5)
+
+ CHECK(6, 1, t6_count, 10, 0, "gpio trigger count")
+
+ CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length")
+
+t7_count=0
+
+def t7cbf(gpio, level, tick):
+ global t7_count
+ if level == pigpio.TIMEOUT:
+ t7_count += 1
+
+def t7():
+ global t7_count
+
+ print("Watchdog tests.")
+
+ # type of edge shouldn't matter for watchdogs
+ t7cb = pigpio.callback(GPIO, pigpio.FALLING_EDGE, t7cbf)
+
+ pigpio.set_watchdog(GPIO, 10) # 10 ms, 100 per second
+ time.sleep(0.5)
+ oc = t7_count
+ time.sleep(2)
+ c = t7_count - oc
+ CHECK(7, 1, c, 200, 1, "set watchdog on count")
+
+ pigpio.set_watchdog(GPIO, 0) # 0 switches watchdog off
+ time.sleep(0.5)
+ oc = t7_count
+ time.sleep(2)
+ c = t7_count - oc
+ CHECK(7, 2, c, 0, 1, "set watchdog off count")
+
+def t8():
+ print("Bank read/write tests.")
+
+ pigpio.write(GPIO, 0)
+ v = pigpio.read_bank_1() & (1<<GPIO)
+ CHECK(8, 1, v, 0, 0, "read bank 1")
+
+ pigpio.write(GPIO, 1)
+ v = pigpio.read_bank_1() & (1<<GPIO)
+ CHECK(8, 2, v, (1<<GPIO), 0, "read bank 1")
+
+ pigpio.clear_bank_1(1<<GPIO)
+ v = pigpio.read(GPIO)
+ CHECK(8, 3, v, 0, 0, "clear bank 1")
+
+ pigpio.set_bank_1(1<<GPIO)
+ v = pigpio.read(GPIO)
+ CHECK(8, 4, v, 1, 0, "set bank 1")
+
+ t = 0
+ v = (1<<16)
+ for i in range(100):
+ if pigpio.read_bank_2() & v:
+ t += 1
+ CHECK(8, 5, t, 60, 75, "read bank 2")
+
+ v = pigpio.clear_bank_2(0)
+ CHECK(8, 6, v, 0, 0, "clear bank 2")
+
+ pigpio.exceptions = False
+ v = pigpio.clear_bank_2(0xffffff)
+ pigpio.exceptions = True
+ CHECK(8, 7, v, pigpio.PI_SOME_PERMITTED, 0, "clear bank 2")
+
+ v = pigpio.set_bank_2(0)
+ CHECK(8, 8, v, 0, 0, "set bank 2")
+
+ pigpio.exceptions = False
+ v = pigpio.set_bank_2(0xffffff)
+ pigpio.exceptions = True
+ CHECK(8, 9, v, pigpio.PI_SOME_PERMITTED, 0, "set bank 2")
+
+def t9():
+ print("Script store/run/status/stop/delete tests.")
+
+ pigpio.write(GPIO, 0) # need known state
+
+ # 100 loops per second
+ # p0 number of loops
+ # p1 GPIO
+ script="""
+ ldap 0
+ ldva 0
+ label 0
+ w p1 1
+ milli 5
+ w p1 0
+ milli 5
+ dcrv 0
+ ldav 0
+ ldpa 9
+ jp 0"""
+
+ t9cb = pigpio.callback(GPIO)
+
+ s = pigpio.store_script(script)
+ oc = t9cb.tally()
+ pigpio.run_script(s, [99, GPIO])
+ time.sleep(2)
+ c = t9cb.tally() - oc
+ CHECK(9, 1, c, 100, 0, "store/run script")
+
+ oc = t9cb.tally()
+ pigpio.run_script(s, [200, GPIO])
+ while True:
+ e, p = pigpio.script_status(s)
+ if e != pigpio.PI_SCRIPT_RUNNING:
+ break
+ time.sleep(0.5)
+ c = t9cb.tally() - oc
+ time.sleep(0.1)
+ CHECK(9, 2, c, 201, 0, "run script/script status")
+
+ oc = t9cb.tally()
+ pigpio.run_script(s, [2000, GPIO])
+ while True:
+ e, p = pigpio.script_status(s)
+ if e != pigpio.PI_SCRIPT_RUNNING:
+ break
+ if p[9] < 1900:
+ pigpio.stop_script(s)
+ time.sleep(0.1)
+ c = t9cb.tally() - oc
+ time.sleep(0.1)
+ CHECK(9, 3, c, 110, 10, "run/stop script/script status")
+
+ e = pigpio.delete_script(s)
+ CHECK(9, 4, e, 0, 0, "delete script")
+
+if pigpio.start(''): # must run notification test on localhost
+ print("Connected to pigpio daemon.")
+
+ test = [t0, t1, t2, t3, t4, t5, t6, t7, t8, t9]
+
+ for t in test:
+ t();
+
+ pigpio.stop()
+
--- /dev/null
+/*
+gcc -o x_pigpiod_if x_pigpiod_if.c -lpigpiod_if -lrt -lpthread
+sudo ./x_pigpiod_if
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "pigpiod_if.h"
+
+#define GPIO 4
+
+void CHECK(int t, int st, int got, int expect, int pc, char *desc)
+{
+ if ((got >= (((1E2-pc)*expect)/1E2)) && (got <= (((1E2+pc)*expect)/1E2)))
+ {
+ printf("TEST %2d.%-2d PASS (%s: %d)\n", t, st, desc, expect);
+ }
+ else
+ {
+ fprintf(stderr,
+ "TEST %2d.%-2d FAILED got %d (%s: %d)\n",
+ t, st, got, desc, expect);
+ }
+}
+
+void t0()
+{
+ printf("Version.\n");
+
+ printf("pigpio version %d.\n", get_pigpio_version());
+
+ printf("Hardware revision %d.\n", get_hardware_revision());
+}
+
+void t1()
+{
+ int v;
+
+ printf("Mode/PUD/read/write tests.\n");
+
+ set_mode(GPIO, PI_INPUT);
+ v = get_mode(GPIO);
+ CHECK(1, 1, v, 0, 0, "set mode, get mode");
+
+ set_pull_up_down(GPIO, PI_PUD_UP);
+ v = gpio_read(GPIO);
+ CHECK(1, 2, v, 1, 0, "set pull up down, read");
+
+ set_pull_up_down(GPIO, PI_PUD_DOWN);
+ v = gpio_read(GPIO);
+ CHECK(1, 3, v, 0, 0, "set pull up down, read");
+
+ gpio_write(GPIO, PI_LOW);
+ v = get_mode(GPIO);
+ CHECK(1, 4, v, 1, 0, "write, get mode");
+
+ v = gpio_read(GPIO);
+ CHECK(1, 5, v, 0, 0, "read");
+
+ gpio_write(GPIO, PI_HIGH);
+ v = gpio_read(GPIO);
+ CHECK(1, 6, v, 1, 0, "write, read");
+}
+
+int t2_count=0;
+
+void t2cb(unsigned gpio, unsigned level, uint32_t tick)
+{
+ t2_count++;
+}
+
+void t2()
+{
+ int f, r, rr, oc;
+
+ printf("PWM dutycycle/range/frequency tests.\n");
+
+ set_PWM_range(GPIO, 255);
+ set_PWM_frequency(GPIO, 0);
+ f = get_PWM_frequency(GPIO);
+ CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency");
+
+ callback(GPIO, EITHER_EDGE, t2cb);
+
+ set_PWM_dutycycle(GPIO, 0);
+ time_sleep(0.5); /* allow old notifications to flush */
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 2, f, 0, 0, "set PWM dutycycle, callback");
+
+ set_PWM_dutycycle(GPIO, 128);
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 3, f, 40, 5, "set PWM dutycycle, callback");
+
+ set_PWM_frequency(GPIO, 100);
+ f = get_PWM_frequency(GPIO);
+ CHECK(2, 4, f, 100, 0, "set/get PWM frequency");
+
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 5, f, 400, 1, "callback");
+
+ set_PWM_frequency(GPIO, 1000);
+ f = get_PWM_frequency(GPIO);
+ CHECK(2, 6, f, 1000, 0, "set/get PWM frequency");
+
+ oc = t2_count;
+ time_sleep(2);
+ f = t2_count - oc;
+ CHECK(2, 7, f, 4000, 1, "callback");
+
+ r = get_PWM_range(GPIO);
+ CHECK(2, 8, r, 255, 0, "get PWM range");
+
+ rr = get_PWM_real_range(GPIO);
+ CHECK(2, 9, rr, 200, 0, "get PWM real range");
+
+ set_PWM_range(GPIO, 2000);
+ r = get_PWM_range(GPIO);
+ CHECK(2, 10, r, 2000, 0, "set/get PWM range");
+
+ rr = get_PWM_real_range(GPIO);
+ CHECK(2, 11, rr, 200, 0, "get PWM real range");
+
+ set_PWM_dutycycle(GPIO, 0);
+}
+
+int t3_reset=1;
+int t3_count=0;
+uint32_t t3_tick=0;
+float t3_on=0.0;
+float t3_off=0.0;
+
+void t3cbf(unsigned gpio, unsigned level, uint32_t tick)
+{
+ uint32_t td;
+
+ if (t3_reset)
+ {
+ t3_count = 0;
+ t3_on = 0.0;
+ t3_off = 0.0;
+ t3_reset = 0;
+ }
+ else
+ {
+ td = tick - t3_tick;
+
+ if (level == 0) t3_on += td;
+ else t3_off += td;
+ }
+
+ t3_count ++;
+ t3_tick = tick;
+}
+
+void t3()
+{
+ int pw[3]={500, 1500, 2500};
+ int dc[4]={20, 40, 60, 80};
+
+ int f, rr;
+ float on, off;
+
+ int t;
+
+ printf("PWM/Servo pulse accuracy tests.\n");
+
+ callback(GPIO, EITHER_EDGE, t3cbf);
+
+ for (t=0; t<3; t++)
+ {
+ set_servo_pulsewidth(GPIO, pw[t]);
+ time_sleep(1);
+ t3_reset = 1;
+ time_sleep(4);
+ on = t3_on;
+ off = t3_off;
+ CHECK(3, 1+t, (1000.0*(on+off))/on, 20000000.0/pw[t], 1,
+ "set servo pulsewidth");
+ }
+
+ set_servo_pulsewidth(GPIO, 0);
+ set_PWM_frequency(GPIO, 1000);
+ f = get_PWM_frequency(GPIO);
+ CHECK(3, 4, f, 1000, 0, "set/get PWM frequency");
+
+ rr = set_PWM_range(GPIO, 100);
+ CHECK(3, 5, rr, 200, 0, "set PWM range");
+
+ for (t=0; t<4; t++)
+ {
+ set_PWM_dutycycle(GPIO, dc[t]);
+ time_sleep(1);
+ t3_reset = 1;
+ time_sleep(2);
+ on = t3_on;
+ off = t3_off;
+ CHECK(3, 6+t, (1000.0*on)/(on+off), 10.0*dc[t], 1,
+ "set PWM dutycycle");
+ }
+
+ set_PWM_dutycycle(GPIO, 0);
+
+}
+
+void t4()
+{
+ int h, e, f, n, s, b, l, seq_ok, toggle_ok;
+ gpioReport_t r;
+ char p[32];
+
+ printf("Pipe notification tests.\n");
+
+ set_PWM_frequency(GPIO, 0);
+ set_PWM_dutycycle(GPIO, 0);
+ set_PWM_range(GPIO, 100);
+
+ h = notify_open();
+ e = notify_begin(h, (1<<4));
+ CHECK(4, 1, e, 0, 0, "notify open/begin");
+
+ time_sleep(1);
+
+ sprintf(p, "/dev/pigpio%d", h);
+
+ f = open(p, O_RDONLY);
+
+ set_PWM_dutycycle(GPIO, 50);
+ time_sleep(4);
+ set_PWM_dutycycle(GPIO, 0);
+
+ e = notify_pause(h);
+ CHECK(4, 2, e, 0, 0, "notify pause");
+
+ e = notify_close(h);
+ CHECK(4, 3, e, 0, 0, "notify close");
+
+ n = 0;
+ s = 0;
+ l = 0;
+ seq_ok = 1;
+ toggle_ok = 1;
+
+ while (1)
+ {
+ b = read(f, &r, 12);
+ if (b == 12)
+ {
+ if (s != r.seqno) seq_ok = 0;
+
+ if (n) if (l != (r.level&(1<<4))) toggle_ok = 0;
+
+ if (r.level&(1<<4)) l = 0;
+ else l = (1<<4);
+
+ s++;
+ n++;
+
+ // printf("%d %d %d %X\n", r.seqno, r.flags, r.tick, r.level);
+ }
+ else break;
+ }
+ close(f);
+
+ CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok");
+
+ CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok");
+
+ CHECK(4, 6, n, 80, 10, "number of notifications");
+}
+
+int t5_count = 0;
+
+void t5cbf(unsigned gpio, unsigned level, uint32_t tick)
+{
+ t5_count++;
+}
+
+void t5()
+{
+ int BAUD=4800;
+
+ char *TEXT=
+"\n\
+Now is the winter of our discontent\n\
+Made glorious summer by this sun of York;\n\
+And all the clouds that lour'd upon our house\n\
+In the deep bosom of the ocean buried.\n\
+Now are our brows bound with victorious wreaths;\n\
+Our bruised arms hung up for monuments;\n\
+Our stern alarums changed to merry meetings,\n\
+Our dreadful marches to delightful measures.\n\
+Grim-visaged war hath smooth'd his wrinkled front;\n\
+And now, instead of mounting barded steeds\n\
+To fright the souls of fearful adversaries,\n\
+He capers nimbly in a lady's chamber\n\
+To the lascivious pleasing of a lute.\n\
+";
+
+ gpioPulse_t wf[] =
+ {
+ {1<<GPIO, 0, 10000},
+ {0, 1<<GPIO, 30000},
+ {1<<GPIO, 0, 60000},
+ {0, 1<<GPIO, 100000},
+ };
+
+ int e, oc, c;
+
+ char text[2048];
+
+ printf("Waveforms & serial read/write tests.\n");
+
+ callback(GPIO, FALLING_EDGE, t5cbf);
+
+ set_mode(GPIO, PI_OUTPUT);
+
+ e = wave_clear();
+ CHECK(5, 1, e, 0, 0, "callback, set mode, wave clear");
+
+ e = wave_add_generic(4, wf);
+ CHECK(5, 2, e, 4, 0, "pulse, wave add generic");
+
+ e = wave_tx_repeat();
+ CHECK(5, 3, e, 9, 0, "wave tx repeat");
+
+ oc = t5_count;
+ time_sleep(5);
+ c = t5_count - oc;
+ CHECK(5, 4, c, 50, 1, "callback");
+
+ e = wave_tx_stop();
+ CHECK(5, 5, e, 0, 0, "wave tx stop");
+
+ e = serial_read_open(GPIO, BAUD);
+ CHECK(5, 6, e, 0, 0, "serial read open");
+
+ wave_clear();
+ e = wave_add_serial(GPIO, BAUD, 5000000, strlen(TEXT), TEXT);
+ CHECK(5, 7, e, 3405, 0, "wave clear, wave add serial");
+
+ e = wave_tx_start();
+ CHECK(5, 8, e, 6811, 0, "wave tx start");
+
+ oc = t5_count;
+ time_sleep(3);
+ c = t5_count - oc;
+ CHECK(5, 9, c, 0, 0, "callback");
+
+ oc = t5_count;
+ while (wave_tx_busy()) time_sleep(0.1);
+ time_sleep(0.1);
+ c = t5_count - oc;
+ CHECK(5, 10, c, 1702, 0, "wave tx busy, callback");
+
+ c = serial_read(GPIO, text, sizeof(text)-1);
+ if (c > 0) text[c] = 0; /* null terminate string */
+ CHECK(5, 11, strcmp(TEXT, text), 0, 0, "wave tx busy, serial read");
+
+ e = serial_read_close(GPIO);
+ CHECK(5, 12, e, 0, 0, "serial read close");
+
+ c = wave_get_micros();
+ CHECK(5, 13, c, 6158704, 0, "wave get micros");
+
+ c = wave_get_high_micros();
+ CHECK(5, 14, c, 6158704, 0, "wave get high micros");
+
+ c = wave_get_max_micros();
+ CHECK(5, 15, c, 1800000000, 0, "wave get max micros");
+
+ c = wave_get_pulses();
+ CHECK(5, 16, c, 3405, 0, "wave get pulses");
+
+ c = wave_get_high_pulses();
+ CHECK(5, 17, c, 3405, 0, "wave get high pulses");
+
+ c = wave_get_max_pulses();
+ CHECK(5, 18, c, 12000, 0, "wave get max pulses");
+
+ c = wave_get_cbs();
+ CHECK(5, 19, c, 6810, 0, "wave get cbs");
+
+ c = wave_get_high_cbs();
+ CHECK(5, 20, c, 6810, 0, "wave get high cbs");
+
+ c = wave_get_max_cbs();
+ CHECK(5, 21, c, 25016, 0, "wave get max cbs");
+}
+
+int t6_count=0;
+int t6_on=0;
+uint32_t t6_on_tick=0;
+
+void t6cbf(unsigned gpio, unsigned level, uint32_t tick)
+{
+ if (level == 1)
+ {
+ t6_on_tick = tick;
+ t6_count++;
+ }
+ else
+ {
+ if (t6_on_tick) t6_on += (tick - t6_on_tick);
+ }
+}
+
+void t6()
+{
+ int tp, t, p;
+
+ printf("Trigger tests.\n");
+
+ gpio_write(GPIO, PI_LOW);
+
+ tp = 0;
+
+ callback(GPIO, EITHER_EDGE, t6cbf);
+
+ time_sleep(0.2);
+
+ for (t=0; t<10; t++)
+ {
+ time_sleep(0.1);
+ p = 10 + (t*10);
+ tp += p;
+ gpio_trigger(4, p, 1);
+ }
+
+ time_sleep(0.5);
+
+ CHECK(6, 1, t6_count, 10, 0, "gpio trigger count");
+
+ CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length");
+}
+
+int t7_count=0;
+
+void t7cbf(unsigned gpio, unsigned level, uint32_t tick)
+{
+ if (level == PI_TIMEOUT) t7_count++;
+}
+
+void t7()
+{
+ int c, oc;
+
+ printf("Watchdog tests.\n");
+
+ /* type of edge shouldn't matter for watchdogs */
+ callback(GPIO, FALLING_EDGE, t7cbf);
+
+ set_watchdog(GPIO, 10); /* 10 ms, 100 per second */
+ time_sleep(0.5);
+ oc = t7_count;
+ time_sleep(2);
+ c = t7_count - oc;
+ CHECK(7, 1, c, 200, 1, "set watchdog on count");
+
+ set_watchdog(GPIO, 0); /* 0 switches watchdog off */
+ time_sleep(0.5);
+ oc = t7_count;
+ time_sleep(2);
+ c = t7_count - oc;
+ CHECK(7, 2, c, 0, 1, "set watchdog off count");
+}
+
+void t8()
+{
+ int v, t, i;
+
+ printf("Bank read/write tests.\n");
+
+ gpio_write(GPIO, 0);
+ v = read_bank_1() & (1<<GPIO);
+ CHECK(8, 1, v, 0, 0, "read bank 1");
+
+ gpio_write(GPIO, 1);
+ v = read_bank_1() & (1<<GPIO);
+ CHECK(8, 2, v, (1<<GPIO), 0, "read bank 1");
+
+ clear_bank_1(1<<GPIO);
+ v = gpio_read(GPIO);
+ CHECK(8, 3, v, 0, 0, "clear bank 1");
+
+ set_bank_1(1<<GPIO);
+ v = gpio_read(GPIO);
+ CHECK(8, 4, v, 1, 0, "set bank 1");
+
+ t = 0;
+ v = (1<<16);
+ for (i=0; i<100; i++)
+ {
+ if (read_bank_2() & v) t++;
+ };
+ CHECK(8, 5, t, 60, 75, "read bank 2");
+
+ v = clear_bank_2(0);
+ CHECK(8, 6, v, 0, 0, "clear bank 2");
+
+ v = clear_bank_2(0xffffff);
+ CHECK(8, 7, v, PI_SOME_PERMITTED, 0, "clear bank 2");
+
+ v = set_bank_2(0);
+ CHECK(8, 8, v, 0, 0, "set bank 2");
+
+ v = set_bank_2(0xffffff);
+ CHECK(8, 9, v, PI_SOME_PERMITTED, 0, "set bank 2");
+}
+
+int t9_count = 0;
+
+void t9cbf(unsigned gpio, unsigned level, uint32_t tick)
+{
+ t9_count++;
+}
+
+void t9()
+{
+ int s, oc, c, e;
+ uint32_t p[10];
+
+ printf("Script store/run/status/stop/delete tests.\n");
+
+ gpio_write(GPIO, 0); /* need known state */
+
+ /*
+ 100 loops per second
+ p0 number of loops
+ p1 GPIO
+ */
+ char *script="\
+ ldap 0\
+ ldva 0\
+ label 0\
+ w p1 1\
+ milli 5\
+ w p1 0\
+ milli 5\
+ dcrv 0\
+ ldav 0\
+ ldpa 9\
+ jp 0";
+
+ callback(GPIO, RISING_EDGE, t9cbf);
+
+ s = store_script(script);
+ oc = t9_count;
+ p[0] = 99;
+ p[1] = GPIO;
+ run_script(s, 2, p);
+ time_sleep(2);
+ c = t9_count - oc;
+ CHECK(9, 1, c, 100, 0, "store/run script");
+
+ oc = t9_count;
+ p[0] = 200;
+ p[1] = GPIO;
+ run_script(s, 2, p);
+ while (1)
+ {
+ e = script_status(s, p);
+ if (e != PI_SCRIPT_RUNNING) break;
+ time_sleep(0.5);
+ }
+ c = t9_count - oc;
+ time_sleep(0.1);
+ CHECK(9, 2, c, 201, 0, "run script/script status");
+
+ oc = t9_count;
+ p[0] = 2000;
+ p[1] = GPIO;
+ run_script(s, 2, p);
+ while (1)
+ {
+ e = script_status(s, p);
+ if (e != PI_SCRIPT_RUNNING) break;
+ if (p[9] < 1900) stop_script(s);
+ time_sleep(0.1);
+ }
+ c = t9_count - oc;
+ time_sleep(0.1);
+ CHECK(9, 3, c, 110, 10, "run/stop script/script status");
+
+ e = delete_script(s);
+ CHECK(9, 4, e, 0, 0, "delete script");
+}
+
+int main(int argc, char *argv[])
+{
+ int t, status;
+ void (*test[])(void) = {t0, t1, t2, t3, t4, t5, t6, t7, t8, t9};
+
+ status = pigpio_start(0, 0);
+
+ if (status < 0)
+ {
+ fprintf(stderr, "pigpio initialisation failed.\n");
+ return 1;
+ }
+
+ printf("Connected to pigpio daemon.\n");
+
+ for (t=0; t<10; t++) test[t]();
+
+ pigpio_stop();
+
+ return 0;
+}
+
--- /dev/null
+#!/bin/bash
+
+GPIO=4
+
+#
+# This script serves as a confidence check that the socket interface to
+# the pigpio library is ok.
+#
+# The script uses gpio 4 (P1-7). Make sure that nothing (or only a LED)
+# is connected to gpio 4 before running the script.
+#
+# To run the script
+# sudo pigpiod # if not already running on the Pi
+# export PIGPIO_ADDR=pi_host # to specify the Pi if testing remotely
+# ./x_pigs
+#
+
+s=$(pigs bc1 0)
+if [[ $s = "" ]]; then echo "BC1 ok"; else echo "BC1 fail ($s)"; fi
+
+s=$(pigs bc2 0)
+if [[ $s = "" ]]; then echo "BC2 ok"; else echo "BC2 fail ($s)"; fi
+
+s=$(pigs br1)
+if [[ ${#s} = 8 ]]
+then echo "BR1 ok"
+else echo "BR1 fail ($s)"
+fi
+
+s=$(pigs br2)
+if [[ ${#s} = 8 ]]
+then echo "BR2 ok"
+else echo "BR2 fail ($s)"
+fi
+
+s=$(pigs bs1 0)
+if [[ $s = "" ]]; then echo "BS1 ok"; else echo "BS1 fail ($s)"; fi
+
+s=$(pigs bs2 0)
+if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
+
+s=$(pigs h)
+if [[ ${#s} = 2999 ]]; 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
+
+s=$(pigs micro 1000)
+if [[ $s = "" ]]; then echo "MICRO ok"; else echo "MICRO fail ($s)"; fi
+
+s=$(pigs milli 10)
+if [[ $s = "" ]]; then echo "MILLI ok"; else echo "MILLI fail ($s)"; fi
+
+s=$(pigs modes $GPIO 0)
+s=$(pigs modeg $GPIO)
+if [[ $s = 4 ]]; then echo "MODEG ok"; else echo "MODEG fail ($s)"; fi
+s=$(pigs m $GPIO r)
+s=$(pigs mg $GPIO)
+if [[ $s = 0 ]]; then echo "MODES ok"; else echo "MODES fail ($s)"; fi
+
+h=$(pigs no)
+if [[ $h -ge 0 && $h -le 31 ]]
+then echo "NO($h) ok"
+else echo "NO fail ($s)"
+fi
+
+s=$(pigs nb $h 0xabcd)
+if [[ $s = "" ]]; then echo "NB($h) ok"; else echo "NB fail ($s)"; fi
+
+s=$(pigs np $h)
+if [[ $s = "" ]]; then echo "NP($h) ok"; else echo "NP fail ($s)"; fi
+
+s=$(pigs nc $h)
+if [[ $s = "" ]]; then echo "NC($h) ok"; else echo "NC fail ($s)"; fi
+
+s=$(pigs pfs $GPIO 800)
+if [[ $s = 800 ]]; then echo "PFG-a ok"; else echo "PFG-a fail ($s)"; fi
+
+s=$(pigs pfg $GPIO)
+if [[ $s = 800 ]]; then echo "PFG-b ok"; else echo "PFG-b fail ($s)"; fi
+
+s=$(pigs pfs $GPIO 0)
+if [[ $s = 10 ]]; then echo "PFS-a ok"; else echo "PFS-a fail ($s)"; fi
+
+s=$(pigs pfs $GPIO 800)
+if [[ $s = 800 ]]; then echo "PFS-b ok"; else echo "PFS-b fail ($s)"; fi
+
+s=$(pigs pigpv)
+if [[ $s = 13 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
+
+s=$(pigs prs $GPIO 255)
+if [[ $s = 250 ]]; then echo "PRG-a ok"; else echo "PRG-a fail ($s)"; fi
+s=$(pigs prg $GPIO)
+if [[ $s = 255 ]]; then echo "PRG-b ok"; else echo "PRG-b fail ($s)"; fi
+
+p=$(pigs proc ldap 0 ldpa 1 ldai 1234 ldpa 0 label 999 milli 1000 jmp 999)
+if [[ $p -ge 0 && $p -le 31 ]]
+then echo "PROC($p) ok"
+else echo "PROC($p) fail ($s)"
+fi
+
+s=$(pigs procr $p 9876)
+if [[ $s = 0 ]]; then echo "PROCR($p) ok"; else echo "PROCR($p) fail ($s)"; fi
+
+s=$(pigs procp $p)
+v=(${s// / })
+if [[ ${v[0]} = 1 && ${v[1]} = 1234 && ${v[2]} = 9876 ]]
+then echo "PROCP($p) ok"
+else echo "PROCP($p) fail ($s)"
+fi
+
+s=$(pigs procs $p)
+if [[ $s = 0 ]]; then echo "PROCS($p) ok"; else echo "PROCS($p) fail ($s)"; fi
+
+s=$(pigs procd $p)
+if [[ $s = 0 ]]; then echo "PROCD($p) ok"; else echo "PROCD($p) fail ($s)"; fi
+
+s=$(pigs prrg $GPIO)
+if [[ $s = 250 ]]; then echo "PRRG ok"; else echo "PRRG fail ($s)"; fi
+
+s=$(pigs prs $GPIO 1000)
+if [[ $s = 250 ]]; then echo "PRS-a ok"; else echo "PRS-a fail ($s)"; fi
+s=$(pigs prg $GPIO)
+if [[ $s = 1000 ]]; then echo "PRS-b ok"; else echo "PRS-b fail ($s)"; fi
+s=$(pigs prs $GPIO 255)
+if [[ $s = 250 ]]; then echo "PRS-c ok"; else echo "PRS-c fail ($s)"; fi
+s=$(pigs prg $GPIO)
+if [[ $s = 255 ]]; then echo "PRS-d ok"; else echo "PRS-d fail ($s)"; fi
+
+s=$(pigs pud $GPIO u)
+if [[ $s = "" ]]; then echo "PUD-a ok"; else echo "PUD-a fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 1 ]]; then echo "PUD-b ok"; else echo "PUD-b fail ($s)"; fi
+s=$(pigs pud $GPIO d)
+if [[ $s = "" ]]; then echo "PUD-c ok"; else echo "PUD-c fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 0 ]]; then echo "PUD-d ok"; else echo "PUD-d fail ($s)"; fi
+s=$(pigs pud $GPIO o)
+if [[ $s = "" ]]; then echo "PUD-e ok"; else echo "PUD-e fail ($s)"; fi
+
+s=$(pigs p $GPIO 128)
+if [[ $s = "" ]]; then echo "PWM-a ok"; else echo "PWM-a fail ($s)"; fi
+s=$(pigs pwm $GPIO 64)
+if [[ $s = "" ]]; then echo "PWM-b ok"; else echo "PWM-b fail ($s)"; fi
+s=$(pigs pwm $GPIO 0)
+if [[ $s = "" ]]; then echo "PWM-c ok"; else echo "PWM-c fail ($s)"; fi
+s=$(pigs m $GPIO r)
+if [[ $s = "" ]]; then echo "PWM-d ok"; else echo "PWM-d fail ($s)"; fi
+
+s=$(pigs pud $GPIO u)
+if [[ $s = "" ]]; then echo "READ-a ok"; else echo "READ-a fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 1 ]]; then echo "READ-b ok"; else echo "READ-b fail ($s)"; fi
+s=$(pigs pud $GPIO d)
+if [[ $s = "" ]]; then echo "READ-c ok"; else echo "READ-c fail ($s)"; fi
+s=$(pigs read $GPIO)
+if [[ $s = 0 ]]; then echo "READ-d ok"; else echo "READ-d fail ($s)"; fi
+s=$(pigs pud $GPIO o)
+if [[ $s = "" ]]; then echo "READ-e ok"; else echo "READ-e fail ($s)"; fi
+
+s=$(pigs s $GPIO 500)
+if [[ $s = "" ]]; then echo "SERVO-a ok"; else echo "SERVO-a fail ($s)"; fi
+s=$(pigs servo $GPIO 2500)
+if [[ $s = "" ]]; then echo "SERVO-b ok"; else echo "SERVO-b fail ($s)"; fi
+s=$(pigs servo $GPIO 0)
+if [[ $s = "" ]]; then echo "SERVO-c ok"; else echo "SERVO-c fail ($s)"; fi
+s=$(pigs w $GPIO 1)
+if [[ $s = "" ]]; then echo "SERVO-d ok"; else echo "SERVO-d fail ($s)"; fi
+
+s=$(pigs wvclr)
+if [[ $s = 0 ]]; then echo "SLR-a ok"; else echo "SLR-a fail ($s)"; fi
+s=$(pigs slro $GPIO 1200)
+if [[ $s = 0 ]]; then echo "SLR-b ok"; else echo "SLR-b fail ($s)"; fi
+s=$(pigs wvas $GPIO 1200 0 "my name is joan")
+if [[ $s = 95 ]]; then echo "SLR-c ok"; else echo "SLR-c fail ($s)"; fi
+s=$(pigs m $GPIO w)
+if [[ $s = "" ]]; then echo "SLR-d ok"; else echo "SLR-d fail ($s)"; fi
+s=$(pigs wvgo)
+if [[ $s = 191 ]]; then echo "SLR-e ok"; else echo "SLR-e fail ($s)"; fi
+sleep 0.1
+s=$(pigs slr $GPIO 100)
+if [[ $s = "my name is joan" ]]
+then echo "SLR-f ok"
+else echo "SLR-f fail with [$s]"
+fi
+s=$(pigs slrc $GPIO)
+if [[ $s = 0 ]]; then echo "SLR-g ok"; else echo "SLR-g fail ($s)"; fi
+
+t1=$(pigs t)
+t2=$(pigs tick)
+s=$(($t2-$t1))
+if [[ $s -gt 0 && $s -lt 20000 ]]
+then echo "TICK ok"
+else echo "TICK fail($s)"
+fi
+
+pigs w $GPIO 1 # put in known state
+s=$(pigs trig $GPIO 10 1)
+if [[ $s = "" ]]; then echo "TRIG-a ok"; else echo "TRIG-a fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 0 ]]; then echo "TRIG-b ok"; else echo "TRIG-b fail ($s)"; fi
+s=$(pigs trig $GPIO 10 0)
+if [[ $s = "" ]]; then echo "TRIG-c ok"; else echo "TRIG-c fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 1 ]]; then echo "TRIG-d ok"; else echo "TRIG-d fail ($s)"; fi
+
+s=$(pigs wdog $GPIO 1000)
+if [[ $s = "" ]]; then echo "WDOG-a ok"; else echo "WDOG-a fail ($s)"; fi
+s=$(pigs wdog $GPIO 0)
+if [[ $s = "" ]]; then echo "WDOG-b ok"; else echo "WDOG-b fail ($s)"; fi
+
+s=$(pigs w $GPIO 1)
+if [[ $s = "" ]]; then echo "WRITE-a ok"; else echo "WRITE-a fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 1 ]]; then echo "WRITE-b ok"; else echo "WRITE-b fail ($s)"; fi
+s=$(pigs write $GPIO 0)
+if [[ $s = "" ]]; then echo "WRITE-c ok"; else echo "WRITE-c fail ($s)"; fi
+s=$(pigs r $GPIO)
+if [[ $s = 0 ]]; then echo "WRITE-d ok"; else echo "WRITE-d fail ($s)"; fi
+
+
+s=$(pigs wvclr )
+if [[ $s = 0 ]]; then echo "WVCLR ok"; else echo "WVCLR fail ($s)"; fi
+s=$(pigs wvas $GPIO 300 0 "this is then winter of my discontent made glorious")
+if [[ $s = 309 ]]; then echo "WVAS ok"; else echo "WVAS fail ($s)"; fi
+s=$(pigs wvag 16 0 5000000 0 16 5000000)
+if [[ $s = 310 ]]; then echo "WVAG ok"; else echo "WVAG fail ($s)"; fi
+s=$(pigs wvgo)
+if [[ $s = 621 ]]; then echo "WVGO ok"; else echo "WVGO fail ($s)"; fi
+s=$(pigs wvbsy)
+if [[ $s = 1 ]]; then echo "WVBSY-a ok"; else echo "WVBSY-a fail ($s)"; fi
+sleep 1
+s=$(pigs wvbsy)
+if [[ $s = 1 ]]; then echo "WVBSY-b ok"; else echo "WVBSY-b fail ($s)"; fi
+s=$(pigs wvhlt)
+if [[ $s = 0 ]]; then echo "WVHLT ok"; else echo "WVHLT fail ($s)"; fi
+s=$(pigs wvbsy)
+if [[ $s = 0 ]]; then echo "WVBSY-c ok"; else echo "WVBSY-c fail ($s)"; fi
+s=$(pigs wvgor)
+if [[ $s = 621 ]]; then echo "WVGOR ok"; else echo "WVGOR fail ($s)"; fi
+s=$(pigs wvbsy)
+if [[ $s = 1 ]]; then echo "WVBSY-d ok"; else echo "WVBSY-d fail ($s)"; fi
+s=$(pigs wvhlt)
+if [[ $s = 0 ]]; then echo "WVHLT ok"; else echo "WVHLT fail ($s)"; fi
+s=$(pigs wvbsy)
+if [[ $s = 0 ]]; then echo "WVBSY-e ok"; else echo "WVBSY-e fail ($s)"; fi
+
+s=$(pigs wvsc 0)
+if [[ $s = 620 ]]; then echo "WVSC-a ok"; else echo "WVSC-a fail ($s)"; fi
+s=$(pigs wvsc 1)
+if [[ $s -ge 620 ]]; then echo "WVSC-b ok"; else echo "WVSC-b fail ($s)"; fi
+s=$(pigs wvsc 2)
+if [[ $s = 25016 ]]; then echo "WVSC-c ok"; else echo "WVSC-c fail ($s)"; fi
+
+s=$(pigs wvsm 0)
+if [[ $s = 10000000 ]]; then echo "WVSM-a ok"; else echo "WVSM-a fail ($s)"; fi
+s=$(pigs wvsm 1)
+if [[ $s -ge 10000000 ]]; then echo "WVSM-b ok"; else echo "WVSM-b fail ($s)"; fi
+s=$(pigs wvsm 2)
+if [[ $s = 1800000000 ]]
+then echo "WVSM-c ok"
+else echo "WVSM-c fail ($s)"
+fi
+
+s=$(pigs wvsp 0)
+if [[ $s = 310 ]]; then echo "WVSP-a ok"; else echo "WVSP-a fail ($s)"; fi
+s=$(pigs wvsp 1)
+if [[ $s -ge 310 ]]; then echo "WVSP-b ok"; else echo "WVSP-b fail ($s)"; fi
+s=$(pigs wvsp 2)
+if [[ $s = 12000 ]]; then echo "WVSP-c ok"; else echo "WVSP-c fail ($s)"; fi
+
--- /dev/null
+#!/bin/bash
+
+GPIO=4
+
+#
+# This script serves as a confidence check that the pipe interface to
+# the pigpio library is ok.
+#
+# The script uses gpio 4 (P1-7). Make sure that nothing (or only a LED)
+# is connected to gpio 4 before running the script.
+#
+# To run the script
+# sudo pigpiod # if not already running
+# ./x_pipe # on the Pi running pigpiod
+#
+
+echo "bc1 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "BC1 ok"; else echo "BC1 fail ($s)"; fi
+
+echo "bc2 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "BC2 ok"; else echo "BC2 fail ($s)"; fi
+
+echo "br1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ ${#s} = 8 ]]
+then echo "BR1 ok"
+else echo "BR1 fail ($s)"
+fi
+
+echo "br2" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ ${#s} = 8 ]]
+then echo "BR2 ok"
+else echo "BR2 fail ($s)"
+fi
+
+echo "bs1 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "BS1 ok"; else echo "BS1 fail ($s)"; fi
+
+echo "bs2 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
+
+echo "h" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = "BC1 v Clear gpios defined by mask v in bank 1." ]]
+then echo "HELP-a ok"
+else echo "HELP-a fail ($s)"
+fi
+read -t 1 -N 9000 </dev/pigout # dump rest of help
+echo "help" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = "BC1 v Clear gpios defined by mask v in bank 1." ]]
+then echo "HELP-b ok"
+else echo "HELP-b fail ($s)"
+fi
+read -t 1 -N 9000 </dev/pigout # dump rest of help
+
+echo "hwver" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi
+
+echo "micro 1000" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "MICRO ok"; else echo "MICRO fail ($s)"; fi
+
+echo "milli 10" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "MILLI ok"; else echo "MILLI fail ($s)"; fi
+
+echo "modes $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+echo "modeg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 4 ]]; then echo "MODEG ok"; else echo "MODEG fail ($s)"; fi
+echo "m $GPIO r" >/dev/pigpio
+read -t 1 s </dev/pigout
+echo "mg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "MODES ok"; else echo "MODES fail ($s)"; fi
+
+echo "no" >/dev/pigpio
+read -t 1 h </dev/pigout
+if [[ $h -ge 0 && $h -le 31 ]]
+then echo "NO($h) ok"
+else echo "NO fail ($s)"
+fi
+
+echo "nb $h 0xabcd" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "NB($h) ok"; else echo "NB fail ($s)"; fi
+
+echo "np $h" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "NP($h) ok"; else echo "NP fail ($s)"; fi
+
+echo "nc $h" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "NC($h) ok"; else echo "NC fail ($s)"; fi
+
+echo "pfs $GPIO 800" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 800 ]]; then echo "PFG-a ok"; else echo "PFG-a fail ($s)"; fi
+
+echo "pfg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 800 ]]; then echo "PFG-b ok"; else echo "PFG-b fail ($s)"; fi
+
+echo "pfs $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 10 ]]; then echo "PFS-a ok"; else echo "PFS-a fail ($s)"; fi
+
+echo "pfs $GPIO 800" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 800 ]]; then echo "PFS-b ok"; else echo "PFS-b fail ($s)"; fi
+
+echo "pigpv" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 13 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
+
+echo "prs $GPIO 255" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 250 ]]; then echo "PRG-a ok"; else echo "PRG-a fail ($s)"; fi
+echo "prg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 255 ]]; then echo "PRG-b ok"; else echo "PRG-b fail ($s)"; fi
+
+echo "proc ldap 0 ldpa 1 ldai 29 ldpa 0 label 9 milli 1000 jmp 9" >/dev/pigpio
+read -t 1 p </dev/pigout
+if [[ $p -ge 0 && $p -le 31 ]]
+then echo "PROC($p) ok"
+else echo "PROC($p) fail ($s)"
+fi
+
+echo "procr $p 9876" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PROCR($p) ok"; else echo "PROCR($p) fail ($s)"; fi
+
+echo "procp $p" >/dev/pigpio
+read -t 1 -a v </dev/pigout
+if [[ ${v[0]} = 1 && ${v[1]} = 29 && ${v[2]} = 9876 ]]
+then echo "PROCP($p) ok"
+else echo "PROCP($p) fail ($s)"
+fi
+
+echo "procs $p" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PROCS($p) ok"; else echo "PROCS($p) fail ($s)"; fi
+
+echo "procd $p" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PROCD($p) ok"; else echo "PROCD($p) fail ($s)"; fi
+
+echo "prrg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 250 ]]; then echo "PRRG ok"; else echo "PRRG fail ($s)"; fi
+
+echo "prs $GPIO 1000" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 250 ]]; then echo "PRS-a ok"; else echo "PRS-a fail ($s)"; fi
+echo "prg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1000 ]]; then echo "PRS-b ok"; else echo "PRS-b fail ($s)"; fi
+echo "prs $GPIO 255" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 250 ]]; then echo "PRS-c ok"; else echo "PRS-c fail ($s)"; fi
+echo "prg $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 255 ]]; then echo "PRS-d ok"; else echo "PRS-d fail ($s)"; fi
+
+echo "pud $GPIO u" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PUD-a ok"; else echo "PUD-a fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "PUD-b ok"; else echo "PUD-b fail ($s)"; fi
+echo "pud $GPIO d" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PUD-c ok"; else echo "PUD-c fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PUD-d ok"; else echo "PUD-d fail ($s)"; fi
+echo "pud $GPIO o" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PUD-e ok"; else echo "PUD-e fail ($s)"; fi
+
+echo "p $GPIO 128" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PWM-a ok"; else echo "PWM-a fail ($s)"; fi
+echo "pwm $GPIO 64" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PWM-b ok"; else echo "PWM-b fail ($s)"; fi
+echo "pwm $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PWM-c ok"; else echo "PWM-c fail ($s)"; fi
+echo "m $GPIO r" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "PWM-d ok"; else echo "PWM-d fail ($s)"; fi
+
+echo "pud $GPIO u" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "READ-a ok"; else echo "READ-a fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "READ-b ok"; else echo "READ-b fail ($s)"; fi
+echo "pud $GPIO d" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "READ-c ok"; else echo "READ-c fail ($s)"; fi
+echo "read $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "READ-d ok"; else echo "READ-d fail ($s)"; fi
+echo "pud $GPIO o" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "READ-e ok"; else echo "READ-e fail ($s)"; fi
+
+echo "s $GPIO 500" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SERVO-a ok"; else echo "SERVO-a fail ($s)"; fi
+echo "servo $GPIO 2500" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SERVO-b ok"; else echo "SERVO-b fail ($s)"; fi
+echo "servo $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SERVO-c ok"; else echo "SERVO-c fail ($s)"; fi
+echo "w $GPIO 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SERVO-d ok"; else echo "SERVO-d fail ($s)"; fi
+
+echo "wvclr" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SLR-a ok"; else echo "SLR-a fail ($s)"; fi
+echo "slro $GPIO 1200" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SLR-b ok"; else echo "SLR-b fail ($s)"; fi
+echo "wvas $GPIO 1200 0 my name is joan¬" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 105 ]]; then echo "SLR-c ok"; else echo "SLR-c fail ($s)"; fi
+echo "m $GPIO w" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SLR-d ok"; else echo "SLR-d fail ($s)"; fi
+echo "wvgo" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 211 ]]; then echo "SLR-e ok"; else echo "SLR-e fail ($s)"; fi
+sleep 0.2
+echo "slr $GPIO 100" >/dev/pigpio
+read -t 1 -d ¬ s </dev/pigout
+if [[ $s = "my name is joan" ]]
+then echo "SLR-f ok"
+else echo "SLR-f fail with ($s)"
+fi
+read -t 1 s </dev/pigout # dump any junk
+echo "slrc $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "SLR-g ok"; else echo "SLR-g fail ($s)"; fi
+
+echo "t" >/dev/pigpio
+echo "tick" >/dev/pigpio
+read -t 1 t1 </dev/pigout
+read -t 1 t2 </dev/pigout
+s=$((t2-t1))
+if [[ $s -gt 0 && $s -lt 5000 ]]
+then echo "TICK ok"
+else echo "TICK fail ($s)"
+fi
+
+pigs w $GPIO 1 # put in known state
+echo "trig $GPIO 10 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "TRIG-a ok"; else echo "TRIG-a fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "TRIG-b ok"; else echo "TRIG-b fail ($s)"; fi
+echo "trig $GPIO 10 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "TRIG-c ok"; else echo "TRIG-c fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "TRIG-d ok"; else echo "TRIG-d fail ($s)"; fi
+
+echo "wdog $GPIO 1000" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WDOG-a ok"; else echo "WDOG-a fail ($s)"; fi
+echo "wdog $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WDOG-b ok"; else echo "WDOG-b fail ($s)"; fi
+
+echo "w $GPIO 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WRITE-a ok"; else echo "WRITE-a fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "WRITE-b ok"; else echo "WRITE-b fail ($s)"; fi
+echo "write $GPIO 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WRITE-c ok"; else echo "WRITE-c fail ($s)"; fi
+echo "r $GPIO" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WRITE-d ok"; else echo "WRITE-d fail ($s)"; fi
+
+echo "wvclr" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WVCLR ok"; else echo "WVCLR fail ($s)"; fi
+echo "wvas $GPIO 300 0 this is the winter of my discontent" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 215 ]]; then echo "WVAS ok"; else echo "WVAS fail ($s)"; fi
+echo "wvag 16 0 5000000 0 16 5000000" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 216 ]]; then echo "WVAG ok"; else echo "WVAG fail ($s)"; fi
+echo "wvgo" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 433 ]]; then echo "WVGO ok"; else echo "WVGO fail ($s)"; fi
+echo "wvbsy" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "WVBSY-a ok"; else echo "WVBSY-a fail ($s)"; fi
+sleep 1
+echo "wvbsy" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "WVBSY-b ok"; else echo "WVBSY-b fail ($s)"; fi
+echo "wvhlt" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WVHLT ok"; else echo "WVHLT fail ($s)"; fi
+echo "wvbsy" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WVBSY-c ok"; else echo "WVBSY-c fail ($s)"; fi
+echo "wvgor" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 433 ]]; then echo "WVGOR ok"; else echo "WVGOR fail ($s)"; fi
+echo "wvbsy" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1 ]]; then echo "WVBSY-d ok"; else echo "WVBSY-d fail ($s)"; fi
+echo "wvhlt" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WVHLT ok"; else echo "WVHLT fail ($s)"; fi
+echo "wvbsy" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 0 ]]; then echo "WVBSY-e ok"; else echo "WVBSY-e fail ($s)"; fi
+
+echo "wvsc 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 432 ]]; then echo "WVSC-a ok"; else echo "WVSC-a fail ($s)"; fi
+echo "wvsc 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s -ge 432 ]]; then echo "WVSC-b ok"; else echo "WVSC-b fail ($s)"; fi
+echo "wvsc 2" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 25016 ]]; then echo "WVSC-c ok"; else echo "WVSC-c fail ($s)"; fi
+
+echo "wvsm 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 10000000 ]]; then echo "WVSM-a ok"; else echo "WVSM-a fail ($s)"; fi
+echo "wvsm 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s -ge 10000000 ]]; then echo "WVSM-b ok"; else echo "WVSM-b fail ($s)"; fi
+echo "wvsm 2" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 1800000000 ]]
+then echo "WVSM-c ok"
+else echo "WVSM-c fail ($s)"
+fi
+
+echo "wvsp 0" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 216 ]]; then echo "WVSP-a ok"; else echo "WVSP-a fail ($s)"; fi
+echo "wvsp 1" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s -ge 216 ]]; then echo "WVSP-b ok"; else echo "WVSP-b fail ($s)"; fi
+echo "wvsp 2" >/dev/pigpio
+read -t 1 s </dev/pigout
+if [[ $s = 12000 ]]; then echo "WVSP-c ok"; else echo "WVSP-c fail ($s)"; fi
+