V11
authorjoan <joan@abyz.me.uk>
Tue, 21 Jan 2014 19:04:59 +0000 (19:04 +0000)
committerjoan <joan@abyz.me.uk>
Tue, 21 Jan 2014 19:04:59 +0000 (19:04 +0000)
13 files changed:
MakeRemote
Makefile
README
command.c
command.h
pigpio.c
pigpio.h
pigpio.py
pigpiod.c
pigpiod_if.c
pigpiod_if.h
pigs.c
setup.py

index e0f6361ab8337102716f9e3de043ff55345edda7..c27fc649d3079ff99e455a31d19fdf0b65411d89 100644 (file)
@@ -5,11 +5,11 @@ SIZE    = size
 
 CFLAGS = -O3 -Wall
 
-ALL     = libpigpiod_if.a pigs
+ALL     = libpigpiod_if.a pigs pigpio.py setup.py
 
 all:   $(ALL)
 
-pigs:          command.o
+pigs:          command.o pigs.o
        $(CC) -o pigs pigs.c command.c
 
 clean:
@@ -41,7 +41,7 @@ $(LIB):       $(OBJ)
 # generated using gcc -MM *.c
 
 command.o: command.c pigpio.h command.h
-pigpiod.o: pigpiod.c pigpio.h command.h
-pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h
+pigpiod.o: pigpiod.c pigpio.h
+pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h command.h
 pigs.o: pigs.c pigpio.h command.h
 
index 6ce0b3dbedd49da572e3b677436446126b1e84bb..9b1e561e3236a852baa4cb13dac37688e5ca4a42 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -72,7 +72,7 @@ checklib.o: checklib.c pigpio.h
 command.o: command.c pigpio.h command.h
 pig2vcd.o: pig2vcd.c pigpio.h
 pigpio.o: pigpio.c pigpio.h command.h
-pigpiod.o: pigpiod.c pigpio.h command.h
+pigpiod.o: pigpiod.c pigpio.h
 pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h
 pigs.o: pigs.c pigpio.h command.h
 
diff --git a/README b/README
index ba15cb60fee2c2ef189b62902571e3de1c965eed..8737d361931f4230464509753aaea91b5a9fce1d 100644 (file)
--- a/README
+++ b/README
@@ -31,8 +31,7 @@ EXAMPLE CODE
 checklib.c, pig2vcd.c, and pigpiod.c
 show examples of interfacing with the pigpio library.
 
-pigs.c, pigpio.py, and test_pigpiod_if.c
-show examples of interfacing with the pigpiod daemon.
+pigs.c and pigpio.py show examples of interfacing with the pigpiod daemon.
 
 DAEMON
 
index 80b380136ddddc1ba6e748948007e434c26c0e88..a128a9dce28b971e22460b09d7a2ef5cdc18ff54 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 10+
+This version is for pigpio version 11+
 */
 
 #include <stdio.h>
@@ -38,79 +38,144 @@ This version is for pigpio version 10+
 #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
+*/
+
+/* 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 PROG  %s
+*/
+
 cmdInfo_t cmdInfo[]=
 {
-   {PI_CMD_BR1,   "BR1",   1, 3},
-   {PI_CMD_BR2,   "BR2",   1, 3},
-   {PI_CMD_BC1,   "BC1",   7, 1},
-   {PI_CMD_BC2,   "BC2",   7, 1},
-   {PI_CMD_BS1,   "BS1",   7, 1},
-   {PI_CMD_BS2,   "BS2",   7, 1},
-   {PI_CMD_HWVER, "HWVER", 1, 4},
-   {PI_CMD_MODES, "MODES", 8, 0},
-   {PI_CMD_MODES, "M",     8, 0},
-   {PI_CMD_MODEG, "MODEG", 2, 2},
-   {PI_CMD_MODEG, "MG"   , 2, 2},
-   {PI_CMD_NO,    "NO",    1, 2},
-   {PI_CMD_NB,    "NB",    4, 0},
-   {PI_CMD_NP,    "NP",    2, 0},
-   {PI_CMD_NC,    "NC",    2, 0},
-   {PI_CMD_PWM,   "PWM",   3, 0},
-   {PI_CMD_PWM,   "P",     3, 0},
-   {PI_CMD_PFS,   "PFS",   3, 2},
-   {PI_CMD_PFG,   "PFG",   2, 2},
-   {PI_CMD_PRS,   "PRS",   3, 2},
-   {PI_CMD_PRG,   "PRG",   2, 2},
-   {PI_CMD_PRRG,  "PRRG",  2, 2},
-   {PI_CMD_PUD,   "PUD",   9, 0},
-   {PI_CMD_READ,  "READ",  2, 2},
-   {PI_CMD_READ,  "R",     2, 2},
-   {PI_CMD_SERVO, "SERVO", 3, 0},
-   {PI_CMD_SERVO, "S",     3, 0},
-   {PI_CMD_WRITE, "WRITE", 3, 0},
-   {PI_CMD_WRITE, "W",     3, 0},
-   {PI_CMD_WDOG,  "WDOG",  3, 0},
-   {PI_CMD_TICK,  "TICK",  1, 4},
-   {PI_CMD_TICK,  "T",     1, 4},
-   {PI_CMD_HELP,  "HELP",  6, 5},
-   {PI_CMD_HELP,  "H",     6, 5},
-   {PI_CMD_PIGPV, "PIGPV", 1, 4},
+   /* num         str   vfyt retv ext */
+
+   {PI_CMD_BC1,   "BC1",   7, 1,  0},
+   {PI_CMD_BC2,   "BC2",   7, 1,  0},
+   {PI_CMD_BR1,   "BR1",   1, 3,  0},
+   {PI_CMD_BR2,   "BR2",   1, 3,  0},
+   {PI_CMD_BS1,   "BS1",   7, 1,  0},
+   {PI_CMD_BS2,   "BS2",   7, 1,  0},
+   {PI_CMD_HELP,  "H",     6, 5,  0},
+   {PI_CMD_HELP,  "HELP",  6, 5,  0},
+   {PI_CMD_HWVER, "HWVER", 1, 4,  0},
+   {PI_CMD_MODEG, "MG"   , 2, 2,  0},
+   {PI_CMD_MODEG, "MODEG", 2, 2,  0},
+   {PI_CMD_MODES, "M",     8, 0,  0},
+   {PI_CMD_MODES, "MODES", 8, 0,  0},
+   {PI_CMD_NB,    "NB",    4, 0,  0},
+   {PI_CMD_NC,    "NC",    2, 0,  0},
+   {PI_CMD_NO,    "NO",    1, 2,  0},
+   {PI_CMD_NP,    "NP",    2, 0,  0},
+   {PI_CMD_PFG,   "PFG",   2, 2,  0},
+   {PI_CMD_PFS,   "PFS",   3, 2,  0},
+   {PI_CMD_PIGPV, "PIGPV", 1, 4,  0},
+   {PI_CMD_PRG,   "PRG",   2, 2,  0},
+   {PI_CMD_PROC,  "PROC", 10, 2,  1},
+   {PI_CMD_PROCD, "PROCD", 2, 2,  0},
+   {PI_CMD_PROCR, "PROCR", 2, 2,  0},
+   {PI_CMD_PROCS, "PROCS", 2, 2,  0},
+   {PI_CMD_PRRG,  "PRRG",  2, 2,  0},
+   {PI_CMD_PRS,   "PRS",   3, 2,  0},
+   {PI_CMD_PUD,   "PUD",   9, 0,  0},
+   {PI_CMD_PWM,   "P",     3, 0,  0},
+   {PI_CMD_PWM,   "PWM",   3, 0,  0},
+   {PI_CMD_READ,  "R",     2, 2,  0},
+   {PI_CMD_READ,  "READ",  2, 2,  0},
+   {PI_CMD_SERVO, "S",     3, 0,  0},
+   {PI_CMD_SERVO, "SERVO", 3, 0,  0},
+   {PI_CMD_WDOG,  "WDOG",  3, 0,  0},
+   {PI_CMD_WRITE, "W",     3, 0,  0},
+   {PI_CMD_WRITE, "WRITE", 3, 0,  0},
+   {PI_CMD_TICK,  "T",     1, 4,  0},
+   {PI_CMD_TICK,  "TICK",  1, 4,  0},
+   {PI_CMD_TRIG,  "TRIG",  5, 0,  1},
+   {PI_CMD_WVAS,  "WVAS", 11, 2,  3},
+   {PI_CMD_WVBSY, "WVBSY", 1, 2,  0},
+   {PI_CMD_WVCLR, "WVCLR", 1, 2,  0},
+   {PI_CMD_WVGO,  "WVGO" , 1, 2,  0},
+   {PI_CMD_WVGOR, "WVGOR", 1, 2,  0},
+   {PI_CMD_WVHLT, "WVHLT", 1, 2,  0},
+   {PI_CMD_WVSC,  "WVSC",  2, 2,  0},
+   {PI_CMD_WVSM,  "WVSM",  2, 2,  0},
+   {PI_CMD_WVSP,  "WVSP",  2, 2,  0},
 };
 
 char * cmdUsage = "\
-BR1          read gpios bank 1\n\
-BR2          read gpios bank 2\n\
 BC1 x        clear gpios in bank 1\n\
 BC2 x        clear gpios in bank 2\n\
+BR1          read gpios bank 1\n\
+BR2          read gpios bank 2\n\
 BS1 x        set gpios in bank 1\n\
 BS2 x        set gpios in bank 2\n\
+H            displays command help\n\
+HELP         displays command help\n\
 HWVER        return hardware version\n\
-MODES/M g m  set gpio mode\n\
-MODEG/MG g   get gpio mode\n\
-NO           request notification handle\n\
+M g m        set gpio mode\n\
+MG g         get gpio mode\n\
+MODEG g      get gpio mode\n\
+MODES g m    set gpio mode\n\
 NB h x       start notification\n\
-NP h         pause notification\n\
 NC h         close notification\n\
-PWM/P u d    set PWM value for gpio\n\
-PFS u d      set PWM frequency for gpio\n\
+NO           request notification handle\n\
+NP h         pause notification\n\
+P u d        set PWM value for gpio\n\
 PFG u        get PWM frequency for gpio\n\
+PFS u d      set PWM frequency for gpio\n\
 PIGPV        return pigpio version\n\
-PRS u d      set PWM range for gpio\n\
 PRG u        get PWM range for gpio\n\
+PROC t       validate and store script\n\
+PROCD s      delete script\n\
+PROCR s      run script\n\
+PROCS s      stop script\n\
 PRRG u       get PWM real range for gpio\n\
+PRS u d      set PWM range for gpio\n\
 PUD g p      set gpio pull up/down\n\
-READ/R g     read gpio\n\
-SERVO/S u d  set servo value for gpio\n\
-WRITE/W g d  write value to gpio\n\
+PWM u d      set PWM value for gpio\n\
+R g          read gpio\n\
+READ g       read gpio\n\
+S u d        set servo value for gpio\n\
+SERVO u d    set servo value for gpio\n\
+T            return current tick\n\
+TICK         return current tick\n\
+TRIG u pl l  trigger level l for pl micros on gpio\n\
+W g l        write level to gpio\n\
 WDOG u d     set watchdog on gpio\n\
-TICK/T       return current tick\n\
-HELP/H       displays command help\n\
+WRITE g l    write level to gpio\n\
+WVAS u b t   wave add serial data\n\
+WVBSY        check if wave busy\n\
+WVCLR        wave clear\n\
+WVGO         wave transmit\n\
+WVGOR        wave transmit repeat\n\
+WVHLT        wave stop\n\
+WVSC ws      wave get cbs stats\n\
+WVSM ws      wave get micros stats\n\
+WVSP ws      wave get pulses stats\n\
 \n\
+b = baud rate\n\
 d = decimal value\n\
 g = gpio (0-53)\n\
 h = handle (0-31)\n\
+l = level (0-1)\n\
 m = mode (RW540123)\n\
 p = pud (ODU)\n\
+pl = pulse length (0-100)\n\
+s = script id\n\
+t = text\n\
 u = user gpio (0-31)\n\
 x = hex value\n\
 ";
