V14
authorjoan <joan@abyz.me.uk>
Sat, 19 Apr 2014 11:19:29 +0000 (12:19 +0100)
committerjoan <joan@abyz.me.uk>
Sat, 19 Apr 2014 11:19:29 +0000 (12:19 +0100)
17 files changed:
README
command.c
command.h
pigpio.c
pigpio.h
pigpio.py
pigpiod.c
pigpiod_if.c
pigpiod_if.h
pigs.c
setup.py
tarball [new file with mode: 0755]
x_pigpio.c
x_pigpio.py
x_pigpiod_if.c
x_pigs
x_pipe

diff --git a/README b/README
index d04da3cc91c8170865c65691434ade0c5d6f915e..a9993b5eb0c553fda217510a24fa75456df1fe60 100644 (file)
--- a/README
+++ b/README
@@ -22,11 +22,18 @@ o the Python module pigpio.py
 
 TEST (optional)
 
+*** WARNING ************************************************
+*                                                          *
+* All the tests make extensive use of gpio 4 (pin P1-7).   *
+* Ensure that either nothing or just a LED is connected to *
+* gpio 4 before running any of the tests.                  *
+************************************************************
+
 To test the library do
 
 sudo ./x_pigpio
 
-To text the pigpio daemon do
+To test the pigpio daemon do
 
 sudo pigpiod
 
@@ -41,7 +48,7 @@ x_pigpio.c, pig2vcd.c, and pigpiod.c show examples of interfacing
 with the pigpio library.
 
 pigs.c, pigpio.py, x_pigpiod_if.c, x_pigpio.py, x_pigs, and x_pipe
-show examples of interfacing with the pigpiod daemon.
+show examples of interfacing with the pigpio daemon.
 
 DAEMON
 
index 9bf8f9bdc21d8543cb7693472dd120882c0de43e..683b587a624211a47a252477cd643d2a3cd71590 100644 (file)
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 13+
+This version is for pigpio version 14+
 */
 
 #include <stdio.h>
@@ -38,170 +38,137 @@ This version is for pigpio version 13+
 #include "pigpio.h"
 #include "command.h"
 
-/* retv
-  pigs          pipe
-0 ""   <0 ERR   %d
-1 ""   <0 ERR   %d
-2 %d   <0 ERR   %d
-3 %08X          %08X
-4 %u            %u
-5 HELP          HELP
-6 %s   <0 ERR
-*/
-
-/* vfyt
- 1 cmd
- 2 cmd   %d
- 3 cmd   %d %d
- 4 cmd   %d %x
- 6 HELP
- 7 cmd   %x
- 8 MODES %d %c
- 9 PUD   %d %c
-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 */
 
-   {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",   111, 1},
+   {PI_CMD_BC2,   "BC2",   111, 1},
+   {PI_CMD_BR1,   "BR1",   101, 3},
+   {PI_CMD_BR2,   "BR2",   101, 3},
+   {PI_CMD_BS1,   "BS1",   111, 1},
+   {PI_CMD_BS2,   "BS2",   111, 1},
+   {PI_CMD_HELP,  "H",     101, 5},
+   {PI_CMD_HELP,  "HELP",  101, 5},
+   {PI_CMD_HWVER, "HWVER", 101, 4},
+   {PI_CMD_MICS,  "MICS",  112, 0},
+   {PI_CMD_MILS,  "MILS",  112, 0},
+   {PI_CMD_MODEG, "MG"   , 112, 2},
+   {PI_CMD_MODEG, "MODEG", 112, 2},
+   {PI_CMD_MODES, "M",     125, 0},
+   {PI_CMD_MODES, "MODES", 125, 0},
+   {PI_CMD_NB,    "NB",    122, 0},
+   {PI_CMD_NC,    "NC",    112, 0},
+   {PI_CMD_NO,    "NO",    101, 2},
+   {PI_CMD_NP,    "NP",    112, 0},
+   {PI_CMD_PARSE, "PARSE", 115, 2},
+   {PI_CMD_PFG,   "PFG",   112, 2},
+   {PI_CMD_PFS,   "PFS",   121, 2},
+   {PI_CMD_PIGPV, "PIGPV", 101, 4},
+   {PI_CMD_PRG,   "PRG",   112, 2},
+   {PI_CMD_PROC,  "PROC",  115, 2},
+   {PI_CMD_PROCD, "PROCD", 112, 2},
+   {PI_CMD_PROCP, "PROCP", 112, 7},
+   {PI_CMD_PROCR, "PROCR", 191, 2},
+   {PI_CMD_PROCS, "PROCS", 112, 2},
+   {PI_CMD_PRRG,  "PRRG",  112, 2},
+   {PI_CMD_PRS,   "PRS",   121, 2},
+   {PI_CMD_PUD,   "PUD",   126, 0},
+   {PI_CMD_PWM,   "P",     121, 0},
+   {PI_CMD_PWM,   "PWM",   121, 0},
+   {PI_CMD_READ,  "R",     112, 2},
+   {PI_CMD_READ,  "READ",  112, 2},
+   {PI_CMD_SERVO, "S",     121, 0},
+   {PI_CMD_SERVO, "SERVO", 121, 0},
+   {PI_CMD_SLR,   "SLR",   121, 6},
+   {PI_CMD_SLRC,  "SLRC",  112, 2},
+   {PI_CMD_SLRO,  "SLRO",  121, 2},
+   {PI_CMD_TICK,  "T",     101, 4},
+   {PI_CMD_TICK,  "TICK",  101, 4},
+   {PI_CMD_TRIG,  "TRIG",  131, 0},
+   {PI_CMD_WDOG,  "WDOG",  121, 0},
+   {PI_CMD_WRITE, "W",     121, 0},
+   {PI_CMD_WRITE, "WRITE", 121, 0},
+   {PI_CMD_WVAG,  "WVAG",  192, 2},
+   {PI_CMD_WVAS,  "WVAS",  141, 2},
+   {PI_CMD_WVBSY, "WVBSY", 101, 2},
+   {PI_CMD_WVCLR, "WVCLR", 101, 2},
+   {PI_CMD_WVCRE, "WVCRE", 101, 2},
+   {PI_CMD_WVDEL, "WVDEL", 112, 2},
+   {PI_CMD_WVGO,  "WVGO" , 101, 2},
+   {PI_CMD_WVGOR, "WVGOR", 101, 2},
+   {PI_CMD_WVHLT, "WVHLT", 101, 2},
+   {PI_CMD_WVNEW, "WVNEW", 101, 2},
+   {PI_CMD_WVSC,  "WVSC",  112, 2},
+   {PI_CMD_WVSM,  "WVSM",  112, 2},
+   {PI_CMD_WVSP,  "WVSP",  112, 2},
+   {PI_CMD_WVTX,  "WVTX",  112, 2},
+   {PI_CMD_WVTXR, "WVTXR", 112, 2},
+
+   {PI_CMD_ADD  , "ADD"  , 111, 0},
+   {PI_CMD_AND  , "AND"  , 111, 0},
+   {PI_CMD_CALL , "CALL" , 114, 0},
+   {PI_CMD_CMP  , "CMP"  , 111, 0},
+   {PI_CMD_DCR  , "DCR"  , 113, 0},
+   {PI_CMD_DCRA , "DCRA" , 101, 0},
+   {PI_CMD_DIV  , "DIV"  , 111, 0},
+   {PI_CMD_HALT , "HALT" , 101, 0},
+   {PI_CMD_INR  , "INR"  , 113, 0},
+   {PI_CMD_INRA , "INRA" , 101, 0},
+   {PI_CMD_JM   , "JM"   , 114, 0},
+   {PI_CMD_JMP  , "JMP"  , 114, 0},
+   {PI_CMD_JNZ  , "JNZ"  , 114, 0},
+   {PI_CMD_JP   , "JP"   , 114, 0},
+   {PI_CMD_JZ   , "JZ"   , 114, 0},
+   {PI_CMD_LD   , "LD"   , 123, 0},
+   {PI_CMD_LDA  , "LDA"  , 111, 0},
+   {PI_CMD_MLT  , "MLT"  , 111, 0},
+   {PI_CMD_MOD  , "MOD"  , 111, 0},
+   {PI_CMD_OR   , "OR"   , 111, 0},
+   {PI_CMD_POP  , "POP"  , 113, 0},
+   {PI_CMD_POPA , "POPA" , 101, 0},
+   {PI_CMD_PUSH , "PUSH" , 113, 0},
+   {PI_CMD_PUSHA, "PUSHA", 101, 0},
+   {PI_CMD_RET  , "RET"  , 101, 0},
+   {PI_CMD_RL   , "RL"   , 123, 0},
+   {PI_CMD_RLA  , "RLA"  , 111, 0},
+   {PI_CMD_RR   , "RR"   , 123, 0},
+   {PI_CMD_RRA  , "RRA"  , 111, 0},
+   {PI_CMD_STA  , "STA"  , 113, 0},
+   {PI_CMD_SUB  , "SUB"  , 111, 0},
+   {PI_CMD_SYS  , "SYS"  , 116, 0},
+   {PI_CMD_TAG  , "TAG"  , 114, 0},
+   {PI_CMD_WAIT , "WAIT" , 111, 0},
+   {PI_CMD_X    , "X"    , 124, 0},
+   {PI_CMD_XA   , "XA"   , 113, 0},
+   {PI_CMD_XOR  , "XOR"  , 111, 0},
 
 };
 
 char * cmdUsage = "\
-BC1 v         Clear gpios defined by mask v in bank 1.\n\
-BC2 v         Clear gpios defined by mask v in bank 2.\n\
+BC1 v         Clear gpios specified by mask v in bank 1.\n\
+BC2 v         Clear gpios specified 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\
+BS1 v         Set gpios specified by mask v in bank 1.\n\
+BS2 v         Set gpios specified 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\
+MICS v        Delay for v microseconds.\n\
+MILS 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\
+NB h v        Start notifications on handle h for gpios specified 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\
+P u v         Set PWM value for user gpio u to v.\n\
+PARSE t       Validate script text t without storing.\n\
 PFG u         Get PWM frequency for user gpio u.\n\
-PFS u v       Set PWM frequency for user gpio u to d.\n\
+PFS u v       Set PWM frequency for user gpio u to v.\n\
 PIGPV         Return pigpio version.\n\
 PRG u         Get PWM range for user gpio u.\n\
 PROC t        Store text t of script.\n\
@@ -210,13 +177,13 @@ 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\
+PRS u v       Set PWM range for user gpio u to v.\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\
+PWM u v       Set PWM value for user gpio u to v.\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\
+S u v         Set servo value for user gpio u to v microseconds.\n\
+SERVO u v     Set servo value for user gpio u to v 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\
@@ -224,34 +191,40 @@ 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\
+WDOG u v      Set watchdog of v 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\
+WVCRE         Create wave from added pulses.\n\
+WVDEL w       Delete waves w and higher.\n\
+WVGO          Wave transmit (DEPRECATED).\n\
+WVGOR         Wave transmit repeatedly (DEPRECATED).\n\
 WVHLT         Wave stop.\n\
+WVNEW         Start a new empty wave.\n\
 WVSC ws       Wave get DMA control block stats.\n\
 WVSM ws       Wave get micros stats.\n\
 WVSP ws       Wave get pulses stats.\n\
+WVTX w        Transmit wave w as one-shot.\n\
+WVTXR w       Transmit wave w repeatedly.\n\
 \n\
 b = baud rate.\n\
 g = any gpio (0-53).\n\
-h = handle (0-31).\n\
+h = handle (>=0).\n\
 L = level (0-1).\n\
 m = mode (RW540123).\n\
 mask = a bit mask where (1<<g) is set for each gpio g of interest.\n\
-o = offset (0-).\n\
+o = offset (>=0).\n\
 p = pud (ODU).\n\
 pars = 0 to 10 parameters for script.\n\
-pl = pulse length (0-100).\n\
+pl = pulse length (1-50).\n\
 pulses = 1 or more triplets of gpios on, gpios off, delay.\n\
-s = script id (0-31).\n\
+s = script id (>=0).\n\
 t = text.\n\
 u = user gpio (0-31).\n\
 v = value.\n\
+w = wave id (>=0).\n\
 ws = 0=now, 1=high, 2=max.\n\
 \n\
 Numbers may be entered as hex (prefix 0x), octal (prefix 0),\n\
@@ -311,15 +284,15 @@ static errInfo_t errInfo[]=
    {PI_BAD_WVSC_COMMND  , "bad WVSC subcommand"},
    {PI_BAD_WVSM_COMMND  , "bad WVSM subcommand"},
    {PI_BAD_WVSP_COMMND  , "bad WVSP subcommand"},
-   {PI_BAD_PULSELEN     , "trigger pulse > 100 microseconds"},
+   {PI_BAD_PULSELEN     , "trigger pulse > 50 microseconds"},
    {PI_BAD_SCRIPT       , "invalid script"},
    {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_DUP_TAG          , "script has duplicate tag"},
+   {PI_TOO_MANY_TAGS    , "script has too many tags"},
    {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"},
@@ -328,6 +301,14 @@ static errInfo_t errInfo[]=
    {PI_SOCK_WRIT_FAILED , "socket write failed"},
    {PI_TOO_MANY_PARAM   , "too many script parameters > 10"},
    {PI_NOT_HALTED       , "script already running or failed"},
+   {PI_BAD_TAG          , "script has unresolved tag"},
+   {PI_BAD_MICS_DELAY   , "bad MICS delay (too large)"},
+   {PI_BAD_MILS_DELAY   , "bad MILS delay (too large)"},
+   {PI_BAD_WAVE_ID      , "non existent wave id"},
+   {PI_TOO_MANY_CBS     , "No more CBs for waveform"},
+   {PI_TOO_MANY_OOL     , "No more OOL for waveform"},
+   {PI_EMPTY_WAVEFORM   , "attempt to create an empty waveform"},
+   {PI_NO_WAVEFORM_ID   , "no more waveform ids"},
 
 };
 
@@ -342,12 +323,13 @@ static int cmdMatch(char *str)
    {
       if (strcasecmp(str, cmdInfo[i].name) == 0) return i;
    }
-   return -1;
+   return CMD_UNKNOWN_CMD;
 }
 
-static int getNum(char *str, unsigned *val, uint8_t *opt, int flags)
+static int getNum(char *str, unsigned *val, int8_t *opt)
 {
-   int f, n, v;
+   int f, n;
+   unsigned v;
 
    *opt = 0;
 
@@ -360,28 +342,24 @@ static int getNum(char *str, unsigned *val, uint8_t *opt, int flags)
       return n;
    }
 
-   if (flags & PARSE_FLAGS_PARAMS)
-   {
-      f = sscanf(str, " p%i %n", &v, &n);
+   f = sscanf(str, " v%i %n", &v, &n);
 
-      if (f == 1)
-      {
-         *val = v;
-         *opt = CMD_PARAM;
-         return n;
-      }
+   if (f == 1)
+   {
+      *val = v;
+      if (v < PI_MAX_SCRIPT_VARS) *opt = CMD_VAR;
+      else *opt = -CMD_VAR;
+      return n;
    }
 
-   if (flags & PARSE_FLAGS_VARS)
-   {
-      f = sscanf(str, " v%i %n", &v, &n);
+   f = sscanf(str, " p%i %n", &v, &n);
 
-      if (f == 1)
-      {
-         *val = v;
-         *opt = CMD_VAR;
-         return n;
-      }
+   if (f == 1)
+   {
+      *val = v;
+      if (v < PI_MAX_SCRIPT_PARAMS) *opt = CMD_PAR;
+      else *opt = -CMD_PAR;
+      return n;
    }
 
    return 0;
@@ -394,16 +372,18 @@ char *cmdStr(void)
    return intCmdStr;
 }
 
-int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
+int cmdParse(char *buf, uint32_t *p, void **v, cmdCtlParse_t *ctl)
 {
    int f, valid, idx, val, pp, pars, n, n2, i;
    char *ptr;
    char c;
-   int param[MAX_PARAM];
+   int32_t param[MAX_PARAM];
 
    bzero(&ctl->opt, sizeof(ctl->opt));
 
-   sscanf(buf+ctl->eaten, " %31s", intCmdStr);
+   sscanf(buf+ctl->eaten, " %31s %n", intCmdStr, &pp);
+
+   ctl->eaten += pp;
 
    p[0] = -1;
 
@@ -411,10 +391,6 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
 
    if (idx < 0) return idx;
 
-   sscanf(buf+ctl->eaten, " %*31s %n", &pp);
-
-   ctl->eaten += pp;
-
    valid = 0;
 
    p[0] = cmdInfo[idx].cmd;
@@ -423,61 +399,164 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
 
    switch (cmdInfo[idx].vt)
    {
-      case 1: /* BR1  BR2  HWVER  NO  PIGPV  TICK  WVBSY  WVCLR  WVGO
-                 WVGOR  WVHLT
-              */
+      case 101: /* BR1  BR2  DCRA  H  HALT  HELP  HWVER  INRA  NO
+                   PIGPV  POPA  PUSHA  RET  T  TICK  WVBSY  WVCLR
+                   WVCRE  WVGO  WVGOR  WVHLT  WVNEW
+
+                   No parameters, always valid.
+                */
          valid = 1;
+
          break;
 
-      case 2: /* MODEG  NC  NP  PFG  PRG  PROCD  PROCS  PRRG
-                 SLRC  READ  WVSC  WVSM  WVSP
-              */
-         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
-         if (ctl->opt[0]) valid = 1;
+      case 111: /* ADD  AND  BC1  BC2  BS1  BS2  CMP  DIV  LDA  MLT
+                   MOD  OR  RLA  RRA  SUB  WAIT  XOR
+
+                   One parameter, any value.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+
+         if (ctl->opt[0] > 0) valid = 1;
+
          break;
 
-      case 3: /* PFS  PRS  PWM  SERVO  SLR  SLRO  WDOG  WRITE
-              */
-         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;
+      case 112: /* MG  MICS  MILS  MODEG  NC  NP  PFG  PRG
+                   PROCD  PROCP  PROCS  PRRG  R  READ  SLRC
+                   WVDEL  WVSC  WVSM  WVSP  WVTX  WVTXR
+
+                   One positive parameter.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0)) valid = 1;
+
          break;
 
-      case 4: /* NB
-              */
-         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;
+      case 113: /* DCR  INR  POP  PUSH  STA  XA
+
+                   One register parameter.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+
+         if ((ctl->opt[0] > 0) && (p[1] < PI_MAX_SCRIPT_VARS)) valid = 1;
+
          break;
 
-      case 5: /* TRIG
-              */
-         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;
+      case 114: /* CALL  JM  JMP  JNZ  JP  JZ  TAG
+
+                   One numeric parameter, any value.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         if (ctl->opt[0] == CMD_NUMERIC) valid = 1;
+
          break;
 
-      case 6: /* HELP
-              */
+      case 115: /* PARSE  PROC
+
+                   One parameter, string (rest of input).
+                */
+         p[1] = strlen(buf+ctl->eaten);
+         v[1] = buf+ctl->eaten;
+         ctl->eaten += p[1];
+
          valid = 1;
+
+         break;
+
+      case 116: /* SYS
+
+                   One parameter, a string of letters, digits, '-' and '_'.
+                */
+         f = sscanf(buf+ctl->eaten, " %*s%n %n", &n, &n2);
+         if ((f >= 0) && n)
+         {
+            valid = 1;
+
+            for (i=0; i<n; i++)
+            {
+               c = buf[ctl->eaten+i];
+
+               if ((!isalnum(c)) && (c != '_') && (c != '-'))
+               {
+                  valid = 0;
+                  break;
+               }
+            }
+
+            if (valid)
+            {
+               p[1] = n;
+               ctl->opt[0] = CMD_NUMERIC;
+               v[1]=buf+ctl->eaten;
+               ctl->eaten += n2;
+            }
+         }
+
+         break;
+
+      case 121: /* P  PFS  PRS  PWM  S  SERVO  SLR  SLRO  W  WDOG  WRITE
+
+                   Two positive parameters.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) &&
+             (ctl->opt[1] > 0) && ((int)p[2] >= 0)) valid = 1;
+
          break;
 
-      case 7: /* BC1  BC2  BS1  BS2
-              */
-         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
-         if (ctl->opt[0]) valid = 1;
+      case 122: /* NB
+
+                   Two parameters, first positive, second any value.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) &&
+             (ctl->opt[1] > 0)) valid = 1;
+
+         break;
+
+      case 123: /* LD  RL  RR
+
+                   Two parameters, first register, second any value.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+
+         if ((ctl->opt[0] > 0) &&
+             (p[1] < PI_MAX_SCRIPT_VARS) &&
+             (ctl->opt[1] > 0)) valid = 1;
+
          break;
 
-      case 8: /* MODES
-              */
-         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+      case 124: /* X
+
+                   Two register parameters.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+
+         if ((ctl->opt[0] > 0) && (p[1] < PI_MAX_SCRIPT_VARS) &&
+             (ctl->opt[1] > 0) && (p[2] < PI_MAX_SCRIPT_VARS)) valid = 1;
+
+         break;
+
+      case 125: /* M MODES
+
+                   Two parameters, first positive, second in 'RW540123'.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+
          f = sscanf(buf+ctl->eaten, " %c %n", &c, &n);
-         if (ctl->opt[0] && (f >= 1))
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) && (f >= 1))
          {
             ctl->eaten += n;
             val = toupper(c);
             ptr = strchr(fmtMdeStr, val);
+
             if (ptr != NULL)
             {
                val = ptr - fmtMdeStr;
@@ -485,13 +564,18 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
                valid = 1;
             }
          }
+
          break;
 
-      case 9: /* PUD
-              */
-         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
+      case 126: /* PUD
+
+                   Two parameters, first positive, second in 'ODU'.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+
          f = sscanf(buf+ctl->eaten, " %c %n", &c, &n);
-         if (ctl->opt[0] && (f >= 1))
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0)  && (f >= 1))
          {
             ctl->eaten += n;
             val = toupper(c);
@@ -503,186 +587,285 @@ int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctl)
                valid = 1;
             }
          }
+
          break;
 
-      case 10: /* PROC
-               */
-         p[1] = strlen(buf+ctl->eaten);
-         v[1] = buf+ctl->eaten;
-         ctl->eaten += p[1];
-         valid = 1;
+      case 131: /* TRIG
+
+                   Three positive parameters.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2]);
+
+         if ((ctl->opt[0] > 0) && ((int)p[1] >= 0) &&
+             (ctl->opt[1] > 0) && ((int)p[2] >= 0) &&
+             (ctl->opt[2] == CMD_NUMERIC) && ((int)p[3] >= 0))
+            valid = 1;
+
          break;
 
-      case 11: /* WVAS
-               */
-         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0], ctl->flags);
-         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], ctl->flags);
-         ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2], ctl->flags);
+      case 141: /* WVAS
 
-         if (ctl->opt[0] && ctl->opt[1] && ctl->opt[2])
+                  Four parameters, first two positive, third any value,
+                  last string (rest of input).
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+         ctl->eaten += getNum(buf+ctl->eaten, &p[3], &ctl->opt[2]);
+
+         if ((ctl->opt[0] == CMD_NUMERIC) && ((int)p[1] >= 0) &&
+             (ctl->opt[1] == CMD_NUMERIC) && ((int)p[2] >= 0) &&
+             (ctl->opt[2] == CMD_NUMERIC))
          {
             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);
+      case 191: /* PROCR
 
-         pars = 0;
+                   One to 11 parameters, first positive,
+                   optional remainder, any value.
+                */
+         ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
 
