V7
authorjoan <joan@abyz.me.uk>
Thu, 12 Dec 2013 10:32:49 +0000 (10:32 +0000)
committerjoan <joan@abyz.me.uk>
Thu, 12 Dec 2013 10:32:49 +0000 (10:32 +0000)
Makefile
README
command.c
command.h
pigpio.c
pigpio.h
pigpio.py [new file with mode: 0644]
pigpiod.c
pigs.c
setup.py [new file with mode: 0644]

index 2b69494d9d197263279f8cf75abb443190b3b4b0..8684ac6dd2347f27fc2105f91bcd8e498c9192c3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,9 @@ SIZE    = size
 
 CFLAGS = -O3 -Wall
 
-all:   libpigpio.a checklib demolib pig2vcd pigpiod pigs
+ALL     = libpigpio.a checklib demolib pig2vcd pigpiod pigs
+
+all:   $(ALL)
 
 checklib:      checklib.o libpigpio.a
        $(CC) -o checklib checklib.c -L. -lpigpio -lpthread -lrt
@@ -19,31 +21,29 @@ pig2vcd:    pig2vcd.o
 pigpiod:       pigpiod.o libpigpio.a
        $(CC) -o pigpiod pigpiod.c -L. -lpigpio -lpthread -lrt
 
-pigs:  pigs.o command.o
+pigs:          command.o
        $(CC) -o pigs pigs.c command.c
 
-.c.o:
-       $(CC) -c $(CFLAGS) $<
-
 clean:
-       rm -f *.o *.i *.s *~ libpigpio.a checklib demolib pigpiod pigs pig2vcd
+       rm -f *.o *.i *.s *~ $(ALL)
 
 install:       $(LIB) 
-       sudo install -m 0755 -d          /usr/local/bin
        sudo install -m 0755 -d          /usr/local/include
+       sudo install -m 0644 pigpio.h    /usr/local/include
        sudo install -m 0755 -d          /usr/local/lib
+       sudo install -m 0644 libpigpio.a /usr/local/lib
+       sudo install -m 0755 -d          /usr/local/bin
        sudo install -m 0755 pig2vcd     /usr/local/bin
        sudo install -m 0755 pigpiod     /usr/local/bin
        sudo install -m 0755 pigs        /usr/local/bin
-       sudo install -m 0644 pigpio.h    /usr/local/include
-       sudo install -m 0644 libpigpio.a /usr/local/lib
+       sudo python setup.py install
 
 uninstall:
+       sudo rm -f /usr/local/include/pigpio.h
+       sudo rm -f /usr/local/lib/libpigpio.a
        sudo rm -f /usr/local/bin/pig2vcd
        sudo rm -f /usr/local/bin/pigpiod
        sudo rm -f /usr/local/bin/pigs
-       sudo rm -f /usr/local/include/pigpio.h
-       sudo rm -f /usr/local/lib/libpigpio.a
 
 LIB     = libpigpio.a
 OBJ     = pigpio.o command.o
@@ -53,11 +53,13 @@ $(LIB):     $(OBJ)
        $(RANLIB) $(LIB)
        $(SIZE)   $(LIB)
 
+# generated using gcc -M *.c
 
-# DO NOT DELETE
+checklib.o: checklib.c pigpio.h
+command.o: command.c pigpio.h command.h
+demolib.o: demolib.c pigpio.h
+pig2vcd.o: pig2vcd.c pigpio.h
+pigpio.o: pigpio.c pigpio.h command.h
+pigpiod.o: pigpiod.c pigpio.h command.h
+pigs.o: pigs.c pigpio.h command.h
 
-checklib.o:    checklib.c pigpio.h
-demolib.o:     demolib.c pigpio.h
-pig2vcd:       pigpio.h
-pigpiod:       pigpiod.c pigpio.h
-pigs:          pigs.c command.c pigpio.h command.h
diff --git a/README b/README
index 41c00cb25fd09f83e0dc726d312d696e21c02570..b673035a0d179cca72b1d124f379ed3d59106245 100644 (file)
--- a/README
+++ b/README
@@ -15,6 +15,7 @@ This will install:
    the daemon (pigpiod) in /usr/local/bin
    the socket interface (pigs) in /usr/local/bin
    the utility pig2vcd in /usr/local/bin
+   the Python module pigpio.py
 
 TEST
 
@@ -22,8 +23,8 @@ To test the library do
 
 sudo ./checklib
 
-checklib.c, demolib.c, pig2vcd.c, pigpiod.c, and pigs.c  show examples
-of interfacing with the library.
+checklib.c, demolib.c, pig2vcd.c, pigpiod.c, pigs.c, and pigpio.py
+show examples of interfacing with the library.
 
 DAEMON
 
@@ -59,9 +60,30 @@ cat /dev/pigerr &
 
 echo "help" >/dev/pigpio
 
+PYTHON INTERFACE
+
+If the pigpiod daemon is running you can test the Python
+interface by entering the following commands.
+
+python
+
+import pigpio
+
+pigpio.start()
+
+print(pigpio.get_current_tick())
+
+print(hex(pigpio.read_bank_1()))
+
+pigpio.stop()
+
+help(pigpio)
+
+quit()
+
 STOP DAEMON
 
-To stop the daemon
+To stop the pigpiod daemon
 
 sudo killall pigpiod
 
index ab46aa8273a98c4924c46f34e86c846c5d95deda..c3eba859c696ee3b4b5e899af6947eab6c4a3b40 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 4+
+This version is for pigpio version 7+
 */
 
 #include <stdio.h>
@@ -141,7 +141,7 @@ static errInfo_t errInfo[]=
    {PI_BAD_CLK_SOURCE   , "clock source not 0-1"},
    {PI_BAD_CLK_MICROS   , "clock micros not 1, 2, 4, 5, 8, or 10"},
    {PI_BAD_BUF_MILLIS   , "buf millis not 100-10000"},
-   {PI_BAD_DUTY_RANGE   , "dutycycle range not 25-40000"},
+   {PI_BAD_DUTYRANGE    , "dutycycle range not 25-40000"},
    {PI_BAD_SIGNUM       , "signum not 0-63"},
    {PI_BAD_PATHNAME     , "can't open pathname"},
    {PI_NO_HANDLE        , "no handle available"},
@@ -159,7 +159,8 @@ static errInfo_t errInfo[]=
    {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"},
 };
 
 static char * fmtMdeStr="RW540123";
@@ -289,4 +290,3 @@ char * cmdErrStr(int error)
    }
    return "unknown error";
 }
-
index 9d2da7d95f585139eafede625af3a586e03d28b1..6ace8c725705ecb364d05999e4f3dbd4436fc21d 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 3+
+This version is for pigpio version 7+
 */
 
 #ifndef COMMAND_H
@@ -39,10 +39,10 @@ This version is for pigpio version 3+
 
 typedef struct
 {
-   int    cmd;
-   char * name;
-   int    vt;
-   int    rv;
+   int    cmd;  /* command number            */
+   char * name; /* command name              */
+   int    vt;   /* command verification type */
+   int    rv;   /* command return value type */
 } cmdInfo_t;
 
 extern cmdInfo_t cmdInfo[];
index c577ced817a5059060a856975c6b04c86b16f4e9..5b721b83fd1d26e5452ea88f52645657a9a71759 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 6 */
+/* pigpio version 7 */
 
 #include <stdio.h>
 #include <string.h>
@@ -229,6 +229,13 @@ bit 0 READ_LAST_NOT_SET_ERROR
    }                                                               \
    while (0)
 