@@ -130,7 +195,7 @@ static errInfo_t errInfo[]=
    {PI_BAD_LEVEL        , "level not 0-1"},
    {PI_BAD_PUD          , "pud not 0-2"},
    {PI_BAD_PULSEWIDTH   , "pulsewidth not 0 or 500-2500"},
-   {PI_BAD_DUTYCYCLE    , "dutycycle not 0-255"},
+   {PI_BAD_DUTYCYCLE    , "dutycycle outside set range"},
    {PI_BAD_TIMER        , "timer not 0-9"},
    {PI_BAD_MS           , "ms not 10-60000"},
    {PI_BAD_TIMETYPE     , "timetype not 0-1"},
@@ -165,6 +230,13 @@ static errInfo_t errInfo[]=
    {PI_BAD_SERIAL_BUF   , "bad (null) serial buf parameter"}, 
    {PI_NOT_PERMITTED    , "no permission to update gpio"},
    {PI_SOME_PERMITTED   , "no permission to update one or more gpios"},
+   {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_SCRIPT       , "invalid script"},
+   {PI_BAD_SCRIPT_ID    , "unknown script id"},
+   {PI_BAD_SER_OFFSET   , "add serial data offset > 30 minute"},
 };
 
 static char * fmtMdeStr="RW540123";
@@ -181,11 +253,11 @@ static int cmdMatch(char * str)
    return -1;
 }
 
-int cmdParse(char * buf, cmdCmd_t * cmd)
+int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext)
 {
    char str[8];
    int f, valid, idx, val;
-   char * ptr;
+   char *ptr;
    char c, t;
 
    sscanf(buf, " %7s", str);
@@ -204,36 +276,57 @@ int cmdParse(char * buf, cmdCmd_t * cmd)
 
    switch (cmdInfo[idx].vt)
    {
-      case 1: /* BR1 BR2 HWVER PIGPV NO TICK */
+      case 1: /* BR1   BR2   HWVER NO    PIGPV TICK  WVBSY WVCLR WVGO WVGOR
+                 WVHLT
+              */
          f = sscanf(buf, " %7s %c", str, &t);
          if (f == 1) valid = 1;
          break;
 
-      case 2: /* MODEG READ NC NP PFG PRG PRRG */
+      case 2: /* MODEG NC    NP    PFG   PRG   PROCD PROCR PROCS PRRG  READ
+                 WVSC  WVSM  WVSP
+              */
          f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t);
          if (f == 2) valid = 1;
          break;
-   
-      case 3: /* WRITE PWM PRS PFS SERVO WDOG */
+
+      case 3: /* PFS   PRS   PWM   SERVO WDOG  WRITE
+              */
          f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t);
          if (f == 3) valid = 1;
          break;
-   
-      case 4: /* NB */
+
+      case 4: /* NB
+              */
          f = sscanf(buf, " %7s %d %x %c", str, &cmd->p1, &cmd->p2, &t);
          if (f == 3) valid = 1;
          break;
-   
-      case 6: /* HELP */
+
+      case 5: /* TRIG
+              */
+         f = sscanf(buf, " %7s %d %d %d %c",
+            str, &cmd->p1, &cmd->p2, &ext[0].data, &t);
+         if (f == 4)
+         {
+            ext[0].n = sizeof(unsigned);
+            ext[0].ptr = &ext[0].data;
+            valid = 1;
+         }
+         break;
+
+      case 6: /* HELP
+              */
          valid = 1;
          break;
-   
-      case 7: /* BC1 BC2 BS1 BS2 */
+
+      case 7: /* BC1   BC2   BS1   BS2
+              */
          f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t);
          if (f == 2) valid = 1;
          break;
-   
-      case 8: /* MODES */
+
+      case 8: /* MODES
+              */
          f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t);
          if (f == 3)
          {
@@ -248,7 +341,8 @@ int cmdParse(char * buf, cmdCmd_t * cmd)
          }
          break;
 
-      case 9: /* PUD */
+      case 9: /* PUD
+              */
          f = sscanf(buf, " %7s %d %c %c", str, &cmd->p1, &c, &t);
          if (f == 3)
          {
@@ -262,28 +356,43 @@ int cmdParse(char * buf, cmdCmd_t * cmd)
             }
          }
          break;
+
+      case 10: /* PROC
+               */
+         if (argc == 3)
+         {
+            cmd->p1 = strlen(argv[2]);
+            ext[0].n = cmd->p1;
+            ext[0].ptr = argv[2];
+            valid = 1;
+         }
+         break;
+
+      case 11: /* WVAS
+               */
+         if (argc == 6)
+         {
+            f = sscanf(buf, " %7s %d %d %d ",
+               str, &cmd->p1, &ext[0].data, &ext[1].data);
+            if (f == 4)
+            {
+               ext[0].n = sizeof(unsigned);
+               ext[0].ptr = &ext[0].data;
+               ext[1].n = sizeof(unsigned);
+               ext[1].ptr = &ext[1].data;
+               cmd->p2 = strlen(argv[5]);
+               ext[2].n = cmd->p2;
+               ext[2].ptr = argv[5];
+               valid = 1;
+            }
+         }
+         break;
    }
 
    if (valid) return idx;
    else       return -1;
 }
 
-void cmdFatal(char *fmt, ...)
-{
-   char buf[128];
-   va_list ap;
-
-   va_start(ap, fmt);
-   vsnprintf(buf, sizeof(buf), fmt, ap);
-   va_end(ap);
-
-   fprintf(stderr, "%s\n", buf);
-
-   fflush(stderr);
-
-   exit(EXIT_FAILURE);
-}
-
 char * cmdErrStr(int error)
 {
    int i;
index 6ace8c725705ecb364d05999e4f3dbd4436fc21d..bdffefb7394c24b19897e60d0dd2cfad945f3c56 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 7+
+This version is for pigpio version 11+
 */
 
 #ifndef COMMAND_H
@@ -43,16 +43,17 @@ typedef struct
    char * name; /* command name              */
    int    vt;   /* command verification type */
    int    rv;   /* command return value type */
+   int    ext;  /* command has extensions    */
 } cmdInfo_t;
 
 extern cmdInfo_t cmdInfo[];
 
 extern char * cmdUsage;
 
-int    cmdParse(char * buf, cmdCmd_t * cmd);
+int cmdParse
+   (char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t * ext);
 
 char * cmdErrStr(int error);
 
-void   cmdFatal(char *fmt, ...);
-
 #endif
+
index 510b45abcfe6d8cbd0c437ff68a9631de31d1134..2c378178966e2291547ca008064ba1e288ed6c1d 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 10 */
+/* pigpio version 11 */
 
 #include <stdio.h>
 #include <string.h>
@@ -752,7 +752,7 @@ static int wfcur=0;
 
 static wfStats_t wfStats=
 {
-   0, 0, -1,
+   0, 0, PI_WAVE_MAX_MICROS,
    0, 0, PI_WAVE_MAX_PULSES,
    0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE)
 };
@@ -765,7 +765,7 @@ static volatile uint32_t notifyBits   = 0;
 
 static volatile int DMAstarted = 0;
 
-static int      libInitialised   = 0;
+static int      libInitialised = 0;
 
 static int pthAlertRunning  = 0;
 static int pthFifoRunning   = 0;
@@ -881,7 +881,7 @@ static uint32_t myGpioDelay(uint32_t micros)
 
    start = systReg[SYST_CLO];
 
-   if (micros < 100) while ((systReg[SYST_CLO] - start) <= micros) ;
+   if (micros < 101) while ((systReg[SYST_CLO] - start) <= micros) ;
 
    else myGpioSleep(micros/MILLION, micros%MILLION);
 
@@ -977,63 +977,130 @@ static uint32_t myGetTick(int pos)
 
 /* ----------------------------------------------------------------------- */
 
