diff --git a/Makefile b/Makefile
index 9b1e561..bfb0beb 100644
--- a/Makefile
+++ b/Makefile
@@ -13,17 +13,22 @@ OBJ2 = pigpiod_if.o command.o
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
@@ -35,6 +40,7 @@ clean:
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
@@ -68,7 +74,8 @@ $(LIB2): $(OBJ2)
# 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
diff --git a/README b/README
index 8737d36..d04da3c 100644
--- a/README
+++ b/README
@@ -20,18 +20,28 @@ o the socket interface (pigs) in /usr/local/bin
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
@@ -77,25 +87,6 @@ pythonx.y setup.py install
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
@@ -105,7 +96,7 @@ sudo killall pigpiod
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.
diff --git a/command.c b/command.c
index 757b082..9bf8f9b 100644
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 12+
+This version is for pigpio version 13+
*/
#include
@@ -58,135 +58,204 @@ This version is for pigpio version 12+
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 */
+ /* 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},
- {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},
};
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< 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;
@@ -264,65 +345,117 @@ static int cmdMatch(char * str)
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];
- sscanf(buf, " %7s", str);
+ bzero(&ctl->opt, sizeof(ctl->opt));
- cmd->cmd = -1;
+ sscanf(buf+ctl->eaten, " %31s", intCmdStr);
- idx = cmdMatch(str);
+ p[0] = -1;
+
+ 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
@@ -332,21 +465,23 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
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;
}
}
@@ -354,15 +489,17 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
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;
}
}
@@ -370,51 +507,167 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
case 10: /* PROC
*/
- if ((argc == 0) || (argc == 3))
- {
- 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;
- valid = 1;
- }
+ p[1] = strlen(buf+ctl->eaten);
+ v[1] = buf+ctl->eaten;
+ ctl->eaten += p[1];
+ valid = 1;
break;
case 11: /* WVAS
*/
- if ((argc == 0) || (argc == 6))
+ 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])
{
- f = sscanf(buf, " %*s %d %d %d %n",
- &cmd->p1, &ext[0].data, &ext[1].data, &p);
- if (f == 3)
+ p[4] = strlen(buf+ctl->eaten);
+ v[1] = buf+ctl->eaten;
+ ctl->eaten += p[4];
+ valid = 1;
+ }
+ break;
+
+ 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
+ */
+ 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)
+ {
+ 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; ieaten+i];
- if (argc) /* pigs */
+ if ((!isalnum(c)) && (c != '_') && (c != '-'))
{
- cmd->p2 = strlen(argv[5]);
- ext[2].ptr = argv[5];
+ valid = 0;
+ break;
}
- else /* pipe i/f */
- {
- cmd->p2 = strlen(buf+p);
- ext[2].ptr = buf+p;
- }
-
- 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;
}
@@ -432,3 +685,4 @@ char * cmdErrStr(int error)
}
return "unknown error";
}
+
diff --git a/command.h b/command.h
index bdffefb..7e62405 100644
--- a/command.h
+++ b/command.h
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 11+
+This version is for pigpio version 13+
*/
#ifndef COMMAND_H
@@ -37,23 +37,39 @@ This version is for pigpio version 11+
#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, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t * ext);
+int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctlParse);
-char * cmdErrStr(int error);
+char *cmdErrStr(int error);
+
+char *cmdStr(void);
#endif
diff --git a/pigpio.c b/pigpio.c
index cde0e58..b9cdb29 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* pigpio version 12 */
+/* pigpio version 13 */
#include
#include
@@ -254,13 +254,6 @@ bit 0 READ_LAST_NOT_SET_ERROR
} \
while (0)
-#define PERM_ERROR(format, arg...) \
- do \
- { \
- fprintf(stderr, "%s " format "\n", myTimeStamp(), ## arg); \
- } \
- while (0)
-
#define TIMER_ADD(a, b, result) \
do \
{ \
@@ -491,20 +484,20 @@ bit 0 READ_LAST_NOT_SET_ERROR
#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)
@@ -515,16 +508,17 @@ bit 0 READ_LAST_NOT_SET_ERROR
#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)
@@ -535,12 +529,14 @@ bit 0 READ_LAST_NOT_SET_ERROR
#define BLOCK_SIZE (PAGES_PER_BLOCK*PAGE_SIZE)
-#define DMA_PAGES (PAGES_PER_BLOCK * bufferBlocks)
+#define DMAI_PAGES (PAGES_PER_BLOCK * bufferBlocks)
+
+#define DMAO_PAGES (PAGES_PER_BLOCK * PI_WAVE_BLOCKS)
+
+#define NUM_OOL (DMAO_PAGES * OOL_PER_OPAGE)
#define TICKSLOTS 50
-#define PI_NOTIFY_SLOTS 32
-
#define PI_NOTIFY_CLOSED 0
#define PI_NOTIFY_CLOSING 1
#define PI_NOTIFY_OPENED 2
@@ -549,7 +545,7 @@ bit 0 READ_LAST_NOT_SET_ERROR
#define PI_WFRX_NONE 0
#define PI_WFRX_SERIAL 1
-#define PI_WF_MICROS 2
+#define PI_WF_MICROS 1
#define DATUMS 2000
@@ -558,7 +554,7 @@ bit 0 READ_LAST_NOT_SET_ERROR
#define MAX_EMITS (PIPE_BUF / sizeof(gpioReport_t))
#define SRX_BUF_SIZE 8192
-#define CMD_BUF_SIZE 2048
+#define CMD_BUF_SIZE 4096
/* --------------------------------------------------------------- */
@@ -587,13 +583,13 @@ typedef struct
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;
@@ -630,6 +626,12 @@ typedef struct
uint32_t bits;
} gpioGetSamples_t;
+typedef struct
+{
+ uint32_t label;
+ int step;
+} gpioLabelStep_t;
+
typedef struct
{
callbk_t func;
@@ -642,6 +644,51 @@ typedef struct
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;
@@ -752,7 +799,7 @@ static struct timespec libStarted;
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};
@@ -762,14 +809,15 @@ static wfStats_t wfStats=
{
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;
@@ -787,6 +835,8 @@ static gpioInfo_t gpioInfo [PI_MAX_USER_GPIO+1];
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];
@@ -864,10 +914,15 @@ static const uint16_t pwmRealRange[PWM_FREQS]=
/* ======================================================================= */
-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;
@@ -878,11 +933,12 @@ static void myGpioSleep(int seconds, int micros)
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;
@@ -896,6 +952,8 @@ static uint32_t myGpioDelay(uint32_t micros)
return (systReg[SYST_CLO] - start);
}
+/* ----------------------------------------------------------------------- */
+
static char * myTimeStamp()
{
static struct timeval last;
@@ -926,7 +984,7 @@ static void myCreatePipe(char * name, int perm)
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;
}
}
@@ -985,30 +1043,176 @@ static uint32_t myGetTick(int pos)
/* ----------------------------------------------------------------------- */
-static void myDoCommand
- (cmdCmd_t *cmd, gpioExtent_t *iExt, gpioExtent_t *oExt)
+static int myParseScript(char *script, gpioScript_t *s)
{
- int p1, p2, res, i;
- uint32_t mask, tmp;
+ 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)= 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; jinstrs;
+ 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; iinstrs; 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; jinstr[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 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;
@@ -1016,13 +1220,13 @@ static void myDoCommand
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;
@@ -1034,13 +1238,13 @@ static void myDoCommand
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;
@@ -1048,13 +1252,13 @@ static void myDoCommand
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;
@@ -1063,121 +1267,129 @@ static void myDoCommand
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<= 0)) res = PI_SOME_PERMITTED;
@@ -1215,17 +1429,13 @@ static void myDoCommand
break;
case PI_CMD_WVAS:
- if (gpioMask & (uint64_t)(1<res = res;
+ return (res);
}
/* ----------------------------------------------------------------------- */
@@ -1390,8 +1600,8 @@ static void myGpioSetServo(unsigned gpio, int oldVal, int newVal)
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;
@@ -1462,17 +1672,35 @@ static uint32_t waveCbPOadr(int pos)
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 uint32_t waveOnOffPOadr(int pos)
+static void waveSetOOL(int pos, uint32_t OOL)
{
int page, slot;
- page = pos/ONOFF_PER_OPAGE;
- slot = pos%ONOFF_PER_OPAGE;
+ waveOOLPageSlot(pos, &page, &slot);
- return (uint32_t) &dmaOPhys[page]->gpioOnOff[slot];
+ dmaOVirt[page]->OOL[slot] = OOL;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static uint32_t waveOOLPOadr(int pos)
+{
+ int page, slot;
+
+ waveOOLPageSlot(pos, &page, &slot);
+
+ return (uint32_t) &dmaOPhys[page]->OOL[slot];
}
@@ -1491,7 +1719,7 @@ static void waveCbOPrint(int pos)
/* ----------------------------------------------------------------------- */
-void waveBitDelay(unsigned baud, unsigned * bitDelay)
+static void waveBitDelay(unsigned baud, unsigned * bitDelay)
{
unsigned fullBit, halfBit, s, e, d, m, i, err;
@@ -1528,47 +1756,22 @@ void waveBitDelay(unsigned baud, unsigned * bitDelay)
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; igpioOnOff[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++);
@@ -1655,7 +1878,7 @@ static int wave2Cbs(unsigned mode)
}
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;
}
}
@@ -1755,9 +1978,9 @@ static void waveRxBit(int gpio, int level, uint32_t tick)
/* ----------------------------------------------------------------------- */
-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;
@@ -1765,7 +1988,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
uint32_t tNow, tNext1, tNext2, tDelay;
- gpioPulse_t * in2, * out;
+ gpioWave_t *in2, *out;
numIn2 = wfc[wfcur];
in2 = wf[wfcur];
@@ -1793,6 +2016,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
out[outPos].gpioOn = in1[inPos1].gpioOn;
out[outPos].gpioOff = in1[inPos1].gpioOff;
+ out[outPos].flags = in1[inPos1].flags;
tNext1 = tNow + in1[inPos1].usDelay; ++inPos1;
}
@@ -1809,6 +2033,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
out[outPos].gpioOn = in2[inPos2].gpioOn;
out[outPos].gpioOff = in2[inPos2].gpioOff;
+ out[outPos].flags = in2[inPos2].flags;
tNext2 = tNow + in2[inPos2].usDelay; ++inPos2;
}
@@ -1825,6 +2050,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
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;
@@ -1841,6 +2067,18 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
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;
@@ -1848,7 +2086,7 @@ static int waveMerge(unsigned numIn1, gpioPulse_t * in1)
}
- if (outPos < numOut)
+ if ((outPos < numOut) && (outPos < level))
{
wfStats.micros = tNow;
@@ -1897,7 +2135,7 @@ static void dmaCbPrint(int pos)
/* ----------------------------------------------------------------------- */
-static unsigned dmaCurrentCb(void)
+static unsigned dmaNowAtICB(void)
{
unsigned cb;
static unsigned lastPage=0;
@@ -1932,7 +2170,43 @@ static unsigned dmaCurrentCb(void)
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;
}
@@ -1961,6 +2235,8 @@ static uint32_t dmaPwmDataAdr(int pos)
return (uint32_t) &dmaIPhys[pos]->periphData;
}
+/* ----------------------------------------------------------------------- */
+
static uint32_t dmaGpioOnAdr(int pos)
{
int page, slot;
@@ -2095,7 +2371,7 @@ static void dmaDelayCb(int b)
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;
}
@@ -2186,13 +2462,19 @@ static void sigHandler(int signum)
}
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);
}
@@ -2202,7 +2484,7 @@ static void sigHandler(int signum)
{
/* exit */
- DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
+ DBG(DBG_ALWAYS, "Unhandled signal %d, terminating\n", signum);
exit(-1);
}
@@ -2256,7 +2538,7 @@ static void * pthAlertThread(void *x)
gpioStats.startTick = tick;
- oldSlot = dmaCurrentSlot(dmaCurrentCb());
+ oldSlot = dmaCurrentSlot(dmaNowAtICB());
cycle = (oldSlot/PULSE_PER_CYCLE);
pulse = (oldSlot%PULSE_PER_CYCLE);
@@ -2273,7 +2555,7 @@ static void * pthAlertThread(void *x)
req.tv_nsec = rem.tv_nsec;
}
- newSlot = dmaCurrentSlot(dmaCurrentCb());
+ newSlot = dmaCurrentSlot(dmaNowAtICB());
numSamples = 0;
@@ -2581,6 +2863,28 @@ static void * pthAlertThread(void *x)
}
}
+ if (changedBits & scriptBits)
+ {
+ for (n=0; n 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 scrPush(gpioScript_t *s, int *SP, int *S, int val)
+{
+ 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);
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void scrSwap(int *v1, int *v2)
+{
+ int t;
+
+ 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)
+ {
+ s->run_state = PI_SCRIPT_WAITING;
+ s->waitBits = bits;
+ intScriptBits();
+
+ pthread_cond_wait(&s->pthCond, &s->pthMutex);
+
+ s->waitBits = 0;
+ intScriptBits();
+ s->run_state = PI_SCRIPT_RUNNING;
+ }
+
+ pthread_mutex_unlock(&s->pthMutex);
+
+ 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)
@@ -2652,11 +3210,15 @@ static void * pthTimerTick(void *x)
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);
@@ -2686,53 +3248,79 @@ static void * pthFifoThread(void *x)
buf[len] = 0; /* replace terminating */
}
- if ((idx=cmdParse(buf, &cmd, 0, NULL, iExt)) >= 0)
+ ctl.eaten = 0;
+ idx = 0;
+
+ while (((ctl.eaten)= 0))
{
- oExt[0].ptr = buf;
- oExt[0].size = CMD_BUF_SIZE-1;
-
- myDoCommand(&cmd, iExt, oExt);
-
- switch (cmdInfo[idx].rv)
+ if ((idx=cmdParse(buf, p, v, &ctl)) >= 0)
{
- case 0:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ oExt[0].ptr = buf;
+ oExt[0].size = CMD_BUF_SIZE-1;
- case 1:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ 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;
+ }
- case 2:
- fprintf(outFifo, "%d\n", cmd.res);
- break;
+ res = myDoCommand(p, oExt);
- case 3:
- fprintf(outFifo, "%08X\n", cmd.res);
- break;
+ switch (cmdInfo[idx].rv)
+ {
+ case 0:
+ fprintf(outFifo, "%d\n", res);
+ break;
- case 4:
- fprintf(outFifo, "%u\n", cmd.res);
- break;
+ case 1:
+ fprintf(outFifo, "%d\n", res);
+ break;
- case 5:
- fprintf(outFifo, cmdUsage);
- break;
+ case 2:
+ fprintf(outFifo, "%d\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 3:
+ fprintf(outFifo, "%08X\n", res);
+ break;
+ case 4:
+ fprintf(outFifo, "%u\n", res);
+ 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 0)
- {
- write(sock, oExt[0].ptr, cmd.res);
- }
- break;
-
- default:
- break;
- }
-
+ else res = PI_NO_MEMORY;
+ break;
+ default:
+ res = myDoCommand(p, oExt);
+ break;
+ }
+
+ p[3] = res;
+
+ write(sock, p, 16);
+
+ switch (p[0])
+ {
+ case PI_CMD_SLR: /* extension */
+
+ if (res > 0)
+ {
+ write(sock, oExt[0].ptr, res);
+ }
+ 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);
@@ -3291,7 +3913,7 @@ static int initDMAcbs(void)
(uint32_t)gpioReg, (uint32_t)pwmReg,
(uint32_t)pcmReg, (uint32_t)clkReg);
- for (i=0; i= 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;
+
+ gettimeofday(&tv, 0);
+
+ t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6);
+
+ return t;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void time_sleep(double seconds)
+{
+ struct timespec ts, rem;
+
+ if (seconds > 0.0)
+ {
+ ts.tv_sec = seconds;
+ ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9;
+
+ 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;
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+void gpioDumpWave(void)
+{
+ int i;
+
+ unsigned numWaves, t;
+
+ gpioWave_t *waves;
+
+ numWaves = wfc[wfcur];
+ waves = wf [wfcur];
+
+ t = 0;
+
+ for (i=0; i PI_WAVE_MAX_PULSES)
SOFT_ERROR(PI_TOO_MANY_PULSES, "bad number of pulses (%d)", numPulses);
- return waveMerge(numPulses, pulses);
+ for (p=0; p bitDelay[0]) wf[2][p].usDelay = offset;
else wf[2][p].usDelay = bitDelay[0];
@@ -4461,6 +5269,7 @@ int gpioWaveAddSerial(unsigned gpio,
wf[2][p].gpioOn = 0;
wf[2][p].gpioOff = (1< 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<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<= DBG_SLOW_TICK)
@@ -4727,7 +5683,7 @@ static int intGpioSetAlertFunc(
alertBits &= ~BIT;
}
- monitorBits = alertBits | notifyBits | gpioGetSamples.bits;
+ monitorBits = alertBits | notifyBits | scriptBits | gpioGetSamples.bits;
return 0;
}
@@ -4784,6 +5740,7 @@ int gpioNotifyOpen(void)
{
if (gpioNotify[i].state == PI_NOTIFY_CLOSED)
{
+ gpioNotify[i].state = PI_NOTIFY_OPENED;
slot = i;
break;
}
@@ -4799,9 +5756,11 @@ int gpioNotifyOpen(void)
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;
@@ -4846,6 +5805,27 @@ static int gpioNotifyOpenInBand(int fd)
/* ----------------------------------------------------------------------- */
+static void intScriptBits(void)
+{
+ int i;
+ uint32_t bits;
+
+ bits = 0;
+
+ for (i=0; irequest = 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;
+}
+
/* ----------------------------------------------------------------------- */
@@ -5214,11 +6289,24 @@ int gpioStopScript(int 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;
}
-
-
/* ----------------------------------------------------------------------- */
int gpioDeleteScript(int script_id)
@@ -5227,7 +6315,37 @@ int gpioDeleteScript(int 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;
}
@@ -5441,7 +6559,7 @@ uint32_t gpioDelay(uint32_t micros)
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));
@@ -5672,7 +6790,7 @@ int gpioCfgInternals(unsigned what, int value)
gpioCfg.showStats = value;
- DBG(DBG_MIN_LEVEL, "showStats is %u", value);
+ DBG(DBG_ALWAYS, "showStats is %u", value);
retVal = 0;
@@ -5680,13 +6798,13 @@ int gpioCfgInternals(unsigned what, int value)
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;
diff --git a/pigpio.h b/pigpio.h
index bf5fa89..0ddac32 100644
--- a/pigpio.h
+++ b/pigpio.h
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 12
+This version is for pigpio version 13
*/
#ifndef PIGPIO_H
@@ -86,7 +86,7 @@ This version is for pigpio version 12
#include
#include
-#define PIGPIO_VERSION 12
+#define PIGPIO_VERSION 13
/*-------------------------------------------------------------------------*/
@@ -164,6 +164,7 @@ gpioStopThread Stop a previously started thread.
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.
@@ -217,6 +218,12 @@ gpioCfgSocketPort Configure socket port.
extern "C" {
#endif
+typedef struct
+{
+ uint16_t func;
+ uint16_t size;
+} gpioHeader_t;
+
typedef struct
{
uint32_t cmd;
@@ -229,7 +236,7 @@ typedef struct
{
size_t size;
void *ptr;
- int data;
+ uint32_t data;
} gpioExtent_t;
typedef struct
@@ -253,6 +260,29 @@ 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);
@@ -768,6 +798,8 @@ int gpioNotifyOpen(void);
handle.
*/
+#define PI_NOTIFY_SLOTS 32
+
/*-------------------------------------------------------------------------*/
@@ -915,7 +947,7 @@ int gpioWaveAddSerial(unsigned user_gpio,
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)
@@ -924,8 +956,6 @@ int gpioWaveAddSerial(unsigned user_gpio,
#define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */
-
-
/*-------------------------------------------------------------------------*/
int gpioWaveTxStart(unsigned mode);
/*-------------------------------------------------------------------------*/
@@ -1321,18 +1351,53 @@ int gpioStoreScript(char *script);
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
+
+
+
/* ----------------------------------------------------------------------- */
int gpioStopScript(int script_id);
/* ----------------------------------------------------------------------- */
@@ -1798,12 +1863,98 @@ int gpioCfgInternals(unsigned what,
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);
+/*-------------------------------------------------------------------------*/
+/* 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);
+/*-------------------------------------------------------------------------*/
+/* 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 gpioWaveDump(void);
+void time_sleep(double seconds);
/*-------------------------------------------------------------------------*/
-/* Used to print a readable version of the current waveform to stdout.
+/* 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.
*/
@@ -1859,6 +2010,10 @@ void gpioWaveDump(void);
#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.
@@ -1872,6 +2027,53 @@ after this command is issued.
#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
/*-------------------------------------------------------------------------*/
@@ -1930,7 +2132,17 @@ after this command is issued.
#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 */
/*-------------------------------------------------------------------------*/
diff --git a/pigpio.py b/pigpio.py
index dd74105..f5591ca 100644
--- a/pigpio.py
+++ b/pigpio.py
@@ -76,7 +76,7 @@ import threading
import os
import atexit
-VERSION = "1.3"
+VERSION = "1.4"
# gpio levels
@@ -113,6 +113,13 @@ PUD_OFF = 0
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
@@ -160,6 +167,7 @@ _PI_CMD_PROCS=41
_PI_CMD_SLRO= 42
_PI_CMD_SLR= 43
_PI_CMD_SLRC= 44
+_PI_CMD_PROCP=45
_PI_CMD_NOIB= 99
@@ -205,7 +213,7 @@ _PI_BAD_CFG_INTERNAL=-34
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
@@ -218,6 +226,18 @@ PI_BAD_SCRIPT =-47
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
@@ -270,6 +290,19 @@ _errors=[
[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
@@ -348,8 +381,8 @@ def _pigpio_command(sock, cmd, p1, p2):
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))
@@ -364,8 +397,8 @@ def _pigpio_command_ext(sock, cmd, p1, p2, extents):
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:
@@ -1676,15 +1709,57 @@ def store_script(script):
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.
"""
- return _u2i(_pigpio_command(_control, _PI_CMD_PROCR, script_id, 0))
+ # 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.
+ """
+ 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):
"""
@@ -2015,7 +2090,8 @@ def start(host = os.getenv("PIGPIO_ADDR", ''),
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.
diff --git a/pigpiod_if.c b/pigpiod_if.c
index 4960150..2fab6d0 100644
--- a/pigpiod_if.c
+++ b/pigpiod_if.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* PIGPIOD_IF_VERSION 3 */
+/* PIGPIOD_IF_VERSION 4 */
#include
#include
@@ -534,10 +534,10 @@ int get_mode(unsigned gpio)
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)
@@ -600,7 +600,7 @@ uint32_t get_current_tick(void)
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)
@@ -725,8 +725,41 @@ int store_script(char *script)
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);}
diff --git a/pigpiod_if.h b/pigpiod_if.h
index c8e8fc5..809800c 100644
--- a/pigpiod_if.h
+++ b/pigpiod_if.h
@@ -30,7 +30,7 @@ For more information, please refer to
#include "pigpio.h"
-#define PIGPIOD_IF_VERSION 3
+#define PIGPIOD_IF_VERSION 4
typedef enum
{
@@ -79,7 +79,7 @@ pthread_t *start_thread(gpioThreadFunc_t func, void *arg);
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);
@@ -87,7 +87,7 @@ 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);
@@ -139,7 +139,7 @@ int set_pull_up_down(unsigned gpio, unsigned pud);
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.
@@ -147,7 +147,7 @@ int read_gpio(unsigned gpio);
gpio:0-53.
*/
-int write_gpio(unsigned gpio, unsigned level);
+int gpio_write(unsigned gpio, unsigned level);
/*
Write the gpio level.
@@ -507,6 +507,12 @@ uint32_t get_hardware_revision(void);
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.
@@ -659,10 +665,31 @@ int store_script(char *script);
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);
@@ -684,7 +711,7 @@ int serial_read_open(unsigned user_gpio, unsigned baud);
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.
diff --git a/pigs.c b/pigs.c
index 4043c70..35c47e4 100644
--- a/pigs.c
+++ b/pigs.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 12+
+This version is for pigpio version 13+
*/
#include
@@ -47,6 +47,9 @@ This program provides a socket interface to some of
the commands available from pigpio.
*/
+char command_buf[8192];
+char response_buf[8192];
+
void fatal(char *fmt, ...)
{
char buf[128];
@@ -103,109 +106,226 @@ static int openSocket(void)
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= 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)
+ command_buf[0] = 0;
+ l = 0;
+ pp = 0;
+
+ for (i=1; i= 0)
+ if (pp) {command_buf[--pp] = 0;}
+
+ ctl.flags = 0;
+ ctl.eaten = 0;
+
+ len = strlen(command_buf);
+ idx = 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 0)
- {
- recv(sock, &buf, r, MSG_WAITALL);
- buf[r] = 0;
- printf("%s", buf);
- }
+ case PI_CMD_PROC:
+ cmd.p2 = 0;
break;
}
+
+ if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+ {
+ put_extensions(sock, command, p, v);
+
+ if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) ==
+ sizeof(cmdCmd_t))
+ {
+ get_extensions(sock, command, cmd.res);
+
+ 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");
diff --git a/setup.py b/setup.py
index 3a8ea36..dc6e304 100644
--- a/setup.py
+++ b/setup.py
@@ -3,15 +3,15 @@
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']
)
diff --git a/x_pigpio.c b/x_pigpio.c
new file mode 100644
index 0000000..d884f4d
--- /dev/null
+++ b/x_pigpio.c
@@ -0,0 +1,638 @@
+/*
+gcc -o x_pigpio x_pigpio.c -lpigpio -lrt -lpthread
+sudo ./x_pigpio
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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< 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<= (((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<
+#include
+#include
+#include
+#include
+#include
+
+#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< 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</dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 h /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 p /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 -a v /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 -d ¬ s /dev/pigpio
+read -t 1 s /dev/pigpio
+echo "tick" >/dev/pigpio
+read -t 1 t1 /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s /dev/pigpio
+read -t 1 s