V40
authorjoan <joan@abyz.co.uk>
Tue, 10 Nov 2015 14:57:12 +0000 (14:57 +0000)
committerjoan <joan@abyz.co.uk>
Tue, 10 Nov 2015 14:57:12 +0000 (14:57 +0000)
18 files changed:
MakeRemote
Makefile
README
command.c
pig2vcd.1
pigpio.3
pigpio.c
pigpio.h
pigpio.py
pigpiod.1
pigpiod_if.3
pigpiod_if.h
pigpiod_if2.3 [new file with mode: 0644]
pigpiod_if2.c [new file with mode: 0644]
pigpiod_if2.h [new file with mode: 0644]
pigs.1
setup.py
x_pigpiod_if2.c [new file with mode: 0644]

index 14dd6227818911ba85f5e3f613f732bf41ccdb08..586cbf81452d1e44af7ab6c6b682540605fa1bae 100644 (file)
@@ -4,43 +4,56 @@ SIZE     = size
 SHLIB    = gcc -shared
 STRIPLIB = strip --strip-unneeded
 
-CFLAGS += -O3 -Wall
+CFLAGS += -O3 -Wall -pthread
 
-ALL = libpigpiod_if.so pigs
+ALL = libpigpiod_if.so libpigpiod_if2.so pigs x_pigpiod_if x_pigpiod_if2
 
 all: $(ALL) pigpio.py setup.py
 
 pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h
        $(CC) $(CFLAGS) -fpic -c -o pigpiod_if.o pigpiod_if.c
 
+pigpiod_if2.o: pigpiod_if2.c pigpio.h command.h pigpiod_if2.h
+       $(CC) $(CFLAGS) -fpic -c -o pigpiod_if2.o pigpiod_if2.c
+
 command.o: command.c pigpio.h command.h
        $(CC) $(CFLAGS) -fpic -c -o command.o command.c
 
-
 pigs: command.o pigs.o
        $(CC) $(CFLAGS) -fpic -o pigs pigs.c command.c
 
+x_pigpiod_if:  x_pigpiod_if.o $(LIB1)
+       $(CC) -o x_pigpiod_if x_pigpiod_if.o $(LL1)
+
+x_pigpiod_if2:  x_pigpiod_if2.o $(LIB2)
+       $(CC) -o x_pigpiod_if2 x_pigpiod_if2.o $(LL2)
+
 clean:
        rm -f *.o *.i *.s *~ $(ALL)
 
-install: $(LIB) 
-       install -m 0755 -d              /usr/local/include
-       install -m 0644 pigpio.h        /usr/local/include
-       install -m 0644 pigpiod_if.h    /usr/local/include
-       install -m 0755 -d              /usr/local/lib
-       install -m 0644 libpigpiod_if.so /usr/local/lib
-       install -m 0755 -d              /usr/local/bin
-       install -m 0755 pigs            /usr/local/bin
+install: $(LIB1) $(LIB2)
+       install -m 0755 -d                /usr/local/include
+       install -m 0644 pigpio.h          /usr/local/include
+       install -m 0644 pigpiod_if.h      /usr/local/include
+       install -m 0644 pigpiod_if2.h     /usr/local/include
+       install -m 0755 -d                /usr/local/lib
+       install -m 0644 libpigpiod_if.so  /usr/local/lib
+       install -m 0644 libpigpiod_if2.so /usr/local/lib
+       install -m 0755 -d                /usr/local/bin
+       install -m 0755 pigs              /usr/local/bin
        python2 setup.py install
        python3 setup.py install
-       install -m 0755 -d              /usr/local/man/man1
-       install -m 0644 *.1             /usr/local/man/man1
-       install -m 0755 -d              /usr/local/man/man3
-       install -m 0644 *.3             /usr/local/man/man3
+       install -m 0755 -d                /usr/local/man/man1
+       install -m 0644 *.1               /usr/local/man/man1
+       install -m 0755 -d                /usr/local/man/man3
+       install -m 0644 *.3               /usr/local/man/man3
 
 uninstall:
        rm -f /usr/local/include/pigpio.h
+       rm -f /usr/local/include/pigpiod_if.h
+       rm -f /usr/local/include/pigpiod_if2.h
        rm -f /usr/local/lib/libpigpiod_if.so
+       rm -f /usr/local/lib/libpigpiod_if2.so
        echo removing python2 files
        python2 setup.py install --record /tmp/pigpio >/dev/null
        xargs rm -f < /tmp/pigpio >/dev/null
@@ -51,18 +64,30 @@ uninstall:
        rm -f /usr/local/man/man1/pig*.1
        rm -f /usr/local/man/man3/pig*.3
 
-LIB = libpigpiod_if.so
-OBJ = pigpiod_if.o command.o
+LL1    = -L. -lpigpiod_if -pthread -lrt
+LL2    = -L. -lpigpiod_if2 -pthread -lrt
+
+LIB1 = libpigpiod_if.so
+OBJ1 = pigpiod_if.o command.o
+
+LIB2 = libpigpiod_if2.so
+OBJ2 = pigpiod_if2.o command.o
+
+$(LIB1): $(OBJ1)
+       $(SHLIB) -o $(LIB1) $(OBJ1)
+       $(STRIPLIB) $(LIB1)
+       $(SIZE)     $(LIB1)
 
-$(LIB): $(OBJ)
-       $(SHLIB) -o $(LIB) $(OBJ)
-       $(STRIPLIB) $(LIB)
-       $(SIZE)   $(LIB)
+$(LIB2): $(OBJ2)
+       $(SHLIB) -o $(LIB2) $(OBJ2)
+       $(STRIPLIB) $(LIB2)
+       $(SIZE)     $(LIB2)
 
 # generated using gcc -MM *.c
 
 command.o: command.c pigpio.h command.h
 pigpiod.o: pigpiod.c pigpio.h
 pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h command.h
+pigpiod_if2.o: pigpiod_if2.c pigpio.h pigpiod_if2.h command.h
 pigs.o: pigs.c pigpio.h command.h
 
index bf8155e83a5fb95f0fb535f0ff7dc0298f024097..5a0ba83d9bd5b57b5a03c7886064b97dc54ed572 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ SIZE     = size
 SHLIB    = gcc -shared
 STRIPLIB = strip --strip-unneeded
 
-CFLAGS += -O3 -Wall
+CFLAGS += -O3 -Wall -pthread
 
 LIB1     = libpigpio.so
 OBJ1     = pigpio.o command.o
@@ -14,13 +14,18 @@ OBJ1     = pigpio.o command.o
 LIB2     = libpigpiod_if.so
 OBJ2     = pigpiod_if.o command.o
 
-LIB      = $(LIB1) $(LIB2)
+LIB3     = libpigpiod_if2.so
+OBJ3     = pigpiod_if2.o command.o
 
-ALL     = $(LIB) x_pigpio x_pigpiod_if pig2vcd pigpiod pigs
+LIB      = $(LIB1) $(LIB2) $(LIB3)
 
-LL1      = -L. -lpigpio -lpthread -lrt
+ALL     = $(LIB) x_pigpio x_pigpiod_if x_pigpiod_if2 pig2vcd pigpiod pigs
 
-LL2      = -L. -lpigpiod_if -lpthread -lrt
+LL1      = -L. -lpigpio -pthread -lrt
+
+LL2      = -L. -lpigpiod_if -pthread -lrt
+
+LL3      = -L. -lpigpiod_if2 -pthread -lrt
 
 all:   $(ALL)
 
@@ -30,6 +35,9 @@ pigpio.o: pigpio.c pigpio.h command.h custom.cext
 pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h
        $(CC) $(CFLAGS) -fpic -c -o pigpiod_if.o pigpiod_if.c
 
+pigpiod_if2.o: pigpiod_if2.c pigpio.h command.h pigpiod_if2.h
+       $(CC) $(CFLAGS) -fpic -c -o pigpiod_if2.o pigpiod_if2.c
+
 command.o: command.c pigpio.h command.h
        $(CC) $(CFLAGS) -fpic -c -o command.o command.c
 
@@ -39,6 +47,9 @@ x_pigpio:     x_pigpio.o $(LIB1)
 x_pigpiod_if:  x_pigpiod_if.o $(LIB2)
        $(CC) -o x_pigpiod_if x_pigpiod_if.o $(LL2)
 
+x_pigpiod_if2: x_pigpiod_if2.o $(LIB3)
+       $(CC) -o x_pigpiod_if2 x_pigpiod_if2.o $(LL3)
+
 pigpiod:       pigpiod.o $(LIB1)
        $(CC) -o pigpiod pigpiod.o $(LL1)
 
@@ -52,30 +63,34 @@ clean:
        rm -f *.o *.i *.s *~ $(ALL)
 
 install:       $(ALL)
-       install -m 0755 -d               /opt/pigpio/cgi
-       install -m 0755 -d               /usr/local/include
-       install -m 0644 pigpio.h         /usr/local/include
-       install -m 0644 pigpiod_if.h     /usr/local/include
-       install -m 0755 -d               /usr/local/lib
-       install -m 0755 libpigpio.so     /usr/local/lib
-       install -m 0755 libpigpiod_if.so /usr/local/lib
-       install -m 0755 -d               /usr/local/bin
-       install -m 0755 -s pig2vcd       /usr/local/bin
-       install -m 0755 -s pigpiod       /usr/local/bin
-       install -m 0755 -s pigs          /usr/local/bin
+       install -m 0755 -d                /opt/pigpio/cgi
+       install -m 0755 -d                /usr/local/include
+       install -m 0644 pigpio.h          /usr/local/include
+       install -m 0644 pigpiod_if.h      /usr/local/include
+       install -m 0644 pigpiod_if2.h     /usr/local/include
+       install -m 0755 -d                /usr/local/lib
+       install -m 0755 libpigpio.so      /usr/local/lib
+       install -m 0755 libpigpiod_if.so  /usr/local/lib
+       install -m 0755 libpigpiod_if2.so /usr/local/lib
+       install -m 0755 -d                /usr/local/bin
+       install -m 0755 -s pig2vcd        /usr/local/bin
+       install -m 0755 -s pigpiod        /usr/local/bin
+       install -m 0755 -s pigs           /usr/local/bin
        if which python2; then python2 setup.py install; fi
        if which python3; then python3 setup.py install; fi
-       install -m 0755 -d               /usr/local/man/man1
-       install -m 0644 *.1              /usr/local/man/man1
-       install -m 0755 -d               /usr/local/man/man3
-       install -m 0644 *.3              /usr/local/man/man3
+       install -m 0755 -d                /usr/local/man/man1
+       install -m 0644 *.1               /usr/local/man/man1
+       install -m 0755 -d                /usr/local/man/man3
+       install -m 0644 *.3               /usr/local/man/man3
        ldconfig
 
 uninstall:
        rm -f /usr/local/include/pigpio.h
        rm -f /usr/local/include/pigpiod_if.h
+       rm -f /usr/local/include/pigpiod_if2.h
        rm -f /usr/local/lib/libpigpio.so
        rm -f /usr/local/lib/libpigpiod_if.so
+       rm -f /usr/local/lib/libpigpiod_if2.so
        rm -f /usr/local/bin/pig2vcd
        rm -f /usr/local/bin/pigpiod
        rm -f /usr/local/bin/pigs
@@ -95,6 +110,11 @@ $(LIB2):    $(OBJ2)
        $(STRIPLIB) $(LIB2)
        $(SIZE)     $(LIB2)
 
+$(LIB3):       $(OBJ3)
+       $(SHLIB) -o $(LIB3) $(OBJ3)
+       $(STRIPLIB) $(LIB3)
+       $(SIZE)     $(LIB3)
+
 # generated using gcc -MM *.c
 
 pig2vcd.o: pig2vcd.c pigpio.h
@@ -102,3 +122,4 @@ pigpiod.o: pigpiod.c pigpio.h
 pigs.o: pigs.c pigpio.h command.h
 x_pigpio.o: x_pigpio.c pigpio.h
 x_pigpiod_if.o: x_pigpiod_if.c pigpiod_if.h pigpio.h
+x_pigpiod_if2.o: x_pigpiod_if2.c pigpiod_if2.h pigpio.h
diff --git a/README b/README
index bb18a21c2217e21cb658fc1b79a5d6b9c37f9a87..3f3d7669d5075f4006ed24935555aa96b1a1a614 100644 (file)
--- a/README
+++ b/README
@@ -13,18 +13,20 @@ IN THAT DIRECTORY
 Enter the following two commands (in this order)
 
 make
-make install
+sudo make install
 
 This will install
 
 o the library (libpigpio.so) in /usr/local/lib
 o the library (libpigpiod_if.so) in /usr/local/lib
+o the library (libpigpiod_if2.so) in /usr/local/lib
 o the header file (pigpio.h) in /usr/local/include
 o the header file (pigpiod_if.h) in /usr/local/include
+o the header file (pigpiod_if2.h) in /usr/local/include
 o the daemon (pigpiod) in /usr/local/bin
 o the socket interface (pigs) in /usr/local/bin
 o the utility pig2vcd in /usr/local/bin
-o man pages in /usr/local/man/man1 and man3
+o man pages in /usr/local/man/man1 and /usr/local/man/man3
 o the Python module pigpio.py for Python 2 and 3
 
 TEST (optional)
@@ -48,19 +50,21 @@ To test the pigpio daemon do
 
 sudo pigpiod
 
-./x_pigpiod_if # test the C I/F to the pigpio daemon
-./x_pigpio.py  # test the Python I/F to the pigpio daemon
-./x_pigs       # test the socket I/F to the pigpio daemon
-./x_pipe       # test the pipe I/F to the pigpio daemon
+./x_pigpiod_if  # test the C I/F to the pigpio daemon
+./x_pigpiod_if2 # test the C I/F to the pigpio daemon
+./x_pigpio.py   # test the Python I/F to the pigpio daemon
+./x_pigs        # test the socket I/F to the pigpio daemon
+./x_pipe        # test the pipe I/F to the pigpio daemon
 
 EXAMPLE CODE
 
 x_pigpio.c, pig2vcd.c, and pigpiod.c show examples of interfacing
 with the pigpio library.
 
-pigs.c, pigpio.py, x_pigpiod_if.c, x_pigpio.py, x_pigs, and x_pipe
-show examples of interfacing with the pigpio daemon.  x_pipe uses
-the pipe interface, the others use the socket interface.
+pigs.c, pigpio.py, x_pigpiod_if, x_pigpiod_if2.c, x_pigpio.py,
+x_pigs, and x_pipe show examples of interfacing with the pigpio
+daemon.  x_pipe uses the pipe interface, the others use the
+socket interface.
 
 DAEMON
 
@@ -123,6 +127,7 @@ In particular this allows you to use the following on non-Pi's.
 o pigs
 o the pigpio Python module
 o the C socket I/F using libpigpiod_if (header file pigpiod_if.h)
+o the C socket I/F using libpigpiod_if2 (header file pigpiod_if2.h)
 
 On a Linux machine
 
@@ -133,10 +138,12 @@ make -f MakeRemote install
 This will install
 
 o the library (libpigpiod_if.so) in /usr/local/lib
+o the library (libpigpiod_if2.so) in /usr/local/lib
 o the header file (pigpio.h) in /usr/local/include
 o the header file (pigpiod_if.h) in /usr/local/include
+o the header file (pigpiod_if2.h) in /usr/local/include
 o the socket interface (pigs) in /usr/local/bin
-o man pages in /usr/local/man/man1 and man3
+o man pages in /usr/local/man/man1 and /usr/local/man/man3
 o the Python module pigpio.py
 
 On Windows machines (and possibly Macs)
@@ -145,8 +152,8 @@ The Python module should install with
 
 python setup.py install
 
-pigs and pigpiod_if.c will need minor mods to reflect the
-Window's/Mac's socket interface.
+pigs, pigpiod_if, and pigpiod_if2 will need minor mods to
+reflect the Windows/Mac socket interface.
 
 DOCUMENTATION
 
@@ -160,6 +167,7 @@ man pig2vcd
 
 man pigpio
 man pigpiod_if
+man pigpiod_if2
 
 pydoc pigpio
 