-static void myDoCommand(cmdCmd_t * cmd)
+static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
 {
-   int p1, p2, res;
-   uint32_t mask;
+   int p1, p2, res, i;
+   uint32_t mask, tmp;
+   gpioPulse_t *pulse;
+   int masked;
 
    p1  = cmd->p1;
    p2  = cmd->p2;
-
-   res = 0;
+   res = cmd->res;
 
    switch (cmd->cmd)
    {
-      case PI_CMD_MODES:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetMode(p1, p2);
-         else
+      case PI_CMD_BC1:
+         mask = gpioMask;
+
+         res = gpioWrite_Bits_0_31_Clear(p1&mask);
+
+         if ((mask | p1) != mask)
          {
-            PERM_ERROR("gpioSetMode: gpio %d, no permission to update", p1);
-            res = PI_NOT_PERMITTED;
+            PERM_ERROR(
+               "gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
          }
          break;
 
-      case PI_CMD_MODEG:
-         res = gpioGetMode(p1);
+      case PI_CMD_BC2:
+         mask = gpioMask>>32;
+
+         res = gpioWrite_Bits_32_53_Clear(p1&mask);
+
+         if ((mask | p1) != mask)
+         {
+            PERM_ERROR(
+               "gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
+         }
          break;
 
-      case PI_CMD_PUD:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPullUpDown(p1, p2);
-         else
+      case PI_CMD_BR1: res = gpioRead_Bits_0_31(); break;
+
+      case PI_CMD_BR2: res = gpioRead_Bits_32_53(); break;
+
+      case PI_CMD_BS1:
+         mask = gpioMask;
+
+         res = gpioWrite_Bits_0_31_Set(p1&mask);
+
+         if ((mask | p1) != mask)
          {
             PERM_ERROR(
-               "gpioSetPullUpDown: gpio %d, no permission to update", p1);
-            res = PI_NOT_PERMITTED;
+               "gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
          }
          break;
 
-      case PI_CMD_READ:
-         res = gpioRead(p1);
+      case PI_CMD_BS2:
+         mask = gpioMask>>32;
+
+         res = gpioWrite_Bits_32_53_Set(p1&mask);
+
+         if ((mask | p1) != mask)
+         {
+            PERM_ERROR(
+               "gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
+         }
          break;
 
-      case PI_CMD_WRITE:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioWrite(p1, p2);
+      case PI_CMD_HELP: break;
+
+      case PI_CMD_HWVER: res = gpioHardwareRevision(); break;
+
+      case PI_CMD_MODEG: res = gpioGetMode(p1); break;
+
+      case PI_CMD_MODES:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetMode(p1, p2);
          else
          {
-            PERM_ERROR("gpioWrite: gpio %d, no permission to update", p1);
+            PERM_ERROR("gpioSetMode: gpio %d, no permission to update", p1);
             res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_PWM:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioPWM(p1, p2);
+      case PI_CMD_NB: res = gpioNotifyBegin(p1, p2); break;
+
+      case PI_CMD_NC: res = gpioNotifyClose(p1); break;
+
+      case PI_CMD_NO: res = gpioNotifyOpen();  break;
+
+      case PI_CMD_NP: res = gpioNotifyPause(p1); break;
+
+      case PI_CMD_PFG: res = gpioGetPWMfrequency(p1); break;
+
+      case PI_CMD_PFS:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMfrequency(p1, p2);
          else
          {
-            PERM_ERROR("gpioPWM: gpio %d, no permission to update", p1);
+            PERM_ERROR(
+               "gpioSetPWMfrequency: gpio %d, no permission to update", p1);
             res = PI_NOT_PERMITTED;
          }
          break;
 
+      case PI_CMD_PIGPV: res = gpioVersion(); break;
+
+      case PI_CMD_PRG: res = gpioGetPWMrange(p1); break;
+
+      case PI_CMD_PROC:
+         res = gpioStoreScript(ext[0].ptr);
+         break;
+
+      case PI_CMD_PROCD: res = gpioDeleteScript(p1); break;
+
+      case PI_CMD_PROCR: res = gpioRunScript(p1); break;
+
+      case PI_CMD_PROCS: res = gpioStopScript(p1); break;
+
+      case PI_CMD_PRRG: res = gpioGetPWMrealRange(p1); break;
+
       case PI_CMD_PRS:
          if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMrange(p1, p2);
          else
@@ -1044,139 +1111,148 @@ static void myDoCommand(cmdCmd_t * cmd)
          }
          break;
 
-      case PI_CMD_PFS:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMfrequency(p1, p2);
+      case PI_CMD_PUD:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPullUpDown(p1, p2);
          else
          {
             PERM_ERROR(
-               "gpioSetPWMfrequency: gpio %d, no permission to update", p1);
+               "gpioSetPullUpDown: gpio %d, no permission to update", p1);
             res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_SERVO:
-         if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
+      case PI_CMD_PWM:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioPWM(p1, p2);
          else
          {
-            PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
+            PERM_ERROR("gpioPWM: gpio %d, no permission to update", p1);
             res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_WDOG:
-         res = gpioSetWatchdog(p1, p2);
-         break;
-
-      case PI_CMD_BR1:
-         res = gpioRead_Bits_0_31();
-         break;
-
-      case PI_CMD_BR2:
-         res = gpioRead_Bits_32_53();
-         break;
+      case PI_CMD_READ: res = gpioRead(p1); break;
 
-      case PI_CMD_BC1:
-         mask = gpioMask;
+      case PI_CMD_WDOG: res = gpioSetWatchdog(p1, p2); break;
 
-         res = gpioWrite_Bits_0_31_Clear(p1&mask);
-
-         if ((mask | p1) != mask)
+      case PI_CMD_WRITE:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioWrite(p1, p2);
+         else
          {
-            PERM_ERROR(
-               "gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
-               p1, mask);
-            res = PI_SOME_PERMITTED;
+            PERM_ERROR("gpioWrite: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_BC2:
-         mask = gpioMask>>32;
-
-         res = gpioWrite_Bits_32_53_Clear(p1&mask);
-
-         if ((mask | p1) != mask)
+      case PI_CMD_SERVO:
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
+         else
          {
-            PERM_ERROR(
-               "gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
-               p1, mask);
-            res = PI_SOME_PERMITTED;
+            PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_BS1:
-         mask = gpioMask;
-
-         res = gpioWrite_Bits_0_31_Set(p1&mask);
+      case PI_CMD_TICK: res = gpioTick(); break;
 
-         if ((mask | p1) != mask)
+      case PI_CMD_TRIG:
+         if (gpioMask & (uint64_t)(1<<p1))
+            res = gpioTrigger(p1, p2, *(int *) (ext[0].ptr));
+         else
          {
-            PERM_ERROR(
-               "gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
-               p1, mask);
-            res = PI_SOME_PERMITTED;
+            PERM_ERROR("gpioTrigger: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
          }
          break;
 
-      case PI_CMD_BS2:
-         mask = gpioMask>>32;
+      case PI_CMD_WVAG:
 
-         res = gpioWrite_Bits_32_53_Set(p1&mask);
+         /* need to mask off any non permitted gpios */
 
-         if ((mask | p1) != mask)
+         mask = gpioMask;
+         pulse = ext[0].ptr;
+         masked = 0;
+
+         for (i=0; i<p1; i++)
          {
-            PERM_ERROR(
-               "gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
-               p1, mask);
-            res = PI_SOME_PERMITTED;
+            tmp = pulse[i].gpioOn & mask;
+            if (tmp != pulse[i].gpioOn)
+            {
+               pulse[i].gpioOn = tmp;
+               masked = 1;
+            }
+
+            tmp = pulse[i].gpioOff & mask;
+            if (tmp != pulse[i].gpioOff)
+            {
+               pulse[i].gpioOff = tmp;
+               masked = 1;
+            }
          }
-         break;
 
-      case PI_CMD_TICK:
-         res = gpioTick();
-         break;
+         res = gpioWaveAddGeneric(p1, pulse);
 
-      case PI_CMD_HWVER:
-         res = gpioHardwareRevision();
-         break;
+         /* report permission error unless another error occurred */
+         if (masked && (res >= 0)) res = PI_SOME_PERMITTED;
 
-      case PI_CMD_PRG:
-         res = gpioGetPWMrange(p1);
          break;
 
-      case PI_CMD_PFG:
-         res = gpioGetPWMfrequency(p1);
+      case PI_CMD_WVAS:
+         if (gpioMask & (uint64_t)(1<<p1))
+            res = gpioWaveAddSerial
+               (p1,
+                *(int *)(ext[0].ptr),
+                *(int *)(ext[1].ptr),
+                p2,
+                ext[2].ptr);
+         else
+         {
+            PERM_ERROR
+               ("gpioWaveAddSerial: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
-      case PI_CMD_PRRG:
-         res = gpioGetPWMrealRange(p1);
-         break;
+      case PI_CMD_WVBSY: res = gpioWaveTxBusy(); break;
 
-      case PI_CMD_NO:
-         res = gpioNotifyOpen();
-         break;
+      case PI_CMD_WVCLR: res = gpioWaveClear(); break;
 
-      case PI_CMD_NB:
-         res = gpioNotifyBegin(p1, p2);
-         break;
+      case PI_CMD_WVGO:  res = gpioWaveTxStart(PI_WAVE_MODE_ONE_SHOT); break;
 
-      case PI_CMD_NP:
-         res = gpioNotifyPause(p1);
-         break;
+      case PI_CMD_WVGOR: res = gpioWaveTxStart(PI_WAVE_MODE_REPEAT); break;
 
-      case PI_CMD_NC:
-         res = gpioNotifyClose(p1);
-         break;
+      case PI_CMD_WVHLT: res = gpioWaveTxStop(); break;
 
-      case PI_CMD_HELP:
+      case PI_CMD_WVSC:
+         switch(p1)
+         {
+            case 0: res = gpioWaveGetCbs();     break;
+            case 1: res = gpioWaveGetHighCbs(); break;
+            case 2: res = gpioWaveGetMaxCbs();  break;
+            default: res = -9999;
+         }
          break;
 
-      case PI_CMD_PIGPV:
-         res = gpioVersion();
+      case PI_CMD_WVSM:
+         switch(p1)
+         {
+            case 0: res = gpioWaveGetMicros();     break;
+            case 1: res = gpioWaveGetHighMicros(); break;
+            case 2: res = gpioWaveGetMaxMicros();  break;
+            default: res = -9999;
+         }
          break;
 
-      }
-
-      cmd->res = res;
+      case PI_CMD_WVSP:
+         switch(p1)
+         {
+            case 0: res = gpioWaveGetPulses();     break;
+            case 1: res = gpioWaveGetHighPulses(); break;
+            case 2: res = gpioWaveGetMaxPulses();  break;
+            default: res = -9999;
+         }
+         break;
+   }
+   cmd->res = res;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -2545,9 +2621,10 @@ static void * pthTimerTick(void *x)
 
 static void * pthFifoThread(void *x)
 {
-   char inBuf[128];
+   char inBuf[256];
    int idx, flags;
    cmdCmd_t cmd;
+   gpioExtent_t ext[3];
 
    myCreatePipe(PI_INPFIFO, 0662);
 
@@ -2569,9 +2646,9 @@ static void * pthFifoThread(void *x)
       if (fgets(inBuf, sizeof(inBuf), inpFifo) == NULL)
          SOFT_ERROR((void*)PI_INIT_FAILED, "fifo fgets failed (%m)");
 
-      if ((idx=cmdParse(inBuf, &cmd)) >= 0)
+      if ((idx=cmdParse(inBuf, &cmd, 0, NULL, ext)) >= 0)
       {
-         myDoCommand(&cmd);
+         myDoCommand(&cmd, NULL);
 
          switch (cmdInfo[idx].rv)
          {
@@ -2611,24 +2688,150 @@ static void * pthFifoThread(void *x)
 
 /* ----------------------------------------------------------------------- */
 
-static void * pthSocketThreadHandler(void *fdC)
+static void *pthSocketThreadHandler(void *fdC)
 {
    int sock = *(int*)fdC;
    cmdCmd_t cmd;
-   
+   unsigned bytes;
+   char *memPtr;
+   gpioExtent_t ext[3];
+   unsigned tmp;
+
    free(fdC);
 
    while(1)
    {
-      if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+      if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) == sizeof(cmdCmd_t))
       {
-         if (cmd.cmd != PI_CMD_NOIB)
+         if (cmd.cmd == PI_CMD_NOIB)
          {
-            myDoCommand(&cmd);
+            cmd.res = gpioNotifyOpenInBand(sock);
+         }
+         else if (cmd.cmd == PI_CMD_WVAG)
+         {
+            /*
+            p1=numPulses
+            p2=0
+            ## extension ##
+            gpioPulse_t[] pulses
+            */
+
+            bytes = cmd.p1 * sizeof(gpioPulse_t);
+
+            memPtr = malloc(bytes);
+            if (memPtr)
+            {
+               if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
+               {
+                  ext[0].n = bytes;
+                  ext[0].ptr = memPtr;
+                  myDoCommand(&cmd, ext);
+                  free(memPtr);
+               }
+               else
+               {
+                  free(memPtr);
+                  break;
+               }
+            }
+            else break;
+
+         }
+         else if (cmd.cmd == PI_CMD_WVAS)
+         {
+            /*
+            p1=user_gpio
+            p2=numChar
+            ## extension ##
+            unsigned baud
+            unsigned offset
+            char[] str
+            */
+
+            bytes = sizeof(unsigned) + sizeof(unsigned) + cmd.p2;
+
+            memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
+
+            if (memPtr)
+            {
+               if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
+               {
+                  ext[0].n = sizeof(unsigned);
+                  ext[0].ptr = memPtr;
+                  ext[1].n = sizeof(unsigned);
+                  ext[1].ptr = memPtr + sizeof(unsigned);
+                  ext[2].n = cmd.p2;
+                  ext[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned);
+                  memPtr[bytes] = 0; /* may be duplicate terminator */
+                  myDoCommand(&cmd, ext);
+                  free(memPtr);
+               }
+               else
+               {
+                  free(memPtr);
+                  break;
+               }
+            }
+            else break;
+
+         }
+         else if (cmd.cmd == PI_CMD_PROC)
+         {
+            /*
+            p1=script length
+            p2=0
+            ## extension ##
+            char[] script
+            */
+
+            bytes = cmd.p1;
+
+            memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
+            if (memPtr)
+            {
+               if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
+               {
+                  ext[0].n = bytes;
+                  ext[0].ptr = memPtr;
+                  memPtr[bytes] = 0; /* may be duplicate terminator */
+                  myDoCommand(&cmd, ext);
+                  free(memPtr);
+               }
+               else
+               {
+                  free(memPtr);
+                  break;
+               }
+            }
+            else break;
+
          }
          else
          {
-            cmd.res = gpioNotifyOpenInBand(sock);
+            switch (cmd.cmd)
+            {
+               case PI_CMD_TRIG:
+                  /*
+                  p1=user_gpio
+                  p2=pulseLen
+                  ## extension ##
+                  unsigned level
+                  */
+                  ext[0].n = 4;
+                  ext[0].ptr = &tmp;
+
+                  if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) !=
+                     sizeof(unsigned))
+                  {
+                     close(sock);
+                     return 0;
+                  }
+                  break;
+
+               default:
+                  break;
+            }
+            myDoCommand(&cmd, ext);
          }
 
          write(sock, &cmd, sizeof(cmdCmd_t));
@@ -2647,10 +2850,8 @@ static void * pthSocketThreadHandler(void *fdC)
 static void * pthSocketThread(void *x)
 {
    int fdC, c, *sock;
-   struct sockaddr_in server, client;
+   struct sockaddr_in client;
    pthread_attr_t attr;
-   char * portStr;
-   unsigned port;
  
    if (pthread_attr_init(&attr))
       SOFT_ERROR((void*)PI_INIT_FAILED,
@@ -2664,21 +2865,8 @@ static void * pthSocketThread(void *x)
       SOFT_ERROR((void*)PI_INIT_FAILED,
          "pthread_attr_setdetachstate failed (%m)");
 
-   fdSock = socket(AF_INET , SOCK_STREAM , 0);
-
-   if (fdSock == -1)
-      SOFT_ERROR((void*)PI_INIT_FAILED, "socket failed (%m)");
-   
-   portStr = getenv(PI_ENVPORT);
-
-   if (portStr) port = atoi(portStr); else port = gpioCfg.socketPort;
-
-   server.sin_family      = AF_INET;
-   server.sin_addr.s_addr = INADDR_ANY;
-   server.sin_port = htons(port);
-   
-   if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0)
-      SOFT_ERROR((void*)PI_INIT_FAILED, "bind failed (%m)");
+   /* fdSock opened in gpioInitialise so that we can treat
+      failure to bind as fatal. */
 
    listen(fdSock, 100);
    
@@ -3264,7 +3452,7 @@ static void initClearGlobals(void)
 
    wfStats.micros     = 0;
    wfStats.highMicros = 0;
-   wfStats.maxMicros  = -1;
+   wfStats.maxMicros  = PI_WAVE_MAX_MICROS;
 
    wfStats.pulses     = 0;
    wfStats.highPulses = 0;
@@ -3406,7 +3594,8 @@ static void initReleaseResources(void)
          munmap(dmaVirt[i], PAGE_SIZE);
       }
 
-      munmap(dmaVirt, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
+      munmap(dmaVirt,
+         PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
    }
 
    dmaVirt = MAP_FAILED;
@@ -3418,7 +3607,8 @@ static void initReleaseResources(void)
          munmap(dmaPhys[i], PAGE_SIZE);
       }
 
-      munmap(dmaPhys, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
+      munmap(dmaPhys,
+         PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
    }
 
    dmaPhys = MAP_FAILED;
@@ -3474,6 +3664,9 @@ static void initReleaseResources(void)
 int gpioInitialise(void)
 {
    int i;
+   struct sockaddr_in server;
+   char * portStr;
+   unsigned port;
 
    clock_gettime(CLOCK_REALTIME, &libStarted);
 
@@ -3542,6 +3735,22 @@ int gpioInitialise(void)
 
    if (!(gpioCfg.ifFlags & PI_DISABLE_SOCK_IF))
    {
+      fdSock = socket(AF_INET , SOCK_STREAM , 0);
+
+      if (fdSock == -1)
+         SOFT_ERROR(PI_INIT_FAILED, "socket failed (%m)");
+   
+      portStr = getenv(PI_ENVPORT);
+
+      if (portStr) port = atoi(portStr); else port = gpioCfg.socketPort;
+
+      server.sin_family = AF_INET;
+      server.sin_addr.s_addr = INADDR_ANY;
+      server.sin_port = htons(port);
+   
+      if (bind(fdSock,(struct sockaddr *)&server , sizeof(server)) < 0)
+         SOFT_ERROR(PI_INIT_FAILED, "bind to port %d failed (%m)", port);
+
       if (pthread_create(&pthSocket, &pthAttr, pthSocketThread, &i))
          SOFT_ERROR(PI_INIT_FAILED, "pthread_create socket failed (%m)");
 
@@ -4127,15 +4336,16 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses)
 
 int gpioWaveAddSerial(unsigned gpio,
                       unsigned baud,
+                      unsigned offset,
                       unsigned numChar,
-                      char *   str)
+                      char     *str)
 {
    int i, b, p, lev, c, v;
 
    unsigned bitDelay[10];
 
-   DBG(DBG_USER, "gpio=%d baud=%d numChar=%d str*=%08X",
-      gpio, baud, numChar, (uint32_t)str);
+   DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s",
+      gpio, baud, offset, numChar, str);
 
    CHECK_INITED;
 
@@ -4149,6 +4359,9 @@ int gpioWaveAddSerial(unsigned gpio,
    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;
 
    waveBitDelay(baud, bitDelay);
@@ -4157,7 +4370,9 @@ int gpioWaveAddSerial(unsigned gpio,
 
    wf[2][p].gpioOn  = (1<<gpio);
    wf[2][p].gpioOff = 0;
-   wf[2][p].usDelay = bitDelay[0];
+
+   if (offset > bitDelay[0]) wf[2][p].usDelay = offset;
+   else                      wf[2][p].usDelay = bitDelay[0];
 
    for (i=0; i<numChar; i++)
    {
@@ -4609,6 +4824,35 @@ int gpioNotifyClose(unsigned handle)
    return 0;
 }
 
+/* ----------------------------------------------------------------------- */
+
+int gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
+{
+   DBG(DBG_USER, "gpio=%d pulseLen=%d level=%d", gpio, pulseLen, level);
+
+   CHECK_INITED;
+
+   if (gpio > PI_MAX_USER_GPIO)
+      SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
+
+   if (level > PI_ON)
+      SOFT_ERROR(PI_BAD_LEVEL, "gpio %d, bad level (%d)", gpio, level);
+
+   if (pulseLen > PI_MAX_PULSELEN)
+      SOFT_ERROR(PI_BAD_PULSELEN,
+         "gpio %d, bad pulseLen (%d)", gpio, pulseLen);
+
+   if (level == PI_OFF) *(gpioReg + GPCLR0 + BANK) = BIT;
+   else                 *(gpioReg + GPSET0 + BANK) = BIT;
+
+   myGpioDelay(pulseLen);
+
+   if (level != PI_OFF) *(gpioReg + GPCLR0 + BANK) = BIT;
+   else                 *(gpioReg + GPSET0 + BANK) = BIT;
+
+   return 0;
+}
+
 
 /* ----------------------------------------------------------------------- */
 
@@ -4769,7 +5013,7 @@ int gpioSetTimerFuncEx(unsigned id, unsigned ms, gpioTimerFuncEx_t f,
 
 /* ----------------------------------------------------------------------- */
 
-pthread_t *gpioStartThread(ThreadFunc_t func, void *arg)
+pthread_t *gpioStartThread(gpioThreadFunc_t func, void *arg)
 {
    pthread_t *pth;
    pthread_attr_t pthAttr;
@@ -4818,6 +5062,58 @@ void gpioStopThread(pthread_t *pth)
    }
 }
 
+/* ----------------------------------------------------------------------- */
+
+int gpioStoreScript(char *script)
+{
+   DBG(DBG_USER, "script=%s", script);
+
+   CHECK_INITED;
+
+   return PI_BAD_SCRIPT;
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+int gpioRunScript(int script_id)
+{
+   DBG(DBG_USER, "script_id=%d", script_id);
+
+   CHECK_INITED;
+
+   return PI_BAD_SCRIPT_ID;
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+int gpioStopScript(int script_id)
+{
+   DBG(DBG_USER, "script_id=%d", script_id);
+
+   CHECK_INITED;
+
+   return PI_BAD_SCRIPT_ID;
+}
+
+
+
+/* ----------------------------------------------------------------------- */
+
+int gpioDeleteScript(int script_id)
+{
+   DBG(DBG_USER, "script_id=%d", script_id);
+
+   CHECK_INITED;
+
+   return PI_BAD_SCRIPT_ID;
+}
+
+
+
 /* ----------------------------------------------------------------------- */
 
 int gpioSetSignalFunc(unsigned signum, gpioSignalFunc_t f)
index f4faaa040e804736c8f47e2f14773ea065523f0b..cf91696298533a091a850ce40827902c3bf2e7b7 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 10
+This version is for pigpio version 11
 */
 
 #ifndef PIGPIO_H
@@ -86,7 +86,7 @@ This version is for pigpio version 10
 #include <stdint.h>
 #include <pthread.h>
 
-#define PIGPIO_VERSION 10
+#define PIGPIO_VERSION 11
 
 /*-------------------------------------------------------------------------*/
 
@@ -148,6 +148,8 @@ gpioWaveGetCbs             Length in cbs of the current waveform.
 gpioWaveGetHighCbs         Length of longest waveform so far.
 gpioWaveGetMaxCbs          Absolute maximum allowed cbs.
 
+gpioTrigger                Send a trigger pulse to a gpio.
+
 gpioSetWatchdog            Set a watchdog on a gpio.
 
 gpioSetGetSamplesFunc      Requests a gpio samples callback.
@@ -159,6 +161,11 @@ gpioSetTimerFuncEx         Request a regular timed callback, extended.
 gpioStartThread            Start a new thread.
 gpioStopThread             Stop a previously started thread.
 
+gpioStoreScript            Store a script.
+gpioRunScript              Run a stored script.
+gpioStopScript             Stop a running script.
+gpioDeleteScript           Delete a stored script.
+
 gpioSetSignalFunc          Request a signal callback.
 gpioSetSignalFuncEx        Request a signal callback, extended.
 
@@ -217,6 +224,13 @@ typedef struct
    uint32_t res;
 } cmdCmd_t;
 
+typedef struct
+{
+   size_t n;
+   void *ptr;
+   int data;
+} gpioExtent_t;
+
 typedef struct
 {
    uint32_t tick;
@@ -271,8 +285,7 @@ typedef void (*gpioGetSamplesFuncEx_t) (const gpioSample_t * samples,
                                         int                  numSamples,
                                         void *               userdata);
 
-typedef void *(ThreadFunc_t) (void *);
-
+typedef void *(gpioThreadFunc_t) (void *);
 
 
 /*
@@ -881,7 +894,6 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses);
 
    If the added waveform is intended to start after or within the existing
    waveform then the first pulse should consist of a delay.
-
 */
 
 
@@ -889,15 +901,17 @@ int gpioWaveAddGeneric(unsigned numPulses, gpioPulse_t * pulses);
 /*-------------------------------------------------------------------------*/
 int gpioWaveAddSerial(unsigned user_gpio,
                       unsigned baud,
+                      unsigned offset,
                       unsigned numChar,
                       char *   str);
 /*-------------------------------------------------------------------------*/
 /* This function adds a waveform representing serial data to the
-   existing waveform (if any).
+   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.
+   otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_TOO_MANY_CHARS,
+   PI_BAD_SER_OFFSET, or PI_TOO_MANY_PULSES.
 
    NOTES:
 
@@ -915,6 +929,8 @@ int gpioWaveAddSerial(unsigned user_gpio,
 #define PI_WAVE_MIN_BAUD      100
 #define PI_WAVE_MAX_BAUD      250000
 
+#define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */
+
 
 
 /*-------------------------------------------------------------------------*/
@@ -923,7 +939,8 @@ int gpioWaveTxStart(unsigned mode);
 /* This function transmits the current waveform.  The mode determines
    whether the waveform is sent once or cycles endlessly.
 
-   Returns 0 if OK, otherwise PI_BAD_WAVE_MODE.
+   Returns the number of DMA control blocks in the waveform if OK,
+   otherwise PI_BAD_WAVE_MODE.
 */
 
 #define PI_WAVE_MODE_ONE_SHOT 0
@@ -1112,6 +1129,19 @@ int gpioWaveGetMaxCbs(void);
 
 
 
+/*-------------------------------------------------------------------------*/
+int gpioTrigger(unsigned user_gpio, unsigned pulseLen, unsigned level);
+/*-------------------------------------------------------------------------*/
+/* This function sends a trigger pulse to a gpio.  The gpio is set to
+   level for pulseLen microseconds and then reset to not level.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL,
+   or PI_BAD_PULSELEN.
+*/
+
+#define PI_MAX_PULSELEN 100
+
+
 /*-------------------------------------------------------------------------*/
 int gpioSetWatchdog(unsigned user_gpio,
                     unsigned timeout);
@@ -1267,7 +1297,7 @@ int gpioSetTimerFuncEx(unsigned          timer,
 
 
 /* ----------------------------------------------------------------------- */
-pthread_t *gpioStartThread(ThreadFunc_t func, void *arg);
+pthread_t *gpioStartThread(gpioThreadFunc_t func, void *arg);
 /*-------------------------------------------------------------------------*/
 /* Starts a new thread of execution with func as the main routine.
 
@@ -1327,6 +1357,46 @@ void gpioStopThread(pthread_t *pth);
 */
 
 
+/* ----------------------------------------------------------------------- */
+int gpioStoreScript(char *script);
+/* ----------------------------------------------------------------------- */
+/* This function stores a null terminated script for later execution.
+
+   The function returns a script id if the script is valid,
+   otherwise PI_BAD_SCRIPT.
+*/
+
+
+
+/* ----------------------------------------------------------------------- */
+int gpioRunScript(int script_id);
+/* ----------------------------------------------------------------------- */
+/* This function runs a stored script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
+
+
+/* ----------------------------------------------------------------------- */
+int gpioStopScript(int script_id);
+/* ----------------------------------------------------------------------- */
+/* This function stops a running script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
+
+
+/* ----------------------------------------------------------------------- */
+int gpioDeleteScript(int script_id);
+/* ----------------------------------------------------------------------- */
+/* This function deletes a stored script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
+
 
 /*-------------------------------------------------------------------------*/
 int gpioSetSignalFunc(unsigned         signum,
@@ -1816,6 +1886,21 @@ void gpioWaveDump(void);
 #define PI_CMD_PRRG  24
 #define PI_CMD_HELP  25
 #define PI_CMD_PIGPV 26
+#define PI_CMD_WVCLR 27
+#define PI_CMD_WVAG  28
+#define PI_CMD_WVAS  29
+#define PI_CMD_WVGO  30
+#define PI_CMD_WVGOR 31
+#define PI_CMD_WVBSY 32
+#define PI_CMD_WVHLT 33
+#define PI_CMD_WVSM  34
+#define PI_CMD_WVSP  35
+#define PI_CMD_WVSC  36
+#define PI_CMD_TRIG  37
+#define PI_CMD_PROC  38
+#define PI_CMD_PROCD 39
+#define PI_CMD_PROCR 40
+#define PI_CMD_PROCS 41
 
 /*
 The following command only works on the socket interface.
@@ -1841,7 +1926,7 @@ after this command is issued.
 #define PI_BAD_LEVEL         -5 /* level not 0-1                           */
 #define PI_BAD_PUD           -6 /* pud not 0-2                             */
 #define PI_BAD_PULSEWIDTH    -7 /* pulsewidth not 0 or 500-2500            */
-#define PI_BAD_DUTYCYCLE     -8 /* dutycycle not 0-255                     */
+#define PI_BAD_DUTYCYCLE     -8 /* dutycycle outside set range             */
 #define PI_BAD_TIMER         -9 /* timer not 0-9                           */
 #define PI_BAD_MS           -10 /* ms not 10-60000                         */
 #define PI_BAD_TIMETYPE     -11 /* timetype not 0-1                        */
@@ -1878,6 +1963,13 @@ after this command is issued.
 #define PI_BAD_SERIAL_BUF   -40 /* bad (null) serial buf parameter         */
 #define PI_NOT_PERMITTED    -41 /* gpio operation not permitted            */
 #define PI_SOME_PERMITTED   -42 /* one or more gpios not permitted         */
+#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_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     */
 
 
 /*-------------------------------------------------------------------------*/
index c9e4be58db71003acf65727703a999b73972e714..0b40af8d027690ff91d6d89aa31d74b09457de89 100644 (file)
--- a/pigpio.py
+++ b/pigpio.py
@@ -76,7 +76,7 @@ import threading
 import os
 import atexit
 
-VERSION = "1.1"
+VERSION = "1.2"
 
 # gpio levels
 
@@ -140,8 +140,28 @@ _PI_CMD_NC=   21
 _PI_CMD_PRG=  22
 _PI_CMD_PFG=  23
 _PI_CMD_PRRG= 24
+_PI_CMD_HELP= 25
+_PI_CMD_PIGPV=26
+_PI_CMD_WVCLR=27
+_PI_CMD_WVAG= 28
+_PI_CMD_WVAS= 29
+_PI_CMD_WVGO= 30
+_PI_CMD_WVGOR=31
+_PI_CMD_WVBSY=32
+_PI_CMD_WVHLT=33
+_PI_CMD_WVSM= 34
+_PI_CMD_WVSP= 35
+_PI_CMD_WVSC= 36
+_PI_CMD_TRIG= 37
+_PI_CMD_PROC= 38
+_PI_CMD_PROCD=39
+_PI_CMD_PROCR=40
+_PI_CMD_PROCS=41
+
+
 _PI_CMD_NOIB= 99
 
+
 # pigpio error numbers
 
 _PI_INIT_FAILED     =-1
@@ -179,14 +199,21 @@ _PI_NOT_INITIALISED =-31
 _PI_INITIALISED     =-32
 _PI_BAD_WAVE_MODE   =-33
 _PI_BAD_CFG_INTERNAL=-34
-_PI_BAD_WAVE_BAUD   =-35
-_PI_TOO_MANY_PULSES =-36
-_PI_TOO_MANY_CHARS  =-37
+PI_BAD_WAVE_BAUD    =-35
+PI_TOO_MANY_PULSES  =-36
+PI_TOO_MANY_CHARS   =-37
 _PI_NOT_SERIAL_GPIO =-38
 _PI_BAD_SERIAL_STRUC=-39
 _PI_BAD_SERIAL_BUF  =-40
 PI_NOT_PERMITTED    =-41
 PI_SOME_PERMITTED   =-42
+PI_BAD_WVSC_COMMND  =-43
+PI_BAD_WVSM_COMMND  =-44
+PI_BAD_WVSP_COMMND  =-45
+PI_BAD_PULSELEN     =-46
+PI_BAD_SCRIPT       =-47
+PI_BAD_SCRIPT_ID    =-48
+PI_BAD_SER_OFFSET   =-49
 
 # pigpio error text
 
@@ -225,12 +252,19 @@ _errors=[
    [_PI_INITIALISED      , "function called after gpioInitialise"],
    [_PI_BAD_WAVE_MODE    , "waveform mode not 0-1"],
    [_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"],
-   [_PI_BAD_WAVE_BAUD    , "baud rate not 100-250000"],
-   [_PI_TOO_MANY_PULSES  , "waveform has too many pulses"],
-   [_PI_TOO_MANY_CHARS   , "waveform has too many chars"],
+   [PI_BAD_WAVE_BAUD    , "baud rate not 100-250000"],
+   [PI_TOO_MANY_PULSES  , "waveform has too many pulses"],
+   [PI_TOO_MANY_CHARS   , "waveform has too many chars"],
    [_PI_NOT_SERIAL_GPIO  , "no serial read in progress on gpio"],
    [PI_NOT_PERMITTED     , "no permission to update gpio"],
-   [PI_SOME_PERMITTED    , "no permission to update one or more gpios"]
+   [PI_SOME_PERMITTED    , "no permission to update one or more gpios"],
+   [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_SCRIPT        , "invalid script"],
+   [PI_BAD_SCRIPT_ID     , "unknown script id"],
+   [PI_BAD_SER_OFFSET    , "add serial data offset > 30 minute"],
 ]
 
 _control = None
@@ -262,7 +296,7 @@ def error(pigpio_error):
    for e in _errors:
       if e[0] == pigpio_error:
          return e[1]
-   return "unknown error"
+   return "unknown error ({})".format(pigpio_error)
 
 def tickDiff(tStart, tEnd):
    """Calculate the time difference between two ticks.
@@ -304,7 +338,8 @@ def _u2i(number):
          return v
 
 def _pigpio_command(sock, cmd, p1, p2):
-   """Executes a pigpio socket command.
+   """
+   Executes a pigpio socket command.
 
    sock: command socket.
    cmd:  the command to be executed.
@@ -318,6 +353,27 @@ def _pigpio_command(sock, cmd, p1, p2):
    else:
       raise  _pigpioError("*** Module not started, call pigpio.start() ***")
 
+def _pigpio_command_ext(sock, cmd, p1, p2, extents):
+   """
+   Executes an extended pigpio socket command.
+
+   sock: command socket.
+   cmd:  the command to be executed.
+   p1:   command paramter 1 (if applicable).
+   p2:   command paramter 2 (if applicable).
+   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)
+
+      x, y, z, res = struct.unpack('IIII', sock.recv(16))
+      return res
+   else:
+      raise  _pigpioError("*** Module not started, call pigpio.start() ***")
+
 class _callback:
    """An ADT class to hold callback information."""
 
@@ -462,8 +518,7 @@ def set_mode(gpio, mode):
    pigpio.set_mode(10, pigpio.ALT2) # gpio 10 as ALT2
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_MODES, gpio, mode))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_MODES, gpio, mode))
 
 def get_mode(gpio):
    """Get the gpio mode.
@@ -482,8 +537,7 @@ def get_mode(gpio):
    6
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_MODEG, gpio, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_MODEG, gpio, 0))
 
 def set_pull_up_down(gpio, pud):
    """Set or clear the gpio pull-up/down resistor.
@@ -516,8 +570,7 @@ def set_pull_up_down(gpio, pud):
    1
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PUD, gpio, pud))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PUD, gpio, pud))
 
 def read(gpio):
    """Read the gpio level.
@@ -545,8 +598,7 @@ def read(gpio):
    1
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_READ, gpio, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_READ, gpio, 0))
 
 def write(gpio, level):
    """Write the gpio level.
@@ -578,8 +630,7 @@ def write(gpio, level):
    1
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_WRITE, gpio, level))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_WRITE, gpio, level))
 
 def set_PWM_dutycycle(user_gpio, dutycycle):
    """Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
@@ -609,8 +660,7 @@ def set_PWM_dutycycle(user_gpio, dutycycle):
    set_PWM_dutycycle(4, 255) # PWM full on
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PWM, user_gpio, dutycycle))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PWM, user_gpio, dutycycle))
 
 def set_PWM_range(user_gpio, range_):
    """Set the range of PWM values to be used on the gpio.
@@ -645,8 +695,7 @@ def set_PWM_range(user_gpio, range_):
    pigpio.set_PWM_range(9, 3000) # now 750 1/4, 1500 1/2, 2250 3/4 on
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PRS, user_gpio, range_))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PRS, user_gpio, range_))
 
 def get_PWM_range(user_gpio):
    """Get the range of PWM values being used on the gpio.
@@ -674,8 +723,7 @@ def get_PWM_range(user_gpio):
    3000
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PRG, user_gpio, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PRG, user_gpio, 0))
 
 def get_PWM_real_range(user_gpio):
    """Get the real underlying range of PWM values being used on the gpio.
@@ -701,8 +749,7 @@ def get_PWM_real_range(user_gpio):
    25
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PRRG, user_gpio, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PRRG, user_gpio, 0))
 
 def set_PWM_frequency(user_gpio, frequency):
    """Set the frequency (in Hz) of the PWM to be used on the gpio.
@@ -759,8 +806,7 @@ def set_PWM_frequency(user_gpio, frequency):
    8000
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PFS, user_gpio, frequency))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PFS, user_gpio, frequency))
 
 def get_PWM_frequency(user_gpio):
    """Get the frequency of PWM being used on the gpio.
@@ -788,8 +834,7 @@ def get_PWM_frequency(user_gpio):
    8000
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_PFG, user_gpio, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_PFG, user_gpio, 0))
 
 def set_servo_pulsewidth(user_gpio, pulsewidth):
    """Start (500-2500) or stop (0) servo pulses on the gpio.
@@ -845,8 +890,8 @@ def set_servo_pulsewidth(user_gpio, pulsewidth):
    for m in moves:
       pigpio.set_servo_pulsewidth(24, m[0]);
       time.sleep(m[1])
-      message = str(m[1]) + " seconds @ " + str(m[0]) + " us"
-      print(message)
+      s = str(m[1]) + " seconds @ " + str(m[0]) + " us"
+      print(s)
 
    pigpio.stop()
 
@@ -875,8 +920,8 @@ def set_servo_pulsewidth(user_gpio, pulsewidth):
    for m in moves:
       pigpio.set_PWM_dutycycle(25, m[0]);
       time.sleep(m[1])
-      message = str(m[1]) + " seconds @ " + str(m[0]) + " us"
-      print(message)
+      s = str(m[1]) + " seconds @ " + str(m[0]) + " us"
+      print(s)
 
    pigpio.stop()
 
@@ -888,8 +933,7 @@ def set_servo_pulsewidth(user_gpio, pulsewidth):
    5 seconds @ 2000 us
    0 seconds @ 1000 us
 """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_SERVO, user_gpio, pulsewidth))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_SERVO, user_gpio, pulsewidth))
 
 def notify_open():
    """Get a free notification handle.
@@ -917,8 +961,7 @@ def notify_open():
       pigpio.notify_begin(h, 1234)
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0))
 
 def notify_begin(handle, bits):
    """Start notifications on a previously opened handle.