+#define PERM_ERROR(format, arg...)                                 \
+   do                                                              \
+   {                                                               \
+      fprintf(stderr, "%s " format "\n", myTimeStamp(), ## arg);   \
+   }                                                               \
+   while (0)
+
 #define TIMER_ADD(a, b, result)                                    \
    do                                                              \
    {                                                               \
@@ -519,8 +526,6 @@ bit 0 READ_LAST_NOT_SET_ERROR
 #define PI_WFRX_SERIAL 1
 #define PI_WF_MICROS   2
 
-#define PI_WAVE_MAX_PULSES 3000
-
 #define DATUMS 2000
 
 #define DEFAULT_PWM_IDX 5
@@ -704,12 +709,16 @@ static volatile gpioCfg_t gpioCfg =
 
 static volatile gpioStats_t gpioStats;
 
+static int gpioMaskSet = 0;
+
 /* initialise every gpioInitialise */
 
 static struct timespec libStarted;
 
 /* initialse if not libInitialised */
 
+static uint64_t gpioMask;
+
 static gpioPulse_t wf[3][PI_WAVE_MAX_PULSES];
 
 static int wfc[3]={0, 0, 0};
@@ -732,7 +741,6 @@ static volatile uint32_t notifyBits   = 0;
 static volatile int DMAstarted = 0;
 
 static int      libInitialised   = 0;
-static unsigned hardwareRevision = 0;
 
 static int pthAlertRunning  = 0;
 static int pthFifoRunning   = 0;
@@ -947,6 +955,7 @@ static uint32_t myGetTick(int pos)
 static void myDoCommand(cmdCmd_t * cmd)
 {
    int p1, p2, res;
+   uint32_t mask;
 
    p1  = cmd->p1;
    p2  = cmd->p2;
@@ -956,7 +965,12 @@ static void myDoCommand(cmdCmd_t * cmd)
    switch (cmd->cmd)
    {
       case PI_CMD_MODES:
-         res = gpioSetMode(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetMode(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioSetMode: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_MODEG:
@@ -964,7 +978,12 @@ static void myDoCommand(cmdCmd_t * cmd)
          break;
 
       case PI_CMD_PUD:
-         res = gpioSetPullUpDown(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPullUpDown(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioSetPullUpDown: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_READ:
@@ -972,23 +991,48 @@ static void myDoCommand(cmdCmd_t * cmd)
          break;
 
       case PI_CMD_WRITE:
-         res = gpioWrite(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioWrite(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioWrite: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_PWM:
-         res = gpioPWM(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioPWM(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioPWM: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_PRS:
-         res = gpioSetPWMrange(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMrange(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioSetPWMrange: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_PFS:
-         res = gpioSetPWMfrequency(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMfrequency(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioSetPWMfrequency: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_SERVO:
-         res = gpioServo(p1, p2);
+         if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
+         else
+         {
+            PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
+            res = PI_NOT_PERMITTED;
+         }
          break;
 
       case PI_CMD_WDOG:
@@ -1004,19 +1048,55 @@ static void myDoCommand(cmdCmd_t * cmd)
          break;
 
       case PI_CMD_BC1:
-         gpioWrite_Bits_0_31_Clear(p1);
+         mask = gpioMask;
+
+         res = gpioWrite_Bits_0_31_Clear(p1&mask);
+
+         if ((mask | p1) != mask)
+         {
+            PERM_ERROR("gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
+         }
          break;
 
       case PI_CMD_BC2:
-         gpioWrite_Bits_32_53_Clear(p1);
+         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_BS1:
-         gpioWrite_Bits_0_31_Set(p1);
+         mask = gpioMask;
+
+         res = gpioWrite_Bits_0_31_Set(p1&mask);
+
+         if ((mask | p1) != mask)
+         {
+            PERM_ERROR("gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
+               p1, mask);
+            res = PI_SOME_PERMITTED;
+         }
          break;
 
       case PI_CMD_BS2:
-         gpioWrite_Bits_32_53_Set(p1);
+         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_TICK:
@@ -1274,7 +1354,7 @@ static void waveCbOPrint(int pos)
 
    p = waveCbVOadr(pos);
 
-   fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx",
+   fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n",
       p->info, p->src, p->dst, p->length, p->stride, p->next);
 }
 
@@ -1669,7 +1749,7 @@ static void dmaCbPrint(int pos)
 
    p = dmaCB2adr(pos);
 
-   fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx",
+   fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n",
       p->info, p->src, p->dst, p->length, p->stride, p->next);
 }
 
@@ -1962,13 +2042,15 @@ static void sigHandler(int signum)
 
             DBG(DBG_USER, "Debug level %d\n", gpioCfg.dbgLevel);
          }
+         else if (signum == SIGPIPE)
+         {
+            DBG(DBG_USER, "SIGPIPE received");
+         }
          else
          {
-            /* close library safely and exit */
-
-            DBG(DBG_USER, "Unhandled signal %d, terminating\n", signum);
+            /* exit */
 
-            gpioTerminate();
+            DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
 
             exit(-1);
          }
@@ -1976,11 +2058,9 @@ static void sigHandler(int signum)
    }
    else
    {
-      /* close library safely and exit */
+      /* exit */
 
-      DBG(DBG_USER, "Unhandled signal %d, terminating\n", signum);
-
-      gpioTerminate();
+      DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
 
       exit(-1);
    }
@@ -2424,7 +2504,6 @@ static void * pthTimerTick(void *x)
    return 0;
 }
 
-
 /* ----------------------------------------------------------------------- */
 
 
@@ -2465,6 +2544,7 @@ static void * pthFifoThread(void *x)
                break;
 
             case 1:
+               fprintf(outFifo, "%d\n", cmd.res);
                break;
 
             case 2:
@@ -2860,7 +2940,7 @@ static int initDMAcbs(void)
    /* allocate memory for pointers to virtual and physical pages */
 
    dmaBloc = mmap(
-       0, (bufferBlocks+1)*sizeof(dmaPage_t *),
+       0, (bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
        PROT_READ|PROT_WRITE,
        MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
        -1, 0);
@@ -2869,7 +2949,7 @@ static int initDMAcbs(void)
       SOFT_ERROR(PI_INIT_FAILED, "mmap dma virtual failed (%m)");
 
    dmaVirt = mmap(
-       0, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *),
+       0, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
        PROT_READ|PROT_WRITE,
        MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
        -1, 0);
@@ -2878,7 +2958,7 @@ static int initDMAcbs(void)
       SOFT_ERROR(PI_INIT_FAILED, "mmap dma virtual failed (%m)");
 
    dmaPhys = mmap(
-       0, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *),
+       0, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
        PROT_READ|PROT_WRITE,
        MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
        -1, 0);
@@ -2901,7 +2981,7 @@ static int initDMAcbs(void)
    if (pagemapFd < 0)
       SOFT_ERROR(PI_INIT_FAILED, "open pagemap failed(%m)");
 
-   for (i=0; i<(bufferBlocks+1); i++) initDMAblock(pagemapFd, i);
+   for (i=0; i<(bufferBlocks+PI_WAVE_BLOCKS); i++) initDMAblock(pagemapFd, i);
 
    close(pagemapFd);
 
@@ -2918,7 +2998,10 @@ static int initDMAcbs(void)
    dmaInitCbs();
 
    if (gpioCfg.dbgLevel >= DBG_DMACBS)
+   {
+      fprintf(stderr, "*** INPUT DMA CONTROL BLOCKS ***\n");
       for (i=0; i<NUM_CBS; i++) dmaCbPrint(i);
+   }
 
    return 0;
 }
@@ -3132,7 +3215,6 @@ static void initClearGlobals(void)
 
    libInitialised   = 0;
    DMAstarted       = 0;
-   hardwareRevision = 0;
 
    pthAlertRunning  = 0;
    pthFifoRunning   = 0;
@@ -3224,37 +3306,6 @@ static void initClearGlobals(void)
 
 /* ----------------------------------------------------------------------- */
 
-static unsigned initHardwareRevision(void)
-{
-   FILE * filp;
-   unsigned rev;
-   char buf[512];
-   char term;
-
-   rev = 0;
-
-   filp = fopen ("/proc/cpuinfo", "r");
-
-   if (filp != NULL)
-   {
-      while (fgets(buf, sizeof(buf), filp) != NULL)
-      {
-         if (!strncasecmp("revision\t", buf, 9))
-         {
-            if (sscanf(buf+strlen(buf)-5, "%x%c", &rev, &term) == 2)
-            {
-               if (term == '\n') break;
-               rev = 0;
-            }
-         }
-      }
-      fclose(filp);
-   }
-   return rev;
-}
-
-/* ----------------------------------------------------------------------- */
-
 static void initReleaseResources(void)
 {
    int i;
@@ -3299,7 +3350,7 @@ static void initReleaseResources(void)
    /* release mmap'd memory */
 
    if (clkReg  != MAP_FAILED) munmap((void *)clkReg,  CLK_LEN);
-   if (dmaReg  != MAP_FAILED) munmap((void *)dmaReg,   DMA_LEN);
+   if (dmaReg  != MAP_FAILED) munmap((void *)dmaReg,  DMA_LEN);
    if (gpioReg != MAP_FAILED) munmap((void *)gpioReg, GPIO_LEN);
    if (pcmReg  != MAP_FAILED) munmap((void *)pcmReg,  PCM_LEN);
    if (pwmReg  != MAP_FAILED) munmap((void *)pwmReg,  PWM_LEN);
@@ -3314,36 +3365,36 @@ static void initReleaseResources(void)
 
    if (dmaVirt != MAP_FAILED)
    {
-      for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+1); i++)
+      for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
       {
          munmap(dmaVirt[i], PAGE_SIZE);
       }
 
-      munmap(dmaVirt, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *));
+      munmap(dmaVirt, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
    }
 
    dmaVirt = MAP_FAILED;
 
    if (dmaPhys != MAP_FAILED)
    {
-      for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+1); i++)
+      for (i=0; i<PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS); i++)
       {
          munmap(dmaPhys[i], PAGE_SIZE);
       }
 
-      munmap(dmaPhys, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *));
+      munmap(dmaPhys, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
    }
 
    dmaPhys = MAP_FAILED;
 
    if (dmaBloc != MAP_FAILED)
    {
-      for (i=0; i<(bufferBlocks+1); i++)
+      for (i=0; i<(bufferBlocks+PI_WAVE_BLOCKS); i++)
       {
          munmap(dmaBloc[i], PAGES_PER_BLOCK*PAGE_SIZE);
       }
 
-      munmap(dmaBloc, (bufferBlocks+1)*sizeof(dmaPage_t *));
+      munmap(dmaBloc, (bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *));
    }
 
    dmaBloc = MAP_FAILED;
@@ -3403,6 +3454,17 @@ int gpioInitialise(void)
    if (fdLock < 0)
       SOFT_ERROR(PI_INIT_FAILED, "Can't lock %s", PI_LOCKFILE);
 
+   if (!gpioMaskSet)
+   {
+      i = gpioHardwareRevision();
+
+      if      (i == 0) gpioMask = PI_DEFAULT_UPDATE_MASK_R0;
+      else if (i <  4) gpioMask = PI_DEFAULT_UPDATE_MASK_R1;
+      else             gpioMask = PI_DEFAULT_UPDATE_MASK_R2;
+
+      gpioMaskSet = 1;
+   }
+
    sigSetHandler();
 
    if (initPeripherals() < 0) return PI_INIT_FAILED;
@@ -3450,8 +3512,6 @@ int gpioInitialise(void)
       pthSocketRunning = 1;
    }
 
-   hardwareRevision = initHardwareRevision();
-
    initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIPhys[0]);
 
    return PIGPIO_VERSION;
@@ -3465,6 +3525,7 @@ void gpioTerminate(void)
 
    DBG(DBG_USER, "");
 
+   gpioMaskSet = 0;
 
    if (libInitialised)
    {
@@ -3716,7 +3777,7 @@ int gpioSetPWMrange(unsigned gpio, unsigned range)
       SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
 
    if ((range < PI_MIN_DUTYCYCLE_RANGE)  || (range > PI_MAX_DUTYCYCLE_RANGE))
-      SOFT_ERROR(PI_BAD_DUTY_RANGE, "gpio %d, bad range (%d)", gpio, range);
+      SOFT_ERROR(PI_BAD_DUTYRANGE, "gpio %d, bad range (%d)", gpio, range);
 
    oldWidth = gpioInfo[gpio].width;
 
@@ -4247,7 +4308,10 @@ int gpioWaveTxStart(unsigned mode)
    cb = wave2Cbs(mode);
 
    if (gpioCfg.dbgLevel >= DBG_SLOW_TICK)
+   {
+      fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n");
       for (i=0; i<cb; i++) waveCbOPrint(i);
+   }
 
    initDMAgo((uint32_t *)dmaOut, (uint32_t)dmaOPhys[0]);
 
@@ -4899,11 +4963,34 @@ uint32_t gpioTick(void)
 
 unsigned gpioHardwareRevision(void)
 {
+   static unsigned rev = 0;
+
+   FILE * filp;
+   char buf[512];
+   char term;
+
    DBG(DBG_USER, "");
 
-   CHECK_INITED;
+   if (rev) return rev;
+
+   filp = fopen ("/proc/cpuinfo", "r");
 
-   return hardwareRevision;
+   if (filp != NULL)
+   {
+      while (fgets(buf, sizeof(buf), filp) != NULL)
+      {
+         if (!strncasecmp("revision\t", buf, 9))
+         {
+            if (sscanf(buf+strlen(buf)-5, "%x%c", &rev, &term) == 2)
+            {
+               if (term == '\n') break;
+               rev = 0;
+            }
+         }
+      }
+      fclose(filp);
+   }
+   return rev;
 }
 
 
@@ -4994,6 +5081,22 @@ int gpioCfgDMAchannels(unsigned primaryChannel, unsigned secondaryChannel)
 }
 
 
+/*-------------------------------------------------------------------------*/
+
+int gpioCfgPermissions(uint64_t updateMask)
+{
+   DBG(DBG_USER, "gpio update mask=%llX", updateMask);
+
+   CHECK_NOT_INITED;
+
+   gpioMask = updateMask;
+
+   gpioMaskSet = 1;
+
+   return 0;
+}
+
+
 /* ----------------------------------------------------------------------- */
 
 int gpioCfgInterfaces(unsigned ifFlags)
index aa958927e085d3ff8e4bb750df4f3df397241a60..ce7b8b2045fdcf0c59758fdc169ba28aeab58bd9 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 6
+This version is for pigpio version 7
 */
 
 #ifndef PIGPIO_H
@@ -82,7 +82,7 @@ This version is for pigpio version 6
 
 #include <stdint.h>
 
-#define PIGPIO_VERSION 6
+#define PIGPIO_VERSION 7
 
 /*-------------------------------------------------------------------------*/
 
@@ -175,7 +175,9 @@ gpioHardwareRevision       Get hardware version.
 
 gpioCfgBufferSize          Configure the gpio sample buffer size.
 gpioCfgClock               Configure the gpio sample rate.
-gpioCfgDMAchannel          Configure the DMA channel.
+gpioCfgDMAchannel          Configure the DMA channel (DEPRECATED).
+gpioCfgDMAchannels         Configure the DMA channels.
+gpioCfgPermissions         Configure the gpio access permissions.
 gpioCfgInterfaces          Configure user interfaces.
 gpioCfgSocketPort          Configure socket port.
 
@@ -482,7 +484,7 @@ int gpioSetPWMrange(unsigned user_gpio,
    to gpioPWM will use a dutycycle between 0 (off) and range (fully on).
 
    Returns the real range for the given gpio's frequency if OK,
-   otherwise PI_BAD_USER_GPIO or PI_BAD_DUTY_RANGE.
+   otherwise PI_BAD_USER_GPIO or PI_BAD_DUTYRANGE.
 
    EXAMPLE:
    ...
@@ -892,9 +894,12 @@ int gpioWaveAddSerial(unsigned user_gpio,
    the same waveform.
 */
 
+#define PI_WAVE_BLOCKS     3
+#define PI_WAVE_MAX_PULSES (PI_WAVE_BLOCKS * 3000)
+#define PI_WAVE_MAX_CHARS  (PI_WAVE_BLOCKS *  256)
+
 #define PI_WAVE_MIN_BAUD      100
 #define PI_WAVE_MAX_BAUD      250000
-#define PI_WAVE_MAX_CHARS     256
 
 
 
@@ -1601,7 +1606,7 @@ int gpioCfgClock(unsigned micros,
 
 
 /*-------------------------------------------------------------------------*/
-int gpioCfgDMAchannel(unsigned channel);
+int gpioCfgDMAchannel(unsigned channel); /* DEPRECATED */
 /*-------------------------------------------------------------------------*/
 /* Configures pigpio to use the specified DMA channel.
 
@@ -1622,7 +1627,7 @@ int gpioCfgDMAchannels(unsigned primaryChannel,
 /* Configures pigpio to use the specified DMA channels.
 
    The default setting is to use channel 14 for the primary channel and
-   channel 6 for the secondary channel.
+   channel 5 for the secondary channel.
 */
 
 #define PI_MAX_PRIMARY_CHANNEL   14
@@ -1630,6 +1635,18 @@ int gpioCfgDMAchannels(unsigned primaryChannel,
 
 
 
+/*-------------------------------------------------------------------------*/
+int gpioCfgPermissions(uint64_t updateMask);
+/*-------------------------------------------------------------------------*/
+/* Configures pigpio to only allow updates (writes or mode changes) for the
+   gpios specified by the mask.
+
+   The default setting is to allow updates to gpios 0-31, i.e. an update mask
+   of 0x00000000FFFFFFFF.
+*/
+
+
+
 /*-------------------------------------------------------------------------*/
 int gpioCfgSocketPort(unsigned port);
 /*-------------------------------------------------------------------------*/
@@ -1746,7 +1763,8 @@ after this command is issued.
 #define PI_BAD_CLK_SOURCE   -18 /* clock source not 0-1                    */
 #define PI_BAD_CLK_MICROS   -19 /* clock micros not 1, 2, 4, 5, 8, or 10   */
 #define PI_BAD_BUF_MILLIS   -20 /* buf millis not 100-10000                */
-#define PI_BAD_DUTY_RANGE   -21 /* dutycycle range not 25-40000            */
+#define PI_BAD_DUTYRANGE    -21 /* dutycycle range not 25-40000            */
+#define PI_BAD_DUTY_RANGE   -21 /* DEPRECATED (use PI_BAD_DUTYRANGE)       */
 #define PI_BAD_SIGNUM       -22 /* signum not 0-63                         */
 #define PI_BAD_PATHNAME     -23 /* can't open pathname                     */
 #define PI_NO_HANDLE        -24 /* no handle available                     */
@@ -1767,6 +1785,8 @@ after this command is issued.
 #define PI_NOT_SERIAL_GPIO  -38 /* no serial read in progress on gpio      */
 #define PI_BAD_SERIAL_STRUC -39 /* bad null serial structure parameter     */
 #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         */
 
 
 /*-------------------------------------------------------------------------*/
@@ -1778,8 +1798,12 @@ after this command is issued.
 #define PI_DEFAULT_IF_FLAGS              0
 #define PI_DEFAULT_DMA_CHANNEL           14
 #define PI_DEFAULT_DMA_PRIMARY_CHANNEL   14
-#define PI_DEFAULT_DMA_SECONDARY_CHANNEL 6
+#define PI_DEFAULT_DMA_SECONDARY_CHANNEL 5
 #define PI_DEFAULT_SOCKET_PORT           8888
+#define PI_DEFAULT_SOCKET_PORT_STR       "8888"
+#define PI_DEFAULT_SOCKET_ADDR_STR       "127.0.0.1"
+#define PI_DEFAULT_UPDATE_MASK_R0        0xFBE6CF9F
+#define PI_DEFAULT_UPDATE_MASK_R1        0x03E6CF93
+#define PI_DEFAULT_UPDATE_MASK_R2        0xFBC6CF9C
 
 #endif
-
diff --git a/pigpio.py b/pigpio.py
new file mode 100644 (file)
index 0000000..d4e7894
--- /dev/null
+++ b/pigpio.py
@@ -0,0 +1,1591 @@
+"""
+pigpio is a Python module for the Raspberry Pi which allows control
+of the general purpose input outputs (gpios).
+
+There are 54 gpios in total, arranged in two banks. Bank 1 contains
+gpios 0-31. Bank 2 contains gpios 32-54.
+
+Most of the gpios are dedicated to system use.
+
+A user should only manipulate gpios in bank 1.
+
+For a Rev.1 board only use gpios 0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17,
+18, 21, 22, 23, 24, 25.
+
+For a Rev.2 board only use gpios 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17,
+18, 22, 23, 24, 25, 27, 28, 29, 30, 31.
+
+It is safe to read all the gpios. If you try to write a system gpio or
+change its mode you can crash the Pi or corrupt the data on the SD card.
+
+Features
+
+The pigpio module's main features are:
+
+- provision of PWM on any number of gpios 0-31 simultaneously.
+
+- provision of servo pulses on any number of gpios 0-31 simultaneously.
+
+- callbacks when any of gpios 0-31 change state.
+
+- reading/writing gpios and setting their modes (typically input
+  or output).
+
+- reading/writing all of the gpios in a bank (0-31, 32-53) as a single
+  operation.
+
+Notes
+
+ALL gpios are identified by their Broadcom number.
+
+This module uses the services of the C pigpio library.  That library
+must be running on the Pi whose gpios are to be manipulated.
+
+The normal way to start the library is as a daemon (during system
+start).
+
+sudo pigpiod
+
+Your Python program should wrap the use of the module up in calls
+to pigpio.start() and pigpio.stop().
+
+Settings
+
+A number of settings are determined when the pigpiod daemon is started.
+
+- the sample rate (1, 2, 4, 5, 8, or 10us, default 5us).
+
+- the set of gpios which may be updated (generally written to).  The
+  default set is those listed above for the Rev.1 or Rev.2 boards.
+
+- the available PWM frequencies (see set_PWM_frequency()).
+
+Exceptions
+
+By default a fatal exception is raised if you pass an invalid
+argument to a pigpio function.
+
+If you wish to handle the returned status yourself you should set
+pigpio.exceptions = False.
+
+"""
+import socket
+import struct
+import time
+import threading
+import os
+import atexit
+
+VERSION = "1.0"
+
+# gpio levels
+
+OFF   = 0
+LOW   = 0
+CLEAR = 0
+
+ON   = 1
+HIGH = 1
+SET  = 1
+
+TIMEOUT = 2
+
+# gpio edges
+
+EITHER_EDGE  = 0
+RISING_EDGE  = 1
+FALLING_EDGE = 2
+
+# gpio modes
+
+INPUT  = 0
+OUTPUT = 1
+ALT0   = 4
+ALT1   = 5
+ALT2   = 6
+ALT3   = 7
+ALT4   = 3
+ALT5   = 2
+
+# gpio Pull Up Down
+
+PUD_OFF  = 0
+PUD_DOWN = 1
+PUD_UP   = 2
+
+# pigpio command numbers
+
+_PI_CMD_MODES= 0
+_PI_CMD_MODEG= 1
+_PI_CMD_PUD=   2
+_PI_CMD_READ=  3
+_PI_CMD_WRITE= 4
+_PI_CMD_PWM=   5
+_PI_CMD_PRS=   6
+_PI_CMD_PFS=   7
+_PI_CMD_SERVO= 8
+_PI_CMD_WDOG=  9
+_PI_CMD_BR1=  10
+_PI_CMD_BR2=  11
+_PI_CMD_BC1=  12
+_PI_CMD_BC2=  13
+_PI_CMD_BS1=  14
+_PI_CMD_BS2=  15
+_PI_CMD_TICK= 16
+_PI_CMD_HWVER=17
+_PI_CMD_NO=   18
+_PI_CMD_NB=   19
+_PI_CMD_NP=   20
+_PI_CMD_NC=   21
+_PI_CMD_PRG=  22
+_PI_CMD_PFG=  23
+_PI_CMD_PRRG= 24
+_PI_CMD_NOIB= 99
+
+# pigpio error numbers
+
+_PI_INIT_FAILED     =-1
+PI_BAD_USER_GPIO    =-2
+PI_BAD_GPIO         =-3
+PI_BAD_MODE         =-4
+PI_BAD_LEVEL        =-5
+PI_BAD_PUD          =-6
+PI_BAD_PULSEWIDTH   =-7
+PI_BAD_DUTYCYCLE    =-8
+_PI_BAD_TIMER       =-9
+_PI_BAD_MS          =-10
+_PI_BAD_TIMETYPE    =-11
+_PI_BAD_SECONDS     =-12
+_PI_BAD_MICROS      =-13
+_PI_TIMER_FAILED    =-14
+PI_BAD_WDOG_TIMEOUT =-15
+_PI_NO_ALERT_FUNC   =-16
+_PI_BAD_CLK_PERIPH  =-17
+_PI_BAD_CLK_SOURCE  =-18
+_PI_BAD_CLK_MICROS  =-19
+_PI_BAD_BUF_MILLIS  =-20
+PI_BAD_DUTYRANGE    =-21
+_PI_BAD_SIGNUM      =-22
+_PI_BAD_PATHNAME    =-23
+PI_NO_HANDLE        =-24
+PI_BAD_HANDLE       =-25
+_PI_BAD_IF_FLAGS    =-26
+_PI_BAD_CHANNEL     =-27
+_PI_BAD_PRIM_CHANNEL=-27
+_PI_BAD_SOCKET_PORT =-28
+_PI_BAD_FIFO_COMMAND=-29
+_PI_BAD_SECO_CHANNEL=-30
+_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_NOT_SERIAL_GPIO =-38
+_PI_BAD_SERIAL_STRUC=-39
+_PI_BAD_SERIAL_BUF  =-40
+PI_NOT_PERMITTED    =-41
+PI_SOME_PERMITTED   =-42
+
+# pigpio error text
+
+_errors=[
+   [_PI_INIT_FAILED      , "pigpio initialisation failed"],
+   [PI_BAD_USER_GPIO     , "gpio not 0-31"],
+   [PI_BAD_GPIO          , "gpio not 0-53"],
+   [PI_BAD_MODE          , "mode not 0-7"],
+   [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_TIMER        , "timer not 0-9"],
+   [_PI_BAD_MS           , "ms not 10-60000"],
+   [_PI_BAD_TIMETYPE     , "timetype not 0-1"],
+   [_PI_BAD_SECONDS      , "seconds < 0"],
+   [_PI_BAD_MICROS       , "micros not 0-999999"],
+   [_PI_TIMER_FAILED     , "gpioSetTimerFunc failed"],
+   [PI_BAD_WDOG_TIMEOUT  , "timeout not 0-60000"],
+   [_PI_NO_ALERT_FUNC    , "DEPRECATED"],
+   [_PI_BAD_CLK_PERIPH   , "clock peripheral not 0-1"],
+   [_PI_BAD_CLK_SOURCE   , "clock source not 0-1"],
+   [_PI_BAD_CLK_MICROS   , "clock micros not 1, 2, 4, 5, 8, or 10"],
+   [_PI_BAD_BUF_MILLIS   , "buf millis not 100-10000"],
+   [PI_BAD_DUTYRANGE     , "dutycycle range not 25-40000"],
+   [_PI_BAD_SIGNUM       , "signum not 0-63"],
+   [_PI_BAD_PATHNAME     , "can't open pathname"],
+   [PI_NO_HANDLE         , "no handle available"],
+   [PI_BAD_HANDLE        , "unknown notify handle"],
+   [_PI_BAD_IF_FLAGS     , "ifFlags > 3"],
+   [_PI_BAD_CHANNEL      , "DMA channel not 0-14"],
+   [_PI_BAD_SOCKET_PORT  , "socket port not 1024-30000"],
+   [_PI_BAD_FIFO_COMMAND , "unknown fifo command"],
+   [_PI_BAD_SECO_CHANNEL , "DMA secondary channel not 0-6"],
+   [_PI_NOT_INITIALISED  , "function called before gpioInitialise"],
+   [_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_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"]
+]
+
+_control = None
+_notify  = None
+
+_host = ''
+_port = 8888
+
+exceptions = True
+
+class _pigpioError(Exception):
+   """pigpio module exception"""
+   def __init__(self, value):
+      self.value = value
+   def __str__(self):
+      return repr(self.value)
+
+def error(pigpio_error):
+   """Converts a pigpio error number to a text description.
+
+   pigpio_error: an error number (<0) returned by pigpio.
+
+   Example
+   ...
+   print(pigpio.error(-5))
+   level not 0-1
+   ...
+   """
+   for e in _errors:
+      if e[0] == pigpio_error:
+         return e[1]
+   return "unknown error"
+
+def tickDiff(tStart, tEnd):
+   """Calculate the time difference between two ticks.
+
+   tStart: the earlier tick.
+   tEnd:   the later tick.
+
+   The function handles wrap around as the tick overflows 32 bits.
+
+   The returned value is in microseconds.
+
+   Example
+   ...
+   print(pigpio.tickDiff(4294967272, 12))
+   36
+   ...
+   """
+   tDiff = tEnd - tStart
+   if tDiff < 0:
+      tDiff += (1 << 32)
+   return tDiff
+
+def _u2i(number):
+   """Converts a number from unsigned to signed.
+
+   number: a 32 bit unsigned number
+   """
+   mask = (2 ** 32) - 1
+   if number & (1 << 31):
+      v = number | ~mask
+   else:
+      v = number & mask
+   if v >= 0:
+      return v;
+   else:
+      if exceptions:
+         raise _pigpioError(error(v))
+      else:
+         return v
+
+def _pigpio_command(sock, cmd, p1, p2):
+   """Executes a pigpio socket command.
+
+   sock: command socket.
+   cmd:  the command to be executed.
+   p1:   command paramter 1 (if applicable).
+   p2:   command paramter 2 (if applicable).
+   """
+   if sock is not None:
+      sock.send(struct.pack('IIII', cmd, p1, p2, 0))
+      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."""
+
+   def __init__(self, gpio, edge, func):
+      """Initialises a callback ADT.
+
+      gpio: Broadcom gpio number.
+      edge: EITHER_EDGE, RISING_EDGE, or FALLING_EDGE.
+      func: a user function taking three arguments (gpio, level, tick).
+      """
+      self.gpio = gpio
+      self.edge = edge
+      self.func = func
+      self.bit = 1<<gpio
+
+class _callback_thread(threading.Thread):
+   """A class to encapsulate pigpio notification callbacks."""
+   def __init__(self):
+      """Initialises notifications."""
+      threading.Thread.__init__(self)
+      self.daemon = True
+      self.monitor = 0
+      self.callbacks = []
+      self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+      self.sock.connect((_host,_port))
+      self.handle = _pigpio_command(self.sock, _PI_CMD_NOIB, 0, 0)
+      self.start()
+
+   def stop(self):
+      """Stops notifications."""
+      if self.go:
+         self.go = False
+         self.sock.send(struct.pack('IIII', _PI_CMD_NC, self.handle, 0, 0))
+
+   def append(self, callb):
+      """Adds a callback to the notification thread.
+
+      callb:
+      """
+      self.callbacks.append(callb)
+      self.monitor = self.monitor | callb.bit
+      notify_begin(self.handle, self.monitor)
+
+   def remove(self, callb):
+      """Removes a callback from the notification thread.
+
+      callb:
+      """
+      if callb in self.callbacks:
+         self.callbacks.remove(callb)
+         newMonitor = 0
+         for c in self.callbacks:
+            newMonitor |= c.bit
+         if newMonitor != self.monitor:
+            self.monitor = newMonitor
+            notify_begin(self.handle, self.monitor)
+
+   def run(self):
+      """Execute the notification thread."""
+      self.go = True
+      lastLevel = 0
+      while self.go:
+         seq_no, flags, tick, level = (
+            struct.unpack('HHII', self.sock.recv(12, socket.MSG_WAITALL)))
+         if self.go:
+            if flags == 0:
+               changed = level ^ lastLevel
+               lastLevel = level
+               for cb in self.callbacks:
+                  if cb.bit & changed:
+                     newLevel = 0
+                     if cb.bit & level:
+                        newLevel = 1
+                     if (cb.edge == EITHER_EDGE or
+                         cb.edge == RISING_EDGE and newLevel == 1 or
+                         cb.edge == FALLING_EDGE and newLevel == 0):
+                         cb.func(cb.gpio, newLevel, tick)
+            else:
+               gpio = flags & 31
+               for cb in self.callbacks:
+                  if cb.gpio == gpio:
+                     cb.func(cb.gpio, TIMEOUT, tick)
+            
+      self.sock.close()
+
+class _wait_for_edge:
+   """A class to encapsulate waiting for gpio edges."""
+
+   def __init__(self, gpio, edge, timeout):
+      """Initialise a wait_for_edge.
+
+      gpio:
+      edge:
+      timeout:
+      """
+      self.callb = _callback(gpio, edge, self.func)
+      self.trigger = False
+      _notify.append(self.callb)
+      self.start = time.time()
+      while (self.trigger == False) and ((time.time()-self.start) < timeout):
+         time.sleep(0.1)
+      _notify.remove(self.callb)
+
+   def func(self, gpio, level, tick):
+      """Set wait_for_edge triggered.
+
+      gpio:
+      level:
+      tick:
+      """
+      self.trigger = True
+
+
+def set_mode(gpio, mode):
+   """Set the gpio mode.
+
+   gpio: 0-53.
+   mode: INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5.
+
+   Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_MODE,
+   or PI_NOT_PERMITTED.
+
+   Notes
+
+   Arduino style: pinMode.
+
+   Example
+   ...
+   pigpio.set_mode(4, pigpio.INPUT) # gpio 4 as input
+   pigpio.set_mode(7, pigpio.OUTPUT) # gpio 7 as output
+   pigpio.set_mode(10, pigpio.ALT2) # gpio 10 as ALT2
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_MODES, gpio, mode))
+   return r
+
+def get_mode(gpio):
+   """Get the gpio mode.
+
+   Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
+
+   gpio: 0-53.
+
+   Example
+   ...
+   print(pigpio.get_mode(4))
+   0
+   print(pigpio.get_mode(7))
+   1
+   print(pigpio.get_mode(10))
+   6
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_MODEG, gpio, 0))
+   return r
+
+def set_pull_up_down(gpio, pud):
+   """Set or clear the gpio pull-up/down resistor.
+
+   Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
+   or PI_NOT_PERMITTED.
+
+   gpio: 0-53.
+   pud:  PUD_UP, PUD_DOWN, PUD_OFF.
+
+   Example
+   ...
+   pigpio.set_mode(23, pigpio.INPUT)
+   pigpio.set_mode(24, pigpio.INPUT)
+
+   pigpio.set_pull_up_down(23, pigpio.PUD_UP)
+   pigpio.set_pull_up_down(24, pigpio.PUD_DOWN)
+
+   print(pigpio.read(23))
+   1
+   print(pigpio.read(24))
+   0
+
+   pigpio.set_pull_up_down(23, pigpio.PUD_DOWN)
+   pigpio.set_pull_up_down(24, pigpio.PUD_UP)
+
+   print(pigpio.read(23))
+   0
+   print(pigpio.read(24))
+   1
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PUD, gpio, pud))
+   return r
+
+def read(gpio):
+   """Read the gpio level.
+
+   Returns the gpio level if OK, otherwise PI_BAD_GPIO.
+
+   gpio:0-53.
+
+   Notes
+
+   Arduino style: digitalRead.
+
+   Example
+   ...
+   pigpio.set_mode(25, pigpio.INPUT)
+
+   pigpio.set_pull_up_down(25, pigpio.PUD_DOWN)
+
+   print(pigpio.read(25))
+   0
+
+   pigpio.set_pull_up_down(25, pigpio.PUD_UP)
+
+   print(pigpio.read(25))
+   1
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_READ, gpio, 0))
+   return r
+
+def write(gpio, level):
+   """Write the gpio level.
+
+   Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_LEVEL,
+   or PI_NOT_PERMITTED.
+
+   gpio:  0-53.
+   level: 0, 1.
+
+   Notes
+
+   If PWM or servo pulses are active on the gpio they are switched off.
+
+   Arduino style: digitalWrite
+
+   Example
+   ...
+   pigpio.set_mode(11, pigpio.OUTPUT)
+
+   pigpio.write(11,0)
+
+   print(pigpio.read(11))
+   0
+
+   pigpio.write(11,1)
+
+   print(pigpio.read(11))
+   1
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_WRITE, gpio, level))
+   return r
+
+def set_PWM_dutycycle(user_gpio, dutycycle):
+   """Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
+   or PI_NOT_PERMITTED.
+
+   user_gpio: 0-31.
+   dutycycle: 0-range (range defaults to 255).
+
+   Notes
+
+   Arduino style: analogWrite
+
+   This and the servo functionality use the DMA and PWM or PCM
+   peripherals to control and schedule the pulse lengths and
+   duty cycles.
+
+   The set_PWM_range() function can change the default range of 255.
+
+   Example
+   ...
+   set_PWM_dutycycle(4,   0) # PWM off
+   set_PWM_dutycycle(4,  64) # PWM 1/4 on
+   set_PWM_dutycycle(4, 128) # PWM 1/2 on
+   set_PWM_dutycycle(4, 192) # PWM 3/4 on
+   set_PWM_dutycycle(4, 255) # PWM full on
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PWM, user_gpio, dutycycle))
+   return r
+
+def set_PWM_range(user_gpio, range_):
+   """Set the range of PWM values to be used on the gpio.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
+   or PI_NOT_PERMITTED.
+
+   user_gpio: 0-31.
+   range_:    25-40000.
+
+   Notes
+
+   If PWM is currently active on the gpio its dutycycle will be
+   scaled to reflect the new range.
+
+   The real range, the number of steps between fully off and fully on
+   for each of the 18 available gpio frequencies is
+
+   25(#1), 50(#2), 100(#3), 125(#4), 200(#5), 250(#6), 400(#7),
+   500(#8), 625(#9), 800(#10), 1000(#11), 1250(#12), 2000(#13),
+   2500(#14), 4000(#15), 5000(#16), 10000(#17), 20000(#18)
+
+   The real value set by set_PWM_range is
+   (dutycycle * real range) / range.
+
+   Example
+   ...
+   pigpio.set_PWM_range(9, 100) # now 25 1/4, 50 1/2, 75 3/4 on
+
+   pigpio.set_PWM_range(9, 500) # now 125 1/4, 250 1/2, 375 3/4 on
+
+   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
+
+def get_PWM_range(user_gpio):
+   """Get the range of PWM values being used on the gpio.
+
+   Returns the dutycycle range used for the gpio if OK,
+   otherwise PI_BAD_USER_GPIO.
+
+   user_gpio: 0-31.
+
+   Example
+   ...
+   print(pigpio.get_PWM_range(9))
+   255
+
+   pigpio.set_PWM_range(9, 100)
+   print(pigpio.get_PWM_range(9))
+   100
+
+   pigpio.set_PWM_range(9, 500)
+   print(pigpio.get_PWM_range(9))
+   500
+
+   pigpio.set_PWM_range(9, 3000)
+   print(pigpio.get_PWM_range(9))
+   3000
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PRG, user_gpio, 0))
+   return r
+
+def get_PWM_real_range(user_gpio):
+   """Get the real underlying range of PWM values being used on the gpio.
+
+   Returns the real range used for the gpio if OK,
+   otherwise PI_BAD_USER_GPIO.
+
+   user_gpio: 0-31.
+
+   Example
+   ...
+   pigpio.set_PWM_frequency(4,0)
+
+   print(pigpio.get_PWM_real_range(4))
+   20000
+
+   pigpio.set_PWM_frequency(4,800)
+   print(pigpio.get_PWM_real_range(4))
+   250
+
+   pigpio.set_PWM_frequency(4,100000)
+   print(pigpio.get_PWM_real_range(4))
+   25
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PRRG, user_gpio, 0))
+   return r
+
+def set_PWM_frequency(user_gpio, frequency):
+   """Set the frequency (in Hz) of the PWM to be used on the gpio.
+
+   Returns the numerically closest frequency if OK, otherwise
+   PI_BAD_USER_GPIO or PI_NOT_PERMITTED.
+
+   user_gpio: 0-31.
+   frequency: 0- (Hz).
+
+   The selectable frequencies depend upon the sample rate which
+   may be 1, 2, 4, 5, 8, or 10 microseconds (default 5).  The
+   sample rate is set when the C pigpio library is started.
+
+   Each gpio can be independently set to one of 18 different
+   PWM frequencies.
+
+   If PWM is currently active on the gpio it will be switched
+   off and then back on at the new frequency.
+
+   1us 40000, 20000, 10000, 8000, 5000, 4000, 2500, 2000, 1600,
+       1250, 1000, 800, 500, 400, 250, 200, 100, 50
+
+   2us 20000, 10000,  5000, 4000, 2500, 2000, 1250, 1000, 800,
+       625, 500, 400, 250, 200, 125, 100, 50, 25
+
+   4us 10000, 5000, 2500, 2000, 1250, 1000, 625, 500, 400,
+       313, 250, 200, 125, 100, 63, 50, 25, 13
+
+   5us 8000, 4000, 2000, 1600, 1000, 800, 500, 400, 320,
+       250, 200, 160, 100, 80, 50, 40, 20, 10
+
+   8us 5000, 2500, 1250, 1000, 625, 500, 313, 250, 200,
+       156, 125, 100, 63, 50, 31, 25, 13, 6
+
+   10us 4000, 2000, 1000, 800, 500, 400, 250, 200, 160,
+        125, 100, 80, 50, 40, 25, 20, 10, 5
+
+   Example
+   ...
+   pigpio.set_PWM_frequency(4,0)
+
+   print(pigpio.get_PWM_frequency(4))
+   10
+
+   pigpio.set_PWM_frequency(4,800)
+
+   print(pigpio.get_PWM_frequency(4))
+   800
+
+   pigpio.set_PWM_frequency(4,100000)
+
+   print(pigpio.get_PWM_frequency(4))
+   8000
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PFS, user_gpio, frequency))
+   return r
+
+def get_PWM_frequency(user_gpio):
+   """Get the frequency of PWM being used on the gpio.
+
+   Returns the frequency (in hertz) used for the gpio if OK,
+   otherwise PI_BAD_USER_GPIO.
+
+   user_gpio: 0-31.
+
+   Example
+   ...
+   pigpio.set_PWM_frequency(4,0)
+
+   print(pigpio.get_PWM_frequency(4))
+   10
+
+   pigpio.set_PWM_frequency(4,800)
+
+   print(pigpio.get_PWM_frequency(4))
+   800
+
+   pigpio.set_PWM_frequency(4,100000)
+
+   print(pigpio.get_PWM_frequency(4))
+   8000
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_PFG, user_gpio, 0))
+   return r
+
+def set_servo_pulsewidth(user_gpio, pulsewidth):
+   """Start (500-2500) or stop (0) servo pulses on the gpio.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_PULSEWIDTH or
+   PI_NOT_PERMITTED.
+
+   user_gpio:  0-31.
+   pulsewidth: 0 (off), 500 (most anti-clockwise) - 2500 (most clockwise).
+
+   The selected pulsewidth will continue to be transmitted until
+   changed by a subsequent call to set_servo_pulsewidth().
+
+   The pulsewidths supported by servos varies and should probably be
+   determined by experiment. A value of 1500 should always be safe and
+   represents the mid-point of rotation.
+
+   You can DAMAGE a servo if you command it to move beyond its limits.
+
+   OTHER UPDATE RATES:
+
+   This function updates servos at 50Hz.  If you wish to use a different
+   update frequency you will have to use the PWM functions.
+
+   Update Rate (Hz) 50   100  200  400  500
+   1E6/Hz        20000 10000 5000 2500 2000
+
+   Firstly set the desired PWM frequency using set_PWM_frequency().
+
+   Then set the PWM range using set_PWM_range() to 1E6/Hz.
+   Doing this allows you to use units of microseconds when setting
+   the servo pulse width.
+
+   E.g. If you want to update a servo connected to gpio 25 at 400Hz
+
+   set_PWM_frequency(25, 400)
+   set_PWM_range(25, 2500)
+
+   Thereafter use the set_PWM_dutycycle() function to move the servo,
+   e.g. set_PWM_dutycycle(25, 1500) will set a 1500 us pulse. 
+
+   Example 1: standard 50 Hz hobby servo updates
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   moves = [[1000, 5],[1200,3],[1500,2],[2000,5],[1000,0]]
+
+   pigpio.start()
+
+   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)
+
+   pigpio.stop()
+
+   will print lines
+
+   5 seconds @ 1000 us
+   3 seconds @ 1200 us
+   2 seconds @ 1500 us
+   5 seconds @ 2000 us
+   0 seconds @ 1000 us
+
+   Example 2: 400 Hz ESC type servo updates
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   moves = [[1000, 5],[1200,3],[1500,2],[2000,5],[1000,0]]
+
+   pigpio.start()
+
+   pigpio.set_PWM_frequency(25, 400)
+   pigpio.set_PWM_range(25, 2500)
+
+   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)
+
+   pigpio.stop()
+
+   will print lines
+
+   5 seconds @ 1000 us
+   3 seconds @ 1200 us
+   2 seconds @ 1500 us
+   5 seconds @ 2000 us
+   0 seconds @ 1000 us
+"""
+   r=_u2i(_pigpio_command(_control, _PI_CMD_SERVO, user_gpio, pulsewidth))
+   return r
+
+def notify_open():
+   """Get a free notification handle.
+
+   Returns a handle greater than or equal to zero if OK,
+   otherwise PI_NO_HANDLE.
+
+   A notification is a method for being notified of gpio state
+   changes via a pipe.
+
+   Pipes are only accessible from the local machine so this function
+   serves no purpose if you are using Python from a remote machine.
+   The in-built (socket) notifications provided by callback()
+   should be used instead.
+
+   Notifications for handle x will be available at the pipe
+   named /dev/pigpiox (where x is the handle number).
+   E.g. if the function returns 15 then the notifications must be
+   read from /dev/pigpio15.
+
+   Example
+   ...
+   h = pigpio.notify_open()
+   if h >= 0:
+      pigpio.notify_begin(h, 1234)
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0))
+   return r
+
+def notify_begin(handle, bits):
+   """Start notifications on a previously opened handle.
+
+   Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+   handle: 0-31 (as returned by notify_open())
+   bits:   a mask indicating the gpios to be notified.
+
+   The notification sends state changes for each gpio whose
+   corresponding bit in bits is set.
+
+   Example
+   ...
+   h = pigpio.notify_open()
+   if h >= 0:
+      pigpio.notify_begin(h, 1234)
+   ...
+
+   This will start notifications for gpios 1, 4, 6, 7, 10
+   (1234 = 0x04D2 = 0b0000010011010010).
+
+   Notes
+
+   Each notification occupies 12 bytes in the fifo as follows:
+
+   H (16 bit) seqno
+   H (16 bit) flags
+   I (32 bit) tick
+   I (32 bit) level
+
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits))
+   return r
+
+def notify_pause(handle):
+   """Pause notifications on a previously opened handle.
+
+   Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+   handle: 0-31 (as returned by notify_open())
+
+   Notifications for the handle are suspended until
+   notify_begin() is called again.
+
+   Example
+   ...
+   h = pigpio.notify_open()
+   if h >= 0:
+      pigpio.notify_begin(h, 1234)
+      ...
+      pigpio.notify_pause(h)
+      ...
+      pigpio.notify_begin(h, 1234)
+      ...
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0))
+   return r
+
+def notify_close(handle):
+   """Stop notifications on a previously opened handle and
+   release the handle for reuse.
+
+   Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+   handle: 0-31 (as returned by notify_open())
+
+   Example
+   ...
+   h = pigpio.notify_open()
+   if h >= 0:
+      pigpio.notify_begin(h, 1234)
+      ...
+      pigpio.notify_close(h)
+      ...
+   ...
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0))
+   return r
+
+def set_watchdog(user_gpio, timeout):
+   """Sets a watchdog for a gpio.
+
+   Returns 0 if OK, otherwise PI_BAD_USER_GPIO
+   or PI_BAD_WDOG_TIMEOUT.
+
+   user_gpio: 0-31.
+   timeout:   0-60000.
+
+   The watchdog is nominally in milliseconds.
+
+   Only one watchdog may be registered per gpio.
+
+   The watchdog may be cancelled by setting timeout to 0.
+
+   If no level change has been detected for the gpio for timeout
+   milliseconds any notification for the gpio has a report written
+   to the fifo with the flags set to indicate a watchdog timeout.
+
+   The callback() class interprets the flags and will
+   call registered callbacks for the gpio with level TIMEOUT.
+
+   Example
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   def cbf(g, L, t):
+      message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
+      print(message)
+
+   pigpio.start()
+
+   cb = pigpio.callback(22, pigpio.EITHER_EDGE, cbf)
+
+   print("callback started, 5 second delay")
+
+   time.sleep(5)
+
+   pigpio.set_watchdog(22, 1000) # 1000ms watchdog
+
+   print("watchdog started, 5 second delay")
+
+   time.sleep(5)
+
+   pigpio.set_watchdog(22, 0) # cancel watchdog
+
+   print("watchdog cancelled, 5 second delay")
+
+   time.sleep(5)
+
+   cb.cancel()
+
+   pigpio.stop()
+
+   will print lines such as
+
+   callback started, 5 second delay
+   watchdog started, 5 second delay
+   gpio=22 level=2 at 3547411617
+   gpio=22 level=2 at 3548411254
+   gpio=22 level=2 at 3549411927
+   gpio=22 level=2 at 3550412060
+   gpio=22 level=2 at 3551411622
+   watchdog cancelled, 5 second delay
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout))
+   return r
+
+def read_bank_1():
+   """Read the levels of the bank 1 gpios (gpios 0-31).
+
+   The returned 32 bit integer has a bit set if the corresponding
+   gpio is logic 1.  Gpio n has bit value (1<<n).
+
+   Example
+   ...
+   print(bin(pigpio.read_bank_1()))
+   0b10010100000011100100001001111
+   ...
+   """
+   return _pigpio_command(_control, _PI_CMD_BR1, 0, 0)
+
+def read_bank_2():
+   """Read the levels of the bank 2 gpios (gpios 32-53).
+
+   The returned 32 bit integer has a bit set if the corresponding
+   gpio is logic 1.  Gpio n has bit value (1<<(n-32)).
+
+   Example
+   ...
+   print(bin(pigpio.read_bank_2()))
+   0b1111110000000000000000
+   ...
+   """
+   return _pigpio_command(_control, _PI_CMD_BR2, 0, 0)
+
+def clear_bank_1(levels):
+   """Clears gpios 0-31 if the corresponding bit in levels is set.
+
+   Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+   A status of PI_SOME_PERMITTED indicates that the user is not
+   allowed to write to one or more of the gpios.
+
+   levels: a bit mask with 1 set if the corresponding gpio is
+           to be cleared.
+
+   Example
+
+   #!/usr/bin/python
+
+   import pigpio
+
+   pigpio.start()
+
+   pigpio.set_mode(4,  pigpio.OUTPUT)
+   pigpio.set_mode(7,  pigpio.OUTPUT)
+   pigpio.set_mode(8,  pigpio.OUTPUT)
+   pigpio.set_mode(9,  pigpio.OUTPUT)
+   pigpio.set_mode(10, pigpio.OUTPUT)
+   pigpio.set_mode(11, pigpio.OUTPUT)
+
+   pigpio.set_bank_1(int("111110010000",2))
+
+   # 0x1000 is added so that all numbers are aligned
+
+   b1 = (pigpio.read_bank_1() & 0xFFF) + 0x1000
+   print(bin(b1))
+
+   pigpio.clear_bank_1(int("111110010000",2))
+
+   b2 = (pigpio.read_bank_1() & 0xFFF) + 0x1000
+   print(bin(b2))
+
+   print(bin((b1^b2) + 0x1000))
+
+   pigpio.stop()
+
+   displays
+
+   0b1111111011111
+   0b1000001001111
+   0b1111110010000
+
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_BC1, levels, 0))
+   return r
+
+def clear_bank_2(levels):
+   """Clears gpios 32-53 if the corresponding bit (0-21) in levels is set.
+
+   Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+   A status of PI_SOME_PERMITTED indicates that the user is not
+   allowed to write to one or more of the gpios.
+
+   levels: a bit mask with 1 set if the corresponding gpio is
+           to be cleared.
+
+   See clear_bank_1() for an example.
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_BC2, levels, 0))
+   return r
+
+def set_bank_1(levels):
+   """Sets gpios 0-31 if the corresponding bit in levels is set.
+
+   Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+   A status of PI_SOME_PERMITTED indicates that the user is not
+   allowed to write to one or more of the gpios.
+
+   levels: a bit mask with 1 set if the corresponding gpio is
+           to be set.
+
+   Example
+
+   #!/usr/bin/python
+
+   import pigpio
+
+   pigpio.start()
+
+   pigpio.set_mode(4,  pigpio.OUTPUT)
+   pigpio.set_mode(7,  pigpio.OUTPUT)
+   pigpio.set_mode(8,  pigpio.OUTPUT)
+   pigpio.set_mode(9,  pigpio.OUTPUT)
+   pigpio.set_mode(10, pigpio.OUTPUT)
+   pigpio.set_mode(11, pigpio.OUTPUT)
+
+   pigpio.clear_bank_1(int("111110010000",2))
+
+   # 0x1000 is added so that all numbers are aligned
+
+   b1 = (pigpio.read_bank_1() & 0xFFF) + 0x1000
+   print(bin(b1))
+
+   pigpio.set_bank_1(int("111110010000",2))
+
+   b2 = (pigpio.read_bank_1() & 0xFFF) + 0x1000
+   print(bin(b2))
+
+   print(bin((b1^b2) + 0x1000))
+
+   pigpio.stop()
+
+   displays
+
+   0b1000001001111
+   0b1111111011111
+   0b1111110010000
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_BS1, levels, 0))
+   return r
+
+def set_bank_2(levels):
+   """Sets gpios 32-53 if the corresponding bit (0-21) in levels is set.
+
+   Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+   A status of PI_SOME_PERMITTED indicates that the user is not
+   allowed to write to one or more of the gpios.
+
+   levels: a bit mask with 1 set if the corresponding gpio is
+           to be set.
+
+   See set_bank_1() for an example.
+   """
+   r=_u2i(_pigpio_command(_control, _PI_CMD_BS2, levels, 0))
+   return r
+
+def get_current_tick():
+   """Gets the current system tick.
+
+   Tick is the number of microseconds since system boot.
+
+   As tick is an unsigned 32 bit quantity it wraps around after
+   2**32 microseconds, which is approximately 1 hour 12 minutes.
+
+   Example
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   pigpio.start()
+
+   t1 = pigpio.get_current_tick()
+
+   time.sleep(5)
+
+   t2 = pigpio.get_current_tick()
+
+   message = "5 seconds is " + str(pigpio.tickDiff(t1, t2)) + " ticks"
+
+   print(message) 
+
+   pigpio.stop()
+
+   displays
+
+   5 seconds is 5003398 ticks
+   """
+   return _pigpio_command(_control, _PI_CMD_TICK, 0, 0)
+
+def get_hardware_revision():
+   """Get the Pi's hardware revision number.
+
+   It is unfortunate that Pi boards have been named Revision.1 and
+   Revision.2.  That use of the word revision is distinct from the
+   Pi's hardware revision number.'
+
+   The hardware revision is the last 4 characters on the Revision line
+   of /proc/cpuinfo.
+
+   The revision number can be used to determine the assignment of gpios
+   to pins.
+
+   There are at least two types of board.
+
+   Type 1 has gpio 0 on P1-3, gpio 1 on P1-5, and gpio 21 on P1-13.
+   Type 2 has gpio 2 on P1-3, gpio 3 on P1-5, gpio 27 on P1-13, and
+   gpios 28-31 on P5.
+
+   Type 1 boards have hardware revision numbers of 2 and 3.
+
+   Type 2 boards have hardware revision numbers of 4, 5, 6, and 15.
+
+   If the hardware revision can not be found or is not a valid
+   hexadecimal number the function returns 0.
+
+   Example 1:
+   ...
+   print(pigpio.get_hardware_revision())
+   2
+   ...
+   Example 2:
+
+   for "Revision : 0002" the function returns 2.
+   for "Revision : 000f" the function returns 15.
+   for "Revision : 000g" the function returns 0.
+   """
+   return _pigpio_command(_control, _PI_CMD_HWVER, 0, 0)
+
+class callback:
+   """A class to provide gpio level change callbacks."""
+
+   def __init__(self, user_gpio, edge=RISING_EDGE, func=None):
+      """Initialise a callback and adds it to the notification thread.
+
+      user_gpio: 0-31.
+      edge:      EITHER_EDGE, RISING_EDGE (default), or FALLING_EDGE.
+      func:      user supplied callback function.
+
+      If a user callback is not specified a default tally callback is
+      provided which simply counts edges.
+
+      The user supplied callback receives three parameters, the gpio,
+      the level, and the tick.
+
+      Example 1: user supplied edge and callback
+
+      #!/usr/bin/python
+
+      import pigpio
+      import time
+
+      def cbf(g, L, t):
+         message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
+         print(message)
+
+      pigpio.start()
+
+      cb = pigpio.callback(22, pigpio.EITHER_EDGE, cbf)
+
+      time.sleep(30)
+
+      cb.cancel()
+
+      pigpio.stop()
+
+      will print lines such as
+
+      gpio=22 level=1 at 548556842
+      gpio=22 level=0 at 551316679
+      gpio=22 level=1 at 553411795
+      gpio=22 level=0 at 555269219
+      gpio=22 level=1 at 557689701
+
+      Example 2: user supplied edge, default (tally) callback
+
+      #!/usr/bin/python
+
+      import pigpio
+      import time
+
+      pigpio.start()
+
+      pigpio.set_PWM_dutycycle(4, 0)
+
+      pigpio.set_PWM_frequency(4, 2000)
+
+      cb = pigpio.callback(4, pigpio.EITHER_EDGE)
+
+      pigpio.set_PWM_dutycycle(4, 128) # half power
+
+      tally_1 = cb.tally()
+
+      time.sleep(50)
+
+      tally_2 = cb.tally()
+
+      message = "counted " + str(tally_2 - tally_1) + " edges"
+
+      print(message)
+
+      cb.cancel()
+
+      pigpio.stop()
+
+      will print a line such as
+
+      counted 200200 edges
+
+      Example 3: default edge and (tally) callback
+
+      #!/usr/bin/python
+
+      import pigpio
+      import time
+
+      pigpio.start()
+
+      pigpio.set_PWM_dutycycle(17, 0)
+
+      pigpio.set_PWM_frequency(17, 2000)
+
+      cb = pigpio.callback(17)
+
+      pigpio.set_PWM_dutycycle(17, 64) # quarter power
+
+      tally_1 = cb.tally()
+
+      time.sleep(50)
+
+      tally_2 = cb.tally()
+
+      message = "counted " + str(tally_2 - tally_1) + " rising edges"
+
+      print(message)
+
+      cb.cancel()
+
+      pigpio.stop()
+
+      will print a line such as
+
+      counted 100101 rising edges
+
+      """
+      self.count=0
+      if func is None:
+         func=self._tally
+      self.callb = _callback(user_gpio, edge, func)
+      _notify.append(self.callb)
+
+   def cancel(self):
+      """Cancels a callback by removing it from the notification thread."""
+      _notify.remove(self.callb)
+
+   def _tally(self, user_gpio, level, tick):
+      """Increment the callback called count.
+
+      user_gpio:
+      level:
+      tick:
+      """
+      self.count += 1
+
+   def tally(self):
+      """Provides a count of how many times the default tally
+      callback has triggered.
+
+      The count will be zero if the user has supplied their own
+      callback function.
+      """
+      return self.count
+
+
+def wait_for_edge(user_gpio, edge=RISING_EDGE, timeout=60.0):
+   """Wait for an edge event on a gpio.
+
+   The function returns as soon as the edge is detected
+   or after the number of seconds specified by timeout has
+   expired.
+
+   user_gpio: 0-31.
+   edge:      EITHER_EDGE, RISING_EDGE (default), or FALLING_EDGE.
+   timeout:   0.0- (default 60.0).
+
+   The function returns True if the edge is detected,
+   otherwise False.
+
+   Example 1: default edge and timeout
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   pigpio.start()
+
+   if pigpio.wait_for_edge(23):
+      print("Rising edge detected")
+   else:
+      print("wait for edge timed out")
+
+   pigpio.stop()
+
+   will print
+
+   Rising edge detected
+
+   or
+
+   wait for edge timed out
+
+   Example 2: user supplied edge and timeout
+
+   #!/usr/bin/python
+
+   import pigpio
+   import time
+
+   pigpio.start()
+
+   if pigpio.wait_for_edge(23, pigpio.FALLING_EDGE, 5.0):
+      print("Falling edge detected")
+   else:
+      print("wait for falling edge timed out")
+
+   pigpio.stop()
+
+
+   will print
+
+   Falling edge detected
+
+   or
+
+   wait for falling edge timed out
+
+   """
+   a = _wait_for_edge(user_gpio, edge, timeout)
+   return a.trigger
+
+def start(host = os.getenv("PIGPIO_ADDR", ''),
+          port = os.getenv("PIGPIO_PORT", 8888)):
+   """Start the pigpio module.
+
+   host: the host name of the Pi on which the pigpio daemon is running.
+         The default is localhost unless overwritten by the PIGPIO_ADDR
+         environment variable.
+   port: the port number on which the pigpio daemon is listening.
+         The default is 8888 unless overwritten by the PIGPIO_PORT
+         environment variable.  The pigpiod must have been started
+         with the same port number.
+
+   The function connects to the pigpio daemon and reserves resources
+   to be used for sending commands and receiving notifications.
+
+   EXAMPLES:
+   ...
+   pigpio.start() # use defaults
+
+   pigpio.start('mypi') # specify host, default port
+
+   pigpio.start('mypi', 7777) # specify host and port
+   ...
+   """
+
+   global _control, _notify
+   global _host, _port
+
+   _host = host
+   _port = int(port)
+
+   _control = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+   try:
+      _control.connect((_host, _port))
+      _notify = _callback_thread()
+   except socket.error:
+      if _control is not None:
+         _control = None
+      if _host == '':
+         h = "localhost"
+      else:
+         h = _host
+      errStr = "Can't connect to pigpio on " + str(h) + "(" + str(_port) + ")"
+      print("********************************************************")
+      print(errStr)
+      print("")
+      print("Did you start the pigpio daemon?")
+      print("(sudo pigpiod)")
+      print("")
+      print("Did you specify the correct Pi host/port in the environment")
+      print("variables PIGPIO_ADDR/PIGPIO_PORT?")
+      print("(e.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888)")
+      print("")
+      print("Did you specify the correct Pi host/port in the")
+      print("pigpio.start() function")
+      print("(e.g. pigpio.start('soft', 8888))")
+      print("********************************************************")
+      raise
+
+def stop():
+   """Release pigpio resources.
+
+   Example
+   ...
+   pigpio.stop()
+   ...
+   """
+   global _control, _notify
+
+   if _notify is not None:
+      _notify.stop()
+      _notify = None
+
+   if _control is not None:
+      _control.close()
+      _control = None
+
+atexit.register(stop)
+
index 106354b6bfb54517041170083bd942262dda2899..3d45548bac2ec23bb96640f21bff24704a96b077 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 4+
+This version is for pigpio version 7+
 */
 
 #include <sys/types.h>
