diff --git a/Makefile b/Makefile
index 2b69494..8684ac6 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,9 @@ SIZE = size
CFLAGS = -O3 -Wall
-all: libpigpio.a checklib demolib pig2vcd pigpiod pigs
+ALL = libpigpio.a checklib demolib pig2vcd pigpiod pigs
+
+all: $(ALL)
checklib: checklib.o libpigpio.a
$(CC) -o checklib checklib.c -L. -lpigpio -lpthread -lrt
@@ -19,31 +21,29 @@ pig2vcd: pig2vcd.o
pigpiod: pigpiod.o libpigpio.a
$(CC) -o pigpiod pigpiod.c -L. -lpigpio -lpthread -lrt
-pigs: pigs.o command.o
+pigs: command.o
$(CC) -o pigs pigs.c command.c
-.c.o:
- $(CC) -c $(CFLAGS) $<
-
clean:
- rm -f *.o *.i *.s *~ libpigpio.a checklib demolib pigpiod pigs pig2vcd
+ rm -f *.o *.i *.s *~ $(ALL)
install: $(LIB)
- sudo install -m 0755 -d /usr/local/bin
sudo install -m 0755 -d /usr/local/include
+ sudo install -m 0644 pigpio.h /usr/local/include
sudo install -m 0755 -d /usr/local/lib
+ sudo install -m 0644 libpigpio.a /usr/local/lib
+ sudo install -m 0755 -d /usr/local/bin
sudo install -m 0755 pig2vcd /usr/local/bin
sudo install -m 0755 pigpiod /usr/local/bin
sudo install -m 0755 pigs /usr/local/bin
- sudo install -m 0644 pigpio.h /usr/local/include
- sudo install -m 0644 libpigpio.a /usr/local/lib
+ sudo python setup.py install
uninstall:
+ sudo rm -f /usr/local/include/pigpio.h
+ sudo rm -f /usr/local/lib/libpigpio.a
sudo rm -f /usr/local/bin/pig2vcd
sudo rm -f /usr/local/bin/pigpiod
sudo rm -f /usr/local/bin/pigs
- sudo rm -f /usr/local/include/pigpio.h
- sudo rm -f /usr/local/lib/libpigpio.a
LIB = libpigpio.a
OBJ = pigpio.o command.o
@@ -53,11 +53,13 @@ $(LIB): $(OBJ)
$(RANLIB) $(LIB)
$(SIZE) $(LIB)
+# generated using gcc -M *.c
-# DO NOT DELETE
+checklib.o: checklib.c pigpio.h
+command.o: command.c pigpio.h command.h
+demolib.o: demolib.c pigpio.h
+pig2vcd.o: pig2vcd.c pigpio.h
+pigpio.o: pigpio.c pigpio.h command.h
+pigpiod.o: pigpiod.c pigpio.h command.h
+pigs.o: pigs.c pigpio.h command.h
-checklib.o: checklib.c pigpio.h
-demolib.o: demolib.c pigpio.h
-pig2vcd: pigpio.h
-pigpiod: pigpiod.c pigpio.h
-pigs: pigs.c command.c pigpio.h command.h
diff --git a/README b/README
index 41c00cb..b673035 100644
--- a/README
+++ b/README
@@ -15,6 +15,7 @@ This will install:
the daemon (pigpiod) in /usr/local/bin
the socket interface (pigs) in /usr/local/bin
the utility pig2vcd in /usr/local/bin
+ the Python module pigpio.py
TEST
@@ -22,8 +23,8 @@ To test the library do
sudo ./checklib
-checklib.c, demolib.c, pig2vcd.c, pigpiod.c, and pigs.c show examples
-of interfacing with the library.
+checklib.c, demolib.c, pig2vcd.c, pigpiod.c, pigs.c, and pigpio.py
+show examples of interfacing with the library.
DAEMON
@@ -59,9 +60,30 @@ cat /dev/pigerr &
echo "help" >/dev/pigpio
+PYTHON INTERFACE
+
+If the pigpiod daemon is running you can test the Python
+interface by entering the following commands.
+
+python
+
+import pigpio
+
+pigpio.start()
+
+print(pigpio.get_current_tick())
+
+print(hex(pigpio.read_bank_1()))
+
+pigpio.stop()
+
+help(pigpio)
+
+quit()
+
STOP DAEMON
-To stop the daemon
+To stop the pigpiod daemon
sudo killall pigpiod
diff --git a/command.c b/command.c
index ab46aa8..c3eba85 100644
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 4+
+This version is for pigpio version 7+
*/
#include
@@ -141,7 +141,7 @@ static errInfo_t errInfo[]=
{PI_BAD_CLK_SOURCE , "clock source not 0-1"},
{PI_BAD_CLK_MICROS , "clock micros not 1, 2, 4, 5, 8, or 10"},
{PI_BAD_BUF_MILLIS , "buf millis not 100-10000"},
- {PI_BAD_DUTY_RANGE , "dutycycle range not 25-40000"},
+ {PI_BAD_DUTYRANGE , "dutycycle range not 25-40000"},
{PI_BAD_SIGNUM , "signum not 0-63"},
{PI_BAD_PATHNAME , "can't open pathname"},
{PI_NO_HANDLE , "no handle available"},
@@ -159,7 +159,8 @@ static errInfo_t errInfo[]=
{PI_TOO_MANY_PULSES , "waveform has too many pulses"},
{PI_TOO_MANY_CHARS , "waveform has too many chars"},
{PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"},
-
+ {PI_NOT_PERMITTED , "no permission to update gpio"},
+ {PI_SOME_PERMITTED , "no permission to update one or more gpios"},
};
static char * fmtMdeStr="RW540123";
@@ -289,4 +290,3 @@ char * cmdErrStr(int error)
}
return "unknown error";
}
-
diff --git a/command.h b/command.h
index 9d2da7d..6ace8c7 100644
--- a/command.h
+++ b/command.h
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 3+
+This version is for pigpio version 7+
*/
#ifndef COMMAND_H
@@ -39,10 +39,10 @@ This version is for pigpio version 3+
typedef struct
{
- int cmd;
- char * name;
- int vt;
- int rv;
+ int cmd; /* command number */
+ char * name; /* command name */
+ int vt; /* command verification type */
+ int rv; /* command return value type */
} cmdInfo_t;
extern cmdInfo_t cmdInfo[];
diff --git a/pigpio.c b/pigpio.c
index c577ced..5b721b8 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* pigpio version 6 */
+/* pigpio version 7 */
#include
#include
@@ -229,6 +229,13 @@ bit 0 READ_LAST_NOT_SET_ERROR
} \
while (0)
+#define PERM_ERROR(format, arg...) \
+ do \
+ { \
+ fprintf(stderr, "%s " format "\n", myTimeStamp(), ## arg); \
+ } \
+ while (0)
+
#define TIMER_ADD(a, b, result) \
do \
{ \
@@ -519,8 +526,6 @@ bit 0 READ_LAST_NOT_SET_ERROR
#define PI_WFRX_SERIAL 1
#define PI_WF_MICROS 2
-#define PI_WAVE_MAX_PULSES 3000
-
#define DATUMS 2000
#define DEFAULT_PWM_IDX 5
@@ -704,12 +709,16 @@ static volatile gpioCfg_t gpioCfg =
static volatile gpioStats_t gpioStats;
+static int gpioMaskSet = 0;
+
/* initialise every gpioInitialise */
static struct timespec libStarted;
/* initialse if not libInitialised */
+static uint64_t gpioMask;
+
static gpioPulse_t wf[3][PI_WAVE_MAX_PULSES];
static int wfc[3]={0, 0, 0};
@@ -732,7 +741,6 @@ static volatile uint32_t notifyBits = 0;
static volatile int DMAstarted = 0;
static int libInitialised = 0;
-static unsigned hardwareRevision = 0;
static int pthAlertRunning = 0;
static int pthFifoRunning = 0;
@@ -947,6 +955,7 @@ static uint32_t myGetTick(int pos)
static void myDoCommand(cmdCmd_t * cmd)
{
int p1, p2, res;
+ uint32_t mask;
p1 = cmd->p1;
p2 = cmd->p2;
@@ -956,7 +965,12 @@ static void myDoCommand(cmdCmd_t * cmd)
switch (cmd->cmd)
{
case PI_CMD_MODES:
- res = gpioSetMode(p1, p2);
+ if (gpioMask & (uint64_t)(1<>32;
+
+ res = gpioWrite_Bits_32_53_Clear(p1&mask);
+
+ if ((mask | p1) != mask)
+ {
+ PERM_ERROR("gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
+ p1, mask);
+ res = PI_SOME_PERMITTED;
+ }
break;
case PI_CMD_BS1:
- gpioWrite_Bits_0_31_Set(p1);
+ mask = gpioMask;
+
+ res = gpioWrite_Bits_0_31_Set(p1&mask);
+
+ if ((mask | p1) != mask)
+ {
+ PERM_ERROR("gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
+ p1, mask);
+ res = PI_SOME_PERMITTED;
+ }
break;
case PI_CMD_BS2:
- gpioWrite_Bits_32_53_Set(p1);
+ mask = gpioMask>>32;
+
+ res = gpioWrite_Bits_32_53_Set(p1&mask);
+
+ if ((mask | p1) != mask)
+ {
+ PERM_ERROR("gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
+ p1, mask);
+ res = PI_SOME_PERMITTED;
+ }
break;
case PI_CMD_TICK:
@@ -1274,7 +1354,7 @@ static void waveCbOPrint(int pos)
p = waveCbVOadr(pos);
- fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx",
+ fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n",
p->info, p->src, p->dst, p->length, p->stride, p->next);
}
@@ -1669,7 +1749,7 @@ static void dmaCbPrint(int pos)
p = dmaCB2adr(pos);
- fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx",
+ fprintf(stderr, "i=%lx s=%lx d=%lx len=%lx s=%lx nxt=%lx\n",
p->info, p->src, p->dst, p->length, p->stride, p->next);
}
@@ -1962,13 +2042,15 @@ static void sigHandler(int signum)
DBG(DBG_USER, "Debug level %d\n", gpioCfg.dbgLevel);
}
+ else if (signum == SIGPIPE)
+ {
+ DBG(DBG_USER, "SIGPIPE received");
+ }
else
{
- /* close library safely and exit */
+ /* exit */
- DBG(DBG_USER, "Unhandled signal %d, terminating\n", signum);
-
- gpioTerminate();
+ DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
exit(-1);
}
@@ -1976,11 +2058,9 @@ static void sigHandler(int signum)
}
else
{
- /* close library safely and exit */
+ /* exit */
- DBG(DBG_USER, "Unhandled signal %d, terminating\n", signum);
-
- gpioTerminate();
+ DBG(DBG_MIN_LEVEL, "Unhandled signal %d, terminating\n", signum);
exit(-1);
}
@@ -2424,7 +2504,6 @@ static void * pthTimerTick(void *x)
return 0;
}
-
/* ----------------------------------------------------------------------- */
@@ -2465,6 +2544,7 @@ static void * pthFifoThread(void *x)
break;
case 1:
+ fprintf(outFifo, "%d\n", cmd.res);
break;
case 2:
@@ -2860,7 +2940,7 @@ static int initDMAcbs(void)
/* allocate memory for pointers to virtual and physical pages */
dmaBloc = mmap(
- 0, (bufferBlocks+1)*sizeof(dmaPage_t *),
+ 0, (bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
-1, 0);
@@ -2869,7 +2949,7 @@ static int initDMAcbs(void)
SOFT_ERROR(PI_INIT_FAILED, "mmap dma virtual failed (%m)");
dmaVirt = mmap(
- 0, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *),
+ 0, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
-1, 0);
@@ -2878,7 +2958,7 @@ static int initDMAcbs(void)
SOFT_ERROR(PI_INIT_FAILED, "mmap dma virtual failed (%m)");
dmaPhys = mmap(
- 0, PAGES_PER_BLOCK*(bufferBlocks+1)*sizeof(dmaPage_t *),
+ 0, PAGES_PER_BLOCK*(bufferBlocks+PI_WAVE_BLOCKS)*sizeof(dmaPage_t *),
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED,
-1, 0);
@@ -2901,7 +2981,7 @@ static int initDMAcbs(void)
if (pagemapFd < 0)
SOFT_ERROR(PI_INIT_FAILED, "open pagemap failed(%m)");
- for (i=0; i<(bufferBlocks+1); i++) initDMAblock(pagemapFd, i);
+ for (i=0; i<(bufferBlocks+PI_WAVE_BLOCKS); i++) initDMAblock(pagemapFd, i);
close(pagemapFd);
@@ -2918,7 +2998,10 @@ static int initDMAcbs(void)
dmaInitCbs();
if (gpioCfg.dbgLevel >= DBG_DMACBS)
+ {
+ fprintf(stderr, "*** INPUT DMA CONTROL BLOCKS ***\n");
for (i=0; i PI_MAX_DUTYCYCLE_RANGE))
- SOFT_ERROR(PI_BAD_DUTY_RANGE, "gpio %d, bad range (%d)", gpio, range);
+ SOFT_ERROR(PI_BAD_DUTYRANGE, "gpio %d, bad range (%d)", gpio, range);
oldWidth = gpioInfo[gpio].width;
@@ -4247,7 +4308,10 @@ int gpioWaveTxStart(unsigned mode)
cb = wave2Cbs(mode);
if (gpioCfg.dbgLevel >= DBG_SLOW_TICK)
+ {
+ fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n");
for (i=0; i
*/
/*
-This version is for pigpio version 6
+This version is for pigpio version 7
*/
#ifndef PIGPIO_H
@@ -82,7 +82,7 @@ This version is for pigpio version 6
#include
-#define PIGPIO_VERSION 6
+#define PIGPIO_VERSION 7
/*-------------------------------------------------------------------------*/
@@ -175,7 +175,9 @@ gpioHardwareRevision Get hardware version.
gpioCfgBufferSize Configure the gpio sample buffer size.
gpioCfgClock Configure the gpio sample rate.
-gpioCfgDMAchannel Configure the DMA channel.
+gpioCfgDMAchannel Configure the DMA channel (DEPRECATED).
+gpioCfgDMAchannels Configure the DMA channels.
+gpioCfgPermissions Configure the gpio access permissions.
gpioCfgInterfaces Configure user interfaces.
gpioCfgSocketPort Configure socket port.
@@ -482,7 +484,7 @@ int gpioSetPWMrange(unsigned user_gpio,
to gpioPWM will use a dutycycle between 0 (off) and range (fully on).
Returns the real range for the given gpio's frequency if OK,
- otherwise PI_BAD_USER_GPIO or PI_BAD_DUTY_RANGE.
+ otherwise PI_BAD_USER_GPIO or PI_BAD_DUTYRANGE.
EXAMPLE:
...
@@ -892,9 +894,12 @@ int gpioWaveAddSerial(unsigned user_gpio,
the same waveform.
*/
+#define PI_WAVE_BLOCKS 3
+#define PI_WAVE_MAX_PULSES (PI_WAVE_BLOCKS * 3000)
+#define PI_WAVE_MAX_CHARS (PI_WAVE_BLOCKS * 256)
+
#define PI_WAVE_MIN_BAUD 100
#define PI_WAVE_MAX_BAUD 250000
-#define PI_WAVE_MAX_CHARS 256
@@ -1601,7 +1606,7 @@ int gpioCfgClock(unsigned micros,
/*-------------------------------------------------------------------------*/
-int gpioCfgDMAchannel(unsigned channel);
+int gpioCfgDMAchannel(unsigned channel); /* DEPRECATED */
/*-------------------------------------------------------------------------*/
/* Configures pigpio to use the specified DMA channel.
@@ -1622,7 +1627,7 @@ int gpioCfgDMAchannels(unsigned primaryChannel,
/* Configures pigpio to use the specified DMA channels.
The default setting is to use channel 14 for the primary channel and
- channel 6 for the secondary channel.
+ channel 5 for the secondary channel.
*/
#define PI_MAX_PRIMARY_CHANNEL 14
@@ -1630,6 +1635,18 @@ int gpioCfgDMAchannels(unsigned primaryChannel,
+/*-------------------------------------------------------------------------*/
+int gpioCfgPermissions(uint64_t updateMask);
+/*-------------------------------------------------------------------------*/
+/* Configures pigpio to only allow updates (writes or mode changes) for the
+ gpios specified by the mask.
+
+ The default setting is to allow updates to gpios 0-31, i.e. an update mask
+ of 0x00000000FFFFFFFF.
+*/
+
+
+
/*-------------------------------------------------------------------------*/
int gpioCfgSocketPort(unsigned port);
/*-------------------------------------------------------------------------*/
@@ -1746,7 +1763,8 @@ after this command is issued.
#define PI_BAD_CLK_SOURCE -18 /* clock source not 0-1 */
#define PI_BAD_CLK_MICROS -19 /* clock micros not 1, 2, 4, 5, 8, or 10 */
#define PI_BAD_BUF_MILLIS -20 /* buf millis not 100-10000 */
-#define PI_BAD_DUTY_RANGE -21 /* dutycycle range not 25-40000 */
+#define PI_BAD_DUTYRANGE -21 /* dutycycle range not 25-40000 */
+#define PI_BAD_DUTY_RANGE -21 /* DEPRECATED (use PI_BAD_DUTYRANGE) */
#define PI_BAD_SIGNUM -22 /* signum not 0-63 */
#define PI_BAD_PATHNAME -23 /* can't open pathname */
#define PI_NO_HANDLE -24 /* no handle available */
@@ -1767,6 +1785,8 @@ after this command is issued.
#define PI_NOT_SERIAL_GPIO -38 /* no serial read in progress on gpio */
#define PI_BAD_SERIAL_STRUC -39 /* bad null serial structure parameter */
#define PI_BAD_SERIAL_BUF -40 /* bad null serial buf parameter */
+#define PI_NOT_PERMITTED -41 /* gpio operation not permitted */
+#define PI_SOME_PERMITTED -42 /* one or more gpios not permitted */
/*-------------------------------------------------------------------------*/
@@ -1778,8 +1798,12 @@ after this command is issued.
#define PI_DEFAULT_IF_FLAGS 0
#define PI_DEFAULT_DMA_CHANNEL 14
#define PI_DEFAULT_DMA_PRIMARY_CHANNEL 14
-#define PI_DEFAULT_DMA_SECONDARY_CHANNEL 6
+#define PI_DEFAULT_DMA_SECONDARY_CHANNEL 5
#define PI_DEFAULT_SOCKET_PORT 8888
+#define PI_DEFAULT_SOCKET_PORT_STR "8888"
+#define PI_DEFAULT_SOCKET_ADDR_STR "127.0.0.1"
+#define PI_DEFAULT_UPDATE_MASK_R0 0xFBE6CF9F
+#define PI_DEFAULT_UPDATE_MASK_R1 0x03E6CF93
+#define PI_DEFAULT_UPDATE_MASK_R2 0xFBC6CF9C
#endif
-
diff --git a/pigpio.py b/pigpio.py
new file mode 100644
index 0000000..d4e7894
--- /dev/null
+++ b/pigpio.py
@@ -0,0 +1,1591 @@
+"""
+pigpio is a Python module for the Raspberry Pi which allows control
+of the general purpose input outputs (gpios).
+
+There are 54 gpios in total, arranged in two banks. Bank 1 contains
+gpios 0-31. Bank 2 contains gpios 32-54.
+
+Most of the gpios are dedicated to system use.
+
+A user should only manipulate gpios in bank 1.
+
+For a Rev.1 board only use gpios 0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17,
+18, 21, 22, 23, 24, 25.
+
+For a Rev.2 board only use gpios 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17,
+18, 22, 23, 24, 25, 27, 28, 29, 30, 31.
+
+It is safe to read all the gpios. If you try to write a system gpio or
+change its mode you can crash the Pi or corrupt the data on the SD card.
+
+Features
+
+The pigpio module's main features are:
+
+- provision of PWM on any number of gpios 0-31 simultaneously.
+
+- provision of servo pulses on any number of gpios 0-31 simultaneously.
+
+- callbacks when any of gpios 0-31 change state.
+
+- reading/writing gpios and setting their modes (typically input
+ or output).
+
+- reading/writing all of the gpios in a bank (0-31, 32-53) as a single
+ operation.
+
+Notes
+
+ALL gpios are identified by their Broadcom number.
+
+This module uses the services of the C pigpio library. That library
+must be running on the Pi whose gpios are to be manipulated.
+
+The normal way to start the library is as a daemon (during system
+start).
+
+sudo pigpiod
+
+Your Python program should wrap the use of the module up in calls
+to pigpio.start() and pigpio.stop().
+
+Settings
+
+A number of settings are determined when the pigpiod daemon is started.
+
+- the sample rate (1, 2, 4, 5, 8, or 10us, default 5us).
+
+- the set of gpios which may be updated (generally written to). The
+ default set is those listed above for the Rev.1 or Rev.2 boards.
+
+- the available PWM frequencies (see set_PWM_frequency()).
+
+Exceptions
+
+By default a fatal exception is raised if you pass an invalid
+argument to a pigpio function.
+
+If you wish to handle the returned status yourself you should set
+pigpio.exceptions = False.
+
+"""
+import socket
+import struct
+import time
+import threading
+import os
+import atexit
+
+VERSION = "1.0"
+
+# gpio levels
+
+OFF = 0
+LOW = 0
+CLEAR = 0
+
+ON = 1
+HIGH = 1
+SET = 1
+
+TIMEOUT = 2
+
+# gpio edges
+
+EITHER_EDGE = 0
+RISING_EDGE = 1
+FALLING_EDGE = 2
+
+# gpio modes
+
+INPUT = 0
+OUTPUT = 1
+ALT0 = 4
+ALT1 = 5
+ALT2 = 6
+ALT3 = 7
+ALT4 = 3
+ALT5 = 2
+
+# gpio Pull Up Down
+
+PUD_OFF = 0
+PUD_DOWN = 1
+PUD_UP = 2
+
+# pigpio command numbers
+
+_PI_CMD_MODES= 0
+_PI_CMD_MODEG= 1
+_PI_CMD_PUD= 2
+_PI_CMD_READ= 3
+_PI_CMD_WRITE= 4
+_PI_CMD_PWM= 5
+_PI_CMD_PRS= 6
+_PI_CMD_PFS= 7
+_PI_CMD_SERVO= 8
+_PI_CMD_WDOG= 9
+_PI_CMD_BR1= 10
+_PI_CMD_BR2= 11
+_PI_CMD_BC1= 12
+_PI_CMD_BC2= 13
+_PI_CMD_BS1= 14
+_PI_CMD_BS2= 15
+_PI_CMD_TICK= 16
+_PI_CMD_HWVER=17
+_PI_CMD_NO= 18
+_PI_CMD_NB= 19
+_PI_CMD_NP= 20
+_PI_CMD_NC= 21
+_PI_CMD_PRG= 22
+_PI_CMD_PFG= 23
+_PI_CMD_PRRG= 24
+_PI_CMD_NOIB= 99
+
+# pigpio error numbers
+
+_PI_INIT_FAILED =-1
+PI_BAD_USER_GPIO =-2
+PI_BAD_GPIO =-3
+PI_BAD_MODE =-4
+PI_BAD_LEVEL =-5
+PI_BAD_PUD =-6
+PI_BAD_PULSEWIDTH =-7
+PI_BAD_DUTYCYCLE =-8
+_PI_BAD_TIMER =-9
+_PI_BAD_MS =-10
+_PI_BAD_TIMETYPE =-11
+_PI_BAD_SECONDS =-12
+_PI_BAD_MICROS =-13
+_PI_TIMER_FAILED =-14
+PI_BAD_WDOG_TIMEOUT =-15
+_PI_NO_ALERT_FUNC =-16
+_PI_BAD_CLK_PERIPH =-17
+_PI_BAD_CLK_SOURCE =-18
+_PI_BAD_CLK_MICROS =-19
+_PI_BAD_BUF_MILLIS =-20
+PI_BAD_DUTYRANGE =-21
+_PI_BAD_SIGNUM =-22
+_PI_BAD_PATHNAME =-23
+PI_NO_HANDLE =-24
+PI_BAD_HANDLE =-25
+_PI_BAD_IF_FLAGS =-26
+_PI_BAD_CHANNEL =-27
+_PI_BAD_PRIM_CHANNEL=-27
+_PI_BAD_SOCKET_PORT =-28
+_PI_BAD_FIFO_COMMAND=-29
+_PI_BAD_SECO_CHANNEL=-30
+_PI_NOT_INITIALISED =-31
+_PI_INITIALISED =-32
+_PI_BAD_WAVE_MODE =-33
+_PI_BAD_CFG_INTERNAL=-34
+_PI_BAD_WAVE_BAUD =-35
+_PI_TOO_MANY_PULSES =-36
+_PI_TOO_MANY_CHARS =-37
+_PI_NOT_SERIAL_GPIO =-38
+_PI_BAD_SERIAL_STRUC=-39
+_PI_BAD_SERIAL_BUF =-40
+PI_NOT_PERMITTED =-41
+PI_SOME_PERMITTED =-42
+
+# pigpio error text
+
+_errors=[
+ [_PI_INIT_FAILED , "pigpio initialisation failed"],
+ [PI_BAD_USER_GPIO , "gpio not 0-31"],
+ [PI_BAD_GPIO , "gpio not 0-53"],
+ [PI_BAD_MODE , "mode not 0-7"],
+ [PI_BAD_LEVEL , "level not 0-1"],
+ [PI_BAD_PUD , "pud not 0-2"],
+ [PI_BAD_PULSEWIDTH , "pulsewidth not 0 or 500-2500"],
+ [PI_BAD_DUTYCYCLE , "dutycycle not 0-255"],
+ [_PI_BAD_TIMER , "timer not 0-9"],
+ [_PI_BAD_MS , "ms not 10-60000"],
+ [_PI_BAD_TIMETYPE , "timetype not 0-1"],
+ [_PI_BAD_SECONDS , "seconds < 0"],
+ [_PI_BAD_MICROS , "micros not 0-999999"],
+ [_PI_TIMER_FAILED , "gpioSetTimerFunc failed"],
+ [PI_BAD_WDOG_TIMEOUT , "timeout not 0-60000"],
+ [_PI_NO_ALERT_FUNC , "DEPRECATED"],
+ [_PI_BAD_CLK_PERIPH , "clock peripheral not 0-1"],
+ [_PI_BAD_CLK_SOURCE , "clock source not 0-1"],
+ [_PI_BAD_CLK_MICROS , "clock micros not 1, 2, 4, 5, 8, or 10"],
+ [_PI_BAD_BUF_MILLIS , "buf millis not 100-10000"],
+ [PI_BAD_DUTYRANGE , "dutycycle range not 25-40000"],
+ [_PI_BAD_SIGNUM , "signum not 0-63"],
+ [_PI_BAD_PATHNAME , "can't open pathname"],
+ [PI_NO_HANDLE , "no handle available"],
+ [PI_BAD_HANDLE , "unknown notify handle"],
+ [_PI_BAD_IF_FLAGS , "ifFlags > 3"],
+ [_PI_BAD_CHANNEL , "DMA channel not 0-14"],
+ [_PI_BAD_SOCKET_PORT , "socket port not 1024-30000"],
+ [_PI_BAD_FIFO_COMMAND , "unknown fifo command"],
+ [_PI_BAD_SECO_CHANNEL , "DMA secondary channel not 0-6"],
+ [_PI_NOT_INITIALISED , "function called before gpioInitialise"],
+ [_PI_INITIALISED , "function called after gpioInitialise"],
+ [_PI_BAD_WAVE_MODE , "waveform mode not 0-1"],
+ [_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"],
+ [_PI_BAD_WAVE_BAUD , "baud rate not 100-250000"],
+ [_PI_TOO_MANY_PULSES , "waveform has too many pulses"],
+ [_PI_TOO_MANY_CHARS , "waveform has too many chars"],
+ [_PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"],
+ [PI_NOT_PERMITTED , "no permission to update gpio"],
+ [PI_SOME_PERMITTED , "no permission to update one or more gpios"]
+]
+
+_control = None
+_notify = None
+
+_host = ''
+_port = 8888
+
+exceptions = True
+
+class _pigpioError(Exception):
+ """pigpio module exception"""
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+def error(pigpio_error):
+ """Converts a pigpio error number to a text description.
+
+ pigpio_error: an error number (<0) returned by pigpio.
+
+ Example
+ ...
+ print(pigpio.error(-5))
+ level not 0-1
+ ...
+ """
+ for e in _errors:
+ if e[0] == pigpio_error:
+ return e[1]
+ return "unknown error"
+
+def tickDiff(tStart, tEnd):
+ """Calculate the time difference between two ticks.
+
+ tStart: the earlier tick.
+ tEnd: the later tick.
+
+ The function handles wrap around as the tick overflows 32 bits.
+
+ The returned value is in microseconds.
+
+ Example
+ ...
+ print(pigpio.tickDiff(4294967272, 12))
+ 36
+ ...
+ """
+ tDiff = tEnd - tStart
+ if tDiff < 0:
+ tDiff += (1 << 32)
+ return tDiff
+
+def _u2i(number):
+ """Converts a number from unsigned to signed.
+
+ number: a 32 bit unsigned number
+ """
+ mask = (2 ** 32) - 1
+ if number & (1 << 31):
+ v = number | ~mask
+ else:
+ v = number & mask
+ if v >= 0:
+ return v;
+ else:
+ if exceptions:
+ raise _pigpioError(error(v))
+ else:
+ return v
+
+def _pigpio_command(sock, cmd, p1, p2):
+ """Executes a pigpio socket command.
+
+ sock: command socket.
+ cmd: the command to be executed.
+ p1: command paramter 1 (if applicable).
+ p2: command paramter 2 (if applicable).
+ """
+ if sock is not None:
+ sock.send(struct.pack('IIII', cmd, p1, p2, 0))
+ x, y, z, res = struct.unpack('IIII', sock.recv(16))
+ return res
+ else:
+ raise _pigpioError("*** Module not started, call pigpio.start() ***")
+
+class _callback:
+ """An ADT class to hold callback information."""
+
+ def __init__(self, gpio, edge, func):
+ """Initialises a callback ADT.
+
+ gpio: Broadcom gpio number.
+ edge: EITHER_EDGE, RISING_EDGE, or FALLING_EDGE.
+ func: a user function taking three arguments (gpio, level, tick).
+ """
+ self.gpio = gpio
+ self.edge = edge
+ self.func = func
+ self.bit = 1<= 0:
+ pigpio.notify_begin(h, 1234)
+ ...
+ """
+ r=_u2i(_pigpio_command(_control, _PI_CMD_NO, 0, 0))
+ return r
+
+def notify_begin(handle, bits):
+ """Start notifications on a previously opened handle.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+ bits: a mask indicating the gpios to be notified.
+
+ The notification sends state changes for each gpio whose
+ corresponding bit in bits is set.
+
+ Example
+ ...
+ h = pigpio.notify_open()
+ if h >= 0:
+ pigpio.notify_begin(h, 1234)
+ ...
+
+ This will start notifications for gpios 1, 4, 6, 7, 10
+ (1234 = 0x04D2 = 0b0000010011010010).
+
+ Notes
+
+ Each notification occupies 12 bytes in the fifo as follows:
+
+ H (16 bit) seqno
+ H (16 bit) flags
+ I (32 bit) tick
+ I (32 bit) level
+
+ """
+ r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, bits))
+ return r
+
+def notify_pause(handle):
+ """Pause notifications on a previously opened handle.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+
+ Notifications for the handle are suspended until
+ notify_begin() is called again.
+
+ Example
+ ...
+ h = pigpio.notify_open()
+ if h >= 0:
+ pigpio.notify_begin(h, 1234)
+ ...
+ pigpio.notify_pause(h)
+ ...
+ pigpio.notify_begin(h, 1234)
+ ...
+ ...
+ """
+ r=_u2i(_pigpio_command(_control, _PI_CMD_NB, handle, 0))
+ return r
+
+def notify_close(handle):
+ """Stop notifications on a previously opened handle and
+ release the handle for reuse.
+
+ Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+ handle: 0-31 (as returned by notify_open())
+
+ Example
+ ...
+ h = pigpio.notify_open()
+ if h >= 0:
+ pigpio.notify_begin(h, 1234)
+ ...
+ pigpio.notify_close(h)
+ ...
+ ...
+ """
+ r=_u2i(_pigpio_command(_control, _PI_CMD_NC, handle, 0))
+ return r
+
+def set_watchdog(user_gpio, timeout):
+ """Sets a watchdog for a gpio.
+
+ Returns 0 if OK, otherwise PI_BAD_USER_GPIO
+ or PI_BAD_WDOG_TIMEOUT.
+
+ user_gpio: 0-31.
+ timeout: 0-60000.
+
+ The watchdog is nominally in milliseconds.
+
+ Only one watchdog may be registered per gpio.
+
+ The watchdog may be cancelled by setting timeout to 0.
+
+ If no level change has been detected for the gpio for timeout
+ milliseconds any notification for the gpio has a report written
+ to the fifo with the flags set to indicate a watchdog timeout.
+
+ The callback() class interprets the flags and will
+ call registered callbacks for the gpio with level TIMEOUT.
+
+ Example
+
+ #!/usr/bin/python
+
+ import pigpio
+ import time
+
+ def cbf(g, L, t):
+ message = "gpio=" + str(g) + " level=" + str(L) + " at " + str(t)
+ print(message)
+
+ pigpio.start()
+
+ cb = pigpio.callback(22, pigpio.EITHER_EDGE, cbf)
+
+ print("callback started, 5 second delay")
+
+ time.sleep(5)
+
+ pigpio.set_watchdog(22, 1000) # 1000ms watchdog
+
+ print("watchdog started, 5 second delay")
+
+ time.sleep(5)
+
+ pigpio.set_watchdog(22, 0) # cancel watchdog
+
+ print("watchdog cancelled, 5 second delay")
+
+ time.sleep(5)
+
+ cb.cancel()
+
+ pigpio.stop()
+
+ will print lines such as
+
+ callback started, 5 second delay
+ watchdog started, 5 second delay
+ gpio=22 level=2 at 3547411617
+ gpio=22 level=2 at 3548411254
+ gpio=22 level=2 at 3549411927
+ gpio=22 level=2 at 3550412060
+ gpio=22 level=2 at 3551411622
+ watchdog cancelled, 5 second delay
+ """
+ r=_u2i(_pigpio_command(_control, _PI_CMD_WDOG, user_gpio, timeout))
+ return r
+
+def read_bank_1():
+ """Read the levels of the bank 1 gpios (gpios 0-31).
+
+ The returned 32 bit integer has a bit set if the corresponding
+ gpio is logic 1. Gpio n has bit value (1<
*/
/*
-This version is for pigpio version 4+
+This version is for pigpio version 7+
*/
#include
@@ -54,8 +54,10 @@ static unsigned clockMicros = PI_DEFAULT_CLK_MICROS;
static unsigned clockPeripheral = PI_DEFAULT_CLK_PERIPHERAL;
static unsigned clockSource = PI_DEFAULT_CLK_SOURCE;
static unsigned ifFlags = PI_DEFAULT_IF_FLAGS;
-static unsigned DMAchannelChannel = PI_DEFAULT_DMA_CHANNEL;
+static unsigned DMAprimaryChannel = PI_DEFAULT_DMA_PRIMARY_CHANNEL;
+static unsigned DMAsecondaryChannel = PI_DEFAULT_DMA_SECONDARY_CHANNEL;
static unsigned socketPort = PI_DEFAULT_SOCKET_PORT;
+static uint64_t updateMask = -1;
static FILE * errFifo;
@@ -64,13 +66,15 @@ void usage()
fprintf(stderr, "\n" \
"Usage: sudo pigpiod [OPTION] ...\n" \
" -b value, gpio sample buffer in milliseconds, default 120\n" \
- " -d value, DMA channel, 0-14, default 14\n" \
+ " -d value, primary DMA channel, 0-14, default 14\n" \
+ " -e value, secondary DMA channel, 0-6, default 5\n" \
" -f, disable fifo interface, default enabled\n" \
" -k, disable socket interface, default enabled\n" \
" -p value, socket port, 1024-32000, default 8888\n" \
" -s value, sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
" -t value, clock peripheral, 0=PWM 1=PCM, default PCM\n" \
" -u value, clock source, 0=OSC 1=PLLD, default PLLD\n" \
+ " -x mask, gpios which may be updated, default 0xFFFFFFFF\n" \
"EXAMPLE\n" \
"sudo pigpiod -s 2 -b 200 -f\n" \
" Set a sample rate of 2 microseconds with a 200 millisecond\n" \
@@ -81,8 +85,10 @@ void usage()
static void initOpts(int argc, char *argv[])
{
int i, opt;
+ uint64_t mask;
+ char * endptr;
- while ((opt = getopt(argc, argv, "b:d:fkp:s:t:u:")) != -1)
+ while ((opt = getopt(argc, argv, "b:d:e:fkp:s:t:u:x:")) != -1)
{
i = -1;
@@ -97,11 +103,18 @@ static void initOpts(int argc, char *argv[])
case 'd':
i = atoi(optarg);
- if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_DMA_CHANNEL))
- DMAchannelChannel = i;
+ if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_PRIMARY_CHANNEL))
+ DMAprimaryChannel = i;
else cmdFatal("invalid -d option (%d)", i);
break;
+ case 'e':
+ i = atoi(optarg);
+ if ((i >= PI_MIN_DMA_CHANNEL) && (i <= PI_MAX_SECONDARY_CHANNEL))
+ DMAsecondaryChannel = i;
+ else cmdFatal("invalid -e option (%d)", i);
+ break;
+
case 'f':
ifFlags |= PI_DISABLE_FIFO_IF;
break;
@@ -151,6 +164,13 @@ static void initOpts(int argc, char *argv[])
else cmdFatal("invalid -u option (%d)", i);
break;
+ case 'x':
+ mask = strtoll(optarg, &endptr, 0);
+ printf("mask=%llx\n", mask);
+ if (!*endptr) updateMask = mask;
+ else cmdFatal("invalid -x option (%s)", optarg);
+ break;
+
default: /* '?' */
usage();
exit(-1);
@@ -224,10 +244,12 @@ int main(int argc, char **argv)
gpioCfgInterfaces(ifFlags);
- gpioCfgDMAchannel(DMAchannelChannel);
+ gpioCfgDMAchannels(DMAprimaryChannel, DMAsecondaryChannel);
gpioCfgSocketPort(socketPort);
+ if (updateMask != -1) gpioCfgPermissions(updateMask);
+
/* start library */
if (gpioInitialise()< 0) cmdFatal("Can't initialise pigpio library");
@@ -275,4 +297,3 @@ int main(int argc, char **argv)
return 0;
}
-
diff --git a/pigs.c b/pigs.c
index e794632..7115304 100644
--- a/pigs.c
+++ b/pigs.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 3+
+This version is for pigpio version 7+
*/
#include
@@ -34,6 +34,8 @@ This version is for pigpio version 3+
#include
#include
#include
+#include
+#include
#include
#include "pigpio.h"
@@ -44,100 +46,123 @@ This program provides a socket interface
to the commands available from pigpio.
*/
+static int openSocket(void)
+{
+ int sock, err;
+ struct addrinfo hints, *res, *rp;
+ const char *addrStr, *portStr;
+
+ portStr = getenv(PI_ENVPORT);
+
+ if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
+
+ addrStr = getenv(PI_ENVADDR);
+
+ if (!addrStr) addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
+
+ memset (&hints, 0, sizeof (hints));
+
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags |= AI_CANONNAME;
+
+ err = getaddrinfo(addrStr, portStr, &hints, &res);
+
+ if (err) return -1;
+
+ for (rp=res; rp!=NULL; rp=rp->ai_next)
+ {
+ 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 -1;
+
+ return sock;
+}
+
int main(int argc , char *argv[])
{
- int sock, r, idx, port;
- struct sockaddr_in server;
+ int sock, r, idx;
cmdCmd_t cmd;
- char * portStr, * addrStr;
char buf[128];
-
- sock = socket(AF_INET, SOCK_STREAM, 0);
-
+
+ sock = openSocket();
+
if (sock != -1)
{
- portStr = getenv(PI_ENVPORT);
-
- if (portStr) port = atoi(portStr);
- else port = PI_DEFAULT_SOCKET_PORT;
-
- addrStr = getenv(PI_ENVADDR);
-
- if (!addrStr) addrStr="127.0.0.1";
-
- server.sin_addr.s_addr = inet_addr(addrStr);
- server.sin_family = AF_INET;
- server.sin_port = htons(port);
-
- if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0)
+ switch(argc)
{
- switch(argc)
- {
- case 1:
- exit(0);
+ case 1:
+ exit(0);
- case 2:
- sprintf(buf, "%10s", argv[1]);
- break;
+ case 2:
+ sprintf(buf, "%10s", argv[1]);
+ break;
- case 3:
- sprintf(buf, "%10s %10s", argv[1], argv[2]);
- break;
+ case 3:
+ sprintf(buf, "%10s %10s", argv[1], argv[2]);
+ break;
- case 4:
- sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
- break;
+ case 4:
+ sprintf(buf, "%10s %10s %10s", argv[1], argv[2], argv[3]);
+ break;
- default:
- cmdFatal("what?");
- }
-
- if ((idx=cmdParse(buf, &cmd)) >= 0)
- {
- if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
- {
- if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
- {
- switch (cmdInfo[idx].rv)
- {
- case 0:
- r = cmd.res;
- if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
- break;
-
- case 1:
- break;
-
- case 2:
- r = cmd.res;
- if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
- else printf("%d\n", r);
- break;
-
- case 3:
- printf("%08X\n", cmd.res);
- break;
-
- case 4:
- printf("%u\n", cmd.res);
- break;
-
- case 5:
- printf(cmdUsage);
- break;
- }
- }
- else cmdFatal("recv failed, %m");
- }
- else cmdFatal("send failed, %m");
- }
- else cmdFatal("what?");
+ default:
+ cmdFatal("what?");
}
- else cmdFatal("connect failed, %m");
- close(sock);
+ if ((idx=cmdParse(buf, &cmd)) >= 0)
+ {
+ if (send(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+ {
+ if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
+ {
+ switch (cmdInfo[idx].rv)
+ {
+ case 0:
+ r = cmd.res;
+ if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+ break;
+
+ case 1:
+ r = cmd.res;
+ if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+ break;
+
+ case 2:
+ r = cmd.res;
+ if (r < 0) cmdFatal("ERROR: %s", cmdErrStr(r));
+ else printf("%d\n", r);
+ break;
+
+ case 3:
+ printf("%08X\n", cmd.res);
+ break;
+
+ case 4:
+ printf("%u\n", cmd.res);
+ break;
+
+ case 5:
+ printf(cmdUsage);
+ break;
+ }
+ }
+ else cmdFatal("recv failed, %m");
+ }
+ else cmdFatal("send failed, %m");
+ }
+ else cmdFatal("what?");
}
- else cmdFatal("socket failed, %m");
+ else cmdFatal("connect failed, %m");
+
+ close(sock);
return 0;
}
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..ceff7d9
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+
+setup(name='pigpio',
+ version='1.0',
+ description='Raspberry Pi gpio utility',
+ author='joan',
+ author_email='joan@abyz.me.uk',
+ url='http://abyz.co.uk/rpi/pigpio/python.html/',
+ py_modules=['pigpio']
+ )