@@ -951,8 +994,7 @@ def notify_begin(handle, bits):
    I (32 bit) level
 
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits))
 
 def notify_pause(handle):
    """Pause notifications on a previously opened handle.
@@ -976,8 +1018,7 @@ def notify_pause(handle):
       ...
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0))
 
 def notify_close(handle):
    """Stop notifications on a previously opened handle and
@@ -997,8 +1038,7 @@ def notify_close(handle):
       ...
    ...
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0))
 
 def set_watchdog(user_gpio, timeout):
    """Sets a watchdog for a gpio.
@@ -1030,8 +1070,8 @@ def set_watchdog(user_gpio, timeout):
    import time
 
    def cbf(g, L, t):
-      message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
-      print(message)
+      s = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
+      print(s)
 
    pigpio.start()
 
@@ -1068,8 +1108,7 @@ def set_watchdog(user_gpio, timeout):
    gpio=22 level=2 at 3551411622
    watchdog cancelled, 5 second delay
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout))
 
 def read_bank_1():
    """Read the levels of the bank 1 gpios (gpios 0-31).
@@ -1148,8 +1187,7 @@ def clear_bank_1(levels):
    0b1111110010000
 
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_BC1, levels, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_BC1, levels, 0))
 
 def clear_bank_2(levels):
    """Clears gpios 32-53 if the corresponding bit (0-21) in levels is set.
@@ -1164,8 +1202,7 @@ def clear_bank_2(levels):
 
    See clear_bank_1() for an example.
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_BC2, levels, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_BC2, levels, 0))
 
 def set_bank_1(levels):
    """Sets gpios 0-31 if the corresponding bit in levels is set.