-         while (pars < 10)
+         if ((ctl->opt[0] == CMD_NUMERIC) && ((int)p[1] >= 0))
          {
-            ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1], 0);
-            if (ctl->opt[1]) param[pars++] = p[2];
-            else break;
-         }
+            pars = 0;
 
-         p[2] = pars;
+            while (pars < PI_MAX_SCRIPT_PARAMS)
+            {
+               ctl->eaten += getNum(buf+ctl->eaten, &p[2], &ctl->opt[1]);
+               if (ctl->opt[1] == CMD_NUMERIC) param[pars++] = p[2];
+               else break;
+            }
 
-         v[1] = param;
+            p[2] = pars;
+
+            v[1] = param;
+
+            valid = 1;
+         }
 
-         if (ctl->opt[0]) valid = 1;
          break;
 
-      case 13: /* WVAG
-               */
+      case 192: /* WVAG
+
+                   One or more triplets (gpios on, gpios off, delay),
+                   any value.
+                */
          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];
+            ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[0]);
+            if (ctl->opt[0] == CMD_NUMERIC) param[pars++] = p[1];
             else break;
          }
 
-         p[1] = pars/3;
+         p[1] = pars / 3;
 
          v[1] = param;
 
-         if (pars && ((pars%3)==0)) valid = 1;
-         break;
+         if (pars && ((pars % 3) == 0)) valid = 1;
 
-      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;
+   if (valid) return idx; else return CMD_BAD_PARAMETER;
+}
 
-      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;
+char * cmdErrStr(int error)
+{
+   int i;
 
-      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;
+   for (i=0; i<(sizeof(errInfo)/sizeof(errInfo_t)); i++)
+   {
+      if (errInfo[i].error == error) return errInfo[i].str;
+   }
+   return "unknown error";
+}
 
-      case 26: /*
-              */
-         f = sscanf(buf+ctl->eaten, " %d %n", &p[1], &n);
-         if (f >= 1)
-         {
-            ctl->eaten += n;
-            valid = 1;
-         }
-         break;
+int cmdParseScript(char *script, cmdScript_t *s, int diags)
+{
+   int idx, len, b, i, j, tags, resolved;
+   int status;
+   uint32_t p[10];
+   void *v[10];
+   cmdInstr_t instr;
+   cmdCtlParse_t ctl;
 
-      case 27: /*
-              */
-         f = sscanf(buf+ctl->eaten, " %*s%n %n", &n, &n2);
-         if ((f >= 0) && n)
+   ctl.eaten = 0;
+
+   status = 0;
+
+   cmdTagStep_t tag_step[PI_MAX_SCRIPT_TAGS];
+
+   len = strlen(script);
+
+   /* calloc space for PARAMS, VARS, CMDS, and STRINGS */
+
+   b = (sizeof(int) * (PI_MAX_SCRIPT_PARAMS + PI_MAX_SCRIPT_VARS)) +
+       (sizeof(cmdInstr_t) * (len + 2) / 2) + len;
+
+   s->par = calloc(b, 1);
+
+   if (s->par == NULL) return -1;
+
+   s->var = s->par + PI_MAX_SCRIPT_PARAMS;
+
+   s->instr = (cmdInstr_t *)(s->var + PI_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;
+
+   tags = 0;
+
+   idx = 0;
+
+   while (ctl.eaten<len)
+   {
+      idx = cmdParse(script, p, v, &ctl);
+
+      memcpy(&instr.p, p, sizeof(instr.p));
+
+      if (idx >= 0)
+      {
+         switch (instr.p[0])
          {
-            valid = 1;
+            case PI_CMD_HELP:
+            case PI_CMD_PARSE:
+            case PI_CMD_PROC:
+            case PI_CMD_PROCD:
+            case PI_CMD_PROCP:
+            case PI_CMD_PROCR:
+            case PI_CMD_PROCS:
+            case PI_CMD_SLR:
+            case PI_CMD_SLRC:
+            case PI_CMD_SLRO:
+            case PI_CMD_WVAG:
+            case PI_CMD_WVAS:
+
+               if (diags)
+               {
+                  fprintf(stderr, "Illegal command: %s\n", cmdStr());
+               }
 
-            for (i=0; i<n; i++)
-            {
-               c = buf[ctl->eaten+i];
+               if (!status) status = PI_BAD_SCRIPT_CMD;
+               idx = -1;
 
-               if ((!isalnum(c)) && (c != '_') && (c != '-'))
+               break;
+
+            case PI_CMD_TAG:
+
+               if (tags < PI_MAX_SCRIPT_TAGS)
                {
-                  valid = 0;
-                  break;
+                  /* check tag not already used */
+                  for (j=0; j<tags; j++)
+                  {
+                     if (tag_step[j].tag == instr.p[1])
+                     {
+                        if (diags)
+                        {
+                           fprintf(stderr, "Duplicate tag: %d\n", instr.p[1]);
+                        }
+
+                        if (!status) status = PI_DUP_TAG;
+                        idx = -1;
+                     }
+                  }
+
+                  tag_step[tags].tag = instr.p[1];
+                  tag_step[tags].step = s->instrs;
+                  tags++;
+               }
+               else
+               {
+                  if (diags)
+                  {
+                      fprintf(stderr, "Too many tags: %d\n", instr.p[1]);
+                  }
+                  if (!status) status = PI_TOO_MANY_TAGS;
+                  idx = -1;
                }
-            }
 
-            if (valid)
-            {
-               p[1] = n;
-               ctl->opt[0] = CMD_NUMERIC;
-               v[1]=buf+ctl->eaten;
-               ctl->eaten += n2;
-            }
+               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] = (intptr_t) s->str_area+s->str_area_pos;
+               s->str_area_pos += (p[1] + 1);
+
+               break;
+
          }
-         break;
+      }
+      else
+      {
+         if (diags)
+         {
+            if (idx == CMD_UNKNOWN_CMD)
+               fprintf(stderr, "Unknown command: %s\n", cmdStr());
+            else
+               fprintf(stderr, "Bad parameter to %s\n", cmdStr());
+         }
+         if (!status) status = PI_BAD_SCRIPT_CMD;
+      }
 
-      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))
+      if (idx >= 0)
+      {
+         if (instr.p[0] != PI_CMD_TAG)
          {
-            ctl->eaten += n;
-            valid = 1;
+            memcpy(instr.opt, &ctl.opt, sizeof(instr.opt));
+            s->instr[s->instrs++] = instr;
          }
-         break;
+      }
    }
 
-   if (valid) return idx; else return -1;
-}
+   for (i=0; i<s->instrs; i++)
+   {
+      instr = s->instr[i];
 
-char * cmdErrStr(int error)
-{
-   int i;
+      /* resolve jumps */
 
-   for (i=0; i<(sizeof(errInfo)/sizeof(errInfo_t)); i++)
-   {
-      if (errInfo[i].error == error) return errInfo[i].str;
+      if ((instr.p[0] == PI_CMD_JMP) || (instr.p[0] == PI_CMD_CALL) ||
+          (instr.p[0] == PI_CMD_JZ)  || (instr.p[0] == PI_CMD_JNZ)  ||
+          (instr.p[0] == PI_CMD_JM)  || (instr.p[0] == PI_CMD_JP))
+      {
+         resolved = 0;
+
+         for (j=0; j<tags; j++)
+         {
+            if (instr.p[1] == tag_step[j].tag)
+            {
+               s->instr[i].p[1] = tag_step[j].step;
+               resolved = 1;
+               break;
+            }
+         }
+
+         if (!resolved)
+         {
+            if (diags)
+            {
+               fprintf(stderr, "Can't resolve tag %d\n", instr.p[1]);
+            }
+            if (!status) status = PI_BAD_TAG;
+         }
+      }
    }
-   return "unknown error";
+   return status;
 }
 
index 7e624059d719aa07e0b6d884c0bd5a6dc957a772..06d0fefc81f4dd95058f9b513776b7b2124fedae 100644 (file)
--- a/command.h
+++ b/command.h
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 13+
+This version is for pigpio version 14+
 */
 
 #ifndef COMMAND_H
@@ -39,19 +39,18 @@ This version is for pigpio version 13+
 
 #define MAX_PARAM 512
 
-#define PARSE_FLAGS_PARAMS 1
-#define PARSE_FLAGS_VARS   2
+#define CMD_UNKNOWN_CMD   -1
+#define CMD_BAD_PARAMETER -2
 
 #define CMD_NUMERIC 1
-#define CMD_PARAM   2
-#define CMD_VAR     3
+#define CMD_VAR     2
+#define CMD_PAR     3
 
 typedef struct
 {
-   int     flags;
-   int     eaten;
-   uint8_t opt[8];
-} gpioCtlParse_t;
+   int    eaten;
+   int8_t opt[4];
+} cmdCtlParse_t;
 
 typedef struct
 {
@@ -61,11 +60,41 @@ typedef struct
    int   rv;   /* command return value type */
 } cmdInfo_t;
 
+typedef struct
+{
+   uint32_t tag;
+   int      step;
+} cmdTagStep_t;
+
+typedef struct
+{
+   uint32_t p[7];
+   int8_t opt[4];
+} cmdInstr_t;
+
+typedef struct
+{
+   /*
+     +-----------+---------+---------+----------------+
+     | PARAMS... | VARS... | CMDS... | STRING AREA... |
+     +-----------+---------+---------+----------------+
+   */
+   int *par;
+   int *var;
+   cmdInstr_t *instr;
+   int instrs;
+   char *str_area;
+   int str_area_len;
+   int str_area_pos;
+} cmdScript_t;
+
 extern cmdInfo_t cmdInfo[];
 
 extern char *cmdUsage;
 
-int cmdParse(char *buf, uint32_t *p, void **v, gpioCtlParse_t *ctlParse);
+int cmdParse(char *buf, uint32_t *p, void **v, cmdCtlParse_t *ctl);
+
+int cmdParseScript(char *script, cmdScript_t *s, int diags);
 
 char *cmdErrStr(int error);
 
index b9cdb2965e76a1fe21cb558d373a7d86687f69a2..0c540d2b6015483cfea5c5b341011575499dd5aa 100644 (file)
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 For more information, please refer to <http://unlicense.org/>
 */
 
-/* pigpio version 13 */
+/* pigpio version 14 */
 
 #include <stdio.h>
 #include <string.h>
@@ -533,7 +533,8 @@ bit 0 READ_LAST_NOT_SET_ERROR
 
 #define DMAO_PAGES (PAGES_PER_BLOCK * PI_WAVE_BLOCKS)
 
-#define NUM_OOL (DMAO_PAGES * OOL_PER_OPAGE)
+#define NUM_WAVE_OOL (DMAO_PAGES * OOL_PER_OPAGE)
+#define NUM_WAVE_CBS (DMAO_PAGES * CBS_PER_OPAGE)
 
 #define TICKSLOTS 50
 
@@ -556,28 +557,20 @@ bit 0 READ_LAST_NOT_SET_ERROR
 #define SRX_BUF_SIZE 8192
 #define CMD_BUF_SIZE 4096
 
+#define MAX_DELAY 50
+
 /* --------------------------------------------------------------- */
 
 typedef void (*callbk_t) ();
 
-typedef struct { /* linux/arch/arm/mach-bcm2708/include/mach/dma.h */
-   unsigned long info;
-   unsigned long src;
-   unsigned long dst;
-   unsigned long length;
-   unsigned long stride;
-   unsigned long next;
-   unsigned long pad[2];
-} dmaCbs_t;
-
 typedef struct
 {
-   dmaCbs_t cb           [128];
+   rawCbs_t cb           [128];
 } dmaPage_t;
 
 typedef struct
 {
-   dmaCbs_t cb           [CBS_PER_IPAGE];
+   rawCbs_t cb           [CBS_PER_IPAGE];
    uint32_t level        [LVS_PER_IPAGE];
    uint32_t gpioOff      [OFF_PER_IPAGE];
    uint32_t tick         [TCK_PER_IPAGE];
@@ -588,7 +581,7 @@ typedef struct
 
 typedef struct
 {
-   dmaCbs_t cb     [CBS_PER_OPAGE];
+   rawCbs_t cb     [CBS_PER_OPAGE];
    uint32_t OOL    [OOL_PER_OPAGE];
    uint32_t periphData;
 } dmaOPage_t;
@@ -626,12 +619,6 @@ typedef struct
    uint32_t bits;
 } gpioGetSamples_t;
 
-typedef struct
-{
-   uint32_t label;
-   int      step;
-} gpioLabelStep_t;
-
 typedef struct
 {
    callbk_t        func;
@@ -653,16 +640,8 @@ typedef struct
 #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;
@@ -674,18 +653,7 @@ typedef struct
    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;
+   cmdScript_t script;
 } gpioScript_t;
 
 
@@ -768,6 +736,13 @@ typedef struct
    int      mode;
 } wfRx_t;
 
+typedef struct
+{
+   int botCB;  /* first CB used by wave */
+   int topCB;  /* last CB used by wave */
+   int botOOL;
+   int topOOL;
+} waveInfo_t;
 
 /* --------------------------------------------------------------- */
 
@@ -812,8 +787,16 @@ static wfStats_t wfStats=
    0, 0, (DMAO_PAGES * CBS_PER_OPAGE)
 };
 
+static waveInfo_t waveInfo[PI_MAX_WAVES];
+
 static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1];
 
+static int waveOutBotCB  = 0;
+static int waveOutTopCB  = NUM_WAVE_CBS;
+static int waveOutBotOOL = 0;
+static int waveOutTopOOL = NUM_WAVE_OOL;
+static int waveOutCount = 0;
+
 static volatile uint32_t alertBits   = 0;
 static volatile uint32_t monitorBits = 0;
 static volatile uint32_t notifyBits  = 0;
@@ -835,7 +818,7 @@ static gpioInfo_t       gpioInfo   [PI_MAX_USER_GPIO+1];
 
 static gpioNotify_t     gpioNotify [PI_NOTIFY_SLOTS];
 
-static gpioScript_t     gpioScript [PI_SCRIPT_SLOTS];
+static gpioScript_t     gpioScript [PI_MAX_SCRIPTS];
 
 static gpioSignal_t     gpioSignal [PI_MAX_SIGNUM+1];
 
@@ -945,7 +928,7 @@ static uint32_t myGpioDelay(uint32_t micros)
 
    start = systReg[SYST_CLO];
 
-   if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ;
+   if (micros <= MAX_DELAY) while ((systReg[SYST_CLO] - start) <= micros) ;
 
    else myGpioSleep(micros/MILLION, micros%MILLION);
 
@@ -1041,153 +1024,9 @@ static uint32_t myGetTick(int pos)
    return tick;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static int myParseScript(char *script, gpioScript_t *s)
