diff --git a/MakeRemote b/MakeRemote
new file mode 100644
index 0000000..e0f6361
--- /dev/null
+++ b/MakeRemote
@@ -0,0 +1,47 @@
+CC = gcc
+AR = ar
+RANLIB = ranlib
+SIZE = size
+
+CFLAGS = -O3 -Wall
+
+ALL = libpigpiod_if.a pigs
+
+all: $(ALL)
+
+pigs: command.o
+ $(CC) -o pigs pigs.c command.c
+
+clean:
+ rm -f *.o *.i *.s *~ $(ALL)
+
+install: $(LIB)
+ sudo install -m 0755 -d /usr/local/include
+ sudo install -m 0644 pigpio.h /usr/local/include
+ sudo install -m 0644 pigpiod_if.h /usr/local/include
+ sudo install -m 0755 -d /usr/local/lib
+ sudo install -m 0644 libpigpiod_if.a /usr/local/lib
+ sudo install -m 0755 -d /usr/local/bin
+ sudo install -m 0755 pigs /usr/local/bin
+ sudo python setup.py install
+
+uninstall:
+ sudo rm -f /usr/local/include/pigpio.h
+ sudo rm -f /usr/local/lib/libpigpiod_if.a
+ sudo rm -f /usr/local/bin/pigs
+
+LIB = libpigpiod_if.a
+OBJ = pigpiod_if.o command.o
+
+$(LIB): $(OBJ)
+ $(AR) rcs $(LIB) $(OBJ)
+ $(RANLIB) $(LIB)
+ $(SIZE) $(LIB)
+
+# generated using gcc -MM *.c
+
+command.o: command.c pigpio.h command.h
+pigpiod.o: pigpiod.c pigpio.h command.h
+pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h
+pigs.o: pigs.c pigpio.h command.h
+
diff --git a/Makefile b/Makefile
index 8684ac6..6ce0b3d 100644
--- a/Makefile
+++ b/Makefile
@@ -5,61 +5,74 @@ SIZE = size
CFLAGS = -O3 -Wall
-ALL = libpigpio.a checklib demolib pig2vcd pigpiod pigs
+LIB1 = libpigpio.a
+OBJ1 = pigpio.o command.o
+
+LIB2 = libpigpiod_if.a
+OBJ2 = pigpiod_if.o command.o
+
+LIB = $(LIB1) $(LIB2)
+
+ALL = $(LIB) checklib pig2vcd pigpiod pigs
+
+LL = -L. -lpigpio -lpthread -lrt
all: $(ALL)
-checklib: checklib.o libpigpio.a
- $(CC) -o checklib checklib.c -L. -lpigpio -lpthread -lrt
+checklib: checklib.o $(LIB1)
+ $(CC) -o checklib checklib.c $(LL)
-demolib: demolib.o libpigpio.a
- $(CC) -o demolib demolib.c -L. -lpigpio -lpthread -lrt
+pigpiod: pigpiod.o $(LIB1)
+ $(CC) -o pigpiod pigpiod.c $(LL)
+
+pigs: pigs.o command.o
+ $(CC) -o pigs pigs.c command.c
pig2vcd: pig2vcd.o
$(CC) -o pig2vcd pig2vcd.c
-pigpiod: pigpiod.o libpigpio.a
- $(CC) -o pigpiod pigpiod.c -L. -lpigpio -lpthread -lrt
-
-pigs: command.o
- $(CC) -o pigs pigs.c command.c
-
clean:
rm -f *.o *.i *.s *~ $(ALL)
install: $(LIB)
- sudo install -m 0755 -d /usr/local/include
- sudo install -m 0644 pigpio.h /usr/local/include
- sudo install -m 0755 -d /usr/local/lib
- sudo install -m 0644 libpigpio.a /usr/local/lib
- sudo install -m 0755 -d /usr/local/bin
- sudo install -m 0755 pig2vcd /usr/local/bin
- sudo install -m 0755 pigpiod /usr/local/bin
- sudo install -m 0755 pigs /usr/local/bin
+ sudo install -m 0755 -d /usr/local/include
+ sudo install -m 0644 pigpio.h /usr/local/include
+ sudo install -m 0644 pigpiod_if.h /usr/local/include
+ sudo install -m 0755 -d /usr/local/lib
+ sudo install -m 0644 libpigpio.a /usr/local/lib
+ sudo install -m 0644 libpigpiod_if.a /usr/local/lib
+ sudo install -m 0755 -d /usr/local/bin
+ sudo install -m 0755 pig2vcd /usr/local/bin
+ sudo install -m 0755 pigpiod /usr/local/bin
+ sudo install -m 0755 pigs /usr/local/bin
sudo python setup.py install
uninstall:
sudo rm -f /usr/local/include/pigpio.h
+ sudo rm -f /usr/local/include/pigpiod_if.h
sudo rm -f /usr/local/lib/libpigpio.a
+ sudo rm -f /usr/local/lib/libpigpiod_if.a
sudo rm -f /usr/local/bin/pig2vcd
sudo rm -f /usr/local/bin/pigpiod
sudo rm -f /usr/local/bin/pigs
-LIB = libpigpio.a
-OBJ = pigpio.o command.o
+$(LIB1): $(OBJ1)
+ $(AR) rcs $(LIB1) $(OBJ1)
+ $(RANLIB) $(LIB1)
+ $(SIZE) $(LIB1)
-$(LIB): $(OBJ)
- $(AR) rcs $(LIB) $(OBJ)
- $(RANLIB) $(LIB)
- $(SIZE) $(LIB)
+$(LIB2): $(OBJ2)
+ $(AR) rcs $(LIB2) $(OBJ2)
+ $(RANLIB) $(LIB2)
+ $(SIZE) $(LIB2)
-# generated using gcc -M *.c
+# generated using gcc -MM *.c
checklib.o: checklib.c pigpio.h
command.o: command.c pigpio.h command.h
-demolib.o: demolib.c pigpio.h
pig2vcd.o: pig2vcd.c pigpio.h
pigpio.o: pigpio.c pigpio.h command.h
pigpiod.o: pigpiod.c pigpio.h command.h
+pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h
pigs.o: pigs.c pigpio.h command.h
diff --git a/README b/README
index 86e7ba0..ba15cb6 100644
--- a/README
+++ b/README
@@ -9,13 +9,16 @@ Enter the following two commands (in this order)
make
make install
-This will install:
- the library (libpigpio.a) in /usr/local/lib
- the header file (pigpio.h) in /usr/local/include
- the daemon (pigpiod) in /usr/local/bin
- the socket interface (pigs) in /usr/local/bin
- the utility pig2vcd in /usr/local/bin
- the Python module pigpio.py
+This will install
+
+o the library (libpigpio.a) in /usr/local/lib
+o the library (libpigpiod_if.a) 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 daemon (pigpiod) in /usr/local/bin
+o the socket interface (pigs) in /usr/local/bin
+o the utility pig2vcd in /usr/local/bin
+o the Python module pigpio.py
TEST
@@ -23,8 +26,13 @@ To test the library do
sudo ./checklib
-checklib.c, demolib.c, pig2vcd.c, pigpiod.c, pigs.c, and pigpio.py
-show examples of interfacing with the library.
+EXAMPLE CODE
+
+checklib.c, pig2vcd.c, and pigpiod.c
+show examples of interfacing with the pigpio library.
+
+pigs.c, pigpio.py, and test_pigpiod_if.c
+show examples of interfacing with the pigpiod daemon.
DAEMON
@@ -39,7 +47,7 @@ When the library starts it locks
/var/run/pigpio.pid
-The file should be deleted when the library terminates.
+The file should be automatically deleted when the library terminates.
SOCKET INTERFACE
@@ -62,16 +70,16 @@ echo "help" >/dev/pigpio
PYTHON MODULE
-By default the Python pigpio module is installed to the
-default python location. You can install it for additional
-Python versions by
+The Python pigpio module is installed to the default python location.
+
+You can install it for additional Python versions by
pythonx.y setup.py install
where x.y is the Python version.
-If the pigpiod daemon is running you can test the Python
-module by entering the following commands.
+If the pigpiod daemon is running you can test the Python module
+by entering the following commands.
python
@@ -95,3 +103,37 @@ To stop the pigpiod daemon
sudo killall pigpiod
+RUNNING ON NON Pi's
+
+You can access the pigpiod daemon running on the Pi from any machine which
+can access it over the network. This access is via the socket interface.
+
+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)
+
+On a Linux machine
+
+make -f MakeRemote clean
+make -f MakeRemote
+make -f MakeRemote install
+
+This will install
+
+o the library (libpigpiod_if.a) 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 socket interface (pigs) in /usr/local/bin
+o the Python module pigpio.py
+
+On Windows machines (and possibly Macs)
+
+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.
+
diff --git a/command.c b/command.c
index c3eba85..80b3801 100644
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 7+
+This version is for pigpio version 10+
*/
#include
@@ -74,6 +74,7 @@ cmdInfo_t cmdInfo[]=
{PI_CMD_TICK, "T", 1, 4},
{PI_CMD_HELP, "HELP", 6, 5},
{PI_CMD_HELP, "H", 6, 5},
+ {PI_CMD_PIGPV, "PIGPV", 1, 4},
};
char * cmdUsage = "\
@@ -93,6 +94,7 @@ NC h close notification\n\
PWM/P u d set PWM value for gpio\n\
PFS u d set PWM frequency for gpio\n\
PFG u get PWM frequency for gpio\n\
+PIGPV return pigpio version\n\
PRS u d set PWM range for gpio\n\
PRG u get PWM range for gpio\n\
PRRG u get PWM real range for gpio\n\
@@ -159,6 +161,8 @@ static errInfo_t errInfo[]=
{PI_TOO_MANY_PULSES , "waveform has too many pulses"},
{PI_TOO_MANY_CHARS , "waveform has too many chars"},
{PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"},
+ {PI_BAD_SERIAL_STRUC , "bad (null) serial structure parameter"},
+ {PI_BAD_SERIAL_BUF , "bad (null) serial buf parameter"},
{PI_NOT_PERMITTED , "no permission to update gpio"},
{PI_SOME_PERMITTED , "no permission to update one or more gpios"},
};
@@ -200,7 +204,7 @@ int cmdParse(char * buf, cmdCmd_t * cmd)
switch (cmdInfo[idx].vt)
{
- case 1: /* BR1 BR2 HWVER NO TICK */
+ case 1: /* BR1 BR2 HWVER PIGPV NO TICK */
f = sscanf(buf, " %7s %c", str, &t);
if (f == 1) valid = 1;
break;
diff --git a/demolib.c b/demolib.c
deleted file mode 100644
index d2e9bd4..0000000
--- a/demolib.c
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
-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
-*/
-
-/*
-This version is for pigpio version 3+
-*/
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "pigpio.h"
-
-/* ===========================================================================
-THIS PROGRAM NEEDS THE I2C DEVICE AND DEVELOPMENT LIBRARY
-
-TO GET THE NEEDED FILES DO
-
-sudo apt-get install libi2c-dev
-
-BEFORE RUNNING THE PROGRAM ENSURE THAT THE I2C DEVICE IS PRESENT
-
-sudo modprobe i2c-bcm2708
-sudo modprobe i2c-dev
-sudo chmod o+rw /dev/i2c*
-=========================================================================== */
-
-/*
-
-P1 Name gpio used for
-
- 3 SDA 0/2 i2c
- 5 SCL 1/3 i2c
- 7 --- 4 LASER
- 8 TXD 14 LED1
-10 RXD 15 LED2
-11 --- 17 SERVO 1
-12 --- 18 SERVO 2
-13 --- 21/27 SERVO 3
-15 --- 22 LED3
-16 --- 23 TI Launchpad
-18 --- 24 Sonar trigger
-19 MOSI 10 Sonar echo
-21 MISO 9 Motor B In 1
-22 --- 25 LDR
-23 SCLK 11 Motor B In 2
-24 CE0 8 Motor A In1
-26 CE1 7 Motor A In2
-
-*/
-
-#define LASER 4
-#define MOTOR_A_IN2 7
-#define MOTOR_A_IN1 8
-#define MOTOR_B_IN1 9
-#define SONAR_ECHO 10
-#define MOTOR_B_IN2 11
-#define LED1 14
-#define LED2 15
-#define SERVO1 17
-#define SERVO2 18
-#define SERVO3 21
-#define LED3 22
-#define LAUNCHPAD 23
-#define SONAR_TRIGGER 24
-#define LDR 25
-
-#define LEDS 4
-
-short rawAcc[3];
-short rawGyr[3];
-short rawMag[3];
-
-#define ROLL 0
-#define PITCH 1
-#define YAW 2
-
-#define ACC_ORIENTATION(X, Y, Z) \
- {rawAcc[ROLL] = -X; rawAcc[PITCH] = -Y; rawAcc[YAW] = Z;}
-
-#define GYRO_ORIENTATION(X, Y, Z) \
- {rawGyr[ROLL] = Y; rawGyr[PITCH] = -X; rawGyr[YAW] = -Z;}
-
-#define MAG_ORIENTATION(X, Y, Z) \
- {rawMag[ROLL] = X; rawMag[PITCH] = Y; rawMag[YAW] = -Z;}
-
-
-#define CALIBRATIONS 200
-
-#define ADXL345_I2C_ADDR 0x53
-#define ITG3200_I2C_ADDR 0x68
-
-static int version, micros=5, millis=100;
-
-static volatile unsigned long launchpadPulses;
-static volatile unsigned long launchpad5;
-static volatile unsigned long launchpad10;
-static volatile unsigned long launchpad15;
-static volatile unsigned long launchpadOutRange;
-static volatile int launchpadErr;
-static volatile uint32_t LDRrechargeTick;
-
-
-/* forward prototypes */
-
-void LEDlaserTick (void);
-void motorTick(void);
-void i2cTick (void);
-void servoTick (void);
-void sonarLDRtick(void);
-
-void launchpadAlert(int gpio, int level, uint32_t tick);
-void sonarAlert(int gpio, int level, uint32_t tick);
-void LDRalert(int gpio, int level, uint32_t tick);
-
-void putTTY(char * buf);
-void putTTYstr(int row, int col, char * buf);
-
-
-int main(int argc, char *argv[])
-{
- char str[256];
-
- if (argc > 1) micros = atoi(argv[1]);
-
- if (argc > 2) millis = atoi(argv[2]);
-
- putTTY("\033c"); /* clear console */
-
- gpioCfgBufferSize(millis);
-
- gpioCfgClock(micros, PI_CLOCK_PCM, PI_CLOCK_PLLD);
-
-
- /* before using the library you must call gpioInitialise */
-
- version = gpioInitialise();
-
- if (version >= 0)
- {
- /* initialise pins, only gpio numbers are supported */
-
- gpioSetMode(SERVO1, PI_OUTPUT);
- gpioSetMode(SERVO2, PI_OUTPUT);
- gpioSetMode(SERVO3, PI_OUTPUT);
- gpioSetMode(LASER, PI_OUTPUT);
- gpioSetMode(LED1, PI_OUTPUT);
- gpioSetMode(LED2, PI_OUTPUT);
- gpioSetMode(LED3, PI_OUTPUT);
- gpioSetMode(MOTOR_A_IN1, PI_OUTPUT);
- gpioSetMode(MOTOR_A_IN2, PI_OUTPUT);
- gpioSetMode(MOTOR_B_IN1, PI_OUTPUT);
- gpioSetMode(MOTOR_B_IN2, PI_OUTPUT);
-
- gpioSetMode(SONAR_TRIGGER, PI_OUTPUT);
- gpioWrite (SONAR_TRIGGER, PI_OFF);
-
- gpioSetMode(SONAR_ECHO, PI_INPUT);
- gpioSetMode(LAUNCHPAD, PI_INPUT);
- gpioSetMode(LDR, PI_INPUT);
-
- /* update i2c fifty times a second, timer #0 */
-
- gpioSetTimerFunc(0, 20, i2cTick);
-
- //gpioSetTimerFunc(0, 1000, servoTick);
-
- /* update LEDs and laser once a second, timer #1 */
-
- gpioSetTimerFunc(1, 1000, LEDlaserTick);
-
- /* update motors every three seconds, timer #2 */
-
- gpioSetTimerFunc(2, 3000, motorTick);
-
- /* update sonar/LDR 10 times a second, timer #3 */
-
- gpioSetTimerFunc(3, 100, sonarLDRtick);
-
- /* an attachecd TI launchpad is transmitting high pulses of
- 15, 35, 55, 75, ..., 975, 995 microseconds repeating with 50
- microseconds off between each pulse */
-
- gpioSetAlertFunc(LAUNCHPAD, launchpadAlert);
-
- /* monitor sonar echos */
-
- gpioSetAlertFunc(SONAR_ECHO, sonarAlert);
-
- /* monitor LDR level changes */
-
- gpioSetAlertFunc(LDR, LDRalert);
-
- while (1)
- {
- sleep(1);
-
- sprintf(str, "TI pulses %8ld", launchpadPulses);
- putTTYstr(9, 1, str);
-
- sprintf(str, "+/-5 %8ld", launchpad5);
- putTTYstr(10, 6, str);
-
- sprintf(str, "+/-10 %8ld", launchpad10);
- putTTYstr(11, 5, str);
-
- sprintf(str, "+/-15 %8ld", launchpad15);
- putTTYstr(12, 5, str);
-
- sprintf(str, "Others %8ld (last %d) ",
- launchpadOutRange, launchpadErr);
- putTTYstr(13, 4, str);
- }
- }
-
- gpioTerminate();
-
- return 0;
-}
-
-void LEDlaserTick(void)
-{
- static int gpio[LEDS]={LED1, LED2, LED3, LASER};
- static int pos [LEDS]={ 0, 3, 6, 9};
- static int inc [LEDS]={ 1, 1, 1, 1};
-
- static int vals[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 249};
-
- int i;
-
- for (i=0; i=(sizeof(vals)/4)) || (pos[i]<0) )
- {
- inc[i] = -inc[i];
- pos[i] += inc[i];
- }
- }
-}
-
-void sonarLDRtick(void)
-{
- /* trigger a sonar reading */
-
- gpioWrite(SONAR_TRIGGER, PI_ON);
- usleep(20);
- gpioWrite(SONAR_TRIGGER, PI_OFF);
-
- /* trigger a LDR reading */
-
- gpioSetMode(LDR, PI_OUTPUT); /* drain capacitor */
-
- gpioWrite(LDR, PI_OFF);
-
- usleep(200);
-
- LDRrechargeTick = gpioTick();
-
- gpioSetMode(LDR, PI_INPUT); /* start capacitor recharge */
- }
-
-void motorTick(void)
-{
- static int gpio_in1[2]={MOTOR_A_IN1, MOTOR_B_IN1};
- static int gpio_in2[2]={MOTOR_A_IN2, MOTOR_B_IN2};
- static int speed [2]={ 80, 80};
- static int inc [2]={ -50, 50};
-
- int i;
- char str[256];
-
- for (i=0; i<2; i++)
- {
- speed[i]+=inc[i];
-
- if (speed[i]<0)
- {
- gpioPWM(gpio_in1[i], -speed[i]);
- gpioPWM(gpio_in2[i], 0);
- if (speed[i] < -205) inc[i] = -inc[i];
- sprintf(str, "MOT%d IN1=%3d IN2=%3d", i+1, -speed[i], 0);
- }
- else
- {
- gpioPWM(gpio_in2[i], speed[i]);
- gpioPWM(gpio_in1[i], 0);
- if (speed[i] > 205) inc[i] = -inc[i];
- sprintf(str, "MOT%d IN1=%3d IN2=%3d", i+1, 0, speed[i]);
- }
- if (i) putTTYstr(7, 1, str); else putTTYstr(5, 1, str);
- }
-}
-
-/* loads of code to read/write i2c */
-
-void selectDevice(int i2c, int addr, char * name)
-{
- if (ioctl(i2c, I2C_SLAVE, addr) < 0)
- {
- fprintf(stderr, "%s not present\n", name);
- }
-}
-
-void writeToDevice(int i2c, char * buf, int len)
-{
- static int reported = 0;
- if (write(i2c, buf, len) != len)
- {
- if (!reported)
- {
- fprintf(stderr, "Can't write to device\n");
- reported = 1;
- }
- }
- else reported = 0;
-}
-
-void readADXL345(int i2c)
-{
- char buf[8];
- static int reported = 0;
-
- selectDevice(i2c, ADXL345_I2C_ADDR, "ADXL345");
-
- writeToDevice(i2c, "\x32", 1);
-
- if (read(i2c, buf, 6) != 6)
- {
- if (!reported)
- {
- fprintf(stderr, "Unable to read from ADXL345\n");
- reported = 1;
- }
- }
- else
- {
- reported = 0;
-
- ACC_ORIENTATION (
- ((buf[1]<<8) | buf[0]),
- ((buf[3]<<8) | buf[2]),
- ((buf[5]<<8) | buf[4]) );
- }
-}
-
-void readITG3200(int i2c)
-{
- char buf[8];
- static int reported = 0;
-
- selectDevice(i2c, ITG3200_I2C_ADDR, "ITG3200");
-
- writeToDevice(i2c, "\x1D", 1);
-
- if (read(i2c, buf, 6) != 6)
- {
- if (!reported)
- {
- fprintf(stderr, "Unable to read from ITG3200\n");
- reported = 1;
- }
- }
- else
- {
- reported = 0;
-
- GYRO_ORIENTATION (
- ((buf[0]<<8) | buf[1]),
- ((buf[2]<<8) | buf[3]),
- ((buf[4]<<8) | buf[5]) );
- }
-}
-
-int initI2Cdevices(void)
-{
- int i2c;
-
- if ((i2c = open("/dev/i2c-0", O_RDWR)) < 0)
- {
- perror("Failed to open i2c bus");
- exit(1);
- }
-
- /* initialise ADXL345 */
-
- selectDevice(i2c, ADXL345_I2C_ADDR, "ADXL345");
-
- writeToDevice(i2c, "\x2d\x00", 2);
- writeToDevice(i2c, "\x2d\x10", 2);
- writeToDevice(i2c, "\x2d\x08", 2);
- writeToDevice(i2c, "\x31\x00", 2);
- writeToDevice(i2c, "\x31\x0b", 2);
-
- /* initialise ITG3200 */
-
- selectDevice(i2c, ITG3200_I2C_ADDR, "ITG3200");
-
- writeToDevice(i2c, "\x16\b00011000", 2);
-
- return i2c;
-}
-
-/* an attached IMU (GY-85) supplies orientation information which
- is used to position the servos */
-
-float estimateAngle(int acc, int gyro, float oldAng, int elapsed)
-{
- float angleAcc, angleInc, estAngle;
- float secs;
-
- secs = (float) elapsed / 1e6f;
-
- angleAcc = (float) acc * 90.0f / 256.0f;
-
- angleInc = (float) gyro * secs * 2000.0f / 32768.0f;
-
- estAngle = 0.75 * (oldAng + angleInc) + 0.25 * angleAcc;
-
- return estAngle;
-}
-
-void servoTick(void)
-{
- static int wid1=1500, wid2=1500, wid3=1500;
- static int inc1=50, inc2=75, inc3=100;
-
- gpioServo(SERVO1, wid1);
- gpioServo(SERVO2, wid2);
- gpioServo(SERVO3, wid3);
-
- wid1+=inc1; if ((wid1<1000) || (wid1>2000)) {inc1 = -inc1; wid1+=inc1;}
- wid2+=inc2; if ((wid2<1000) || (wid2>2000)) {inc2 = -inc2; wid2+=inc2;}
- wid3+=inc3; if ((wid3<1000) || (wid3>2000)) {inc3 = -inc3; wid3+=inc3;}
-}
-
-void i2cTick(void)
-{
- static int inited = 0;
- static int calibrated = 0;
- static int calibrations = 0;
- static int accCalibX = 0, accCalibY = 0, accCalibZ = 0;
- static int gyroCalibX = 0, gyroCalibY = 0, gyroCalibZ = 0;
- static int i2c;
- static float X=0.0, Y=0.0, Z=0.0;
-
- static uint32_t lastTick;
-
- uint32_t tick;
- int elapsed;
- int pulse;
- char str[256];
-
- if (inited)
- {
- tick = gpioTick();
- elapsed = tick - lastTick;
- lastTick = tick;
-
- readADXL345(i2c);
- readITG3200(i2c);
-
- if (calibrated)
- {
- X = estimateAngle(
- rawAcc[ROLL], rawGyr[ROLL] -gyroCalibX, X, elapsed);
-
- Y = estimateAngle(
- rawAcc[PITCH], rawGyr[PITCH] - gyroCalibY, Y, elapsed);
-
- Z = estimateAngle(
- rawAcc[YAW], rawGyr[YAW] - gyroCalibZ, Z, elapsed);
-
- pulse = 1500 + (Y * 1000 / 90);
- if (pulse < 500) pulse = 500;
- if (pulse > 2500) pulse = 2500;
- gpioServo(SERVO1, pulse);
-
- pulse = 1500 - (X * 500 / 90);
- if (pulse < 1000) pulse = 1000;
- if (pulse > 2000) pulse = 2000;
- gpioServo(SERVO2, pulse);
-
- /* prefer Z but that doesn't change much */
- pulse = 1500 - (Y * 500 / 90);
- if (pulse < 800) pulse = 800;
- if (pulse > 2200) pulse = 2200;
- gpioServo(SERVO3, pulse);
-
- sprintf(str, "X=%4.0f Y=%4.0f Z=%4.0f ", X, Y, Z);
- putTTYstr(1, 1, str);
- }
- else
- {
- accCalibX+=rawAcc[ROLL];
- accCalibY+=rawAcc[PITCH];
- accCalibZ+=rawAcc[YAW];
-
- gyroCalibX+=rawGyr[ROLL];
- gyroCalibY+=rawGyr[PITCH];
- gyroCalibZ+=rawGyr[YAW];
-
- if (++calibrations >= CALIBRATIONS)
- {
- accCalibX /= CALIBRATIONS;
- accCalibY /= CALIBRATIONS;
- accCalibZ /= CALIBRATIONS;
-
- gyroCalibX /= CALIBRATIONS;
- gyroCalibY /= CALIBRATIONS;
- gyroCalibZ /= CALIBRATIONS;
-
- calibrated = 1;
- }
- }
- }
- else
- {
- i2c = initI2Cdevices();
-
- gpioServo(SERVO1, 1500);
- gpioServo(SERVO2, 1500);
- gpioServo(SERVO3, 1500);
-
- inited = 1;
- }
-}
-
-void sonarAlert(int gpio, int level, uint32_t tick)
-{
- static uint32_t startTick;
-
- int diffTick;
- char str[256];
-
- if (level == PI_ON)
- {
- startTick = tick;
- }
- else if (level == PI_OFF)
- {
- diffTick = tick - startTick;
-
- if (diffTick < 26100)
- {
- sprintf(str, "Sonar %3d cms", (diffTick+29)/58);
- putTTYstr(15, 1, str);
- }
- }
-}
-
-void LDRalert(int pin, int level, uint32_t tick)
-{
- int diffTick;
- char str[256];
-
- if (level == PI_ON)
- {
- diffTick = tick - LDRrechargeTick;
-
- sprintf(str, "LDR %4d micros", diffTick);
- putTTYstr(17, 1, str);
- }
-}
-
-void launchpadAlert(int pin, int level, uint32_t tick)
-{
- static int inited = 0, lastTick, lastPulseLen;
-
- int pulseLen, pulseDif;
-
- if (inited)
- {
- pulseLen = tick - lastTick;
- lastTick = tick;
-
- if (level==0)
- {
- if (lastPulseLen)
- {
- pulseDif = pulseLen - lastPulseLen;
-
- /* allow for wrap around */
- if (pulseDif < 0) pulseDif += 1096;
-
- /* now centre around expected value */
- pulseDif -= 33;
-
- if (pulseDif < 0) pulseDif = -pulseDif;
-
- launchpadPulses++;
-
- if (pulseDif <= 5)
- {
- launchpad5++;
- }
- else if (pulseDif <= 10)
- {
- launchpad10++;
- }
- else if (pulseDif <= 15)
- {
- launchpad15++;
- }
- else
- {
- launchpadOutRange++;
- launchpadErr = pulseDif;
- }
- }
- lastPulseLen = pulseLen;
- }
- }
- else
- {
- lastTick = tick;
- lastPulseLen = 0;
-
- launchpadPulses = 0;
- launchpad5 = 0;
- launchpad10 = 0;
- launchpad15 = 0;
- launchpadOutRange = 0;
-
- inited = 1;
- }
-}
-
-void putTTY(char * buf)
-{
- write(1, buf, strlen(buf));
-}
-
-void putTTYstr(int row, int col, char * buf)
-{
- char str[256];
-
- sprintf(str, "\033[%d;%dH%s", row, col, buf);
-
- putTTY(str);
-}
-
diff --git a/pigpio.c b/pigpio.c
index de8f142..510b45a 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* pigpio version 9 */
+/* pigpio version 10 */
#include
#include
@@ -198,6 +198,31 @@ bit 0 READ_LAST_NOT_SET_ERROR
} \
while (0)
+#define CHECK_INITED_RET_NULL_PTR \
+ do \
+ { \
+ if (!libInitialised) \
+ { \
+ fprintf(stderr, \
+ "%s %s: pigpio uninitialised, call gpioInitialise()\n",\
+ myTimeStamp(), __FUNCTION__); \
+ return (NULL); \
+ } \
+ } \
+ while (0)
+
+#define CHECK_INITED_RET_NIL \
+ do \
+ { \
+ if (!libInitialised) \
+ { \
+ fprintf(stderr, \
+ "%s %s: pigpio uninitialised, call gpioInitialise()\n",\
+ myTimeStamp(), __FUNCTION__); \
+ } \
+ } \
+ while (0)
+
#define CHECK_NOT_INITED \
do \
{ \
@@ -322,16 +347,16 @@ bit 0 READ_LAST_NOT_SET_ERROR
/* DMA CS Control and Status bits */
#define DMA_CHANNEL_RESET (1<<31)
#define DMA_WAIT_ON_WRITES (1<<28)
-#define DMA_PANIC_PRIORITY(x) ((x)<<20)
-#define DMA_PRIORITY(x) ((x)<<16)
+#define DMA_PANIC_PRIORITY(x) ((x)<<20)
+#define DMA_PRIORITY(x) ((x)<<16)
#define DMA_INTERRUPT_STATUS (1<< 2)
#define DMA_END_FLAG (1<< 1)
#define DMA_ACTIVATE (1<< 0)
/* DMA control block "info" field bits */
#define DMA_NO_WIDE_BURSTS (1<<26)
-#define DMA_PERIPHERAL_MAPPING(x) ((x)<<16)
-#define DMA_BURST_LENGTH(x) ((x)<<12)
+#define DMA_PERIPHERAL_MAPPING(x) ((x)<<16)
+#define DMA_BURST_LENGTH(x) ((x)<<12)
#define DMA_SRC_IGNORE (1<<11)
#define DMA_SRC_DREQ (1<<10)
#define DMA_SRC_INC (1<< 8)
@@ -981,7 +1006,8 @@ static void myDoCommand(cmdCmd_t * cmd)
if (gpioMask & (uint64_t)(1<res = res;
@@ -4731,6 +4767,56 @@ int gpioSetTimerFuncEx(unsigned id, unsigned ms, gpioTimerFuncEx_t f,
return 0;
}
+/* ----------------------------------------------------------------------- */
+
+pthread_t *gpioStartThread(ThreadFunc_t func, void *arg)
+{
+ pthread_t *pth;
+ pthread_attr_t pthAttr;
+
+ DBG(DBG_USER, "func=%08X, arg=%08X", (uint32_t)func, (uint32_t)arg);
+
+ CHECK_INITED_RET_NULL_PTR;
+
+ pth = malloc(sizeof(pthread_t));
+
+ if (pth)
+ {
+ if (pthread_attr_init(&pthAttr))
+ {
+ free(pth);
+ SOFT_ERROR(NULL, "pthread_attr_init failed");
+ }
+
+ if (pthread_attr_setstacksize(&pthAttr, STACK_SIZE))
+ {
+ free(pth);
+ SOFT_ERROR(NULL, "pthread_attr_setstacksize failed");
+ }
+
+ if (pthread_create(pth, &pthAttr, func, arg))
+ {
+ free(pth);
+ SOFT_ERROR(NULL, "pthread_create failed");
+ }
+ }
+ return pth;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void gpioStopThread(pthread_t *pth)
+{
+ DBG(DBG_USER, "pth=%08X", (uint32_t)pth);
+
+ CHECK_INITED_RET_NIL;
+
+ if (pth)
+ {
+ pthread_cancel(*pth);
+ pthread_join(*pth, NULL);
+ }
+}
/* ----------------------------------------------------------------------- */
@@ -4959,6 +5045,16 @@ uint32_t gpioTick(void)
}
+/* ----------------------------------------------------------------------- */
+
+unsigned gpioVersion(void)
+{
+ DBG(DBG_USER, "");
+
+ return PIGPIO_VERSION;
+}
+
+
/* ----------------------------------------------------------------------- */
unsigned gpioHardwareRevision(void)
diff --git a/pigpio.h b/pigpio.h
index 9b46ead..f4faaa0 100644
--- a/pigpio.h
+++ b/pigpio.h
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 9
+This version is for pigpio version 10
*/
#ifndef PIGPIO_H
@@ -51,6 +51,7 @@ This version is for pigpio version 9
/ output gpio level changes. /
/ 9) rudimentary permission control through the socket and pipe interfaces /
/ so users can be prevented from "updating" inappropriate gpios. /
+/ 10) a simple interface to start and stop new threads. /
/ /
/ NOTE: /
/ /
@@ -83,8 +84,9 @@ This version is for pigpio version 9
****************************************************************************/
#include
+#include
-#define PIGPIO_VERSION 9
+#define PIGPIO_VERSION 10
/*-------------------------------------------------------------------------*/
@@ -154,6 +156,9 @@ gpioSetGetSamplesFuncEx Requests a gpio samples callback, extended.
gpioSetTimerFunc Request a regular timed callback.
gpioSetTimerFuncEx Request a regular timed callback, extended.
+gpioStartThread Start a new thread.
+gpioStopThread Stop a previously started thread.
+
gpioSetSignalFunc Request a signal callback.
gpioSetSignalFuncEx Request a signal callback, extended.
@@ -175,6 +180,8 @@ gpioTick Get current tick (microseconds).
gpioHardwareRevision Get hardware version.
+gpioVersion Get the pigpio version.
+
gpioCfgBufferSize Configure the gpio sample buffer size.
gpioCfgClock Configure the gpio sample rate.
gpioCfgDMAchannel Configure the DMA channel (DEPRECATED).
@@ -264,11 +271,15 @@ typedef void (*gpioGetSamplesFuncEx_t) (const gpioSample_t * samples,
int numSamples,
void * userdata);
+typedef void *(ThreadFunc_t) (void *);
+
+
+
/*
All the functions which return an int return < 0 on error.
- If the library isn't initialised all but the gpioCfg* functions
- will return error PI_NOT_INITIALISED.
+ If the library isn't initialised all but the gpioCfg*, gpioVersion,
+ and gpioHardwareRevision functions will return error PI_NOT_INITIALISED.
If the library is initialised the gpioCfg* functions will
return error PI_INITIALISED.
@@ -381,9 +392,9 @@ int gpioSetPullUpDown(unsigned gpio,
/* pud: 0-2 */
-#define PI_PUD_OFF 0
-#define PI_PUD_DOWN 1
-#define PI_PUD_UP 2
+#define PI_PUD_OFF 0
+#define PI_PUD_DOWN 1
+#define PI_PUD_UP 2
@@ -406,14 +417,14 @@ int gpioRead (unsigned gpio);
/* level: 0-1 */
-#define PI_OFF 0
-#define PI_ON 1
+#define PI_OFF 0
+#define PI_ON 1
-#define PI_CLEAR 0
-#define PI_SET 1
+#define PI_CLEAR 0
+#define PI_SET 1
-#define PI_LOW 0
-#define PI_HIGH 1
+#define PI_LOW 0
+#define PI_HIGH 1
/* level: only reported for gpio timeout, see gpioSetWatchdogTimeout */
@@ -1255,6 +1266,68 @@ int gpioSetTimerFuncEx(unsigned timer,
+/* ----------------------------------------------------------------------- */
+pthread_t *gpioStartThread(ThreadFunc_t func, void *arg);
+/*-------------------------------------------------------------------------*/
+/* Starts a new thread of execution with func as the main routine.
+
+ Returns a pointer to pthread_t if OK, otherwise NULL.
+
+ The function is passed the single argument arg.
+
+ The thread can be cancelled by passing the pointer to pthread_t to
+ gpioStopThread().
+
+ EXAMPLE:
+
+ #include
+ #include
+
+ void *myfunc(void *arg)
+ {
+ while (1)
+ {
+ printf("%s\n", arg);
+ sleep(1);
+ }
+ }
+
+ int main(int argc, char *argv[])
+ {
+ pthread_t *p1, *p2, *p3;
+
+ if (gpioInitialise() < 0) return 1;
+
+ p1 = gpioStartThread(myfunc, "thread 1"); sleep(3);
+
+ p2 = gpioStartThread(myfunc, "thread 2"); sleep(3);
+
+ p3 = gpioStartThread(myfunc, "thread 3"); sleep(3);
+
+ gpioStopThread(p3); sleep(3);
+
+ gpioStopThread(p2); sleep(3);
+
+ gpioStopThread(p1); sleep(3);
+
+ gpioTerminate();
+ }
+*/
+
+
+
+/* ----------------------------------------------------------------------- */
+void gpioStopThread(pthread_t *pth);
+/*-------------------------------------------------------------------------*/
+/* Cancels the thread pointed at by pth.
+
+ No value is returned.
+
+ The thread to be stopped should have been started with gpioStartThread().
+*/
+
+
+
/*-------------------------------------------------------------------------*/
int gpioSetSignalFunc(unsigned signum,
gpioSignalFunc_t f);
@@ -1518,9 +1591,17 @@ unsigned gpioHardwareRevision(void);
EXAMPLES:
- for "Revision : 0002" the function returns 2.
- for "Revision : 000f" the function returns 15.
- for "Revision : 000g" the function returns 0.
+ for "Revision : 0002" the function returns 2.
+ for "Revision : 000f" the function returns 15.
+ for "Revision : 000g" the function returns 0.
+*/
+
+
+
+/*-------------------------------------------------------------------------*/
+unsigned gpioVersion(void);
+/*-------------------------------------------------------------------------*/
+/* Returns the pigpio version.
*/
@@ -1734,6 +1815,7 @@ void gpioWaveDump(void);
#define PI_CMD_PFG 23
#define PI_CMD_PRRG 24
#define PI_CMD_HELP 25
+#define PI_CMD_PIGPV 26
/*
The following command only works on the socket interface.
@@ -1792,8 +1874,8 @@ after this command is issued.
#define PI_TOO_MANY_PULSES -36 /* waveform has too many pulses */
#define PI_TOO_MANY_CHARS -37 /* waveform has too many chars */
#define PI_NOT_SERIAL_GPIO -38 /* no serial read in progress on gpio */
-#define PI_BAD_SERIAL_STRUC -39 /* bad null serial structure parameter */
-#define PI_BAD_SERIAL_BUF -40 /* bad null serial buf parameter */
+#define PI_BAD_SERIAL_STRUC -39 /* bad (null) serial structure parameter */
+#define PI_BAD_SERIAL_BUF -40 /* bad (null) serial buf parameter */
#define PI_NOT_PERMITTED -41 /* gpio operation not permitted */
#define PI_SOME_PERMITTED -42 /* one or more gpios not permitted */
@@ -1816,3 +1898,4 @@ after this command is issued.
#define PI_DEFAULT_UPDATE_MASK_R2 0xFBC6CF9C
#endif
+
diff --git a/pigpio.py b/pigpio.py
index d4e7894..c9e4be5 100644
--- a/pigpio.py
+++ b/pigpio.py
@@ -76,7 +76,7 @@ import threading
import os
import atexit
-VERSION = "1.0"
+VERSION = "1.1"
# gpio levels
@@ -92,9 +92,9 @@ TIMEOUT = 2
# gpio edges
-EITHER_EDGE = 0
-RISING_EDGE = 1
-FALLING_EDGE = 2
+RISING_EDGE = 0
+FALLING_EDGE = 1
+EITHER_EDGE = 2
# gpio modes
@@ -338,12 +338,14 @@ class _callback_thread(threading.Thread):
def __init__(self):
"""Initialises notifications."""
threading.Thread.__init__(self)
+ self.go = False
self.daemon = True
self.monitor = 0
self.callbacks = []
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((_host,_port))
self.handle = _pigpio_command(self.sock, _PI_CMD_NOIB, 0, 0)
+ self.go = True
self.start()
def stop(self):
@@ -376,13 +378,23 @@ class _callback_thread(threading.Thread):
notify_begin(self.handle, self.monitor)
def run(self):
+
"""Execute the notification thread."""
- self.go = True
+
lastLevel = 0
+
+ MSG_SIZ = 12
+
while self.go:
- seq_no, flags, tick, level = (
- struct.unpack('HHII', self.sock.recv(12, socket.MSG_WAITALL)))
+
+ buf = self.sock.recv(MSG_SIZ)
+
+ while self.go and len(buf) < MSG_SIZ:
+ buf += self.sock.recv(MSG_SIZ-len(buf))
+
if self.go:
+ seq, flags, tick, level = (struct.unpack('HHII', buf))
+
if flags == 0:
changed = level ^ lastLevel
lastLevel = level
@@ -391,19 +403,18 @@ class _callback_thread(threading.Thread):
newLevel = 0
if cb.bit & level:
newLevel = 1
- if (cb.edge == EITHER_EDGE or
- cb.edge == RISING_EDGE and newLevel == 1 or
- cb.edge == FALLING_EDGE and newLevel == 0):
+ if (cb.edge ^ newLevel):
cb.func(cb.gpio, newLevel, tick)
else:
gpio = flags & 31
for cb in self.callbacks:
if cb.gpio == gpio:
cb.func(cb.gpio, TIMEOUT, tick)
-
+
self.sock.close()
class _wait_for_edge:
+
"""A class to encapsulate waiting for gpio edges."""
def __init__(self, gpio, edge, timeout):
@@ -1553,20 +1564,18 @@ def start(host = os.getenv("PIGPIO_ADDR", ''),
else:
h = _host
errStr = "Can't connect to pigpio on " + str(h) + "(" + str(_port) + ")"
- print("********************************************************")
+ print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
print(errStr)
print("")
- print("Did you start the pigpio daemon?")
- print("(sudo pigpiod)")
+ print("Did you start the pigpio daemon? E.g. sudo pigpiod")
print("")
print("Did you specify the correct Pi host/port in the environment")
print("variables PIGPIO_ADDR/PIGPIO_PORT?")
- print("(e.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888)")
+ print("E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888")
print("")
print("Did you specify the correct Pi host/port in the")
- print("pigpio.start() function")
- print("(e.g. pigpio.start('soft', 8888))")
- print("********************************************************")
+ print("pigpio.start() function? E.g. pigpio.start('soft', 8888))")
+ print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
raise
def stop():
diff --git a/pigpiod_if.c b/pigpiod_if.c
new file mode 100644
index 0000000..6f095cb
--- /dev/null
+++ b/pigpiod_if.c
@@ -0,0 +1,688 @@
+/*
+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
+*/
+
+/* PIGPIOD_IF_VERSION 1 */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "pigpio.h"
+#include "command.h"
+
+#include "pigpiod_if.h"
+
+#define PISCOPE_MAX_REPORTS_PER_READ 4096
+
+#define STACK_SIZE (256*1024)
+
+typedef void (*CBF_t) ();
+
+struct callback_s
+{
+ int id;
+ int gpio;
+ int edge;
+ CBF_t f;
+ void * user;
+ int ex;
+ callback_t *prev;
+ callback_t *next;
+};
+
+/* GLOBALS ---------------------------------------------------------------- */
+
+static gpioReport_t gReport[PISCOPE_MAX_REPORTS_PER_READ];
+
+static int gPigCommand = -1;
+static int gPigHandle = -1;
+static int gPigNotify = -1;
+
+static uint32_t gNotifyBits;
+
+callback_t *gCallBackFirst = 0;
+callback_t *gCallBackLast = 0;
+
+static int gPigStarted = 0;
+
+static pthread_t *pthNotify;
+
+/* PRIVATE ---------------------------------------------------------------- */
+
+static int pigpio_command(int fd, int command, int p1, int p2)
+{
+ cmdCmd_t cmd;
+
+ cmd.cmd = command;
+ cmd.p1 = p1;
+ cmd.p2 = p2;
+ cmd.res = 0;
+
+ if (send(fd, &cmd, sizeof(cmdCmd_t), 0) != sizeof(cmdCmd_t))
+ return pigif_bad_send;
+
+ if (recv(fd, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) != sizeof(cmdCmd_t))
+ return pigif_bad_recv;
+
+ return cmd.res;
+}
+
+static int pigpioOpenSocket(char *addr, char *port)
+{
+ int sock, err;
+ 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;
+
+ 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(gpioReport_t *r)
+{
+ static uint32_t lastLevel = 0;
+
+ callback_t *p;
+ uint32_t changed;
+ int l, g;
+
+ /*
+ printf("s=%d f=%d l=%8X, t=%10u\n",
+ r->seqno, r->flags, r->level, r->tick);
+ */
+
+ if (r->flags == 0)
+ {
+ changed = (r->level ^ lastLevel) & gNotifyBits;
+
+ lastLevel = r->level;
+
+ p = gCallBackFirst;
+
+ while (p)
+ {
+ if (changed & (1<<(p->gpio)))
+ {
+ if ((r->level) & (1<<(p->gpio))) l = 1; else l = 0;
+ if ((p->edge) ^ l)
+ {
+ if (p->ex) (p->f)(p->gpio, l, r->tick, p->user);
+ else (p->f)(p->gpio, l, r->tick);
+ }
+ }
+ p = p->next;
+ }
+ }
+ else
+ {
+ g = (r->flags) & 31;
+
+ p = gCallBackFirst;
+
+ while (p)
+ {
+ if ((p->gpio) == g)
+ {
+ if (p->ex) (p->f)(g, PI_TIMEOUT, r->tick, p->user);
+ else (p->f)(g, PI_TIMEOUT, r->tick);
+ }
+ p = p->next;
+ }
+ }
+}
+
+static void *pthNotifyThread(void *x)
+{
+ static int got = 0;
+
+ int bytes, r;
+
+ while (1)
+ {
+ bytes = read(gPigNotify, (char*)&gReport+got, sizeof(gReport)-got);
+
+ if (bytes > 0) got += bytes;
+ else break;
+
+ r = 0;
+
+ while (got >= sizeof(gpioReport_t))
+ {
+ dispatch_notification(&gReport[r]);
+
+ r++;
+
+ got -= sizeof(gpioReport_t);
+ }
+
+ /* copy any partial report to start of array */
+
+ if (got && r) gReport[0] = gReport[r];
+ }
+ return 0;
+}
+
+static void findNotifyBits(void)
+{
+ callback_t *p;
+ uint32_t bits = 0;
+
+ p = gCallBackFirst;
+
+ while (p)
+ {
+ bits |= (1<<(p->gpio));
+ p = p->next;
+ }
+
+ if (bits != gNotifyBits)
+ {
+ gNotifyBits = bits;
+ pigpio_command(gPigCommand, PI_CMD_NB, gPigHandle, gNotifyBits);
+ }
+}
+
+static void _wfe(int gpio, int level, uint32_t tick, void *user)
+{
+ *(int *)user = 1;
+}
+
+static int intCallback(int gpio, int edge, void *f, void *user, int ex)
+{
+ static int id = 0;
+ callback_t *p;
+
+ if ((gpio >=0) && (gpio < 32) && (edge >=0) && (edge <= 2) && f)
+ {
+ /* prevent duplicates */
+
+ p = gCallBackFirst;
+
+ while (p)
+ {
+ if ((p->gpio == 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->gpio = 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();
+
+ return p->id;
+ }
+
+ return pigif_bad_malloc;
+ }
+
+ return pigif_bad_callback;
+}
+
+/* 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;
+ }
+ }
+}
+
+const char *pigpio_error(int error)
+{
+ if (error > -1000) return cmdErrStr(error);
+ else
+ {
+ switch(error)
+ {
+ 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 noib";
+ 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";
+ default:
+ return "unknown error";
+ }
+ }
+}
+
+unsigned pigpiod_if_version(void)
+{
+ return PIGPIOD_IF_VERSION;
+}
+
+pthread_t *start_thread(ThreadFunc_t func, void *arg)
+{
+ 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, func, arg))
+ {
+ 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);
+ }
+}
+
+int pigpio_start(char *addrStr, char *portStr)
+{
+ if (!gPigStarted)
+ {
+ gPigCommand = pigpioOpenSocket(addrStr, portStr);
+
+ if (gPigCommand >= 0)
+ {
+ gPigNotify = pigpioOpenSocket(addrStr, portStr);
+
+ if (gPigNotify >= 0)
+ {
+ gPigHandle = pigpio_command(gPigNotify, PI_CMD_NOIB, 0, 0);
+
+ if (gPigHandle < 0) return pigif_bad_noib;
+ else
+ {
+ pthNotify = start_thread(pthNotifyThread, 0);
+ if (pthNotify)
+ {
+ gPigStarted = 1;
+ return 0;
+ }
+ else return pigif_notify_failed;
+ }
+ }
+ else return gPigNotify;
+ }
+ else return gPigCommand;
+ }
+ return 0;
+}
+
+void pigpio_stop(void)
+{
+ gPigStarted = 0;
+
+ if (pthNotify)
+ {
+ stop_thread(pthNotify);
+ pthNotify = 0;
+ }
+
+ if (gPigNotify >= 0)
+ {
+ if (gPigHandle >= 0)
+ {
+ pigpio_command(gPigNotify, PI_CMD_NC, gPigHandle, 0);
+ gPigHandle = -1;
+ }
+
+ close(gPigNotify);
+ gPigNotify = -1;
+ }
+
+ if (gPigCommand >= 0)
+ {
+ if (gPigHandle >= 0)
+ {
+ pigpio_command(gPigCommand, PI_CMD_NC, gPigHandle, 0);
+ gPigHandle = -1;
+ }
+
+ close(gPigCommand);
+ gPigCommand = -1;
+ }
+}
+
+int set_mode(int gpio, int mode)
+{
+ return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);
+}
+
+int get_mode(int gpio)
+{
+ return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);
+}
+
+int set_pull_up_down(int gpio, int pud)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);
+}
+
+int read_gpio(int gpio)
+{
+ return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);
+}
+
+int write_gpio(int gpio, int level)
+{
+ return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);
+}
+
+int set_PWM_dutycycle(int user_gpio, int dutycycle)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);
+}
+
+int set_PWM_range(int user_gpio, int range_)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);
+}
+
+int get_PWM_range(int user_gpio)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);
+}
+
+int get_PWM_real_range(int user_gpio)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);
+}
+
+int set_PWM_frequency(int user_gpio, int frequency)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);
+}
+
+int get_PWM_frequency(int user_gpio)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);
+}
+
+int set_servo_pulsewidth(int user_gpio, int pulsewidth)
+{
+ return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);
+}
+
+int notify_open(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);
+}
+
+int notify_begin(int handle, uint32_t bits)
+{
+ return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);
+}
+
+int notify_pause(int handle)
+{
+ return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);
+}
+
+int notify_close(int handle)
+{
+ return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);
+}
+
+int set_watchdog(int user_gpio, int timeout)
+{
+ return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);
+}
+
+uint32_t read_bank_1(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BR1, 0, 0);
+}
+
+uint32_t read_bank_2(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BR2, 0, 0);
+}
+
+int clear_bank_1(uint32_t levels)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BC1, levels, 0);
+}
+
+int clear_bank_2(uint32_t levels)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BC2, levels, 0);
+}
+
+int set_bank_1(uint32_t levels)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BS1, levels, 0);
+}
+
+int set_bank_2(uint32_t levels)
+{
+ return pigpio_command(gPigCommand, PI_CMD_BS2, levels, 0);
+}
+
+uint32_t get_current_tick(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_TICK, 0, 0);
+}
+
+uint32_t get_hardware_revision(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);
+}
+
+unsigned get_pigpio_version(void)
+{
+ return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);
+}
+
+int callback(int gpio, int edge, CBFunc_t f)
+{
+ return intCallback(gpio, edge, f, 0, 0);
+}
+
+int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
+{
+ return intCallback(gpio, edge, f, user, 1);
+}
+
+int callback_cancel(int id)
+{
+ callback_t *p;
+
+ p = gCallBackFirst;
+
+ while (p)
+ {
+ if (p->id == id)
+ {
+ 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();
+
+ return 0;
+ }
+ p = p->next;
+ }
+ return pigif_callback_not_found;
+}
+
+int wait_for_edge(int gpio, int edge, double timeout)
+{
+ int triggered = 0;
+ int id;
+ double due;
+
+ if (timeout <= 0.0) return 0;
+
+ due = time_time() + timeout;
+
+ id = callback_ex(gpio, edge, _wfe, &triggered);
+
+ while (!triggered && (time_time() < due)) time_sleep(0.1);
+
+ callback_cancel(id);
+
+ return triggered;
+}
+
diff --git a/pigpiod_if.h b/pigpiod_if.h
new file mode 100644
index 0000000..bde8a71
--- /dev/null
+++ b/pigpiod_if.h
@@ -0,0 +1,527 @@
+/*
+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
+*/
+
+#ifndef PIGPIOD_IF_H
+#define PIGPIOD_IF_H
+
+#include "pigpio.h"
+
+#define PIGPIOD_IF_VERSION 1
+
+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,
+} piscopeError_t;
+
+
+typedef void (*CBFunc_t) (int gpio, int level, uint32_t tick);
+
+typedef void (*CBFuncEx_t)(int gpio, int level, uint32_t tick, void * user);
+
+typedef struct callback_s callback_t;
+
+#define RISING_EDGE 0
+#define FALLING_EDGE 1
+#define EITHER_EDGE 2
+
+double time_time(void);
+/* Return the current time in seconds since the Epoch.*/
+
+void time_sleep(double seconds);
+/* Delay execution for a given number of seconds */
+
+const char *pigpio_error(int error);
+/* Return a string for a pigpio library error. */
+
+unsigned pigpiod_if_version(void);
+/* Return the pigpiod_if version. */
+
+pthread_t *start_thread(ThreadFunc_t func, void *arg);
+/* Starts a new thread of execution with func as the main routine.
+
+ Returns a pointer to pthread_t if OK, otherwise NULL.
+
+ The function is passed the single argument arg.
+
+ The thread can be cancelled by passing the pointer to pthread_t to
+ gpioStopThread().
+*/
+
+void stop_thread(pthread_t *pth);
+/* Cancels the thread pointed at by pth.
+
+ No value is returned.
+
+ The thread to be stopped should have been started with gpioStartThread().
+*/
+
+int pigpio_start(char *addrStr, char *portStr);
+/* 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 overriden 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 overriden by the PIGPIO_PORT environment
+ variable.
+*/
+
+void pigpio_stop(void);
+/*
+ Terminates the connection to the pigpio daemon and releases
+ resources used by the library.
+*/
+
+int set_mode(int gpio, int mode);
+/* Set the gpio mode.
+
+ gpio: 0-53.
+ mode: INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5.
+
+ Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_MODE,
+ or PI_NOT_PERMITTED.
+*/
+
+int get_mode(int gpio);
+/* Get the gpio mode.
+
+ Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
+
+ gpio: 0-53.
+*/
+
+int set_pull_up_down(int gpio, int pud);
+/* Set or clear the gpio pull-up/down resistor.
+
+ Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
+ or PI_NOT_PERMITTED.
+
+ gpio: 0-53.
+ pud: PUD_UP, PUD_DOWN, PUD_OFF.
+*/
+
+int read_gpio(int gpio);
+/* Read the gpio level.
+
+ Returns the gpio level if OK, otherwise PI_BAD_GPIO.
+
+ gpio:0-53.
+*/
+
+int write_gpio(int gpio, int level);
+/*
+ Write the gpio level.
+
+ Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_LEVEL,
+ or PI_NOT_PERMITTED.
+
+ gpio: 0-53.
+ level: 0, 1.
+
+ Notes
+
+ If PWM or servo pulses are active on the gpio they are switched off.
+*/
+
+int set_PWM_dutycycle(int user_gpio, int dutycycle);
+/* Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
+
+ Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
+ or PI_NOT_PERMITTED.
+
+ user_gpio: 0-31.
+ dutycycle: 0-range (range defaults to 255).
+
+ Notes
+
+ The set_PWM_range() function can change the default range of 255.
+*/
+
+int set_PWM_range(int user_gpio, int range_);
+/* Set the range of PWM values to be used on the gpio.
+
+ Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
+ or PI_NOT_PERMITTED.
+
+ user_gpio: 0-31.
+ range_: 25-40000.
+
+ Notes
+
+ If PWM is currently active on the gpio its dutycycle will be
+ scaled to reflect the new range.
+
+ The real range, the number of steps between fully off and fully on
+ for each of the 18 available gpio frequencies is
+
+ 25(#1), 50(#2), 100(#3), 125(#4), 200(#5), 250(#6), 400(#7),
+ 500(#8), 625(#9), 800(#10), 1000(#11), 1250(#12), 2000(#13),
+ 2500(#14), 4000(#15), 5000(#16), 10000(#17), 20000(#18)
+
+ The real value set by set_PWM_range is
+ (dutycycle * real range) / range.
+
+*/
+
+int get_PWM_range(int user_gpio);
+/* Get the range of PWM values being used on the gpio.
+
+ Returns the dutycycle range used for the gpio if OK,
+ otherwise PI_BAD_USER_GPIO.
+
+ user_gpio: 0-31.
+*/
+
+int get_PWM_real_range(int user_gpio);
+/* Get the real underlying range of PWM values being used on the gpio.
+
+ Returns the real range used for the gpio if OK,
+ otherwise PI_BAD_USER_GPIO.
+
+ user_gpio: 0-31.
+*/
+
+int set_PWM_frequency(int user_gpio, int frequency);
+/*
+ Set the frequency (in Hz) of the PWM to be used on the gpio.
+
+ Returns the numerically closest frequency if OK, otherwise
+ PI_BAD_USER_GPIO or PI_NOT_PERMITTED.
+
+ user_gpio: 0-31.
+ frequency: 0- (Hz).
+
+ The selectable frequencies depend upon the sample rate which
+ may be 1, 2, 4, 5, 8, or 10 microseconds (default 5). The
+ sample rate is set when the C pigpio library is started.
+
+ Each gpio can be independently set to one of 18 different
+ PWM frequencies.
+
+ If PWM is currently active on the gpio it will be switched
+ off and then back on at the new frequency.
+
+ 1us 40000, 20000, 10000, 8000, 5000, 4000, 2500, 2000, 1600,
+ 1250, 1000, 800, 500, 400, 250, 200, 100, 50
+
+ 2us 20000, 10000, 5000, 4000, 2500, 2000, 1250, 1000, 800,
+ 625, 500, 400, 250, 200, 125, 100, 50, 25
+
+ 4us 10000, 5000, 2500, 2000, 1250, 1000, 625, 500, 400,
+ 313, 250, 200, 125, 100, 63, 50, 25, 13
+
+ 5us 8000, 4000, 2000, 1600, 1000, 800, 500, 400, 320,
+ 250, 200, 160, 100, 80, 50, 40, 20, 10
+
+ 8us 5000, 2500, 1250, 1000, 625, 500, 313, 250, 200,
+ 156, 125, 100, 63, 50, 31, 25, 13, 6
+
+ 10us 4000, 2000, 1000, 800, 500, 400, 250, 200, 160,
+ 125, 100, 80, 50, 40, 25, 20, 10, 5
+*/
+
+int get_PWM_frequency(int user_gpio);
+/*
+ Get the frequency of PWM being used on the gpio.
+
+ Returns the frequency (in hertz) used for the gpio if OK,
+ otherwise PI_BAD_USER_GPIO.
+
+ user_gpio: 0-31.
+*/
+
+int set_servo_pulsewidth(int user_gpio, int pulsewidth);
+/*
+ Start (500-2500) or stop (0) servo pulses on the gpio.
+
+ Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_PULSEWIDTH or
+ PI_NOT_PERMITTED.
+
+ user_gpio: 0-31.
+ pulsewidth: 0 (off), 500 (most anti-clockwise) - 2500 (most clockwise).
+
+ The selected pulsewidth will continue to be transmitted until
+ changed by a subsequent call to set_servo_pulsewidth().
+
+ The pulsewidths supported by servos varies and should probably be
+ determined by experiment. A value of 1500 should always be safe and
+ represents the mid-point of rotation.
+
+ You can DAMAGE a servo if you command it to move beyond its limits.
+
+ OTHER UPDATE RATES:
+
+ This function updates servos at 50Hz. If you wish to use a different
+ update frequency you will have to use the PWM functions.
+
+ Update Rate (Hz) 50 100 200 400 500
+ 1E6/Hz 20000 10000 5000 2500 2000
+
+ Firstly set the desired PWM frequency using set_PWM_frequency().
+
+ Then set the PWM range using set_PWM_range() to 1E6/Hz.
+ Doing this allows you to use units of microseconds when setting
+ the servo pulse width.
+
+ E.g. If you want to update a servo connected to gpio 25 at 400Hz
+
+ set_PWM_frequency(25, 400);
+ set_PWM_range(25, 2500);
+
+ Thereafter use the set_PWM_dutycycle() function to move the servo,
+ e.g. set_PWM_dutycycle(25, 1500) will set a 1500 us pulse.
+*/
+
+int notify_open(void);
+/*
+ Get a free notification handle.
+
+ Returns a handle greater than or equal to zero if OK,
+ otherwise PI_NO_HANDLE.
+
+ A notification is a method for being notified of gpio state
+ changes via a pipe.
+
+ Pipes are only accessible from the local machine so this function
+ serves no purpose if you are using 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.
+*/
+
+int notify_begin(int handle, uint32_t bits);
+/*
+ Start notifications on a previously opened handle.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+ bits: a mask indicating the gpios to be notified.
+
+ The notification sends state changes for each gpio whose
+ corresponding bit in bits is set.
+
+ 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
+*/
+
+int notify_pause(int handle);
+/*
+ Pause notifications on a previously opened handle.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+
+ Notifications for the handle are suspended until
+ notify_begin() is called again.
+*/
+
+int notify_close(int handle);
+/*
+ Stop notifications on a previously opened handle and
+ release the handle for reuse.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+*/
+
+int set_watchdog(int user_gpio, int timeout);
+/*
+ Sets a watchdog for a gpio.
+
+ Returns 0 if OK, otherwise PI_BAD_USER_GPIO
+ or PI_BAD_WDOG_TIMEOUT.
+
+ user_gpio: 0-31.
+ timeout: 0-60000.
+
+ The watchdog is nominally in milliseconds.
+
+ Only one watchdog may be registered per gpio.
+
+ The watchdog may be cancelled by setting timeout to 0.
+
+ If no level change has been detected for the gpio for timeout
+ milliseconds any notification for the gpio has a report written
+ to the fifo with the flags set to indicate a watchdog timeout.
+
+ The callback() and callback_ex functions interpret the flags and will
+ call registered callbacks for the gpio with level TIMEOUT.
+*/
+
+uint32_t read_bank_1(void);
+/*
+ Read the levels of the bank 1 gpios (gpios 0-31).
+
+ The returned 32 bit integer has a bit set if the corresponding
+ gpio is logic 1. Gpio n has bit value (1<