@@ -1215,8 +1252,7 @@ def set_bank_1(levels):
    0b1111111011111
    0b1111110010000
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_BS1, levels, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_BS1, levels, 0))
 
 def set_bank_2(levels):
    """Sets gpios 32-53 if the corresponding bit (0-21) in levels is set.
@@ -1231,8 +1267,7 @@ def set_bank_2(levels):
 
    See set_bank_1() for an example.
    """
-   r=_u2i(_pigpio_command(_control, _PI_CMD_BS2, levels, 0))
-   return r
+   return _u2i(_pigpio_command(_control, _PI_CMD_BS2, levels, 0))
 
 def get_current_tick():
    """Gets the current system tick.
@@ -1257,9 +1292,9 @@ def get_current_tick():
 
    t2 = pigpio.get_current_tick()
 
-   message = "5 seconds is " + str(pigpio.tickDiff(t1, t2)) + " ticks"
+   s = "5 seconds is " + str(pigpio.tickDiff(t1, t2)) + " ticks"
 
-   print(message
+   print(s
 
    pigpio.stop()
 
@@ -1308,6 +1343,365 @@ def get_hardware_revision():
    """
    return _pigpio_command(_control, _PI_CMD_HWVER, 0, 0)
 
+def get_pigpio_version():
+   """
+   Returns the pigpio software version.
+   """
+   return _pigpio_command(_control, _PI_CMD_PIGPV, 0, 0)
+
+class pulse:
+   """
+   An ADT class to hold pulse information.
+   """
+
+   def __init__(self, gpio_on, gpio_off, delay):
+      """
+      Initialises a pulse ADT.
+
+      gpio_on: the gpios to switch on at the start of the pulse.
+      gpio_off: the gpios to switch off at the start of the pulse.
+      delay: the delay in microseconds before the next pulse.
+      """
+      self.gpio_on = gpio_on
+      self.gpio_off = gpio_off
+      self.delay = delay
+
+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.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVCLR, 0, 0))
+
+def wave_add_generic(pulses):
+   """
+   Adds a list of pulses to the current waveform.
+
+   Returns the new total number of pulses in the current waveform
+   if OK, otherwise PI_TOO_MANY_PULSES.
+
+   pulses: list of pulses to add to the 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 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.
+
+   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
+
+   pigpio.start()
+
+   s1 = stepper(14, 15, 18, 17)
+   s2 = stepper(24, 25,  8,  7)
+
+   f1=[] # pulses to drive stepper 1 forward
+   b2=[] # pulses to drive stepper 2 backward
+
+   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))
+
+   pigpio.wave_clear() # initialise a new waveform
+
+   pigpio.wave_add_generic(f1) # add stepper 1 forward
+   pigpio.wave_add_generic(b2) # add stepper 2 backward
+
+   pigpio.wave_tx_repeat() # repeately transmit pulses
+
+   time.sleep(10)
+
+   pigpio.wave_tx_stop() # stop waveform
+
+   pigpio.stop()
+   """
+   # pigpio message format
+
+   # I p1 number of 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))
+
+def wave_add_serial(user_gpio, baud, offset, data):
+   """
+   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, PI_BAD_SER_OFFSET, or PI_TOO_MANY_PULSES.
+
+   user_gpio: gpio to transmit data.  You must set the gpio mode
+              to output.
+   baud: baud rate to use.
+   offset: number of microseconds from the starts of the waveform.
+   data: the data to transmit.
+
+   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.
+
+   Example
+
+   #!/usr/bin/env python
+
+   import time
+
+   import pigpio
+
+   GPIO=24
+
+   pigpio.start()
+
+   pigpio.set_mode(TX_GPIO, pigpio.OUTPUT)
+
+   pigpio.wave_clear() # initialise waveform
+
+   for i in range(10):
+      pigpio.wave_add_serial(
+         GPIO, 9600, i*2000000, "{} seconds in.\r\n".format(i*2))
+
+   pigpio.wave_tx_start()
+
+   time.sleep(22)
+
+   pigpio.stop()
+   """
+   # pigpio message format
+
+   # I p1 user_gpio
+   # I p2 len(data)
+   ## extension ##
+   # 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))
+
+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_tx_repeat().
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVHLT, 0, 0))
+
+def wave_tx_start():
+   """
+   Transmits the current waveform.  The waveform is sent once.
+
+   Returns the number of cbs in the waveform if OK,
+   otherwise PI_BAD_WAVE_MODE.
+   """
+   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.
+
+   Returns the number of cbs in the waveform if OK,
+   otherwise PI_BAD_WAVE_MODE.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVGOR, 0, 0))
+
+def wave_get_micros():
+   """
+   Returns the length in microseconds of the current waveform.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSM, 0, 0))
+
+def wave_get_max_micros():
+   """
+   Returns the maximum possible size of a waveform in microseconds.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSM, 2, 0))
+
+def wave_get_pulses():
+   """
+   Returns the length in pulses of the current waveform.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSP, 0, 0))
+
+def wave_get_max_pulses():
+   """
+   Returns the maximum possible size of a waveform in pulses.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSP, 2, 0))
+
+def wave_get_cbs():
+   """
+   Returns the length in DMA control blocks of the current waveform.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSC, 0, 0))
+
+def wave_get_max_cbs():
+   """
+   Returns the maximum possible size of a waveform in DMA control blocks.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_WVSC, 2, 0))
+
+def gpio_trigger(user_gpio, pulse_len=10, level=1):
+   """
+   Send a trigger pulse to a gpio.  The gpio is set to
+   level for pulse_len microseconds and then reset to not level.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL,
+   PI_BAD_PULSELEN, or PI_NOT_PERMITTED.
+
+   user_gpio: gpio to pulse.
+   pulse_len: length of pulse in microseconds.
+   level: whether the pulse should be high or low.
+
+   Example
+
+   #!/usr/bin/env python
+
+   import time
+
+   import pigpio
+
+   GPIO=24
+
+   pigpio.start()
+
+   for i in range(10):
+      pigpio.gpio_trigger(GPIO, (i*5)+10, 1)
+      time.sleep(1)
+
+   pigpio.stop()
+
+   """
+   # pigpio message format
+
+   # I p1 user_gpio
+   # I p2 pulse_len
+   ## extension ##
+   # I level
+
+   extents = [struct.pack("I", level)]
+
+   return _u2i(_pigpio_command_ext(
+      _control, _PI_CMD_TRIG, user_gpio, pulse_len, extents))
+
+def store_script(script):
+   """
+   Store a script for later execution.
+
+   Returns a script id if OK, otherwise PI_BAD_SCRIPT.
+   """
+   # I p1 script length
+   # I p2 0
+   ## extension ##
+   # s script
+
+   return _u2i(_pigpio_command_ext(
+      _control, _PI_CMD_PROC, len(script), 0, script))
+
+def run_script(script_id):
+   """
+   Runs a stored script.
+
+   Returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+
+   script_id: script_id of stored script.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_PROCR, script_id, 0))
+
+def stop_script(script_id):
+   """
+   Stops a running script.
+
+   Returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+
+   script_id: script_id of stored script.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_PROCS, script_id, 0))
+
+def delete_script(script_id):
+   """
+   Deletes a stored script.
+
+   Returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+
+   script_id: script_id of stored script.
+   """
+   return _u2i(_pigpio_command(_control, _PI_CMD_PROCD, script_id, 0))
+
+
 class callback:
    """A class to provide gpio level change callbacks."""
 