+static int myPermit(unsigned gpio)
 {
-   int idx, len, b, i, j, labels, resolved, pos;
-   int status;
-   uint32_t p[10];
-   void *v[10];
-   gpioInstr_t instr;
-   gpioCtlParse_t ctl;
-
-   ctl.flags = PARSE_FLAGS_PARAMS | PARSE_FLAGS_VARS;
-   ctl.eaten = 0;
-
-   status = 0;
-
-   gpioLabelStep_t label_step[MAX_SCRIPT_LABELS];
-
-   len = strlen(script);
-
-   /* calloc space for PARAMS, VARS, CMDS, and STRINGS */
-
-   b = (sizeof(int) * (MAX_SCRIPT_PARAMS + MAX_SCRIPT_VARS)) +
-       (sizeof(gpioInstr_t) * (len + 2) / 2) + len;
-
-   s->param = calloc(b, 1);
-
-   if (s->param == NULL) return -1;
-
-   s->var = s->param + MAX_SCRIPT_PARAMS;
-
-   s->instr = (gpioInstr_t *)(s->var + MAX_SCRIPT_VARS);
-
-   s->str_area = (char *)(s->instr + ((len + 2) / 2));
-
-   s->str_area_len = len;
-   s->str_area_pos = 0;
-
-   s->instrs = 0;
-
-   labels = 0;
-
-   idx = 0;
-
-   while (!status && ((ctl.eaten)<len) && (idx >= 0))
-   {
-      pos = ctl.eaten;
-
-      idx = cmdParse(script, p, v, &ctl);
-
-      memcpy(&instr.p, p, sizeof(instr.p));
-
-      if (idx >= 0)
-      {
-         switch (instr.p[0])
-         {
-            case PI_CMD_LABEL:
-
-               if (labels < MAX_SCRIPT_LABELS)
-               {
-                  /* check label not already used */
-                  for (j=0; j<labels; j++)
-                  {
-                     if (label_step[j].label == instr.p[1])
-                     {
-                        DBG(DBG_USER, "duplicate label: %s", script+pos);
-                        status = PI_DUP_LABEL;
-                        idx = -1;
-                     }
-                  }
-
-                  label_step[labels].label = instr.p[1];
-                  label_step[labels].step = s->instrs;
-                  labels++;
-               }
-               else
-               {
-                  DBG(DBG_USER, "too many labels: %s", script+pos);
-                  status = PI_TOO_MANY_LABELS;
-                  idx = -1;
-               }
-
-               break;
-
-            case PI_CMD_SYS:
-
-               strncpy(s->str_area+s->str_area_pos, v[1], p[1]);
-               s->str_area[s->str_area_pos+p[1]] = 0;
-               instr.p[1] = (int) s->str_area+s->str_area_pos;
-               s->str_area_pos += (p[1] + 1);
-
-               break;
-
-            case PI_CMD_TRIG:
-               break;
-
-         }
-      }
-      else
-      {
-         DBG(DBG_USER, "invalid command: %s", script+pos);
-         status = PI_BAD_SCRIPT_CMD;
-      }
-
-      if (idx >= 0)
-      {
-         if (instr.p[0] != PI_CMD_LABEL)
-         {
-            memcpy(instr.opt, &ctl.opt, sizeof(instr.opt));
-            s->instr[s->instrs++] = instr;
-         }
-      }
-   }
-
-   DBG(DBG_SCRIPT, "status=%d eaten=%d len=%d idx=%d",
-      status, ctl.eaten, len, idx);
-
-   for (i=0; i<s->instrs; i++)
-   {
-      instr = s->instr[i];
-
-      /* resolve jumps */
-
-      if ((instr.p[0] == PI_CMD_JMP) || (instr.p[0] == PI_CMD_CALL) ||
-          (instr.p[0] == PI_CMD_JZ)  || (instr.p[0] == PI_CMD_JNZ)  ||
-          (instr.p[0] == PI_CMD_JM)  || (instr.p[0] == PI_CMD_JP))
-      {
-         resolved = 0;
-
-         for (j=0; j<labels; j++)
-         {
-            if (instr.p[1] == label_step[j].label)
-            {
-               s->instr[i].p[1] = label_step[j].step;
-               resolved = 1;
-               break;
-            }
-         }
-
-         if (!resolved)
-         {
-            DBG(DBG_USER, "can't resolve label %d\n", instr.p[1]);
-            status = PI_BAD_SCRIPT;
-         }
-      }
-   }
-   return status;
+   if (gpioMask & ((uint64_t)(1)<<gpio)) return 1; else return 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -1267,14 +1106,20 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
 
       case PI_CMD_HWVER: res = gpioHardwareRevision(); break;
 
-      case PI_CMD_MICRO: myGpioDelay(p[1]); break;
+      case PI_CMD_MICS:
+         if (p[1] <= PI_MAX_MICS_DELAY) myGpioDelay(p[1]);
+         else res = PI_BAD_MICS_DELAY;
+         break;
 
-      case PI_CMD_MILLI: myGpioDelay(p[1] * 1000); break;
+      case PI_CMD_MILS:
+         if (p[1] <= PI_MAX_MILS_DELAY) myGpioDelay(p[1] * 1000);
+         else res = PI_BAD_MILS_DELAY;
+         break;
 
       case PI_CMD_MODEG: res = gpioGetMode(p[1]); break;
 
       case PI_CMD_MODES:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetMode(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioSetMode(p[1], p[2]);
          else
          {
             DBG(DBG_USER, "gpioSetMode: gpio %d, no permission to update", p[1]);
@@ -1293,7 +1138,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
       case PI_CMD_PFG: res = gpioGetPWMfrequency(p[1]); break;
 
       case PI_CMD_PFS:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPWMfrequency(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioSetPWMfrequency(p[1], p[2]);
          else
          {
             DBG(DBG_USER, 
@@ -1323,7 +1168,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
       case PI_CMD_PRRG: res = gpioGetPWMrealRange(p[1]); break;
 
       case PI_CMD_PRS:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPWMrange(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioSetPWMrange(p[1], p[2]);
          else
          {
             DBG(DBG_USER, 
@@ -1333,7 +1178,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
          break;
 
       case PI_CMD_PUD:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioSetPullUpDown(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioSetPullUpDown(p[1], p[2]);
          else
          {
             DBG(DBG_USER, 
@@ -1343,7 +1188,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
          break;
 
       case PI_CMD_PWM:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioPWM(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioPWM(p[1], p[2]);
          else
          {
             DBG(DBG_USER, "gpioPWM: gpio %d, no permission to update", p[1]);
@@ -1354,7 +1199,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
       case PI_CMD_READ: res = gpioRead(p[1]); break;
 
       case PI_CMD_SERVO:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioServo(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioServo(p[1], p[2]);
          else
          {
             DBG(DBG_USER, "gpioServo: gpio %d, no permission to update", p[1]);
@@ -1374,8 +1219,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
       case PI_CMD_TICK: res = gpioTick(); break;
 
       case PI_CMD_TRIG:
-         if (gpioMask & (uint64_t)(1<<p[1]))
-            res = gpioTrigger(p[1], p[2], p[3]);
+         if (myPermit(p[1])) res = gpioTrigger(p[1], p[2], p[3]);
          else
          {
             DBG(DBG_USER, "gpioTrigger: gpio %d, no permission to update", p[1]);
@@ -1386,7 +1230,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
       case PI_CMD_WDOG: res = gpioSetWatchdog(p[1], p[2]); break;
 
       case PI_CMD_WRITE:
-         if (gpioMask & (uint64_t)(1<<p[1])) res = gpioWrite(p[1], p[2]);
+         if (myPermit(p[1])) res = gpioWrite(p[1], p[2]);
          else
          {
             DBG(DBG_USER, "gpioWrite: gpio %d, no permission to update", p[1]);
@@ -1429,7 +1273,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
          break;
 
       case PI_CMD_WVAS:
-         if (gpioMask & (uint64_t)(1<<p[1]))
+         if (myPermit(p[1]))
             res = gpioWaveAddSerial(p[1], p[2], p[3], p[4], (char *)p[5]);
          else
          {
@@ -1444,19 +1288,25 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
 
       case PI_CMD_WVCLR: res = gpioWaveClear(); break;
 
+      case PI_CMD_WVCRE: res = gpioWaveCreate(); break;
+
+      case PI_CMD_WVDEL: res = gpioWaveDelete(p[1]); break;
+
       case PI_CMD_WVGO:  res = gpioWaveTxStart(PI_WAVE_MODE_ONE_SHOT); break;
 
       case PI_CMD_WVGOR: res = gpioWaveTxStart(PI_WAVE_MODE_REPEAT); break;
 
       case PI_CMD_WVHLT: res = gpioWaveTxStop(); break;
 
+      case PI_CMD_WVNEW: res = gpioWaveAddNew(); break;
+
       case PI_CMD_WVSC:
          switch(p[1])
          {
             case 0: res = gpioWaveGetCbs();     break;
             case 1: res = gpioWaveGetHighCbs(); break;
             case 2: res = gpioWaveGetMaxCbs();  break;
-            default: res = -9999;
+            default: res = PI_BAD_WVSC_COMMND;
          }
          break;
 
@@ -1466,7 +1316,7 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
             case 0: res = gpioWaveGetMicros();     break;
             case 1: res = gpioWaveGetHighMicros(); break;
             case 2: res = gpioWaveGetMaxMicros();  break;
-            default: res = -9999;
+            default: res = PI_BAD_WVSM_COMMND;
          }
          break;
 
@@ -1476,9 +1326,16 @@ static int myDoCommand(uint32_t *p, gpioExtent_t *oExt)
             case 0: res = gpioWaveGetPulses();     break;
             case 1: res = gpioWaveGetHighPulses(); break;
             case 2: res = gpioWaveGetMaxPulses();  break;
-            default: res = -9999;
+            default: res = PI_BAD_WVSP_COMMND;
          }
          break;
+
+      case PI_CMD_WVTX:
+         res = gpioWaveTxSend(p[1], PI_WAVE_MODE_ONE_SHOT); break;
+
+      case PI_CMD_WVTXR:
+         res = gpioWaveTxSend(p[1], PI_WAVE_MODE_REPEAT); break;
+
    }
    return (res);
 }
@@ -1649,12 +1506,12 @@ static void myGpioSetServo(unsigned gpio, int oldVal, int newVal)
 
 /* ======================================================================= */
 
-static dmaCbs_t * waveCbVOadr(int pos)
+rawCbs_t * rawWaveCBAdr(int n)
 {
    int page, slot;
 
-   page = pos/CBS_PER_OPAGE;
-   slot = pos%CBS_PER_OPAGE;
+   page = n/CBS_PER_OPAGE;
+   slot = n%CBS_PER_OPAGE;
 
    return &dmaOVirt[page]->cb[slot];
 }
@@ -1708,9 +1565,9 @@ static uint32_t waveOOLPOadr(int pos)
 
 static void waveCbOPrint(int pos)
 {
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
-   p = waveCbVOadr(pos);
+   p = rawWaveCBAdr(pos);
 
    fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n",
       p->info, p->src, p->dst, p->length, p->stride, p->next);
@@ -1756,15 +1613,26 @@ static void waveBitDelay(unsigned baud, unsigned * bitDelay)
    bitDelay[9] = (e-s)/100;
 }
 
+static int errCBsOOL(int cb, int botOOL, int topOOL)
+{
+   if (cb >= waveOutTopCB) return PI_TOO_MANY_CBS;
+
+   if (botOOL >= topOOL) return PI_TOO_MANY_OOL;
+
+   return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 
 static int wave2Cbs(unsigned mode)
 {
-   int cb=0, onoff=0, level=NUM_OOL;
+   int botCB=waveOutBotCB, botOOL=waveOutBotOOL, topOOL=waveOutTopOOL;
 
-   dmaCbs_t *p=NULL;
+   int status;
+
+   rawCbs_t *p=NULL;
 
-   unsigned i, half, repeatCb;
+   unsigned i, half, repeatCB;
 
    unsigned numWaves;
 
@@ -1775,9 +1643,11 @@ static int wave2Cbs(unsigned mode)
 
    half = PI_WF_MICROS/2;
 
+   if ((status = errCBsOOL(botCB+1, botOOL, topOOL))) return status;
+
    /* add delay cb at start of DMA */
 
-   p = waveCbVOadr(cb++);
+   p = rawWaveCBAdr(botCB++);
 
    /* use the secondary clock */
 
@@ -1786,7 +1656,6 @@ static int wave2Cbs(unsigned mode)
       p->info   = NORMAL_DMA |
                   DMA_DEST_DREQ |
                   DMA_PERIPHERAL_MAPPING(2);
-
       p->dst    = ((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | 0x7e000000;
    }
    else
@@ -1794,69 +1663,78 @@ static int wave2Cbs(unsigned mode)
       p->info   = NORMAL_DMA |
                   DMA_DEST_DREQ |
                   DMA_PERIPHERAL_MAPPING(5);
-
       p->dst    = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | 0x7e000000;
    }
 
    p->src    = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR;
-   p->length = 4 * 50 / PI_WF_MICROS; /* 50 micros delay */
-   p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+   p->length = 4 * 20 / PI_WF_MICROS; /* 20 micros delay */
+   p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
 
-   repeatCb = cb;
+   repeatCB = botCB;
 
    for (i=0; i<numWaves; i++)
    {
       if (waves[i].gpioOn)
       {
-         waveSetOOL(onoff, waves[i].gpioOn);
+         if ((status = errCBsOOL(botCB+1, botOOL+1, topOOL))) return status;
+
+         waveSetOOL(botOOL, waves[i].gpioOn);
 
-         p = waveCbVOadr(cb++);
+         p = rawWaveCBAdr(botCB++);
 
          p->info   = NORMAL_DMA;
-         p->src    = waveOOLPOadr(onoff++) | DMA_BUS_ADR;
+         p->src    = waveOOLPOadr(botOOL++) | DMA_BUS_ADR;
          p->dst    = ((GPIO_BASE + (GPSET0*4)) & 0x00ffffff) | 0x7e000000;
          p->length = 4;
-         p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+         p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
       }
 
       if (waves[i].gpioOff)
       {
-         waveSetOOL(onoff, waves[i].gpioOff);
+         if ((status = errCBsOOL(botCB+1, botOOL+1, topOOL))) return status;
 
-         p = waveCbVOadr(cb++);
+         waveSetOOL(botOOL, waves[i].gpioOff);
+
+         p = rawWaveCBAdr(botCB++);
 
          p->info   = NORMAL_DMA;
-         p->src    = waveOOLPOadr(onoff++) | DMA_BUS_ADR;
+         p->src    = waveOOLPOadr(botOOL++) | DMA_BUS_ADR;
          p->dst    = ((GPIO_BASE + (GPCLR0*4)) & 0x00ffffff) | 0x7e000000;
          p->length = 4;
-         p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+         p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
       }
 
       if (waves[i].flags & WAVE_FLAG_READ)
       {
-         p = waveCbVOadr(cb++);
+         if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status;
+
+         p = rawWaveCBAdr(botCB++);
 
          p->info   = NORMAL_DMA;
          p->src    = ((GPIO_BASE + (GPLEV0*4)) & 0x00ffffff) | 0x7e000000;
-         p->dst    = waveOOLPOadr(--level) | DMA_BUS_ADR;
+         p->dst    = waveOOLPOadr(--topOOL) | DMA_BUS_ADR;
          p->length = 4;
-         p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+         p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
       }
 
       if (waves[i].flags & WAVE_FLAG_TICK)
       {
-         p = waveCbVOadr(cb++);
+         if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status;
+
+         p = rawWaveCBAdr(botCB++);
 
          p->info   = NORMAL_DMA;
          p->src    = ((SYST_BASE + (SYST_CLO*4)) & 0x00ffffff) | 0x7e000000;
-         p->dst    = waveOOLPOadr(--level) | DMA_BUS_ADR;
+         p->dst    = waveOOLPOadr(--topOOL) | DMA_BUS_ADR;
          p->length = 4;
-         p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+         p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
       }
 
       if (waves[i].usDelay)
       {
-         p = waveCbVOadr(cb++);
+         if ((status = errCBsOOL(botCB+1, botOOL, topOOL))) return status;
+
+         p = rawWaveCBAdr(botCB++);
 
          /* use the secondary clock */
 
@@ -1879,7 +1757,7 @@ static int wave2Cbs(unsigned mode)
 
          p->src    = (uint32_t) (&dmaOPhys[0]->periphData) | DMA_BUS_ADR;
          p->length = 4 * ((waves[i].usDelay+half)/PI_WF_MICROS);
-         p->next   = waveCbPOadr(cb) | DMA_BUS_ADR;
+         p->next   = waveCbPOadr(botCB) | DMA_BUS_ADR;
       }
    }
 
@@ -1887,10 +1765,16 @@ static int wave2Cbs(unsigned mode)
    {
       if (mode == PI_WAVE_MODE_ONE_SHOT)
            p->next = 0;
-      else p->next = waveCbPOadr(repeatCb) | DMA_BUS_ADR;
+      else p->next = waveCbPOadr(repeatCB) | DMA_BUS_ADR;
    }
 
-   return cb;
+   status = botCB - waveOutBotCB;
+
+   waveOutBotCB  = botCB;
+   waveOutBotOOL = botOOL;
+   waveOutTopOOL = topOOL;
+
+   return status;
 }
 
 
@@ -1980,7 +1864,7 @@ static void waveRxBit(int gpio, int level, uint32_t tick)
 
 static int waveMerge(unsigned numIn1, gpioWave_t *in1)
 {
-   unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_OOL;
+   unsigned inPos1=0, inPos2=0, outPos=0, level = NUM_WAVE_OOL;
 
    unsigned cbs=0;
 
@@ -2111,7 +1995,7 @@ static int waveMerge(unsigned numIn1, gpioWave_t *in1)
 
 /* ======================================================================= */
 
-static dmaCbs_t * dmaCB2adr(int pos)
+static rawCbs_t * dmaCB2adr(int pos)
 {
    int page, slot;
 
@@ -2125,7 +2009,7 @@ static dmaCbs_t * dmaCB2adr(int pos)
 
 static void dmaCbPrint(int pos)
 {
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(pos);
 
@@ -2180,7 +2064,7 @@ static unsigned dmaNowAtICB(void)
 
 /* ----------------------------------------------------------------------- */
 
-unsigned dmaNowAtOCB(void)
+unsigned rawWaveCB(void)
 {
    unsigned cb;
    static unsigned lastPage=0;
@@ -2296,7 +2180,7 @@ static uint32_t dmaCbAdr(int pos)
 
 static void dmaGpioOnCb(int b, int pos)
 {   
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(b);
 
@@ -2311,7 +2195,7 @@ static void dmaGpioOnCb(int b, int pos)
 
 static void dmaTickCb(int b, int pos)
 {   
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(b);
 
@@ -2326,7 +2210,7 @@ static void dmaTickCb(int b, int pos)
 
 static void dmaGpioOffCb(int b, int pos)
 {
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(b);
 
@@ -2341,7 +2225,7 @@ static void dmaGpioOffCb(int b, int pos)
 
 static void dmaReadLevelsCb(int b, int pos)
 {
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(b);
 
@@ -2356,7 +2240,7 @@ static void dmaReadLevelsCb(int b, int pos)
 
 static void dmaDelayCb(int b)
 {
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    p = dmaCB2adr(b);
 
@@ -2382,7 +2266,7 @@ static void dmaInitCbs(void)
 {
    int b, pulse, level, cycle;
 
-   dmaCbs_t * p;
+   rawCbs_t * p;
 
    /* set up the DMA control blocks */
 
@@ -2816,16 +2700,22 @@ static void * pthAlertThread(void *x)
 
                      if (err != (MAX_EMITS*sizeof(gpioReport_t)))
                      {
-                        DBG(0, "fd=%d err=%d errno=%d",
-                          gpioNotify[n].fd, err, errno);
-                        if (err < 0) DBG(0, "%s", strerror(errno));
-                        if ((err != EAGAIN) && (err != EWOULDBLOCK))
+                        if (err < 0)
                         {
-                           /* serious error, no point continuing */
-                           gpioNotify[n].bits  = 0;
-                           gpioNotify[n].state = PI_NOTIFY_CLOSING;
-                           intNotifyBits();
-                           break;
+                           if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
+                           {
+                              /* serious error, no point continuing */
+
+                              DBG(0, "fd=%d err=%d errno=%d",
+                                 gpioNotify[n].fd, err, errno);
+
+                              DBG(0, "%s", strerror(errno));
+
+                              gpioNotify[n].bits  = 0;
+                              gpioNotify[n].state = PI_NOTIFY_CLOSING;
+                              intNotifyBits();
+                              break;
+                           }
                         }
                      }
 
@@ -2840,16 +2730,21 @@ static void * pthAlertThread(void *x)
 
                      if (err != (emit*sizeof(gpioReport_t)))
                      {
-                        DBG(0, "fd=%d err=%d errno=%d",
-                          gpioNotify[n].fd, err, errno);
-                        if (err < 0) DBG(0, "%s", strerror(errno));
-                        if ((err != EAGAIN) && (err != EWOULDBLOCK))
+                        if (err < 0)
                         {
-                           /* serious error, no point continuing */
-                           gpioNotify[n].bits  = 0;
-                           gpioNotify[n].state = PI_NOTIFY_CLOSING;
-                           intNotifyBits();
-                           break;
+                           if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
+                           {
+                              DBG(0, "fd=%d err=%d errno=%d",
+                                 gpioNotify[n].fd, err, errno);
+
+                              DBG(0, "%s", strerror(errno));
+
+                              /* serious error, no point continuing */
+                              gpioNotify[n].bits  = 0;
+                              gpioNotify[n].state = PI_NOTIFY_CLOSING;
+                              intNotifyBits();
+                              break;
+                           }
                         }
                      }
 
@@ -2865,7 +2760,7 @@ static void * pthAlertThread(void *x)
 
       if (changedBits & scriptBits)
       {
-         for (n=0; n<PI_SCRIPT_SLOTS; n++)
+         for (n=0; n<PI_MAX_SCRIPTS; n++)
          {
             if ((gpioScript[n].state     == PI_SCRIPT_IN_USE)  &&
                 (gpioScript[n].run_state == PI_SCRIPT_WAITING) &&
@@ -2986,8 +2881,8 @@ static void *pthScript(void *x)
    gpioScript_t *s;
    gpioExtent_t oExt[3];
    char buf[CMD_BUF_SIZE];
-   gpioInstr_t instr;
-   int p1, p2;
+   cmdInstr_t instr;
+   int p1, p2, p1o, p2o, *t1, *t2;
 
    int PC, A, F, SP;
    int S[PI_SCRIPT_STACK_SIZE];
@@ -3014,34 +2909,22 @@ static void *pthScript(void *x)
       while ((s->request   == PI_SCRIPT_RUN    ) &&
              (s->run_state == PI_SCRIPT_RUNNING))
       {
-         instr = s->instr[PC];
+         instr = s->script.instr[PC];
+
+         p1o = instr.p[1];
+         p2o = instr.p[2];
 
-         p1 = instr.p[1];
-         p2 = instr.p[2];
+         if      (instr.opt[0] == CMD_VAR) instr.p[1] = s->script.var[p1o];
+         else if (instr.opt[0] == CMD_PAR) instr.p[1] = s->script.par[p1o];
+
+         if      (instr.opt[1] == CMD_VAR) instr.p[2] = s->script.var[p2o];
+         else if (instr.opt[1] == CMD_PAR) instr.p[2] = s->script.par[p2o];
 
          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;
@@ -3050,98 +2933,146 @@ static void *pthScript(void *x)
          }
          else
          {
+            p1 = instr.p[1];
+            p2 = instr.p[2];
+
             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_ADD:   A+=p1; F=A;                     PC++; break;
 
-               case PI_CMD_ANDV:  A&=s->var[p1]; F=A;              PC++; break;
+               case PI_CMD_AND:   A&=p1; F=A;                     PC++; break;
 
-               case PI_CMD_CALL:  scrPush(s, S, &SP, PC+1);     PC = p1; break;
+               case PI_CMD_CALL:  scrPush(s, &SP, S, PC+1);    PC = p1; break;
 
-               case PI_CMD_CMPI:  F=A-p1;                          PC++; break;
+               case PI_CMD_CMP:   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_DCR:
+                  if (instr.opt[0] == CMD_PAR)
+                     {--s->script.par[p1o]; F=s->script.par[p1o];}
+                  else
+                     {--s->script.var[p1o]; F=s->script.var[p1o];}
+                  PC++;
+                  break;
 
-               case PI_CMD_INRA:  ++A; F=A;                        PC++; break;
+               case PI_CMD_DCRA:  --A; F=A;                       PC++; break;
 
-               case PI_CMD_INRV:  ++s->var[p1]; F=s->var[p1];      PC++; break;
+               case PI_CMD_DIV:   A/=p1; F=A;                     PC++; break;
 
-               case PI_CMD_JM:    if (F<0)  PC=p1; else PC++;            break;
+               case PI_CMD_HALT: s->run_state = PI_SCRIPT_HALTED;       break;
 
-               case PI_CMD_JMP:   PC=p1;                                 break;
+               case PI_CMD_INR:
+                  if (instr.opt[0] == CMD_PAR)
+                     {++s->script.par[p1o]; F=s->script.par[p1o];}
+                  else
+                     {++s->script.var[p1o]; F=s->script.var[p1o];}
+                  PC++;
+                  break;
 
-               case PI_CMD_JNZ:   if (F)    PC=p1; else PC++;            break;
+               case PI_CMD_INRA:  ++A; F=A;                       PC++; break;
 
-               case PI_CMD_JP:    if (F>=0) PC=p1; else PC++;            break;
+               case PI_CMD_JM:    if (F<0)  PC=p1; else PC++;           break;
 
-               case PI_CMD_JZ:    if (!F)   PC=p1; else PC++;            break;
+               case PI_CMD_JMP:   PC=p1;                                break;
 
-               case PI_CMD_LABEL:                                  PC++; break;
+               case PI_CMD_JNZ:   if (F)    PC=p1; else PC++;           break;
 
-               case PI_CMD_LDAI:  A=p1;                            PC++; break;
+               case PI_CMD_JP:    if (F>=0) PC=p1; else PC++;           break;
 
-               case PI_CMD_LDAP:  A=s->param[p1];                  PC++; break;
+               case PI_CMD_JZ:    if (!F)   PC=p1; else PC++;           break;
 
-               case PI_CMD_LDAV:  A=s->var[p1];                    PC++; break;
+               case PI_CMD_LD:
+                  if (instr.opt[0] == CMD_PAR) s->script.par[p1o]=p2;
+                  else                         s->script.var[p1o]=p2;
+                  PC++;
+                  break;
 
-               case PI_CMD_LDPA:  s->param[p1]=A;                  PC++; break;
+               case PI_CMD_LDA:   A=p1;                           PC++; break;
 
-               case PI_CMD_LDVA:  s->var[p1]=A;                    PC++; break;
+               case PI_CMD_MLT:   A*=p1; F=A;                     PC++; break;
 
-               case PI_CMD_LDVI:  s->var[p1] = p2;                 PC++; break;
+               case PI_CMD_MOD:   A%=p1; F=A;                     PC++; break;
 
-               case PI_CMD_LDVV:  s->var[p1]=s->var[p2];           PC++; break;
+               case PI_CMD_OR:    A|=p1; F=A;                     PC++; break;
 
-               case PI_CMD_ORI:   A|=p1; F=A;                      PC++; break;
+               case PI_CMD_POP:
+                  if (instr.opt[0] == CMD_PAR)
+                     s->script.par[p1o]=scrPop(s, &SP, S);
+                  else
+                     s->script.var[p1o]=scrPop(s, &SP, S);
+                  PC++;
+                  break;
 
-               case PI_CMD_ORV:   A|=s->var[p1]; F=A;              PC++; break;
+               case PI_CMD_POPA:  A=scrPop(s, &SP, S);            PC++; break;
 
-               case PI_CMD_POPA:  A=scrPop(s, S, &SP);             PC++; break;
+               case PI_CMD_PUSH:
+                  if (instr.opt[0] == CMD_PAR)
+                     scrPush(s, &SP, S, s->script.par[p1o]);
+                  else
+                     scrPush(s, &SP, S, s->script.var[p1o]);
+                  PC++;
+                  break;
 
-               case PI_CMD_POPV:  s->var[p1]=scrPop(s, S, &SP);    PC++; break;
+               case PI_CMD_PUSHA: scrPush(s, &SP, S, A);          PC++; break;
 
-               case PI_CMD_PUSHA: scrPush(s, S, &SP, A);           PC++; break;
+               case PI_CMD_RET:   PC=scrPop(s, &SP, S);                 break;
 
-               case PI_CMD_PUSHV: scrPush(s, S, &SP, s->var[p1]);  PC++; break;
+               case PI_CMD_RL:
+                  if (instr.opt[0] == CMD_PAR)
+                     {s->script.par[p1o]<<=p2; F=s->script.par[p1o];}
+                  else
+                     {s->script.var[p1o]<<=p2; F=s->script.var[p1o];}
+                  PC++;
+                  break;
 
-               case PI_CMD_RET:   PC=scrPop(s, S, &SP);                  break;
+               case PI_CMD_RLA:   A<<=p1; F=A;                    PC++; break;
 
-               case PI_CMD_RAL:   A<<=p1; F=A;                     PC++; break;
+               case PI_CMD_RR:
+                  if (instr.opt[0] == CMD_PAR)
+                     {s->script.par[p1o]>>=p2; F=s->script.par[p1o];}
+                  else
+                     {s->script.var[p1o]>>=p2; F=s->script.var[p1o];}
+                  PC++;
+                  break;
 
-               case PI_CMD_RAR:   A>>=p1; F=A;                     PC++; break;
+               case PI_CMD_RRA:   A>>=p1; F=A;                    PC++; break;
 
-               case PI_CMD_SUBI:  A-=p1; F=A;                      PC++; break;
+               case PI_CMD_STA:
+                  if (instr.opt[0] == CMD_PAR) s->script.par[p1o]=A;
+                  else                         s->script.var[p1o]=A;
+                  PC++;
+                  break;
 
-               case PI_CMD_SUBV:  A-=s->var[p1]; F=A;              PC++; break;
+               case PI_CMD_SUB:   A-=p1; F=A;                     PC++; break;
 
-               case PI_CMD_SWAPA: scrSwap(&s->var[p1], &A);        PC++; break;
+               case PI_CMD_X:
+                  if (instr.opt[0] == CMD_PAR) t1 = &s->script.par[p1o];
+                  else                         t1 = &s->script.var[p1o];
 
-               case PI_CMD_SWAPV: scrSwap(&s->var[p1], &s->var[p2]);PC++; break;
+                  if (instr.opt[1] == CMD_PAR) t2 = &s->script.par[p2o];
+                  else                         t2 = &s->script.var[p2o];
 
-               case PI_CMD_SYS:   A=scrSys((char*)p1, A); F=A;     PC++; break;
+                  scrSwap(t1, t2);
+                  PC++;
+                  break;
 
-               case PI_CMD_WAITI: A=scrWait(s, p1); F=A;           PC++; break;
+               case PI_CMD_XA:
+                  if (instr.opt[0] == CMD_PAR)
+                     scrSwap(&s->script.par[p1o], &A);
+                  else
+                     scrSwap(&s->script.var[p1o], &A);
+                  PC++;
+                  break;
 
-               case PI_CMD_WAITV: A=scrWait(s, s->var[p1]); F=A;   PC++; break;
+               case PI_CMD_SYS:   A=scrSys((char*)p1, A); F=A;    PC++; break;
 
-               case PI_CMD_XORI:  A^=p1; F=A;                      PC++; break;
+               case PI_CMD_WAIT:  A=scrWait(s, p1); F=A;          PC++; break;
 
-               case PI_CMD_XORV:  A^=s->var[p1]; F=A;              PC++; break;
+               case PI_CMD_XOR:   A^=p1; F=A;                     PC++; break;
 
             }
          }
 
-         if (PC >= s->instrs) s->run_state = PI_SCRIPT_HALTED;
+         if (PC >= s->script.instrs) s->run_state = PI_SCRIPT_HALTED;
 
       }
 
@@ -3214,12 +3145,10 @@ static void * pthFifoThread(void *x)
    uint32_t p[10];
    void *v[10];
    gpioExtent_t oExt[3];
-   gpioCtlParse_t ctl;
+   cmdCtlParse_t ctl;
    char *pp;
    uint32_t *param;
 
-   ctl.flags = 0;
-
    myCreatePipe(PI_INPFIFO, 0662);
 
    if ((inpFifo = fopen(PI_INPFIFO, "r+")) == NULL)
@@ -3310,7 +3239,7 @@ static void * pthFifoThread(void *x)
                   {
                      fprintf(outFifo, "%d", res);
                      param = oExt[0].ptr;
-                     for (i=0; i<MAX_SCRIPT_PARAMS; i++)
+                     for (i=0; i<PI_MAX_SCRIPT_PARAMS; i++)
                      {
                         fprintf(outFifo, " %d", param[i]);
                      }
@@ -3528,7 +3457,7 @@ static void *pthSocketThreadHandler(void *fdC)
 
             if (res >= 0)
             {
-               write(sock, oExt[0].ptr, sizeof(uint32_t)*MAX_SCRIPT_PARAMS);
+               write(sock, oExt[0].ptr, sizeof(uint32_t)*PI_MAX_SCRIPT_PARAMS);
             }
             break;
 
@@ -4390,11 +4319,11 @@ void putBitInBytes(int bitPos, uint8_t *buf, int val)
 
 /* ----------------------------------------------------------------------- */
 
-uint32_t waveGetRawOut(int pos)
+uint32_t rawWaveGetOut(int pos)
 {
    int page, slot;
 
-   if ((pos >= 0) && (pos < NUM_OOL))
+   if ((pos >= 0) && (pos < NUM_WAVE_OOL))
    {
       waveOOLPageSlot(pos, &page, &slot);
       return (dmaOVirt[page]->OOL[slot]);
@@ -4409,7 +4338,7 @@ void waveSetRawOut(int pos, uint32_t value)
 {
    int page, slot;
 
-   if ((pos >= 0) && (pos < NUM_OOL))
+   if ((pos >= 0) && (pos < NUM_WAVE_OOL))
    {
       waveOOLPageSlot(pos, &page, &slot);
       dmaOVirt[page]->OOL[slot] = value;
@@ -4419,13 +4348,13 @@ void waveSetRawOut(int pos, uint32_t value)
 
 /* ----------------------------------------------------------------------- */
 
-uint32_t waveGetRawIn(int pos)
+uint32_t rawWaveGetIn(int pos)
 {
    int page, slot;
 
-   if ((pos >= 0) && (pos < NUM_OOL))
+   if ((pos >= 0) && (pos < NUM_WAVE_OOL))
    {
-      waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot);
+      waveOOLPageSlot((NUM_WAVE_OOL-1)-pos, &page, &slot);
       return (dmaOVirt[page]->OOL[slot]);
    }
 
@@ -4434,13 +4363,13 @@ uint32_t waveGetRawIn(int pos)
 
 /* ----------------------------------------------------------------------- */
 
-void waveSetRawIn(int pos, uint32_t value)
+void rawWaveSetIn(int pos, uint32_t value)
 {
    int page, slot;
 
-   if ((pos >= 0) && (pos < NUM_OOL))
+   if ((pos >= 0) && (pos < NUM_WAVE_OOL))
    {
-      waveOOLPageSlot((NUM_OOL-1)-pos, &page, &slot);
+      waveOOLPageSlot((NUM_WAVE_OOL-1)-pos, &page, &slot);
       dmaOVirt[page]->OOL[slot] = value;
    }
 }
@@ -4481,7 +4410,7 @@ void time_sleep(double seconds)
 
 /* ----------------------------------------------------------------------- */
 
-void gpioDumpWave(void)
+void rawDumpWave(void)
 {
    int i;
 
@@ -4505,30 +4434,30 @@ void gpioDumpWave(void)
 
 /* ----------------------------------------------------------------------- */
 
-void gpioDumpScript(int s)
+void rawDumpScript(int s)
 {
    int i;
 
-   for (i=0; i<MAX_SCRIPT_PARAMS; i++)
+   for (i=0; i<PI_MAX_SCRIPT_PARAMS; i++)
    {
-      fprintf(stderr, "p%d=%d ", i, gpioScript[s].param[i]);
+      fprintf(stderr, "p%d=%d ", i, gpioScript[s].script.par[i]);
    }
 
    fprintf(stderr, "\n");
 
-   for (i=0; i<MAX_SCRIPT_VARS; i++)
+   for (i=0; i<PI_MAX_SCRIPT_VARS; i++)
    {
-      fprintf(stderr, "v%d=%d ", i, gpioScript[s].var[i]);
+      fprintf(stderr, "v%d=%d ", i, gpioScript[s].script.var[i]);
    }
 
    fprintf(stderr, "\n");
 
-   for (i=0; i<gpioScript[s].instrs; i++)
+   for (i=0; i<gpioScript[s].script.instrs; i++)
    {
       fprintf(stderr, "c%d=[%d, %d(%d), %d(%d)]\n",
-         i, gpioScript[s].instr[i].p[0],
-         gpioScript[s].instr[i].p[1], gpioScript[s].instr[i].opt[0],
-         gpioScript[s].instr[i].p[2], gpioScript[s].instr[i].opt[1]);
+         i, gpioScript[s].script.instr[i].p[0],
+         gpioScript[s].script.instr[i].p[1], gpioScript[s].script.instr[i].opt[0],
+         gpioScript[s].script.instr[i].p[2], gpioScript[s].script.instr[i].opt[1]);
    }
 }
 
@@ -5061,193 +4990,111 @@ int gpioServo(unsigned gpio, unsigned val)
 
 /* ----------------------------------------------------------------------- */
 
-int gpioWaveGetMicros(void)
+int gpioWaveClear(void)
 {
    DBG(DBG_USER, "");
 
    CHECK_INITED;
 
-   return wfStats.micros;
-}
+   wfc[0] = 0;
+   wfc[1] = 0;
+   wfc[2] = 0;
 
+   wfcur = 0;
 
-/* ----------------------------------------------------------------------- */
+   wfStats.micros = 0;
+   wfStats.pulses = 0;
+   wfStats.cbs    = 0;
 
-int gpioWaveGetHighMicros(void)
-{
-   DBG(DBG_USER, "");
+   waveOutBotCB  = 0;
+   waveOutTopCB  = NUM_WAVE_CBS;
+   waveOutBotOOL = 0;
+   waveOutTopOOL = NUM_WAVE_OOL;
 
-   CHECK_INITED;
+   waveOutCount = 0;
 
-   return wfStats.highMicros;
+   return 0;
 }
 
-
 /* ----------------------------------------------------------------------- */
 
-int gpioWaveGetMaxMicros(void)
+int gpioWaveAddNew(void)
 {
    DBG(DBG_USER, "");
 
    CHECK_INITED;
 
-   return wfStats.maxMicros;
-}
-
-
-/* ----------------------------------------------------------------------- */
+   wfc[0] = 0;
+   wfc[1] = 0;
+   wfc[2] = 0;
 
-int gpioWaveGetPulses(void)
-{
-   DBG(DBG_USER, "");
+   wfcur = 0;
 
-   CHECK_INITED;
+   wfStats.micros = 0;
+   wfStats.pulses = 0;
+   wfStats.cbs    = 0;
 
-   return wfStats.pulses;
+   return 0;
 }
 
-
 /* ----------------------------------------------------------------------- */
 
-int gpioWaveGetHighPulses(void)
+int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t *pulses)
 {
-   DBG(DBG_USER, "");
+   int p;
+
+   DBG(DBG_USER, "numPulses=%u pulses=%08X", numPulses, (uint32_t)pulses);
 
    CHECK_INITED;
 
-   return wfStats.highPulses;
-}
+   if (numPulses > PI_WAVE_MAX_PULSES)
+      SOFT_ERROR(PI_TOO_MANY_PULSES, "bad number of pulses (%d)", numPulses);
+
+   for (p=0; p<numPulses; p++)
+   {
+      wf[2][p].gpioOff = pulses[p].gpioOff;
+      wf[2][p].gpioOn  = pulses[p].gpioOn;
+      wf[2][p].usDelay = pulses[p].usDelay;
+      wf[2][p].flags   = 0;
+   }
 
+   return waveMerge(numPulses, wf[2]);
+}
 
 /* ----------------------------------------------------------------------- */
 
-int gpioWaveGetMaxPulses(void)
+int gpioWaveAddSerial(unsigned gpio,
+                      unsigned baud,
+                      unsigned offset,
+                      unsigned numChar,
+                      char     *str)
 {
-   DBG(DBG_USER, "");
+   int i, b, p, lev, c, v;
 
-   CHECK_INITED;
+   unsigned bitDelay[10];
 
-   return wfStats.maxPulses;
-}
+   DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=[%s]",
+      gpio, baud, offset, numChar, str);
 
+   DBG(DBG_USER, "l=%d s=%X e=%X",
+      strlen(str), str[0], str[strlen(str)-1]);
 
-/* ----------------------------------------------------------------------- */
+   CHECK_INITED;
 
-int gpioWaveGetCbs(void)
-{
-   DBG(DBG_USER, "");
+   if (gpio > PI_MAX_USER_GPIO)
+      SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
 
-   CHECK_INITED;
+   if ((baud < PI_WAVE_MIN_BAUD) || (baud > PI_WAVE_MAX_BAUD))
+      SOFT_ERROR(PI_BAD_WAVE_BAUD,
+         "gpio %d, bad baud rate (%d)", gpio, baud);
 
-   return wfStats.cbs;
-}
+   if (numChar > PI_WAVE_MAX_CHARS)
+      SOFT_ERROR(PI_TOO_MANY_CHARS, "too many chars (%d)", numChar);
 
+   if (offset > PI_WAVE_MAX_MICROS)
+      SOFT_ERROR(PI_BAD_SER_OFFSET, "offset too large (%d)", offset);
 
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveGetHighCbs(void)
-{
-   DBG(DBG_USER, "");
-
-   CHECK_INITED;
-
-   return wfStats.highCbs;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveGetMaxCbs(void)
-{
-   DBG(DBG_USER, "");
-
-   CHECK_INITED;
-
-   return wfStats.maxCbs;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveClear(void)
-{
-   DBG(DBG_USER, "");
-
-   CHECK_INITED;
-
-   wfc[0] = 0;
-   wfc[1] = 0;
-   wfc[2] = 0;
-
-   wfcur = 0;
-
-   wfStats.micros = 0;
-   wfStats.pulses = 0;
-   wfStats.cbs    = 0;
-
-   return 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t *pulses)
-{
-   int p;
-
-   DBG(DBG_USER, "numPulses=%u pulses=%08X", numPulses, (uint32_t)pulses);
-
-   CHECK_INITED;
-
-   if (numPulses > PI_WAVE_MAX_PULSES)
-      SOFT_ERROR(PI_TOO_MANY_PULSES, "bad number of pulses (%d)", numPulses);
-
-   for (p=0; p<numPulses; p++)
-   {
-      wf[2][p].gpioOff = pulses[p].gpioOff;
-      wf[2][p].gpioOn  = pulses[p].gpioOn;
-      wf[2][p].usDelay = pulses[p].usDelay;
-      wf[2][p].flags   = 0;
-   }
-
-   return waveMerge(numPulses, wf[2]);
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveAddSerial(unsigned gpio,
-                      unsigned baud,
-                      unsigned offset,
-                      unsigned numChar,
-                      char     *str)
-{
-   int i, b, p, lev, c, v;
-
-   unsigned bitDelay[10];
-
-   DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=[%s]",
-      gpio, baud, offset, numChar, str);
-
-   DBG(DBG_USER, "l=%d s=%X e=%X",
-      strlen(str), str[0], str[strlen(str)-1]);
-
-   CHECK_INITED;
-
-   if (gpio > PI_MAX_USER_GPIO)
-      SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
-
-   if ((baud < PI_WAVE_MIN_BAUD) || (baud > PI_WAVE_MAX_BAUD))
-      SOFT_ERROR(PI_BAD_WAVE_BAUD,
-         "gpio %d, bad baud rate (%d)", gpio, baud);
-
-   if (numChar > PI_WAVE_MAX_CHARS)
-      SOFT_ERROR(PI_TOO_MANY_CHARS, "too many chars (%d)", numChar);
-
-   if (offset > PI_WAVE_MAX_MICROS)
-      SOFT_ERROR(PI_BAD_SER_OFFSET, "offset too large (%d)", offset);
-
-   if (!numChar) return 0;
+   if (!numChar) return 0;
 
    waveBitDelay(baud, bitDelay);
 
@@ -5329,8 +5176,8 @@ int gpioWaveAddSerial(unsigned gpio,
 
 /* ----------------------------------------------------------------------- */
 
-int gpioWaveAddSPI(
-   gpioSPI_t *spi,
+int rawWaveAddSPI(
+   rawSPI_t *spi,
    unsigned offset,
    unsigned ss,
    uint8_t *tx_bits,
@@ -5467,6 +5314,275 @@ int gpioWaveAddSPI(
    return waveMerge(p, wf[2]);
 }
 
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveCreate(void)
+{
+   int cb;
+
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   if (wfc[wfcur] == 0) return PI_EMPTY_WAVEFORM;
+
+   if (waveOutCount < PI_MAX_WAVES)
+   {
+      waveInfo[waveOutCount].botCB  = waveOutBotCB;
+      waveInfo[waveOutCount].botOOL = waveOutBotOOL;
+      waveInfo[waveOutCount].topOOL = waveOutTopOOL;
+
+      if ((cb = wave2Cbs(PI_WAVE_MODE_ONE_SHOT)) < 0) return cb;
+
+      waveInfo[waveOutCount].topCB  = waveOutBotCB-1;
+
+      gpioWaveAddNew();
+
+      return waveOutCount++;
+   }
+
+   return PI_NO_WAVEFORM_ID;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveDelete(unsigned wave_id)
+{
+   DBG(DBG_USER, "wave id=%d", wave_id);
+
+   CHECK_INITED;
+
+   if (wave_id >= waveOutCount)
+      SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id);
+
+   waveOutBotCB  = waveInfo[wave_id].botCB;
+   waveOutBotOOL = waveInfo[wave_id].botOOL;
+   waveOutTopOOL = waveInfo[wave_id].topOOL;
+
+   waveOutCount = wave_id;
+
+   return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveTxStart(unsigned mode)
+{
+   /* This function is deprecated and will be removed. */
+
+   static int secondaryClockInited = 0;
+
+   int cb, i;
+
+   DBG(DBG_USER, "mode=%d", mode);
+
+   CHECK_INITED;
+
+   if (mode > PI_WAVE_MODE_REPEAT)
+      SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode);
+
+   if (wfc[wfcur] == 0) return 0;
+   
+   if (!secondaryClockInited)
+   {
+      initClock(0); /* initialise secondary clock */
+      secondaryClockInited = 1;
+   }
+
+   dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
+
+   dmaOut[DMA_CONBLK_AD] = 0;
+
+   waveOutBotCB  = 0;
+   waveOutTopCB  = NUM_WAVE_CBS;
+   waveOutBotOOL = 0;
+   waveOutTopOOL = NUM_WAVE_OOL;
+
+   waveOutCount = 0;
+
+   cb = wave2Cbs(mode);
+
+   if (gpioCfg.dbgLevel >= DBG_SLOW_TICK)
+   {
+      fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n");
+      for (i=0; i<cb; i++) waveCbOPrint(i);
+   }
+
+   initDMAgo((uint32_t *)dmaOut, (uint32_t)dmaOPhys[0]);
+
+   return cb;
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveTxSend(unsigned wave_id, unsigned mode)
+{
+   rawCbs_t *p=NULL;
+
+   static int secondaryClockInited = 0;
+
+   DBG(DBG_USER, "wave_id=%d mode=%d", wave_id, mode);
+
+   CHECK_INITED;
+
+   if (wave_id >= waveOutCount)
+      SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id);
+
+   if (mode > PI_WAVE_MODE_REPEAT)
+      SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode);
+
+   if (!secondaryClockInited)
+   {
+      initClock(0); /* initialise secondary clock */
+      secondaryClockInited = 1;
+   }
+
+   p = rawWaveCBAdr(waveInfo[wave_id].topCB);
+
+   if (mode == PI_WAVE_MODE_ONE_SHOT) p->next = 0;
+   else p->next = waveCbPOadr(waveInfo[wave_id].botCB+1) | DMA_BUS_ADR;
+
+   dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
+
+   dmaOut[DMA_CONBLK_AD] = 0;
+
+   initDMAgo((uint32_t *)dmaOut, waveCbPOadr(waveInfo[wave_id].botCB));
+
+   /* for compatability with the deprecated gpioWaveTxStart return the
+      number of cbs
+   */
+   return (waveInfo[wave_id].topCB - waveInfo[wave_id].botCB) + 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+int gpioWaveTxBusy(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   if (dmaOut[DMA_CONBLK_AD])
+      return 1;
+   else
+      return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveTxStop(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
+
+   dmaOut[DMA_CONBLK_AD] = 0;
+
+   return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetMicros(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.micros;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetHighMicros(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.highMicros;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetMaxMicros(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.maxMicros;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetPulses(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.pulses;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetHighPulses(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.highPulses;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetMaxPulses(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.maxPulses;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetCbs(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.cbs;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetHighCbs(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.highCbs;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int gpioWaveGetMaxCbs(void)
+{
+   DBG(DBG_USER, "");
+
+   CHECK_INITED;
+
+   return wfStats.maxCbs;
+}
+
 /*-------------------------------------------------------------------------*/
 
 int gpioSerialReadOpen(unsigned gpio, unsigned baud)
@@ -5540,7 +5656,7 @@ int gpioSerialRead(unsigned gpio, void *buf, size_t bufSize)
 
       if (bytes > bufSize) bytes = bufSize;
 
-      memcpy(buf, p->buf+p->readPos, bytes);
+      if (buf) memcpy(buf, p->buf+p->readPos, bytes);
 
       p->readPos += bytes;
 
@@ -5586,78 +5702,6 @@ int gpioSerialReadClose(unsigned gpio)
 }
 
 
-/*-------------------------------------------------------------------------*/
-
-int gpioWaveTxBusy(void)
-{
-   DBG(DBG_USER, "");
-
-   CHECK_INITED;
-
-   if (dmaOut[DMA_CONBLK_AD])
-      return 1;
-   else
-      return 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveTxStart(unsigned mode)
-{
-   static int secondaryClockInited = 0;
-
-   int cb, i;
-
-   DBG(DBG_USER, "mode=%d", mode);
-
-   CHECK_INITED;
-
-   if (mode > PI_WAVE_MODE_REPEAT)
-      SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", mode);
-
-   if (wfc[wfcur] == 0) return 0;
-   
-   if (!secondaryClockInited)
-   {
-      initClock(0); /* initialise secondary clock */
-      secondaryClockInited = 1;
-   }
-
-   dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
-
-   dmaOut[DMA_CONBLK_AD] = 0;
-
-   cb = wave2Cbs(mode);
-
-   if (gpioCfg.dbgLevel >= DBG_SLOW_TICK)
-   {
-      fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n");
-      for (i=0; i<cb; i++) waveCbOPrint(i);
-   }
-
-   initDMAgo((uint32_t *)dmaOut, (uint32_t)dmaOPhys[0]);
-
-   return cb;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-int gpioWaveTxStop(void)
-{
-   DBG(DBG_USER, "");
-
-   CHECK_INITED;
-
-   dmaOut[DMA_CS] = DMA_CHANNEL_RESET;
-
-   dmaOut[DMA_CONBLK_AD] = 0;
-
-   return 0;
-}
-
-
 /* ----------------------------------------------------------------------- */
 
 static int intGpioSetAlertFunc(
@@ -5812,7 +5856,7 @@ static void intScriptBits(void)
 
    bits = 0;
 
-   for (i=0; i<PI_SCRIPT_SLOTS; i++)
+   for (i=0; i<PI_MAX_SCRIPTS; i++)
    {
       if (gpioScript[i].state == PI_SCRIPT_IN_USE)
       {
@@ -5855,7 +5899,7 @@ int gpioNotifyBegin(unsigned handle, uint32_t bits)
 
    CHECK_INITED;
 
-   if (handle > PI_NOTIFY_SLOTS)
+   if (handle >= PI_NOTIFY_SLOTS)
       SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
 
    if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING)
@@ -5879,7 +5923,7 @@ int gpioNotifyPause (unsigned handle)
 
    CHECK_INITED;
 
-   if (handle > PI_NOTIFY_SLOTS)
+   if (handle >= PI_NOTIFY_SLOTS)
       SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
 
    if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING)
@@ -5903,7 +5947,7 @@ int gpioNotifyClose(unsigned handle)
 
    CHECK_INITED;
 
-   if (handle > PI_NOTIFY_SLOTS)
+   if (handle >= PI_NOTIFY_SLOTS)
       SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
 
    if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING)
@@ -6171,7 +6215,7 @@ int gpioStoreScript(char *script)
 
    slot = -1;
 
-   for (i=0; i<PI_SCRIPT_SLOTS; i++)
+   for (i=0; i<PI_MAX_SCRIPTS; i++)
    {
       if (gpioScript[i].state == PI_SCRIPT_FREE)
       {
@@ -6186,7 +6230,7 @@ int gpioStoreScript(char *script)
 
    s = &gpioScript[slot];
 
-   status = myParseScript(script, s);
+   status = cmdParseScript(script, &s->script, 0);
 
    if (status == 0)
    {
@@ -6207,8 +6251,8 @@ int gpioStoreScript(char *script)
    }
    else
    {
-      if (s->param) free(s->param);
-      s->param = NULL;
+      if (s->script.par) free(s->script.par);
+      s->script.par = NULL;
       gpioScript[slot].state = PI_SCRIPT_FREE;
    }
 
@@ -6218,7 +6262,7 @@ int gpioStoreScript(char *script)
 
 /* ----------------------------------------------------------------------- */
 
-int gpioRunScript(int script_id, unsigned numParam, uint32_t *param)
+int gpioRunScript(unsigned script_id, unsigned numParam, uint32_t *param)
 {
    int status = 0;
 
@@ -6227,7 +6271,10 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param)
 
    CHECK_INITED;
 
-   if (numParam > MAX_SCRIPT_PARAMS)
+   if (script_id >= PI_MAX_SCRIPTS)
+      SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id);
+
+   if (numParam > PI_MAX_SCRIPT_PARAMS)
       SOFT_ERROR(PI_TOO_MANY_PARAM, "bad number of parameters(%d)", numParam);
 
    if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
@@ -6238,7 +6285,7 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param)
       {
          if ((numParam > 0) && (param != 0))
          {
-            memcpy(gpioScript[script_id].param, param,
+            memcpy(gpioScript[script_id].script.par, param,
                sizeof(uint32_t) * numParam);
          }
 
@@ -6255,24 +6302,30 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param)
 
       return status;
    }
-   else return PI_BAD_SCRIPT_ID;
+   else
+   {
+      return PI_BAD_SCRIPT_ID;
+   }
 }
 
 
 /* ----------------------------------------------------------------------- */
 
-int gpioScriptStatus(int script_id, uint32_t *param)
+int gpioScriptStatus(unsigned script_id, uint32_t *param)
 {
    DBG(DBG_USER, "script_id=%d param=%08X", script_id, (uint32_t)param);
 
    CHECK_INITED;
 
+   if (script_id >= PI_MAX_SCRIPTS)
+      SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id);
+
    if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
    {
       if (param != 0)
       {
-         memcpy(param, gpioScript[script_id].param,
-            sizeof(uint32_t) * MAX_SCRIPT_PARAMS);
+         memcpy(param, gpioScript[script_id].script.par,
+            sizeof(uint32_t) * PI_MAX_SCRIPT_PARAMS);
       }
 
       return gpioScript[script_id].run_state;
@@ -6283,12 +6336,15 @@ int gpioScriptStatus(int script_id, uint32_t *param)
 
 /* ----------------------------------------------------------------------- */
 
-int gpioStopScript(int script_id)
+int gpioStopScript(unsigned script_id)
 {
    DBG(DBG_USER, "script_id=%d", script_id);
 
    CHECK_INITED;
 
+   if (script_id >= PI_MAX_SCRIPTS)
+      SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id);
+
    if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
    {
       pthread_mutex_lock(&gpioScript[script_id].pthMutex);
@@ -6309,12 +6365,15 @@ int gpioStopScript(int script_id)
 
 /* ----------------------------------------------------------------------- */
 
-int gpioDeleteScript(int script_id)
+int gpioDeleteScript(unsigned script_id)
 {
    DBG(DBG_USER, "script_id=%d", script_id);
 
    CHECK_INITED;
 
+   if (script_id >= PI_MAX_SCRIPTS)
+      SOFT_ERROR(PI_BAD_SCRIPT_ID, "bad script id(%d)", script_id);
+
    if (gpioScript[script_id].state == PI_SCRIPT_IN_USE)
    {
       gpioScript[script_id].state = PI_SCRIPT_DYING;
@@ -6337,9 +6396,9 @@ int gpioDeleteScript(int script_id)
 
       gpioStopThread(gpioScript[script_id].pthIdp);
 
-      if (gpioScript[script_id].param) free(gpioScript[script_id].param);
+      if (gpioScript[script_id].script.par) free(gpioScript[script_id].script.par);
 
-      gpioScript[script_id].param = NULL;
+      gpioScript[script_id].script.par = NULL;
 
       gpioScript[script_id].state = PI_SCRIPT_FREE;
 
@@ -6559,7 +6618,7 @@ uint32_t gpioDelay(uint32_t micros)
 
    start = systReg[SYST_CLO];
 
-   if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ;
+   if (micros <= MAX_DELAY) while ((systReg[SYST_CLO] - start) <= micros) ;
 
    else gpioSleep(PI_TIME_RELATIVE, (micros/MILLION), (micros%MILLION));
 
index 0ddac321f6b767b6a489273040b9ff8341fa8acf..6b163dd855758eb7f8e406b3f08e4b86965adbd1 100644 (file)
--- a/pigpio.h
+++ b/pigpio.h
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 13
+This version is for pigpio version 14
 */
 
 #ifndef PIGPIO_H
@@ -86,7 +86,7 @@ This version is for pigpio version 13
 #include <stdint.h>
 #include <pthread.h>
 
-#define PIGPIO_VERSION 13
+#define PIGPIO_VERSION 14
 
 /*-------------------------------------------------------------------------*/
 
@@ -125,18 +125,21 @@ gpioNotifyBegin            Begin a gpio(s) changed notification.
 gpioNotifyPause            Pause a gpio(s) changed notification.
 gpioNotifyClose            Close a gpio(s) changed notification.
 
-gpioWaveClear              Initialises a new waveform.
+gpioWaveClear              Deletes all waveforms.
+
+gpioWaveAddNew             Starts a new waveform.
 gpioWaveAddGeneric         Adds a series of pulses to the waveform.
 gpioWaveAddSerial          Adds serial data to the waveform.
 
-gpioWaveTxStart            Transmits the waveform.
+gpioWaveCreate             Creates a waveform from added data.
+gpioWaveDelete             Deletes one or more waveforms.
+
+gpioWaveTxStart            Creates/transmits a waveform (DEPRECATED).
+
+gpioWaveTxSend             Transmits a waveform.
 gpioWaveTxBusy             Checks to see if the waveform has ended.
 gpioWaveTxStop             Aborts the current waveform.
 
-gpioSerialReadOpen         Opens a gpio for reading serial data.
-gpioSerialRead             Reads serial data from a gpio.
-gpioSerialReadClose        Closes a gpio for reading serial data.
-
 gpioWaveGetMicros          Length in microseconds of the current waveform.
 gpioWaveGetHighMicros      Length of longest waveform so far.
 gpioWaveGetMaxMicros       Absolute maximum allowed micros.
@@ -149,6 +152,10 @@ gpioWaveGetCbs             Length in cbs of the current waveform.
 gpioWaveGetHighCbs         Length of longest waveform so far.
 gpioWaveGetMaxCbs          Absolute maximum allowed cbs.
 
+gpioSerialReadOpen         Opens a gpio for reading serial data.
+gpioSerialRead             Reads serial data from a gpio.
+gpioSerialReadClose        Closes a gpio for reading serial data.
+
 gpioTrigger                Send a trigger pulse to a gpio.
 
 gpioSetWatchdog            Set a watchdog on a gpio.
@@ -281,7 +288,17 @@ typedef struct
    int clk_pol; /* clock off state          */
    int clk_pha; /* clock phase              */
    int clk_us;  /* clock micros             */
-} gpioSPI_t;
+} rawSPI_t;
+
+typedef struct { /* linux/arch/arm/mach-bcm2708/include/mach/dma.h */
+   unsigned long info;
+   unsigned long src;
+   unsigned long dst;
+   unsigned long length;
+   unsigned long stride;
+   unsigned long next;
+   unsigned long pad[2];
+} rawCbs_t;
 
 typedef void (*gpioAlertFunc_t)    (int      gpio,
                                     int      level,
@@ -873,34 +890,26 @@ int gpioNotifyClose(unsigned handle);
 /*-------------------------------------------------------------------------*/
 int gpioWaveClear(void);
 /*-------------------------------------------------------------------------*/
-/* This function initialises a new waveform.
+/* This function clears all waveforms and any data added by calls to the
+   gpioWaveAdd* functions.
 
    Returns 0 if OK.
+*/
 
-   A waveform comprises one of more pulses.  Each pulse consists of a
-   gpioPulse_t structure.
-
-   typedef struct
-   {
-      uint32_t gpioOn;
-      uint32_t gpioOff;
-      uint32_t usDelay;
-   } gpioPulse_t;
 
-   The fields specify
 
-   1) the gpios to be switched on at the start of the pulse.
-   2) the gpios to be switched off at the start of the pulse.
-   3) the delay in microseconds before the next pulse.
-
-   Any or all the fields can be zero.  It doesn't make any sense to
-   set all the fields to zero (the pulse will be ignored).
+/*-------------------------------------------------------------------------*/
+int gpioWaveAddNew(void);
+/*-------------------------------------------------------------------------*/
+/* This function starts a new empty waveform.  You wouldn't normally need
+   to call this function as it is automatically called after a waveform is
+   created with the gpioWaveCreate function.
 
-   When a waveform is started each pulse is executed in order with the
-   specified delay between the pulse and the next.
+   Returns 0 if OK.
 */
 
 
+
 /*-------------------------------------------------------------------------*/
 int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses);
 /*-------------------------------------------------------------------------*/
@@ -911,7 +920,7 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses);
 
    NOTES:
 
-   The   pulses are interleaved in time order within the existing waveform
+   The pulses are interleaved in time order within the existing waveform
    (if any).
 
    Merging allows the waveform to be built in parts, that is the settings
@@ -956,81 +965,123 @@ int gpioWaveAddSerial(unsigned user_gpio,
 
 #define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */
 
+#define PI_MAX_WAVES 100
+
+
+
 /*-------------------------------------------------------------------------*/
-int gpioWaveTxStart(unsigned mode);
+int gpioWaveCreate(void);
 /*-------------------------------------------------------------------------*/
-/* This function transmits the current waveform.  The mode determines
-   whether the waveform is sent once or cycles endlessly.
+/* This function creates a waveform from the data provided by the prior
+   calls to the gpioWaveAdd* functions.  Upon success a positive wave id
+   is returned.
 
-   Returns the number of DMA control blocks in the waveform if OK,
-   otherwise PI_BAD_WAVE_MODE.
-*/
+   The data provided by the gpioWaveAdd* functions is consumed by this
+   function.
 
-#define PI_WAVE_MODE_ONE_SHOT 0
-#define PI_WAVE_MODE_REPEAT   1
+   As many waveforms may be created as there is space available.  The
+   wave id is passed to gpioWaveTxSend to specify the waveform to transmit.
 
+   Normal usage would be
 
+   Step 1. gpioWaveClear to clear all waveforms and added data.
 
-/*-------------------------------------------------------------------------*/
-int gpioWaveTxBusy(void);
-/*-------------------------------------------------------------------------*/
-/* This function checks to see if a waveform is currently being
-   transmitted.
+   Step 2. gpioWaveAdd* calls to supply the waveform data.
 
-   Returns 1 if a waveform is currently being transmitted, otherwise 0.
-*/
+   Step 3. gpioWaveCreate to create the waveform and get a unique id
 
+   Repeat steps 2 and 3 as needed.
 
+   Step 4. gpioWaveTxSend with the id of the waveform to transmit.
 
-/*-------------------------------------------------------------------------*/
-int gpioWaveTxStop(void);
-/*-------------------------------------------------------------------------*/
-/* This function aborts the transmission of the current waveform.
+   A waveform comprises one of more pulses.  Each pulse consists of a
+   gpioPulse_t structure.
 
-   Returns 0 if OK.
+   typedef struct
+   {
+      uint32_t gpioOn;
+      uint32_t gpioOff;
+      uint32_t usDelay;
+   } gpioPulse_t;
 
-   NOTES:
+   The fields specify
+
+   1) the gpios to be switched on at the start of the pulse.
+   2) the gpios to be switched off at the start of the pulse.
+   3) the delay in microseconds before the next pulse.
 
-   This function is intended to stop a waveform started with the repeat mode.
+   Any or all the fields can be zero.  It doesn't make any sense to
+   set all the fields to zero (the pulse will be ignored).
+
+   When a waveform is started each pulse is executed in order with the
+   specified delay between the pulse and the next.
+
+   Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM,
+   PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL.
 */
 
 
+/*-------------------------------------------------------------------------*/
+int gpioWaveDelete(unsigned wave_id);
+/*-------------------------------------------------------------------------*/
+/* This function deletes all created waveforms with ids greater than or
+   equal to wave_id.
+
+   Wave ids are allocated in order, 0, 1, 2, etc.
+
+   Returns 0 if OK, otherwise PI_BAD_WAVE_ID.
+*/
+
 
 /*-------------------------------------------------------------------------*/
-int gpioSerialReadOpen(unsigned user_gpio, unsigned baud);
+int gpioWaveTxStart(unsigned mode); /* DEPRECATED */
 /*-------------------------------------------------------------------------*/
-/* This function opens a gpio for reading serial data.
+/* This function creates and then transmits a waveform.  The mode
+   determines whether the waveform is sent once or cycles endlessly.
 
-   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
-   or PI_GPIO_IN_USE.
+   This function is deprecated and should no longer be used.  Use
+   gpioWaveCreate/gpioWaveTxSend instead.
 
-   The serial data is returned in a cyclic buffer and is read using
-   gpioSerialRead().
+   Returns the number of DMA control blocks in the waveform if OK,
+   otherwise PI_BAD_WAVE_MODE.
+*/
 
-   It is the caller's responsibility to read data from the cyclic buffer
-   in a timely fashion.
+/*-------------------------------------------------------------------------*/
+int gpioWaveTxSend(unsigned wave_id, unsigned mode);
+/*-------------------------------------------------------------------------*/
+/* This function transmits the waveform with id wave_id.  The mode
+   determines whether the waveform is sent once or cycles endlessly.
+
+   Returns the number of DMA control blocks in the waveform if OK,
+   otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
 */
 
+#define PI_WAVE_MODE_ONE_SHOT 0
+#define PI_WAVE_MODE_REPEAT   1
+
 
 
 /*-------------------------------------------------------------------------*/
-int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize);
+int gpioWaveTxBusy(void);
 /*-------------------------------------------------------------------------*/
-/* This function copies up to bufSize bytes of data read from the
-   serial cyclic buffer to the buffer starting at buf.
+/* This function checks to see if a waveform is currently being
+   transmitted.
 
-   Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
-   or PI_NOT_SERIAL_GPIO.
+   Returns 1 if a waveform is currently being transmitted, otherwise 0.
 */
 
 
 
 /*-------------------------------------------------------------------------*/
-int gpioSerialReadClose(unsigned user_gpio);
+int gpioWaveTxStop(void);
 /*-------------------------------------------------------------------------*/
-/* This function closes a gpio for reading serial data.
+/* This function aborts the transmission of the current waveform.
 
-   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
+   Returns 0 if OK.
+
+   NOTES:
+
+   This function is intended to stop a waveform started in repeat mode.
 */
 
 
@@ -1114,6 +1165,45 @@ int gpioWaveGetMaxCbs(void);
 
 
 
+/*-------------------------------------------------------------------------*/
+int gpioSerialReadOpen(unsigned user_gpio, unsigned baud);
+/*-------------------------------------------------------------------------*/
+/* This function opens a gpio for reading serial data.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
+   or PI_GPIO_IN_USE.
+
+   The serial data is returned in a cyclic buffer and is read using
+   gpioSerialRead().
+
+   It is the caller's responsibility to read data from the cyclic buffer
+   in a timely fashion.
+*/
+
+
+
+/*-------------------------------------------------------------------------*/
+int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize);
+/*-------------------------------------------------------------------------*/
+/* This function copies up to bufSize bytes of data read from the
+   serial cyclic buffer to the buffer starting at buf.
+
+   Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
+   or PI_NOT_SERIAL_GPIO.
+*/
+
+
+
+/*-------------------------------------------------------------------------*/
+int gpioSerialReadClose(unsigned user_gpio);
+/*-------------------------------------------------------------------------*/
+/* This function closes a gpio for reading serial data.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
+*/
+
+
+
 /*-------------------------------------------------------------------------*/
 int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level);
 /*-------------------------------------------------------------------------*/
@@ -1124,7 +1214,7 @@ int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level);
    or PI_BAD_PULSELEN.
 */
 
-#define PI_MAX_PULSELEN 100
+#define PI_MAX_PULSELEN 50
 
 
 /*-------------------------------------------------------------------------*/
@@ -1351,13 +1441,15 @@ int gpioStoreScript(char *script);
    otherwise PI_BAD_SCRIPT.
 */
 
-#define MAX_SCRIPT_LABELS  50
-#define MAX_SCRIPT_VARS   150
-#define MAX_SCRIPT_PARAMS  10
+#define PI_MAX_SCRIPTS       32
+
+#define PI_MAX_SCRIPT_TAGS   50
+#define PI_MAX_SCRIPT_VARS  150
+#define PI_MAX_SCRIPT_PARAMS 10
 
 
 /* ----------------------------------------------------------------------- */
-int gpioRunScript(int script_id, unsigned numParam, uint32_t *param);
+int gpioRunScript(unsigned script_id, unsigned numParam, uint32_t *param);
 /* ----------------------------------------------------------------------- */
 /* This function runs a stored script.
 
@@ -1371,7 +1463,7 @@ int gpioRunScript(int script_id, unsigned numParam, uint32_t *param);
 
 
 /* ----------------------------------------------------------------------- */
-int gpioScriptStatus(int script_id, uint32_t *param);
+int gpioScriptStatus(unsigned 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.
@@ -1399,7 +1491,7 @@ int gpioScriptStatus(int script_id, uint32_t *param);
 
 
 /* ----------------------------------------------------------------------- */
-int gpioStopScript(int script_id);
+int gpioStopScript(unsigned script_id);
 /* ----------------------------------------------------------------------- */
 /* This function stops a running script.
 
@@ -1409,7 +1501,7 @@ int gpioStopScript(int script_id);
 
 
 /* ----------------------------------------------------------------------- */
-int gpioDeleteScript(int script_id);
+int gpioDeleteScript(unsigned script_id);
 /* ----------------------------------------------------------------------- */
 /* This function deletes a stored script.
 
@@ -1615,7 +1707,8 @@ uint32_t gpioDelay(uint32_t micros);
    Returns the actual length of the delay in microseconds.  
 */
 
-
+#define PI_MAX_MICS_DELAY 1000000 /* 1 second */
+#define PI_MAX_MILS_DELAY 60000   /* 60 seconds */
 
 /*-------------------------------------------------------------------------*/
 uint32_t gpioTick(void);
@@ -1860,12 +1953,13 @@ int gpioCfgInternals(unsigned what,
                      int      value);
 /*-------------------------------------------------------------------------*/
 /* Used to tune internal settings.
+
    Not intended for general use.
 */
 
 /*-------------------------------------------------------------------------*/
-int gpioWaveAddSPI(
-   gpioSPI_t *spi,
+int rawWaveAddSPI(
+   rawSPI_t *spi,
    unsigned offset,
    unsigned ss,
    uint8_t *tx_bits,
@@ -1883,36 +1977,59 @@ int gpioWaveAddSPI(
 
    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.
+
+   Not intended for general use.
 */
 
+/* ----------------------------------------------------------------------- */
+unsigned rawWaveCB(void);
+/* ----------------------------------------------------------------------- */
+/*
+   Returns the number of the cb being currently output.
+
+   Not intended for general use.
+*/
+
+/* ----------------------------------------------------------------------- */
+rawCbs_t * rawWaveCBAdr(int n);
+/* ----------------------------------------------------------------------- */
+/*
+   Return the Linux address of contol block n.
+
+   Not intended for general use.
+*/
 
 /* ----------------------------------------------------------------------- */
-uint32_t waveGetRawOut(int pos);
+uint32_t rawWaveGetOut(int pos);
 /* ----------------------------------------------------------------------- */
 /* Gets the wave output parameter stored at pos.
+
    Not intended for general use.
 */
 
 
 /* ----------------------------------------------------------------------- */
-void waveSetRawOut(int pos, uint32_t value);
+void rawWaveSetOut(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);
+uint32_t rawWaveGetIn(int pos);
 /* ----------------------------------------------------------------------- */
 /* Gets the wave input value parameter stored at pos.
+
    Not intended for general use.
 */
 
 
 /* ----------------------------------------------------------------------- */
-void waveSetRawIn(int pos, uint32_t value);
+void rawWaveSetIn(int pos, uint32_t value);
 /* ----------------------------------------------------------------------- */
 /* Sets the wave input value stored at pos to value.
+
    Not intended for general use.
 */
 
@@ -1944,17 +2061,19 @@ void time_sleep(double seconds);
 
 
 /*-------------------------------------------------------------------------*/
-void gpioDumpWave(void);
+void rawDumpWave(void);
 /*-------------------------------------------------------------------------*/
 /* Used to print a readable version of the current waveform to stderr.
+
    Not intended for general use.
 */
 
 
 /*-------------------------------------------------------------------------*/
-void gpioDumpScript(int s);
+void rawDumpScript(int s);
 /*-------------------------------------------------------------------------*/
 /* Used to print a readable version of a script to stderr.
+
    Not intended for general use.
 */
 
@@ -2011,8 +2130,14 @@ void gpioDumpScript(int s);
 #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
+#define PI_CMD_MICS  46
+#define PI_CMD_MILS  47
+#define PI_CMD_PARSE 48
+#define PI_CMD_WVCRE 49
+#define PI_CMD_WVDEL 50
+#define PI_CMD_WVTX  51
+#define PI_CMD_WVTXR 52
+#define PI_CMD_WVNEW 53
 
 
 /*
@@ -2031,49 +2156,43 @@ after this command is issued.
 
 #define PI_CMD_SCRIPT 800
 
-#define PI_CMD_ADDI  800
-#define PI_CMD_ADDV  801
-#define PI_CMD_ANDI  802
-#define PI_CMD_ANDV  803
-#define PI_CMD_CALL  804
-#define PI_CMD_CMPI  805
-#define PI_CMD_CMPV  806
-#define PI_CMD_DCRA  807
-#define PI_CMD_DCRV  808
-#define PI_CMD_HALT  809
-#define PI_CMD_INRA  810
-#define PI_CMD_INRV  811
-#define PI_CMD_JM    812
-#define PI_CMD_JMP   813
-#define PI_CMD_JNZ   814
-#define PI_CMD_JP    815
-#define PI_CMD_JZ    816
-#define PI_CMD_LABEL 817
-#define PI_CMD_LDAI  818
-#define PI_CMD_LDAP  819
-#define PI_CMD_LDAV  820
-#define PI_CMD_LDPA  821
-#define PI_CMD_LDVA  822
-#define PI_CMD_LDVI  823
-#define PI_CMD_LDVV  824
-#define PI_CMD_ORI   827
-#define PI_CMD_ORV   828
-#define PI_CMD_POPA  829
-#define PI_CMD_POPV  830
-#define PI_CMD_PUSHA 831
-#define PI_CMD_PUSHV 832
-#define PI_CMD_RET   833
-#define PI_CMD_RAL   834
-#define PI_CMD_RAR   835
-#define PI_CMD_SUBI  836
-#define PI_CMD_SUBV  837
-#define PI_CMD_SWAPA 838
-#define PI_CMD_SWAPV 839
-#define PI_CMD_SYS   840
-#define PI_CMD_WAITI 841
-#define PI_CMD_WAITV 842
-#define PI_CMD_XORI  843
-#define PI_CMD_XORV  844
+#define PI_CMD_ADD   800
+#define PI_CMD_AND   801
+#define PI_CMD_CALL  802
+#define PI_CMD_CMP   803
+#define PI_CMD_DCR   804
+#define PI_CMD_DCRA  805
+#define PI_CMD_DIV   806
+#define PI_CMD_HALT  807
+#define PI_CMD_INR   808
+#define PI_CMD_INRA  809
+#define PI_CMD_JM    810
+#define PI_CMD_JMP   811
+#define PI_CMD_JNZ   812
+#define PI_CMD_JP    813
+#define PI_CMD_JZ    814
+#define PI_CMD_TAG   815
+#define PI_CMD_LD    816
+#define PI_CMD_LDA   817
+#define PI_CMD_MLT   818
+#define PI_CMD_MOD   819
+#define PI_CMD_OR    820
+#define PI_CMD_POP   821
+#define PI_CMD_POPA  822
+#define PI_CMD_PUSH  823
+#define PI_CMD_PUSHA 824
+#define PI_CMD_RET   825
+#define PI_CMD_RL    826
+#define PI_CMD_RLA   827
+#define PI_CMD_RR    828
+#define PI_CMD_RRA   829
+#define PI_CMD_STA   830
+#define PI_CMD_SUB   831
+#define PI_CMD_SYS   832
+#define PI_CMD_WAIT  833
+#define PI_CMD_X     834
+#define PI_CMD_XA    835
+#define PI_CMD_XOR   836
 
 /*-------------------------------------------------------------------------*/
 
@@ -2126,15 +2245,15 @@ after this command is issued.
 #define PI_BAD_WVSC_COMMND  -43 /* bad WVSC subcommand                     */
 #define PI_BAD_WVSM_COMMND  -44 /* bad WVSM subcommand                     */
 #define PI_BAD_WVSP_COMMND  -45 /* bad WVSP subcommand                     */
-#define PI_BAD_PULSELEN     -46 /* trigger pulse length > 100              */
+#define PI_BAD_PULSELEN     -46 /* trigger pulse length > 50               */
 #define PI_BAD_SCRIPT       -47 /* invalid script                          */
 #define PI_BAD_SCRIPT_ID    -48 /* unknown script id                       */
 #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_DUP_TAG          -53 /* script has duplicate tag                */
+#define PI_TOO_MANY_TAGS    -54 /* script has too many tags                */
 #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                */
@@ -2143,6 +2262,14 @@ after this command is issued.
 #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        */
+#define PI_BAD_TAG          -63 /* script has unresolved tag               */
+#define PI_BAD_MICS_DELAY   -64 /* bad MICS delay (too large)              */
+#define PI_BAD_MILS_DELAY   -65 /* bad MILS delay (too large)              */
+#define PI_BAD_WAVE_ID      -66 /* non existent wave id                    */
+#define PI_TOO_MANY_CBS     -67 /* No more CBs for waveform                */
+#define PI_TOO_MANY_OOL     -68 /* No more OOL for waveform                */
+#define PI_EMPTY_WAVEFORM   -69 /* attempt to create an empty waveform     */
+#define PI_NO_WAVEFORM_ID   -70 /* no more waveforms                       */
 
 /*-------------------------------------------------------------------------*/
 
index f5591ca0fd2b50ee6004927df67efced23cd364d..3124ecda2a02be34620a298c1d1858ebe1bfabab 100644 (file)
--- a/pigpio.py
+++ b/pigpio.py
@@ -26,7 +26,8 @@ The pigpio module's main features are:
 
 - provision of servo pulses on any number of gpios 0-31 simultaneously.
 
-- callbacks when any of gpios 0-31 change state.
+- callbacks when any of gpios 0-31 change state (callbacks receive the
+  time of the event accurate to a few microseconds).
 
 - reading/writing gpios and setting their modes (typically input
   or output).
@@ -34,6 +35,11 @@ The pigpio module's main features are:
 - reading/writing all of the gpios in a bank (0-31, 32-53) as a single
   operation.
 
+- creating and transmitting precisely timed waveforms (accurate
+  to a few microseconds).
+
+- creating and running scripts on the pigpio daemon.
+
 Notes
 
 ALL gpios are identified by their Broadcom number.
@@ -76,7 +82,7 @@ import threading
 import os
 import atexit
 
-VERSION = "1.4"
+VERSION = "1.5"
 
 # gpio levels
 
@@ -168,11 +174,16 @@ _PI_CMD_SLRO= 42
 _PI_CMD_SLR=  43
 _PI_CMD_SLRC= 44
 _PI_CMD_PROCP=45
-
+_PI_CMD_MICRO=46
+_PI_CMD_MILLI=47
+_PI_CMD_PARSE=48
+_PI_CMD_WVCRE=49
+_PI_CMD_WVDEL=50
+_PI_CMD_WVTX =51
+_PI_CMD_WVTXR=52
 
 _PI_CMD_NOIB= 99
 
-
 # pigpio error numbers
 
 _PI_INIT_FAILED     =-1
@@ -228,8 +239,8 @@ 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_DUP_TAG          =-53
+PI_TOO_MANY_TAGS    =-54
 PI_BAD_SCRIPT_CMD   =-55
 PI_BAD_VAR_NUM      =-56
 PI_NO_SCRIPT_ROOM   =-57
@@ -238,6 +249,14 @@ PI_SOCK_READ_FAILED =-59
 PI_SOCK_WRIT_FAILED =-60
 PI_TOO_MANY_PARAM   =-61
 PI_NOT_HALTED       =-62
+PI_BAD_TAG          =-63
+PI_BAD_MICS_DELAY   =-64
+PI_BAD_MILS_DELAY   =-65
+PI_BAD_WAVE_ID      =-66
+PI_TOO_MANY_CBS     =-67
+PI_TOO_MANY_OOL     =-68
+PI_EMPTY_WAVEFORM   =-69
+PI_NO_WAVEFORM_ID   =-70
 
 # pigpio error text
 
@@ -285,15 +304,15 @@ _errors=[
    [PI_BAD_WVSC_COMMND   , "bad WVSC subcommand"],
    [PI_BAD_WVSM_COMMND   , "bad WVSM subcommand"],
    [PI_BAD_WVSP_COMMND   , "bad WVSP subcommand"],
-   [PI_BAD_PULSELEN      , "trigger pulse length > 100"],
+   [PI_BAD_PULSELEN      , "trigger pulse length > 50"],
    [PI_BAD_SCRIPT        , "invalid script"],
    [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_DUP_TAG           , "script has duplicate tag"],
+   [PI_TOO_MANY_TAGS     , "script has too many tags"],
    [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"],
@@ -302,6 +321,14 @@ _errors=[
    [PI_SOCK_WRIT_FAILED  , "socket write failed"],
    [PI_TOO_MANY_PARAM    , "too many script parameters (> 10)"],
    [PI_NOT_HALTED        , "script already running or failed"],
+   [PI_BAD_TAG           , "script has unresolved tag"],
+   [PI_BAD_MICS_DELAY    , "bad MICS delay (too large)"],
+   [PI_BAD_MILS_DELAY    , "bad MILS delay (too large)"],
+   [PI_BAD_WAVE_ID       , "non existent wave id"],
+   [PI_TOO_MANY_CBS      , "No more CBs for waveform"],
+   [PI_TOO_MANY_OOL      , "No more OOL for waveform"],
+   [PI_EMPTY_WAVEFORM    , "attempt to create an empty waveform"],
+   [PI_NO_WAVEFORM_ID    , "No more waveform ids"],
 
 ]
 
@@ -402,11 +429,9 @@ def _pigpio_command_ext(sock, cmd, p1, p2, extents):
    extents: additional data blocks
    """
    if sock is not None:
-      sock.send(struct.pack('IIII', cmd, p1, p2, 0))
-
-      for ext in extents:
-         sock.sendall(ext)
-
+      msg = struct.pack('IIII', cmd, p1, p2, 0)
+      for ext in extents: msg += ext
+      sock.sendall(msg)
       x, y, z, res = struct.unpack('IIII', sock.recv(16))
       return res
    else:
@@ -523,7 +548,7 @@ class _wait_for_edge:
       _notify.append(self.callb)
       self.start = time.time()
       while (self.trigger == False) and ((time.time()-self.start) < timeout):
-         time.sleep(0.1)
+         time.sleep(0.05)
       _notify.remove(self.callb)
 
    def func(self, gpio, level, tick):
@@ -916,7 +941,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth):
 
    Example 1: standard 50 Hz hobby servo updates
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
@@ -943,7 +968,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth):
 
    Example 2: 400 Hz ESC type servo updates
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
@@ -1102,7 +1127,7 @@ def set_watchdog(user_gpio, timeout):
 
    Example
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
@@ -1189,7 +1214,7 @@ def clear_bank_1(levels):
 
    Example
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
 
@@ -1255,7 +1280,7 @@ def set_bank_1(levels):
 
    Example
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
 
@@ -1317,7 +1342,7 @@ def get_current_tick():
 
    Example
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
@@ -1406,26 +1431,19 @@ class pulse:
 
 def wave_clear():
    """
-   Initialises a new waveform.
-
-   Returns 0 if OK.
-
-   A waveform comprises one of more pulses.
-
-   A pulse specifies
-
-   1) the gpios to be switched on at the start of the pulse.
-   2) the gpios to be switched off at the start of the pulse.
-   3) the delay in microseconds before the next pulse.
-
-   Any or all the fields can be zero.  It doesn't make any sense
-   to set all the fields to zero (the pulse will be ignored).
-
-   When a waveform is started each pulse is executed in order with
-   the specified delay between the pulse and the next.
+   Clears all waveforms and any data added by calls to the
+   wave_add_* functions.
    """
    return _u2i(_pigpio_command(_control, _PI_CMD_WVCLR, 0, 0))
 
+def wave_add_new():
+   """
+   Starts a new empty waveform.  You wouldn't normally need
+   to call this function as it is automatically called after a
+   waveform is created with the wave_create function.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVNEW, 0, 0))
+
 def wave_add_generic(pulses):
    """
    Adds a list of pulses to the current waveform.
@@ -1447,62 +1465,54 @@ def wave_add_generic(pulses):
 
    Example
 
-   #!/usr/bin/env python
-
    import time
+
    import pigpio
 
-   class stepper:
-
-      def __init__(self, g1, g2, g3, g4):
-         self.g1 = g1
-         self.g2 = g2
-         self.g3 = g3
-         self.g4 = g4
-         self.all = (1<<g1 | 1<<g2 | 1<<g3 | 1<<g4)
-
-         pigpio.set_mode(g1, pigpio.OUTPUT)
-         pigpio.set_mode(g2, pigpio.OUTPUT)
-         pigpio.set_mode(g3, pigpio.OUTPUT)
-         pigpio.set_mode(g4, pigpio.OUTPUT)
-
-      def step_on(self, pos):
-         if   pos == 0: return (1<<self.g4)
-         elif pos == 1: return (1<<self.g3 | 1<<self.g4)
-         elif pos == 2: return (1<<self.g3)
-         elif pos == 3: return (1<<self.g2 | 1<<self.g3)
-         elif pos == 4: return (1<<self.g2)
-         elif pos == 5: return (1<<self.g1 | 1<<self.g2)
-         elif pos == 6: return (1<<self.g1)
-         elif pos == 7: return (1<<self.g1 | 1<<self.g4)
-         else:          return 0
-
-      def step_off(self, pos):
-         return self.step_on(pos) ^ self.all
+   G1=4
+   G2=22
 
    pigpio.start()
 
-   s1 = stepper(14, 15, 18, 17)
-   s2 = stepper(24, 25,  8,  7)
+   pigpio.set_mode(G1, pigpio.OUTPUT)
+   pigpio.set_mode(G2, pigpio.OUTPUT)
+
+
+   flash_500=[] # flash every 500 ms
+   flash_100=[] # flash every 100 ms
 
-   f1=[] # pulses to drive stepper 1 forward
-   b2=[] # pulses to drive stepper 2 backward
+   #                              ON     OFF  DELAY
 
-   for i in range(8):
-      f1.append(pigpio.pulse(s1.step_on(i), s1.step_off(i), 1200))
-      b2.append(pigpio.pulse(s2.step_on(7-i), s2.step_off(7-i), 1200))
+   flash_500.append(pigpio.pulse(1<<G1, 1<<G2, 500000))
+   flash_500.append(pigpio.pulse(1<<G2, 1<<G1, 500000))
 
-   pigpio.wave_clear() # initialise a new waveform
+   flash_100.append(pigpio.pulse(1<<G1, 1<<G2, 100000))
+   flash_100.append(pigpio.pulse(1<<G2, 1<<G1, 100000))
 
-   pigpio.wave_add_generic(f1) # add stepper 1 forward
-   pigpio.wave_add_generic(b2) # add stepper 2 backward
+   pigpio.wave_clear() # clear any existing waveforms
 
-   pigpio.wave_tx_repeat() # repeately transmit pulses
+   pigpio.wave_add_generic(flash_500) # 500 ms flashes
+   f500 = pigpio.wave_create() # create and save id
 
-   time.sleep(10)
+   pigpio.wave_add_generic(flash_100) # 100 ms flashes
+   f100 = pigpio.wave_create() # create and save id
+
+   pigpio.wave_send_repeat(f500)
+
+   time.sleep(4)
+
+   pigpio.wave_send_repeat(f100)
+
+   time.sleep(4)
+
+   pigpio.wave_send_repeat(f500)
+
+   time.sleep(4)
 
    pigpio.wave_tx_stop() # stop waveform
 
+   pigpio.wave_clear() # clear all waveforms
+
    pigpio.stop()
    """
    # pigpio message format
@@ -1511,12 +1521,15 @@ def wave_add_generic(pulses):
    # I p2 0
    ## extension ##
    # III on/off/delay * number of pulses
-   msg = ""
-   for p in pulses:
-      msg += struct.pack("III", p.gpio_on, p.gpio_off, p.delay)
-   extents = [msg]
-   return _u2i(_pigpio_command_ext(
-      _control, _PI_CMD_WVAG, len(pulses), 0, extents))
+   if len(pulses):
+      msg = ""
+      for p in pulses:
+         msg += struct.pack("III", p.gpio_on, p.gpio_off, p.delay)
+      extents = [msg]
+      return _u2i(_pigpio_command_ext(
+         _control, _PI_CMD_WVAG, len(pulses), 0, extents))
+   else:
+      return 0
 
 def wave_add_serial(user_gpio, baud, offset, data):
    """
@@ -1548,22 +1561,26 @@ def wave_add_serial(user_gpio, baud, offset, data):
 
    import pigpio
 
-   GPIO=24
+   TX_GPIO=22
 
    pigpio.start()
 
    pigpio.set_mode(TX_GPIO, pigpio.OUTPUT)
 
-   pigpio.wave_clear() # initialise waveform
+   pigpio.wave_clear() # clear all waveforms
 
    for i in range(10):
       pigpio.wave_add_serial(
-         GPIO, 9600, i*2000000, "{} seconds in.\r\n".format(i*2))
+         TX_GPIO, 300, i*2000000, "{} seconds in.\r\n".format(i*2))
+
+   id = pigpio.wave_create()
 
-   pigpio.wave_tx_start()
+   pigpio.wave_send_once(id)
 
    time.sleep(22)
 
+   pigpio.write(TX_GPIO, 0)
+
    pigpio.stop()
    """
    # pigpio message format
@@ -1574,48 +1591,117 @@ def wave_add_serial(user_gpio, baud, offset, data):
    # I baud
    # I offset
    # s data
-   extents = [struct.pack("I", baud),struct.pack("I", offset), data]
-   return _u2i(_pigpio_command_ext(
-      _control, _PI_CMD_WVAS, user_gpio, len(data), extents))
+   if len(data):
+      extents = [struct.pack("I", baud),struct.pack("I", offset), data]
+      return _u2i(_pigpio_command_ext(
+         _control, _PI_CMD_WVAS, user_gpio, len(data), extents))
+   else:
+      return 0
 
-def wave_tx_busy():
+def wave_create():
    """
-   Checks to see if a waveform is currently being transmitted.
+   Creates a waveform from the data provided by the prior calls to the
+   wave_add_* functions.  Upon success a positive wave id is returned.
 
-   Returns 1 if a waveform is currently being transmitted, otherwise 0.
+   The data provided by the wave_add_* functions is consumed by this
+   function.
+
+   As many waveforms may be created as there is space available.  The
+   wave id is passed to wave_send_* to specify the waveform to transmit.
+
+   Normal usage would be
+
+   Step 1. wave_clear to clear all waveforms and added data.
+
+   Step 2. wave_add_* calls to supply the waveform data.
+
+   Step 3. wave_create to create the waveform and get a unique id
+
+   Repeat steps 2 and 3 as needed.
+
+   Step 4. wave_send_* with the id of the waveform to transmit.
+
+   A waveform comprises one or more pulses.
+
+   A pulse specifies
+
+   1) the gpios to be switched on at the start of the pulse.
+   2) the gpios to be switched off at the start of the pulse.
+   3) the delay in microseconds before the next pulse.
+
+   Any or all the fields can be zero.  It doesn't make any sense
+   to set all the fields to zero (the pulse will be ignored).
+
+   When a waveform is started each pulse is executed in order with
+   the specified delay between the pulse and the next.
    """
-   return _u2i(_pigpio_command(_control, _PI_CMD_WVBSY, 0, 0))
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVCRE, 0, 0))
 
-def wave_tx_stop():
+def wave_delete(wave_id):
    """
-   Stops the transmission of the current waveform.
+   Deletes all created waveforms with ids greater than or equal
+   to wave_id.
 
-   Returns 0 if OK.
+   Wave ids are allocated in order, 0, 1, 2, etc.
 
-   This function is intended to stop a waveform started with
-   wave_tx_repeat().
+   Returns 0 if OK, otherwise PI_BAD_WAVE_ID.
    """
-   return _u2i(_pigpio_command(_control, _PI_CMD_WVHLT, 0, 0))
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVDEL, wave_id, 0))
 
 def wave_tx_start():
    """
-   Transmits the current waveform.  The waveform is sent once.
+   This function is deprecated and will be removed.
 
-   Returns the number of cbs in the waveform if OK,
-   otherwise PI_BAD_WAVE_MODE.
+     Use wave_create/wave_send_* instead.
    """
    return _u2i(_pigpio_command(_control, _PI_CMD_WVGO, 0, 0))
 
 def wave_tx_repeat():
    """
-   Transmits the current waveform.  The waveform repeats until
-   wave_tx_stop is called.
+   This function is deprecated and will be removed.
 
-   Returns the number of cbs in the waveform if OK,
-   otherwise PI_BAD_WAVE_MODE.
+   Use wave_create/wave_send_* instead.
    """
    return _u2i(_pigpio_command(_control, _PI_CMD_WVGOR, 0, 0))
 
+def wave_send_once(wave_id):
+   """
+   Transmits the waveform with id wave_id.  The waveform is sent once.
+
+   Returns the number of cbs in the waveform if OK,
+   otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVTX, wave_id, 0))
+
+def wave_send_repeat(wave_id):
+   """
+   Transmits the waveform with id wave_id.  The waveform repeats until
+   wave_tx_stop is called or another call to wave_send_* is made.
+
+   Returns the number of cbs in the waveform if OK,
+   otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVTXR, wave_id, 0))
+
+def wave_tx_busy():
+   """
+   Checks to see if a waveform is currently being transmitted.
+
+   Returns 1 if a waveform is currently being transmitted, otherwise 0.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVBSY, 0, 0))
+
+def wave_tx_stop():
+   """
+   Stops the transmission of the current waveform.
+
+   Returns 0 if OK.
+
+   This function is intended to stop a waveform started with
+   wave_send_repeatedly.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVHLT, 0, 0))
+
 def wave_get_micros():
    """
    Returns the length in microseconds of the current waveform.
@@ -1676,7 +1762,7 @@ def gpio_trigger(user_gpio, pulse_len=10, level=1):
 
    pigpio.start()
 
-   for i in range(10):
+   for i in range(5):
       pigpio.gpio_trigger(GPIO, (i*5)+10, 1)
       time.sleep(1)
 
@@ -1840,7 +1926,7 @@ class callback:
 
       Example 1: user supplied edge and callback
 
-      #!/usr/bin/python
+      #!/usr/bin/env python
 
       import pigpio
       import time
@@ -1869,7 +1955,7 @@ class callback:
 
       Example 2: user supplied edge, default (tally) callback
 
-      #!/usr/bin/python
+      #!/usr/bin/env python
 
       import pigpio
       import time
@@ -1904,7 +1990,7 @@ class callback:
 
       Example 3: default edge and (tally) callback
 
-      #!/usr/bin/python
+      #!/usr/bin/env python
 
       import pigpio
       import time
@@ -1983,7 +2069,7 @@ def wait_for_edge(user_gpio, edge=RISING_EDGE, timeout=60.0):
 
    Example 1: default edge and timeout
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
@@ -2007,7 +2093,7 @@ def wait_for_edge(user_gpio, edge=RISING_EDGE, timeout=60.0):
 
    Example 2: user supplied edge and timeout
 
-   #!/usr/bin/python
+   #!/usr/bin/env python
 
    import pigpio
    import time
index 5338b86a2066e47d44ec531cf87e7dccc4bb2529..2a8b9f2e1805d6e79d004482e04eaa1b7460b17e 100644 (file)
--- a/pigpiod.c
+++ b/pigpiod.c
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 11+
+This version is for pigpio version 14+
 */
 
 #include <sys/types.h>
@@ -59,6 +59,8 @@ static unsigned DMAsecondaryChannel    = PI_DEFAULT_DMA_SECONDARY_CHANNEL;
 static unsigned socketPort             = PI_DEFAULT_SOCKET_PORT;
 static uint64_t updateMask             = -1;
 
+static int updateMaskSet = 0;
+
 static FILE * errFifo;
 
 void fatal(char *fmt, ...)
@@ -183,7 +185,11 @@ static void initOpts(int argc, char *argv[])
          case 'x':
             mask = strtoll(optarg, &endptr, 0);
             printf("mask=%llx\n", mask);
-            if (!*endptr) updateMask = mask;
+            if (!*endptr)
+            {
+               updateMask = mask;
+               updateMaskSet = 1;
+            }
             else fatal("invalid -x option (%s)", optarg);
             break;
 
@@ -264,7 +270,7 @@ int main(int argc, char **argv)
 
    gpioCfgSocketPort(socketPort);
 
-   if (updateMask != -1) gpioCfgPermissions(updateMask);
+   if (updateMaskSet) gpioCfgPermissions(updateMask);
 
    /* start library */
 
index 2fab6d0b272fa5419c3e3285412e764a1d9ec1b1..b5cc3e7f855c3a266d2b2304ec6dca64bc361637 100644 (file)
@@ -606,6 +606,9 @@ uint32_t get_pigpio_version(void)
 int wave_clear(void)
    {return pigpio_command(gPigCommand, PI_CMD_WVCLR, 0, 0);}
 
+int wave_add_new(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVNEW, 0, 0);}
+
 int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses)
 {
    gpioExtent_t ext[1];
@@ -617,6 +620,8 @@ int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses)
    gpioPulse_t[] pulses
    */
 
+   if (!numPulses) return 0;
+
    ext[0].size = numPulses * sizeof(gpioPulse_t);
    ext[0].ptr = pulses;
 
@@ -637,6 +642,8 @@ int wave_add_serial(
    char[] str
    */
 
+   if (!numChar) return 0;
+
    ext[0].size = sizeof(unsigned);
    ext[0].ptr = &baud;
 
@@ -649,18 +656,30 @@ int wave_add_serial(
    return pigpio_command_ext(gPigCommand, PI_CMD_WVAS, gpio, numChar, 3, ext);
 }
 
-int wave_tx_busy(void)
-   {return pigpio_command(gPigCommand, PI_CMD_WVBSY, 0, 0);}
+int wave_create(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVCRE, 0, 0);}
 
-int wave_tx_stop(void)
-   {return pigpio_command(gPigCommand, PI_CMD_WVHLT, 0, 0);}
+int wave_delete(unsigned wave_id)
+   {return pigpio_command(gPigCommand, PI_CMD_WVDEL, wave_id, 0);}
 
-int wave_tx_start(void)
+int wave_tx_start(void) /* DEPRECATED */
    {return pigpio_command(gPigCommand, PI_CMD_WVGO, 0, 0);}
 
-int wave_tx_repeat(void)
+int wave_tx_repeat(void) /* DEPRECATED */
    {return pigpio_command(gPigCommand, PI_CMD_WVGOR, 0, 0);}
 
+int wave_send_once(unsigned wave_id)
+   {return pigpio_command(gPigCommand, PI_CMD_WVTX, 0, 0);}
+
+int wave_send_repeat(unsigned wave_id)
+   {return pigpio_command(gPigCommand, PI_CMD_WVTXR, 0, 0);}
+
+int wave_tx_busy(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVBSY, 0, 0);}
+
+int wave_tx_stop(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVHLT, 0, 0);}
+
 int wave_get_micros(void)
    {return pigpio_command(gPigCommand, PI_CMD_WVSM, 0, 0);}
 
@@ -743,10 +762,10 @@ int run_script(unsigned script_id, unsigned numPar, uint32_t *param)
       (gPigCommand, PI_CMD_PROCR, script_id, numPar, 1, ext);
 }
 
-int script_status(int script_id, uint32_t *param)
+int script_status(unsigned script_id, uint32_t *param)
 {
    int status;
-   uint32_t p[MAX_SCRIPT_PARAMS];
+   uint32_t p[PI_MAX_SCRIPT_PARAMS];
 
    status = pigpio_command(gPigCommand, PI_CMD_PROCP, script_id, 0);
 
index 809800c4d10a48ceb9991201afb5393e72b7cd5d..ef01ca8ac0042ae5984f9c36eccf01e27312491c 100644 (file)
@@ -30,7 +30,7 @@ For more information, please refer to <http://unlicense.org/>
 
 #include "pigpio.h"
 
-#define PIGPIOD_IF_VERSION 4
+#define PIGPIOD_IF_VERSION 5
 
 typedef enum
 {
@@ -514,11 +514,79 @@ uint32_t get_pigpio_version(void);
 
 
 int wave_clear(void);
-/* This function initialises a new waveform.
+/* This function clears all waveforms and any data added by calls to the
+   wave_add_* functions.
 
    Returns 0 if OK.
+*/
+
+int wave_add_new(void);
+/* This function starts a new empty waveform.  You wouldn't normally need
+   to call this function as it is automatically called after a waveform is
+   created with the wave_create function.
+
+   Returns 0 if OK.
+*/
+
+int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses);
+/* This function adds a number of pulses to the current waveform.
+
+   Returns the new total number of pulses in the current waveform if OK,
+   otherwise PI_TOO_MANY_PULSES.
+
+   The pulses are interleaved in time order within the existing waveform
+   (if any).
 
-   A waveform comprises one of more pulses.  Each pulse consists of a
+   Merging allows the waveform to be built in parts, that is the settings
+   for gpio#1 can be added, and then gpio#2 etc.
+
+   If the added waveform is intended to start after or within the existing
+   waveform then the first pulse should consist solely of a delay.
+*/
+
+int wave_add_serial
+   (unsigned gpio, unsigned baud, unsigned offset, unsigned numChar, char *str);
+/* This function adds a waveform representing serial data to the
+   existing waveform (if any).  The serial data starts offset microseconds
+   from the start of the waveform.
+
+   Returns the new total number of pulses in the current waveform if OK,
+   otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS, or
+   PI_TOO_MANY_PULSES.
+
+   NOTES:
+
+   The serial data is formatted as one start bit, eight data bits, and one
+   stop bit.
+
+   It is legal to add serial data streams with different baud rates to
+   the same waveform.
+*/
+
+int wave_create(void);
+/* This function creates a waveform from the data provided by the prior
+   calls to the wave_add_* functions.  Upon success a positive wave id
+   is returned.
+
+   The data provided by the wave_add_* functions is consumed by this
+   function.
+
+   As many waveforms may be created as there is space available.  The
+   wave id is passed to wave_send_* to specify the waveform to transmit.
+
+   Normal usage would be
+
+   Step 1. wave_clear to clear all waveforms and added data.
+
+   Step 2. wave_add_* calls to supply the waveform data.
+
+   Step 3. wave_create to create the waveform and get a unique id
+
+   Repeat steps 2 and 3 as needed.
+
+   Step 4. wave_send_* with the id of the waveform to transmit.
+
+   A waveform comprises one or more pulses.  Each pulse consists of a
    gpioPulse_t structure.
 
    typedef struct
@@ -539,72 +607,62 @@ int wave_clear(void);
 
    When a waveform is started each pulse is executed in order with the
    specified delay between the pulse and the next.
-*/
 
-int wave_tx_busy(void);
-/* This function checks to see if a waveform is currently being
-   transmitted.
-
-   Returns 1 if a waveform is currently being transmitted, otherwise 0.
+   Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM,
+   PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL.
 */
 
-int wave_tx_stop(void);
-/* This function stops the transmission of the current waveform.
 
-   Returns 0 if OK.
+int wave_delete(unsigned wave_id);
+/* This function deletes all created waveforms with ids greater than or
+   equal to wave_id.
 
-   This function is intended to stop a waveform started with the repeat mode.
+   Wave ids are allocated in order, 0, 1, 2, etc.
+
+   Returns 0 if OK, otherwise PI_BAD_WAVE_ID.
 */
 
 int wave_tx_start(void);
-/* This function transmits the current waveform.  The waveform is
-   sent once.
-
-   Returns the number of DMA control blocks in the waveform if OK,
-   otherwise PI_BAD_WAVE_MODE.
+/* This function is deprecated and should no longer be used.  Use
+   wave_create/wave_send_* instead.
 */
 
 int wave_tx_repeat(void);
-/* This function transmits the current waveform.  The waveform repeats
-   endlessly until wave_tx_stop is called.
+/* This function is deprecated and should no longer be used.  Use
+   wave_create/wave_send_* instead.
+*/
+
+int wave_send_once(unsigned wave_id);
+/* This function transmits the waveform with id wave_id.  The waveform
+   is sent once.
 
    Returns the number of DMA control blocks in the waveform if OK,
-   otherwise PI_BAD_WAVE_MODE.
+   otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
 */
 
-int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses);
-/* This function adds a number of pulses to the current waveform.
+int wave_send_repeat(unsigned wave_id);
+/* This function transmits the waveform with id wave_id.  The waveform
+   cycles until cancelled (either by the sending of a new waveform or
+   by wave_tx_stop).
 
-   Returns the new total number of pulses in the current waveform if OK,
-   otherwise PI_TOO_MANY_PULSES.
+   Returns the number of DMA control blocks in the waveform if OK,
+   otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+*/
 
-   The   pulses are interleaved in time order within the existing waveform
-   (if any).
 
-   Merging allows the waveform to be built in parts, that is the settings
-   for gpio#1 can be added, and then gpio#2 etc.
+int wave_tx_busy(void);
+/* This function checks to see if a waveform is currently being
+   transmitted.
 
-   If the added waveform is intended to start after or within the existing
-   waveform then the first pulse should consist solely of a delay.
+   Returns 1 if a waveform is currently being transmitted, otherwise 0.
 */
 
-int wave_add_serial
-   (unsigned gpio, unsigned baud, unsigned offset, unsigned numChar, char *str);
-/* This function adds a waveform representing serial data to the
-   existing waveform (if any).  The serial data starts offset microseconds
-   from the start of the waveform.
-
-   Returns the new total number of pulses in the current waveform if OK,
-   otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS, or
-   PI_TOO_MANY_PULSES.
-
-   NOTES:
+int wave_tx_stop(void);
+/* This function stops the transmission of the current waveform.
 
-   The serial data is formatted as one start bit, eight data bits, and one
-   stop bit.
+   Returns 0 if OK.
 
-   It is legal to add serial data streams with different baud rates to
-   the same waveform.
+   This function is intended to stop a waveform started with the repeat mode.
 */
 
 int wave_get_micros(void);
@@ -675,7 +733,7 @@ int run_script(unsigned script_id, unsigned numPar, uint32_t *param);
    the script as param 0 to param 9..
 */
 
-int script_status(int script_id, uint32_t *param);
+int script_status(unsigned 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.
 
diff --git a/pigs.c b/pigs.c
index 35c47e4cc2c2223fe94f4a05b450e86e78eefa88..3cce6119694edb40ac870eefe88398b5e6dc0ee7 100644 (file)
--- a/pigs.c
+++ b/pigs.c
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 13+
+This version is for pigpio version 14+
 */
 
 #include <stdio.h>
@@ -50,6 +50,8 @@ the commands available from pigpio.
 char command_buf[8192];
 char response_buf[8192];
 
+#define SOCKET_OPEN_FAILED -1
+
 void fatal(char *fmt, ...)
 {
    char buf[128];
@@ -88,7 +90,7 @@ static int openSocket(void)
 
    err = getaddrinfo(addrStr, portStr, &hints, &res);
 
-   if (err) return -1;
+   if (err) return SOCKET_OPEN_FAILED;
 
    for (rp=res; rp!=NULL; rp=rp->ai_next)
    {
@@ -101,7 +103,7 @@ static int openSocket(void)
 
    freeaddrinfo(res);
 
-   if (rp == NULL) return -1;
+   if (rp == NULL) return SOCKET_OPEN_FAILED;
 
    return sock;
 }
@@ -156,7 +158,7 @@ void print_result(int sock, int rv, cmdCmd_t cmd)
 
             p = (uint32_t *)response_buf;
 
-            for (i=0; i<MAX_SCRIPT_PARAMS; i++)
+            for (i=0; i<PI_MAX_SCRIPT_PARAMS; i++)
             {
                printf(" %d", p[i]);
             }
@@ -176,7 +178,7 @@ void get_extensions(int sock, int command, int res)
          {
             recv(sock,
                  response_buf,
-                 sizeof(uint32_t)*MAX_SCRIPT_PARAMS,
+                 sizeof(uint32_t)*PI_MAX_SCRIPT_PARAMS,
                  MSG_WAITALL);
          }
          break;
@@ -259,38 +261,47 @@ int main(int argc , char *argv[])
    cmdCmd_t cmd;
    uint32_t p[10];
    void *v[10];
-   gpioCtlParse_t ctl;
+   cmdCtlParse_t ctl;
+   cmdScript_t s;
 
-   sock = openSocket(); 
+   sock = openSocket();
 
-   if (sock != -1)
-   {
-      command_buf[0] = 0;
-      l = 0;
-      pp = 0;
+   command_buf[0] = 0;
+   l = 0;
+   pp = 0;
 
-      for (i=1; i<argc; i++)
-      {
-         l += (strlen(argv[i]) + 1);
-         if (l < sizeof(command_buf))
-            {sprintf(command_buf+pp, "%s ", argv[i]); pp=l;}
-      }
+   for (i=1; i<argc; i++)
+   {
+      l += (strlen(argv[i]) + 1);
+      if (l < sizeof(command_buf))
+         {sprintf(command_buf+pp, "%s ", argv[i]); pp=l;}
+   }
 
-      if (pp) {command_buf[--pp] = 0;}
+   if (pp) {command_buf[--pp] = 0;}
 
-      ctl.flags = 0;
-      ctl.eaten = 0;
+   ctl.eaten = 0;
 
-      len = strlen(command_buf);
-      idx = 0;
+   len = strlen(command_buf);
+   idx = 0;
 
-      while ((idx >= 0) && (ctl.eaten < len))
+   while ((idx >= 0) && (ctl.eaten < len))
+   {
+      if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0)
       {
-         if ((idx=cmdParse(command_buf, p, v, &ctl)) >= 0)
-         {
-            command = p[0];
+         command = p[0];
 
-            if (command < PI_CMD_SCRIPT)
+         if (command < PI_CMD_SCRIPT)
+         {
+            if (command == PI_CMD_HELP)
+            {
+               printf(cmdUsage);
+            }
+            else if (command == PI_CMD_PARSE)
+            {
+               cmdParseScript(v[1], &s, 1);
+               if (s.par) free (s.par);
+            }
+            else
             {
                cmd.cmd = command;
                cmd.p1 = p[1];
@@ -300,36 +311,46 @@ int main(int argc , char *argv[])
                {
                   case PI_CMD_WVAS:
                      cmd.p2 = p[4];
-                    break;
+                     break;
 
                   case PI_CMD_PROC:
                      cmd.p2 = 0;
                      break;
                }
 
-               if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+               if (sock != SOCKET_OPEN_FAILED)
                {
-                  put_extensions(sock, command, p, v);
-
-                  if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) ==
+                  if (send(sock, &cmd, sizeof(cmdCmd_t), 0) ==
                      sizeof(cmdCmd_t))
                   {
-                     get_extensions(sock, command, cmd.res);
+                     put_extensions(sock, command, p, v);
 
-                     print_result(sock, cmdInfo[idx].rv, cmd);
+                     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("recv failed, %m");
+                  else fatal("send failed, %m");
                }
-               else fatal("send failed, %m");
+               else fatal("connect failed");
             }
-            else fatal("%s only allowed within a script", cmdInfo[idx].name);
          }
-         else fatal("%s? pigs h for help", cmdStr());
+         else fatal("%s only allowed within a script", cmdInfo[idx].name);
+      }
+      else
+      {
+         if (idx == CMD_UNKNOWN_CMD)
+            fatal("%s? unknown command, pigs h for help", cmdStr());
+         else
+            fatal("%s: bad parameter, pigs h for help", cmdStr());
       }
    }
-   else fatal("connect failed, %m");
 
-   close(sock);
+   if (sock >= 0) close(sock);
 
    return 0;
 }
index dc6e3040c0015c2a87593e14bf7490b61146b855..14465f1ada65af06926d0920fd2e74673dd75832 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name='pigpio',
-      version='1.4',
+      version='1.5',
       author='joan',
       author_email='joan@abyz.co.uk',
       maintainer='joan',
diff --git a/tarball b/tarball
new file mode 100755 (executable)
index 0000000..aab4ff7
--- /dev/null
+++ b/tarball
@@ -0,0 +1,29 @@
+#!/bin/bash
+#
+rm -rf                PIGPIO
+mkdir                 PIGPIO
+#
+cp command.c          PIGPIO
+cp command.h          PIGPIO
+cp Makefile           PIGPIO
+cp MakeRemote         PIGPIO
+cp pig2vcd.c          PIGPIO
+cp pigpio.c           PIGPIO
+cp pigpio.h           PIGPIO
+cp pigpiod.c          PIGPIO
+cp pigpiod_if.c       PIGPIO
+cp pigpiod_if.h       PIGPIO
+cp pigpio.py          PIGPIO
+cp pigs.c             PIGPIO
+cp README             PIGPIO
+cp setup.py           PIGPIO
+cp UNLICENCE          PIGPIO
+cp x_pigpio.c         PIGPIO
+cp x_pigpio.py        PIGPIO
+cp x_pigpiod_if.c     PIGPIO
+cp x_pigs             PIGPIO
+cp x_pipe             PIGPIO
+#
+zip -r pigpio-$1.zip  PIGPIO
+tar cvf pigpio-$1.tar PIGPIO
+
index d884f4d1b272b87c8806905cc2bc68a6c26dc134..c827a7b51e7ed004f53521b4ea44d619c9cfd3d5 100644 (file)
@@ -1,6 +1,13 @@
 /*
 gcc -o x_pigpio x_pigpio.c -lpigpio -lrt -lpthread
 sudo ./x_pigpio
+
+*** WARNING ************************************************
+*                                                          *
+* All the tests make extensive use of gpio 4 (pin P1-7).   *
+* Ensure that either nothing or just a LED is connected to *
+* gpio 4 before running any of the tests.                  *
+************************************************************
 */
 
 #include <stdio.h>
@@ -448,17 +455,17 @@ void t6()
 
    gpioSetAlertFunc(GPIO, t6cbf);
 
-   for (t=0; t<10; t++)
+   for (t=0; t<5; t++)
    {
       time_sleep(0.1);
       p = 10 + (t*10);
       tp += p;
-      gpioTrigger(4, p, 1);
+      gpioTrigger(GPIO, p, 1);
    }
 
    time_sleep(0.2);
 
-   CHECK(6, 1, t6_count, 10, 0, "gpio trigger count");
+   CHECK(6, 1, t6_count, 5, 0, "gpio trigger count");
 
    CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length");
 }
@@ -553,16 +560,16 @@ void t9()
    p1 GPIO
    */
    char *script="\
-   lda0\
-   ldva 0\
-   label 0\
+   lda p0\
+   sta v0\
+   tag 0\
    w p1 1\
-   milli 5\
+   mils 5\
    w p1 0\
-   milli 5\
-   dcr0\
-   lda0\
-   ldpa 9\
+   mils 5\
+   dcr v0\
+   lda v0\
+   sta p9\
    jp 0";
 
    printf("Script store/run/status/stop/delete tests.\n");
index 7b099085934a4b97782a441340e14d4d1d970f26..55a63e3d290ca72b10266dfb28d4c1d39ed2adb7 100755 (executable)
@@ -1,5 +1,12 @@
 #!/usr/bin/env python
 
+#*** WARNING ************************************************
+#*                                                          *
+#* All the tests make extensive use of gpio 4 (pin P1-7).   *
+#* Ensure that either nothing or just a LED is connected to *
+#* gpio 4 before running any of the tests.                  *
+#************************************************************
+
 import time
 import struct
 
@@ -364,6 +371,50 @@ To the lascivious pleasing of a lute.
    c = pigpio.wave_get_max_cbs()
    CHECK(5, 21, c, 25016, 0, "wave get max cbs")
 
+   e = pigpio.wave_clear()
+   CHECK(5, 22, e, 0, 0, "wave clear")
+
+   e = pigpio.wave_add_generic(wf)
+   CHECK(5, 23, e, 4, 0, "pulse, wave add generic")
+
+   w1 = pigpio.wave_create()
+   CHECK(5, 24, w1, 0, 0, "wave create")
+
+   e = pigpio.wave_send_repeat(w1)
+   CHECK(5, 25, e, 9, 0, "wave send repeat")
+
+   oc = t5_count
+   time.sleep(5)
+   c = t5_count - oc
+   CHECK(5, 26, c, 50, 1, "callback")
+
+   e = pigpio.wave_tx_stop()
+   CHECK(5, 27, e, 0, 0, "wave tx stop")
+
+   e = pigpio.wave_add_serial(GPIO, BAUD, 5000000, TEXT)
+   CHECK(5, 28, e, 3405, 0, "wave add serial")
+
+   w2 = pigpio.wave_create()
+   CHECK(5, 29, w2, 1, 0, "wave create")
+
+   e = pigpio.wave_send_once(w2)
+   CHECK(5, 30, e, 6811, 0, "wave send once")
+
+   oc = t5_count
+   time.sleep(3)
+   c = t5_count - oc
+   CHECK(5, 31, c, 0, 0, "callback")
+
+   oc = t5_count
+   while pigpio.wave_tx_busy():
+      time.sleep(0.1)
+   time.sleep(0.1)
+   c = t5_count - oc
+   CHECK(5, 32, c, 1702, 0, "wave tx busy, callback")
+
+   e = pigpio.wave_delete(0)
+   CHECK(5, 33, e, 0, 0, "wave delete")
+
 t6_count=0
 t6_on=0
 t6_on_tick=None
@@ -388,15 +439,15 @@ def t6():
 
    t6cb = pigpio.callback(GPIO, pigpio.EITHER_EDGE, t6cbf)
 
-   for t in range(10):
+   for t in range(5):
       time.sleep(0.1)
       p = 10 + (t*10)
       tp += p;
-      pigpio.gpio_trigger(4, p, 1)
+      pigpio.gpio_trigger(GPIO, p, 1)
 
    time.sleep(0.5)
 
-   CHECK(6, 1, t6_count, 10, 0, "gpio trigger count")
+   CHECK(6, 1, t6_count, 5, 0, "gpio trigger count")
 
    CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length")
 
@@ -480,16 +531,16 @@ def t9():
    # p0 number of loops
    # p1 GPIO
    script="""
-   lda0
-   ldva 0
-   label 0
+   lda p0
+   sta v0
+   tag 0
    w p1 1
-   milli 5
+   mils 5
    w p1 0
-   milli 5
-   dcr0
-   lda0
-   ldpa 9
+   mils 5
+   dcr v0
+   lda v0
+   sta p9
    jp 0"""
 
    t9cb = pigpio.callback(GPIO)
index 9ae322900f4b2f941ee49ae34c3111d4cd40f2f5..787c6d45e6f68f50afbc933d9f39da1825e69c33 100644 (file)
@@ -1,6 +1,13 @@
 /*
 gcc -o x_pigpiod_if x_pigpiod_if.c -lpigpiod_if -lrt -lpthread
 sudo ./x_pigpiod_if
+
+*** WARNING ************************************************
+*                                                          *
+* All the tests make extensive use of gpio 4 (pin P1-7).   *
+* Ensure that either nothing or just a LED is connected to *
+* gpio 4 before running any of the tests.                  *
+************************************************************
 */
 
 #include <stdio.h>
@@ -429,17 +436,17 @@ void t6()
 
    time_sleep(0.2);
 
-   for (t=0; t<10; t++)
+   for (t=0; t<5; t++)
    {
       time_sleep(0.1);
       p = 10 + (t*10);
       tp += p;
-      gpio_trigger(4, p, 1);
+      gpio_trigger(GPIO, p, 1);
    }
 
    time_sleep(0.5);
 
-   CHECK(6, 1, t6_count, 10, 0, "gpio trigger count");
+   CHECK(6, 1, t6_count, 5, 0, "gpio trigger count");
 
    CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length");
 }
@@ -540,16 +547,16 @@ void t9()
    p1 GPIO
    */
    char *script="\
-   lda0\
-   ldva 0\
-   label 0\
+   lda p0\
+   sta v0\
+   tag 0\
    w p1 1\
-   milli 5\
+   mils 5\
    w p1 0\
-   milli 5\
-   dcr0\
-   lda0\
-   ldpa 9\
+   mils 5\
+   dcr v0\
+   lda v0\
+   sta p9\
    jp 0";
 
    callback(GPIO, RISING_EDGE, t9cbf);
diff --git a/x_pigs b/x_pigs
index 82d9124456840d83446f3a1f08d4affdc801778e..9b1bc5680f3641ac25230452c0298b538636e7ab 100755 (executable)
--- a/x_pigs
+++ b/x_pigs
@@ -40,16 +40,16 @@ s=$(pigs bs2 0)
 if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
 
 s=$(pigs h)
-if [[ ${#s} = 2999 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
+if [[ ${#s} = 3315 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
 
 s=$(pigs hwver)
 if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi
 
-s=$(pigs micro 1000)
-if [[ $s = "" ]]; then echo "MICRO ok"; else echo "MICRO fail ($s)"; fi
+s=$(pigs mics 1000)
+if [[ $s = "" ]]; then echo "MICS ok"; else echo "MICS fail ($s)"; fi
 
-s=$(pigs milli 10)
-if [[ $s = "" ]]; then echo "MILLI ok"; else echo "MILLI fail ($s)"; fi
+s=$(pigs mils 10)
+if [[ $s = "" ]]; then echo "MILS ok"; else echo "MILS fail ($s)"; fi
 
 s=$(pigs modes $GPIO 0)
 s=$(pigs modeg $GPIO)
@@ -86,14 +86,14 @@ s=$(pigs pfs $GPIO 800)
 if [[ $s = 800 ]]; then echo "PFS-b ok"; else echo "PFS-b fail ($s)"; fi
 
 s=$(pigs pigpv)
-if [[ $s = 13 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
+if [[ $s = 14 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
 
 s=$(pigs prs $GPIO 255)
 if [[ $s = 250 ]]; then echo "PRG-a ok"; else echo "PRG-a fail ($s)"; fi
 s=$(pigs prg $GPIO)
 if [[ $s = 255 ]]; then echo "PRG-b ok"; else echo "PRG-b fail ($s)"; fi
 
-p=$(pigs proc ldap 0 ldpa 1 ldai 1234 ldpa 0 label 999 milli 1000 jmp 999)
+p=$(pigs proc ld p1 p0 ld p0 1234 tag 999 mils 1000 jmp 999)
 if [[ $p -ge 0 && $p -le 31 ]]
 then echo "PROC($p) ok"
 else echo "PROC($p) fail ($s)"
@@ -186,10 +186,10 @@ fi
 s=$(pigs slrc $GPIO)
 if [[ $s = 0 ]]; then echo "SLR-g ok"; else echo "SLR-g fail ($s)"; fi
 
-t1=$(pigs t)
-t2=$(pigs tick)
-s=$(($t2-$t1))
-if [[ $s -gt 0 && $s -lt 20000 ]]
+t=$(pigs t tick)
+v=(${t// / })
+s=$((v[1]-v[0]))
+if [[ $s -gt 0 && $s -lt 2000 ]]
 then echo "TICK ok"
 else echo "TICK fail($s)"
 fi
diff --git a/x_pipe b/x_pipe
index 16eb20981f411f6899b12e110431b37883e3f112..0dfb5344a39b7a721ed096fe34fe0378410d5a10 100755 (executable)
--- a/x_pipe
+++ b/x_pipe
@@ -46,14 +46,14 @@ if [[ $s = 0 ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
 
 echo "h" >/dev/pigpio
 read -t 1 s </dev/pigout
-if [[ $s = "BC1 v         Clear gpios defined by mask v in bank 1." ]]
+if [[ $s = "BC1 v         Clear gpios specified by mask v in bank 1." ]]
 then echo "HELP-a ok"
 else echo "HELP-a fail ($s)"
 fi
 read -t 1 -N 9000 </dev/pigout # dump rest of help
 echo "help" >/dev/pigpio
 read -t 1 s </dev/pigout
-if [[ $s = "BC1 v         Clear gpios defined by mask v in bank 1." ]]
+if [[ $s = "BC1 v         Clear gpios specified by mask v in bank 1." ]]
 then echo "HELP-b ok"
 else echo "HELP-b fail ($s)"
 fi
@@ -63,13 +63,13 @@ echo "hwver" >/dev/pigpio
 read -t 1 s </dev/pigout
 if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi
 
-echo "micro 1000" >/dev/pigpio
+echo "mics 1000" >/dev/pigpio
 read -t 1 s </dev/pigout
-if [[ $s = 0 ]]; then echo "MICRO ok"; else echo "MICRO fail ($s)"; fi
+if [[ $s = 0 ]]; then echo "MICS ok"; else echo "MICS fail ($s)"; fi
 
-echo "milli 10" >/dev/pigpio
+echo "mils 10" >/dev/pigpio
 read -t 1 s </dev/pigout
-if [[ $s = 0 ]]; then echo "MILLI ok"; else echo "MILLI fail ($s)"; fi
+if [[ $s = 0 ]]; then echo "MILS ok"; else echo "MILS fail ($s)"; fi
 
 echo "modes $GPIO 0" >/dev/pigpio
 read -t 1 s </dev/pigout
@@ -119,7 +119,7 @@ if [[ $s = 800 ]]; then echo "PFS-b ok"; else echo "PFS-b fail ($s)"; fi
 
 echo "pigpv" >/dev/pigpio
 read -t 1 s </dev/pigout
-if [[ $s = 13 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
+if [[ $s = 14 ]]; then echo "PIGPV ok"; else echo "PIGPV fail ($s)"; fi
 
 echo "prs $GPIO 255" >/dev/pigpio
 read -t 1 s </dev/pigout
@@ -128,7 +128,7 @@ echo "prg $GPIO" >/dev/pigpio
 read -t 1 s </dev/pigout
 if [[ $s = 255 ]]; then echo "PRG-b ok"; else echo "PRG-b fail ($s)"; fi
 
-echo "proc ldap 0 ldpa 1 ldai 29 ldpa 0 label 9 milli 1000 jmp 9" >/dev/pigpio
+echo "proc ld p1 p0 ld p0 29 tag 9 mils 1000 jmp 9" >/dev/pigpio
 read -t 1 p </dev/pigout
 if [[ $p -ge 0 && $p -le 31 ]]
 then echo "PROC($p) ok"