index 49ac7c62c540d0a32a2af4fcb84020c348c759d3..6bd6fae6efbb8a76e65d8c4393794eeb4592ba60 100644 (file)
--- a/command.c
+++ b/command.c
@@ -556,7 +556,7 @@ int cmdParse(
    char *p8;
    int32_t *p32;
    char c;
-   uint32_t tp1, tp2, tp3;
+   uint32_t tp1=0, tp2=0, tp3=0;
    int8_t to1, to2, to3;
    int eaten;
 
index 65fab373e53371711d0556cf13a9019c08e61627..492ec68a9db9ec5a8adfa37329473d5e43730cb9 100644 (file)
--- a/pig2vcd.1
+++ b/pig2vcd.1
@@ -2,7 +2,7 @@
 ." Process this file with
 ." groff -man -Tascii pig2vcd.1
 ."
-.TH pig2vcd 1 2012-2014 Linux "pigpio archive"
+.TH pig2vcd 1 2012-2015 Linux "pigpio archive"
 .SH NAME
 pig2vd - A utility to convert pigpio notifications to VCD.
 
@@ -236,7 +236,7 @@ The state lines contain the new state followed by the gpio identifier.
 
 .SH SEE ALSO
 
-pigpiod(1), pigs(1), pigpio(3), pigpiod_if(3)
+pigpiod(1), pigs(1), pigpio(3), pigpiod_if(3), pigpiod_if2(3)
 .SH AUTHOR
 
 joan@abyz.co.uk
index c06b3de593cd9b0f4a6bb2122fba1e1bf8eb6a22..52ff01ee3fda6e41f53356c18a24699adda9939a 100644 (file)
--- a/pigpio.3
+++ b/pigpio.3
@@ -2,13 +2,16 @@
 ." Process this file with
 ." groff -man -Tascii pigpio.3
 ."
-.TH pigpio 3 2012-2014 Linux "pigpio archive"
+.TH pigpio 3 2012-2015 Linux "pigpio archive"
 .SH NAME
 pigpio - A C library to manipulate the Pi's gpios.
 
 .SH SYNOPSIS
 
-gcc -o prog prog.c -lpigpio -lrt -lpthread
+#include <pigpio.h>
+
+
+gcc -Wall -pthread -o prog prog.c -lpigpio -lrt
 
 sudo ./prog
 .SH DESCRIPTION
@@ -130,7 +133,7 @@ run the executable.
 .br
 
 .EX
-gcc -o prog prog.c -lpigpio -lpthread -lrt
+gcc -Wall -pthread -o prog prog.c -lpigpio -lrt
 .br
 sudo ./prog
 .br
@@ -2411,23 +2414,23 @@ of the function description.  The following abbreviations are used.
 .br
 
 .EX
-S     (1 bit) : Start bit
+S      (1 bit) : Start bit
 .br
-P     (1 bit) : Stop bit
+P      (1 bit) : Stop bit
 .br
-Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
+Rd/Wr  (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
 .br
-A, NA (1 bit) : Accept and not accept bit.
+A, NA  (1 bit) : Accept and not accept bit.
 .br
 .br
 .br
-Addr  (7 bits): I2C 7 bit address.
+Addr   (7 bits): I2C 7 bit address.
 .br
-Comm  (8 bits): Command byte, a data byte which often selects a register.
+i2cReg (8 bits): Command byte, a byte which often selects a register.
 .br
-Data  (8 bits): A data byte.
+Data   (8 bits): A data byte.
 .br
-Count (8 bits): A data byte containing the length of a block operation.
+Count  (8 bits): A byte defining the length of a block operation.
 .br
 
 .br
@@ -2484,7 +2487,7 @@ PI_I2C_WRITE_FAILED.
 Quick command. SMBus 2.0 5.5.1
 
 .EX
-S Addr Rd/Wr [A] P
+S Addr bit [A] P
 .br
 
 .EE
@@ -2517,7 +2520,7 @@ PI_I2C_WRITE_FAILED.
 Send byte. SMBus 2.0 5.5.2
 
 .EX
-S Addr Wr [A] Data [A] P
+S Addr Wr [A] bVal [A] P
 .br
 
 .EE
@@ -2584,7 +2587,7 @@ PI_I2C_WRITE_FAILED.
 Write byte. SMBus 2.0 5.5.4
 
 .EX
-S Addr Wr [A] Comm [A] Data [A] P
+S Addr Wr [A] i2cReg [A] bVal [A] P
 .br
 
 .EE
@@ -2620,7 +2623,7 @@ PI_I2C_WRITE_FAILED.
 Write word. SMBus 2.0 5.5.4
 
 .EX
-S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
+S Addr Wr [A] i2cReg [A] wValLow [A] wValHigh [A] P
 .br
 
 .EE
@@ -2654,7 +2657,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 Read byte. SMBus 2.0 5.5.5
 
 .EX
-S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
+S Addr Wr [A] i2cReg [A] S Addr Rd [A] [Data] NA P
 .br
 
 .EE
@@ -2688,7 +2691,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 Read word. SMBus 2.0 5.5.5
 
 .EX
-S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
+S Addr Wr [A] i2cReg [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
 .br
 
 .EE
@@ -2724,7 +2727,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 Process call. SMBus 2.0 5.5.6
 
 .EX
-S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A]
+S Addr Wr [A] i2cReg [A] wValLow [A] wValHigh [A]
 .br
    S Addr Rd [A] [DataLow] A [DataHigh] NA P
 .br
@@ -2764,7 +2767,9 @@ PI_I2C_WRITE_FAILED.
 Block write. SMBus 2.0 5.5.7
 
 .EX
-S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P
+S Addr Wr [A] i2cReg [A] count [A]
+.br
+   buf0 [A] buf1 [A] ... [A] bufn [A] P
 .br
 
 .EE
@@ -2805,9 +2810,9 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 Block read. SMBus 2.0 5.5.7
 
 .EX
-S Addr Wr [A] Comm [A]
+S Addr Wr [A] i2cReg [A]
 .br
-   S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
+   S Addr Rd [A] [Count] A [buf0] A [buf1] A ... A [bufn] NA P
 .br
 
 .EE
@@ -2853,9 +2858,9 @@ bytes sent/received must be 32 or less.
 Block write-block read. SMBus 2.0 5.5.8
 
 .EX
-S Addr Wr [A] Comm [A] Count [A] Data [A] ...
+S Addr Wr [A] i2cReg [A] count [A] buf0 [A] ... bufn [A]
 .br
-   S Addr Rd [A] [Count] A [Data] ... A P
+   S Addr Rd [A] [Count] A [buf0] A ... [bufn] A P
 .br
 
 .EE
@@ -2892,9 +2897,9 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 .br
 
 .EX
-S Addr Wr [A] Comm [A]
+S Addr Wr [A] i2cReg [A]
 .br
-   S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+   S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
 .br
 
 .EE
@@ -2931,7 +2936,7 @@ PI_I2C_WRITE_FAILED.
 .br
 
 .EX
-S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
+S Addr Wr [A] i2cReg [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
 .br
 
 .EE
@@ -2960,6 +2965,16 @@ handle: >=0, as returned by a call to \fBi2cOpen\fP
 Returns count (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
 PI_I2C_READ_FAILED.
 
+.br
+
+.br
+
+.EX
+S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+.br
+
+.EE
+
 .IP "\fBint i2cWriteDevice(unsigned handle, char *buf, unsigned count)\fP"
 .IP "" 4
 This writes count bytes from buf to the raw device.
@@ -2984,6 +2999,16 @@ handle: >=0, as returned by a call to \fBi2cOpen\fP
 Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
 PI_I2C_WRITE_FAILED.
 
+.br
+
+.br
+
+.EX
+S Addr Wr [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+.br
+
+.EE
+
 .IP "\fBvoid i2cSwitchCombined(int setting)\fP"
 .IP "" 4
 This sets the I2C (i2c-bcm2708) module "use combined transactions"
@@ -4130,7 +4155,7 @@ registered per timer.
 .br
 See \fBgpioSetTimerFunc\fP for further details.
 
-.IP "\fBpthread_t *gpioStartThread(gpioThreadFunc_t f, void *arg)\fP"
+.IP "\fBpthread_t *gpioStartThread(gpioThreadFunc_t f, void *userdata)\fP"
 .IP "" 4
 Starts a new thread of execution with f as the main routine.
 
@@ -4139,9 +4164,9 @@ Starts a new thread of execution with f as the main routine.
 .br
 
 .EX
-  f: the main function for the new thread
+       f: the main function for the new thread
 .br
-arg: a pointer to arbitrary user data
+userdata: a pointer to arbitrary user data
 .br
 
 .EE
@@ -5706,17 +5731,6 @@ a stable level).
 
 .br
 
-.IP "\fB*arg\fP" 0
-
-.br
-
-.br
-A pointer to a void object passed to a thread started by gpioStartThread.
-
-.br
-
-.br
-
 .IP "\fBarg1\fP" 0
 
 .br
@@ -7410,6 +7424,48 @@ A pointer to arbitrary user data.  This may be used to identify the instance.
 
 .br
 
+.br
+You must ensure that the pointer is in scope at the time it is processed.  If
+it is a pointer to a global this is automatic.  Do not pass the address of a
+local variable.  If you want to pass a transient object then use the
+following technique.
+
+.br
+
+.br
+In the calling function:
+
+.br
+
+.br
+user_type *userdata;
+.br
+user_type my_userdata;
+
+.br
+
+.br
+userdata = malloc(sizeof(user_type));
+.br
+*userdata = my_userdata;
+
+.br
+
+.br
+In the receiving function:
+
+.br
+
+.br
+user_type my_userdata = *(user_type*)userdata;
+
+.br
+
+.br
+free(userdata);
+
+.br
+
 .br
 
 .IP "\fBvoid\fP" 0
@@ -8026,7 +8082,7 @@ A 16-bit word value.
 
 .SH SEE ALSO
 
-pigpiod(1), pig2vcd(1), pigs(1), pigpiod_if(3)
+pigpiod(1), pig2vcd(1), pigs(1), pigpiod_if(3), pigpiod_if2(3)
 .SH AUTHOR
 
 joan@abyz.co.uk
index 3205f2c9dd6f0c69da95950a3e37bc19f718ecb4..cf1069991be1db4457379b4572687f3101114eb3 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 39 */
+/* pigpio version 40 */
 
 /* include ------------------------------------------------------- */
 
@@ -1375,6 +1375,8 @@ static void initDMAgo(volatile uint32_t  *dmaAddr, uint32_t cbAddr);
 
 int gpioWaveTxStart(unsigned wave_mode); /* deprecated */
 
+static void closeOrphanedNotifications(int slot, int fd);
+
 
 /* ======================================================================= */
 
@@ -5394,6 +5396,7 @@ static void * pthAlertThread(void *x)
          {
             if (gpioNotify[n].pipe)
             {
+               DBG(DBG_INTERNAL, "close notify pipe %d", gpioNotify[n].fd);
                close(gpioNotify[n].fd);
 
                sprintf(fifo, "/dev/pigpio%d", n);
@@ -5499,6 +5502,8 @@ static void * pthAlertThread(void *x)
 
             if (emit)
             {
+               DBG(DBG_FAST_TICK, "notification %d (%d reports, %x-%x)",
+                  n, emit, gpioReport[0].seqno,  gpioReport[emit-1].seqno);
                gpioNotify[n].lastReportTick = stick;
                max_emits = gpioNotify[n].max_emits;
 
@@ -6221,7 +6226,10 @@ static void *pthSocketThreadHandler(void *fdC)
             if (recv(sock, buf, p[3], MSG_WAITALL) != p[3])
             {
                /* Serious error.  No point continuing. */
-               DBG(DBG_ALWAYS, "recv failed for %d bytes", p[3]);
+               DBG(DBG_ALWAYS,
+                  "recv failed for %d bytes, sock=%d", p[3], sock);
+
+               closeOrphanedNotifications(-1, sock);
 
                close(sock);
 
@@ -6231,7 +6239,10 @@ static void *pthSocketThreadHandler(void *fdC)
          else
          {
             /* Serious error.  No point continuing. */
-            DBG(DBG_ALWAYS, "ext too large %d(%d)", p[3], sizeof(buf));
+            DBG(DBG_ALWAYS,
+               "ext too large %d(%d), sock=%d", p[3], sizeof(buf), sock);
+
+            closeOrphanedNotifications(-1, sock);
 
             close(sock);
 
@@ -6299,6 +6310,8 @@ static void *pthSocketThreadHandler(void *fdC)
       }
    }
 
+   closeOrphanedNotifications(-1, sock);
+
    close(sock);
 
    return 0;
@@ -6340,6 +6353,8 @@ static void * pthSocketThread(void *x)
    {
       pthread_t thr;
 
+      closeOrphanedNotifications(-1, fdC);
+
       sock = malloc(sizeof(int));
 
       *sock = fdC;
@@ -7123,6 +7138,16 @@ static void initReleaseResources(void)
 
    /* shut down running threads */
 
+   for (i=0; i<=PI_MAX_USER_GPIO; i++)
+   {
+      if (gpioISR[i].pth)
+      {
+         /* destroy thread, unexport GPIO */
+
+         gpioSetISRFunc(i, 0, 0, NULL);
+      }
+   }
+
    for (i=0; i<=PI_MAX_TIMER; i++)
    {
       if (gpioTimer[i].running)
@@ -10026,6 +10051,24 @@ int gpioSetISRFuncEx(
    return intGpioSetISRFunc(gpio, edge, timeout, f, 1, userdata);
 }
 
+static void closeOrphanedNotifications(int slot, int fd)
+{
+   int i;
+
+   /* Check for and close any orphaned notifications. */
+
+   for (i=0; i<PI_NOTIFY_SLOTS; i++)
+   {
+      if ((i != slot) &&
+          (gpioNotify[i].state != PI_NOTIFY_CLOSED) &&
+          (gpioNotify[i].fd == fd))
+      {
+         DBG(DBG_USER, "closed orphaned fd=%d (handle=%d)", fd, i);
+         gpioNotify[i].state = PI_NOTIFY_CLOSED;
+         intNotifyBits();
+      }
+   }
+}
 
 /* ----------------------------------------------------------------------- */
 
@@ -10072,6 +10115,8 @@ int gpioNotifyOpen(void)
    gpioNotify[slot].max_emits  = MAX_EMITS;
    gpioNotify[slot].lastReportTick = gpioTick();
 
+   closeOrphanedNotifications(slot, fd);
+
    return slot;
 }
 
@@ -10082,7 +10127,7 @@ static int gpioNotifyOpenInBand(int fd)
 {
    int i, slot;
 
-   DBG(DBG_USER, "");
+   DBG(DBG_USER, "fd=%d", fd);
 
    CHECK_INITED;
 
@@ -10107,6 +10152,8 @@ static int gpioNotifyOpenInBand(int fd)
    gpioNotify[slot].max_emits  = MAX_EMITS;
    gpioNotify[slot].lastReportTick = gpioTick();
 
+   closeOrphanedNotifications(slot, fd);
+
    return slot;
 }
 
@@ -10491,12 +10538,12 @@ int gpioSetTimerFuncEx(unsigned id, unsigned millis, gpioTimerFuncEx_t f,
 
 /* ----------------------------------------------------------------------- */
 
-pthread_t *gpioStartThread(gpioThreadFunc_t f, void *arg)
+pthread_t *gpioStartThread(gpioThreadFunc_t f, void *userdata)
 {
    pthread_t *pth;
    pthread_attr_t pthAttr;
 
-   DBG(DBG_USER, "f=%08X, arg=%08X", (uint32_t)f, (uint32_t)arg);
+   DBG(DBG_USER, "f=%08X, userdata=%08X", (uint32_t)f, (uint32_t)userdata);
 
    CHECK_INITED_RET_NULL_PTR;
 
@@ -10516,7 +10563,7 @@ pthread_t *gpioStartThread(gpioThreadFunc_t f, void *arg)
          SOFT_ERROR(NULL, "pthread_attr_setstacksize failed");
       }
 
-      if (pthread_create(pth, &pthAttr, f, arg))
+      if (pthread_create(pth, &pthAttr, f, userdata))
       {
          free(pth);
          SOFT_ERROR(NULL, "pthread_create failed");
index bae30c7c2cc5ac1a1c799accd8c562ab29639f38..f6a672d00915f9d707d6bbd4d942334d097d3eba 100644 (file)
--- a/pigpio.h
+++ b/pigpio.h
@@ -31,7 +31,7 @@ For more information, please refer to <http://unlicense.org/>
 #include <stdint.h>
 #include <pthread.h>
 
-#define PIGPIO_VERSION 39
+#define PIGPIO_VERSION 40
 
 /*TEXT
 
@@ -83,7 +83,7 @@ Assuming your source is in prog.c use the following command to build and
 run the executable.
 
 . .
-gcc -o prog prog.c -lpigpio -lpthread -lrt
+gcc -Wall -pthread -o prog prog.c -lpigpio -lrt
 sudo ./prog
 . .
 
@@ -2034,14 +2034,14 @@ For the SMBus commands the low level transactions are shown at the end
 of the function description.  The following abbreviations are used.
 
 . .
-S     (1 bit) : Start bit
-P     (1 bit) : Stop bit
-Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
-A, NA (1 bit) : Accept and not accept bit. 
-Addr  (7 bits): I2C 7 bit address.
-Comm  (8 bits): Command byte, a data byte which often selects a register.
-Data  (8 bits): A data byte.
-Count (8 bits): A data byte containing the length of a block operation.
+S      (1 bit) : Start bit
+P      (1 bit) : Stop bit
+Rd/Wr  (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
+A, NA  (1 bit) : Accept and not accept bit. 
+Addr   (7 bits): I2C 7 bit address.
+i2cReg (8 bits): Command byte, a byte which often selects a register.
+Data   (8 bits): A data byte.
+Count  (8 bits): A byte defining the length of a block operation.
 
 [..]: Data sent by the device.
 . .
@@ -2077,7 +2077,7 @@ PI_I2C_WRITE_FAILED.
 
 Quick command. SMBus 2.0 5.5.1
 . .
-S Addr Rd/Wr [A] P
+S Addr bit [A] P
 . .
 D*/
 
@@ -2097,7 +2097,7 @@ PI_I2C_WRITE_FAILED.
 
 Send byte. SMBus 2.0 5.5.2
 . .
-S Addr Wr [A] Data [A] P
+S Addr Wr [A] bVal [A] P
 . .
 D*/
 
@@ -2138,7 +2138,7 @@ PI_I2C_WRITE_FAILED.
 
 Write byte. SMBus 2.0 5.5.4
 . .
-S Addr Wr [A] Comm [A] Data [A] P
+S Addr Wr [A] i2cReg [A] bVal [A] P
 . .
 D*/
 
@@ -2160,7 +2160,7 @@ PI_I2C_WRITE_FAILED.
 
 Write word. SMBus 2.0 5.5.4
 . .
-S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
+S Addr Wr [A] i2cReg [A] wValLow [A] wValHigh [A] P
 . .
 D*/
 
@@ -2181,7 +2181,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 
 Read byte. SMBus 2.0 5.5.5
 . .
-S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
+S Addr Wr [A] i2cReg [A] S Addr Rd [A] [Data] NA P
 . .
 D*/
 
@@ -2202,7 +2202,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 
 Read word. SMBus 2.0 5.5.5
 . .
-S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
+S Addr Wr [A] i2cReg [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
 . .
 D*/
 
@@ -2224,7 +2224,7 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 
 Process call. SMBus 2.0 5.5.6
 . .
-S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A]
+S Addr Wr [A] i2cReg [A] wValLow [A] wValHigh [A]
    S Addr Rd [A] [DataLow] A [DataHigh] NA P
 . .
 D*/
@@ -2249,7 +2249,8 @@ PI_I2C_WRITE_FAILED.
 
 Block write. SMBus 2.0 5.5.7
 . .
-S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P
+S Addr Wr [A] i2cReg [A] count [A]
+   buf0 [A] buf1 [A] ... [A] bufn [A] P
 . .
 D*/
 
@@ -2273,8 +2274,8 @@ PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 
 Block read. SMBus 2.0 5.5.7
 . .
-S Addr Wr [A] Comm [A]
-   S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
+S Addr Wr [A] i2cReg [A]
+   S Addr Rd [A] [Count] A [buf0] A [buf1] A ... A [bufn] NA P
 . .
 D*/
 
@@ -2303,8 +2304,8 @@ bytes sent/received must be 32 or less.
 
 Block write-block read. SMBus 2.0 5.5.8
 . .
-S Addr Wr [A] Comm [A] Count [A] Data [A] ...
-   S Addr Rd [A] [Count] A [Data] ... A P
+S Addr Wr [A] i2cReg [A] count [A] buf0 [A] ... bufn [A]
+   S Addr Rd [A] [Count] A [buf0] A ... [bufn] A P
 . .
 D*/
 
@@ -2327,8 +2328,8 @@ Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, or PI_I2C_READ_FAILED.
 
 . .
-S Addr Wr [A] Comm [A]
-   S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+S Addr Wr [A] i2cReg [A]
+   S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
 . .
 D*/
 
@@ -2351,7 +2352,7 @@ Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
 PI_I2C_WRITE_FAILED.
 
 . .
-S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
+S Addr Wr [A] i2cReg [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
 . .
 D*/
 
@@ -2368,6 +2369,10 @@ handle: >=0, as returned by a call to [*i2cOpen*]
 
 Returns count (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
 PI_I2C_READ_FAILED.
+
+. .
+S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+. .
 D*/
 
 
@@ -2384,6 +2389,10 @@ handle: >=0, as returned by a call to [*i2cOpen*]
 
 Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
 PI_I2C_WRITE_FAILED.
+
+. .
+S Addr Wr [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+. .
 D*/
 
 /*F*/
@@ -3046,13 +3055,13 @@ D*/
 
 
 /*F*/
-pthread_t *gpioStartThread(gpioThreadFunc_t f, void *arg);
+pthread_t *gpioStartThread(gpioThreadFunc_t f, void *userdata);
 /*D
 Starts a new thread of execution with f as the main routine.
 
 . .
-  f: the main function for the new thread
-arg: a pointer to arbitrary user data
+       f: the main function for the new thread
+userdata: a pointer to arbitrary user data
 . .
 
 Returns a pointer to pthread_t if OK, otherwise NULL.
@@ -4005,10 +4014,6 @@ The number of microseconds level changes are reported for once
 a noise filter has been triggered (by [*steady*] microseconds of
 a stable level).
 
-*arg::
-
-A pointer to a void object passed to a thread started by gpioStartThread.
-
 arg1::
 
 An unsigned argument passed to a user customised function.  Its
@@ -4717,6 +4722,25 @@ See [*gpio*].
 
 A pointer to arbitrary user data.  This may be used to identify the instance.
 
+You must ensure that the pointer is in scope at the time it is processed.  If
+it is a pointer to a global this is automatic.  Do not pass the address of a
+local variable.  If you want to pass a transient object then use the
+following technique.
+
+In the calling function:
+
+user_type *userdata; 
+user_type my_userdata;
+
+userdata = malloc(sizeof(user_type)); 
+*userdata = my_userdata;
+
+In the receiving function:
+
+user_type my_userdata = *(user_type*)userdata;
+
+free(userdata);
+
 void::
 
 Denoting no parameter is required
index 965d9b72bb17c50a9b2e3837af21f9346d60436c..e8587d757c6027c6ec7cea343cb918c7272a5eaa 100644 (file)
--- a/pigpio.py
+++ b/pigpio.py
@@ -269,7 +269,7 @@ import threading
 import os
 import atexit
 
-VERSION = "1.23"
+VERSION = "1.24"
 
 exceptions = True
 
@@ -2190,9 +2190,9 @@ class pi():
       Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
       A, NA (1 bit) : Accept and not accept bit. 
       Addr  (7 bits): I2C 7 bit address.
-      Comm  (8 bits): Command byte, which often selects a register.
+      reg   (8 bits): Command byte, which often selects a register.
       Data  (8 bits): A data byte.
-      Count (8 bits): A byte containing the length of a block operation.
+      Count (8 bits): A byte defining the length of a block operation.
 
       [..]: Data sent by the device.
       . .
@@ -2231,7 +2231,7 @@ class pi():
 
       SMBus 2.0 5.5.1 - Quick command.
       . .
-      S Addr Rd/Wr [A] P
+      S Addr bit [A] P
       . .
 
       ...
@@ -2250,7 +2250,7 @@ class pi():
 
       SMBus 2.0 5.5.2 - Send byte.
       . .
-      S Addr Wr [A] Data [A] P
+      S Addr Wr [A] byte_val [A] P
       . .
 
       ...
@@ -2289,7 +2289,7 @@ class pi():
 
       SMBus 2.0 5.5.4 - Write byte.
       . .
-      S Addr Wr [A] Comm [A] Data [A] P
+      S Addr Wr [A] reg [A] byte_val [A] P
       . .
 
       ...
@@ -2320,7 +2320,7 @@ class pi():
 
       SMBus 2.0 5.5.4 - Write word.
       . .
-      S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
+      S Addr Wr [A] reg [A] word_val_Low [A] word_val_High [A] P
       . .
 
       ...
@@ -2350,7 +2350,7 @@ class pi():
 
       SMBus 2.0 5.5.5 - Read byte.
       . .
-      S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
+      S Addr Wr [A] reg [A] S Addr Rd [A] [Data] NA P
       . .
 
       ...
@@ -2373,7 +2373,7 @@ class pi():
 
       SMBus 2.0 5.5.5 - Read word.
       . .
-      S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
+      S Addr Wr [A] reg [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
       . .
 
       ...
@@ -2397,7 +2397,7 @@ class pi():
 
       SMBus 2.0 5.5.6 - Process call.
       . .
-      S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A]
+      S Addr Wr [A] reg [A] word_val_Low [A] word_val_High [A]
          S Addr Rd [A] [DataLow] A [DataHigh] NA P
       . .
 
@@ -2426,8 +2426,8 @@ class pi():
 
       SMBus 2.0 5.5.7 - Block write.
       . .
-      S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A]
-         Data [A] P
+      S Addr Wr [A] reg [A] len(data) [A] data0 [A] data1 [A] ... [A]
+         datan [A] P
       . .
 
       ...
@@ -2461,7 +2461,7 @@ class pi():
 
       SMBus 2.0 5.5.7 - Block read.
       . .
-      S Addr Wr [A] Comm [A]
+      S Addr Wr [A] reg [A]
          S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
       . .
 
@@ -2505,7 +2505,7 @@ class pi():
 
       SMBus 2.0 5.5.8 - Block write-block read.
       . .
-      S Addr Wr [A] Comm [A] Count [A] Data [A] ...
+      S Addr Wr [A] reg [A] len(data) [A] data0 [A] ... datan [A]
          S Addr Rd [A] [Count] A [Data] ... A P
       . .
 
@@ -2550,8 +2550,7 @@ class pi():
         data:= the bytes to write.
 
       . .
-      S Addr Wr [A] Comm [A]
-         S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+      S Addr Wr [A] reg [A] data0 [A] data1 [A] ... [A] datan [NA] P
       . .
 
       ...
@@ -2585,7 +2584,8 @@ class pi():
        count:= >0, the number of bytes to read.
 
       . .
-      S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P
+      S Addr Wr [A] reg [A]
+         S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
       . .
 
       The returned value is a tuple of the number of bytes read and a
@@ -2626,6 +2626,10 @@ class pi():
       handle:= >=0 (as returned by a prior call to [*i2c_open*]).
        count:= >0, the number of bytes to read.
 
+      . .
+      S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
+      . .
+
       The returned value is a tuple of the number of bytes read and a
       bytearray containing the bytes.  If there was an error the
       number of bytes read will be less than zero (and will contain
@@ -2652,6 +2656,10 @@ class pi():
       handle:= >=0 (as returned by a prior call to [*i2c_open*]).
         data:= the bytes to write.
 
+      . .
+      S Addr Wr [A] data0 [A] data1 [A] ... [A] datan [A] P
+      . .
+
       ...
       pi.i2c_write_device(h, b"\\x12\\x34\\xA8")
 
@@ -3902,7 +3910,9 @@ def xref():
    PI_CHAIN_NESTING = -118
    PI_CHAIN_TOO_BIG = -119
    PI_DEPRECATED = -120
-   PI_BAD_SER_INVERT   = -121
+   PI_BAD_SER_INVERT = -121
+   PI_BAD_FOREVER = -124
+   PI_BAD_FILTER = -125
    . .
 
    frequency: 0-40000
index a54d7b6b8f5aef6ad33126df19b8d913e316ac86..ef04989896f9e0a64e7264a271083b5c3c789e69 100644 (file)
--- a/pigpiod.1
+++ b/pigpiod.1
@@ -2,7 +2,7 @@
 ." Process this file with
 ." groff -man -Tascii pigpiod.1
 ."
-.TH pigpiod 1 2012-2014 Linux "pigpio archive"
+.TH pigpiod 1 2012-2015 Linux "pigpio archive"
 .SH NAME
 pigpiod - A utility to start the pigpio library as a daemon.
 
@@ -183,7 +183,7 @@ The high USB power mode gpio may be written (gpio 38 for type 3 boards).
 
 .SH SEE ALSO
 
-pig2vcd(1), pigs(1), pigpio(3), pigpiod_if(3)
+pig2vcd(1), pigs(1), pigpio(3), pigpiod_if(3), pigpiod_if2(3)
 .SH AUTHOR
 
 joan@abyz.co.uk
index fac7b707d8f7a8ebe553cd3755ae446008184628..6cb1b2762ec562d64eb1c40bf3afd1c120a20044 100644 (file)
@@ -2,18 +2,27 @@
 ." Process this file with
 ." groff -man -Tascii pigpiod_if.3
 ."
-.TH pigpiod_if 3 2012-2014 Linux "pigpio archive"
+.TH pigpiod_if 3 2012-2015 Linux "pigpio archive"
 .SH NAME
 pigpiod_if - A C library to interface to the pigpio daemon.
 
 .SH SYNOPSIS
 
-gcc -o prog prog.c -lpigpiod_if
+#include <pigpiod_if.h>
+
+
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if -lrt
 
  ./prog
 .SH DESCRIPTION
 
 
+.br
+
+.br
+THIS LIBRARY IS DEPRECATED.  NEW CODE SHOULD BE WRITTEN TO
+USE THE MORE VERSATILE pigpiod_if2 LIBRARY.
+
 .br
 
 .br
@@ -122,7 +131,7 @@ Assuming your source is in prog.c use the following command to build
 .br
 
 .EX
-gcc -o prog prog.c -lpigpiod_if
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if -lrt
 .br
 
 .EE
@@ -4770,7 +4779,7 @@ typedef enum
 
 .SH SEE ALSO
 
-pigpiod(1), pig2vcd(1), pigs(1), pigpio(3)
+pigpiod(1), pig2vcd(1), pigs(1), pigpio(3), pigpiod_if2(3)
 .SH AUTHOR
 
 joan@abyz.co.uk
index b819464115c05cb1cc4ec9eae79aa2dbfb58a324..7bafcdbdd6c1b4fa7693f42f683502521c98df39 100644 (file)
@@ -34,6 +34,9 @@ For more information, please refer to <http://unlicense.org/>
 
 /*TEXT
 
+THIS LIBRARY IS DEPRECATED.  NEW CODE SHOULD BE WRITTEN TO
+USE THE MORE VERSATILE pigpiod_if2 LIBRARY.
+
 pigpiod_if is a C library for the Raspberry which allows control
 of the gpios via the socket interface to the pigpio daemon. 
 
@@ -78,7 +81,7 @@ Include <pigpiod_if.h> in your source files.
 Assuming your source is in prog.c use the following command to build
 
 . .
-gcc -o prog prog.c -lpigpiod_if
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if -lrt
 . .
 
 to run make sure the pigpio daemon is running
diff --git a/pigpiod_if2.3 b/pigpiod_if2.3
new file mode 100644 (file)
index 0000000..3015610
--- /dev/null
@@ -0,0 +1,5240 @@
+
+." Process this file with
+." groff -man -Tascii pigpiod_if2.3
+."
+.TH pigpiod_if2 3 2012-2015 Linux "pigpio archive"
+.SH NAME
+pigpiod_if2 - A C library to interface to the pigpio daemon.
+
+.SH SYNOPSIS
+
+#include <pigpiod_if2.h>
+
+
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if2 -lrt
+
+ ./prog
+.SH DESCRIPTION
+
+
+.br
+
+.br
+pigpiod_if2 is a C library for the Raspberry which allows control
+of the gpios via the socket interface to the pigpio daemon.
+.br
+
+.br
+
+.br
+.SS Features
+.br
+
+.br
+o PWM on any of gpios 0-31
+
+.br
+
+.br
+o servo pulses on any of gpios 0-31
+
+.br
+
+.br
+o callbacks when any of gpios 0-31 change state
+
+.br
+
+.br
+o callbacks at timed intervals
+
+.br
+
+.br
+o reading/writing all of the gpios in a bank as one operation
+
+.br
+
+.br
+o individually setting gpio modes, reading and writing
+
+.br
+
+.br
+o notifications when any of gpios 0-31 change state
+
+.br
+
+.br
+o the construction of output waveforms with microsecond timing
+
+.br
+
+.br
+o rudimentary permission control over gpios
+
+.br
+
+.br
+o a simple interface to start and stop new threads
+
+.br
+
+.br
+o I2C, SPI, and serial link wrappers
+
+.br
+
+.br
+o creating and running scripts on the pigpio daemon
+
+.br
+
+.br
+.SS gpios
+.br
+
+.br
+ALL gpios are identified by their Broadcom number.
+
+.br
+
+.br
+.SS Notes
+.br
+
+.br
+The PWM and servo pulses are timed using the DMA and PWM/PCM peripherals.
+
+.br
+
+.br
+.SS Usage
+.br
+
+.br
+Include <pigpiod_if2.h> in your source files.
+
+.br
+
+.br
+Assuming your source is in prog.c use the following command to build
+
+.br
+
+.br
+
+.EX
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if2 -lrt
+.br
+
+.EE
+
+.br
+
+.br
+to run make sure the pigpio daemon is running
+
+.br
+
+.br
+
+.EX
+sudo pigpiod
+.br
+
+.br
+ ./prog # sudo is not required to run programs linked to pigpiod_if2
+.br
+
+.EE
+
+.br
+
+.br
+For examples see x_pigpiod_if2.c within the pigpio archive file.
+
+.br
+
+.br
+.SS Notes
+.br
+
+.br
+All the functions which return an int return < 0 on error
+
+.br
+
+.br
+.SH FUNCTIONS
+
+.IP "\fBdouble time_time(void)\fP"
+.IP "" 4
+Return the current time in seconds since the Epoch.
+
+.IP "\fBvoid time_sleep(double seconds)\fP"
+.IP "" 4
+Delay execution for a given number of seconds.
+
+.br
+
+.br
+
+.EX
+seconds: the number of seconds to delay.
+.br
+
+.EE
+
+.IP "\fBchar *pigpio_error(int errnum)\fP"
+.IP "" 4
+Return a text description for an error code.
+
+.br
+
+.br
+
+.EX
+errnum: the error code.
+.br
+
+.EE
+
+.IP "\fBunsigned pigpiod_if_version(void)\fP"
+.IP "" 4
+Return the pigpiod_if2 version.
+
+.IP "\fBpthread_t *start_thread(gpioThreadFunc_t thread_func, void *userdata)\fP"
+.IP "" 4
+Starts a new thread of execution with thread_func as the main routine.
+
+.br
+
+.br
+
+.EX
+thread_func: the main function for the new thread.
+.br
+   userdata: a pointer to an arbitrary argument.
+.br
+
+.EE
+
+.br
+
+.br
+Returns a pointer to pthread_t if OK, otherwise NULL.
+
+.br
+
+.br
+The function is passed the single argument userdata.
+
+.br
+
+.br
+The thread can be cancelled by passing the pointer to pthread_t to
+\fBstop_thread\fP.
+
+.IP "\fBvoid stop_thread(pthread_t *pth)\fP"
+.IP "" 4
+Cancels the thread pointed at by pth.
+
+.br
+
+.br
+
+.EX
+pth: the thread to be stopped.
+.br
+
+.EE
+
+.br
+
+.br
+No value is returned.
+
+.br
+
+.br
+The thread to be stopped should have been started with \fBstart_thread\fP.
+
+.IP "\fBint pigpio_start(char *addrStr, char *portStr)\fP"
+.IP "" 4
+Connect to the pigpio daemon.  Reserving command and
+notification streams.
+
+.br
+
+.br
+
+.EX
+addrStr: specifies the host or IP address of the Pi running the
+.br
+         pigpio daemon.  It may be NULL in which case localhost
+.br
+         is used unless overridden by the PIGPIO_ADDR environment
+.br
+         variable.
+.br
+
+.br
+portStr: specifies the port address used by the Pi running the
+.br
+         pigpio daemon.  It may be NULL in which case "8888"
+.br
+         is used unless overridden by the PIGPIO_PORT environment
+.br
+         variable.
+.br
+
+.EE
+
+.br
+
+.br
+Returns an integer value greater than or equal to zero if OK.
+
+.br
+
+.br
+This value is passed to the GPIO routines to specify the Pi
+to be operated on.
+
+.IP "\fBvoid pigpio_stop(int pi)\fP"
+.IP "" 4
+Terminates the connection to a pigpio daemon and releases
+resources used by the library.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint set_mode(int pi, unsigned gpio, unsigned mode)\fP"
+.IP "" 4
+Set the gpio mode.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+gpio: 0-53.
+.br
+mode: PI_INPUT, PI_OUTPUT, PI_ALT0, _ALT1,
+.br
+      PI_ALT2, PI_ALT3, PI_ALT4, PI_ALT5.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_MODE,
+or PI_NOT_PERMITTED.
+
+.IP "\fBint get_mode(int pi, unsigned gpio)\fP"
+.IP "" 4
+Get the gpio mode.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+gpio: 0-53.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
+
+.IP "\fBint set_pull_up_down(int pi, unsigned gpio, unsigned pud)\fP"
+.IP "" 4
+Set or clear the gpio pull-up/down resistor.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+gpio: 0-53.
+.br
+ pud: PI_PUD_UP, PI_PUD_DOWN, PI_PUD_OFF.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
+or PI_NOT_PERMITTED.
+
+.IP "\fBint gpio_read(int pi, unsigned gpio)\fP"
+.IP "" 4
+Read the gpio level.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+gpio:0-53.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the gpio level if OK, otherwise PI_BAD_GPIO.
+
+.IP "\fBint gpio_write(int pi, unsigned gpio, unsigned level)\fP"
+.IP "" 4
+Write the gpio level.
+
+.br
+
+.br
+
+.EX
+   pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ gpio: 0-53.
+.br
+level: 0, 1.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_LEVEL,
+or PI_NOT_PERMITTED.
+
+.br
+
+.br
+Notes
+
+.br
+
+.br
+If PWM or servo pulses are active on the gpio they are switched off.
+
+.IP "\fBint set_PWM_dutycycle(int pi, unsigned user_gpio, unsigned dutycycle)\fP"
+.IP "" 4
+Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+dutycycle: 0-range (range defaults to 255).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
+or PI_NOT_PERMITTED.
+Notes
+
+.br
+
+.br
+The \fBset_PWM_range\fP function may be used to change the
+default range of 255.
+
+.IP "\fBint get_PWM_dutycycle(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+Return the PWM dutycycle in use on a gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_PWM_GPIO.
+
+.br
+
+.br
+For normal PWM the dutycycle will be out of the defined range
+for the gpio (see \fBget_PWM_range\fP).
+
+.br
+
+.br
+If a hardware clock is active on the gpio the reported dutycycle
+will be 500000 (500k) out of 1000000 (1M).
+
+.br
+
+.br
+If hardware PWM is active on the gpio the reported dutycycle
+will be out of a 1000000 (1M).
+
+.IP "\fBint set_PWM_range(int pi, unsigned user_gpio, unsigned range)\fP"
+.IP "" 4
+Set the range of PWM values to be used on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+    range: 25-40000.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
+or PI_NOT_PERMITTED.
+
+.br
+
+.br
+Notes
+
+.br
+
+.br
+If PWM is currently active on the gpio its dutycycle will be
+scaled to reflect the new range.
+
+.br
+
+.br
+The real range, the number of steps between fully off and fully on
+for each of the 18 available gpio frequencies is
+
+.br
+
+.br
+
+.EX
+  25(#1),    50(#2),   100(#3),   125(#4),    200(#5),    250(#6),
+.br
+ 400(#7),   500(#8),   625(#9),   800(#10),  1000(#11),  1250(#12),
+.br
+2000(#13), 2500(#14), 4000(#15), 5000(#16), 10000(#17), 20000(#18)
+.br
+
+.EE
+
+.br
+
+.br
+The real value set by set_PWM_range is (dutycycle * real range) / range.
+
+.IP "\fBint get_PWM_range(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+Get the range of PWM values being used on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the dutycycle range used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+
+.br
+
+.br
+If a hardware clock or hardware PWM is active on the gpio the
+reported range will be 1000000 (1M).
+
+.IP "\fBint get_PWM_real_range(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+Get the real underlying range of PWM values being used on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the real range used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+
+.br
+
+.br
+If a hardware clock is active on the gpio the reported
+real range will be 1000000 (1M).
+
+.br
+
+.br
+If hardware PWM is active on the gpio the reported real range
+will be approximately 250M divided by the set PWM frequency.
+
+.br
+
+.br
+
+.IP "\fBint set_PWM_frequency(int pi, unsigned user_gpio, unsigned frequency)\fP"
+.IP "" 4
+Set the frequency (in Hz) of the PWM to be used on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+frequency: 0- (Hz).
+.br
+
+.EE
+
+.br
+
+.br
+Returns the numerically closest frequency if OK, otherwise
+PI_BAD_USER_GPIO or PI_NOT_PERMITTED.
+
+.br
+
+.br
+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.
+
+.br
+
+.br
+Each gpio can be independently set to one of 18 different
+PWM frequencies.
+
+.br
+
+.br
+If PWM is currently active on the gpio it will be switched
+off and then back on at the new frequency.
+
+.br
+
+.br
+
+.EX
+1us 40000, 20000, 10000, 8000, 5000, 4000, 2500, 2000, 1600,
+.br
+     1250,  1000,   800,  500,  400,  250,  200,  100,   50
+.br
+
+.br
+2us 20000, 10000,  5000, 4000, 2500, 2000, 1250, 1000,  800,
+.br
+      625,   500,   400,  250,  200,  125,  100,   50 ,  25
+.br
+
+.br
+4us 10000,  5000,  2500, 2000, 1250, 1000,  625,  500,  400,
+.br
+      313,   250,   200,  125,  100,   63,   50,   25,   13
+.br
+
+.br
+5us  8000,  4000,  2000, 1600, 1000,  800,  500,  400,  320,
+.br
+      250,   200,   160,  100  , 80,   50,   40,   20,   10
+.br
+
+.br
+8us  5000,  2500,  1250, 1000,  625,  500,  313,  250,  200,
+.br
+      156,   125,   100,   63,   50,   31,   25,   13,    6
+.br
+
+.br
+10us 4000,  2000,  1000,  800,  500,  400,  250,  200,  160,
+.br
+      125,   100,    80,   50,   40,   25,   20,   10,    5
+.br
+
+.EE
+
+.IP "\fBint get_PWM_frequency(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+Get the frequency of PWM being used on the gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+For normal PWM the frequency will be that defined for the gpio by
+\fBset_PWM_frequency\fP.
+
+.br
+
+.br
+If a hardware clock is active on the gpio the reported frequency
+will be that set by \fBhardware_clock\fP.
+
+.br
+
+.br
+If hardware PWM is active on the gpio the reported frequency
+will be that set by \fBhardware_PWM\fP.
+
+.br
+
+.br
+Returns the frequency (in hertz) used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+
+.IP "\fBint set_servo_pulsewidth(int pi, unsigned user_gpio, unsigned pulsewidth)\fP"
+.IP "" 4
+Start (500-2500) or stop (0) servo pulses on the gpio.
+
+.br
+
+.br
+
+.EX
+        pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ user_gpio: 0-31.
+.br
+pulsewidth: 0 (off), 500 (anti-clockwise) - 2500 (clockwise).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_PULSEWIDTH or
+PI_NOT_PERMITTED.
+
+.br
+
+.br
+The selected pulsewidth will continue to be transmitted until
+changed by a subsequent call to set_servo_pulsewidth.
+
+.br
+
+.br
+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.
+
+.br
+
+.br
+You can DAMAGE a servo if you command it to move beyond its limits.
+
+.br
+
+.br
+OTHER UPDATE RATES:
+
+.br
+
+.br
+This function updates servos at 50Hz.  If you wish to use a different
+update frequency you will have to use the PWM functions.
+
+.br
+
+.br
+
+.EX
+Update Rate (Hz)     50   100  200  400  500
+.br
+1E6/Hz            20000 10000 5000 2500 2000
+.br
+
+.EE
+
+.br
+
+.br
+Firstly set the desired PWM frequency using \fBset_PWM_frequency\fP.
+
+.br
+
+.br
+Then set the PWM range using \fBset_PWM_range\fP to 1E6/Hz.
+Doing this allows you to use units of microseconds when setting
+the servo pulsewidth.
+
+.br
+
+.br
+E.g. If you want to update a servo connected to gpio 25 at 400Hz
+
+.br
+
+.br
+
+.EX
+set_PWM_frequency(25, 400);
+.br
+set_PWM_range(25, 2500);
+.br
+
+.EE
+
+.br
+
+.br
+Thereafter use the \fBset_PWM_dutycycle\fP function to move the servo,
+e.g. set_PWM_dutycycle(25, 1500) will set a 1500 us pulse.
+.br
+
+.IP "\fBint get_servo_pulsewidth(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+Return the servo pulsewidth in use on a gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_SERVO_GPIO.
+
+.IP "\fBint notify_open(int pi)\fP"
+.IP "" 4
+Get a free notification handle.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Returns a handle greater than or equal to zero if OK,
+otherwise PI_NO_HANDLE.
+
+.br
+
+.br
+A notification is a method for being notified of gpio state
+changes via a pipe.
+
+.br
+
+.br
+Pipes are only accessible from the local machine so this function
+serves no purpose if you are using the library from a remote machine.
+The in-built (socket) notifications provided by \fBcallback\fP
+should be used instead.
+
+.br
+
+.br
+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.
+
+.IP "\fBint notify_begin(int pi, unsigned handle, uint32_t bits)\fP"
+.IP "" 4
+Start notifications on a previously opened handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: 0-31 (as returned by \fBnotify_open\fP)
+.br
+  bits: a mask indicating the gpios to be notified.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.br
+
+.br
+The notification sends state changes for each gpio whose
+corresponding bit in bits is set.
+
+.br
+
+.br
+Notes
+
+.br
+
+.br
+Each notification occupies 12 bytes in the fifo as follows:
+
+.br
+
+.br
+
+.EX
+H (16 bit) seqno
+.br
+H (16 bit) flags
+.br
+I (32 bit) tick
+.br
+I (32 bit) level
+.br
+
+.EE
+
+.IP "\fBint notify_pause(int pi, unsigned handle)\fP"
+.IP "" 4
+Pause notifications on a previously opened handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: 0-31 (as returned by \fBnotify_open\fP)
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.br
+
+.br
+Notifications for the handle are suspended until
+\fBnotify_begin\fP is called again.
+
+.IP "\fBint notify_close(int pi, unsigned handle)\fP"
+.IP "" 4
+Stop notifications on a previously opened handle and
+release the handle for reuse.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: 0-31 (as returned by \fBnotify_open\fP)
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.IP "\fBint set_watchdog(int pi, unsigned user_gpio, unsigned timeout)\fP"
+.IP "" 4
+Sets a watchdog for a gpio.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+  timeout: 0-60000.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO
+or PI_BAD_WDOG_TIMEOUT.
+
+.br
+
+.br
+The watchdog is nominally in milliseconds.
+
+.br
+
+.br
+Only one watchdog may be registered per gpio.
+
+.br
+
+.br
+The watchdog may be cancelled by setting timeout to 0.
+
+.br
+
+.br
+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.
+
+.br
+
+.br
+The \fBcallback\fP and \fBcallback_ex\fP functions interpret the flags
+and will call registered callbacks for the gpio with level TIMEOUT.
+
+.IP "\fBint set_glitch_filter(int pi, unsigned user_gpio, unsigned steady)\fP"
+.IP "" 4
+Sets a glitch filter on a gpio.
+
+.br
+
+.br
+Level changes on the gpio are not reported unless the level
+has been stable for at least \fBsteady\fP microseconds.  The
+level is then reported.  Level changes of less than \fBsteady\fP
+microseconds are ignored.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31
+.br
+   steady: 0-300000
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER.
+
+.br
+
+.br
+Note, each (stable) edge will be timestamped \fBsteady\fP microseconds
+after it was first detected.
+
+.IP "\fBint set_noise_filter(int pi, unsigned user_gpio, unsigned steady, unsigned active)\fP"
+.IP "" 4
+Sets a noise filter on a gpio.
+
+.br
+
+.br
+Level changes on the gpio are ignored until a level which has
+been stable for \fBsteady\fP microseconds is detected.  Level changes
+on the gpio are then reported for \fBactive\fP microseconds after
+which the process repeats.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31
+.br
+   steady: 0-300000
+.br
+   active: 0-1000000
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER.
+
+.br
+
+.br
+Note, level changes before and after the active period may
+be reported.  Your software must be designed to cope with
+such reports.
+
+.IP "\fBuint32_t read_bank_1(int pi)\fP"
+.IP "" 4
+Read the levels of the bank 1 gpios (gpios 0-31).
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+The returned 32 bit integer has a bit set if the corresponding
+gpio is logic 1.  Gpio n has bit value (1<<n).
+
+.IP "\fBuint32_t read_bank_2(int pi)\fP"
+.IP "" 4
+Read the levels of the bank 2 gpios (gpios 32-53).
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+The returned 32 bit integer has a bit set if the corresponding
+gpio is logic 1.  Gpio n has bit value (1<<(n-32)).
+
+.IP "\fBint clear_bank_1(int pi, uint32_t bits)\fP"
+.IP "" 4
+Clears gpios 0-31 if the corresponding bit in bits is set.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+bits: a bit mask with 1 set if the corresponding gpio is
+.br
+      to be cleared.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+.br
+
+.br
+A status of PI_SOME_PERMITTED indicates that the user is not
+allowed to write to one or more of the gpios.
+
+.IP "\fBint clear_bank_2(int pi, uint32_t bits)\fP"
+.IP "" 4
+Clears gpios 32-53 if the corresponding bit (0-21) in bits is set.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+bits: a bit mask with 1 set if the corresponding gpio is
+.br
+      to be cleared.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+.br
+
+.br
+A status of PI_SOME_PERMITTED indicates that the user is not
+allowed to write to one or more of the gpios.
+
+.IP "\fBint set_bank_1(int pi, uint32_t bits)\fP"
+.IP "" 4
+Sets gpios 0-31 if the corresponding bit in bits is set.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+bits: a bit mask with 1 set if the corresponding gpio is
+.br
+      to be set.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+.br
+
+.br
+A status of PI_SOME_PERMITTED indicates that the user is not
+allowed to write to one or more of the gpios.
+
+.IP "\fBint set_bank_2(int pi, uint32_t bits)\fP"
+.IP "" 4
+Sets gpios 32-53 if the corresponding bit (0-21) in bits is set.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+bits: a bit mask with 1 set if the corresponding gpio is
+.br
+      to be set.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_SOME_PERMITTED.
+
+.br
+
+.br
+A status of PI_SOME_PERMITTED indicates that the user is not
+allowed to write to one or more of the gpios.
+
+.IP "\fBint hardware_clock(int pi, unsigned gpio, unsigned clkfreq)\fP"
+.IP "" 4
+Starts a hardware clock on a gpio at the specified frequency.
+Frequencies above 30MHz are unlikely to work.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+     gpio: see description
+.br
+frequency: 0 (off) or 4689-250000000 (250M)
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_NOT_PERMITTED, PI_BAD_GPIO,
+PI_NOT_HCLK_GPIO, PI_BAD_HCLK_FREQ,or PI_BAD_HCLK_PASS.
+
+.br
+
+.br
+The same clock is available on multiple gpios.  The latest
+frequency setting will be used by all gpios which share a clock.
+
+.br
+
+.br
+The gpio must be one of the following.
+
+.br
+
+.br
+
+.EX
+4   clock 0  All models
+.br
+5   clock 1  A+/B+/Pi2 and compute module only (reserved for system use)
+.br
+6   clock 2  A+/B+/Pi2 and compute module only
+.br
+20  clock 0  A+/B+/Pi2 and compute module only
+.br
+21  clock 1  All models but Rev.2 B (reserved for system use)
+.br
+
+.br
+32  clock 0  Compute module only
+.br
+34  clock 0  Compute module only
+.br
+42  clock 1  Compute module only (reserved for system use)
+.br
+43  clock 2  Compute module only
+.br
+44  clock 1  Compute module only (reserved for system use)
+.br
+
+.EE
+
+.br
+
+.br
+Access to clock 1 is protected by a password as its use will likely
+crash the Pi.  The password is given by or'ing 0x5A000000 with the
+gpio number.
+
+.IP "\fBint hardware_PWM(int pi, unsigned gpio, unsigned PWMfreq, uint32_t PWMduty)\fP"
+.IP "" 4
+Starts hardware PWM on a gpio at the specified frequency and dutycycle.
+Frequencies above 30MHz are unlikely to work.
+
+.br
+
+.br
+NOTE: Any waveform started by \fBwave_send_once\fP, \fBwave_send_repeat\fP,
+or \fBwave_chain\fP will be cancelled.
+
+.br
+
+.br
+This function is only valid if the pigpio main clock is PCM.  The
+main clock defaults to PCM but may be overridden when the pigpio
+daemon is started (option -t).
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+   gpio: see descripton
+.br
+PWMfreq: 0 (off) or 1-125000000 (125M)
+.br
+PWMduty: 0 (off) to 1000000 (1M)(fully on)
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_NOT_PERMITTED, PI_BAD_GPIO,
+PI_NOT_HPWM_GPIO, PI_BAD_HPWM_DUTY, PI_BAD_HPWM_FREQ,
+or PI_HPWM_ILLEGAL.
+
+.br
+
+.br
+The same PWM channel is available on multiple gpios.  The latest
+frequency and dutycycle setting will be used by all gpios which
+share a PWM channel.
+
+.br
+
+.br
+The gpio must be one of the following.
+
+.br
+
+.br
+
+.EX
+12  PWM channel 0  A+/B+/Pi2 and compute module only
+.br
+13  PWM channel 1  A+/B+/Pi2 and compute module only
+.br
+18  PWM channel 0  All models
+.br
+19  PWM channel 1  A+/B+/Pi2 and compute module only
+.br
+
+.br
+40  PWM channel 0  Compute module only
+.br
+41  PWM channel 1  Compute module only
+.br
+45  PWM channel 1  Compute module only
+.br
+52  PWM channel 0  Compute module only
+.br
+53  PWM channel 1  Compute module only
+.br
+
+.EE
+
+.IP "\fBuint32_t get_current_tick(int pi)\fP"
+.IP "" 4
+Gets the current system tick.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Tick is the number of microseconds since system boot.
+
+.br
+
+.br
+As tick is an unsigned 32 bit quantity it wraps around after
+2**32 microseconds, which is approximately 1 hour 12 minutes.
+
+.br
+
+.br
+
+.IP "\fBuint32_t get_hardware_revision(int pi)\fP"
+.IP "" 4
+Get the Pi's hardware revision number.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+The hardware revision is the last few characters on the Revision line
+of /proc/cpuinfo.
+
+.br
+
+.br
+If the hardware revision can not be found or is not a valid
+hexadecimal number the function returns 0.
+
+.br
+
+.br
+The revision number can be used to determine the assignment of gpios
+to pins (see \fBgpio\fP).
+
+.br
+
+.br
+There are at least three types of board.
+
+.br
+
+.br
+Type 1 boards have hardware revision numbers of 2 and 3.
+
+.br
+
+.br
+Type 2 boards have hardware revision numbers of 4, 5, 6, and 15.
+
+.br
+
+.br
+Type 3 boards have hardware revision numbers of 16 or greater.
+
+.IP "\fBuint32_t get_pigpio_version(int pi)\fP"
+.IP "" 4
+Returns the pigpio version.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_clear(int pi)\fP"
+.IP "" 4
+This function clears all waveforms and any data added by calls to the
+\fBwave_add_*\fP functions.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK.
+
+.IP "\fBint wave_add_new(int pi)\fP"
+.IP "" 4
+This function starts a new empty waveform.  You wouldn't normally need
+to call this function as it is automatically called after a waveform is
+created with the \fBwave_create\fP function.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK.
+
+.IP "\fBint wave_add_generic(int pi, unsigned numPulses, gpioPulse_t *pulses)\fP"
+.IP "" 4
+This function adds a number of pulses to the current waveform.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+numPulses: the number of pulses.
+.br
+   pulses: an array of pulses.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the new total number of pulses in the current waveform if OK,
+otherwise PI_TOO_MANY_PULSES.
+
+.br
+
+.br
+The pulses are interleaved in time order within the existing waveform
+(if any).
+
+.br
+
+.br
+Merging allows the waveform to be built in parts, that is the settings
+for gpio#1 can be added, and then gpio#2 etc.
+
+.br
+
+.br
+If the added waveform is intended to start after or within the existing
+waveform then the first pulse should consist solely of a delay.
+
+.IP "\fBint wave_add_serial(int pi, unsigned user_gpio, unsigned baud, unsigned data_bits, unsigned stop_bits, unsigned offset, unsigned numBytes, char *str)\fP"
+.IP "" 4
+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.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+     baud: 50-1000000
+.br
+data_bits: number of data bits (1-32)
+.br
+stop_bits: number of stop half bits (2-8)
+.br
+   offset: 0-
+.br
+ numBytes: 1-
+.br
+      str: an array of chars.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the new total number of pulses in the current waveform if OK,
+otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_BAD_DATABITS,
+PI_BAD_STOP_BITS, PI_TOO_MANY_CHARS, PI_BAD_SER_OFFSET,
+or PI_TOO_MANY_PULSES.
+
+.br
+
+.br
+NOTES:
+
+.br
+
+.br
+The serial data is formatted as one start bit, \fBdata_bits\fP data bits,
+and \fBstop_bits\fP/2 stop bits.
+
+.br
+
+.br
+It is legal to add serial data streams with different baud rates to
+the same waveform.
+
+.br
+
+.br
+\fBnumBytes\fP is the number of bytes of data in str.
+
+.br
+
+.br
+The bytes required for each character depend upon \fBdata_bits\fP.
+
+.br
+
+.br
+For \fBdata_bits\fP 1-8 there will be one byte per character.
+.br
+For \fBdata_bits\fP 9-16 there will be two bytes per character.
+.br
+For \fBdata_bits\fP 17-32 there will be four bytes per character.
+
+.IP "\fBint wave_create(int pi)\fP"
+.IP "" 4
+This function creates a waveform from the data provided by the prior
+calls to the \fBwave_add_*\fP functions.  Upon success a wave id
+greater than or equal to 0 is returned, otherwise PI_EMPTY_WAVEFORM,
+PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+The data provided by the \fBwave_add_*\fP functions is consumed by this
+function.
+
+.br
+
+.br
+As many waveforms may be created as there is space available.  The
+wave id is passed to \fBwave_send_*\fP to specify the waveform to transmit.
+
+.br
+
+.br
+Normal usage would be
+
+.br
+
+.br
+Step 1. \fBwave_clear\fP to clear all waveforms and added data.
+
+.br
+
+.br
+Step 2. \fBwave_add_*\fP calls to supply the waveform data.
+
+.br
+
+.br
+Step 3. \fBwave_create\fP to create the waveform and get a unique id
+
+.br
+
+.br
+Repeat steps 2 and 3 as needed.
+
+.br
+
+.br
+Step 4. \fBwave_send_*\fP with the id of the waveform to transmit.
+
+.br
+
+.br
+A waveform comprises one or more pulses.  Each pulse consists of a
+\fBgpioPulse_t\fP structure.
+
+.br
+
+.br
+
+.EX
+typedef struct
+.br
+{
+.br
+   uint32_t gpioOn;
+.br
+   uint32_t gpioOff;
+.br
+   uint32_t usDelay;
+.br
+} gpioPulse_t;
+.br
+
+.EE
+
+.br
+
+.br
+The fields specify
+
+.br
+
+.br
+1) the gpios to be switched on at the start of the pulse.
+.br
+2) the gpios to be switched off at the start of the pulse.
+.br
+3) the delay in microseconds before the next pulse.
+.br
+
+.br
+
+.br
+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).
+
+.br
+
+.br
+When a waveform is started each pulse is executed in order with the
+specified delay between the pulse and the next.
+
+.br
+
+.br
+Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM,
+PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL.
+
+.IP "\fBint wave_delete(int pi, unsigned wave_id)\fP"
+.IP "" 4
+This function deletes the waveform with id wave_id.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+wave_id: >=0, as returned by \fBwave_create\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Wave ids are allocated in order, 0, 1, 2, etc.
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_WAVE_ID.
+
+.IP "\fBint wave_send_once(int pi, unsigned wave_id)\fP"
+.IP "" 4
+This function transmits the waveform with id wave_id.  The waveform
+is sent once.
+
+.br
+
+.br
+NOTE: Any hardware PWM started by \fBhardware_PWM\fP will be cancelled.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+wave_id: >=0, as returned by \fBwave_create\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of DMA control blocks in the waveform if OK,
+otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+
+.IP "\fBint wave_send_repeat(int pi, unsigned wave_id)\fP"
+.IP "" 4
+This function transmits the waveform with id wave_id.  The waveform
+cycles until cancelled (either by the sending of a new waveform or
+by \fBwave_tx_stop\fP).
+
+.br
+
+.br
+NOTE: Any hardware PWM started by \fBhardware_PWM\fP will be cancelled.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+wave_id: >=0, as returned by \fBwave_create\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of DMA control blocks in the waveform if OK,
+otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+
+.IP "\fBint wave_chain(int pi, char *buf, unsigned bufSize)\fP"
+.IP "" 4
+This function transmits a chain of waveforms.
+
+.br
+
+.br
+NOTE: Any hardware PWM started by \fBhardware_PWM\fP will be cancelled.
+
+.br
+
+.br
+The waves to be transmitted are specified by the contents of buf
+which contains an ordered list of \fBwave_id\fPs and optional command
+codes and related data.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+    buf: pointer to the wave_ids and optional command codes
+.br
+bufSize: the number of bytes in buf
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_CHAIN_NESTING, PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, PI_CHAIN_COUNTER,
+PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, or PI_BAD_WAVE_ID.
+
+.br
+
+.br
+Each wave is transmitted in the order specified.  A wave may
+occur multiple times per chain.
+
+.br
+
+.br
+A blocks of waves may be transmitted multiple times by using
+the loop commands. The block is bracketed by loop start and
+end commands.  Loops may be nested.
+
+.br
+
+.br
+Delays between waves may be added with the delay command.
+
+.br
+
+.br
+The following command codes are supported:
+
+.br
+
+.br
+Name           Cmd & Data   Meaning
+
+.br
+Loop Start     255 0        Identify start of a wave block
+
+.br
+Loop Repeat    255 1 x y    loop x + y*256 times
+
+.br
+Delay          255 2 x y    delay x + y*256 microseconds
+
+.br
+Loop Forever   255 3        loop forever
+
+.br
+
+.br
+
+.br
+If present Loop Forever must be the last entry in the chain.
+
+.br
+
+.br
+The code is currently dimensioned to support a chain with roughly
+600 entries and 20 loop counters.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+#include <stdio.h>
+.br
+#include <pigpiod_if2.h>
+.br
+
+.br
+#define WAVES 5
+.br
+#define GPIO 4
+.br
+
+.br
+int main(int argc, char *argv[])
+.br
+{
+.br
+   int i, pi, wid[WAVES];
+.br
+
+.br
+   pi = pigpio_start(0, 0);
+.br
+   if (pi<0) return -1;
+.br
+
+.br
+   set_mode(pi, GPIO, PI_OUTPUT);
+.br
+
+.br
+   for (i=0; i<WAVES; i++)
+.br
+   {
+.br
+      wave_add_generic(pi, 2, (gpioPulse_t[])
+.br
+         {{1<<GPIO, 0,        20},
+.br
+          {0, 1<<GPIO, (i+1)*200}});
+.br
+
+.br
+      wid[i] = wave_create(pi);
+.br
+   }
+.br
+
+.br
+   wave_chain(pi, (char []) {
+.br
+      wid[4], wid[3], wid[2],       // transmit waves 4+3+2
+.br
+      255, 0,                       // loop start
+.br
+         wid[0], wid[0], wid[0],    // transmit waves 0+0+0
+.br
+         255, 0,                    // loop start
+.br
+            wid[0], wid[1],         // transmit waves 0+1
+.br
+            255, 2, 0x88, 0x13,     // delay 5000us
+.br
+         255, 1, 30, 0,             // loop end (repeat 30 times)
+.br
+         255, 0,                    // loop start
+.br
+            wid[2], wid[3], wid[0], // transmit waves 2+3+0
+.br
+            wid[3], wid[1], wid[2], // transmit waves 3+1+2
+.br
+         255, 1, 10, 0,             // loop end (repeat 10 times)
+.br
+      255, 1, 5, 0,                 // loop end (repeat 5 times)
+.br
+      wid[4], wid[4], wid[4],       // transmit waves 4+4+4
+.br
+      255, 2, 0x20, 0x4E,           // delay 20000us
+.br
+      wid[0], wid[0], wid[0],       // transmit waves 0+0+0
+.br
+
+.br
+      }, 46);
+.br
+
+.br
+   while (wave_tx_busy(pi)) time_sleep(0.1);
+.br
+
+.br
+   for (i=0; i<WAVES; i++) wave_delete(pi, wid[i]);
+.br
+
+.br
+   pigpio_stop(pi);
+.br
+}
+.br
+
+.EE
+
+.IP "\fBint wave_tx_busy(int pi)\fP"
+.IP "" 4
+This function checks to see if a waveform is currently being
+transmitted.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 1 if a waveform is currently being transmitted, otherwise 0.
+
+.IP "\fBint wave_tx_stop(int pi)\fP"
+.IP "" 4
+This function stops the transmission of the current waveform.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK.
+
+.br
+
+.br
+This function is intended to stop a waveform started with the repeat mode.
+
+.IP "\fBint wave_get_micros(int pi)\fP"
+.IP "" 4
+This function returns the length in microseconds of the current
+waveform.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_high_micros(int pi)\fP"
+.IP "" 4
+This function returns the length in microseconds of the longest waveform
+created since the pigpio daemon was started.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_max_micros(int pi)\fP"
+.IP "" 4
+This function returns the maximum possible size of a waveform in
+.br
+microseconds.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_pulses(int pi)\fP"
+.IP "" 4
+This function returns the length in pulses of the current waveform.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_high_pulses(int pi)\fP"
+.IP "" 4
+This function returns the length in pulses of the longest waveform
+created since the pigpio daemon was started.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_max_pulses(int pi)\fP"
+.IP "" 4
+This function returns the maximum possible size of a waveform in pulses.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_cbs(int pi)\fP"
+.IP "" 4
+This function returns the length in DMA control blocks of the current
+waveform.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_high_cbs(int pi)\fP"
+.IP "" 4
+This function returns the length in DMA control blocks of the longest
+waveform created since the pigpio daemon was started.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint wave_get_max_cbs(int pi)\fP"
+.IP "" 4
+This function returns the maximum possible size of a waveform in DMA
+control blocks.
+
+.br
+
+.br
+
+.EX
+pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+
+.EE
+
+.IP "\fBint gpio_trigger(int pi, unsigned user_gpio, unsigned pulseLen, unsigned level)\fP"
+.IP "" 4
+This function sends a trigger pulse to a gpio.  The gpio is set to
+level for pulseLen microseconds and then reset to not level.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+ pulseLen: 1-100.
+.br
+    level: 0,1.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL,
+PI_BAD_PULSELEN, or PI_NOT_PERMITTED.
+
+.IP "\fBint store_script(int pi, char *script)\fP"
+.IP "" 4
+This function stores a script for later execution.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+script: the text of the script.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns a script id if the script is valid,
+otherwise PI_BAD_SCRIPT.
+
+.IP "\fBint run_script(int pi, unsigned script_id, unsigned numPar, uint32_t *param)\fP"
+.IP "" 4
+This function runs a stored script.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+script_id: >=0, as returned by \fBstore_script\fP.
+.br
+   numPar: 0-10, the number of parameters.
+.br
+    param: an array of parameters.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or
+PI_TOO_MANY_PARAM
+
+.br
+
+.br
+param is an array of up to 10 parameters which may be referenced in
+the script as p0 to p9.
+
+.IP "\fBint script_status(int pi, unsigned script_id, uint32_t *param)\fP"
+.IP "" 4
+This function returns the run status of a stored script as well
+as the current values of parameters 0 to 9.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+script_id: >=0, as returned by \fBstore_script\fP.
+.br
+    param: an array to hold the returned 10 parameters.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns greater than or equal to 0 if OK,
+otherwise PI_BAD_SCRIPT_ID.
+
+.br
+
+.br
+The run status may be
+
+.br
+
+.br
+
+.EX
+PI_SCRIPT_INITING
+.br
+PI_SCRIPT_HALTED
+.br
+PI_SCRIPT_RUNNING
+.br
+PI_SCRIPT_WAITING
+.br
+PI_SCRIPT_FAILED
+.br
+
+.EE
+
+.br
+
+.br
+The current value of script parameters 0 to 9 are returned in param.
+
+.IP "\fBint stop_script(int pi, unsigned script_id)\fP"
+.IP "" 4
+This function stops a running script.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+script_id: >=0, as returned by \fBstore_script\fP.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+
+.IP "\fBint delete_script(int pi, unsigned script_id)\fP"
+.IP "" 4
+This function deletes a stored script.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+script_id: >=0, as returned by \fBstore_script\fP.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+
+.IP "\fBint bb_serial_read_open(int pi, unsigned user_gpio, unsigned baud, unsigned data_bits)\fP"
+.IP "" 4
+This function opens a gpio for bit bang reading of serial data.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+     baud: 50-250000
+.br
+data_bits: 1-32
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
+or PI_GPIO_IN_USE.
+
+.br
+
+.br
+The serial data is returned in a cyclic buffer and is read using
+bb_serial_read.
+
+.br
+
+.br
+It is the caller's responsibility to read data from the cyclic buffer
+in a timely fashion.
+
+.IP "\fBint bb_serial_read(int pi, unsigned user_gpio, void *buf, size_t bufSize)\fP"
+.IP "" 4
+This function copies up to bufSize bytes of data read from the
+bit bang serial cyclic buffer to the buffer starting at buf.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31, previously opened with \fBbb_serial_read_open\fP.
+.br
+      buf: an array to receive the read bytes.
+.br
+  bufSize: 0-
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
+or PI_NOT_SERIAL_GPIO.
+
+.br
+
+.br
+The bytes returned for each character depend upon the number of
+data bits \fBdata_bits\fP specified in the \fBbb_serial_read_open\fP command.
+
+.br
+
+.br
+For \fBdata_bits\fP 1-8 there will be one byte per character.
+.br
+For \fBdata_bits\fP 9-16 there will be two bytes per character.
+.br
+For \fBdata_bits\fP 17-32 there will be four bytes per character.
+
+.IP "\fBint bb_serial_read_close(int pi, unsigned user_gpio)\fP"
+.IP "" 4
+This function closes a gpio for bit bang reading of serial data.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31, previously opened with \fBbb_serial_read_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
+
+.IP "\fBint bb_serial_invert(int pi, unsigned user_gpio, unsigned invert)\fP"
+.IP "" 4
+This function inverts serial logic for big bang serial reads.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31, previously opened with \fBbb_serial_read_open\fP.
+.br
+   invert: 0-1, 1 invert, 0 normal.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_NOT_SERIAL_GPIO or PI_BAD_SER_INVERT.
+
+.IP "\fBint i2c_open(int pi, unsigned i2c_bus, unsigned i2c_addr, unsigned i2c_flags)\fP"
+.IP "" 4
+This returns a handle for the device at address i2c_addr on bus i2c_bus.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+  i2c_bus: 0-1.
+.br
+ i2c_addr: 0x00-0x7F.
+.br
+i2c_flags: 0.
+.br
+
+.EE
+
+.br
+
+.br
+No flags are currently defined.  This parameter should be set to zero.
+
+.br
+
+.br
+Returns a handle (>=0) if OK, otherwise PI_BAD_I2C_BUS, PI_BAD_I2C_ADDR,
+PI_BAD_FLAGS, PI_NO_HANDLE, or PI_I2C_OPEN_FAILED.
+
+.br
+
+.br
+For the SMBus commands the low level transactions are shown at the end
+of the function description.  The following abbreviations are used.
+
+.br
+
+.br
+
+.EX
+S       (1 bit) : Start bit
+.br
+P       (1 bit) : Stop bit
+.br
+Rd/Wr   (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
+.br
+A, NA   (1 bit) : Accept and not accept bit.
+.br
+.br
+.br
+Addr    (7 bits): I2C 7 bit address.
+.br
+i2c_reg (8 bits): A byte which often selects a register.
+.br
+Data    (8 bits): A data byte.
+.br
+Count   (8 bits): A byte defining the length of a block operation.
+.br
+
+.br
+[..]: Data sent by the device.
+.br
+
+.EE
+
+.IP "\fBint i2c_close(int pi, unsigned handle)\fP"
+.IP "" 4
+This closes the I2C device associated with the handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.IP "\fBint i2c_write_quick(int pi, unsigned handle, unsigned bit)\fP"
+.IP "" 4
+This sends a single bit (in the Rd/Wr bit) to the device associated
+with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+   bit: 0-1, the value to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+Quick command. SMBus 2.0 5.5.1
+
+.EX
+S Addr bit [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_byte(int pi, unsigned handle, unsigned bVal)\fP"
+.IP "" 4
+This sends a single byte to the device associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+  bVal: 0-0xFF, the value to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+Send byte. SMBus 2.0 5.5.2
+
+.EX
+S Addr Wr [A] bVal [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_byte(int pi, unsigned handle)\fP"
+.IP "" 4
+This reads a single byte from the device associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE,
+or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+Receive byte. SMBus 2.0 5.5.3
+
+.EX
+S Addr Rd [A] [Data] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_byte_data(int pi, unsigned handle, unsigned i2c_reg, unsigned bVal)\fP"
+.IP "" 4
+This writes a single byte to the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write.
+.br
+   bVal: 0-0xFF, the value to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+Write byte. SMBus 2.0 5.5.4
+
+.EX
+S Addr Wr [A] i2c_reg [A] bVal [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_word_data(int pi, unsigned handle, unsigned i2c_reg, unsigned wVal)\fP"
+.IP "" 4
+This writes a single 16 bit word to the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write.
+.br
+   wVal: 0-0xFFFF, the value to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+Write word. SMBus 2.0 5.5.4
+
+.EX
+S Addr Wr [A] i2c_reg [A] wval_Low [A] wVal_High [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_byte_data(int pi, unsigned handle, unsigned i2c_reg)\fP"
+.IP "" 4
+This reads a single byte from the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+Read byte. SMBus 2.0 5.5.5
+
+.EX
+S Addr Wr [A] i2c_reg [A] S Addr Rd [A] [Data] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_word_data(int pi, unsigned handle, unsigned i2c_reg)\fP"
+.IP "" 4
+This reads a single 16 bit word from the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+Read word. SMBus 2.0 5.5.5
+
+.EX
+S Addr Wr [A] i2c_reg [A]
+.br
+   S Addr Rd [A] [DataLow] A [DataHigh] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_process_call(int pi, unsigned handle, unsigned i2c_reg, unsigned wVal)\fP"
+.IP "" 4
+This writes 16 bits of data to the specified register of the device
+associated with handle and and reads 16 bits of data in return.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write/read.
+.br
+   wVal: 0-0xFFFF, the value to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+Process call. SMBus 2.0 5.5.6
+
+.EX
+S Addr Wr [A] i2c_reg [A] wVal_Low [A] wVal_High [A]
+.br
+   S Addr Rd [A] [DataLow] A [DataHigh] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_block_data(int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count)\fP"
+.IP "" 4
+This writes up to 32 bytes to the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write.
+.br
+    buf: an array with the data to send.
+.br
+  count: 1-32, the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+Block write. SMBus 2.0 5.5.7
+
+.EX
+S Addr Wr [A] i2c_reg [A] count [A] buf0 [A] buf1 [A] ...
+.br
+   [A] bufn [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_block_data(int pi, unsigned handle, unsigned i2c_reg, char *buf)\fP"
+.IP "" 4
+This reads a block of up to 32 bytes from the specified register of
+the device associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to read.
+.br
+    buf: an array to receive the read data.
+.br
+
+.EE
+
+.br
+
+.br
+The amount of returned data is set by the device.
+
+.br
+
+.br
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+Block read. SMBus 2.0 5.5.7
+
+.EX
+S Addr Wr [A] i2c_reg [A]
+.br
+   S Addr Rd [A] [Count] A [buf0] A [buf1] A ... A [bufn] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_block_process_call(int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count)\fP"
+.IP "" 4
+This writes data bytes to the specified register of the device
+associated with handle and reads a device specified number
+of bytes of data in return.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write/read.
+.br
+    buf: an array with the data to send and to receive the read data.
+.br
+  count: 1-32, the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+
+.br
+
+.br
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+The smbus 2.0 documentation states that a minimum of 1 byte may be
+sent and a minimum of 1 byte may be received.  The total number of
+bytes sent/received must be 32 or less.
+
+.br
+
+.br
+Block write-block read. SMBus 2.0 5.5.8
+
+.EX
+S Addr Wr [A] i2c_reg [A] count [A] buf0 [A] ...
+.br
+   S Addr Rd [A] [Count] A [Data] ... A P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_i2c_block_data(int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count)\fP"
+.IP "" 4
+This reads count bytes from the specified register of the device
+associated with handle .  The count may be 1-32.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to read.
+.br
+    buf: an array to receive the read data.
+.br
+  count: 1-32, the number of bytes to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+.br
+
+.br
+
+.EX
+S Addr Wr [A] i2c_reg [A]
+.br
+   S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_i2c_block_data(int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count)\fP"
+.IP "" 4
+This writes 1 to 32 bytes to the specified register of the device
+associated with handle.
+
+.br
+
+.br
+
+.EX
+     pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+i2c_reg: 0-255, the register to write.
+.br
+    buf: the data to write.
+.br
+  count: 1-32, the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+
+.EX
+S Addr Wr [A] i2c_reg [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_read_device(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This reads count bytes from the raw device into buf.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+   buf: an array to receive the read data bytes.
+.br
+ count: >0, the number of bytes to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns count (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_READ_FAILED.
+
+.br
+
+.br
+
+.EX
+S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+.br
+
+.EE
+
+.IP "\fBint i2c_write_device(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This writes count bytes from buf to the raw device.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2c_open\fP.
+.br
+   buf: an array containing the data bytes to write.
+.br
+ count: >0, the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+
+.EX
+S Addr Wr [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+.br
+
+.EE
+
+.IP "\fBint i2c_zip(int pi, unsigned handle, char *inBuf, unsigned inLen, char *outBuf, unsigned outLen)\fP"
+.IP "" 4
+This function executes a sequence of I2C operations.  The
+operations to be performed are specified by the contents of inBuf
+which contains the concatenated command codes and associated data.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBi2cOpen\fP
+.br
+ inBuf: pointer to the concatenated I2C commands, see below
+.br
+ inLen: size of command buffer
+.br
+outBuf: pointer to buffer to hold returned data
+.br
+outLen: size of output buffer
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_HANDLE, PI_BAD_POINTER, PI_BAD_I2C_CMD, PI_BAD_I2C_RLEN.
+PI_BAD_I2C_WLEN, or PI_BAD_I2C_SEG.
+
+.br
+
+.br
+The following command codes are supported:
+
+.br
+
+.br
+Name      Cmd & Data   Meaning
+
+.br
+End       0            No more commands
+
+.br
+Escape    1            Next P is two bytes
+
+.br
+On        2            Switch combined flag on
+
+.br
+Off       3            Switch combined flag off
+
+.br
+Address   4 P          Set I2C address to P
+
+.br
+Flags     5 lsb msb    Set I2C flags to lsb + (msb << 8)
+
+.br
+Read      6 P          Read P bytes of data
+
+.br
+Write     7 P ...      Write P bytes of data
+
+.br
+
+.br
+
+.br
+The address, read, and write commands take a parameter P.
+Normally P is one byte (0-255).  If the command is preceded by
+the Escape command then P is two bytes (0-65535, least significant
+byte first).
+
+.br
+
+.br
+The address defaults to that associated with the handle.
+The flags default to 0.  The address and flags maintain their
+previous value until updated.
+
+.br
+
+.br
+The returned I2C data is stored in consecutive locations of outBuf.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+Set address 0x53, write 0x32, read 6 bytes
+.br
+Set address 0x1E, write 0x03, read 6 bytes
+.br
+Set address 0x68, write 0x1B, read 8 bytes
+.br
+End
+.br
+
+.br
+0x04 0x53   0x07 0x01 0x32   0x06 0x06
+.br
+0x04 0x1E   0x07 0x01 0x03   0x06 0x06
+.br
+0x04 0x68   0x07 0x01 0x1B   0x06 0x08
+.br
+0x00
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBint bb_i2c_open(int pi, unsigned SDA, unsigned SCL, unsigned baud)\fP"
+.IP "" 4
+This function selects a pair of gpios for bit banging I2C at a
+specified baud rate.
+
+.br
+
+.br
+Bit banging I2C allows for certain operations which are not possible
+with the standard I2C driver.
+
+.br
+
+.br
+o baud rates as low as 50
+.br
+o repeated starts
+.br
+o clock stretching
+.br
+o I2C on any pair of spare gpios
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+ SDA: 0-31
+.br
+ SCL: 0-31
+.br
+baud: 50-500000
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_I2C_BAUD, or
+PI_GPIO_IN_USE.
+
+.br
+
+.br
+NOTE:
+
+.br
+
+.br
+The gpios used for SDA and SCL must have pull-ups to 3V3 connected.  As
+a guide the hardware pull-ups on pins 3 and 5 are 1k8 in value.
+
+.IP "\fBint bb_i2c_close(int pi, unsigned SDA)\fP"
+.IP "" 4
+This function stops bit banging I2C on a pair of gpios previously
+opened with \fBbb_i2c_open\fP.
+
+.br
+
+.br
+
+.EX
+ pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+SDA: 0-31, the SDA gpio used in a prior call to \fBbb_i2c_open\fP
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO.
+
+.IP "\fBint bb_i2c_zip(int pi, unsigned SDA, char *inBuf, unsigned inLen, char *outBuf, unsigned outLen)\fP"
+.IP "" 4
+This function executes a sequence of bit banged I2C operations.  The
+operations to be performed are specified by the contents of inBuf
+which contains the concatenated command codes and associated data.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+   SDA: 0-31 (as used in a prior call to \fBbb_i2c_open\fP)
+.br
+ inBuf: pointer to the concatenated I2C commands, see below
+.br
+ inLen: size of command buffer
+.br
+outBuf: pointer to buffer to hold returned data
+.br
+outLen: size of output buffer
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_I2C_GPIO, PI_BAD_POINTER,
+PI_BAD_I2C_CMD, PI_BAD_I2C_RLEN, PI_BAD_I2C_WLEN,
+PI_I2C_READ_FAILED, or PI_I2C_WRITE_FAILED.
+
+.br
+
+.br
+The following command codes are supported:
+
+.br
+
+.br
+Name      Cmd & Data     Meaning
+
+.br
+End       0              No more commands
+
+.br
+Escape    1              Next P is two bytes
+
+.br
+Start     2              Start condition
+
+.br
+Stop      3              Stop condition
+
+.br
+Address   4 P            Set I2C address to P
+
+.br
+Flags     5 lsb msb      Set I2C flags to lsb + (msb << 8)
+
+.br
+Read      6 P            Read P bytes of data
+
+.br
+Write     7 P ...        Write P bytes of data
+
+.br
+
+.br
+
+.br
+The address, read, and write commands take a parameter P.
+Normally P is one byte (0-255).  If the command is preceded by
+the Escape command then P is two bytes (0-65535, least significant
+byte first).
+
+.br
+
+.br
+The address and flags default to 0.  The address and flags maintain
+their previous value until updated.
+
+.br
+
+.br
+No flags are currently defined.
+
+.br
+
+.br
+The returned I2C data is stored in consecutive locations of outBuf.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+Set address 0x53
+.br
+start, write 0x32, (re)start, read 6 bytes, stop
+.br
+Set address 0x1E
+.br
+start, write 0x03, (re)start, read 6 bytes, stop
+.br
+Set address 0x68
+.br
+start, write 0x1B, (re)start, read 8 bytes, stop
+.br
+End
+.br
+
+.br
+0x04 0x53
+.br
+0x02 0x07 0x01 0x32   0x02 0x06 0x06 0x03
+.br
+
+.br
+0x04 0x1E
+.br
+0x02 0x07 0x01 0x03   0x02 0x06 0x06 0x03
+.br
+
+.br
+0x04 0x68
+.br
+0x02 0x07 0x01 0x1B   0x02 0x06 0x08 0x03
+.br
+
+.br
+0x00
+.br
+
+.EE
+
+.IP "\fBint spi_open(int pi, unsigned spi_channel, unsigned baud, unsigned spi_flags)\fP"
+.IP "" 4
+This function returns a handle for the SPI device on channel.
+Data will be transferred at baud bits per second.  The flags may
+be used to modify the default behaviour of 4-wire operation, mode 0,
+active low chip select.
+
+.br
+
+.br
+An auxiliary SPI device is available on the A+/B+/Pi2 and may be
+selected by setting the A bit in the flags.  The auxiliary
+device has 3 chip selects and a selectable word size in bits.
+
+.br
+
+.br
+
+.EX
+         pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+spi_channel: 0-1 (0-2 for A+/B+/Pi2 auxiliary device).
+.br
+       baud: 32K-125M (values above 30M are unlikely to work).
+.br
+  spi_flags: see below.
+.br
+
+.EE
+
+.br
+
+.br
+Returns a handle (>=0) if OK, otherwise PI_BAD_SPI_CHANNEL,
+PI_BAD_SPI_SPEED, PI_BAD_FLAGS, PI_NO_AUX_SPI, or PI_SPI_OPEN_FAILED.
+
+.br
+
+.br
+spi_flags consists of the least significant 22 bits.
+
+.br
+
+.br
+
+.EX
+21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ b  b  b  b  b  b  R  T  n  n  n  n  W  A u2 u1 u0 p2 p1 p0  m  m
+.br
+
+.EE
+
+.br
+
+.br
+mm defines the SPI mode.
+
+.br
+
+.br
+Warning: modes 1 and 3 do not appear to work on the auxiliary device.
+
+.br
+
+.br
+
+.EX
+Mode POL PHA
+.br
+ 0    0   0
+.br
+ 1    0   1
+.br
+ 2    1   0
+.br
+ 3    1   1
+.br
+
+.EE
+
+.br
+
+.br
+px is 0 if CEx is active low (default) and 1 for active high.
+
+.br
+
+.br
+ux is 0 if the CEx gpio is reserved for SPI (default) and 1 otherwise.
+
+.br
+
+.br
+A is 0 for the standard SPI device, 1 for the auxiliary SPI.  The
+auxiliary device is only present on the A+/B+/Pi2.
+
+.br
+
+.br
+W is 0 if the device is not 3-wire, 1 if the device is 3-wire.  Standard
+SPI device only.
+
+.br
+
+.br
+nnnn defines the number of bytes (0-15) to write before switching
+the MOSI line to MISO to read data.  This field is ignored
+if W is not set.  Standard SPI device only.
+
+.br
+
+.br
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.  Auxiliary SPI
+device only.
+
+.br
+
+.br
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.  Auxiliary SPI
+device only.
+
+.br
+
+.br
+bbbbbb defines the word size in bits (0-32).  The default (0)
+sets 8 bits per word.  Auxiliary SPI device only.
+
+.br
+
+.br
+The other bits in flags should be set to zero.
+
+.IP "\fBint spi_close(int pi, unsigned handle)\fP"
+.IP "" 4
+This functions closes the SPI device identified by the handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBspi_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.IP "\fBint spi_read(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This function reads count bytes of data from the SPI
+device associated with the handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBspi_open\fP.
+.br
+   buf: an array to receive the read data bytes.
+.br
+ count: the number of bytes to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+
+.IP "\fBint spi_write(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This function writes count bytes of data from buf to the SPI
+device associated with the handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBspi_open\fP.
+.br
+   buf: the data bytes to write.
+.br
+ count: the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+
+.IP "\fBint spi_xfer(int pi, unsigned handle, char *txBuf, char *rxBuf, unsigned count)\fP"
+.IP "" 4
+This function transfers count bytes of data from txBuf to the SPI
+device associated with the handle.  Simultaneously count bytes of
+data are read from the device and placed in rxBuf.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBspi_open\fP.
+.br
+ txBuf: the data bytes to write.
+.br
+ rxBuf: the received data bytes.
+.br
+ count: the number of bytes to transfer.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+
+.IP "\fBint serial_open(int pi, char *ser_tty, unsigned baud, unsigned ser_flags)\fP"
+.IP "" 4
+This function opens a serial device at a specified baud rate
+with specified flags.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+  ser_tty: the serial device to open, /dev/tty*.
+.br
+     baud: the baud rate in bits per second, see below.
+.br
+ser_flags: 0.
+.br
+
+.EE
+
+.br
+
+.br
+Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or
+PI_SER_OPEN_FAILED.
+
+.br
+
+.br
+The baud rate must be one of 50, 75, 110, 134, 150,
+200, 300, 600, 1200, 1800, 2400, 4800, 9500, 19200,
+38400, 57600, 115200, or 230400.
+
+.br
+
+.br
+No flags are currently defined.  This parameter should be set to zero.
+
+.IP "\fBint serial_close(int pi, unsigned handle)\fP"
+.IP "" 4
+This function closes the serial device associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.IP "\fBint serial_write_byte(int pi, unsigned handle, unsigned bVal)\fP"
+.IP "" 4
+This function writes bVal to the serial port associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_SER_WRITE_FAILED.
+
+.IP "\fBint serial_read_byte(int pi, unsigned handle)\fP"
+.IP "" 4
+This function reads a byte from the serial port associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
+
+.IP "\fBint serial_write(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This function writes count bytes from buf to the the serial port
+associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+   buf: the array of bytes to write.
+.br
+ count: the number of bytes to write.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_SER_WRITE_FAILED.
+
+.IP "\fBint serial_read(int pi, unsigned handle, char *buf, unsigned count)\fP"
+.IP "" 4
+This function reads up to count bytes from the the serial port
+associated with handle and writes them to buf.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+   buf: an array to receive the read data.
+.br
+ count: the maximum number of bytes to read.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
+
+.IP "\fBint serial_data_available(int pi, unsigned handle)\fP"
+.IP "" 4
+Returns the number of bytes available to be read from the
+device associated with handle.
+
+.br
+
+.br
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+handle: >=0, as returned by a call to \fBserial_open\fP.
+.br
+
+.EE
+
+.br
+
+.br
+Returns the number of bytes of data available (>=0) if OK,
+otherwise PI_BAD_HANDLE.
+
+.IP "\fBint custom_1(int pi, unsigned arg1, unsigned arg2, char *argx, unsigned argc)\fP"
+.IP "" 4
+This function is available for user customisation.
+
+.br
+
+.br
+It returns a single integer value.
+
+.br
+
+.br
+
+.EX
+  pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+arg1: >=0
+.br
+arg2: >=0
+.br
+argx: extra (byte) arguments
+.br
+argc: number of extra arguments
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK, less than 0 indicates a user defined error.
+
+.IP "\fBint custom_2(int pi, unsigned arg1, char *argx, unsigned argc, char *retBuf, unsigned retMax)\fP"
+.IP "" 4
+This function is available for user customisation.
+
+.br
+
+.br
+It differs from custom_1 in that it returns an array of bytes
+rather than just an integer.
+
+.br
+
+.br
+The return value is an integer indicating the number of returned bytes.
+
+.EX
+    pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+  arg1: >=0
+.br
+  argc: extra (byte) arguments
+.br
+ count: number of extra arguments
+.br
+retBuf: buffer for returned data
+.br
+retMax: maximum number of bytes to return
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK, less than 0 indicates a user defined error.
+
+.br
+
+.br
+Note, the number of returned bytes will be retMax or less.
+
+.IP "\fBint callback(int pi, unsigned user_gpio, unsigned edge, CBFunc_t f)\fP"
+.IP "" 4
+This function initialises a new callback.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+.br
+        f: the callback function.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+.br
+
+.br
+The callback is called with the gpio, edge, and tick, whenever the
+gpio has the identified edge.
+
+.IP "\fBint callback_ex(int pi, unsigned user_gpio, unsigned edge, CBFuncEx_t f, void *userdata)\fP"
+.IP "" 4
+This function initialises a new callback.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+.br
+        f: the callback function.
+.br
+ userdata: a pointer to arbitrary user data.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+.br
+
+.br
+The callback is called with the gpio, edge, tick, and user, whenever
+the gpio has the identified edge.
+
+.IP "\fBint callback_cancel(unsigned callback_id)\fP"
+.IP "" 4
+This function cancels a callback identified by its id.
+
+.br
+
+.br
+
+.EX
+callback_id: >=0, as returned by a call to \fBcallback\fP or \fBcallback_ex\fP.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 0 if OK, otherwise pigif_callback_not_found.
+
+.IP "\fBint wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout)\fP"
+.IP "" 4
+This function waits for edge on the gpio for up to timeout
+seconds.
+
+.br
+
+.br
+
+.EX
+       pi: 0- (as returned by \fBpigpio_start\fP).
+.br
+user_gpio: 0-31.
+.br
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+.br
+  timeout: >=0.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 1 if the edge occurred, otherwise 0.
+
+.br
+
+.br
+The function returns when the edge occurs or after the timeout.
+.SH PARAMETERS
+
+.br
+
+.br
+
+.IP "\fBactive\fP: 0-1000000" 0
+
+.br
+
+.br
+The number of microseconds level changes are reported for once
+a noise filter has been triggered (by \fBsteady\fP microseconds of
+a stable level).
+
+.br
+
+.br
+
+.IP "\fB*addrStr\fP" 0
+A string specifying the host or IP address of the Pi running
+the pigpio daemon.  It may be NULL in which case localhost
+is used unless overridden by the PIGPIO_ADDR environment
+variable.
+
+.br
+
+.br
+
+.IP "\fBarg1\fP" 0
+An unsigned argument passed to a user customised function.  Its
+meaning is defined by the customiser.
+
+.br
+
+.br
+
+.IP "\fBarg2\fP" 0
+An unsigned argument passed to a user customised function.  Its
+meaning is defined by the customiser.
+
+.br
+
+.br
+
+.IP "\fBargc\fP" 0
+The count of bytes passed to a user customised function.
+
+.br
+
+.br
+
+.IP "\fB*argx\fP" 0
+A pointer to an array of bytes passed to a user customised function.
+Its meaning and content is defined by the customiser.
+
+.br
+
+.br
+
+.IP "\fBbaud\fP" 0
+The speed of serial communication (I2C, SPI, serial link, waves) in
+bits per second.
+
+.br
+
+.br
+
+.IP "\fBbit\fP" 0
+A value of 0 or 1.
+
+.br
+
+.br
+
+.IP "\fBbits\fP" 0
+A value used to select gpios.  If bit n of bits is set then gpio n is
+selected.
+
+.br
+
+.br
+A convenient way to set bit n is to or in (1<<n).
+
+.br
+
+.br
+e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
+
+.br
+
+.br
+
+.IP "\fB*buf\fP" 0
+A buffer to hold data being sent or being received.
+
+.br
+
+.br
+
+.IP "\fBbufSize\fP" 0
+The size in bytes of a buffer.
+
+.br
+
+.br
+
+.br
+
+.br
+
+.IP "\fBbVal\fP: 0-255 (Hex 0x0-0xFF, Octal 0-0377)" 0
+An 8-bit byte value.
+
+.br
+
+.br
+
+.IP "\fBcallback_id\fP" 0
+A >=0, as returned by a call to \fBcallback\fP or \fBcallback_ex\fP.  This is
+passed to \fBcallback_cancel\fP to cancel the callback.
+
+.br
+
+.br
+
+.IP "\fBCBFunc_t\fP" 0
+
+.EX
+typedef void (*CBFunc_t)
+.br
+   (unsigned user_gpio, unsigned level, uint32_t tick);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBCBFuncEx_t\fP" 0
+
+.EX
+typedef void (*CBFuncEx_t)
+.br
+   (unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBchar\fP" 0
+A single character, an 8 bit quantity able to store 0-255.
+
+.br
+
+.br
+
+.IP "\fBclkfreq\fP: 4689-250000000 (250M)" 0
+The hardware clock frequency.
+
+.br
+
+.br
+
+.IP "\fBcount\fP" 0
+The number of bytes to be transferred in an I2C, SPI, or Serial
+command.
+
+.br
+
+.br
+
+.IP "\fBdata_bits\fP: 1-32" 0
+The number of data bits in each character of serial data.
+
+.br
+
+.br
+
+.EX
+#define PI_MIN_WAVE_DATABITS 1
+.br
+#define PI_MAX_WAVE_DATABITS 32
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBdouble\fP" 0
+A floating point number.
+
+.br
+
+.br
+
+.IP "\fBdutycycle\fP: 0-range" 0
+A number representing the ratio of on time to off time for PWM.
+
+.br
+
+.br
+The number may vary between 0 and range (default 255) where
+0 is off and range is fully on.
+
+.br
+
+.br
+
+.IP "\fBedge\fP" 0
+Used to identify a gpio level transition of interest.  A rising edge is
+a level change from 0 to 1.  A falling edge is a level change from 1 to 0.
+
+.br
+
+.br
+
+.EX
+RISING_EDGE  0
+.br
+FALLING_EDGE 1
+.br
+EITHER_EDGE. 2
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBerrnum\fP" 0
+A negative number indicating a function call failed and the nature
+of the error.
+
+.br
+
+.br
+
+.IP "\fBf\fP" 0
+A function.
+
+.br
+
+.br
+
+.IP "\fBfrequency\fP: 0-" 0
+The number of times a gpio is swiched on and off per second.  This
+can be set per gpio and may be as little as 5Hz or as much as
+40KHz.  The gpio will be on for a proportion of the time as defined
+by its dutycycle.
+
+.br
+
+.br
+
+.br
+
+.br
+
+.IP "\fBgpio\fP" 0
+A Broadcom numbered gpio, in the range 0-53.
+
+.br
+
+.br
+There  are 54 General Purpose Input Outputs (gpios) named gpio0 through
+gpio53.
+
+.br
+
+.br
+They are split into two  banks.   Bank  1  consists  of  gpio0  through
+gpio31.  Bank 2 consists of gpio32 through gpio53.
+
+.br
+
+.br
+All the gpios which are safe for the user to read and write are in
+bank 1.  Not all gpios in bank 1 are safe though.  Type 1 boards
+have 17  safe gpios.  Type 2 boards have 21.  Type 3 boards have 26.
+
+.br
+
+.br
+See \fBget_hardware_revision\fP.
+
+.br
+
+.br
+The user gpios are marked with an X in the following table.
+
+.br
+
+.br
+
+.EX
+          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+.br
+Type 1    X  X  -  -  X  -  -  X  X  X  X  X  -  -  X  X
+.br
+Type 2    -  -  X  X  X  -  -  X  X  X  X  X  -  -  X  X
+.br
+Type 3          X  X  X  X  X  X  X  X  X  X  X  X  X  X
+.br
+
+.br
+         16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+.br
+Type 1    -  X  X  -  -  X  X  X  X  X  -  -  -  -  -  -
+.br
+Type 2    -  X  X  -  -  -  X  X  X  X  -  X  X  X  X  X
+.br
+Type 3    X  X  X  X  X  X  X  X  X  X  X  X  -  -  -  -
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBgpioPulse_t\fP" 0
+
+.EX
+typedef struct
+.br
+{
+.br
+uint32_t gpioOn;
+.br
+uint32_t gpioOff;
+.br
+uint32_t usDelay;
+.br
+} gpioPulse_t;
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBgpioThreadFunc_t\fP" 0
+
+.EX
+typedef void *(gpioThreadFunc_t) (void *);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBhandle\fP: 0-" 0
+A number referencing an object opened by one of \fBi2c_open\fP, \fBnotify_open\fP,
+\fBserial_open\fP, and \fBspi_open\fP.
+
+.br
+
+.br
+
+.IP "\fBi2c_addr\fP" 0
+The address of a device on the I2C bus.
+
+.br
+
+.br
+
+.IP "\fBi2c_bus\fP: 0-1" 0
+An I2C bus, 0 or 1.
+
+.br
+
+.br
+
+.IP "\fBi2c_flags\fP: 0" 0
+Flags which modify an I2C open command.  None are currently defined.
+
+.br
+
+.br
+
+.IP "\fBi2c_reg\fP: 0-255" 0
+A register of an I2C device.
+
+.br
+
+.br
+
+.IP "\fB*inBuf\fP" 0
+A buffer used to pass data to a function.
+
+.br
+
+.br
+
+.IP "\fBinLen\fP" 0
+The number of bytes of data in a buffer.
+
+.br
+
+.br
+
+.IP "\fBint\fP" 0
+A whole number, negative or positive.
+
+.br
+
+.br
+
+.IP "\fBinvert\fP" 0
+A flag used to set normal or inverted bit bang serial data level logic.
+
+.br
+
+.br
+
+.IP "\fBlevel\fP" 0
+The level of a gpio.  Low or High.
+
+.br
+
+.br
+
+.EX
+PI_OFF 0
+.br
+PI_ON 1
+.br
+
+.br
+PI_CLEAR 0
+.br
+PI_SET 1
+.br
+
+.br
+PI_LOW 0
+.br
+PI_HIGH 1
+.br
+
+.EE
+
+.br
+
+.br
+There is one exception.  If a watchdog expires on a gpio the level will be
+reported as PI_TIMEOUT.  See \fBset_watchdog\fP.
+
+.br
+
+.br
+
+.EX
+PI_TIMEOUT 2
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBmode\fP: 0-7" 0
+The operational mode of a gpio, normally INPUT or OUTPUT.
+
+.br
+
+.br
+
+.EX
+PI_INPUT 0
+.br
+PI_OUTPUT 1
+.br
+PI_ALT0 4
+.br
+PI_ALT1 5
+.br
+PI_ALT2 6
+.br
+PI_ALT3 7
+.br
+PI_ALT4 3
+.br
+PI_ALT5 2
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBnumBytes\fP" 0
+The number of bytes used to store characters in a string.  Depending
+on the number of bits per character there may be 1, 2, or 4 bytes
+per character.
+
+.br
+
+.br
+
+.IP "\fBnumPar\fP: 0-10" 0
+The number of parameters passed to a script.
+
+.br
+
+.br
+
+.IP "\fBnumPulses\fP" 0
+The number of pulses to be added to a waveform.
+
+.br
+
+.br
+
+.IP "\fBoffset\fP" 0
+The associated data starts this number of microseconds from the start of
+the waveform.
+
+.br
+
+.br
+
+.IP "\fB*outBuf\fP" 0
+A buffer used to return data from a function.
+
+.br
+
+.br
+
+.IP "\fBoutLen\fP" 0
+The size in bytes of an output buffer.
+
+.br
+
+.br
+
+.IP "\fB*param\fP" 0
+An array of script parameters.
+
+.br
+
+.br
+
+.IP "\fBpi\fP" 0
+An integer defining a connected Pi.  The value is returned by
+\fBpigpio_start\fP upon success.
+
+.br
+
+.br
+
+.IP "\fB*portStr\fP" 0
+A string specifying the port address used by the Pi running
+the pigpio daemon.  It may be NULL in which case "8888"
+is used unless overridden by the PIGPIO_PORT environment
+variable.
+
+.br
+
+.br
+
+.IP "\fB*pth\fP" 0
+A thread identifier, returned by \fBstart_thread\fP.
+
+.br
+
+.br
+
+.br
+
+.br
+
+.IP "\fBpthread_t\fP" 0
+A thread identifier.
+
+.br
+
+.br
+
+.IP "\fBpud\fP: 0-2" 0
+The setting of the pull up/down resistor for a gpio, which may be off,
+pull-up, or pull-down.
+
+.EX
+PI_PUD_OFF 0
+.br
+PI_PUD_DOWN 1
+.br
+PI_PUD_UP 2
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBpulseLen\fP" 0
+1-100, the length of a trigger pulse in microseconds.
+
+.br
+
+.br
+
+.IP "\fB*pulses\fP" 0
+An array of pulses to be added to a waveform.
+
+.br
+
+.br
+
+.IP "\fBpulsewidth\fP: 0, 500-2500" 0
+
+.EX
+PI_SERVO_OFF 0
+.br
+PI_MIN_SERVO_PULSEWIDTH 500
+.br
+PI_MAX_SERVO_PULSEWIDTH 2500
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBPWMduty\fP: 0-1000000 (1M)" 0
+The hardware PWM dutycycle.
+
+.br
+
+.br
+
+.EX
+#define PI_HW_PWM_RANGE 1000000
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBPWMfreq\fP: 1-125000000 (125M)" 0
+The hardware PWM frequency.
+
+.br
+
+.br
+
+.EX
+#define PI_HW_PWM_MIN_FREQ 1
+.br
+#define PI_HW_PWM_MAX_FREQ 125000000
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBrange\fP: 25-40000" 0
+The permissible dutycycle values are 0-range.
+
+.EX
+PI_MIN_DUTYCYCLE_RANGE 25
+.br
+PI_MAX_DUTYCYCLE_RANGE 40000
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fB*retBuf\fP" 0
+A buffer to hold a number of bytes returned to a used customised function,
+
+.br
+
+.br
+
+.IP "\fBretMax\fP" 0
+The maximum number of bytes a user customised function should return.
+
+.br
+
+.br
+
+.br
+
+.br
+
+.IP "\fB*rxBuf\fP" 0
+A pointer to a buffer to receive data.
+
+.br
+
+.br
+
+.IP "\fBSCL\fP" 0
+The user gpio to use for the clock when bit banging I2C.
+
+.br
+
+.br
+
+.IP "\fB*script\fP" 0
+A pointer to the text of a script.
+
+.br
+
+.br
+
+.IP "\fBscript_id\fP" 0
+An id of a stored script as returned by \fBstore_script\fP.
+
+.br
+
+.br
+
+.IP "\fBSDA\fP" 0
+The user gpio to use for data when bit banging I2C.
+
+.br
+
+.br
+
+.IP "\fBseconds\fP" 0
+The number of seconds.
+
+.br
+
+.br
+
+.IP "\fBser_flags\fP" 0
+Flags which modify a serial open command.  None are currently defined.
+
+.br
+
+.br
+
+.IP "\fB*ser_tty\fP" 0
+The name of a serial tty device, e.g. /dev/ttyAMA0, /dev/ttyUSB0, /dev/tty1.
+
+.br
+
+.br
+
+.IP "\fBsize_t\fP" 0
+A standard type used to indicate the size of an object in bytes.
+
+.br
+
+.br
+
+.IP "\fBspi_channel\fP" 0
+A SPI channel, 0-2.
+
+.br
+
+.br
+
+.IP "\fBspi_flags\fP" 0
+See \fBspi_open\fP.
+
+.br
+
+.br
+
+.IP "\fBsteady\fP: 0-300000" 0
+
+.br
+
+.br
+The number of microseconds level changes must be stable for
+before reporting the level changed (\fBset_glitch_filter\fP) or triggering
+the active part of a noise filter (\fBset_noise_filter\fP).
+
+.br
+
+.br
+
+.IP "\fBstop_bits\fP: 2-8" 0
+The number of (half) stop bits to be used when adding serial data
+to a waveform.
+
+.br
+
+.br
+
+.EX
+#define PI_MIN_WAVE_HALFSTOPBITS 2
+.br
+#define PI_MAX_WAVE_HALFSTOPBITS 8
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fB*str\fP" 0
+ An array of characters.
+
+.br
+
+.br
+
+.IP "\fBthread_func\fP" 0
+A function of type gpioThreadFunc_t used as the main function of a
+thread.
+
+.br
+
+.br
+
+.IP "\fBtimeout\fP" 0
+A gpio watchdog timeout in milliseconds.
+
+.EX
+PI_MIN_WDOG_TIMEOUT 0
+.br
+PI_MAX_WDOG_TIMEOUT 60000
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fB*txBuf\fP" 0
+An array of bytes to transmit.
+
+.br
+
+.br
+
+.IP "\fBuint32_t\fP: 0-0-4,294,967,295 (Hex 0x0-0xFFFFFFFF)" 0
+A 32-bit unsigned value.
+
+.br
+
+.br
+
+.IP "\fBunsigned\fP" 0
+A whole number >= 0.
+
+.br
+
+.br
+
+.IP "\fBuser_gpio\fP" 0
+0-31, a Broadcom numbered gpio.
+
+.br
+
+.br
+See \fBgpio\fP.
+
+.br
+
+.br
+
+.IP "\fB*userdata\fP" 0
+
+.br
+
+.br
+A pointer to arbitrary user data.  This may be used to identify the instance.
+
+.br
+
+.br
+You must ensure that the pointer is in scope at the time it is processed.  If
+it is a pointer to a global this is automatic.  Do not pass the address of a
+local variable.  If you want to pass a transient object then use the
+following technique.
+
+.br
+
+.br
+In the calling function:
+
+.br
+
+.br
+user_type *userdata;
+.br
+user_type my_userdata;
+
+.br
+
+.br
+userdata = malloc(sizeof(user_type));
+.br
+*userdata = my_userdata;
+
+.br
+
+.br
+In the receiving function:
+
+.br
+
+.br
+user_type my_userdata = *(user_type*)userdata;
+
+.br
+
+.br
+free(userdata);
+
+.br
+
+.br
+
+.IP "\fBvoid\fP" 0
+Denoting no parameter is required
+
+.br
+
+.br
+
+.IP "\fBwave_add_*\fP" 0
+One of \fBwave_add_new\fP, \fBwave_add_generic\fP, \fBwave_add_serial\fP.
+
+.br
+
+.br
+
+.IP "\fBwave_id\fP" 0
+A number representing a waveform created by \fBwave_create\fP.
+
+.br
+
+.br
+
+.IP "\fBwave_send_*\fP" 0
+One of \fBwave_send_once\fP, \fBwave_send_repeat\fP.
+
+.br
+
+.br
+
+.IP "\fBwVal\fP: 0-65535 (Hex 0x0-0xFFFF, Octal 0-0177777)" 0
+A 16-bit word value.
+
+.br
+
+.br
+.SH pigpiod_if2 Error Codes
+
+.EX
+
+.br
+typedef enum
+.br
+{
+.br
+   pigif_bad_send           = -2000,
+.br
+   pigif_bad_recv           = -2001,
+.br
+   pigif_bad_getaddrinfo    = -2002,
+.br
+   pigif_bad_connect        = -2003,
+.br
+   pigif_bad_socket         = -2004,
+.br
+   pigif_bad_noib           = -2005,
+.br
+   pigif_duplicate_callback = -2006,
+.br
+   pigif_bad_malloc         = -2007,
+.br
+   pigif_bad_callback       = -2008,
+.br
+   pigif_notify_failed      = -2009,
+.br
+   pigif_callback_not_found = -2010,
+.br
+   pigif_unconnected_pi     = -2011,
+.br
+   pigif_too_many_pis       = -2012,
+.br
+} pigifError_t;
+.br
+
+.br
+
+.EE
+
+.SH SEE ALSO
+
+pigpiod(1), pig2vcd(1), pigs(1), pigpio(3), pigpiod_if(3)
+.SH AUTHOR
+
+joan@abyz.co.uk
diff --git a/pigpiod_if2.c b/pigpiod_if2.c
new file mode 100644 (file)
index 0000000..110063d
--- /dev/null
@@ -0,0 +1,1659 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+*/
+
+/* PIGPIOD_IF2_VERSION 1 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <netdb.h>
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <sys/select.h>
+
+#include <arpa/inet.h>
+
+#include "pigpio.h"
+#include "command.h"
+
+#include "pigpiod_if2.h"
+
+#define PI_MAX_REPORTS_PER_READ 4096
+
+#define STACK_SIZE (256*1024)
+
+#define MAX_PI 32
+
+typedef void (*CBF_t) ();
+
+struct callback_s
+{
+
+   int id;
+   int pi;
+   int gpio;
+   int edge;
+   CBF_t f;
+   void * user;
+   int ex;
+   callback_t *prev;
+   callback_t *next;
+};
+
+/* GLOBALS ---------------------------------------------------------------- */
+
+static int             gPiInUse     [MAX_PI];
+
+static int             gPigCommand  [MAX_PI];
+static int             gPigHandle   [MAX_PI];
+static int             gPigNotify   [MAX_PI];
+
+static uint32_t        gNotifyBits  [MAX_PI];
+static uint32_t        gLastLevel   [MAX_PI];
+
+static pthread_t       *gPthNotify  [MAX_PI];
+
+static pthread_mutex_t gCmdMutex    [MAX_PI];
+static int             gCancelState [MAX_PI];
+
+static callback_t *gCallBackFirst = 0;
+static callback_t *gCallBackLast  = 0;
+
+/* PRIVATE ---------------------------------------------------------------- */
+
+static void _pml(int pi)
+{
+   int cancelState;
+
+   pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelState);
+   pthread_mutex_lock(&gCmdMutex[pi]);
+   gCancelState[pi] = cancelState;
+}
+
+static void _pmu(int pi)
+{
+   int cancelState;
+
+   cancelState = gCancelState[pi];
+   pthread_mutex_unlock(&gCmdMutex[pi]);
+   pthread_setcancelstate(cancelState, NULL);
+}
+
+static int pigpio_command(int pi, int command, int p1, int p2, int rl)
+{
+   cmdCmd_t cmd;
+
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi])
+      return pigif_unconnected_pi;
+
+   cmd.cmd = command;
+   cmd.p1  = p1;
+   cmd.p2  = p2;
+   cmd.res = 0;
+
+   _pml(pi);
+
+   if (send(gPigCommand[pi], &cmd, sizeof(cmd), 0) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_send;
+   }
+
+   if (recv(gPigCommand[pi], &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_recv;
+   }
+
+   if (rl) _pmu(pi);
+
+   return cmd.res;
+}
+
+static int pigpio_notify(int pi)
+{
+   cmdCmd_t cmd;
+
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi])
+      return pigif_unconnected_pi;
+
+   cmd.cmd = PI_CMD_NOIB;
+   cmd.p1  = 0;
+   cmd.p2  = 0;
+   cmd.res = 0;
+
+   _pml(pi);
+
+   if (send(gPigNotify[pi], &cmd, sizeof(cmd), 0) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_send;
+   }
+
+   if (recv(gPigNotify[pi], &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_recv;
+   }
+
+   _pmu(pi);
+
+   return cmd.res;
+}
+
+static int pigpio_command_ext
+   (int pi, int command, int p1, int p2, int p3,
+    int extents, gpioExtent_t *ext, int rl)
+{
+   int i;
+   cmdCmd_t cmd;
+
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi])
+      return pigif_unconnected_pi;
+
+   cmd.cmd = command;
+   cmd.p1  = p1;
+   cmd.p2  = p2;
+   cmd.p3  = p3;
+
+   _pml(pi);
+
+   if (send(gPigCommand[pi], &cmd, sizeof(cmd), 0) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_send;
+   }
+
+   for (i=0; i<extents; i++)
+   {
+      if (send(gPigCommand[pi], ext[i].ptr, ext[i].size, 0) != ext[i].size)
+      {
+         _pmu(pi);
+         return pigif_bad_send;
+      }
+   }
+
+   if (recv(gPigCommand[pi], &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
+   {
+      _pmu(pi);
+      return pigif_bad_recv;
+   }
+   if (rl) _pmu(pi);
+
+   return cmd.res;
+}
+
+static int pigpioOpenSocket(char *addr, char *port)
+{
+   int sock, err, opt;
+   struct addrinfo hints, *res, *rp;
+   const char *addrStr, *portStr;
+
+   if (!addr)
+   {
+      addrStr = getenv(PI_ENVADDR);
+
+      if ((!addrStr) || (!strlen(addrStr)))
+      {
+         addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
+      }
+   }
+   else addrStr = addr;
+
+   if (!port)
+   {
+      portStr = getenv(PI_ENVPORT);
+
+      if ((!portStr) || (!strlen(portStr)))
+      {
+         portStr = PI_DEFAULT_SOCKET_PORT_STR;
+      }
+   }
+   else portStr = port;
+
+   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 pigif_bad_getaddrinfo;
+
+   for (rp=res; rp!=NULL; rp=rp->ai_next)
+   {
+      sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+
+      if (sock == -1) continue;
+
+      /* Disable the Nagle algorithm. */
+      opt = 1;
+      setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(int));
+
+      if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
+   }
+
+   freeaddrinfo(res);
+
+   if (rp == NULL) return pigif_bad_connect;
+
+   return sock;
+}
+
+static void dispatch_notification(int pi, gpioReport_t *r)
+{
+   callback_t *p;
+   uint32_t changed;
+   int l, g;
+
+/*
+   printf("s=%4x f=%4x t=%10u l=%8x\n",
+      r->seqno, r->flags, r->tick, r->level);
+*/
+
+   if (r->flags == 0)
+   {
+      changed = (r->level ^ gLastLevel[pi]) & gNotifyBits[pi];
+
+      gLastLevel[pi] = r->level;
+
+      p = gCallBackFirst;
+
+      while (p)
+      {
+         if (((p->pi) == pi) && (changed & (1<<(p->gpio))))
+         {
+            if ((r->level) & (1<<(p->gpio))) l = 1; else l = 0;
+            if ((p->edge) ^ l)
+            {
+               if (p->ex) (p->f)(pi, p->gpio, l, r->tick, p->user);
+               else       (p->f)(pi, p->gpio, l, r->tick);
+            }
+         }
+         p = p->next;
+      }
+   }
+   else
+   {
+      g = (r->flags) & 31;
+
+      p = gCallBackFirst;
+
+      while (p)
+      {
+         if (((p->pi) == pi) && ((p->gpio) == g))
+         {
+            if (p->ex) (p->f)(pi, g, PI_TIMEOUT, r->tick, p->user);
+            else       (p->f)(pi, g, PI_TIMEOUT, r->tick);
+         }
+         p = p->next;
+      }
+   }
+}
+
+static void *pthNotifyThread(void *x)
+{
+   static int got = 0;
+   int pi;
+   int bytes, r;
+   gpioReport_t report[PI_MAX_REPORTS_PER_READ];
+
+   pi = *((int*)x);
+   free(x); /* memory allocated in pigpio_start */
+
+   while (1)
+   {
+      bytes = read(gPigNotify[pi], (char*)&report+got, sizeof(report)-got);
+
+      if (bytes > 0) got += bytes;
+      else break;
+
+      r = 0;
+
+      while (got >= sizeof(gpioReport_t))
+      {
+         dispatch_notification(pi, &report[r]);
+
+         r++;
+
+         got -= sizeof(gpioReport_t);
+      }
+
+      /* copy any partial report to start of array */
+      
+      if (got && r) report[0] = report[r];
+   }
+
+   fprintf(stderr, "notify thread for pi %d broke with read error %d\n",
+      pi, bytes);
+
+   while (1) sleep(1);
+
+   return NULL;
+}
+
+static void findNotifyBits(int pi)
+{
+   callback_t *p;
+   uint32_t bits = 0;
+
+   p = gCallBackFirst;
+
+   while (p)
+   {
+      if (p->pi == pi) bits |= (1<<(p->gpio));
+      p = p->next;
+   }
+
+   if (bits != gNotifyBits[pi])
+   {
+      gNotifyBits[pi] = bits;
+      pigpio_command(pi, PI_CMD_NB, gPigHandle[pi], gNotifyBits[pi], 1);
+   }
+}
+
+static void _wfe(
+   int pi, unsigned user_gpio, unsigned level, uint32_t tick, void *user)
+{
+   *(int *)user = 1;
+}
+
+static int intCallback(
+   int pi, unsigned user_gpio, unsigned edge, void *f, void *user, int ex)
+{
+   static int id = 0;
+   callback_t *p;
+
+   if ((user_gpio >=0) && (user_gpio < 32) && (edge >=0) && (edge <= 2) && f)
+   {
+      /* prevent duplicates */
+
+      p = gCallBackFirst;
+
+      while (p)
+      {
+         if ((p->pi   == pi)        &&
+             (p->gpio == user_gpio) &&
+             (p->edge == edge)      &&
+             (p->f    == f))
+         {
+            return pigif_duplicate_callback;
+         }
+         p = p->next;
+      }
+
+      p = malloc(sizeof(callback_t));
+
+      if (p)
+      {
+         if (!gCallBackFirst) gCallBackFirst = p;
+
+         p->id = id++;
+         p->pi = pi;
+         p->gpio = user_gpio;
+         p->edge = edge;
+         p->f = f;
+         p->user = user;
+         p->ex = ex;
+         p->next = 0;
+         p->prev = gCallBackLast;
+
+         if (p->prev) (p->prev)->next = p;
+         gCallBackLast = p;
+
+         findNotifyBits(pi);
+
+         return p->id;
+      }
+
+      return pigif_bad_malloc;
+   }
+
+   return pigif_bad_callback;
+}
+
+static int recvMax(int pi, void *buf, int bufsize, int sent)
+{
+   uint8_t scratch[4096];
+   int remaining, fetch, count;
+
+   if (sent < bufsize) count = sent; else count = bufsize;
+
+   if (count) recv(gPigCommand[pi], buf, count, MSG_WAITALL);
+
+   remaining = sent - count;
+
+   while (remaining)
+   {
+      fetch = remaining;
+      if (fetch > sizeof(scratch)) fetch = sizeof(scratch);
+      recv(gPigCommand[pi], scratch, fetch, MSG_WAITALL);
+      remaining -= fetch;
+   }
+
+   return count;
+}
+
+/* PUBLIC ----------------------------------------------------------------- */
+
+double time_time(void)
+{
+   struct timeval tv;
+   double t;
+
+   gettimeofday(&tv, 0);
+
+   t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6);
+
+   return t;
+}
+
+void time_sleep(double seconds)
+{
+   struct timespec ts, rem;
+
+   if (seconds > 0.0)
+   {
+      ts.tv_sec = seconds;
+      ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9;
+
+      while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem))
+      {
+         /* copy remaining time to ts */
+         ts.tv_sec  = rem.tv_sec;
+         ts.tv_nsec = rem.tv_nsec;
+      }
+   }
+}
+
+char *pigpio_error(int errnum)
+{
+   if (errnum > -1000) return cmdErrStr(errnum);
+   else
+   {
+      switch(errnum)
+      {
+         case pigif_bad_send:
+            return "failed to send to pigpiod";
+         case pigif_bad_recv:
+            return "failed to receive from pigpiod";
+         case pigif_bad_getaddrinfo:
+            return "failed to find address of pigpiod";
+         case pigif_bad_connect:
+            return "failed to connect to pigpiod";
+         case pigif_bad_socket:
+            return "failed to create socket";
+         case pigif_bad_noib:
+            return "failed to open notification in band";
+         case pigif_duplicate_callback:
+            return "identical callback exists";
+         case pigif_bad_malloc:
+            return "failed to malloc";
+         case pigif_bad_callback:
+            return "bad callback parameter";
+         case pigif_notify_failed:
+            return "failed to create notification thread";
+         case pigif_callback_not_found:
+            return "callback not found";
+         case pigif_unconnected_pi:
+            return "not connected to Pi";
+         case pigif_too_many_pis:
+            return "too many connected Pis";
+
+         default:
+            return "unknown error";
+      }
+   }
+}
+
+unsigned pigpiod_if_version(void)
+{
+   return PIGPIOD_IF2_VERSION;
+}
+
+pthread_t *start_thread(gpioThreadFunc_t thread_func, void *userdata)
+{
+   pthread_t *pth;
+   pthread_attr_t pthAttr;
+
+   pth = malloc(sizeof(pthread_t));
+
+   if (pth)
+   {
+      if (pthread_attr_init(&pthAttr))
+      {
+         perror("pthread_attr_init failed");
+         free(pth);
+         return NULL;
+      }
+
+      if (pthread_attr_setstacksize(&pthAttr, STACK_SIZE))
+      {
+         perror("pthread_attr_setstacksize failed");
+         free(pth);
+         return NULL;
+      }
+
+      if (pthread_create(pth, &pthAttr, thread_func, userdata))
+      {
+         perror("pthread_create socket failed");
+         free(pth);
+         return NULL;
+      }
+   }
+   return pth;
+}
+
+void stop_thread(pthread_t *pth)
+{
+   if (pth)
+   {
+      pthread_cancel(*pth);
+      pthread_join(*pth, NULL);
+      free(pth);
+   }
+}
+
+int pigpio_start(char *addrStr, char *portStr)
+{
+   int pi;
+   int *userdata;
+
+   for (pi=0; pi<MAX_PI; pi++)
+   {
+      if (!gPiInUse[pi]) break;
+   }
+
+   if (pi >= MAX_PI) return pigif_too_many_pis;
+
+   gPiInUse[pi] = 1;
+
+   pthread_mutex_init(&gCmdMutex[pi], NULL);
+
+   gPigCommand[pi] = pigpioOpenSocket(addrStr, portStr);
+
+   if (gPigCommand[pi] >= 0)
+   {
+      gPigNotify[pi] = pigpioOpenSocket(addrStr, portStr);
+
+      if (gPigNotify[pi] >= 0)
+      {
+         gPigHandle[pi] = pigpio_notify(pi);
+
+         if (gPigHandle[pi] < 0) return pigif_bad_noib;
+         else
+         {
+            gLastLevel[pi] = read_bank_1(pi);
+
+            /* must be freed by pthNotifyThread */
+            userdata = malloc(sizeof(*userdata));
+            *userdata = pi;
+
+            gPthNotify[pi] = start_thread(pthNotifyThread, userdata);
+
+            if (gPthNotify[pi]) return pi;
+            else                return pigif_notify_failed;
+
+         }
+      }
+      else return gPigNotify[pi];
+   }
+   else return gPigCommand[pi];
+}
+
+void pigpio_stop(int pi)
+{
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi]) return;
+
+   if (gPthNotify[pi])
+   {
+      stop_thread(gPthNotify[pi]);
+      gPthNotify[pi] = 0;
+   }
+
+   if (gPigCommand[pi] >= 0)
+   {
+      if (gPigHandle[pi] >= 0)
+      {
+         pigpio_command(pi, PI_CMD_NC, gPigHandle[pi], 0, 1);
+         gPigHandle[pi] = -1;
+      }
+
+      close(gPigCommand[pi]);
+      gPigCommand[pi] = -1;
+   }
+
+   if (gPigNotify[pi] >= 0)
+   {
+      close(gPigNotify[pi]);
+      gPigNotify[pi] = -1;
+   }
+
+   gPiInUse[pi] = 0;
+}
+
+int set_mode(int pi, unsigned gpio, unsigned mode)
+   {return pigpio_command(pi, PI_CMD_MODES, gpio, mode, 1);}
+
+int get_mode(int pi, unsigned gpio)
+   {return pigpio_command(pi, PI_CMD_MODEG, gpio, 0, 1);}
+
+int set_pull_up_down(int pi, unsigned gpio, unsigned pud)
+   {return pigpio_command(pi, PI_CMD_PUD, gpio, pud, 1);}
+
+int gpio_read(int pi, unsigned gpio)
+   {return pigpio_command(pi, PI_CMD_READ, gpio, 0, 1);}
+
+int gpio_write(int pi, unsigned gpio, unsigned level)
+   {return pigpio_command(pi, PI_CMD_WRITE, gpio, level, 1);}
+
+int set_PWM_dutycycle(int pi, unsigned user_gpio, unsigned dutycycle)
+   {return pigpio_command(pi, PI_CMD_PWM, user_gpio, dutycycle, 1);}
+
+int get_PWM_dutycycle(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_GDC, user_gpio, 0, 1);}
+
+int set_PWM_range(int pi, unsigned user_gpio, unsigned range)
+   {return pigpio_command(pi, PI_CMD_PRS, user_gpio, range, 1);}
+
+int get_PWM_range(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_PRG, user_gpio, 0, 1);}
+
+int get_PWM_real_range(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_PRRG, user_gpio, 0, 1);}
+
+int set_PWM_frequency(int pi, unsigned user_gpio, unsigned frequency)
+   {return pigpio_command(pi, PI_CMD_PFS, user_gpio, frequency, 1);}
+
+int get_PWM_frequency(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_PFG, user_gpio, 0, 1);}
+
+int set_servo_pulsewidth(int pi, unsigned user_gpio, unsigned pulsewidth)
+   {return pigpio_command(pi, PI_CMD_SERVO, user_gpio, pulsewidth, 1);}
+
+int get_servo_pulsewidth(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_GPW, user_gpio, 0, 1);}
+
+int notify_open(int pi)
+   {return pigpio_command(pi, PI_CMD_NO, 0, 0, 1);}
+
+int notify_begin(int pi, unsigned handle, uint32_t bits)
+   {return pigpio_command(pi, PI_CMD_NB, handle, bits, 1);}
+
+int notify_pause(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_NB, handle, 0, 1);}
+
+int notify_close(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_NC, handle, 0, 1);}
+
+int set_watchdog(int pi, unsigned user_gpio, unsigned timeout)
+   {return pigpio_command(pi, PI_CMD_WDOG, user_gpio, timeout, 1);}
+
+uint32_t read_bank_1(int pi)
+   {return pigpio_command(pi, PI_CMD_BR1, 0, 0, 1);}
+
+uint32_t read_bank_2(int pi)
+   {return pigpio_command(pi, PI_CMD_BR2, 0, 0, 1);}
+
+int clear_bank_1(int pi, uint32_t levels)
+   {return pigpio_command(pi, PI_CMD_BC1, levels, 0, 1);}
+
+int clear_bank_2(int pi, uint32_t levels)
+   {return pigpio_command(pi, PI_CMD_BC2, levels, 0, 1);}
+
+int set_bank_1(int pi, uint32_t levels)
+   {return pigpio_command(pi, PI_CMD_BS1, levels, 0, 1);}
+
+int set_bank_2(int pi, uint32_t levels)
+   {return pigpio_command(pi, PI_CMD_BS2, levels, 0, 1);}
+
+int hardware_clock(int pi, unsigned gpio, unsigned frequency)
+   {return pigpio_command(pi, PI_CMD_HC, gpio, frequency, 1);}
+
+int hardware_PWM(int pi, unsigned gpio, unsigned frequency, uint32_t dutycycle)
+{
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=gpio
+   p2=frequency
+   p3=4
+   ## extension ##
+   uint32_t dutycycle
+   */
+
+   ext[0].size = sizeof(dutycycle);
+   ext[0].ptr = &dutycycle;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_HP, gpio, frequency, sizeof(dutycycle), 1, ext, 1);
+}
+
+uint32_t get_current_tick(int pi)
+   {return pigpio_command(pi, PI_CMD_TICK, 0, 0, 1);}
+
+uint32_t get_hardware_revision(int pi)
+   {return pigpio_command(pi, PI_CMD_HWVER, 0, 0, 1);}
+
+uint32_t get_pigpio_version(int pi)
+   {return pigpio_command(pi, PI_CMD_PIGPV, 0, 0, 1);}
+
+int wave_clear(int pi)
+   {return pigpio_command(pi, PI_CMD_WVCLR, 0, 0, 1);}
+
+int wave_add_new(int pi)
+   {return pigpio_command(pi, PI_CMD_WVNEW, 0, 0, 1);}
+
+int wave_add_generic(int pi, unsigned numPulses, gpioPulse_t *pulses)
+{
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=0
+   p2=0
+   p3=pulses*sizeof(gpioPulse_t)
+   ## extension ##
+   gpioPulse_t[] pulses
+   */
+
+   if (!numPulses) return 0;
+
+   ext[0].size = numPulses * sizeof(gpioPulse_t);
+   ext[0].ptr = pulses;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_WVAG, 0, 0, ext[0].size, 1, ext, 1);
+}
+
+int wave_add_serial(
+   int pi, unsigned user_gpio, unsigned baud, uint32_t databits,
+   uint32_t stophalfbits, uint32_t offset,  unsigned numChar, char *str)
+{
+   uint8_t buf[12];
+   gpioExtent_t ext[2];
+
+   /*
+   p1=user_gpio
+   p2=baud
+   p3=len+12
+   ## extension ##
+   uint32_t databits
+   uint32_t stophalfbits
+   uint32_t offset
+   char[len] str
+   */
+
+   if (!numChar) return 0;
+
+   memcpy(buf, &databits, 4);
+   memcpy(buf+4, &stophalfbits, 4);
+   memcpy(buf+8, &offset, 4);
+
+   ext[0].size = sizeof(buf);
+   ext[0].ptr = buf;
+
+   ext[1].size = numChar;
+   ext[1].ptr = str;
+
+   return pigpio_command_ext(pi, PI_CMD_WVAS,
+      user_gpio, baud, numChar+sizeof(buf), 2, ext, 1);
+}
+
+int wave_create(int pi)
+   {return pigpio_command(pi, PI_CMD_WVCRE, 0, 0, 1);}
+
+int wave_delete(int pi, unsigned wave_id)
+   {return pigpio_command(pi, PI_CMD_WVDEL, wave_id, 0, 1);}
+
+int wave_tx_start(int pi) /* DEPRECATED */
+   {return pigpio_command(pi, PI_CMD_WVGO, 0, 0, 1);}
+
+int wave_tx_repeat(int pi) /* DEPRECATED */
+   {return pigpio_command(pi, PI_CMD_WVGOR, 0, 0, 1);}
+
+int wave_send_once(int pi, unsigned wave_id)
+   {return pigpio_command(pi, PI_CMD_WVTX, wave_id, 0, 1);}
+
+int wave_send_repeat(int pi, unsigned wave_id)
+   {return pigpio_command(pi, PI_CMD_WVTXR, wave_id, 0, 1);}
+
+int wave_chain(int pi, char *buf, unsigned bufSize)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=0
+   p2=0
+   p3=bufSize
+   ## extension ##
+   char buf[bufSize]
+   */
+
+   ext[0].size = bufSize;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_WVCHA, 0, 0, bufSize, 1, ext, 1);
+}
+
+int wave_tx_busy(int pi)
+   {return pigpio_command(pi, PI_CMD_WVBSY, 0, 0, 1);}
+
+int wave_tx_stop(int pi)
+   {return pigpio_command(pi, PI_CMD_WVHLT, 0, 0, 1);}
+
+int wave_get_micros(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSM, 0, 0, 1);}
+
+int wave_get_high_micros(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSM, 1, 0, 1);}
+
+int wave_get_max_micros(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSM, 2, 0, 1);}
+
+int wave_get_pulses(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSP, 0, 0, 1);}
+
+int wave_get_high_pulses(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSP, 1, 0, 1);}
+
+int wave_get_max_pulses(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSP, 2, 0, 1);}
+
+int wave_get_cbs(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSC, 0, 0, 1);}
+
+int wave_get_high_cbs(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSC, 1, 0, 1);}
+
+int wave_get_max_cbs(int pi)
+   {return pigpio_command(pi, PI_CMD_WVSC, 2, 0, 1);}
+
+int gpio_trigger(int pi, unsigned user_gpio, unsigned pulseLen, uint32_t level)
+{
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=user_gpio
+   p2=pulseLen 
+   p3=4
+   ## extension ##
+   unsigned level
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &level;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_TRIG, user_gpio, pulseLen, 4, 1, ext, 1);
+}
+
+int set_glitch_filter(int pi, unsigned user_gpio, unsigned steady)
+   {return pigpio_command(pi, PI_CMD_FG, user_gpio, steady, 1);}
+
+int set_noise_filter(int pi, unsigned user_gpio, unsigned steady, unsigned active)
+{
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=user_gpio
+   p2=steady
+   p3=4
+   ## extension ##
+   unsigned active
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &active;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_FN, user_gpio, steady, 4, 1, ext, 1);
+}
+
+int store_script(int pi, char *script)
+{
+   unsigned len;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=0
+   p2=0
+   p3=len
+   ## extension ##
+   char[len] script
+   */
+
+   len = strlen(script);
+
+   if (!len) return 0;
+
+   ext[0].size = len;
+   ext[0].ptr = script;
+
+   return pigpio_command_ext(pi, PI_CMD_PROC, 0, 0, len, 1, ext, 1);
+}
+
+int run_script(int pi, unsigned script_id, unsigned numPar, uint32_t *param)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=script id
+   p2=0
+   p3=numPar * 4
+   ## extension ##
+   uint32_t[numPar] pars
+   */
+
+   ext[0].size = 4 * numPar;
+   ext[0].ptr = param;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_PROCR, script_id, 0, numPar*4, 1, ext, 1);
+}
+
+int script_status(int pi, unsigned script_id, uint32_t *param)
+{
+   int status;
+   uint32_t p[PI_MAX_SCRIPT_PARAMS+1]; /* space for script status */
+
+   status = pigpio_command(pi, PI_CMD_PROCP, script_id, 0, 0);
+
+   if (status > 0)
+   {
+      recvMax(pi, p, sizeof(p), status);
+      status = p[0];
+      if (param) memcpy(param, p+1, sizeof(p)-4);
+   }
+
+   _pmu(pi);
+
+   return status;
+}
+
+int stop_script(int pi, unsigned script_id)
+   {return pigpio_command(pi, PI_CMD_PROCS, script_id, 0, 1);}
+
+int delete_script(int pi, unsigned script_id)
+   {return pigpio_command(pi, PI_CMD_PROCD, script_id, 0, 1);}
+
+int bb_serial_read_open(int pi, unsigned user_gpio, unsigned baud, uint32_t bbBits)
+{
+   gpioExtent_t ext[1];
+   
+   /*
+   p1=user_gpio
+   p2=baud
+   p3=4
+   ## extension ##
+   unsigned bbBits
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &bbBits;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_SLRO, user_gpio, baud, 4, 1, ext, 1);
+}
+
+int bb_serial_read(int pi, unsigned user_gpio, void *buf, size_t bufSize)
+{
+   int bytes;
+
+   bytes = pigpio_command(pi, PI_CMD_SLR, user_gpio, bufSize, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, bufSize, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int bb_serial_read_close(int pi, unsigned user_gpio)
+   {return pigpio_command(pi, PI_CMD_SLRC, user_gpio, 0, 1);}
+
+int bb_serial_invert(int pi, unsigned user_gpio, unsigned invert)
+   {return pigpio_command(pi, PI_CMD_SLRI, user_gpio, invert, 1);}
+
+int i2c_open(int pi, unsigned i2c_bus, unsigned i2c_addr, uint32_t i2c_flags)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=i2c_bus
+   p2=i2c_addr
+   p3=4
+   ## extension ##
+   uint32_t i2c_flags
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &i2c_flags;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CO, i2c_bus, i2c_addr, 4, 1, ext, 1);
+}
+
+int i2c_close(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_I2CC, handle, 0, 1);}
+
+int i2c_write_quick(int pi, unsigned handle, unsigned bit)
+   {return pigpio_command(pi, PI_CMD_I2CWQ, handle, bit, 1);}
+
+int i2c_write_byte(int pi, unsigned handle, unsigned val)
+   {return pigpio_command(pi, PI_CMD_I2CWS, handle, val, 1);}
+
+int i2c_read_byte(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_I2CRS, handle, 0, 1);}
+
+int i2c_write_byte_data(int pi, unsigned handle, unsigned reg, uint32_t val)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=4
+   ## extension ##
+   uint32_t val
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &val;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CWB, handle, reg, 4, 1, ext, 1);
+}
+
+int i2c_write_word_data(int pi, unsigned handle, unsigned reg, uint32_t val)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=4
+   ## extension ##
+   uint32_t val
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &val;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CWW, handle, reg, 4, 1, ext, 1);
+}
+
+int i2c_read_byte_data(int pi, unsigned handle, unsigned reg)
+   {return pigpio_command(pi, PI_CMD_I2CRB, handle, reg, 1);}
+
+int i2c_read_word_data(int pi, unsigned handle, unsigned reg)
+   {return pigpio_command(pi, PI_CMD_I2CRW, handle, reg, 1);}
+
+int i2c_process_call(int pi, unsigned handle, unsigned reg, uint32_t val)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=4
+   ## extension ##
+   uint32_t val
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &val;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CPK, handle, reg, 4, 1, ext, 1);
+}
+
+int i2c_write_block_data(
+   int pi, unsigned handle, unsigned reg, char *buf, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CWK, handle, reg, count, 1, ext, 1);
+}
+
+int i2c_read_block_data(int pi, unsigned handle, unsigned reg, char *buf)
+{
+   int bytes;
+
+   bytes = pigpio_command(pi, PI_CMD_I2CRK, handle, reg, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, 32, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int i2c_block_process_call(
+   int pi, unsigned handle, unsigned reg, char *buf, unsigned count)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_I2CPK, handle, reg, count, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, 32, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int i2c_read_i2c_block_data(
+   int pi, unsigned handle, unsigned reg, char *buf, uint32_t count)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=4
+   ## extension ##
+   uint32_t count
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &count;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_I2CRI, handle, reg, 4, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, count, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+
+int i2c_write_i2c_block_data(
+   int pi, unsigned handle, unsigned reg, char *buf, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=reg
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CWI, handle, reg, count, 1, ext, 1);
+}
+
+int i2c_read_device(int pi, unsigned handle, char *buf, unsigned count)
+{
+   int bytes;
+
+   bytes = pigpio_command(pi, PI_CMD_I2CRD, handle, count, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, count, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int i2c_write_device(int pi, unsigned handle, char *buf, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=0
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_I2CWD, handle, 0, count, 1, ext, 1);
+}
+
+int i2c_zip(
+   int pi,
+   unsigned handle,
+   char    *inBuf,
+   unsigned inLen,
+   char    *outBuf,
+   unsigned outLen)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=0
+   p3=inLen
+   ## extension ##
+   char inBuf[inLen]
+   */
+
+   ext[0].size = inLen;
+   ext[0].ptr = inBuf;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_I2CZ, handle, 0, inLen, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, outBuf, outLen, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int bb_i2c_open(int pi, unsigned SDA, unsigned SCL, unsigned baud)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=SDA
+   p2=SCL
+   p3=4
+   ## extension ##
+   uint32_t baud
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &baud;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_BI2CO, SDA, SCL, 4, 1, ext, 1);
+}
+
+int bb_i2c_close(int pi, unsigned SDA)
+   {return pigpio_command(pi, PI_CMD_BI2CC, SDA, 0, 1);}
+
+int bb_i2c_zip(
+   int      pi,
+   unsigned SDA,
+   char    *inBuf,
+   unsigned inLen,
+   char    *outBuf,
+   unsigned outLen)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=SDA
+   p2=0
+   p3=inLen
+   ## extension ##
+   char inBuf[inLen]
+   */
+
+   ext[0].size = inLen;
+   ext[0].ptr = inBuf;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_BI2CZ, SDA, 0, inLen, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, outBuf, outLen, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int spi_open(int pi, unsigned channel, unsigned speed, uint32_t flags)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=channel
+   p2=speed
+   p3=4
+   ## extension ##
+   uint32_t flags
+   */
+
+   ext[0].size = sizeof(uint32_t);
+   ext[0].ptr = &flags;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_SPIO, channel, speed, 4, 1, ext, 1);
+}
+
+int spi_close(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_SPIC, handle, 0, 1);}
+
+int spi_read(int pi, unsigned handle, char *buf, unsigned count)
+{
+   int bytes;
+
+   bytes = pigpio_command
+      (pi, PI_CMD_SPIR, handle, count, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, count, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int spi_write(int pi, unsigned handle, char *buf, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=0
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_SPIW, handle, 0, count, 1, ext, 1);
+}
+
+int spi_xfer(int pi, unsigned handle, char *txBuf, char *rxBuf, unsigned count)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=0
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = txBuf;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_SPIX, handle, 0, count, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, rxBuf, count, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int serial_open(int pi, char *dev, unsigned baud, unsigned flags)
+{
+   int len;
+   gpioExtent_t ext[1];
+
+   len = strlen(dev);
+
+   /*
+   p1=baud
+   p2=flags
+   p3=len
+   ## extension ##
+   char dev[len]
+   */
+
+   ext[0].size = len;
+   ext[0].ptr = dev;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_SERO, baud, flags, len, 1, ext, 1);
+}
+
+int serial_close(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_SERC, handle, 0, 1);}
+
+int serial_write_byte(int pi, unsigned handle, unsigned val)
+   {return pigpio_command(pi, PI_CMD_SERWB, handle, val, 1);}
+
+int serial_read_byte(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_SERRB, handle, 0, 1);}
+
+int serial_write(int pi, unsigned handle, char *buf, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=handle
+   p2=0
+   p3=count
+   ## extension ##
+   char buf[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = buf;
+
+   return pigpio_command_ext
+      (pi, PI_CMD_SERW, handle, 0, count, 1, ext, 1);
+}
+
+int serial_read(int pi, unsigned handle, char *buf, unsigned count)
+{
+   int bytes;
+
+   bytes = pigpio_command
+      (pi, PI_CMD_SERR, handle, count, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, buf, count, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int serial_data_available(int pi, unsigned handle)
+   {return pigpio_command(pi, PI_CMD_SERDA, handle, 0, 1);}
+
+int custom_1(int pi, unsigned arg1, unsigned arg2, char *argx, unsigned count)
+{
+   gpioExtent_t ext[1];
+
+   /*
+   p1=arg1
+   p2=arg2
+   p3=count
+   ## extension ##
+   char argx[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = argx;
+
+   return pigpio_command_ext(
+      pi, PI_CMD_CF1, arg1, arg2, count, 1, ext, 1);
+}
+
+
+int custom_2(int pi, unsigned arg1, char *argx, unsigned count,
+             char *retBuf, uint32_t retMax)
+{
+   int bytes;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=arg1
+   p2=retMax
+   p3=count
+   ## extension ##
+   char argx[count]
+   */
+
+   ext[0].size = count;
+   ext[0].ptr = argx;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_CF2, arg1, retMax, count, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      bytes = recvMax(pi, retBuf, retMax, bytes);
+   }
+
+   _pmu(pi);
+
+   return bytes;
+}
+
+int callback(int pi, unsigned user_gpio, unsigned edge, CBFunc_t f)
+   {return intCallback(pi, user_gpio, edge, f, 0, 0);}
+
+int callback_ex(
+   int pi, unsigned user_gpio, unsigned edge, CBFuncEx_t f, void *user)
+   {return intCallback(pi, user_gpio, edge, f, user, 1);}
+
+int callback_cancel(unsigned id)
+{
+   callback_t *p;
+   int pi;
+
+   p = gCallBackFirst;
+
+   while (p)
+   {
+      if (p->id == id)
+      {
+         pi = p->pi;
+
+         if (p->prev) {p->prev->next = p->next;}
+         else         {gCallBackFirst = p->next;}
+
+         if (p->next) {p->next->prev = p->prev;}
+         else         {gCallBackLast = p->prev;}
+
+         free(p);
+
+         findNotifyBits(pi);
+
+         return 0;
+      }
+      p = p->next;
+   }
+   return pigif_callback_not_found;
+}
+
+int wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout)
+{
+   int triggered = 0;
+   int id;
+   double due;
+
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi])
+      return pigif_unconnected_pi;
+
+   if (timeout <= 0.0) return 0;
+
+   due = time_time() + timeout;
+
+   id = callback_ex(pi, user_gpio, edge, _wfe, &triggered);
+
+   while (!triggered && (time_time() < due)) time_sleep(0.1);
+
+   callback_cancel(id);
+
+   return triggered;
+}
+
diff --git a/pigpiod_if2.h b/pigpiod_if2.h
new file mode 100644 (file)
index 0000000..45aeb0f
--- /dev/null
@@ -0,0 +1,3094 @@
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+*/
+
+#ifndef PIGPIOD_IF2_H
+#define PIGPIOD_IF2_H
+
+#include "pigpio.h"
+
+#define PIGPIOD_IF2_VERSION 1
+
+/*TEXT
+
+pigpiod_if2 is a C library for the Raspberry which allows control
+of the gpios via the socket interface to the pigpio daemon. 
+
+*Features*
+
+o PWM on any of gpios 0-31
+
+o servo pulses on any of gpios 0-31
+
+o callbacks when any of gpios 0-31 change state
+
+o callbacks at timed intervals
+
+o reading/writing all of the gpios in a bank as one operation
+
+o individually setting gpio modes, reading and writing
+
+o notifications when any of gpios 0-31 change state
+
+o the construction of output waveforms with microsecond timing
+
+o rudimentary permission control over gpios
+
+o a simple interface to start and stop new threads
+
+o I2C, SPI, and serial link wrappers
+
+o creating and running scripts on the pigpio daemon
+
+*gpios*
+
+ALL gpios are identified by their Broadcom number.
+
+*Notes*
+
+The PWM and servo pulses are timed using the DMA and PWM/PCM peripherals.
+
+*Usage*
+
+Include <pigpiod_if2.h> in your source files.
+
+Assuming your source is in prog.c use the following command to build
+
+. .
+gcc -Wall -pthread -o prog prog.c -lpigpiod_if2 -lrt
+. .
+
+to run make sure the pigpio daemon is running
+
+. .
+sudo pigpiod
+
+ ./prog # sudo is not required to run programs linked to pigpiod_if2
+. .
+
+For examples see x_pigpiod_if2.c within the pigpio archive file.
+
+*Notes*
+
+All the functions which return an int return < 0 on error
+
+TEXT*/
+
+/*OVERVIEW
+
+ESSENTIAL
+
+pigpio_start               Connects to a pigpio daemon
+pigpio_stop                Disconnects from a pigpio daemon
+
+BEGINNER
+
+set_mode                   Set a gpio mode
+get_mode                   Get a gpio mode
+
+set_pull_up_down           Set/clear gpio pull up/down resistor
+
+gpio_read                  Read a gpio
+gpio_write                 Write a gpio
+
+set_PWM_dutycycle          Start/stop PWM pulses on a gpio
+get_PWM_dutycycle          Get the PWM dutycycle in use on a gpio
+
+set_servo_pulsewidth       Start/stop servo pulses on a gpio
+get_servo_pulsewidth       Get the servo pulsewidth in use on a gpio
+
+callback                   Create gpio level change callback
+callback_ex                Create gpio level change callback
+callback_cancel            Cancel a callback
+wait_for_edge              Wait for gpio level change
+
+INTERMEDIATE
+
+gpio_trigger               Send a trigger pulse to a gpio.
+
+set_watchdog               Set a watchdog on a gpio.
+
+set_PWM_range              Configure PWM range for a gpio
+get_PWM_range              Get configured PWM range for a gpio
+
+set_PWM_frequency          Configure PWM frequency for a gpio
+get_PWM_frequency          Get configured PWM frequency for a gpio
+
+read_bank_1                Read all gpios in bank 1
+read_bank_2                Read all gpios in bank 2
+
+clear_bank_1               Clear selected gpios in bank 1
+clear_bank_2               Clear selected gpios in bank 2
+
+set_bank_1                 Set selected gpios in bank 1
+set_bank_2                 Set selected gpios in bank 2
+
+start_thread               Start a new thread
+stop_thread                Stop a previously started thread
+
+ADVANCED
+
+get_PWM_real_range         Get underlying PWM range for a gpio
+
+notify_open                Request a notification handle
+notify_begin               Start notifications for selected gpios
+notify_pause               Pause notifications
+notify_close               Close a notification
+
+bb_serial_read_open        Opens a gpio for bit bang serial reads
+bb_serial_read             Reads bit bang serial data from a gpio
+bb_serial_read_close       Closes a gpio for bit bang serial reads
+bb_serial_invert           Invert serial logic (1 invert, 0 normal)
+
+hardware_clock             Start hardware clock on supported gpios
+hardware_PWM               Start hardware PWM on supported gpios
+
+set_glitch_filter         Set a glitch filter on a gpio
+set_noise_filter          Set a noise filter on a gpio
+
+SCRIPTS
+
+store_script               Store a script
+run_script                 Run a stored script
+script_status              Get script status and parameters
+stop_script                Stop a running script
+delete_script              Delete a stored script
+
+WAVES
+
+wave_clear                 Deletes all waveforms
+
+wave_add_new               Starts a new waveform
+wave_add_generic           Adds a series of pulses to the waveform
+wave_add_serial            Adds serial data to the waveform
+
+wave_create                Creates a waveform from added data
+wave_delete                Deletes one or more waveforms
+
+wave_send_once             Transmits a waveform once
+wave_send_repeat           Transmits a waveform repeatedly
+
+wave_chain                 Transmits a chain of waveforms
+
+wave_tx_busy               Checks to see if the waveform has ended
+wave_tx_stop               Aborts the current waveform
+
+wave_get_micros            Length in microseconds of the current waveform
+wave_get_high_micros       Length of longest waveform so far
+wave_get_max_micros        Absolute maximum allowed micros
+
+wave_get_pulses            Length in pulses of the current waveform
+wave_get_high_pulses       Length of longest waveform so far
+wave_get_max_pulses        Absolute maximum allowed pulses
+
+wave_get_cbs               Length in cbs of the current waveform
+wave_get_high_cbs          Length of longest waveform so far
+wave_get_max_cbs           Absolute maximum allowed cbs
+
+I2C
+
+i2c_open                   Opens an I2C device
+i2c_close                  Closes an I2C device
+
+i2c_write_quick            smbus write quick
+i2c_write_byte             smbus write byte
+i2c_read_byte              smbus read byte
+i2c_write_byte_data        smbus write byte data
+i2c_write_word_data        smbus write word data
+i2c_read_byte_data         smbus read byte data
+i2c_read_word_data         smbus read word data
+i2c_process_call           smbus process call
+i2c_write_block_data       smbus write block data
+i2c_read_block_data        smbus read block data
+i2c_block_process_call     smbus block process call
+
+i2c_write_i2c_block_data   smbus write I2C block data
+i2c_read_i2c_block_data    smbus read I2C block data
+
+i2c_read_device            Reads the raw I2C device
+i2c_write_device           Writes the raw I2C device
+
+i2c_zip                    Performs multiple I2C transactions
+
+bb_i2c_open                Opens gpios for bit banging I2C
+bb_i2c_close               Closes gpios for bit banging I2C
+bb_i2c_zip                 Performs multiple bit banged I2C transactions
+
+SPI
+
+spi_open                   Opens a SPI device
+spi_close                  Closes a SPI device
+
+spi_read                   Reads bytes from a SPI device
+spi_write                  Writes bytes to a SPI device
+spi_xfer                   Transfers bytes with a SPI device
+
+SERIAL
+
+serial_open                Opens a serial device (/dev/tty*)
+serial_close               Closes a serial device
+
+serial_write_byte          Writes a byte to a serial device
+serial_read_byte           Reads a byte from a serial device
+serial_write               Writes bytes to a serial device
+serial_read                Reads bytes from a serial device
+
+serial_data_available      Returns number of bytes ready to be read
+
+CUSTOM
+
+custom_1                   User custom function 1
+custom_2                   User custom function 2
+
+UTILITIES
+
+get_current_tick           Get current tick (microseconds)
+
+get_hardware_revision      Get hardware revision
+get_pigpio_version         Get the pigpio version
+pigpiod_if_version         Get the pigpiod_if2 version
+
+pigpio_error               Get a text description of an error code.
+
+time_sleep                 Sleeps for a float number of seconds
+time_time                  Float number of seconds since the epoch
+
+OVERVIEW*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*CBFunc_t)
+   (int pi, unsigned user_gpio, unsigned level, uint32_t tick);
+
+typedef void (*CBFuncEx_t)
+   (int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+
+typedef struct callback_s callback_t;
+
+/*F*/
+double time_time(void);
+/*D
+Return the current time in seconds since the Epoch.
+D*/
+
+/*F*/
+void time_sleep(double seconds);
+/*D
+Delay execution for a given number of seconds.
+
+. .
+seconds: the number of seconds to delay.
+. .
+D*/
+
+/*F*/
+char *pigpio_error(int errnum);
+/*D
+Return a text description for an error code.
+
+. .
+errnum: the error code.
+. .
+D*/
+
+/*F*/
+unsigned pigpiod_if_version(void);
+/*D
+Return the pigpiod_if2 version.
+D*/
+
+/*F*/
+pthread_t *start_thread(gpioThreadFunc_t thread_func, void *userdata);
+/*D
+Starts a new thread of execution with thread_func as the main routine.
+
+. .
+thread_func: the main function for the new thread.
+   userdata: a pointer to an arbitrary argument.
+. .
+
+Returns a pointer to pthread_t if OK, otherwise NULL.
+
+The function is passed the single argument userdata.
+
+The thread can be cancelled by passing the pointer to pthread_t to
+[*stop_thread*].
+D*/
+
+/*F*/
+void stop_thread(pthread_t *pth);
+/*D
+Cancels the thread pointed at by pth.
+
+. .
+pth: the thread to be stopped.
+. .
+
+No value is returned.
+
+The thread to be stopped should have been started with [*start_thread*].
+D*/
+
+/*F*/
+int pigpio_start(char *addrStr, char *portStr);
+/*D
+Connect to the pigpio daemon.  Reserving command and
+notification streams.
+
+. .
+addrStr: specifies the host or IP address of the Pi running the
+         pigpio daemon.  It may be NULL in which case localhost
+         is used unless overridden by the PIGPIO_ADDR environment
+         variable.
+
+portStr: specifies the port address used by the Pi running the
+         pigpio daemon.  It may be NULL in which case "8888"
+         is used unless overridden by the PIGPIO_PORT environment
+         variable.
+. .
+
+Returns an integer value greater than or equal to zero if OK.
+
+This value is passed to the GPIO routines to specify the Pi
+to be operated on.
+D*/
+
+/*F*/
+void pigpio_stop(int pi);
+/*D
+Terminates the connection to a pigpio daemon and releases
+resources used by the library.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int set_mode(int pi, unsigned gpio, unsigned mode);
+/*D
+Set the gpio mode.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+gpio: 0-53.
+mode: PI_INPUT, PI_OUTPUT, PI_ALT0, _ALT1,
+      PI_ALT2, PI_ALT3, PI_ALT4, PI_ALT5.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_MODE,
+or PI_NOT_PERMITTED.
+D*/
+
+/*F*/
+int get_mode(int pi, unsigned gpio);
+/*D
+Get the gpio mode.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+gpio: 0-53.
+. .
+
+Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
+D*/
+
+/*F*/
+int set_pull_up_down(int pi, unsigned gpio, unsigned pud);
+/*D
+Set or clear the gpio pull-up/down resistor.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+gpio: 0-53.
+ pud: PI_PUD_UP, PI_PUD_DOWN, PI_PUD_OFF.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
+or PI_NOT_PERMITTED.
+D*/
+
+/*F*/
+int gpio_read(int pi, unsigned gpio);
+/*D
+Read the gpio level.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+gpio:0-53.
+. .
+
+Returns the gpio level if OK, otherwise PI_BAD_GPIO.
+D*/
+
+/*F*/
+int gpio_write(int pi, unsigned gpio, unsigned level);
+/*D
+Write the gpio level.
+
+. .
+   pi: 0- (as returned by [*pigpio_start*]).
+ gpio: 0-53.
+level: 0, 1.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_LEVEL,
+or PI_NOT_PERMITTED.
+
+Notes
+
+If PWM or servo pulses are active on the gpio they are switched off.
+D*/
+
+/*F*/
+int set_PWM_dutycycle(int pi, unsigned user_gpio, unsigned dutycycle);
+/*D
+Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+dutycycle: 0-range (range defaults to 255).
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
+or PI_NOT_PERMITTED.
+Notes
+
+The [*set_PWM_range*] function may be used to change the
+default range of 255.
+D*/
+
+/*F*/
+int get_PWM_dutycycle(int pi, unsigned user_gpio);
+/*D
+Return the PWM dutycycle in use on a gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_PWM_GPIO.
+
+For normal PWM the dutycycle will be out of the defined range
+for the gpio (see [*get_PWM_range*]).
+
+If a hardware clock is active on the gpio the reported dutycycle
+will be 500000 (500k) out of 1000000 (1M).
+
+If hardware PWM is active on the gpio the reported dutycycle
+will be out of a 1000000 (1M).
+D*/
+
+/*F*/
+int set_PWM_range(int pi, unsigned user_gpio, unsigned range);
+/*D
+Set the range of PWM values to be used on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+    range: 25-40000.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
+or PI_NOT_PERMITTED.
+
+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.
+D*/
+
+/*F*/
+int get_PWM_range(int pi, unsigned user_gpio);
+/*D
+Get the range of PWM values being used on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+. .
+
+Returns the dutycycle range used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+
+If a hardware clock or hardware PWM is active on the gpio the
+reported range will be 1000000 (1M).
+D*/
+
+/*F*/
+int get_PWM_real_range(int pi, unsigned user_gpio);
+/*D
+Get the real underlying range of PWM values being used on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+. .
+
+Returns the real range used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+
+If a hardware clock is active on the gpio the reported
+real range will be 1000000 (1M).
+
+If hardware PWM is active on the gpio the reported real range
+will be approximately 250M divided by the set PWM frequency.
+
+D*/
+
+/*F*/
+int set_PWM_frequency(int pi, unsigned user_gpio, unsigned frequency);
+/*D
+Set the frequency (in Hz) of the PWM to be used on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+frequency: 0- (Hz).
+. .
+
+Returns the numerically closest frequency if OK, otherwise
+PI_BAD_USER_GPIO or PI_NOT_PERMITTED.
+
+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
+. .
+D*/
+
+/*F*/
+int get_PWM_frequency(int pi, unsigned user_gpio);
+/*D
+Get the frequency of PWM being used on the gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+. .
+
+For normal PWM the frequency will be that defined for the gpio by
+[*set_PWM_frequency*].
+
+If a hardware clock is active on the gpio the reported frequency
+will be that set by [*hardware_clock*].
+
+If hardware PWM is active on the gpio the reported frequency
+will be that set by [*hardware_PWM*].
+
+Returns the frequency (in hertz) used for the gpio if OK,
+otherwise PI_BAD_USER_GPIO.
+D*/
+
+/*F*/
+int set_servo_pulsewidth(int pi, unsigned user_gpio, unsigned pulsewidth);
+/*D
+Start (500-2500) or stop (0) servo pulses on the gpio.
+
+. .
+        pi: 0- (as returned by [*pigpio_start*]).
+ user_gpio: 0-31.
+pulsewidth: 0 (off), 500 (anti-clockwise) - 2500 (clockwise).
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_PULSEWIDTH or
+PI_NOT_PERMITTED.
+
+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 pulsewidth.
+
+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. 
+D*/
+
+/*F*/
+int get_servo_pulsewidth(int pi, unsigned user_gpio);
+/*D
+Return the servo pulsewidth in use on a gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO or PI_NOT_SERVO_GPIO.
+D*/
+
+/*F*/
+int notify_open(int pi);
+/*D
+Get a free notification handle.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+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 the library 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.
+D*/
+
+/*F*/
+int notify_begin(int pi, unsigned handle, uint32_t bits);
+/*D
+Start notifications on a previously opened handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: 0-31 (as returned by [*notify_open*])
+  bits: a mask indicating the gpios to be notified.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+The notification sends state changes for each gpio whose
+corresponding bit in bits is set.
+
+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
+. .
+D*/
+
+/*F*/
+int notify_pause(int pi, unsigned handle);
+/*D
+Pause notifications on a previously opened handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: 0-31 (as returned by [*notify_open*])
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+Notifications for the handle are suspended until
+[*notify_begin*] is called again.
+D*/
+
+/*F*/
+int notify_close(int pi, unsigned handle);
+/*D
+Stop notifications on a previously opened handle and
+release the handle for reuse.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: 0-31 (as returned by [*notify_open*])
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+D*/
+
+/*F*/
+int set_watchdog(int pi, unsigned user_gpio, unsigned timeout);
+/*D
+Sets a watchdog for a gpio.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+  timeout: 0-60000.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO
+or PI_BAD_WDOG_TIMEOUT.
+
+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*] and [*callback_ex*] functions interpret the flags
+and will call registered callbacks for the gpio with level TIMEOUT.
+D*/
+
+/*F*/
+int set_glitch_filter(int pi, unsigned user_gpio, unsigned steady);
+/*D
+Sets a glitch filter on a gpio.
+
+Level changes on the gpio are not reported unless the level
+has been stable for at least [*steady*] microseconds.  The
+level is then reported.  Level changes of less than [*steady*]
+microseconds are ignored.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31
+   steady: 0-300000
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER.
+
+Note, each (stable) edge will be timestamped [*steady*] microseconds
+after it was first detected.
+D*/
+
+/*F*/
+int set_noise_filter(
+   int pi, unsigned user_gpio, unsigned steady, unsigned active);
+/*D
+Sets a noise filter on a gpio.
+
+Level changes on the gpio are ignored until a level which has
+been stable for [*steady*] microseconds is detected.  Level changes
+on the gpio are then reported for [*active*] microseconds after
+which the process repeats.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31
+   steady: 0-300000
+   active: 0-1000000
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER.
+
+Note, level changes before and after the active period may
+be reported.  Your software must be designed to cope with
+such reports.
+D*/
+
+/*F*/
+uint32_t read_bank_1(int pi);
+/*D
+Read the levels of the bank 1 gpios (gpios 0-31).
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+The returned 32 bit integer has a bit set if the corresponding
+gpio is logic 1.  Gpio n has bit value (1<<n).
+D*/
+
+/*F*/
+uint32_t read_bank_2(int pi);
+/*D
+Read the levels of the bank 2 gpios (gpios 32-53).
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+The returned 32 bit integer has a bit set if the corresponding
+gpio is logic 1.  Gpio n has bit value (1<<(n-32)).
+D*/
+
+/*F*/
+int clear_bank_1(int pi, uint32_t bits);
+/*D
+Clears gpios 0-31 if the corresponding bit in bits is set.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+bits: a bit mask with 1 set if the corresponding gpio is
+      to be cleared.
+. .
+
+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.
+D*/
+
+/*F*/
+int clear_bank_2(int pi, uint32_t bits);
+/*D
+Clears gpios 32-53 if the corresponding bit (0-21) in bits is set.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+bits: a bit mask with 1 set if the corresponding gpio is
+      to be cleared.
+. .
+
+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.
+D*/
+
+/*F*/
+int set_bank_1(int pi, uint32_t bits);
+/*D
+Sets gpios 0-31 if the corresponding bit in bits is set.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+bits: a bit mask with 1 set if the corresponding gpio is
+      to be 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.
+D*/
+
+/*F*/
+int set_bank_2(int pi, uint32_t bits);
+/*D
+Sets gpios 32-53 if the corresponding bit (0-21) in bits is set.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+bits: a bit mask with 1 set if the corresponding gpio is
+      to be 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.
+D*/
+
+
+/*F*/
+int hardware_clock(int pi, unsigned gpio, unsigned clkfreq);
+/*D
+Starts a hardware clock on a gpio at the specified frequency.
+Frequencies above 30MHz are unlikely to work.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+     gpio: see description
+frequency: 0 (off) or 4689-250000000 (250M)
+. .
+
+Returns 0 if OK, otherwise PI_NOT_PERMITTED, PI_BAD_GPIO,
+PI_NOT_HCLK_GPIO, PI_BAD_HCLK_FREQ,or PI_BAD_HCLK_PASS.
+
+The same clock is available on multiple gpios.  The latest
+frequency setting will be used by all gpios which share a clock.
+
+The gpio must be one of the following.
+
+. .
+4   clock 0  All models
+5   clock 1  A+/B+/Pi2 and compute module only (reserved for system use)
+6   clock 2  A+/B+/Pi2 and compute module only
+20  clock 0  A+/B+/Pi2 and compute module only
+21  clock 1  All models but Rev.2 B (reserved for system use)
+
+32  clock 0  Compute module only
+34  clock 0  Compute module only
+42  clock 1  Compute module only (reserved for system use)
+43  clock 2  Compute module only
+44  clock 1  Compute module only (reserved for system use)
+. .
+
+Access to clock 1 is protected by a password as its use will likely
+crash the Pi.  The password is given by or'ing 0x5A000000 with the
+gpio number.
+D*/
+
+
+/*F*/
+int hardware_PWM(int pi, unsigned gpio, unsigned PWMfreq, uint32_t PWMduty);
+/*D
+Starts hardware PWM on a gpio at the specified frequency and dutycycle.
+Frequencies above 30MHz are unlikely to work.
+
+NOTE: Any waveform started by [*wave_send_once*], [*wave_send_repeat*],
+or [*wave_chain*] will be cancelled.
+
+This function is only valid if the pigpio main clock is PCM.  The
+main clock defaults to PCM but may be overridden when the pigpio
+daemon is started (option -t).
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+   gpio: see descripton
+PWMfreq: 0 (off) or 1-125000000 (125M)
+PWMduty: 0 (off) to 1000000 (1M)(fully on)
+. .
+
+Returns 0 if OK, otherwise PI_NOT_PERMITTED, PI_BAD_GPIO,
+PI_NOT_HPWM_GPIO, PI_BAD_HPWM_DUTY, PI_BAD_HPWM_FREQ,
+or PI_HPWM_ILLEGAL.
+
+The same PWM channel is available on multiple gpios.  The latest
+frequency and dutycycle setting will be used by all gpios which
+share a PWM channel.
+
+The gpio must be one of the following.
+
+. .
+12  PWM channel 0  A+/B+/Pi2 and compute module only
+13  PWM channel 1  A+/B+/Pi2 and compute module only
+18  PWM channel 0  All models
+19  PWM channel 1  A+/B+/Pi2 and compute module only
+
+40  PWM channel 0  Compute module only
+41  PWM channel 1  Compute module only
+45  PWM channel 1  Compute module only
+52  PWM channel 0  Compute module only
+53  PWM channel 1  Compute module only
+. .
+D*/
+
+
+/*F*/
+uint32_t get_current_tick(int pi);
+/*D
+Gets the current system tick.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+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.
+
+D*/
+
+/*F*/
+uint32_t get_hardware_revision(int pi);
+/*D
+Get the Pi's hardware revision number.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+The hardware revision is the last few characters on the Revision line
+of /proc/cpuinfo.
+
+If the hardware revision can not be found or is not a valid
+hexadecimal number the function returns 0.
+
+The revision number can be used to determine the assignment of gpios
+to pins (see [*gpio*]).
+
+There are at least three types of board.
+
+Type 1 boards have hardware revision numbers of 2 and 3.
+
+Type 2 boards have hardware revision numbers of 4, 5, 6, and 15.
+
+Type 3 boards have hardware revision numbers of 16 or greater.
+D*/
+
+/*F*/
+uint32_t get_pigpio_version(int pi);
+/*D
+Returns the pigpio version.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+
+/*F*/
+int wave_clear(int pi);
+/*D
+This function clears all waveforms and any data added by calls to the
+[*wave_add_**] functions.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+Returns 0 if OK.
+D*/
+
+/*F*/
+int wave_add_new(int pi);
+/*D
+This function starts a new empty waveform.  You wouldn't normally need
+to call this function as it is automatically called after a waveform is
+created with the [*wave_create*] function.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+Returns 0 if OK.
+D*/
+
+/*F*/
+int wave_add_generic(int pi, unsigned numPulses, gpioPulse_t *pulses);
+/*D
+This function adds a number of pulses to the current waveform.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+numPulses: the number of pulses.
+   pulses: an array of pulses.
+. .
+
+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.
+D*/
+
+/*F*/
+int wave_add_serial
+   (int pi, unsigned user_gpio, unsigned baud, unsigned data_bits,
+    unsigned stop_bits, unsigned offset, unsigned numBytes, char *str);
+/*D
+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.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+     baud: 50-1000000
+data_bits: number of data bits (1-32)
+stop_bits: number of stop half bits (2-8)
+   offset: 0-
+ numBytes: 1-
+      str: an array of chars.
+. .
+
+Returns the new total number of pulses in the current waveform if OK,
+otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD, PI_BAD_DATABITS,
+PI_BAD_STOP_BITS, PI_TOO_MANY_CHARS, PI_BAD_SER_OFFSET,
+or PI_TOO_MANY_PULSES.
+
+NOTES:
+
+The serial data is formatted as one start bit, [*data_bits*] data bits,
+and [*stop_bits*]/2 stop bits.
+
+It is legal to add serial data streams with different baud rates to
+the same waveform.
+
+[*numBytes*] is the number of bytes of data in str.
+
+The bytes required for each character depend upon [*data_bits*].
+
+For [*data_bits*] 1-8 there will be one byte per character. 
+For [*data_bits*] 9-16 there will be two bytes per character. 
+For [*data_bits*] 17-32 there will be four bytes per character.
+D*/
+
+/*F*/
+int wave_create(int pi);
+/*D
+This function creates a waveform from the data provided by the prior
+calls to the [*wave_add_**] functions.  Upon success a wave id
+greater than or equal to 0 is returned, otherwise PI_EMPTY_WAVEFORM,
+PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+The data provided by the [*wave_add_**] functions is consumed by this
+function.
+
+As many waveforms may be created as there is space available.  The
+wave id is passed to [*wave_send_**] to specify the waveform to transmit.
+
+Normal usage would be
+
+Step 1. [*wave_clear*] to clear all waveforms and added data.
+
+Step 2. [*wave_add_**] calls to supply the waveform data.
+
+Step 3. [*wave_create*] to create the waveform and get a unique id
+
+Repeat steps 2 and 3 as needed.
+
+Step 4. [*wave_send_**] with the id of the waveform to transmit.
+
+A waveform comprises one or more pulses.  Each pulse consists of a
+[*gpioPulse_t*] structure.
+
+. .
+typedef struct
+{
+   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.
+
+Returns the new waveform id if OK, otherwise PI_EMPTY_WAVEFORM,
+PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL.
+D*/
+
+
+/*F*/
+int wave_delete(int pi, unsigned wave_id);
+/*D
+This function deletes the waveform with id wave_id.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+wave_id: >=0, as returned by [*wave_create*].
+. .
+
+Wave ids are allocated in order, 0, 1, 2, etc.
+
+Returns 0 if OK, otherwise PI_BAD_WAVE_ID.
+D*/
+
+/*F*/
+int wave_send_once(int pi, unsigned wave_id);
+/*D
+This function transmits the waveform with id wave_id.  The waveform
+is sent once.
+
+NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+wave_id: >=0, as returned by [*wave_create*].
+. .
+
+Returns the number of DMA control blocks in the waveform if OK,
+otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+D*/
+
+/*F*/
+int wave_send_repeat(int pi, unsigned wave_id);
+/*D
+This function transmits the waveform with id wave_id.  The waveform
+cycles until cancelled (either by the sending of a new waveform or
+by [*wave_tx_stop*]).
+
+NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+wave_id: >=0, as returned by [*wave_create*].
+. .
+
+Returns the number of DMA control blocks in the waveform if OK,
+otherwise PI_BAD_WAVE_ID, or PI_BAD_WAVE_MODE.
+D*/
+
+/*F*/
+int wave_chain(int pi, char *buf, unsigned bufSize);
+/*D
+This function transmits a chain of waveforms.
+
+NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled.
+
+The waves to be transmitted are specified by the contents of buf
+which contains an ordered list of [*wave_id*]s and optional command
+codes and related data.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+    buf: pointer to the wave_ids and optional command codes
+bufSize: the number of bytes in buf
+. .
+
+Returns 0 if OK, otherwise PI_CHAIN_NESTING, PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, PI_CHAIN_COUNTER,
+PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, or PI_BAD_WAVE_ID.
+
+Each wave is transmitted in the order specified.  A wave may
+occur multiple times per chain.
+
+A blocks of waves may be transmitted multiple times by using
+the loop commands. The block is bracketed by loop start and
+end commands.  Loops may be nested.
+
+Delays between waves may be added with the delay command.
+
+The following command codes are supported:
+
+Name         @ Cmd & Data @ Meaning
+Loop Start   @ 255 0      @ Identify start of a wave block
+Loop Repeat  @ 255 1 x y  @ loop x + y*256 times
+Delay        @ 255 2 x y  @ delay x + y*256 microseconds
+Loop Forever @ 255 3      @ loop forever
+
+If present Loop Forever must be the last entry in the chain.
+
+The code is currently dimensioned to support a chain with roughly
+600 entries and 20 loop counters.
+
+...
+#include <stdio.h>
+#include <pigpiod_if2.h>
+
+#define WAVES 5
+#define GPIO 4
+
+int main(int argc, char *argv[])
+{
+   int i, pi, wid[WAVES];
+
+   pi = pigpio_start(0, 0);
+   if (pi<0) return -1;
+
+   set_mode(pi, GPIO, PI_OUTPUT);
+
+   for (i=0; i<WAVES; i++)
+   {
+      wave_add_generic(pi, 2, (gpioPulse_t[])
+         {{1<<GPIO, 0,        20},
+          {0, 1<<GPIO, (i+1)*200}});
+
+      wid[i] = wave_create(pi);
+   }
+
+   wave_chain(pi, (char []) {
+      wid[4], wid[3], wid[2],       // transmit waves 4+3+2
+      255, 0,                       // loop start
+         wid[0], wid[0], wid[0],    // transmit waves 0+0+0
+         255, 0,                    // loop start
+            wid[0], wid[1],         // transmit waves 0+1
+            255, 2, 0x88, 0x13,     // delay 5000us
+         255, 1, 30, 0,             // loop end (repeat 30 times)
+         255, 0,                    // loop start
+            wid[2], wid[3], wid[0], // transmit waves 2+3+0
+            wid[3], wid[1], wid[2], // transmit waves 3+1+2
+         255, 1, 10, 0,             // loop end (repeat 10 times)
+      255, 1, 5, 0,                 // loop end (repeat 5 times)
+      wid[4], wid[4], wid[4],       // transmit waves 4+4+4
+      255, 2, 0x20, 0x4E,           // delay 20000us
+      wid[0], wid[0], wid[0],       // transmit waves 0+0+0
+
+      }, 46);
+
+   while (wave_tx_busy(pi)) time_sleep(0.1);
+
+   for (i=0; i<WAVES; i++) wave_delete(pi, wid[i]);
+
+   pigpio_stop(pi);
+}
+...
+D*/
+
+
+/*F*/
+int wave_tx_busy(int pi);
+/*D
+This function checks to see if a waveform is currently being
+transmitted.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+Returns 1 if a waveform is currently being transmitted, otherwise 0.
+D*/
+
+/*F*/
+int wave_tx_stop(int pi);
+/*D
+This function stops the transmission of the current waveform.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+
+Returns 0 if OK.
+
+This function is intended to stop a waveform started with the repeat mode.
+D*/
+
+/*F*/
+int wave_get_micros(int pi);
+/*D
+This function returns the length in microseconds of the current
+waveform.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_high_micros(int pi);
+/*D
+This function returns the length in microseconds of the longest waveform
+created since the pigpio daemon was started.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_max_micros(int pi);
+/*D
+This function returns the maximum possible size of a waveform in 
+microseconds.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_pulses(int pi);
+/*D
+This function returns the length in pulses of the current waveform.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_high_pulses(int pi);
+/*D
+This function returns the length in pulses of the longest waveform
+created since the pigpio daemon was started.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_max_pulses(int pi);
+/*D
+This function returns the maximum possible size of a waveform in pulses.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_cbs(int pi);
+/*D
+This function returns the length in DMA control blocks of the current
+waveform.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_high_cbs(int pi);
+/*D
+This function returns the length in DMA control blocks of the longest
+waveform created since the pigpio daemon was started.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int wave_get_max_cbs(int pi);
+/*D
+This function returns the maximum possible size of a waveform in DMA
+control blocks.
+
+. .
+pi: 0- (as returned by [*pigpio_start*]).
+. .
+D*/
+
+/*F*/
+int gpio_trigger(int pi, unsigned user_gpio, unsigned pulseLen, unsigned level);
+/*D
+This function sends a trigger pulse to a gpio.  The gpio is set to
+level for pulseLen microseconds and then reset to not level.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+ pulseLen: 1-100.
+    level: 0,1.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_LEVEL,
+PI_BAD_PULSELEN, or PI_NOT_PERMITTED.
+D*/
+
+/*F*/
+int store_script(int pi, char *script);
+/*D
+This function stores a script for later execution.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+script: the text of the script.
+. .
+
+The function returns a script id if the script is valid,
+otherwise PI_BAD_SCRIPT.
+D*/
+
+/*F*/
+int run_script(int pi, unsigned script_id, unsigned numPar, uint32_t *param);
+/*D
+This function runs a stored script.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+script_id: >=0, as returned by [*store_script*].
+   numPar: 0-10, the number of parameters.
+    param: an array of parameters.
+. .
+
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID, or
+PI_TOO_MANY_PARAM
+
+param is an array of up to 10 parameters which may be referenced in
+the script as p0 to p9.
+D*/
+
+/*F*/
+int script_status(int pi, unsigned script_id, uint32_t *param);
+/*D
+This function returns the run status of a stored script as well
+as the current values of parameters 0 to 9.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+script_id: >=0, as returned by [*store_script*].
+    param: an array to hold the returned 10 parameters.
+. .
+
+The function returns greater than or equal to 0 if OK,
+otherwise PI_BAD_SCRIPT_ID.
+
+The run status may be
+
+. .
+PI_SCRIPT_INITING
+PI_SCRIPT_HALTED
+PI_SCRIPT_RUNNING
+PI_SCRIPT_WAITING
+PI_SCRIPT_FAILED
+. .
+
+The current value of script parameters 0 to 9 are returned in param.
+D*/
+
+/*F*/
+int stop_script(int pi, unsigned script_id);
+/*D
+This function stops a running script.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+script_id: >=0, as returned by [*store_script*].
+. .
+
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+D*/
+
+/*F*/
+int delete_script(int pi, unsigned script_id);
+/*D
+This function deletes a stored script.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+script_id: >=0, as returned by [*store_script*].
+. .
+
+The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
+D*/
+
+/*F*/
+int bb_serial_read_open(int pi, unsigned user_gpio, unsigned baud, unsigned data_bits);
+/*D
+This function opens a gpio for bit bang reading of serial data.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+     baud: 50-250000
+data_bits: 1-32
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
+or PI_GPIO_IN_USE.
+
+The serial data is returned in a cyclic buffer and is read using
+bb_serial_read.
+
+It is the caller's responsibility to read data from the cyclic buffer
+in a timely fashion.
+D*/
+
+/*F*/
+int bb_serial_read(int pi, unsigned user_gpio, void *buf, size_t bufSize);
+/*D
+This function copies up to bufSize bytes of data read from the
+bit bang serial cyclic buffer to the buffer starting at buf.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31, previously opened with [*bb_serial_read_open*].
+      buf: an array to receive the read bytes.
+  bufSize: 0-
+. .
+
+Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
+or PI_NOT_SERIAL_GPIO.
+
+The bytes returned for each character depend upon the number of
+data bits [*data_bits*] specified in the [*bb_serial_read_open*] command.
+
+For [*data_bits*] 1-8 there will be one byte per character. 
+For [*data_bits*] 9-16 there will be two bytes per character. 
+For [*data_bits*] 17-32 there will be four bytes per character.
+D*/
+
+/*F*/
+int bb_serial_read_close(int pi, unsigned user_gpio);
+/*D
+This function closes a gpio for bit bang reading of serial data.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31, previously opened with [*bb_serial_read_open*].
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
+D*/
+
+/*F*/
+int bb_serial_invert(int pi, unsigned user_gpio, unsigned invert);
+/*D
+This function inverts serial logic for big bang serial reads.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31, previously opened with [*bb_serial_read_open*].
+   invert: 0-1, 1 invert, 0 normal.
+. .
+
+Returns 0 if OK, otherwise PI_NOT_SERIAL_GPIO or PI_BAD_SER_INVERT.
+D*/
+
+/*F*/
+int i2c_open(int pi, unsigned i2c_bus, unsigned i2c_addr, unsigned i2c_flags);
+/*D
+This returns a handle for the device at address i2c_addr on bus i2c_bus.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+  i2c_bus: 0-1.
+ i2c_addr: 0x00-0x7F.
+i2c_flags: 0.
+. .
+
+No flags are currently defined.  This parameter should be set to zero.
+
+Returns a handle (>=0) if OK, otherwise PI_BAD_I2C_BUS, PI_BAD_I2C_ADDR,
+PI_BAD_FLAGS, PI_NO_HANDLE, or PI_I2C_OPEN_FAILED.
+
+For the SMBus commands the low level transactions are shown at the end
+of the function description.  The following abbreviations are used.
+
+. .
+S       (1 bit) : Start bit
+P       (1 bit) : Stop bit
+Rd/Wr   (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
+A, NA   (1 bit) : Accept and not accept bit. 
+Addr    (7 bits): I2C 7 bit address.
+i2c_reg (8 bits): A byte which often selects a register.
+Data    (8 bits): A data byte.
+Count   (8 bits): A byte defining the length of a block operation.
+
+[..]: Data sent by the device.
+. .
+D*/
+
+/*F*/
+int i2c_close(int pi, unsigned handle);
+/*D
+This closes the I2C device associated with the handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+D*/
+
+/*F*/
+int i2c_write_quick(int pi, unsigned handle, unsigned bit);
+/*D
+This sends a single bit (in the Rd/Wr bit) to the device associated
+with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+   bit: 0-1, the value to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+Quick command. SMBus 2.0 5.5.1
+. .
+S Addr bit [A] P
+. .
+D*/
+
+/*F*/
+int i2c_write_byte(int pi, unsigned handle, unsigned bVal);
+/*D
+This sends a single byte to the device associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+  bVal: 0-0xFF, the value to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+Send byte. SMBus 2.0 5.5.2
+. .
+S Addr Wr [A] bVal [A] P
+. .
+D*/
+
+/*F*/
+int i2c_read_byte(int pi, unsigned handle);
+/*D
+This reads a single byte from the device associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+. .
+
+Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE,
+or PI_I2C_READ_FAILED.
+
+Receive byte. SMBus 2.0 5.5.3
+. .
+S Addr Rd [A] [Data] NA P
+. .
+D*/
+
+/*F*/
+int i2c_write_byte_data(
+   int pi, unsigned handle, unsigned i2c_reg, unsigned bVal);
+/*D
+This writes a single byte to the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write.
+   bVal: 0-0xFF, the value to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+Write byte. SMBus 2.0 5.5.4
+. .
+S Addr Wr [A] i2c_reg [A] bVal [A] P
+. .
+D*/
+
+/*F*/
+int i2c_write_word_data(
+   int pi, unsigned handle, unsigned i2c_reg, unsigned wVal);
+/*D
+This writes a single 16 bit word to the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write.
+   wVal: 0-0xFFFF, the value to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+Write word. SMBus 2.0 5.5.4
+. .
+S Addr Wr [A] i2c_reg [A] wval_Low [A] wVal_High [A] P
+. .
+D*/
+
+/*F*/
+int i2c_read_byte_data(int pi, unsigned handle, unsigned i2c_reg);
+/*D
+This reads a single byte from the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to read.
+. .
+
+Returns the byte read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+Read byte. SMBus 2.0 5.5.5
+. .
+S Addr Wr [A] i2c_reg [A] S Addr Rd [A] [Data] NA P
+. .
+D*/
+
+/*F*/
+int i2c_read_word_data(int pi, unsigned handle, unsigned i2c_reg);
+/*D
+This reads a single 16 bit word from the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to read.
+. .
+
+Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+Read word. SMBus 2.0 5.5.5
+. .
+S Addr Wr [A] i2c_reg [A]
+   S Addr Rd [A] [DataLow] A [DataHigh] NA P
+. .
+D*/
+
+/*F*/
+int i2c_process_call(int pi, unsigned handle, unsigned i2c_reg, unsigned wVal);
+/*D
+This writes 16 bits of data to the specified register of the device
+associated with handle and and reads 16 bits of data in return.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write/read.
+   wVal: 0-0xFFFF, the value to write.
+. .
+
+Returns the word read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+Process call. SMBus 2.0 5.5.6
+. .
+S Addr Wr [A] i2c_reg [A] wVal_Low [A] wVal_High [A]
+   S Addr Rd [A] [DataLow] A [DataHigh] NA P
+. .
+D*/
+
+/*F*/
+int i2c_write_block_data(
+   int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count);
+/*D
+This writes up to 32 bytes to the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write.
+    buf: an array with the data to send.
+  count: 1-32, the number of bytes to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+Block write. SMBus 2.0 5.5.7
+. .
+S Addr Wr [A] i2c_reg [A] count [A] buf0 [A] buf1 [A] ...
+   [A] bufn [A] P
+. .
+D*/
+
+/*F*/
+int i2c_read_block_data(int pi, unsigned handle, unsigned i2c_reg, char *buf);
+/*D
+This reads a block of up to 32 bytes from the specified register of
+the device associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to read.
+    buf: an array to receive the read data.
+. .
+
+The amount of returned data is set by the device.
+
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+Block read. SMBus 2.0 5.5.7
+. .
+S Addr Wr [A] i2c_reg [A]
+   S Addr Rd [A] [Count] A [buf0] A [buf1] A ... A [bufn] NA P
+. .
+D*/
+
+/*F*/
+int i2c_block_process_call(
+   int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count);
+/*D
+This writes data bytes to the specified register of the device
+associated with handle and reads a device specified number
+of bytes of data in return.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write/read.
+    buf: an array with the data to send and to receive the read data.
+  count: 1-32, the number of bytes to write.
+. .
+
+
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+The smbus 2.0 documentation states that a minimum of 1 byte may be
+sent and a minimum of 1 byte may be received.  The total number of
+bytes sent/received must be 32 or less.
+
+Block write-block read. SMBus 2.0 5.5.8
+. .
+S Addr Wr [A] i2c_reg [A] count [A] buf0 [A] ...
+   S Addr Rd [A] [Count] A [Data] ... A P
+. .
+D*/
+
+/*F*/
+int i2c_read_i2c_block_data(
+   int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count);
+/*D
+This reads count bytes from the specified register of the device
+associated with handle .  The count may be 1-32.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to read.
+    buf: an array to receive the read data.
+  count: 1-32, the number of bytes to read.
+. .
+
+Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, or PI_I2C_READ_FAILED.
+
+. .
+S Addr Wr [A] i2c_reg [A]
+   S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+. .
+D*/
+
+
+/*F*/
+int i2c_write_i2c_block_data(
+   int pi, unsigned handle, unsigned i2c_reg, char *buf, unsigned count);
+/*D
+This writes 1 to 32 bytes to the specified register of the device
+associated with handle.
+
+. .
+     pi: 0- (as returned by [*pigpio_start*]).
+ handle: >=0, as returned by a call to [*i2c_open*].
+i2c_reg: 0-255, the register to write.
+    buf: the data to write.
+  count: 1-32, the number of bytes to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+. .
+S Addr Wr [A] i2c_reg [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+. .
+D*/
+
+/*F*/
+int i2c_read_device(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This reads count bytes from the raw device into buf.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+   buf: an array to receive the read data bytes.
+ count: >0, the number of bytes to read.
+. .
+
+Returns count (>0) if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_READ_FAILED.
+
+. .
+S Addr Rd [A] [buf0] A [buf1] A ... A [bufn] NA P
+. .
+D*/
+
+/*F*/
+int i2c_write_device(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This writes count bytes from buf to the raw device.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2c_open*].
+   buf: an array containing the data bytes to write.
+ count: >0, the number of bytes to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_I2C_WRITE_FAILED.
+
+. .
+S Addr Wr [A] buf0 [A] buf1 [A] ... [A] bufn [A] P
+. .
+D*/
+
+/*F*/
+int i2c_zip(
+   int pi,
+   unsigned handle,
+   char    *inBuf,
+   unsigned inLen,
+   char    *outBuf,
+   unsigned outLen);
+/*D
+This function executes a sequence of I2C operations.  The
+operations to be performed are specified by the contents of inBuf
+which contains the concatenated command codes and associated data.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*i2cOpen*]
+ inBuf: pointer to the concatenated I2C commands, see below
+ inLen: size of command buffer
+outBuf: pointer to buffer to hold returned data
+outLen: size of output buffer
+. .
+
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_HANDLE, PI_BAD_POINTER, PI_BAD_I2C_CMD, PI_BAD_I2C_RLEN.
+PI_BAD_I2C_WLEN, or PI_BAD_I2C_SEG.
+
+The following command codes are supported:
+
+Name    @ Cmd & Data @ Meaning
+End     @ 0          @ No more commands
+Escape  @ 1          @ Next P is two bytes
+On      @ 2          @ Switch combined flag on
+Off     @ 3          @ Switch combined flag off
+Address @ 4 P        @ Set I2C address to P
+Flags   @ 5 lsb msb  @ Set I2C flags to lsb + (msb << 8)
+Read    @ 6 P        @ Read P bytes of data
+Write   @ 7 P ...    @ Write P bytes of data
+
+The address, read, and write commands take a parameter P.
+Normally P is one byte (0-255).  If the command is preceded by
+the Escape command then P is two bytes (0-65535, least significant
+byte first).
+
+The address defaults to that associated with the handle.
+The flags default to 0.  The address and flags maintain their
+previous value until updated.
+
+The returned I2C data is stored in consecutive locations of outBuf.
+
+...
+Set address 0x53, write 0x32, read 6 bytes
+Set address 0x1E, write 0x03, read 6 bytes
+Set address 0x68, write 0x1B, read 8 bytes
+End
+
+0x04 0x53   0x07 0x01 0x32   0x06 0x06
+0x04 0x1E   0x07 0x01 0x03   0x06 0x06
+0x04 0x68   0x07 0x01 0x1B   0x06 0x08
+0x00
+...
+
+D*/
+
+/*F*/
+int bb_i2c_open(int pi, unsigned SDA, unsigned SCL, unsigned baud);
+/*D
+This function selects a pair of gpios for bit banging I2C at a
+specified baud rate.
+
+Bit banging I2C allows for certain operations which are not possible
+with the standard I2C driver.
+
+o baud rates as low as 50 
+o repeated starts 
+o clock stretching 
+o I2C on any pair of spare gpios
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+ SDA: 0-31
+ SCL: 0-31
+baud: 50-500000
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_I2C_BAUD, or
+PI_GPIO_IN_USE.
+
+NOTE:
+
+The gpios used for SDA and SCL must have pull-ups to 3V3 connected.  As
+a guide the hardware pull-ups on pins 3 and 5 are 1k8 in value.
+D*/
+
+/*F*/
+int bb_i2c_close(int pi, unsigned SDA);
+/*D
+This function stops bit banging I2C on a pair of gpios previously
+opened with [*bb_i2c_open*].
+
+. .
+ pi: 0- (as returned by [*pigpio_start*]).
+SDA: 0-31, the SDA gpio used in a prior call to [*bb_i2c_open*]
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO.
+D*/
+
+/*F*/
+int bb_i2c_zip(
+   int pi,
+   unsigned SDA,
+   char    *inBuf,
+   unsigned inLen,
+   char    *outBuf,
+   unsigned outLen);
+/*D
+This function executes a sequence of bit banged I2C operations.  The
+operations to be performed are specified by the contents of inBuf
+which contains the concatenated command codes and associated data.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+   SDA: 0-31 (as used in a prior call to [*bb_i2c_open*])
+ inBuf: pointer to the concatenated I2C commands, see below
+ inLen: size of command buffer
+outBuf: pointer to buffer to hold returned data
+outLen: size of output buffer
+. .
+
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_I2C_GPIO, PI_BAD_POINTER,
+PI_BAD_I2C_CMD, PI_BAD_I2C_RLEN, PI_BAD_I2C_WLEN,
+PI_I2C_READ_FAILED, or PI_I2C_WRITE_FAILED.
+
+The following command codes are supported:
+
+Name    @ Cmd & Data   @ Meaning
+End     @ 0            @ No more commands
+Escape  @ 1            @ Next P is two bytes
+Start   @ 2            @ Start condition
+Stop    @ 3            @ Stop condition
+Address @ 4 P          @ Set I2C address to P
+Flags   @ 5 lsb msb    @ Set I2C flags to lsb + (msb << 8)
+Read    @ 6 P          @ Read P bytes of data
+Write   @ 7 P ...      @ Write P bytes of data
+
+The address, read, and write commands take a parameter P.
+Normally P is one byte (0-255).  If the command is preceded by
+the Escape command then P is two bytes (0-65535, least significant
+byte first).
+
+The address and flags default to 0.  The address and flags maintain
+their previous value until updated.
+
+No flags are currently defined.
+
+The returned I2C data is stored in consecutive locations of outBuf.
+
+...
+Set address 0x53
+start, write 0x32, (re)start, read 6 bytes, stop
+Set address 0x1E
+start, write 0x03, (re)start, read 6 bytes, stop
+Set address 0x68
+start, write 0x1B, (re)start, read 8 bytes, stop
+End
+
+0x04 0x53
+0x02 0x07 0x01 0x32   0x02 0x06 0x06 0x03
+
+0x04 0x1E
+0x02 0x07 0x01 0x03   0x02 0x06 0x06 0x03
+
+0x04 0x68
+0x02 0x07 0x01 0x1B   0x02 0x06 0x08 0x03
+
+0x00
+...
+D*/
+
+/*F*/
+int spi_open(int pi, unsigned spi_channel, unsigned baud, unsigned spi_flags);
+/*D
+This function returns a handle for the SPI device on channel.
+Data will be transferred at baud bits per second.  The flags may
+be used to modify the default behaviour of 4-wire operation, mode 0,
+active low chip select.
+
+An auxiliary SPI device is available on the A+/B+/Pi2 and may be
+selected by setting the A bit in the flags.  The auxiliary
+device has 3 chip selects and a selectable word size in bits.
+
+. .
+         pi: 0- (as returned by [*pigpio_start*]).
+spi_channel: 0-1 (0-2 for A+/B+/Pi2 auxiliary device).
+       baud: 32K-125M (values above 30M are unlikely to work).
+  spi_flags: see below.
+. .
+
+Returns a handle (>=0) if OK, otherwise PI_BAD_SPI_CHANNEL,
+PI_BAD_SPI_SPEED, PI_BAD_FLAGS, PI_NO_AUX_SPI, or PI_SPI_OPEN_FAILED.
+
+spi_flags consists of the least significant 22 bits.
+
+. .
+21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+ b  b  b  b  b  b  R  T  n  n  n  n  W  A u2 u1 u0 p2 p1 p0  m  m
+. .
+
+mm defines the SPI mode.
+
+Warning: modes 1 and 3 do not appear to work on the auxiliary device.
+
+. .
+Mode POL PHA
+ 0    0   0
+ 1    0   1
+ 2    1   0
+ 3    1   1
+. .
+
+px is 0 if CEx is active low (default) and 1 for active high.
+
+ux is 0 if the CEx gpio is reserved for SPI (default) and 1 otherwise.
+
+A is 0 for the standard SPI device, 1 for the auxiliary SPI.  The
+auxiliary device is only present on the A+/B+/Pi2.
+
+W is 0 if the device is not 3-wire, 1 if the device is 3-wire.  Standard
+SPI device only.
+
+nnnn defines the number of bytes (0-15) to write before switching
+the MOSI line to MISO to read data.  This field is ignored
+if W is not set.  Standard SPI device only.
+
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.  Auxiliary SPI
+device only.
+
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.  Auxiliary SPI
+device only.
+
+bbbbbb defines the word size in bits (0-32).  The default (0)
+sets 8 bits per word.  Auxiliary SPI device only.
+
+The other bits in flags should be set to zero.
+D*/
+
+/*F*/
+int spi_close(int pi, unsigned handle);
+/*D
+This functions closes the SPI device identified by the handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*spi_open*].
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+D*/
+
+/*F*/
+int spi_read(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This function reads count bytes of data from the SPI
+device associated with the handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*spi_open*].
+   buf: an array to receive the read data bytes.
+ count: the number of bytes to read.
+. .
+
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+D*/
+
+/*F*/
+int spi_write(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This function writes count bytes of data from buf to the SPI
+device associated with the handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*spi_open*].
+   buf: the data bytes to write.
+ count: the number of bytes to write.
+. .
+
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+D*/
+
+/*F*/
+int spi_xfer(
+   int pi, unsigned handle, char *txBuf, char *rxBuf, unsigned count);
+/*D
+This function transfers count bytes of data from txBuf to the SPI
+device associated with the handle.  Simultaneously count bytes of
+data are read from the device and placed in rxBuf.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*spi_open*].
+ txBuf: the data bytes to write.
+ rxBuf: the received data bytes.
+ count: the number of bytes to transfer.
+. .
+
+Returns the number of bytes transferred if OK, otherwise
+PI_BAD_HANDLE, PI_BAD_SPI_COUNT, or PI_SPI_XFER_FAILED.
+D*/
+
+/*F*/
+int serial_open(int pi, char *ser_tty, unsigned baud, unsigned ser_flags);
+/*D
+This function opens a serial device at a specified baud rate
+with specified flags.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+  ser_tty: the serial device to open, /dev/tty*.
+     baud: the baud rate in bits per second, see below.
+ser_flags: 0.
+. .
+
+Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, or
+PI_SER_OPEN_FAILED.
+
+The baud rate must be one of 50, 75, 110, 134, 150,
+200, 300, 600, 1200, 1800, 2400, 4800, 9500, 19200,
+38400, 57600, 115200, or 230400.
+
+No flags are currently defined.  This parameter should be set to zero.
+D*/
+
+/*F*/
+int serial_close(int pi, unsigned handle);
+/*D
+This function closes the serial device associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+D*/
+
+/*F*/
+int serial_write_byte(int pi, unsigned handle, unsigned bVal);
+/*D
+This function writes bVal to the serial port associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_SER_WRITE_FAILED.
+D*/
+
+/*F*/
+int serial_read_byte(int pi, unsigned handle);
+/*D
+This function reads a byte from the serial port associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+. .
+
+Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
+PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
+D*/
+
+/*F*/
+int serial_write(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This function writes count bytes from buf to the the serial port
+associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+   buf: the array of bytes to write.
+ count: the number of bytes to write.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE, PI_BAD_PARAM, or
+PI_SER_WRITE_FAILED.
+D*/
+
+/*F*/
+int serial_read(int pi, unsigned handle, char *buf, unsigned count);
+/*D
+This function reads up to count bytes from the the serial port
+associated with handle and writes them to buf.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+   buf: an array to receive the read data.
+ count: the maximum number of bytes to read.
+. .
+
+Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
+D*/
+
+/*F*/
+int serial_data_available(int pi, unsigned handle);
+/*D
+Returns the number of bytes available to be read from the
+device associated with handle.
+
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+handle: >=0, as returned by a call to [*serial_open*].
+. .
+
+Returns the number of bytes of data available (>=0) if OK,
+otherwise PI_BAD_HANDLE.
+D*/
+
+/*F*/
+int custom_1(int pi, unsigned arg1, unsigned arg2, char *argx, unsigned argc);
+/*D
+This function is available for user customisation.
+
+It returns a single integer value.
+
+. .
+  pi: 0- (as returned by [*pigpio_start*]).
+arg1: >=0
+arg2: >=0
+argx: extra (byte) arguments
+argc: number of extra arguments
+. .
+
+Returns >= 0 if OK, less than 0 indicates a user defined error.
+D*/
+
+
+/*F*/
+int custom_2(int pi, unsigned arg1, char *argx, unsigned argc,
+             char *retBuf, unsigned retMax);
+/*D
+This function is available for user customisation.
+
+It differs from custom_1 in that it returns an array of bytes
+rather than just an integer.
+
+The return value is an integer indicating the number of returned bytes.
+. .
+    pi: 0- (as returned by [*pigpio_start*]).
+  arg1: >=0
+  argc: extra (byte) arguments
+ count: number of extra arguments
+retBuf: buffer for returned data
+retMax: maximum number of bytes to return
+. .
+
+Returns >= 0 if OK, less than 0 indicates a user defined error.
+
+Note, the number of returned bytes will be retMax or less.
+D*/
+
+
+/*F*/
+int callback(int pi, unsigned user_gpio, unsigned edge, CBFunc_t f);
+/*D
+This function initialises a new callback.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+        f: the callback function.
+. .
+
+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.
+D*/
+
+/*F*/
+int callback_ex
+   (int pi, unsigned user_gpio, unsigned edge, CBFuncEx_t f, void *userdata);
+/*D
+This function initialises a new callback.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+        f: the callback function.
+ userdata: a pointer to arbitrary user data.
+. .
+
+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.
+D*/
+
+/*F*/
+int callback_cancel(unsigned callback_id);
+/*D
+This function cancels a callback identified by its id.
+
+. .
+callback_id: >=0, as returned by a call to [*callback*] or [*callback_ex*].
+. .
+
+The function returns 0 if OK, otherwise pigif_callback_not_found.
+D*/
+
+/*F*/
+int wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout);
+/*D
+This function waits for edge on the gpio for up to timeout
+seconds.
+
+. .
+       pi: 0- (as returned by [*pigpio_start*]).
+user_gpio: 0-31.
+     edge: RISING_EDGE, FALLING_EDGE, or EITHER_EDGE.
+  timeout: >=0.
+. .
+
+The function returns 1 if the edge occurred, otherwise 0.
+
+The function returns when the edge occurs or after the timeout.
+D*/
+
+/*PARAMS
+
+active :: 0-1000000
+
+The number of microseconds level changes are reported for once
+a noise filter has been triggered (by [*steady*] microseconds of
+a stable level).
+
+*addrStr::
+A string specifying the host or IP address of the Pi running
+the pigpio daemon.  It may be NULL in which case localhost
+is used unless overridden by the PIGPIO_ADDR environment
+variable.
+
+arg1::
+An unsigned argument passed to a user customised function.  Its
+meaning is defined by the customiser.
+
+arg2::
+An unsigned argument passed to a user customised function.  Its
+meaning is defined by the customiser.
+
+argc::
+The count of bytes passed to a user customised function.
+
+*argx::
+A pointer to an array of bytes passed to a user customised function.
+Its meaning and content is defined by the customiser.
+
+baud::
+The speed of serial communication (I2C, SPI, serial link, waves) in
+bits per second.
+
+bit::
+A value of 0 or 1.
+
+bits::
+A value used to select gpios.  If bit n of bits is set then gpio n is
+selected.
+
+A convenient way to set bit n is to or in (1<<n).
+
+e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
+
+*buf::
+A buffer to hold data being sent or being received.
+
+bufSize::
+The size in bytes of a buffer.
+
+
+bVal::0-255 (Hex 0x0-0xFF, Octal 0-0377)
+An 8-bit byte value.
+
+callback_id::
+A >=0, as returned by a call to [*callback*] or [*callback_ex*].  This is
+passed to [*callback_cancel*] to cancel the callback.
+
+CBFunc_t::
+. .
+typedef void (*CBFunc_t)
+   (unsigned user_gpio, unsigned level, uint32_t tick);
+. .
+
+CBFuncEx_t::
+. .
+typedef void (*CBFuncEx_t)
+   (unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+. .
+
+char::
+A single character, an 8 bit quantity able to store 0-255.
+
+clkfreq::4689-250000000 (250M)
+The hardware clock frequency.
+
+count::
+The number of bytes to be transferred in an I2C, SPI, or Serial
+command.
+
+data_bits::1-32
+The number of data bits in each character of serial data.
+
+. .
+#define PI_MIN_WAVE_DATABITS 1
+#define PI_MAX_WAVE_DATABITS 32
+. .
+
+double::
+A floating point number.
+
+dutycycle::0-range
+A number representing the ratio of on time to off time for PWM.
+
+The number may vary between 0 and range (default 255) where
+0 is off and range is fully on.
+
+edge::
+Used to identify a gpio level transition of interest.  A rising edge is
+a level change from 0 to 1.  A falling edge is a level change from 1 to 0.
+
+. .
+RISING_EDGE  0
+FALLING_EDGE 1
+EITHER_EDGE. 2
+. .
+
+errnum::
+A negative number indicating a function call failed and the nature
+of the error.
+
+f::
+A function.
+
+frequency::0-
+The number of times a gpio is swiched on and off per second.  This
+can be set per gpio and may be as little as 5Hz or as much as
+40KHz.  The gpio will be on for a proportion of the time as defined
+by its dutycycle.
+
+
+gpio::
+A Broadcom numbered gpio, in the range 0-53.
+
+There  are 54 General Purpose Input Outputs (gpios) named gpio0 through
+gpio53.
+
+They are split into two  banks.   Bank  1  consists  of  gpio0  through
+gpio31.  Bank 2 consists of gpio32 through gpio53.
+
+All the gpios which are safe for the user to read and write are in
+bank 1.  Not all gpios in bank 1 are safe though.  Type 1 boards
+have 17  safe gpios.  Type 2 boards have 21.  Type 3 boards have 26.
+
+See [*get_hardware_revision*].
+
+The user gpios are marked with an X in the following table.
+
+. .
+          0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
+Type 1    X  X  -  -  X  -  -  X  X  X  X  X  -  -  X  X
+Type 2    -  -  X  X  X  -  -  X  X  X  X  X  -  -  X  X
+Type 3          X  X  X  X  X  X  X  X  X  X  X  X  X  X
+
+         16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+Type 1    -  X  X  -  -  X  X  X  X  X  -  -  -  -  -  -
+Type 2    -  X  X  -  -  -  X  X  X  X  -  X  X  X  X  X
+Type 3    X  X  X  X  X  X  X  X  X  X  X  X  -  -  -  -
+. .
+
+gpioPulse_t::
+. .
+typedef struct
+{
+uint32_t gpioOn;
+uint32_t gpioOff;
+uint32_t usDelay;
+} gpioPulse_t;
+. .
+
+gpioThreadFunc_t::
+. .
+typedef void *(gpioThreadFunc_t) (void *);
+. .
+
+handle::0-
+A number referencing an object opened by one of [*i2c_open*], [*notify_open*],
+[*serial_open*], and [*spi_open*].
+
+i2c_addr::
+The address of a device on the I2C bus.
+
+i2c_bus::0-1
+An I2C bus, 0 or 1.
+
+i2c_flags::0
+Flags which modify an I2C open command.  None are currently defined.
+
+i2c_reg:: 0-255
+A register of an I2C device.
+
+*inBuf::
+A buffer used to pass data to a function.
+
+inLen::
+The number of bytes of data in a buffer.
+
+int::
+A whole number, negative or positive.
+
+invert::
+A flag used to set normal or inverted bit bang serial data level logic.
+
+level::
+The level of a gpio.  Low or High.
+
+. .
+PI_OFF 0
+PI_ON 1
+
+PI_CLEAR 0
+PI_SET 1
+
+PI_LOW 0
+PI_HIGH 1
+. .
+
+There is one exception.  If a watchdog expires on a gpio the level will be
+reported as PI_TIMEOUT.  See [*set_watchdog*].
+
+. .
+PI_TIMEOUT 2
+. .
+
+mode::0-7
+The operational mode of a gpio, normally INPUT or OUTPUT.
+
+. .
+PI_INPUT 0
+PI_OUTPUT 1
+PI_ALT0 4
+PI_ALT1 5
+PI_ALT2 6
+PI_ALT3 7
+PI_ALT4 3
+PI_ALT5 2
+. .
+
+numBytes::
+The number of bytes used to store characters in a string.  Depending
+on the number of bits per character there may be 1, 2, or 4 bytes
+per character.
+
+numPar:: 0-10
+The number of parameters passed to a script.
+
+numPulses::
+The number of pulses to be added to a waveform.
+
+offset::
+The associated data starts this number of microseconds from the start of
+the waveform.
+
+*outBuf::
+A buffer used to return data from a function.
+
+outLen::
+The size in bytes of an output buffer.
+
+*param::
+An array of script parameters.
+
+pi::
+An integer defining a connected Pi.  The value is returned by
+[*pigpio_start*] upon success.
+
+*portStr::
+A string specifying the port address used by the Pi running
+the pigpio daemon.  It may be NULL in which case "8888"
+is used unless overridden by the PIGPIO_PORT environment
+variable.
+
+*pth::
+A thread identifier, returned by [*start_thread*].
+
+
+pthread_t::
+A thread identifier.
+
+pud::0-2
+The setting of the pull up/down resistor for a gpio, which may be off,
+pull-up, or pull-down.
+. .
+PI_PUD_OFF 0
+PI_PUD_DOWN 1
+PI_PUD_UP 2
+. .
+
+pulseLen::
+1-100, the length of a trigger pulse in microseconds.
+
+*pulses::
+An array of pulses to be added to a waveform.
+
+pulsewidth::0, 500-2500
+. .
+PI_SERVO_OFF 0
+PI_MIN_SERVO_PULSEWIDTH 500
+PI_MAX_SERVO_PULSEWIDTH 2500
+. .
+
+PWMduty::0-1000000 (1M)
+The hardware PWM dutycycle.
+
+. .
+#define PI_HW_PWM_RANGE 1000000
+. .
+
+PWMfreq::1-125000000 (125M)
+The hardware PWM frequency.
+
+. .
+#define PI_HW_PWM_MIN_FREQ 1
+#define PI_HW_PWM_MAX_FREQ 125000000
+. .
+
+range::25-40000
+The permissible dutycycle values are 0-range.
+. .
+PI_MIN_DUTYCYCLE_RANGE 25
+PI_MAX_DUTYCYCLE_RANGE 40000
+. .
+
+*retBuf::
+A buffer to hold a number of bytes returned to a used customised function,
+
+retMax::
+The maximum number of bytes a user customised function should return.
+
+
+*rxBuf::
+A pointer to a buffer to receive data.
+
+SCL::
+The user gpio to use for the clock when bit banging I2C.
+
+*script::
+A pointer to the text of a script.
+
+script_id::
+An id of a stored script as returned by [*store_script*].
+
+SDA::
+The user gpio to use for data when bit banging I2C.
+
+seconds::
+The number of seconds.
+
+ser_flags::
+Flags which modify a serial open command.  None are currently defined.
+
+*ser_tty::
+The name of a serial tty device, e.g. /dev/ttyAMA0, /dev/ttyUSB0, /dev/tty1.
+
+size_t::
+A standard type used to indicate the size of an object in bytes.
+
+spi_channel::
+A SPI channel, 0-2.
+
+spi_flags::
+See [*spi_open*].
+
+steady :: 0-300000
+
+The number of microseconds level changes must be stable for
+before reporting the level changed ([*set_glitch_filter*]) or triggering
+the active part of a noise filter ([*set_noise_filter*]).
+
+stop_bits::2-8
+The number of (half) stop bits to be used when adding serial data
+to a waveform.
+
+. .
+#define PI_MIN_WAVE_HALFSTOPBITS 2
+#define PI_MAX_WAVE_HALFSTOPBITS 8
+. .
+
+*str::
+ An array of characters.
+
+thread_func::
+A function of type gpioThreadFunc_t used as the main function of a
+thread.
+
+timeout::
+A gpio watchdog timeout in milliseconds.
+. .
+PI_MIN_WDOG_TIMEOUT 0
+PI_MAX_WDOG_TIMEOUT 60000
+. .
+
+*txBuf::
+An array of bytes to transmit.
+
+uint32_t::0-0-4,294,967,295 (Hex 0x0-0xFFFFFFFF)
+A 32-bit unsigned value.
+
+unsigned::
+A whole number >= 0.
+
+user_gpio::
+0-31, a Broadcom numbered gpio.
+
+See [*gpio*].
+
+*userdata::
+
+A pointer to arbitrary user data.  This may be used to identify the instance.
+
+You must ensure that the pointer is in scope at the time it is processed.  If
+it is a pointer to a global this is automatic.  Do not pass the address of a
+local variable.  If you want to pass a transient object then use the
+following technique.
+
+In the calling function:
+
+user_type *userdata; 
+user_type my_userdata;
+
+userdata = malloc(sizeof(user_type)); 
+*userdata = my_userdata;
+
+In the receiving function:
+
+user_type my_userdata = *(user_type*)userdata;
+
+free(userdata);
+
+void::
+Denoting no parameter is required
+
+wave_add_*::
+One of [*wave_add_new*], [*wave_add_generic*], [*wave_add_serial*].
+
+wave_id::
+A number representing a waveform created by [*wave_create*].
+
+wave_send_*::
+One of [*wave_send_once*], [*wave_send_repeat*].
+
+wVal::0-65535 (Hex 0x0-0xFFFF, Octal 0-0177777)
+A 16-bit word value.
+
+PARAMS*/
+
+/*DEF_S pigpiod_if2 Error Codes*/
+
+typedef enum
+{
+   pigif_bad_send           = -2000,
+   pigif_bad_recv           = -2001,
+   pigif_bad_getaddrinfo    = -2002,
+   pigif_bad_connect        = -2003,
+   pigif_bad_socket         = -2004,
+   pigif_bad_noib           = -2005,
+   pigif_duplicate_callback = -2006,
+   pigif_bad_malloc         = -2007,
+   pigif_bad_callback       = -2008,
+   pigif_notify_failed      = -2009,
+   pigif_callback_not_found = -2010,
+   pigif_unconnected_pi     = -2011,
+   pigif_too_many_pis       = -2012,
+} pigifError_t;
+
+/*DEF_E*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/pigs.1 b/pigs.1
index a3706e633ee4017358b02d46a7f77604adfbcb4b..12cad6b36065de295c9460208a8c1f45e2ac9daa 100644 (file)
--- a/pigs.1
+++ b/pigs.1
@@ -2,7 +2,7 @@
 ." Process this file with
 ." groff -man -Tascii foo.1
 ."
-.TH pigs 1 2012-2014 Linux "pigpio archive"
+.TH pigs 1 2012-2015 Linux "pigpio archive"
 .SH NAME
 pigs - command line socket access to the pigpio daemon.
 
@@ -4339,7 +4339,7 @@ the current gpio levels.
 
 .SH SEE ALSO
 
-pigpiod(1), pig2vcd(1), pigpio(3), pigpiod_if(3)
+pigpiod(1), pig2vcd(1), pigpio(3), pigpiod_if(3), pigpiod_if2(3)
 .SH AUTHOR
 
 joan@abyz.co.uk
index a7df3a0ddf1e852a0bf6da6d067ff83bacb3bc14..407cb8db6f6e8136023957d66bc1035ffc19b10f 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name='pigpio',
-      version='1.23',
+      version='1.24',
       author='joan',
       author_email='joan@abyz.co.uk',
       maintainer='joan',
diff --git a/x_pigpiod_if2.c b/x_pigpiod_if2.c
new file mode 100644 (file)
index 0000000..732f772
--- /dev/null
@@ -0,0 +1,884 @@
+/*
+gcc -o x_pigpiod_if2 x_pigpiod_if2.c -lpigpiod_if2 -lpthread
+./x_pigpiod_if2
+
+*** WARNING ************************************************
+*                                                          *
+* All the tests make extensive use of gpio 4 (pin P1-7).   *
+* Ensure that either nothing or just a LED is connected to *
+* gpio 4 before running any of the tests.                  *
+*                                                          *
+* Some tests are statistical in nature and so may on       *
+* occasion fail.  Repeated failures on the same test or    *
+* many failures in a group of tests indicate a problem.    *
+************************************************************
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "pigpiod_if2.h"
+
+#define GPIO 4
+
+void CHECK(int t, int st, int got, int expect, int pc, char *desc)
+{
+   if ((got >= (((1E2-pc)*expect)/1E2)) && (got <= (((1E2+pc)*expect)/1E2)))
+   {
+      printf("TEST %2d.%-2d PASS (%s: %d)\n", t, st, desc, expect);
+   }
+   else
+   {
+      fprintf(stderr,
+              "TEST %2d.%-2d FAILED got %d (%s: %d)\n",
+              t, st, got, desc, expect);
+   }
+}
+
+void t0(int pi)
+{
+   printf("Version.\n");
+
+   printf("pigpio version %d.\n", get_pigpio_version(pi));
+
+   printf("Hardware revision %d.\n", get_hardware_revision(pi));
+}
+
+void t1(int pi)
+{
+   int v;
+
+   printf("Mode/PUD/read/write tests.\n");
+
+   set_mode(pi, GPIO, PI_INPUT);
+   v = get_mode(pi, GPIO);
+   CHECK(1, 1, v, 0, 0, "set mode, get mode");
+
+   set_pull_up_down(pi, GPIO, PI_PUD_UP);
+   v = gpio_read(pi, GPIO);
+   CHECK(1, 2, v, 1, 0, "set pull up down, read");
+
+   set_pull_up_down(pi, GPIO, PI_PUD_DOWN);
+   v = gpio_read(pi, GPIO);
+   CHECK(1, 3, v, 0, 0, "set pull up down, read");
+
+   gpio_write(pi, GPIO, PI_LOW);
+   v = get_mode(pi, GPIO);
+   CHECK(1, 4, v, 1, 0, "write, get mode");
+
+   v = gpio_read(pi, GPIO);
+   CHECK(1, 5, v, 0, 0, "read");
+
+   gpio_write(pi, GPIO, PI_HIGH);
+   v = gpio_read(pi, GPIO);
+   CHECK(1, 6, v, 1, 0, "write, read");
+}
+
+int t2_count=0;
+
+void t2cb(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   t2_count++;
+}
+
+void t2(int pi)
+{
+   int dc, f, r, rr, oc, id;
+
+   printf("PWM dutycycle/range/frequency tests.\n");
+
+   set_PWM_range(pi, GPIO, 255);
+   set_PWM_frequency(pi, GPIO, 0);
+   f = get_PWM_frequency(pi, GPIO);
+   CHECK(2, 1, f, 10, 0, "set PWM range, set/get PWM frequency");
+
+   id = callback(pi, GPIO, EITHER_EDGE, t2cb);
+
+   set_PWM_dutycycle(pi, GPIO, 0);
+   dc = get_PWM_dutycycle(pi, GPIO);
+   CHECK(2, 2, dc, 0, 0, "get PWM dutycycle");
+
+   time_sleep(0.5); /* allow old notifications to flush */
+   oc = t2_count;
+   time_sleep(2);
+   f = t2_count - oc;
+   CHECK(2, 3, f, 0, 0, "set PWM dutycycle, callback");
+
+   set_PWM_dutycycle(pi, GPIO, 128);
+   dc = get_PWM_dutycycle(pi, GPIO);
+   CHECK(2, 4, dc, 128, 0, "get PWM dutycycle");
+
+   oc = t2_count;
+   time_sleep(2);
+   f = t2_count - oc;
+   CHECK(2, 5, f, 40, 5, "set PWM dutycycle, callback");
+
+   set_PWM_frequency(pi, GPIO, 100);
+   f = get_PWM_frequency(pi, GPIO);
+   CHECK(2, 6, f, 100, 0, "set/get PWM frequency");
+
+   oc = t2_count;
+   time_sleep(2);
+   f = t2_count - oc;
+   CHECK(2, 7, f, 400, 1, "callback");
+
+   set_PWM_frequency(pi, GPIO, 1000);
+   f = get_PWM_frequency(pi, GPIO);
+   CHECK(2, 8, f, 1000, 0, "set/get PWM frequency");
+
+   oc = t2_count;
+   time_sleep(2);
+   f = t2_count - oc;
+   CHECK(2, 9, f, 4000, 1, "callback");
+
+   r = get_PWM_range(pi, GPIO);
+   CHECK(2, 10, r, 255, 0, "get PWM range");
+
+   rr = get_PWM_real_range(pi, GPIO);
+   CHECK(2, 11, rr, 200, 0, "get PWM real range");
+
+   set_PWM_range(pi, GPIO, 2000);
+   r = get_PWM_range(pi, GPIO);
+   CHECK(2, 12, r, 2000, 0, "set/get PWM range");
+
+   rr = get_PWM_real_range(pi, GPIO);
+   CHECK(2, 13, rr, 200, 0, "get PWM real range");
+
+   set_PWM_dutycycle(pi, GPIO, 0);
+
+   callback_cancel(id);
+}
+
+int t3_reset=1;
+int t3_count=0;
+uint32_t t3_tick=0;
+float t3_on=0.0;
+float t3_off=0.0;
+
+void t3cbf(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   uint32_t td;
+
+//   printf("pi=%d g=%d l=%d t=%u\n", pi, gpio, level, tick);
+   if (t3_reset)
+   {
+      t3_count = 0;
+      t3_on = 0.0;
+      t3_off = 0.0;
+      t3_reset = 0;
+   }
+   else
+   {
+      td = tick - t3_tick;
+
+      if (level == 0) t3_on += td;
+      else            t3_off += td;
+   }
+
+   t3_count ++;
+   t3_tick = tick;
+}
+
+void t3(int pi)
+{
+   int pw[3]={500, 1500, 2500};
+   int dc[4]={20, 40, 60, 80};
+
+   int f, rr, v;
+   float on, off;
+
+   int t, id;
+
+   printf("PWM/Servo pulse accuracy tests.\n");
+
+   id = callback(pi, GPIO, EITHER_EDGE, t3cbf);
+
+   for (t=0; t<3; t++)
+   {
+      set_servo_pulsewidth(pi, GPIO, pw[t]);
+      v = get_servo_pulsewidth(pi, GPIO);
+      CHECK(3, t+t+1, v, pw[t], 0, "get servo pulsewidth");
+
+      time_sleep(1);
+      t3_reset = 1;
+      time_sleep(4);
+      on = t3_on;
+      off = t3_off;
+      CHECK(3, t+t+2, (1000.0*(on+off))/on, 20000000.0/pw[t], 1,
+         "set servo pulsewidth");
+   }
+
+   set_servo_pulsewidth(pi, GPIO, 0);
+   set_PWM_frequency(pi, GPIO, 1000);
+   f = get_PWM_frequency(pi, GPIO);
+   CHECK(3, 7, f, 1000, 0, "set/get PWM frequency");
+
+   rr = set_PWM_range(pi, GPIO, 100);
+   CHECK(3, 8, rr, 200, 0, "set PWM range");
+
+   for (t=0; t<4; t++)
+   {
+      set_PWM_dutycycle(pi, GPIO, dc[t]);
+      v = get_PWM_dutycycle(pi, GPIO);
+      CHECK(3, t+t+9, v, dc[t], 0, "get PWM dutycycle");
+
+      time_sleep(1);
+      t3_reset = 1;
+      time_sleep(2);
+      on = t3_on;
+      off = t3_off;
+      CHECK(3, t+t+10, (1000.0*on)/(on+off), 10.0*dc[t], 1,
+         "set PWM dutycycle");
+   }
+
+   set_PWM_dutycycle(pi, GPIO, 0);
+
+   callback_cancel(id);
+}
+
+void t4(int pi)
+{
+   int h, e, f, n, s, b, l, seq_ok, toggle_ok;
+   gpioReport_t r;
+   char p[32];
+
+   printf("Pipe notification tests.\n");
+
+   set_PWM_frequency(pi, GPIO, 0);
+   set_PWM_dutycycle(pi, GPIO, 0);
+   set_PWM_range(pi, GPIO, 100);
+
+   h = notify_open(pi);
+   e = notify_begin(pi, h, (1<<4));
+   CHECK(4, 1, e, 0, 0, "notify open/begin");
+
+   time_sleep(1);
+
+   sprintf(p, "/dev/pigpio%d", h);
+
+   f = open(p, O_RDONLY);
+
+   set_PWM_dutycycle(pi, GPIO, 50);
+   time_sleep(4);
+   set_PWM_dutycycle(pi, GPIO, 0);
+
+   e = notify_pause(pi, h);
+   CHECK(4, 2, e, 0, 0, "notify pause");
+
+   e = notify_close(pi, h);
+   CHECK(4, 3, e, 0, 0, "notify close");
+
+   n = 0;
+   s = 0;
+   l = 0;
+   seq_ok = 1;
+   toggle_ok = 1;
+
+   while (1)
+   {
+      b = read(f, &r, 12);
+      if (b == 12)
+      {
+         if (s != r.seqno) seq_ok = 0;
+
+         if (n) if (l != (r.level&(1<<4))) toggle_ok = 0;
+
+         if (r.level&(1<<4)) l = 0;
+         else                l = (1<<4);
+           
+         s++;
+         n++;
+
+         // printf("%d %d %d %X\n", r.seqno, r.flags, r.tick, r.level);
+      }
+      else break;
+   }
+   close(f);
+   CHECK(4, 4, seq_ok, 1, 0, "sequence numbers ok");
+
+   CHECK(4, 5, toggle_ok, 1, 0, "gpio toggled ok");
+
+   CHECK(4, 6, n, 80, 10, "number of notifications");
+}
+
+int t5_count = 0;
+
+void t5cbf(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   t5_count++;
+}
+
+void t5(int pi)
+{
+   int BAUD=4800;
+
+   char *TEXT=
+"\n\
+Now is the winter of our discontent\n\
+Made glorious summer by this sun of York;\n\
+And all the clouds that lour'd upon our house\n\
+In the deep bosom of the ocean buried.\n\
+Now are our brows bound with victorious wreaths;\n\
+Our bruised arms hung up for monuments;\n\
+Our stern alarums changed to merry meetings,\n\
+Our dreadful marches to delightful measures.\n\
+Grim-visaged war hath smooth'd his wrinkled front;\n\
+And now, instead of mounting barded steeds\n\
+To fright the souls of fearful adversaries,\n\
+He capers nimbly in a lady's chamber\n\
+To the lascivious pleasing of a lute.\n\
+";
+
+   gpioPulse_t wf[] =
+   {
+      {1<<GPIO, 0,  10000},
+      {0, 1<<GPIO,  30000},
+      {1<<GPIO, 0,  60000},
+      {0, 1<<GPIO, 100000},
+   };
+
+   int e, oc, c, wid, id;
+
+   char text[2048];
+
+   printf("Waveforms & serial read/write tests.\n");
+
+   id = callback(pi, GPIO, FALLING_EDGE, t5cbf);
+
+   set_mode(pi, GPIO, PI_OUTPUT);
+
+   e = wave_clear(pi);
+   CHECK(5, 1, e, 0, 0, "callback, set mode, wave clear");
+
+   e = wave_add_generic(pi, 4, wf);
+   CHECK(5, 2, e, 4, 0, "pulse, wave add generic");
+
+   wid = wave_create(pi);
+   e = wave_send_repeat(pi, wid);
+   CHECK(5, 3, e, 9, 0, "wave tx repeat");
+
+   oc = t5_count;
+   time_sleep(5.05);
+   c = t5_count - oc;
+   CHECK(5, 4, c, 50, 2, "callback");
+
+   e = wave_tx_stop(pi);
+   CHECK(5, 5, e, 0, 0, "wave tx stop");
+
+   e = bb_serial_read_open(pi, GPIO, BAUD, 8);
+   CHECK(5, 6, e, 0, 0, "serial read open");
+
+   wave_clear(pi);
+   e = wave_add_serial(pi, GPIO, BAUD, 8, 2, 5000000, strlen(TEXT), TEXT);
+   CHECK(5, 7, e, 3405, 0, "wave clear, wave add serial");
+
+   wid = wave_create(pi);
+   e = wave_send_once(pi, wid);
+   CHECK(5, 8, e, 6811, 0, "wave tx start");
+
+   oc = t5_count;
+   time_sleep(3);
+   c = t5_count - oc;
+   CHECK(5, 9, c, 0, 0, "callback");
+
+   oc = t5_count;
+   while (wave_tx_busy(pi)) time_sleep(0.1);
+   time_sleep(0.1);
+   c = t5_count - oc;
+   CHECK(5, 10, c, 1702, 0, "wave tx busy, callback");
+
+   c = bb_serial_read(pi, GPIO, text, sizeof(text)-1);
+   if (c > 0) text[c] = 0; /* null terminate string */
+   CHECK(5, 11, strcmp(TEXT, text), 0, 0, "wave tx busy, serial read");
+
+   e = bb_serial_read_close(pi, GPIO);
+   CHECK(5, 12, e, 0, 0, "serial read close");
+
+   c = wave_get_micros(pi);
+   CHECK(5, 13, c, 6158148, 0, "wave get micros");
+
+   c = wave_get_high_micros(pi);
+   if (c > 6158148) c = 6158148;
+   CHECK(5, 14, c, 6158148, 0, "wave get high micros");
+
+   c = wave_get_max_micros(pi);
+   CHECK(5, 15, c, 1800000000, 0, "wave get max micros");
+
+   c = wave_get_pulses(pi);
+   CHECK(5, 16, c, 3405, 0, "wave get pulses");
+
+   c = wave_get_high_pulses(pi);
+   CHECK(5, 17, c, 3405, 0, "wave get high pulses");
+
+   c = wave_get_max_pulses(pi);
+   CHECK(5, 18, c, 12000, 0, "wave get max pulses");
+
+   c = wave_get_cbs(pi);
+   CHECK(5, 19, c, 6810, 0, "wave get cbs");
+
+   c = wave_get_high_cbs(pi);
+   CHECK(5, 20, c, 6810, 0, "wave get high cbs");
+
+   c = wave_get_max_cbs(pi);
+   CHECK(5, 21, c, 25016, 0, "wave get max cbs");
+
+   callback_cancel(id);
+}
+
+int t6_count=0;
+int t6_on=0;
+uint32_t t6_on_tick=0;
+
+void t6cbf(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   if (level == 1)
+   {
+      t6_on_tick = tick;
+      t6_count++;
+   }
+   else
+   {
+      if (t6_on_tick) t6_on += (tick - t6_on_tick);
+   }
+}
+
+void t6(int pi)
+{
+   int tp, t, p, id;
+
+   printf("Trigger tests.\n");
+
+   gpio_write(pi, GPIO, PI_LOW);
+
+   tp = 0;
+
+   id = callback(pi, GPIO, EITHER_EDGE, t6cbf);
+
+   time_sleep(0.2);
+
+   for (t=0; t<5; t++)
+   {
+      time_sleep(0.1);
+      p = 10 + (t*10);
+      tp += p;
+      gpio_trigger(pi, GPIO, p, 1);
+   }
+
+   time_sleep(0.5);
+
+   CHECK(6, 1, t6_count, 5, 0, "gpio trigger count");
+
+   CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length");
+
+   callback_cancel(id);
+}
+
+int t7_count=0;
+
+void t7cbf(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   if (level == PI_TIMEOUT) t7_count++;
+}
+
+void t7(int pi)
+{
+   int c, oc, id;
+
+   printf("Watchdog tests.\n");
+
+   /* type of edge shouldn't matter for watchdogs */
+   id = callback(pi, GPIO, FALLING_EDGE, t7cbf);
+
+   set_watchdog(pi, GPIO, 10); /* 10 ms, 100 per second */
+   time_sleep(0.5);
+   oc = t7_count;
+   time_sleep(2);
+   c = t7_count - oc;
+   CHECK(7, 1, c, 200, 1, "set watchdog on count");
+
+   set_watchdog(pi, GPIO, 0); /* 0 switches watchdog off */
+   time_sleep(0.5);
+   oc = t7_count;
+   time_sleep(2);
+   c = t7_count - oc;
+   CHECK(7, 2, c, 0, 1, "set watchdog off count");
+
+   callback_cancel(id);
+}
+
+void t8(int pi)
+{
+   int v, t, i;
+
+   printf("Bank read/write tests.\n");
+
+   gpio_write(pi, GPIO, 0);
+   v = read_bank_1(pi) & (1<<GPIO);
+   CHECK(8, 1, v, 0, 0, "read bank 1");
+
+   gpio_write(pi, GPIO, 1);
+   v = read_bank_1(pi) & (1<<GPIO);
+   CHECK(8, 2, v, (1<<GPIO), 0, "read bank 1");
+
+   clear_bank_1(pi, 1<<GPIO);
+   v = gpio_read(pi, GPIO);
+   CHECK(8, 3, v, 0, 0, "clear bank 1");
+
+   set_bank_1(pi, 1<<GPIO);
+   v = gpio_read(pi, GPIO);
+   CHECK(8, 4, v, 1, 0, "set bank 1");
+
+   t = 0;
+   v = (1<<16);
+   for (i=0; i<100; i++)
+   {
+      if (read_bank_2(pi) & v) t++;
+   };
+   CHECK(8, 5, t, 60, 75, "read bank 2");
+
+   v = clear_bank_2(pi, 0);
+   CHECK(8, 6, v, 0, 0, "clear bank 2");
+
+   v = clear_bank_2(pi, 0xffffff);
+   CHECK(8, 7, v, PI_SOME_PERMITTED, 0, "clear bank 2");
+
+   v = set_bank_2(pi, 0);
+   CHECK(8, 8, v, 0, 0, "set bank 2");
+
+   v = set_bank_2(pi, 0xffffff);
+   CHECK(8, 9, v, PI_SOME_PERMITTED, 0, "set bank 2");
+}
+
+int t9_count = 0;
+
+void t9cbf(int pi, unsigned gpio, unsigned level, uint32_t tick)
+{
+   t9_count++;
+}
+
+void t9(int pi)
+{
+   int s, oc, c, e, id;
+   uint32_t p[10];
+
+   printf("Script store/run/status/stop/delete tests.\n");
+
+   gpio_write(pi, GPIO, 0); /* need known state */
+
+   /*
+   100 loops per second
+   p0 number of loops
+   p1 GPIO
+   */
+   char *script="\
+   ld p9 p0\
+   tag 0\
+   w p1 1\
+   mils 5\
+   w p1 0\
+   mils 5\
+   dcr p9\
+   jp 0";
+
+   id = callback(pi, GPIO, RISING_EDGE, t9cbf);
+
+   s = store_script(pi, script);
+
+   /* Wait for script to finish initing. */
+   while (1)
+   {
+      time_sleep(0.1);
+      e = script_status(pi, s, p);
+      if (e != PI_SCRIPT_INITING) break;
+   }
+
+   oc = t9_count;
+   p[0] = 99;
+   p[1] = GPIO;
+   run_script(pi, s, 2, p);
+   time_sleep(2);
+   c = t9_count - oc;
+   CHECK(9, 1, c, 100, 0, "store/run script");
+
+   oc = t9_count;
+   p[0] = 200;
+   p[1] = GPIO;
+   run_script(pi, s, 2, p);
+   while (1)
+   {
+      time_sleep(0.1);
+      e = script_status(pi, s, p);
+      if (e != PI_SCRIPT_RUNNING) break;
+   }
+   c = t9_count - oc;
+   time_sleep(0.1);
+   CHECK(9, 2, c, 201, 0, "run script/script status");
+
+   oc = t9_count;
+   p[0] = 2000;
+   p[1] = GPIO;
+   run_script(pi, s, 2, p);
+   while (1)
+   {
+      time_sleep(0.1);
+      e = script_status(pi, s, p);
+      if (e != PI_SCRIPT_RUNNING) break;
+      if (p[9] < 1600) stop_script(pi, s);
+   }
+   c = t9_count - oc;
+   time_sleep(0.1);
+   CHECK(9, 3, c, 410, 10, "run/stop script/script status");
+
+   e = delete_script(pi, s);
+   CHECK(9, 4, e, 0, 0, "delete script");
+
+   callback_cancel(id);
+}
+
+void ta(int pi)
+{
+   int h, b, e;
+   char *TEXT;
+   char text[2048];
+
+   printf("Serial link tests.\n");
+
+   /* this test needs RXD and TXD to be connected */
+
+   h = serial_open(pi, "/dev/ttyAMA0", 57600, 0);
+
+   CHECK(10, 1, h, 0, 0, "serial open");
+
+   time_sleep(0.1); /* allow time for transmission */
+
+   b = serial_read(pi, h, text, sizeof(text)); /* flush buffer */
+
+   b = serial_data_available(pi, h);
+   CHECK(10, 2, b, 0, 0, "serial data available");
+
+   TEXT = "\
+To be, or not to be, that is the question-\
+Whether 'tis Nobler in the mind to suffer\
+The Slings and Arrows of outrageous Fortune,\
+Or to take Arms against a Sea of troubles,\
+";
+   e = serial_write(pi, h, TEXT, strlen(TEXT));
+   CHECK(10, 3, e, 0, 0, "serial write");
+
+   e = serial_write_byte(pi, h, 0xAA);
+   e = serial_write_byte(pi, h, 0x55);
+   e = serial_write_byte(pi, h, 0x00);
+   e = serial_write_byte(pi, h, 0xFF);
+
+   CHECK(10, 4, e, 0, 0, "serial write byte");
+
+   time_sleep(0.1); /* allow time for transmission */
+
+   b = serial_data_available(pi, h);
+   CHECK(10, 5, b, strlen(TEXT)+4, 0, "serial data available");
+
+   b = serial_read(pi, h, text, strlen(TEXT));
+   CHECK(10, 6, b, strlen(TEXT), 0, "serial read");
+   if (b >= 0) text[b] = 0;
+   CHECK(10, 7, strcmp(TEXT, text), 0, 0, "serial read");
+
+   b = serial_read_byte(pi, h);
+   CHECK(10, 8, b, 0xAA, 0, "serial read byte");
+
+   b = serial_read_byte(pi, h);
+   CHECK(10, 9, b, 0x55, 0, "serial read byte");
+
+   b = serial_read_byte(pi, h);
+   CHECK(10, 10, b, 0x00, 0, "serial read byte");
+
+   b = serial_read_byte(pi, h);
+   CHECK(10, 11, b, 0xFF, 0, "serial read byte");
+
+   b = serial_data_available(pi, h);
+   CHECK(10, 12, b, 0, 0, "serial data availabe");
+
+   e = serial_close(pi, h);
+   CHECK(10, 13, e, 0, 0, "serial close");
+}
+
+void tb(int pi)
+{
+   int h, e, b, len;
+   char *exp;
+   char buf[128];
+
+   printf("SMBus / I2C tests.");
+
+   /* this test requires an ADXL345 on I2C bus 1 addr 0x53 */
+
+   h = i2c_open(pi, 1, 0x53, 0);
+   CHECK(11, 1, h, 0, 0, "i2c open");
+
+   e = i2c_write_device(pi, h, "\x00", 1); /* move to known register */
+   CHECK(11, 2, e, 0, 0, "i2c write device");
+
+   b = i2c_read_device(pi, h, buf, 1);
+   CHECK(11, 3, b, 1, 0, "i2c read device");
+   CHECK(11, 4, buf[0], 0xE5, 0, "i2c read device");
+
+   b = i2c_read_byte(pi, h);
+   CHECK(11, 5, b, 0xE5, 0, "i2c read byte");
+
+   b = i2c_read_byte_data(pi, h, 0);
+   CHECK(11, 6, b, 0xE5, 0, "i2c read byte data");
+
+   b = i2c_read_byte_data(pi, h, 48);
+   CHECK(11, 7, b, 2, 0, "i2c read byte data");
+
+   exp = "\x1D[aBcDeFgHjKM]";
+   len = strlen(exp);
+
+   e = i2c_write_device(pi, h, exp, len);
+   CHECK(11, 8, e, 0, 0, "i2c write device");
+
+   e = i2c_write_device(pi, h, "\x1D", 1);
+   b = i2c_read_device(pi, h, buf, len-1);
+   CHECK(11, 9, b, len-1, 0, "i2c read device");
+   CHECK(11, 10, strncmp(buf, exp+1, len-1), 0, 0, "i2c read device");
+
+   if (strncmp(buf, exp+1, len-1))
+      printf("got [%.*s] expected [%.*s]\n", len-1, buf, len-1, exp+1);
+
+   e = i2c_write_byte_data(pi, h, 0x1d, 0xAA);
+   CHECK(11, 11, e, 0, 0, "i2c write byte data");
+
+   b = i2c_read_byte_data(pi, h, 0x1d);
+   CHECK(11, 12, b, 0xAA, 0, "i2c read byte data");
+
+   e = i2c_write_byte_data(pi, h, 0x1d, 0x55);
+   CHECK(11, 13, e, 0, 0, "i2c write byte data");
+
+   b = i2c_read_byte_data(pi, h, 0x1d);
+   CHECK(11, 14, b, 0x55, 0, "i2c read byte data");
+
+   exp = "[1234567890#]";
+   len = strlen(exp);
+
+   e = i2c_write_block_data(pi, h, 0x1C, exp, len);
+   CHECK(11, 15, e, 0, 0, "i2c write block data");
+
+   e = i2c_write_device(pi, h, "\x1D", 1);
+   b = i2c_read_device(pi, h, buf, len);
+   CHECK(11, 16, b, len, 0, "i2c read device");
+   CHECK(11, 17, strncmp(buf, exp, len), 0, 0, "i2c read device");
+
+   if (strncmp(buf, exp, len))
+      printf("got [%.*s] expected [%.*s]\n", len, buf, len, exp);
+
+   b = i2c_read_i2c_block_data(pi, h, 0x1D, buf, len);
+   CHECK(11, 18, b, len, 0, "i2c read i2c block data");
+   CHECK(11, 19, strncmp(buf, exp, len), 0, 0, "i2c read i2c block data");
+
+   if (strncmp(buf, exp, len))
+      printf("got [%.*s] expected [%.*s]\n", len, buf, len, exp);
+
+   exp = "(-+=;:,<>!%)";
+   len = strlen(exp);
+
+   e = i2c_write_i2c_block_data(pi, h, 0x1D, exp, len);
+   CHECK(11, 20, e, 0, 0, "i2c write i2c block data");
+
+   b = i2c_read_i2c_block_data(pi, h, 0x1D, buf, len);
+   CHECK(11, 21, b, len, 0, "i2c read i2c block data");
+   CHECK(11, 22, strncmp(buf, exp, len), 0, 0, "i2c read i2c block data");
+
+   if (strncmp(buf, exp, len))
+      printf("got [%.*s] expected [%.*s]\n", len, buf, len, exp);
+
+   e = i2c_close(pi, h);
+   CHECK(11, 23, e, 0, 0, "i2c close");
+}
+
+void tc(int pi)
+{
+   int h, x, b, e;
+   char buf[128];
+
+   printf("SPI tests.");
+
+   /* this test requires a MCP3202 on SPI channel 1 */
+
+   h = spi_open(pi, 1, 50000, 0);
+   CHECK(12, 1, h, 0, 0, "spi open");
+
+
+   for (x=0; x<5; x++)
+   {
+      sprintf(buf, "\x01\x80");
+      b = spi_xfer(pi, h, buf, buf, 3);
+      CHECK(12, 2, b, 3, 0, "spi xfer");
+      if (b == 3)
+      {
+         time_sleep(1.0);
+         printf("%d ", ((buf[1]&0x0F)*256)|buf[2]);
+      }
+   }
+
+   e = spi_close(pi, h);
+   CHECK(12, 99, e, 0, 0, "spi close");
+}
+
+
+int main(int argc, char *argv[])
+{
+   int i, t, c, pi;
+
+   char test[64];
+
+   if (argc > 1)
+   {
+      t = 0;
+
+      for (i=0; i<strlen(argv[1]); i++)
+      {
+         c = tolower(argv[1][i]);
+
+         if (!strchr(test, c))
+         {
+            test[t++] = c;
+            test[t] = 0;
+         }
+      }
+   }
+   else strcat(test, "0123456789");
+
+   pi = pigpio_start(0, 0);
+
+   if (pi < 0)
+   {
+      fprintf(stderr, "pigpio initialisation failed (%d).\n", pi);
+      return 1;
+   }
+
+   printf("Connected to pigpio daemon (%d).\n", pi);
+
+   if (strchr(test, '0')) t0(pi);
+   if (strchr(test, '1')) t1(pi);
+   if (strchr(test, '2')) t2(pi);
+   if (strchr(test, '3')) t3(pi);
+   if (strchr(test, '4')) t4(pi);
+   if (strchr(test, '5')) t5(pi);
+   if (strchr(test, '6')) t6(pi);
+   if (strchr(test, '7')) t7(pi);
+   if (strchr(test, '8')) t8(pi);
+   if (strchr(test, '9')) t9(pi);
+   if (strchr(test, 'a')) ta(pi);
+   if (strchr(test, 'b')) tb(pi);
+   if (strchr(test, 'c')) tc(pi);
+
+   pigpio_stop(pi);
+
+   return 0;
+}
+