@@ -1332,8 +1726,8 @@ class callback:
       import time
 
       def cbf(g, L, t):
-         message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
-         print(message)
+         s = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
+         print(s)
 
       pigpio.start()
 
@@ -1376,9 +1770,9 @@ class callback:
 
       tally_2 = cb.tally()
 
-      message = "counted " + str(tally_2 - tally_1) + " edges"
+      s = "counted " + str(tally_2 - tally_1) + " edges"
 
-      print(message)
+      print(s)
 
       cb.cancel()
 
@@ -1411,9 +1805,9 @@ class callback:
 
       tally_2 = cb.tally()
 
-      message = "counted " + str(tally_2 - tally_1) + " rising edges"
+      s = "counted " + str(tally_2 - tally_1) + " rising edges"
 
-      print(message)
+      print(s)
 
       cb.cancel()
 
index 3d45548bac2ec23bb96640f21bff24704a96b077..5338b86a2066e47d44ec531cf87e7dccc4bb2529 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 7+
+This version is for pigpio version 11+
 */
 
 #include <sys/types.h>
@@ -34,6 +34,7 @@ This version is for pigpio version 7+
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
@@ -43,7 +44,6 @@ This version is for pigpio version 7+
 #include <ctype.h>
 
 #include "pigpio.h"