@@ -54,8 +54,10 @@ static unsigned clockMicros            = PI_DEFAULT_CLK_MICROS;
 static unsigned clockPeripheral        = PI_DEFAULT_CLK_PERIPHERAL;
 static unsigned clockSource            = PI_DEFAULT_CLK_SOURCE;
 static unsigned ifFlags                = PI_DEFAULT_IF_FLAGS;
-static unsigned DMAchannelChannel      = PI_DEFAULT_DMA_CHANNEL;
+static unsigned DMAprimaryChannel      = PI_DEFAULT_DMA_PRIMARY_CHANNEL;
+static unsigned DMAsecondaryChannel    = PI_DEFAULT_DMA_SECONDARY_CHANNEL;
 static unsigned socketPort             = PI_DEFAULT_SOCKET_PORT;
+static uint64_t updateMask             = -1;
 
 static FILE * errFifo;
 
@@ -64,13 +66,15 @@ void usage()
    fprintf(stderr, "\n" \
       "Usage: sudo pigpiod [OPTION] ...\n" \
       "   -b value, gpio sample buffer in milliseconds, default 120\n" \
-      "   -d value, DMA channel, 0-14,                  default 14\n" \
+      "   -d value, primary DMA channel, 0-14,          default 14\n" \
+      "   -e value, secondary DMA channel, 0-6,         default 5\n" \
       "   -f,       disable fifo interface,             default enabled\n" \
       "   -k,       disable socket interface,           default enabled\n" \
       "   -p value, socket port, 1024-32000,            default 8888\n" \
       "   -s value, sample rate, 1, 2, 4, 5, 8, or 10,  default 5\n" \
       "   -t value, clock peripheral, 0=PWM 1=PCM,      default PCM\n" \
       "   -u value, clock source, 0=OSC 1=PLLD,         default PLLD\n" \
+      "   -x mask,  gpios which may be updated,         default 0xFFFFFFFF\n" \
       "EXAMPLE\n" \
       "sudo pigpiod -s 2 -b 200 -f\n" \
       "  Set a sample rate of 2 microseconds with a 200 millisecond\n" \
@@ -81,8 +85,10 @@ void usage()
 static void initOpts(int argc, char *argv[])
 {
    int i, opt;
+   uint64_t mask;
+   char * endptr;
 
-   while ((opt = getopt(argc, argv, "b:d:fkp:s:t:u:")) != -1)
+   while ((opt = getopt(argc, argv, "b:d:e:fkp:s:t:u:x:")) != -1)
    {
       i = -1;
 
@@ -97,11 +103,18 @@ static void initOpts(int argc, char *argv[])
 
          case 'd':
             i = atoi(optarg);
-            if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_DMA_CHANNEL))
-               DMAchannelChannel = i;
+            if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL))
+               DMAprimaryChannel = i;
             else cmdFatal("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);
+            break;
+
          case 'f':
             ifFlags |= PI_DISABLE_FIFO_IF;
             break; 
@@ -151,6 +164,13 @@ static void initOpts(int argc, char *argv[])
             else cmdFatal("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);
+            break;
+
         default: /* '?' */
            usage();
            exit(-1);
@@ -224,10 +244,12 @@ int main(int argc, char **argv)
 
    gpioCfgInterfaces(ifFlags);
 
-   gpioCfgDMAchannel(DMAchannelChannel);
+   gpioCfgDMAchannels(DMAprimaryChannel, DMAsecondaryChannel);
 
    gpioCfgSocketPort(socketPort);
 
+   if (updateMask != -1) gpioCfgPermissions(updateMask);
+
    /* start library */
 
    if (gpioInitialise()< 0) cmdFatal("Can't initialise pigpio library");
@@ -275,4 +297,3 @@ int main(int argc, char **argv)
 
    return 0;
 }
-
diff --git a/pigs.c b/pigs.c
index e794632db4c3e6cd7a65b1274633790a71e1e7d5..7115304de646cc61607aad5111864f9b33a54866 100644 (file)
--- a/pigs.c
+++ b/pigs.c
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 3+
+This version is for pigpio version 7+
 */
 
 #include <stdio.h>
@@ -34,6 +34,8 @@ This version is for pigpio version 3+
 #include <string.h>
 #include <unistd.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <netdb.h>
 #include <arpa/inet.h>
 
 #include "pigpio.h"
@@ -44,100 +46,123 @@ This program provides a socket interface
 to the commands available from pigpio.
 */
 
-int main(int argc , char *argv[])
+static int openSocket(void)
 {
-   int sock, r, idx, port;
-   struct sockaddr_in server;
-   cmdCmd_t cmd;
-   char * portStr, * addrStr;
-   char buf[128];
-   sock = socket(AF_INET, SOCK_STREAM, 0);
-   if (sock != -1)
+   int sock, err;
+   struct addrinfo hints, *res, *rp;
+   const char *addrStr, *portStr;
+
+   portStr = getenv(PI_ENVPORT);
+
+   if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
+
+   addrStr = getenv(PI_ENVADDR);
+
+   if (!addrStr) addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
+
+   memset (&hints, 0, sizeof (hints));
+
+   hints.ai_family   = PF_UNSPEC;
+   hints.ai_socktype = SOCK_STREAM;
+   hints.ai_flags   |= AI_CANONNAME;
+
+   err = getaddrinfo(addrStr, portStr, &hints, &res);
+
+   if (err) return -1;
+
+   for (rp=res; rp!=NULL; rp=rp->ai_next)
    {
-      portStr = getenv(PI_ENVPORT);
+      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+
+      if (sock == -1) continue;
+
+      if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
+   }
+
+   freeaddrinfo(res);
 
-      if (portStr) port = atoi(portStr);
-      else         port = PI_DEFAULT_SOCKET_PORT;
+   if (rp == NULL) return -1;
 
-      addrStr = getenv(PI_ENVADDR);
+   return sock;
+}
 
-      if (!addrStr) addrStr="127.0.0.1";
+int main(int argc , char *argv[])
+{
+   int sock, r, idx;
+   cmdCmd_t cmd;
+   char buf[128];
 
-      server.sin_addr.s_addr = inet_addr(addrStr);
-      server.sin_family = AF_INET;
-      server.sin_port = htons(port);
+   sock = openSocket(); 
 
-      if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0)
+   if (sock != -1)
+   {
+      switch(argc)
       {
-         switch(argc)
-         {
-            case 1:
-               exit(0);
+         case 1:
+            exit(0);
 
-            case 2:
-               sprintf(buf, "%10s", argv[1]);
-               break;
+         case 2:
+            sprintf(buf, "%10s", argv[1]);
+            break;
 
-            case 3:
-               sprintf(buf, "%10s %10s", argv[1], argv[2]);
-               break;
+         case 3:
+            sprintf(buf, "%10s %10s", argv[1], argv[2]);
+            break;
 
-            case 4:
-               sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
-               break;
+         case 4:
+            sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
+            break;
 
-            default:
-               cmdFatal("what?");
-         }
+         default:
+            cmdFatal("what?");
+      }
 
-         if ((idx=cmdParse(buf, &cmd)) >= 0)
+      if ((idx=cmdParse(buf, &cmd)) >= 0)
+      {
+         if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
          {
-            if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+            if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
             {
-               if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+               switch (cmdInfo[idx].rv)
                {
-                  switch (cmdInfo[idx].rv)
-                  {
-                     case 0:
-                        r = cmd.res;
-                        if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
-                        break;
-
-                     case 1:
-                        break;
-
-                     case 2:
-                        r = cmd.res;
-                        if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
-                        else printf("%d\n", r);
-                        break;
-
-                     case 3:
-                        printf("%08X\n", cmd.res);
-                        break;
-
-                     case 4:
-                        printf("%u\n", cmd.res);
-                        break;
-
-                     case 5:
-                        printf(cmdUsage);
-                        break;
-                  }
+                  case 0:
+                     r = cmd.res;
+                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     break;
+
+                  case 1:
+                     r = cmd.res;
+                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     break;
+
+                  case 2:
+                     r = cmd.res;
+                     if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+                     else printf("%d\n", r);
+                     break;
+
+                  case 3:
+                     printf("%08X\n", cmd.res);
+                     break;
+
+                  case 4:
+                     printf("%u\n", cmd.res);
+                     break;
+
+                  case 5:
+                     printf(cmdUsage);
+                     break;
                }
-               else cmdFatal("recv failed, %m");
             }
-            else cmdFatal("send failed, %m");
+            else cmdFatal("recv failed, %m");
          }
-         else cmdFatal("what?");
+         else cmdFatal("send failed, %m");
       }
-      else cmdFatal("connect failed, %m");
-
-      close(sock);
+      else cmdFatal("what?");
    }
-   else cmdFatal("socket failed, %m");
+   else cmdFatal("connect failed, %m");
+
+   close(sock);
 
    return 0;
 }
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..ceff7d9
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+
+setup(name='pigpio',
+      version='1.0',
+      description='Raspberry Pi gpio utility',
+      author='joan',
+      author_email='joan@abyz.me.uk',
+      url='http://abyz.co.uk/rpi/pigpio/python.html/',
+      py_modules=['pigpio']
+     )