-#include "command.h"
 
 /*
 This program starts the pigpio library as a daemon.
@@ -61,6 +61,22 @@ static uint64_t updateMask             = -1;
 
 static FILE * errFifo;
 
+void fatal(char *fmt, ...)
+{
+   char buf[128];
+   va_list ap;
+
+   va_start(ap, fmt);
+   vsnprintf(buf, sizeof(buf), fmt, ap);
+   va_end(ap);
+
+   fprintf(stderr, "%s\n", buf);
+
+   fflush(stderr);
+
+   exit(EXIT_FAILURE);
+}
+
 void usage()
 {
    fprintf(stderr, "\n" \
@@ -98,21 +114,21 @@ static void initOpts(int argc, char *argv[])
             i = atoi(optarg);
             if ((i >= PI_BUF_MILLIS_MIN) && (i <= PI_BUF_MILLIS_MAX))
                bufferSizeMilliseconds = i;
-            else cmdFatal("invalid -b option (%d)", i);
+            else fatal("invalid -b option (%d)", i);
             break;
 
          case 'd':
             i = atoi(optarg);
             if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL))
                DMAprimaryChannel = i;
-            else cmdFatal("invalid -d option (%d)", i);
+            else fatal("invalid -d option (%d)", i);
             break;
 
          case 'e':
             i = atoi(optarg);
             if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL))
                DMAsecondaryChannel = i;
-            else cmdFatal("invalid -e option (%d)", i);
+            else fatal("invalid -e option (%d)", i);
             break;
 
          case 'f':
@@ -127,7 +143,7 @@ static void initOpts(int argc, char *argv[])
             i = atoi(optarg);
             if ((i >= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT))
                socketPort = i;
-            else cmdFatal("invalid -p option (%d)", i);
+            else fatal("invalid -p option (%d)", i);
             break;
 
          case 's':
@@ -145,7 +161,7 @@ static void initOpts(int argc, char *argv[])
                   break;
 
                default:
-                  cmdFatal("invalid -s option (%d)", i);
+                  fatal("invalid -s option (%d)", i);
                   break;
             }
             break;
@@ -154,21 +170,21 @@ static void initOpts(int argc, char *argv[])
             i = atoi(optarg);
             if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
                clockPeripheral = i;
-            else cmdFatal("invalid -t option (%d)", i);
+            else fatal("invalid -t option (%d)", i);
             break;
 
          case 'u':
             i = atoi(optarg);
             if ((i >= PI_CLOCK_OSC) && (i <= PI_CLOCK_PLLD))
                clockSource = i;
-            else cmdFatal("invalid -u option (%d)", i);
+            else fatal("invalid -u option (%d)", i);
             break;
 
          case 'x':
             mask = strtoll(optarg, &endptr, 0);
             printf("mask=%llx\n", mask);
             if (!*endptr) updateMask = mask;
-            else cmdFatal("invalid -x option (%s)", optarg);
+            else fatal("invalid -x option (%s)", optarg);
             break;
 
         default: /* '?' */
@@ -221,11 +237,11 @@ int main(int argc, char **argv)
    
    /* Create a new SID for the child process */
 
-   if (setsid() < 0) cmdFatal("setsid failed (%m)");
+   if (setsid() < 0) fatal("setsid failed (%m)");
 
    /* Change the current working directory */
 
-   if ((chdir("/")) < 0) cmdFatal("chdir failed (%m)");
+   if ((chdir("/")) < 0) fatal("chdir failed (%m)");
    
    /* check command line parameters */
 
@@ -252,7 +268,7 @@ int main(int argc, char **argv)
 
    /* start library */
 
-   if (gpioInitialise()< 0) cmdFatal("Can't initialise pigpio library");
+   if (gpioInitialise()< 0) fatal("Can't initialise pigpio library");
 
    /* create pipe for error reporting */
 
@@ -261,7 +277,7 @@ int main(int argc, char **argv)
    mkfifo(PI_ERRFIFO, 0664);
 
    if (chmod(PI_ERRFIFO, 0664) < 0)
-      cmdFatal("chmod %s failed (%m)", PI_ERRFIFO);
+      fatal("chmod %s failed (%m)", PI_ERRFIFO);
 
    errFifo = freopen(PI_ERRFIFO, "w+", stderr);
 
index 6f095cbd5c42f34ac11a0c46a297a0ae266309b3..e6884fdc33d3db6ef5c8372eac2bf21c731d5992 100644 (file)
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 For more information, please refer to <http://unlicense.org/>
 */
 
-/* PIGPIOD_IF_VERSION 1 */
+/* PIGPIOD_IF_VERSION 2 */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -97,10 +97,34 @@ static int pigpio_command(int fd, int command, int p1, int p2)
    cmd.p2  = p2;
    cmd.res = 0;
 
-   if (send(fd, &cmd, sizeof(cmdCmd_t), 0) != sizeof(cmdCmd_t))
-      return pigif_bad_send;
+   if (send(fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) return pigif_bad_send;
 
-   if (recv(fd, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) != sizeof(cmdCmd_t))
+   if (recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+      return pigif_bad_recv;
+
+   return cmd.res;
+}
+
+static int pigpio_command_ext
+   (int fd, int command, int p1, int p2, int extents, gpioExtent_t *ext)
+{
+   int i;
+   cmdCmd_t cmd;
+
+   cmd.cmd = command;
+   cmd.p1  = p1;
+   cmd.p2  = p2;
+   cmd.res = 0;
+
+   if (send(fd, &cmd, sizeof(cmd), 0) != sizeof(cmd)) return pigif_bad_send;
+
+   for (i=0; i<extents; i++)
+   {
+      if (send(fd, ext[i].ptr, ext[i].n, 0) != ext[i].n)
+         return pigif_bad_send;
+   }
+
+   if (recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
       return pigif_bad_recv;
 
    return cmd.res;
@@ -390,7 +414,7 @@ unsigned pigpiod_if_version(void)
    return PIGPIOD_IF_VERSION;
 }
 
-pthread_t *start_thread(ThreadFunc_t func, void *arg)
+pthread_t *start_thread(gpioThreadFunc_t func, void *arg)
 {
    pthread_t *pth;
    pthread_attr_t pthAttr;
@@ -501,145 +525,220 @@ void pigpio_stop(void)
 }
 
 int set_mode(int gpio, int mode)
-{
-   return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);}
 
 int get_mode(int gpio)
-{
-   return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);}
 
 int set_pull_up_down(int gpio, int pud)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);}
 
 int read_gpio(int gpio)
-{
-   return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);}
 
 int write_gpio(int gpio, int level)
-{
-   return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);}
 
 int set_PWM_dutycycle(int user_gpio, int dutycycle)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);}
 
 int set_PWM_range(int user_gpio, int range_)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);}
 
 int get_PWM_range(int user_gpio)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);}
 
 int get_PWM_real_range(int user_gpio)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);}
 
 int set_PWM_frequency(int user_gpio, int frequency)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);}
 
 int get_PWM_frequency(int user_gpio)
-{
-   return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);}
 
 int set_servo_pulsewidth(int user_gpio, int pulsewidth)
-{
-   return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);}
 
 int notify_open(void)
-{
-   return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);}
 
 int notify_begin(int handle, uint32_t bits)
-{
-   return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);}
 
 int notify_pause(int handle)
-{
-   return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);}
 
 int notify_close(int handle)
-{
-   return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);}
 
 int set_watchdog(int user_gpio, int timeout)
-{
-   return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);}
 
 uint32_t read_bank_1(void)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BR1, 0, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BR1, 0, 0);}
 
 uint32_t read_bank_2(void)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BR2, 0, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BR2, 0, 0);}
 
 int clear_bank_1(uint32_t levels)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BC1, levels, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BC1, levels, 0);}
 
 int clear_bank_2(uint32_t levels)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BC2, levels, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BC2, levels, 0);}
 
 int set_bank_1(uint32_t levels)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BS1, levels, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BS1, levels, 0);}
 
 int set_bank_2(uint32_t levels)
-{
-   return pigpio_command(gPigCommand, PI_CMD_BS2, levels, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_BS2, levels, 0);}
 
 uint32_t get_current_tick(void)
-{
-   return pigpio_command(gPigCommand, PI_CMD_TICK, 0, 0);
-}
+   {return pigpio_command(gPigCommand, PI_CMD_TICK, 0, 0);}
 
 uint32_t get_hardware_revision(void)
+   {return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);}
+
+unsigned get_pigpio_version(void)
+   {return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);}
+
+int wave_clear(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVCLR, 0, 0);}
+
+int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses)
 {
-   return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=numPulses
+   p2=0
+   ## extension ##
+   gpioPulse_t[] pulses
+   */
+
+   ext[0].n = numPulses * sizeof(gpioPulse_t);
+   ext[0].ptr = pulses;
+
+   return pigpio_command_ext(gPigCommand, PI_CMD_WVAG, numPulses, 0, 1, ext);
 }
 
-unsigned get_pigpio_version(void)
+int wave_add_serial(
+   unsigned gpio, unsigned baud, unsigned offset, unsigned numChar, char *str)
 {
-   return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);
+   gpioExtent_t ext[3];
+
+   /*
+   p1=gpio
+   p2=numChar
+   ## extension ##
+   unsigned baud
+   unsigned offset
+   char[] str
+   */
+
+   ext[0].n = sizeof(unsigned);
+   ext[0].ptr = &baud;
+
+   ext[1].n = sizeof(unsigned);
+   ext[1].ptr = &offset;
+
+   ext[2].n = numChar;
+   ext[2].ptr = str;
+
+   return pigpio_command_ext(gPigCommand, PI_CMD_WVAS, gpio, numChar, 3, ext);
 }
 
-int callback(int gpio, int edge, CBFunc_t f)
+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_tx_start(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVGO, 0, 0);}
+
+int wave_tx_repeat(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVGOR, 0, 0);}
+
+int wave_get_micros(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSM, 0, 0);}
+
+int wave_get_high_micros(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSM, 1, 0);}
+
+int wave_get_max_micros(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSM, 2, 0);}
+
+int wave_get_pulses(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSP, 0, 0);}
+
+int wave_get_high_pulses(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSP, 1, 0);}
+
+int wave_get_max_pulses(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSP, 2, 0);}
+
+int wave_get_cbs(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSC, 0, 0);}
+
+int wave_get_high_cbs(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSC, 1, 0);}
+
+int wave_get_max_cbs(void)
+   {return pigpio_command(gPigCommand, PI_CMD_WVSC, 2, 0);}
+
+int gpio_trigger(unsigned gpio, unsigned pulseLen, unsigned level)
 {
-   return intCallback(gpio, edge, f, 0, 0);
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=gpio
+   p2=pulseLen
+   ## extension ##
+   unsigned level
+   */
+
+   ext[0].n = sizeof(level);
+   ext[0].ptr = &level;
+
+   return pigpio_command_ext(gPigCommand, PI_CMD_TRIG, gpio, pulseLen, 1, ext);
 }
 
-int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
+int store_script(char *script)
 {
-   return intCallback(gpio, edge, f, user, 1);
+   unsigned len;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=script length
+   p2=0
+   ## extension ##
+   char[] script
+   */
+
+   len = strlen(script);
+
+   ext[0].n = len;
+   ext[0].ptr = script;
+
+   return pigpio_command_ext(gPigCommand, PI_CMD_PROC, len, 0, 1, ext);
 }
 
+int run_script(int script_id)
+   {return pigpio_command(gPigCommand, PI_CMD_PROCR, script_id, 0);}
+
+int stop_script(int script_id)
+   {return pigpio_command(gPigCommand, PI_CMD_PROCS, script_id, 0);}
+
+int delete_script(int script_id)
+   {return pigpio_command(gPigCommand, PI_CMD_PROCD, script_id, 0);}
+
+int callback(int gpio, int edge, CBFunc_t f)
+   {return intCallback(gpio, edge, f, 0, 0);}
+
+int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
+   {return intCallback(gpio, edge, f, user, 1);}
+
 int callback_cancel(int id)
 {
    callback_t *p;
index bde8a717fcbeb723a66dc2e3af0fbf2df7ef1f9c..6c009e266760b10c7d974e3f7a40f1b349ddfc9a 100644 (file)
@@ -30,7 +30,7 @@ For more information, please refer to <http://unlicense.org/>
 
 #include "pigpio.h"
 
-#define PIGPIOD_IF_VERSION 1
+#define PIGPIOD_IF_VERSION 2
 
 typedef enum
 {
@@ -70,7 +70,7 @@ const char *pigpio_error(int error);
 unsigned pigpiod_if_version(void);
 /* Return the pigpiod_if version. */
 
-pthread_t *start_thread(ThreadFunc_t func, void *arg);
+pthread_t *start_thread(gpioThreadFunc_t func, void *arg);
 /* Starts a new thread of execution with func as the main routine.
 
    Returns a pointer to pthread_t if OK, otherwise NULL.
@@ -198,7 +198,6 @@ int set_PWM_range(int user_gpio, int range_);
 
    The real value set by set_PWM_range is
    (dutycycle * real range) / range.
-
 */
 
 int get_PWM_range(int user_gpio);
@@ -507,20 +506,213 @@ uint32_t get_hardware_revision(void);
    hexadecimal number the function returns 0.
 */
 
+int wave_clear(void);
+/* This function initialises a new waveform.
+
+   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).
+
+   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.
+*/
+
+int wave_tx_stop(void);
+/* This function stops the transmission of the current waveform.
+
+   Returns 0 if OK.
+
+   This function is intended to stop a waveform started with the repeat mode.
+*/
+
+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.
+*/
+
+int wave_tx_repeat(void);
+/* This function transmits the current waveform.  The waveform repeats
+   endlessly until wave_tx_stop is called.
+
+   Returns the number of DMA control blocks in the waveform if OK,
+   otherwise PI_BAD_WAVE_MODE.
+*/
+
+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).
+
+   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_get_micros(void);
+/* This function returns the length in microseconds of the current
+   waveform.
+*/
+
+int wave_get_high_micros(void);
+/* This function returns the length in microseconds of the longest waveform
+   created since the pigpio daemon was started..
+*/
+
+int wave_get_max_micros(void);
+/* This function returns the maximum possible size of a waveform in 
+   microseconds.
+*/
+
+int wave_get_pulses(void);
+/* This function returns the length in pulses of the current waveform.
+*/
+
+int wave_get_high_pulses(void);
+/* This function returns the length in pulses of the longest waveform
+   created since the pigpio daemon was started..
+*/
+
+int wave_get_max_pulses(void);
+/* This function returns the maximum possible size of a waveform in pulses.
+*/
+
+int wave_get_cbs(void);
+/* This function returns the length in DMA control blocks of the current
+   waveform.
+*/
+
+int wave_get_high_cbs(void);
+/* This function returns the length in DMA control blocks of the longest
+   waveform created since the pigpio daemon was started..
+*/
+
+int wave_get_max_cbs(void);
+/* This function returns the maximum possible size of a waveform in DMA
+   control blocks.
+*/
+
+int gpio_trigger(unsigned gpio, unsigned pulseLen, unsigned level);
+/* This function sends a trigger pulse to a gpio.  The gpio is set to
+   level for pulseLen microseconds and then reset to not level.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL,
+   PI_BAD_PULSELEN, or PI_NOT_PERMITTED.
+*/
+
+int store_script(char *script);
+/* This function stores a script for later execution.
+
+   The function returns a script id if the script is valid,
+   otherwise PI_BAD_SCRIPT.
+*/
+
+int run_script(int script_id);
+/* This function runs a stored script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
+int stop_script(int script_id);
+/* This function stops a running script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
+int delete_script(int script_id);
+/* This function deletes a stored script.
+
+   The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+*/
+
 int callback(int gpio, int edge, CBFunc_t f);
 /*
+   This function initialises a new callback.
+
+   The function returns a callback id if OK, otherwise pigif_bad_malloc,
+   pigif_duplicate_callback, or pigif_bad_callback.
+
+   The callback is called with the gpio, edge, and tick, whenever the
+   gpio has the identified edge.
 */
 
 int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user);
 /*
+   This function initialises a new callback.
+
+   The function returns a callback id if OK, otherwise pigif_bad_malloc,
+   pigif_duplicate_callback, or pigif_bad_callback.
+
+   The callback is called with the gpio, edge, tick, and user, whenever
+   the gpio has the identified edge.
 */
 
 int callback_cancel(int id);
 /*
+   This function cancels a callback identified by its id.
+
+   The function returns 0 if OK, otherwise pigif_callback_not_found.
 */
 
 int wait_for_edge(int gpio, int edge, double timeout);
 /*
+   This function waits for edge on the gpio for up to timeout
+   seconds.
+
+   The function returns 1 if the edge occurred, otherwise 0.
+
+   The function returns when the edge occurs or after the timeout.
 */
 
 #endif
diff --git a/pigs.c b/pigs.c
index 7115304de646cc61607aad5111864f9b33a54866..4cd84c2c5aca0cd34026ae80dc1ce2863fd41178 100644 (file)
--- a/pigs.c
+++ b/pigs.c
@@ -26,11 +26,12 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 7+
+This version is for pigpio version 11+
 */
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/socket.h>
@@ -42,10 +43,26 @@ This version is for pigpio version 7+
 #include "command.h"
 
 /*
-This program provides a socket interface
-to the commands available from pigpio.
+This program provides a socket interface to some of
+the commands available from pigpio.
 */
 
+void fatal(char *fmt, ...)
+{
+   char buf[128];
+   va_list ap;
+
+   va_start(ap, fmt);
+   vsnprintf(buf, sizeof(buf), fmt, ap);
+   va_end(ap);
+
+   fprintf(stderr, "%s\n", buf);
+
+   fflush(stderr);
+
+   exit(EXIT_FAILURE);
+}
+
 static int openSocket(void)
 {
    int sock, err;
@@ -88,9 +105,10 @@ static int openSocket(void)
 
 int main(int argc , char *argv[])
 {
-   int sock, r, idx;
+   int sock, r, idx, i;
    cmdCmd_t cmd;
-   char buf[128];
+   gpioExtent_t ext[3];
+   char buf[1024];
 
    sock = openSocket(); 
 
@@ -113,31 +131,48 @@ int main(int argc , char *argv[])
             sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
             break;
 
+         case 5:
+            sprintf(buf, "%10s %10s %10s %10s",
+               argv[1], argv[2], argv[3], argv[4]);
+            break;
+
+         case 6:
+            sprintf(buf, "%10s %10s %10s %10s %10s",
+               argv[1], argv[2], argv[3], argv[4], argv[5]);
+            break;
+
          default:
-            cmdFatal("what?");
+            fatal("what? 'pigs h' for help");
       }
 
-      if ((idx=cmdParse(buf, &cmd)) >= 0)
+      if ((idx=cmdParse(buf, &cmd, argc, argv, ext)) >= 0)
       {
          if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
          {
+            /* send extensions */
+
+            for (i=0; i<cmdInfo[idx].ext; i++)
+            {
+               send(sock, ext[i].ptr, ext[i].n, 0);
+            }
+
             if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
             {
                switch (cmdInfo[idx].rv)
                {
                   case 0:
                      r = cmd.res;
-                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
                      break;
 
                   case 1:
                      r = cmd.res;
-                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
                      break;
 
                   case 2:
                      r = cmd.res;
-                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
                      else printf("%d\n", r);
                      break;
 
@@ -154,13 +189,13 @@ int main(int argc , char *argv[])
                      break;
                }
             }
-            else cmdFatal("recv failed, %m");
+            else fatal("recv failed, %m");
          }
-         else cmdFatal("send failed, %m");
+         else fatal("send failed, %m");
       }
-      else cmdFatal("what?");
+      else fatal("what? 'pigs h' for help");
    }
-   else cmdFatal("connect failed, %m");
+   else fatal("connect failed, %m");
 
    close(sock);
 
index 9cdab1440bdbbc90f31e6fe6e6f23f5d9c516daf..270786bdd4d3d4f64fe7401ef479d2b0906dae6a 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name='pigpio',
-      version='1.1',
+      version='1.2',
       author='joan',
       author_email='joan@abyz.me.uk',
       maintainer='joan',
@@ -11,7 +11,7 @@ setup(name='pigpio',
       url='http://abyz.co.uk/rpi/pigpio/python.html/',
       description='Raspberry Pi gpio module',
       long_description='Raspberry Pi Python module for access to the pigpio daemon',
-      download_url='http://abyz.co.uk/rpi/pigpio/pigpio.tar',
+      download_url='http://abyz.co.uk/rpi/pigpio/pigpio.zip',
       license='TBD',
       py_modules=['pigpio']
      )