V57
authorjoan <joan@abyz.co.uk>
Sun, 30 Oct 2016 15:30:20 +0000 (15:30 +0000)
committerjoan <joan@abyz.co.uk>
Sun, 30 Oct 2016 15:30:20 +0000 (15:30 +0000)
15 files changed:
command.c
command.h
pigpio.3
pigpio.c
pigpio.h
pigpio.py
pigpiod_if.3
pigpiod_if.h
pigpiod_if2.3
pigpiod_if2.c
pigpiod_if2.h
pigs.1
pigs.c
setup.py
x_pigs

index 2a5d0dc5104536a66fdd57df6fa0e220305541de..82e1c7458641e242c8b503caee779a00c19cb668 100644 (file)
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 56+
+This version is for pigpio version 57+
 */
 
 #include <stdio.h>
@@ -55,6 +55,8 @@ cmdInfo_t cmdInfo[]=
    {PI_CMD_BS1,   "BS1",   111, 1}, // gpioWrite_Bits_0_31_Set
    {PI_CMD_BS2,   "BS2",   111, 1}, // gpioWrite_Bits_32_53_Set
 
+   {PI_CMD_BSCX,  "BSCX",  193, 8}, // bscXfer
+
    {PI_CMD_BSPIC, "BSPIC", 112, 0}, // bbSPIClose
    {PI_CMD_BSPIO, "BSPIO", 134, 0}, // bbSPIOpen
    {PI_CMD_BSPIX, "BSPIX", 193, 6}, // bbSPIXfer
@@ -65,6 +67,9 @@ cmdInfo_t cmdInfo[]=
    {PI_CMD_CGI,   "CGI",   101, 4}, // gpioCfgGetInternals
    {PI_CMD_CSI,   "CSI",   111, 1}, // gpioCfgSetInternals
 
+   {PI_CMD_EVM,   "EVM",   122, 1}, // eventMonitor
+   {PI_CMD_EVT,   "EVT",   112, 0}, // eventTrigger
+
    {PI_CMD_FC,    "FC",    112, 0}, // fileClose
 
    {PI_CMD_FG,    "FG",    121, 0}, // gpioGlitchFilter
@@ -217,6 +222,7 @@ cmdInfo_t cmdInfo[]=
    {PI_CMD_DCR  , "DCR"  , 113, 0},
    {PI_CMD_DCRA , "DCRA" , 101, 0},
    {PI_CMD_DIV  , "DIV"  , 111, 0},
+   {PI_CMD_EVTWT, "EVTWT", 111, 0},
    {PI_CMD_HALT , "HALT" , 101, 0},
    {PI_CMD_INR  , "INR"  , 113, 0},
    {PI_CMD_INRA , "INRA" , 101, 0},
@@ -267,15 +273,21 @@ BSPIX cs ...    SPI bit bang transfer\n\
 \n\
 BR1              Read bank 1 GPIO\n\
 BR2              Read bank 2 GPIO\n\
+\n\
 BS1 bits         Set GPIO in bank 1\n\
 BS2 bits         Set GPIO in bank 2\n\
 \n\
+BSCX bctl bvs    BSC I2C/SPI transfer\n\
+\n\
 CF1 ...          Custom function 1\n\
 CF2 ...          Custom function 2\n\
 \n\
 CGI              Configuration get internals\n\
 CSI v            Configuration set internals\n\
 \n\
+EVM h bits       Set events to monitor\n\
+EVT n            Trigger event\n\
+\n\
 FC h             Close file handle\n\
 FG g steady      Set glitch filter on GPIO\n\
 FL pat n         List files which match pattern\n\
@@ -547,6 +559,7 @@ static errInfo_t errInfo[]=
    {PI_BAD_SCRIPT_NAME  , "bad script name"},
    {PI_BAD_SPI_BAUD     , "bad SPI baud rate, not 50-500k"},
    {PI_NOT_SPI_GPIO     , "no bit bang SPI in progress on GPIO"},
+   {PI_BAD_EVENT_ID     , "bad event id"},
 
 };
 
@@ -1018,10 +1031,12 @@ int cmdParse(
 
          break;
 
-      case 193: /* BI2CZ  FW  I2CWD  I2CZ  SERW  SPIW  SPIX
-                   BSPIX
+      case 193: /* BI2CZ  BSCX  BSPIX  FW  I2CWD  I2CZ  SERW
+                  SPIW  SPIX
 
                    Two or more parameters, first >=0, rest 0-255.
+
+                  BSCX is special case one or more.
                 */
          ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[1]);
 
@@ -1048,7 +1063,7 @@ int cmdParse(
 
             p[3] = pars;
 
-            if (pars) valid = 1;
+            if (pars || (p[0]==PI_CMD_BSCX)) valid = 1;
          }
 
          break;
index c27d64f050caa174189f6673e70a58918a8cf331..eede5929dbb8e1cc97ed8f2c044e18735d56a3f8 100644 (file)
--- a/command.h
+++ b/command.h
@@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
 */
 
 /*
-This version is for pigpio version 56+
+This version is for pigpio version 57+
 */
 
 #ifndef COMMAND_H
index 6902953105b6506e8459a373d8fce5d83903bb9a..47e6a8aa2b32456bde6ef0d495965baf572033a8 100644 (file)
--- a/pigpio.3
+++ b/pigpio.3
@@ -1484,23 +1484,30 @@ by one for each report.
 .br
 
 .br
-flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE.
+flags: three flags are defined, PI_NTFY_FLAGS_WDOG,
+PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT.
 
 .br
 
 .br
-PI_NTFY_FLAGS_WDOG, if bit 5 is set then bits 0-4 of the flags
+If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags
 indicate a GPIO which has had a watchdog timeout.
 
 .br
 
 .br
-PI_NTFY_FLAGS_ALIVE, if bit 6 is set this indicates a keep alive
+If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive
 signal on the pipe/socket and is sent once a minute in the absence
 of other notification activity.
 
 .br
 
+.br
+If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the flags
+indicate an event which has been triggered.
+
+.br
+
 .br
 tick: the number of microseconds since system boot.  It wraps around
 after 1h12m.
@@ -3453,6 +3460,249 @@ End
 
 .EE
 
+.IP "\fBint bscXfer(bsc_xfer_t *bsc_xfer)\fP"
+.IP "" 4
+This function provides a low-level interface to the
+SPI/I2C Slave peripheral.  This peripheral allows the
+Pi to act as a slave device on an I2C or SPI bus.
+
+.br
+
+.br
+I can't get SPI to work properly.  I tried with a
+control word of 0x303 and swapped MISO and MOSI.
+
+.br
+
+.br
+The function sets the BSC mode, writes any data in
+the transmit buffer to the BSC transmit FIFO, and
+copies any data in the BSC receive FIFO to the
+receive buffer.
+
+.br
+
+.br
+
+.EX
+bsc_xfer:= a structure defining the transfer
+.br
+
+.br
+typedef struct
+.br
+{
+.br
+   uint32_t control;          // Write
+.br
+   int rxCnt;                 // Read only
+.br
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+.br
+   int txCnt;                 // Write
+.br
+   char txBuf[BSC_FIFO_SIZE]; // Write
+.br
+} bsc_xfer_t;
+.br
+
+.EE
+
+.br
+
+.br
+To start a transfer set control (see below) and copy the bytes to
+be sent (if any) to txBuf and set the byte count in txCnt.
+
+.br
+
+.br
+Upon return rxCnt will be set to the number of received bytes placed
+in rxBuf.
+
+.br
+
+.br
+Note that the control word sets the BSC mode.  The BSC will stay in
+that mode until a different control word is sent.
+
+.br
+
+.br
+The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL) in I2C mode
+and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO), and 21 (CE) in SPI mode.  You
+need to swap MISO/MOSI between master and slave.
+
+.br
+
+.br
+When a zero control word is received GPIO 18-21 will be reset
+to INPUT mode.
+
+.br
+
+.br
+The returned function value is the status of the transfer (see below).
+
+.br
+
+.br
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+.br
+
+.br
+The most significant word of the returned status contains the number
+of bytes actually copied from txBuf to the BSC transmit FIFO (may be
+less than requested if the FIFO already contained untransmitted data).
+
+.br
+
+.br
+control consists of the following bits.
+
+.br
+
+.br
+
+.EX
+22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+.br
+
+.EE
+
+.br
+
+.br
+Bits 0-13 are copied unchanged to the BSC CR register.  See
+pages 163-165 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.br
+aaaaaaa   defines the I2C slave address (only relevant in I2C mode)
+.br
+IT        invert transmit status flags
+.br
+HC        enable host control
+.br
+TF        enable test FIFO
+.br
+IR        invert receive status flags
+.br
+RE        enable receive
+.br
+TE        enable transmit
+.br
+BK        abort operation and clear FIFOs
+.br
+EC        send control register as first I2C byte
+.br
+ES        send status register as first I2C byte
+.br
+PL        set SPI polarity high
+.br
+PH        set SPI phase high
+.br
+I2        enable I2C mode
+.br
+SP        enable SPI mode
+.br
+EN        enable BSC peripheral
+.br
+
+.br
+
+.br
+The returned status has the following format
+
+.br
+
+.br
+
+.EX
+20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+.br
+
+.EE
+
+.br
+
+.br
+Bits 0-15 are copied unchanged from the BSC FR register.  See
+pages 165-166 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.br
+SSSSS   number of bytes successfully copied to transmit FIFO
+.br
+RRRRR   number of bytes in receieve FIFO
+.br
+TTTTT   number of bytes in transmit FIFO
+.br
+RB      receive busy
+.br
+TE      transmit FIFO empty
+.br
+RF      receive FIFO full
+.br
+TF      transmit FIFO full
+.br
+RE      receive FIFO empty
+.br
+TB      transmit busy
+.br
+
+.br
+
+.br
+The following example shows how to configure the BSC peripheral as
+an I2C slave with address 0x13 and send four bytes.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+bsc_xfer_t xfer;
+.br
+
+.br
+xfer.control = (0x13<<16) | 0x305;
+.br
+
+.br
+memcpy(xfer.txBuf, "ABCD", 4);
+.br
+xfer.txCnt = 4;
+.br
+
+.br
+status = bscXfer(&xfer);
+.br
+
+.br
+if (status >= 0)
+.br
+{
+.br
+   // process transfer
+.br
+}
+.br
+
+.EE
+
 .IP "\fBint bbSPIOpen(unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spiFlags)\fP"
 .IP "" 4
 This function selects a set of GPIO for bit banging SPI with
@@ -4097,6 +4347,11 @@ handle: >=0, as returned by a call to \fBserOpen\fP
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
 
+.br
+
+.br
+If no data is ready PI_SER_READ_NO_DATA is returned.
+
 .IP "\fBint serWrite(unsigned handle, char *buf, unsigned count)\fP"
 .IP "" 4
 This function writes count bytes from buf to the the serial port
@@ -4144,9 +4399,14 @@ handle: >=0, as returned by a call to \fBserOpen\fP
 .br
 
 .br
-Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, or PI_SER_READ_NO_DATA.
 
+.br
+
+.br
+If no data is ready zero is returned.
+
 .IP "\fBint serDataAvailable(unsigned handle)\fP"
 .IP "" 4
 This function returns the number of bytes available
@@ -5519,6 +5779,191 @@ gpioSetPad(0, 16); // set pad 0 strength to 16 mA
 
 .EE
 
+.IP "\fBint eventMonitor(unsigned handle, uint32_t bits)\fP"
+.IP "" 4
+This function selects the events to be reported on a previously
+opened handle.
+
+.br
+
+.br
+
+.EX
+handle: >=0, as returned by \fBgpioNotifyOpen\fP
+.br
+  bits: a bit mask indicating the events of interest
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+.br
+
+.br
+A report is sent each time an event is triggered providing the
+corresponding bit in bits is set.
+
+.br
+
+.br
+See \fBgpioNotifyBegin\fP for the notification format.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+// Start reporting events 3, 6, and 7.
+.br
+
+.br
+//  bit      76543210
+.br
+// (0xC8 = 0b11001000)
+.br
+
+.br
+eventMonitor(h, 0xC8);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBint eventSetFunc(unsigned event, eventFunc_t f)\fP"
+.IP "" 4
+Registers a function to be called (a callback) when the specified
+event occurs.
+
+.br
+
+.br
+
+.EX
+event: 0-31
+.br
+    f: the callback function
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+.br
+
+.br
+One function may be registered per event.
+
+.br
+
+.br
+The function is passed the event, and the tick.
+
+.br
+
+.br
+The callback may be cancelled by passing NULL as the function.
+
+.IP "\fBint eventSetFuncEx(unsigned event, eventFuncEx_t f, void *userdata)\fP"
+.IP "" 4
+Registers a function to be called (a callback) when the specified
+event occurs.
+
+.br
+
+.br
+
+.EX
+   event: 0-31
+.br
+       f: the callback function
+.br
+userdata: pointer to arbitrary user data
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+.br
+
+.br
+One function may be registered per event.
+
+.br
+
+.br
+The function is passed the event, the tick, and the ueserdata pointer.
+
+.br
+
+.br
+The callback may be cancelled by passing NULL as the function.
+
+.br
+
+.br
+Only one of \fBeventSetFunc\fP or \fBeventSetFuncEx\fP can be
+registered per event.
+
+.IP "\fBint eventTrigger(unsigned event)\fP"
+.IP "" 4
+This function signals the occurrence of an event.
+
+.br
+
+.br
+
+.EX
+event: 0-31, the event
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+.br
+
+.br
+An event is a signal used to inform one or more consumers
+to start an action.  Each consumer which has registered an interest
+in the event (e.g. by calling \fBeventSetFunc\fP) will be informed by
+a callback.
+
+.br
+
+.br
+One event, PI_EVENT_BSC (31) is predefined.  This event is
+auto generated on BSC slave activity.
+
+.br
+
+.br
+The meaning of other events is arbitrary.
+
+.br
+
+.br
+Note that other than its id and its tick there is no data associated
+with an event.
+
 .IP "\fBint shell(char *scriptName, char *scriptString)\fP"
 .IP "" 4
 This function uses the system call to execute a shell script
@@ -7045,6 +7490,43 @@ e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
 
 .br
 
+.IP "\fB*bsc_xfer\fP" 0
+A pointer to a \fBbsc_xfer_t\fP object used to control a BSC transfer.
+
+.br
+
+.br
+
+.IP "\fBbsc_xfer_t\fP" 0
+
+.br
+
+.br
+
+.EX
+typedef struct
+.br
+{
+.br
+   uint32_t control;          // Write
+.br
+   int rxCnt;                 // Read only
+.br
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+.br
+   int txCnt;                 // Write
+.br
+   char txBuf[BSC_FIFO_SIZE]; // Write
+.br
+} bsc_xfer_t;
+.br
+
+.EE
+
+.br
+
+.br
+
 .IP "\fB*buf\fP" 0
 
 .br
@@ -7282,7 +7764,7 @@ The number may vary between 0 and range (default 255) where
 .br
 
 .IP "\fBedge\fP: 0-2" 0
-The type of GPIO edge to generate an intrrupt.  See \fBgpioSetISRFunc\fP,
+The type of GPIO edge to generate an interrupt.  See \fBgpioSetISRFunc\fP
 and \fBgpioSetISRFuncEx\fP.
 
 .br
@@ -7303,6 +7785,40 @@ EITHER_EDGE 2
 
 .br
 
+.IP "\fBevent\fP: 0-31" 0
+An event is a signal used to inform one or more consumers
+to start an action.
+
+.br
+
+.br
+
+.IP "\fBeventFunc_t\fP" 0
+
+.EX
+typedef void (*eventFunc_t) (int event, uint32_t tick);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBeventFuncEx_t\fP" 0
+
+.EX
+typedef void (*eventFuncEx_t)
+.br
+   (int event, uint32_t tick, void *userdata);
+.br
+
+.EE
+
+.br
+
+.br
+
 .IP "\fBf\fP" 0
 
 .br
@@ -7425,9 +7941,9 @@ typedef void (*gpioAlertFunc_t) (int gpio, int level, uint32_t tick);
 .IP "\fBgpioAlertFuncEx_t\fP" 0
 
 .EX
-typedef void (*gpioAlertFuncEx_t)
+typedef void (*eventFuncEx_t)
 .br
-   (int gpio, int level, uint32_t tick, void *userdata);
+   (int event, int level, uint32_t tick, void *userdata);
 .br
 
 .EE
@@ -7649,8 +8165,20 @@ One of
 .br
 
 .br
-A number referencing an object opened by one of \fBfileOpen\fP,
-\fBgpioNotifyOpen\fP, \fBi2cOpen\fP, \fBserOpen\fP, \fBspiOpen\fP.
+A number referencing an object opened by one of
+
+.br
+
+.br
+\fBfileOpen\fP
+.br
+\fBgpioNotifyOpen\fP
+.br
+\fBi2cOpen\fP
+.br
+\fBserOpen\fP
+.br
+\fBspiOpen\fP
 
 .br
 
@@ -8137,6 +8665,10 @@ A thread identifier.
 The setting of the pull up/down resistor for a GPIO, which may be off,
 pull-up, or pull-down.
 
+.br
+
+.br
+
 .EX
 PI_PUD_OFF 0
 .br
@@ -8820,16 +9352,24 @@ In the calling function:
 .br
 
 .br
+
+.EX
 user_type *userdata;
 .br
+.br
+.br
 user_type my_userdata;
-
 .br
 
 .br
 userdata = malloc(sizeof(user_type));
 .br
+.br
+.br
 *userdata = my_userdata;
+.br
+
+.EE
 
 .br
 
@@ -8839,12 +9379,16 @@ In the receiving function:
 .br
 
 .br
-user_type my_userdata = *(user_type*)userdata;
 
+.EX
+user_type my_userdata = *(user_type*)userdata;
 .br
 
 .br
 free(userdata);
+.br
+
+.EE
 
 .br
 
@@ -9182,6 +9726,16 @@ A 16-bit word value.
 #define PI_CMD_BSPIX 113
 .br
 
+.br
+#define PI_CMD_BSCX  114
+.br
+
+.br
+#define PI_CMD_EVM   115
+.br
+#define PI_CMD_EVT   116
+.br
+
 .br
 
 .EE
@@ -9480,6 +10034,8 @@ A 16-bit word value.
 .br
 #define PI_NOT_SPI_GPIO    -142 // no bit bang SPI in progress on GPIO
 .br
+#define PI_BAD_EVENT_ID    -143 // bad event id
+.br
 
 .br
 #define PI_PIGIF_ERR_0    -2000
index 4ad429b4d9a80c833c985cd0ea96ad34ffcd6934..912f689d514378c7f0bb660c376bd4ce1c8f6b85 100644 (file)
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 For more information, please refer to <http://unlicense.org/>
 */
 
-/* pigpio version 56 */
+/* pigpio version 57 */
 
 /* include ------------------------------------------------------- */
 
@@ -298,6 +298,7 @@ bit 0 READ_LAST_NOT_SET_ERROR
 #define PI_PERI_BUS 0x7E000000
 
 #define AUX_BASE   (pi_peri_phys + 0x00215000)
+#define BSCS_BASE  (pi_peri_phys + 0x00214000)
 #define CLK_BASE   (pi_peri_phys + 0x00101000)
 #define DMA_BASE   (pi_peri_phys + 0x00007000)
 #define DMA15_BASE (pi_peri_phys + 0x00E05000)
@@ -309,6 +310,7 @@ bit 0 READ_LAST_NOT_SET_ERROR
 #define SYST_BASE  (pi_peri_phys + 0x00003000)
 
 #define AUX_LEN   0xD8
+#define BSCS_LEN  0x40
 #define CLK_LEN   0xA8
 #define DMA_LEN   0x1000 /* allow access to all channels */
 #define GPIO_LEN  0xB4
@@ -922,6 +924,15 @@ typedef struct
 
 } gpioAlert_t;
 
+typedef struct
+{
+   callbk_t func;
+   unsigned ex;
+   void *userdata;
+   int ignore;
+   int fired;
+} eventAlert_t;
+
 typedef struct
 {
    unsigned gpio;
@@ -968,6 +979,7 @@ typedef struct
    unsigned request;
    unsigned run_state;
    uint32_t waitBits;
+   uint32_t eventBits;
    uint32_t changedBits;
    pthread_t *pthIdp;
    pthread_mutex_t pthMutex;
@@ -987,6 +999,7 @@ typedef struct
    uint16_t seqno;
    uint16_t state;
    uint32_t bits;
+   uint32_t eventBits;
    uint32_t lastReportTick;
    int      fd;
    int      pipe;
@@ -1232,6 +1245,8 @@ static volatile uint32_t gFilterBits = 0;
 static volatile uint32_t nFilterBits = 0;
 static volatile uint32_t wdogBits    = 0;
 
+static volatile uint32_t scriptEventBits  = 0;
+
 static volatile int runState = PI_STARTING;
 
 static int pthAlertRunning  = 0;
@@ -1240,6 +1255,8 @@ static int pthSocketRunning = 0;
 
 static gpioAlert_t      gpioAlert  [PI_MAX_USER_GPIO+1];
 
+static eventAlert_t     eventAlert [PI_MAX_EVENT+1];
+
 static gpioISR_t        gpioISR    [PI_MAX_USER_GPIO+1];
 
 static gpioGetSamples_t gpioGetSamples;
@@ -1289,6 +1306,7 @@ static dmaOPage_t * * dmaOVirt = MAP_FAILED;
 static dmaOPage_t * * dmaOBus = MAP_FAILED;
 
 static volatile uint32_t * auxReg  = MAP_FAILED;
+static volatile uint32_t * bscsReg = MAP_FAILED;
 static volatile uint32_t * clkReg  = MAP_FAILED;
 static volatile uint32_t * dmaReg  = MAP_FAILED;
 static volatile uint32_t * gpioReg = MAP_FAILED;
@@ -1351,6 +1369,8 @@ static unsigned old_mode_amosi;
 static uint32_t old_spi_cntl0;
 static uint32_t old_spi_cntl1;
 
+static uint32_t bscFR;
+
 /* const --------------------------------------------------------- */
 
 static const uint8_t clkDef[PI_MAX_GPIO + 1] =
@@ -1445,6 +1465,8 @@ static void intNotifyBits(void);
 
 static void intScriptBits(void);
 
+static void intScriptEventBits(void);
+
 static int  gpioNotifyOpenInBand(int fd);
 
 static void initHWClk
@@ -1805,6 +1827,7 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
    uint32_t mask;
    uint32_t tmp1, tmp2, tmp3, tmp4, tmp5;
    gpioPulse_t *pulse;
+   bsc_xfer_t xfer;
    int masked;
    res = 0;
 
@@ -1857,6 +1880,20 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
          }
          break;
 
+      case PI_CMD_BSCX:
+         xfer.control = p[1];
+         if (p[3] > BSC_FIFO_SIZE) p[3] = BSC_FIFO_SIZE;
+         xfer.txCnt = p[3];
+         if (p[3]) memcpy(&xfer.txBuf, buf, p[3]);
+         res = bscXfer(&xfer);
+         if (res >= 0)
+         {
+            memcpy(buf, &res, 4);
+            res = 4 + xfer.rxCnt;
+            if (res > 4) memcpy(buf+4, &xfer.rxBuf, res-4);
+         }
+         break;
+
       case PI_CMD_BSPIO:
 
          memcpy(&tmp1, buf+ 0, 4); // MISO
@@ -1952,6 +1989,10 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
 
       case PI_CMD_CSI: res = gpioCfgSetInternals(p[1]); break;
 
+      case PI_CMD_EVM: res = eventMonitor(p[1], p[2]); break;
+
+      case PI_CMD_EVT: res = eventTrigger(p[1]); break;
+
       case PI_CMD_FC: res = fileClose(p[1]); break;
 
       case PI_CMD_FG:
@@ -4807,6 +4848,7 @@ int serWriteByte(unsigned handle, unsigned bVal)
 
 int serReadByte(unsigned handle)
 {
+   int r;
    char x;
 
    DBG(DBG_USER, "handle=%d", handle);
@@ -4819,15 +4861,19 @@ int serReadByte(unsigned handle)
    if (serInfo[handle].state != PI_SER_OPENED)
       SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
 
-   if (read(serInfo[handle].fd, &x, 1) != 1)
-   {
-      if (errno == EAGAIN)
-         return PI_SER_READ_NO_DATA;
-      else
-         return PI_SER_READ_FAILED;
-   }
+   r = read(serInfo[handle].fd, &x, 1);
+
+   if (r == 1)
+      return ((int)x) & 0xFF;
+
+   else if (r == 0)
+      return PI_SER_READ_NO_DATA;
+
+   else if ((r == -1) && (errno == EAGAIN))
+      return PI_SER_READ_NO_DATA;
 
-   return ((int)x) & 0xFF;
+   else
+      return PI_SER_READ_FAILED;
 }
 
 int serWrite(unsigned handle, char *buf, unsigned count)
@@ -4880,7 +4926,7 @@ int serRead(unsigned handle, char *buf, unsigned count)
    }
    else
    {
-      buf[r] = 0;
+      if (r < count) buf[r] = 0;
       return r;
    }
 }
@@ -5562,7 +5608,7 @@ static void alertEmit(
    uint32_t oldLevel, newLevel;
    int32_t diff;
    int emit, seqno, emitted;
-   uint32_t changes, bits, timeoutBits;
+   uint32_t changes, bits, timeoutBits, eventBits;
    int d;
    int b, n, v;
    int err;
@@ -5586,6 +5632,36 @@ static void alertEmit(
       }
    }
 
+   eventBits = 0;
+
+   if (bscFR != (bscsReg[BSC_FR]&0xffff))
+   {
+      bscFR = bscsReg[BSC_FR]&0xffff;
+      eventAlert[PI_EVENT_BSC].fired = 1;
+   }
+
+   for (b=0; b<=PI_MAX_EVENT; b++)
+   {
+      if (eventAlert[b].fired && (!eventAlert[b].ignore))
+      {
+         eventBits |= (1<<b);
+
+         if (eventAlert[b].func)
+         {
+            if (eventAlert[b].ex)
+            {
+               (eventAlert[b].func)(b, eTick, eventAlert[b].userdata);
+            }
+            else
+            {
+               (eventAlert[b].func)(b, eTick);
+            }
+         }
+      }
+
+      eventAlert[b].fired = 0;
+   }
+
    /* call alert callbacks for each bit transition */
 
    if (changedBits & alertBits)
@@ -5677,7 +5753,7 @@ static void alertEmit(
 
          gpioNotify[n].state = PI_NOTIFY_CLOSED;
       }
-      else if (gpioNotify[n].state == PI_NOTIFY_RUNNING)
+      else if (gpioNotify[n].state != PI_NOTIFY_CLOSED)
       {
          bits = gpioNotify[n].bits;
 
@@ -5685,54 +5761,85 @@ static void alertEmit(
 
          seqno = gpioNotify[n].seqno;
 
-         /* check to see if any bits have changed for this
-            notification.
+         if (gpioNotify[n].state == PI_NOTIFY_RUNNING)
+         {
+            /* check to see if any bits have changed for this
+               notification.
 
-            bits         is the set of notification bits
-            changedBits is the set of changed bits
-         */
+               bits         is the set of notification bits
+               changedBits is the set of changed bits
+            */
 
-         if (changedBits & bits)
-         {
-            oldLevel = reportedLevel & bits;
+            if (changedBits & bits)
+            {
+               oldLevel = reportedLevel & bits;
+
+               for (d=0; d<numSamples; d++)
+               {
+                  newLevel = sample[d].level & bits;
+
+                  if (newLevel != oldLevel)
+                  {
+                     report[emit].seqno = seqno;
+                     report[emit].flags = 0;
+                     report[emit].tick  = sample[d].tick;
+                     report[emit].level = sample[d].level;
 
-            for (d=0; d<numSamples; d++)
+                     oldLevel = newLevel;
+
+                     emit++;
+                     seqno++;
+                  }
+               }
+            }
+
+            /* check to see if any watchdogs are due for this
+               notification.
+
+               bits        is the set of notification bits
+               timeoutBits is the set of timed out bits
+            */
+
+            bits = gpioNotify[n].bits;
+
+            if (timeoutBits & bits)
             {
-               newLevel = sample[d].level & bits;
+               /* at least one watchdog has fired for this
+                  notification.
+               */
 
-               if (newLevel != oldLevel)
+               for (b=0; b<=PI_MAX_USER_GPIO; b++)
                {
-                  report[emit].seqno = seqno;
-                  report[emit].flags = 0;
-                  report[emit].tick  = sample[d].tick;
-                  report[emit].level = sample[d].level;
+                  if (timeoutBits & bits & (1<<b))
+                  {
+                     if (numSamples)
+                        newLevel = sample[numSamples-1].level;
+                     else
+                        newLevel = reportedLevel;
 
-                  oldLevel = newLevel;
+                     report[emit].seqno = seqno;
+                     report[emit].flags =
+                        PI_NTFY_FLAGS_WDOG | PI_NTFY_FLAGS_BIT(b);
+                     report[emit].tick  = eTick;
+                     report[emit].level = newLevel;
 
-                  emit++;
-                  seqno++;
+                     emit++;
+                     seqno++;
+                  }
                }
             }
          }
 
-         /* check to see if any watchdogs are due for this
-            notification.
+         /* check to see if any events are due
 
-            bits        is the set of notification bits
-            timeoutBits is the set of timed out bits
+            eventBits is the set of events
          */
 
-         bits = gpioNotify[n].bits;
-
-         if (timeoutBits & bits)
+         if (eventBits & gpioNotify[n].eventBits)
          {
-            /* at least one watchdog has fired for this
-               notification.
-            */
-
-            for (b=0; b<=PI_MAX_USER_GPIO; b++)
+            for (b=0; b<=PI_MAX_EVENT; b++)
             {
-               if (timeoutBits & bits & (1<<b))
+               if (eventBits & gpioNotify[n].eventBits & (1<<b))
                {
                   if (numSamples)
                      newLevel = sample[numSamples-1].level;
@@ -5740,8 +5847,8 @@ static void alertEmit(
                      newLevel = reportedLevel;
 
                   report[emit].seqno = seqno;
-                  report[emit].flags = PI_NTFY_FLAGS_WDOG |
-                                           PI_NTFY_FLAGS_BIT(b);
+                  report[emit].flags = 
+                     PI_NTFY_FLAGS_EVENT | PI_NTFY_FLAGS_BIT(b);
                   report[emit].tick  = eTick;
                   report[emit].level = newLevel;
 
@@ -5895,6 +6002,28 @@ static void alertEmit(
       }
    }
 
+   if (eventBits & scriptEventBits)
+   {
+      for (n=0; n<PI_MAX_SCRIPTS; n++)
+      {
+         if ((gpioScript[n].state     == PI_SCRIPT_IN_USE)  &&
+             (gpioScript[n].run_state == PI_SCRIPT_WAITING) &&
+             (gpioScript[n].eventBits & eventBits))
+         {
+            pthread_mutex_lock(&gpioScript[n].pthMutex);
+
+            if (gpioScript[n].run_state == PI_SCRIPT_WAITING)
+            {
+               gpioScript[n].changedBits =
+                  gpioScript[n].eventBits & eventBits;
+               pthread_cond_signal(&gpioScript[n].pthCond);
+            }
+
+            pthread_mutex_unlock(&gpioScript[n].pthMutex);
+         }
+      }
+   }
+
    if (numSamples) reportedLevel = sample[numSamples-1].level;
 }
 
@@ -6206,6 +6335,30 @@ static void scrSwap(int *v1, int *v2)
 
 /* ----------------------------------------------------------------------- */
 
+static int scrEvtWait(gpioScript_t *s, uint32_t bits)
+{
+   pthread_mutex_lock(&s->pthMutex);
+
+   if (s->request == PI_SCRIPT_RUN)
+   {
+      s->run_state = PI_SCRIPT_WAITING;
+      s->eventBits = bits;
+      intScriptEventBits();
+
+      pthread_cond_wait(&s->pthCond, &s->pthMutex);
+
+      s->waitBits = 0;
+      intScriptEventBits();
+      s->run_state = PI_SCRIPT_RUNNING;
+   }
+
+   pthread_mutex_unlock(&s->pthMutex);
+
+   return s->changedBits;
+}
+
+/* ----------------------------------------------------------------------- */
+
 static int scrWait(gpioScript_t *s, uint32_t bits)
 {
    pthread_mutex_lock(&s->pthMutex);
@@ -6337,7 +6490,9 @@ static void *pthScript(void *x)
 
                case PI_CMD_DIV:   A/=p1; F=A;                     PC++; break;
 
-               case PI_CMD_HALT: s->run_state = PI_SCRIPT_HALTED;       break;
+               case PI_CMD_HALT:  s->run_state = PI_SCRIPT_HALTED;      break;
+
+               case PI_CMD_EVTWT: A=scrEvtWait(s, p1); F=A;       PC++; break;
 
                case PI_CMD_INR:
                   if (instr.opt[1] == CMD_PAR)
@@ -6736,6 +6891,7 @@ static void *pthSocketThreadHandler(void *fdC)
          /* extensions */
 
          case PI_CMD_BI2CZ:
+         case PI_CMD_BSCX:
          case PI_CMD_CF2:
          case PI_CMD_FL:
          case PI_CMD_FR:
@@ -7012,6 +7168,11 @@ static int initPeripherals(void)
    if (padsReg == MAP_FAILED)
       SOFT_ERROR(PI_INIT_FAILED, "mmap pads failed (%m)");
 
+   bscsReg  = initMapMem(fdMem, BSCS_BASE,  BSCS_LEN);
+
+   if (bscsReg == MAP_FAILED)
+      SOFT_ERROR(PI_INIT_FAILED, "mmap bscs failed (%m)");
+
    return 0;
 }
 
@@ -7576,6 +7737,13 @@ static void initClearGlobals(void)
       gpioTimer[i].func    = NULL;
    }
 
+   for (i=0; i<=PI_MAX_EVENT; i++)
+   {
+      eventAlert[i].func      = NULL;
+      eventAlert[i].ignore    = 0;
+      eventAlert[i].fired     = 0;
+   }
+
    /* calculate the usable PWM frequencies */
 
    for (i=0; i<PWM_FREQS; i++)
@@ -7665,6 +7833,7 @@ static void initReleaseResources(void)
    /* release mmap'd memory */
 
    if (auxReg  != MAP_FAILED) munmap((void *)auxReg,  AUX_LEN);
+   if (bscsReg != MAP_FAILED) munmap((void *)bscsReg, BSCS_LEN);
    if (clkReg  != MAP_FAILED) munmap((void *)clkReg,  CLK_LEN);
    if (dmaReg  != MAP_FAILED) munmap((void *)dmaReg,  DMA_LEN);
    if (gpioReg != MAP_FAILED) munmap((void *)gpioReg, GPIO_LEN);
@@ -7674,6 +7843,7 @@ static void initReleaseResources(void)
    if (spiReg  != MAP_FAILED) munmap((void *)spiReg,  SPI_LEN);
 
    auxReg  = MAP_FAILED;
+   bscsReg = MAP_FAILED;
    clkReg  = MAP_FAILED;
    dmaReg  = MAP_FAILED;
    gpioReg = MAP_FAILED;
@@ -9894,7 +10064,7 @@ int gpioWaveGetMaxCbs(void)
 static int read_SDA(wfRx_t *w)
 {
    myGpioSetMode(w->I.SDA, PI_INPUT);
-   return gpioRead(w->I.SDA);
+   return myGpioRead(w->I.SDA);
 }
 
 static void set_SDA(wfRx_t *w)
@@ -9925,7 +10095,7 @@ static void I2C_clock_stretch(wfRx_t *w)
 
    myGpioSetMode(w->I.SCL, PI_INPUT);
    now = gpioTick();
-   while ((gpioRead(w->I.SCL) == 0) && ((gpioTick()-now) < max_stretch));
+   while ((myGpioRead(w->I.SCL) == 0) && ((gpioTick()-now) < max_stretch));
 }
 
 static void I2CStart(wfRx_t *w)
@@ -10236,6 +10406,118 @@ int bbI2CZip(
 
 /* ----------------------------------------------------------------------- */
 
+void bscInit(int mode)
+{
+   bscsReg[BSC_CR]=0; /* clear device */
+   bscsReg[BSC_RSR]=0; /* clear underrun and overrun errors */
+   bscsReg[BSC_SLV]=0; /* clear I2C slave address */
+   bscsReg[BSC_IMSC]=0xf; /* mask off all interrupts */
+   bscsReg[BSC_ICR]=0x0f; /* clear all interrupts */
+
+   gpioSetMode(BSC_SDA_MOSI, PI_ALT3);
+   gpioSetMode(BSC_SCL_SCLK, PI_ALT3);
+
+   if (mode > 1) /* SPI uses all GPIO */
+   {
+      gpioSetMode(BSC_MISO, PI_ALT3);
+      gpioSetMode(BSC_CE_N, PI_ALT3);
+   }
+}
+
+void bscTerm(int mode)
+{
+   bscsReg[BSC_CR] = 0; /* clear device */
+   bscsReg[BSC_RSR]=0; /* clear underrun and overrun errors */
+   bscsReg[BSC_SLV]=0; /* clear I2C slave address */
+
+   gpioSetMode(BSC_SDA_MOSI, PI_INPUT);
+   gpioSetMode(BSC_SCL_SCLK, PI_INPUT);
+
+   if (mode > 1)
+   {
+      gpioSetMode(BSC_MISO, PI_INPUT);
+      gpioSetMode(BSC_CE_N, PI_INPUT);
+   }
+}
+
+int bscXfer(bsc_xfer_t *xfer)
+{
+   static int bscMode = 0;
+
+   int copied=0;
+   int active, mode;
+
+   DBG(DBG_USER, "control=0x%X (sa=0x%X, cr=0x%X) tx=%d [%s]",
+      xfer->control,
+      ((xfer->control)>>16) & 127,
+      (xfer->control) & 0x3fff,
+      xfer->txCnt,
+      myBuf2Str(xfer->txCnt, (char *)xfer->txBuf));
+
+   CHECK_INITED;
+
+   eventAlert[PI_EVENT_BSC].ignore = 1;
+
+   if (xfer->control)
+   {
+      /*
+         bscMode (0=None, 1=I2C, 2=SPI) tracks which GPIO have been
+         set to BSC mode
+      */
+      if (xfer->control & 2) mode = 2; /* SPI */
+      else                   mode = 1; /* assume I2C */
+
+      if (mode > bscMode)
+      {
+         bscInit(bscMode);
+         bscMode = mode;
+      }
+   }
+   else
+   {
+      if (bscMode) bscTerm(bscMode);
+      bscMode = 0;
+      return 0; /* leave ignore set */
+   }
+
+   xfer->rxCnt = 0;
+
+   bscsReg[BSC_SLV] = ((xfer->control)>>16) & 127;
+   bscsReg[BSC_CR] = (xfer->control) & 0x3fff;
+   bscsReg[BSC_RSR]=0; /* clear underrun and overrun errors */
+
+   active = 1;
+
+   while (active)
+   {
+      active = 0;
+
+      while ((copied < xfer->txCnt) &&
+             (!(bscsReg[BSC_FR] & BSC_FR_TXFF)))
+      {
+         bscsReg[BSC_DR] = xfer->txBuf[copied++];
+         active = 1;
+      }
+
+      while ((xfer->rxCnt < BSC_FIFO_SIZE) &&
+             (!(bscsReg[BSC_FR] & BSC_FR_RXFE)))
+      {
+         xfer->rxBuf[xfer->rxCnt++] = bscsReg[BSC_DR];
+         active = 1;
+      }
+
+      myGpioSleep(0, 200);
+   }
+
+   bscFR = bscsReg[BSC_FR] & 0xffff;
+
+   eventAlert[PI_EVENT_BSC].ignore = 0;
+
+   return (copied<<16) | bscFR;
+}
+
+/* ----------------------------------------------------------------------- */
+
 static void set_CS(wfRx_t *w)
 {
    myGpioWrite(w->S.CS, PI_SPI_FLAGS_GET_CSPOL(w->S.spiFlags));
@@ -10744,6 +11026,98 @@ int gpioSerialReadClose(unsigned gpio)
 }
 
 
+/* ----------------------------------------------------------------------- */
+
+static int intEventSetFunc(
+   unsigned event,
+   void *   f,
+   int      user,
+   void *   userdata)
+{
+   DBG(DBG_INTERNAL, "event=%d function=%08X, user=%d, userdata=%08X",
+      event, (uint32_t)f, user, (uint32_t)userdata);
+
+   eventAlert[event].ex = user;
+   eventAlert[event].userdata = userdata;
+
+   eventAlert[event].func = f;
+
+   return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+int eventSetFunc(unsigned event, eventFunc_t f)
+{
+   DBG(DBG_USER, "event=%d function=%08X", event, (uint32_t)f);
+
+   CHECK_INITED;
+
+   if (event > PI_MAX_EVENT)
+      SOFT_ERROR(PI_BAD_EVENT_ID, "bad event (%d)", event);
+
+   intEventSetFunc(event, f, 0, NULL);
+
+   return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+int eventSetFuncEx(unsigned event, eventFuncEx_t f, void *userdata)
+{
+   DBG(DBG_USER, "event=%d function=%08X userdata=%08X",
+      event, (uint32_t)f, (uint32_t)userdata);
+
+   CHECK_INITED;
+
+   if (event > PI_MAX_EVENT)
+      SOFT_ERROR(PI_BAD_EVENT_ID, "bad event (%d)", event);
+
+   intEventSetFunc(event, f, 1, userdata);
+
+   return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+int eventMonitor(unsigned handle, uint32_t bits)
+{
+   DBG(DBG_USER, "handle=%d bits=%08X", handle, bits);
+
+   CHECK_INITED;
+
+   if (handle >= PI_NOTIFY_SLOTS)
+      SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
+
+   if (gpioNotify[handle].state <= PI_NOTIFY_CLOSING)
+      SOFT_ERROR(PI_BAD_HANDLE, "bad handle (%d)", handle);
+
+   gpioNotify[handle].eventBits  = bits;
+
+   return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+int eventTrigger(unsigned event)
+{
+   DBG(DBG_USER, "event=%d", event);
+
+   CHECK_INITED;
+
+   if (event > PI_MAX_EVENT)
+      SOFT_ERROR(PI_BAD_EVENT_ID, "bad event (%d)", event);
+
+   eventAlert[event].fired = 1;
+
+   return 0;
+}
+
+
 /* ----------------------------------------------------------------------- */
 
 static int intGpioSetAlertFunc(
@@ -11159,6 +11533,25 @@ static void intScriptBits(void)
 }
 
 
+static void intScriptEventBits(void)
+{
+   int i;
+   uint32_t bits;
+
+   bits = 0;
+
+   for (i=0; i<PI_MAX_SCRIPTS; i++)
+   {
+      if (gpioScript[i].state == PI_SCRIPT_IN_USE)
+      {
+         bits |= gpioScript[i].eventBits;
+      }
+   }
+
+   scriptEventBits = bits;
+}
+
+
 static void intNotifyBits(void)
 {
    int i;
@@ -11463,16 +11856,26 @@ static int intGpioSetTimerFunc(unsigned id,
    {
       if (gpioTimer[id].running)
       {
+
          /* destroy thread */
 
-         if (pthread_cancel(gpioTimer[id].pthId))
-            SOFT_ERROR(PI_TIMER_FAILED, "timer %d, cancel failed (%m)", id);
+         if (pthread_self() == gpioTimer[id].pthId)
+         {
+            gpioTimer[id].running = 0;
+            gpioTimer[id].func    = 0;
+            pthread_exit(NULL);
+         }
+         else
+         {
+            if (pthread_cancel(gpioTimer[id].pthId))
+               SOFT_ERROR(PI_TIMER_FAILED, "timer %d, cancel failed (%m)", id);
 
-         if (pthread_join(gpioTimer[id].pthId, NULL))
-            SOFT_ERROR(PI_TIMER_FAILED, "timer %d, join failed (%m)", id);
+            if (pthread_join(gpioTimer[id].pthId, NULL))
+               SOFT_ERROR(PI_TIMER_FAILED, "timer %d, join failed (%m)", id);
 
-         gpioTimer[id].running = 0;
-         gpioTimer[id].func    = f;
+            gpioTimer[id].running = 0;
+            gpioTimer[id].func    = 0;
+         }
       }
    }
 
@@ -11567,9 +11970,17 @@ void gpioStopThread(pthread_t *pth)
 
    if (pth)
    {
-      pthread_cancel(*pth);
-      pthread_join(*pth, NULL);
-      free(pth);
+      if (pthread_self() == *pth)
+      {
+         free(pth);
+         pthread_exit(NULL);
+      }
+      else
+      {
+         pthread_cancel(*pth);
+         pthread_join(*pth, NULL);
+         free(pth);
+      }
    }
 }
 
index 0822e189f3dd1888d7bafa017932b8de3b8d14d7..c9bb83badf40f12c09e3e5ff74116cf2889bfff0 100644 (file)
--- a/pigpio.h
+++ b/pigpio.h
@@ -31,7 +31,7 @@ For more information, please refer to <http://unlicense.org/>
 #include <stdint.h>
 #include <pthread.h>
 
-#define PIGPIO_VERSION 56
+#define PIGPIO_VERSION 57
 
 /*TEXT
 
@@ -289,6 +289,10 @@ bbSPIOpen                  Opens GPIO for bit banging SPI
 bbSPIClose                 Closes GPIO for bit banging SPI
 bbSPIXfer                  Performs multiple bit banged SPI transactions
 
+I2C/SPI_SLAVE
+
+bscXfer                    I2C/SPI as slave transfer
+
 SERIAL
 
 serOpen                    Opens a serial device
@@ -310,6 +314,13 @@ fileWrite                  Writes bytes to a file
 fileSeek                   Seeks to a position within a file
 fileList                   List files which match a pattern
 
+EVENTS
+
+eventMonitor               Sets the events to monitor
+eventSetFunc               Request an event callback
+eventSetFuncEx             Request an event callback, extended
+eventTrigger               Trigger an event
+
 CONFIGURATION
 
 gpioCfgBufferSize          Configure the GPIO sample buffer size
@@ -482,6 +493,20 @@ typedef struct
    uint8_t  *buf;  /* pointer to msg data */
 } pi_i2c_msg_t;
 
+/* BSC FIFO size */
+
+#define BSC_FIFO_SIZE 16
+
+typedef struct
+{
+   uint32_t control;          /* Write */
+   int rxCnt;                 /* Read only */
+   char rxBuf[BSC_FIFO_SIZE]; /* Read only */
+   int txCnt;                 /* Write */
+   char txBuf[BSC_FIFO_SIZE]; /* Write */
+} bsc_xfer_t;
+
+
 typedef void (*gpioAlertFunc_t)    (int      gpio,
                                     int      level,
                                     uint32_t tick);
@@ -491,6 +516,13 @@ typedef void (*gpioAlertFuncEx_t)  (int      gpio,
                                     uint32_t tick,
                                     void    *userdata);
 
+typedef void (*eventFunc_t)        (int      event,
+                                    uint32_t tick);
+
+typedef void (*eventFuncEx_t)      (int      event,
+                                    uint32_t tick,
+                                    void    *userdata);
+
 typedef void (*gpioISRFunc_t)      (int      gpio,
                                     int      level,
                                     uint32_t tick);
@@ -588,6 +620,7 @@ typedef void *(gpioThreadFunc_t) (void *);
 
 #define PI_NOTIFY_SLOTS  32
 
+#define PI_NTFY_FLAGS_EVENT    (1 <<7)
 #define PI_NTFY_FLAGS_ALIVE    (1 <<6)
 #define PI_NTFY_FLAGS_WDOG     (1 <<5)
 #define PI_NTFY_FLAGS_BIT(x) (((x)<<0)&31)
@@ -696,6 +729,49 @@ typedef void *(gpioThreadFunc_t) (void *);
 #define PI_SPI_FLAGS_CSPOLS(x)  ((x&7)<<2)
 #define PI_SPI_FLAGS_MODE(x)    ((x&3))
 
+/* BSC registers */
+
+#define BSC_DR         0
+#define BSC_RSR        1
+#define BSC_SLV        2
+#define BSC_CR         3
+#define BSC_FR         4
+#define BSC_IFLS       5
+#define BSC_IMSC       6
+#define BSC_RIS        7
+#define BSC_MIS        8
+#define BSC_ICR        9
+#define BSC_DMACR     10
+#define BSC_TDR       11
+#define BSC_GPUSTAT   12
+#define BSC_HCTRL     13
+#define BSC_DEBUG_I2C 14
+#define BSC_DEBUG_SPI 15
+
+#define BSC_CR_TESTFIFO 2048
+#define BSC_CR_RXE  512
+#define BSC_CR_TXE  256
+#define BSC_CR_BRK  128
+#define BSC_CR_CPOL  16
+#define BSC_CR_CPHA   8
+#define BSC_CR_I2C    4
+#define BSC_CR_SPI    2
+#define BSC_CR_EN     1
+
+#define BSC_FR_RXBUSY 32
+#define BSC_FR_TXFE   16
+#define BSC_FR_RXFF    8
+#define BSC_FR_TXFF    4
+#define BSC_FR_RXFE    2
+#define BSC_FR_TXBUSY  1
+
+/* BSC GPIO */
+
+#define BSC_SDA_MOSI 18
+#define BSC_SCL_SCLK 19
+#define BSC_MISO     20
+#define BSC_CE_N     21
+
 /* Longest busy delay */
 
 #define PI_MAX_BUSY_DELAY 100
@@ -825,6 +901,14 @@ typedef void *(gpioThreadFunc_t) (void *);
 
 #define MAX_CONNECT_ADDRESSES 256
 
+/* events */
+
+#define PI_MAX_EVENT 31
+
+/* Event auto generated on BSC slave activity */
+
+#define PI_EVENT_BSC 31
+
 /*F*/
 int gpioInitialise(void);
 /*D
@@ -1525,15 +1609,19 @@ typedef struct
 seqno: starts at 0 each time the handle is opened and then increments
 by one for each report.
 
-flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE.
+flags: three flags are defined, PI_NTFY_FLAGS_WDOG,
+PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT.
 
-PI_NTFY_FLAGS_WDOG, if bit 5 is set then bits 0-4 of the flags
+If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags
 indicate a GPIO which has had a watchdog timeout.
 
-PI_NTFY_FLAGS_ALIVE, if bit 6 is set this indicates a keep alive
+If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive
 signal on the pipe/socket and is sent once a minute in the absence
 of other notification activity.
 
+If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the flags
+indicate an event which has been triggered.
+
 tick: the number of microseconds since system boot.  It wraps around
 after 1h12m.
 
@@ -2704,6 +2792,127 @@ End
 ...
 D*/
 
+/*F*/
+int bscXfer(bsc_xfer_t *bsc_xfer);
+/*D
+This function provides a low-level interface to the
+SPI/I2C Slave peripheral.  This peripheral allows the
+Pi to act as a slave device on an I2C or SPI bus.
+
+I can't get SPI to work properly.  I tried with a
+control word of 0x303 and swapped MISO and MOSI.
+
+The function sets the BSC mode, writes any data in
+the transmit buffer to the BSC transmit FIFO, and
+copies any data in the BSC receive FIFO to the
+receive buffer.
+
+. .
+bsc_xfer:= a structure defining the transfer
+
+typedef struct
+{
+   uint32_t control;          // Write
+   int rxCnt;                 // Read only
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+   int txCnt;                 // Write
+   char txBuf[BSC_FIFO_SIZE]; // Write
+} bsc_xfer_t;
+. .
+
+To start a transfer set control (see below) and copy the bytes to
+be sent (if any) to txBuf and set the byte count in txCnt.
+
+Upon return rxCnt will be set to the number of received bytes placed
+in rxBuf.
+
+Note that the control word sets the BSC mode.  The BSC will stay in
+that mode until a different control word is sent.
+
+The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL) in I2C mode
+and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO), and 21 (CE) in SPI mode.  You
+need to swap MISO/MOSI between master and slave.
+
+When a zero control word is received GPIO 18-21 will be reset
+to INPUT mode.
+
+The returned function value is the status of the transfer (see below).
+
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+The most significant word of the returned status contains the number
+of bytes actually copied from txBuf to the BSC transmit FIFO (may be
+less than requested if the FIFO already contained untransmitted data).
+
+control consists of the following bits.
+
+. .
+22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+ a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+. .
+
+Bits 0-13 are copied unchanged to the BSC CR register.  See
+pages 163-165 of the Broadcom peripherals document for full
+details.
+
+aaaaaaa @ defines the I2C slave address (only relevant in I2C mode)
+IT      @ invert transmit status flags
+HC      @ enable host control
+TF      @ enable test FIFO
+IR      @ invert receive status flags
+RE      @ enable receive
+TE      @ enable transmit
+BK      @ abort operation and clear FIFOs
+EC      @ send control register as first I2C byte
+ES      @ send status register as first I2C byte
+PL      @ set SPI polarity high
+PH      @ set SPI phase high
+I2      @ enable I2C mode
+SP      @ enable SPI mode
+EN      @ enable BSC peripheral
+
+The returned status has the following format
+
+. .
+20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+ S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+. .
+
+Bits 0-15 are copied unchanged from the BSC FR register.  See
+pages 165-166 of the Broadcom peripherals document for full
+details.
+
+SSSSS @ number of bytes successfully copied to transmit FIFO
+RRRRR @ number of bytes in receieve FIFO
+TTTTT @ number of bytes in transmit FIFO
+RB    @ receive busy
+TE    @ transmit FIFO empty
+RF    @ receive FIFO full
+TF    @ transmit FIFO full
+RE    @ receive FIFO empty
+TB    @ transmit busy
+
+The following example shows how to configure the BSC peripheral as
+an I2C slave with address 0x13 and send four bytes.
+
+...
+bsc_xfer_t xfer;
+
+xfer.control = (0x13<<16) | 0x305;
+
+memcpy(xfer.txBuf, "ABCD", 4);
+xfer.txCnt = 4;
+
+status = bscXfer(&xfer);
+
+if (status >= 0)
+{
+   // process transfer
+}
+...
+D*/
+
 /*F*/
 int bbSPIOpen(
    unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK,
@@ -3063,6 +3272,8 @@ handle: >=0, as returned by a call to [*serOpen*]
 
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
+
+If no data is ready PI_SER_READ_NO_DATA is returned.
 D*/
 
 /*F*/
@@ -3094,8 +3305,10 @@ handle: >=0, as returned by a call to [*serOpen*]
  count: the maximum number of bytes to read
 . .
 
-Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+Returns the number of bytes read (>0=) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, or PI_SER_READ_NO_DATA.
+
+If no data is ready zero is returned.
 D*/
 
 
@@ -3885,6 +4098,104 @@ gpioSetPad(0, 16); // set pad 0 strength to 16 mA
 ...
 D*/
 
+/*F*/
+int eventMonitor(unsigned handle, uint32_t bits);
+/*D
+This function selects the events to be reported on a previously
+opened handle.
+
+. .
+handle: >=0, as returned by [*gpioNotifyOpen*]
+  bits: a bit mask indicating the events of interest
+. .
+
+Returns 0 if OK, otherwise PI_BAD_HANDLE.
+
+A report is sent each time an event is triggered providing the
+corresponding bit in bits is set.
+
+See [*gpioNotifyBegin*] for the notification format.
+
+...
+// Start reporting events 3, 6, and 7.
+
+//  bit      76543210
+// (0xC8 = 0b11001000)
+
+eventMonitor(h, 0xC8);
+...
+
+D*/
+
+/*F*/
+int eventSetFunc(unsigned event, eventFunc_t f);
+/*D
+Registers a function to be called (a callback) when the specified
+event occurs.
+
+. .
+event: 0-31
+    f: the callback function
+. .
+
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+One function may be registered per event.
+
+The function is passed the event, and the tick.
+
+The callback may be cancelled by passing NULL as the function.
+D*/
+
+/*F*/
+int eventSetFuncEx(unsigned event, eventFuncEx_t f, void *userdata);
+/*D
+Registers a function to be called (a callback) when the specified
+event occurs.
+
+. .
+   event: 0-31
+       f: the callback function
+userdata: pointer to arbitrary user data
+. .
+
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+One function may be registered per event.
+
+The function is passed the event, the tick, and the ueserdata pointer.
+
+The callback may be cancelled by passing NULL as the function.
+
+Only one of [*eventSetFunc*] or [*eventSetFuncEx*] can be
+registered per event.
+D*/
+
+/*F*/
+int eventTrigger(unsigned event);
+/*D
+This function signals the occurrence of an event.
+
+. .
+event: 0-31, the event
+. .
+
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+An event is a signal used to inform one or more consumers
+to start an action.  Each consumer which has registered an interest
+in the event (e.g. by calling [*eventSetFunc*]) will be informed by
+a callback.
+
+One event, PI_EVENT_BSC (31) is predefined.  This event is
+auto generated on BSC slave activity.
+
+The meaning of other events is arbitrary.
+
+Note that other than its id and its tick there is no data associated
+with an event.
+D*/
+
 
 /*F*/
 int shell(char *scriptName, char *scriptString);
@@ -4771,6 +5082,22 @@ A convenient way to set bit n is to or in (1<<n).
 
 e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
 
+*bsc_xfer::
+A pointer to a [*bsc_xfer_t*] object used to control a BSC transfer.
+
+bsc_xfer_t::
+
+. .
+typedef struct
+{
+   uint32_t control;          // Write
+   int rxCnt;                 // Read only
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+   int txCnt;                 // Write
+   char txBuf[BSC_FIFO_SIZE]; // Write
+} bsc_xfer_t;
+. .
+
 *buf::
 
 A buffer to hold data being sent or being received.
@@ -4866,7 +5193,7 @@ The number may vary between 0 and range (default 255) where
 0 is off and range is fully on.
 
 edge::0-2
-The type of GPIO edge to generate an intrrupt.  See [*gpioSetISRFunc*],
+The type of GPIO edge to generate an interrupt.  See [*gpioSetISRFunc*]
 and [*gpioSetISRFuncEx*].
 
 . .
@@ -4875,6 +5202,21 @@ FALLING_EDGE 1
 EITHER_EDGE 2
 . .
 
+event::0-31
+An event is a signal used to inform one or more consumers
+to start an action.
+
+eventFunc_t::
+. .
+typedef void (*eventFunc_t) (int event, uint32_t tick);
+. .
+
+eventFuncEx_t::
+. .
+typedef void (*eventFuncEx_t)
+   (int event, uint32_t tick, void *userdata);
+. .
+
 f::
 
 A function.
@@ -4931,8 +5273,8 @@ typedef void (*gpioAlertFunc_t) (int gpio, int level, uint32_t tick);
 
 gpioAlertFuncEx_t::
 . .
-typedef void (*gpioAlertFuncEx_t)
-   (int gpio, int level, uint32_t tick, void *userdata);
+typedef void (*eventFuncEx_t)
+   (int event, int level, uint32_t tick, void *userdata);
 . .
 
 gpioCfg*::
@@ -5026,8 +5368,13 @@ One of
 
 handle::>=0
 
-A number referencing an object opened by one of [*fileOpen*],
-[*gpioNotifyOpen*], [*i2cOpen*], [*serOpen*], [*spiOpen*].
+A number referencing an object opened by one of
+
+[*fileOpen*] 
+[*gpioNotifyOpen*] 
+[*i2cOpen*] 
+[*serOpen*] 
+[*spiOpen*]
 
 i2cAddr:: 0-0x7F
 The address of a device on the I2C bus.
@@ -5231,6 +5578,7 @@ pud::0-2
 
 The setting of the pull up/down resistor for a GPIO, which may be off,
 pull-up, or pull-down.
+
 . .
 PI_PUD_OFF 0
 PI_PUD_DOWN 1
@@ -5522,17 +5870,21 @@ following technique.
 
 In the calling function:
 
+. .
 user_type *userdata; 
 user_type my_userdata;
 
 userdata = malloc(sizeof(user_type)); 
 *userdata = my_userdata;
+. .
 
 In the receiving function:
 
+. .
 user_type my_userdata = *(user_type*)userdata;
 
 free(userdata);
+. .
 
 void::
 
@@ -5697,6 +6049,11 @@ PARAMS*/
 #define PI_CMD_BSPIO 112
 #define PI_CMD_BSPIX 113
 
+#define PI_CMD_BSCX  114
+
+#define PI_CMD_EVM   115
+#define PI_CMD_EVT   116
+
 /*DEF_E*/
 
 /*
@@ -5755,6 +6112,7 @@ after this command is issued.
 #define PI_CMD_X     839
 #define PI_CMD_XA    840
 #define PI_CMD_XOR   841
+#define PI_CMD_EVTWT 842
 
 /*DEF_S Error Codes*/
 
@@ -5903,6 +6261,7 @@ after this command is issued.
 #define PI_BAD_SCRIPT_NAME -140 // bad script name
 #define PI_BAD_SPI_BAUD    -141 // bad SPI baud rate, not 50-500k
 #define PI_NOT_SPI_GPIO    -142 // no bit bang SPI in progress on GPIO
+#define PI_BAD_EVENT_ID    -143 // bad event id
 
 #define PI_PIGIF_ERR_0    -2000
 #define PI_PIGIF_ERR_99   -2099
index b0962d557dd710f0a12b396e975668716a94741c..b22202e41817447f9e4ae3f0d268a25810021d6e 100644 (file)
--- a/pigpio.py
+++ b/pigpio.py
@@ -56,7 +56,7 @@ If you wish to handle the returned status yourself you should set
 pigpio.exceptions to False.
 
 You may prefer to check the returned status in only a few parts
-of your code.  In that case do the following.
+of your code.  In that case do the following:
 
 ...
 pigpio.exceptions = False
@@ -242,6 +242,11 @@ bb_spi_open               Opens GPIO for bit banging SPI
 bb_spi_close              Closes GPIO for bit banging SPI
 bb_spi_xfer               Transfers bytes with bit banging SPI
 
+I2C/SPI_Slave
+
+bsc_xfer                  I2C/SPI as slave transfer
+bsc_i2c                   I2C as slave transfer
+
 Serial
 
 serial_open               Opens a serial device
@@ -264,6 +269,12 @@ file_write                Writes bytes to a file
 file_seek                 Seeks to a position within a file
 file_list                 List files which match a pattern
 
+Events
+
+event_callback            Sets a callback for an event
+event_trigger             Triggers an event
+wait_for_event            Wait for an event
+
 Custom
 
 custom_1                  User custom function 1
@@ -288,7 +299,7 @@ import threading
 import os
 import atexit
 
-VERSION = "1.33"
+VERSION = "1.34"
 
 exceptions = True
 
@@ -337,6 +348,7 @@ PI_SCRIPT_FAILED =4
 
 # notification flags
 
+NTFY_FLAGS_EVENT = (1 << 7)
 NTFY_FLAGS_ALIVE = (1 << 6)
 NTFY_FLAGS_WDOG  = (1 << 5)
 NTFY_FLAGS_GPIO  = 31
@@ -376,6 +388,8 @@ SPI_CS_HIGH_ACTIVE  = 1 << 2
 SPI_TX_LSBFIRST = 1 << 14
 SPI_RX_LSBFIRST = 1 << 15
 
+EVENT_BSC = 31
+
 # pigpio command numbers
 
 _PI_CMD_MODES= 0
@@ -518,6 +532,11 @@ _PI_CMD_BSPIC=111
 _PI_CMD_BSPIO=112
 _PI_CMD_BSPIX=113
 
+_PI_CMD_BSCX =114
+
+_PI_CMD_EVM  =115
+_PI_CMD_EVT  =116
+
 # pigpio error numbers
 
 _PI_INIT_FAILED     =-1
@@ -663,6 +682,7 @@ PI_BAD_SHELL_STATUS =-139
 PI_BAD_SCRIPT_NAME  =-140
 PI_BAD_SPI_BAUD     =-141
 PI_NOT_SPI_GPIO     =-142
+PI_BAD_EVENT_ID     =-143
 
 # pigpio error text
 
@@ -807,13 +827,14 @@ _errors=[
    [PI_BAD_SCRIPT_NAME   , "bad script name"],
    [PI_BAD_SPI_BAUD      , "bad SPI baud rate, not 50-500k"],
    [PI_NOT_SPI_GPIO      , "no bit bang SPI in progress on GPIO"],
+   [PI_BAD_EVENT_ID      , "bad event id"],
 ]
 
-except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}"
+_except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}"
 
-except_z = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
+_except_z = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
 
-except1 = """
+_except_1 = """
 Did you start the pigpio daemon? E.g. sudo pigpiod
 
 Did you specify the correct Pi host/port in the environment
@@ -823,7 +844,7 @@ E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888
 Did you specify the correct Pi host/port in the
 pigpio.pi() function? E.g. pigpio.pi('soft', 8888)"""
 
-except2 = """
+_except_2 = """
 Do you have permission to access the pigpio daemon?
 Perhaps it was started with sudo pigpiod -nlocalhost"""
 
@@ -981,6 +1002,22 @@ def _pigpio_command_ext(sl, cmd, p1, p2, p3, extents, rl=True):
    if rl: sl.l.release()
    return res
 
+class _event_ADT:
+   """
+   An ADT class to hold event callback information.
+   """
+
+   def __init__(self, event, func):
+      """
+      Initialises an event callback ADT.
+
+      event:= the event id.
+       func:= a user function taking one argument, the event id.
+      """
+      self.event = event
+      self.func = func
+      self.bit = 1<<event
+
 class _callback_ADT:
    """An ADT class to hold callback information."""
 
@@ -1007,7 +1044,9 @@ class _callback_thread(threading.Thread):
       self.go = False
       self.daemon = True
       self.monitor = 0
+      self.event_bits = 0
       self.callbacks = []
+      self.events = []
       self.sl.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
       self.sl.s.settimeout(None)
       self.sl.s.connect((host, port))
@@ -1039,6 +1078,28 @@ class _callback_thread(threading.Thread):
             _pigpio_command(
                self.control, _PI_CMD_NB, self.handle, self.monitor)
 
+   def append_event(self, callb):
+      """
+      Adds an event callback to the notification thread.
+      """
+      self.events.append(callb)
+      self.event_bits = self.event_bits | callb.bit
+      _pigpio_command(self.control, _PI_CMD_EVM, self.handle, self.event_bits)
+
+   def remove_event(self, callb):
+      """
+      Removes an event callback from the notification thread.
+      """
+      if callb in self.events:
+         self.events.remove(callb)
+         new_event_bits = 0
+         for c in self.events:
+            new_event_bits |= c.bit
+         if new_event_bits != self.event_bits:
+            self.event_bits = new_event_bits
+            _pigpio_command(
+               self.control, _PI_CMD_EVM, self.handle, self.event_bits)
+
    def run(self):
       """Runs the notification thread."""
 
@@ -1071,7 +1132,12 @@ class _callback_thread(threading.Thread):
                   gpio = flags & NTFY_FLAGS_GPIO
                   for cb in self.callbacks:
                      if cb.gpio == gpio:
-                        cb.func(cb.gpio, TIMEOUT, tick)
+                        cb.func(gpio, TIMEOUT, tick)
+               elif flags & NTFY_FLAGS_EVENT:
+                  event = flags & NTFY_FLAGS_GPIO
+                  for cb in self.events:
+                     if cb.event == event:
+                        cb.func(event, tick)
 
       self.sl.s.close()
 
@@ -1118,6 +1184,52 @@ class _callback:
       self._reset = True
       self.count = 0
 
+class _event:
+   """A class to provide event callbacks."""
+
+   def __init__(self, notify, event, func=None):
+      """
+      Initialise an event and adds it to the notification thread.
+      """
+      self._notify = notify
+      self.count=0
+      self._reset = False
+      if func is None:
+         func=self._tally
+      self.callb = _event_ADT(event, func)
+      self._notify.append_event(self.callb)
+
+   def cancel(self):
+      """
+      Cancels a event callback by removing it from the
+      notification thread.
+      """
+      self._notify.remove_event(self.callb)
+
+   def _tally(self, event, tick):
+      """Increment the event callback called count."""
+      if self._reset:
+         self._reset = False
+         self.count = 0
+      self.count += 1
+
+   def tally(self):
+      """
+      Provides a count of how many times the default tally
+      callback has triggered.
+
+      The count will be zero if the user has supplied their own
+      callback function.
+      """
+      return self.count
+
+   def reset_tally(self):
+      """
+      Resets the tally count to zero.
+      """
+      self._reset = True
+      self.count = 0
+
 class _wait_for_edge:
    """Encapsulates waiting for GPIO edges."""
 
@@ -1136,6 +1248,24 @@ class _wait_for_edge:
       """Sets wait_for_edge triggered."""
       self.trigger = True
 
+class _wait_for_event:
+   """Encapsulates waiting for an event."""
+
+   def __init__(self, notify, event, timeout):
+      """Initialises wait_for_event."""
+      self._notify = notify
+      self.callb = _event_ADT(event, self.func)
+      self.trigger = False
+      self._notify.append_event(self.callb)
+      self.start = time.time()
+      while (self.trigger == False) and ((time.time()-self.start) < timeout):
+         time.sleep(0.05)
+      self._notify.remove_event(self.callb)
+
+   def func(self, event, tick):
+      """Sets wait_for_event triggered."""
+      self.trigger = True
+
 class pi():
 
    def _rxbuf(self, count):
@@ -1501,7 +1631,7 @@ class pi():
       E.g. if the function returns 15 then the notifications must be
       read from /dev/pigpio15.
 
-      Notifications have the following structure.
+      Notifications have the following structure:
 
       . .
       H seqno
@@ -1513,16 +1643,20 @@ class pi():
       seqno: starts at 0 each time the handle is opened and then
       increments by one for each report.
 
-      flags: two flags are defined, PI_NTFY_FLAGS_WDOG and
-      PI_NTFY_FLAGS_ALIVE.
+      flags: three flags are defined, PI_NTFY_FLAGS_WDOG,
+      PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT.
 
-      PI_NTFY_FLAGS_WDOG, if bit 5 is set then bits 0-4 of the
+      If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the
       flags indicate a GPIO which has had a watchdog timeout.
 
-      PI_NTFY_FLAGS_ALIVE, if bit 6 is set this indicates a keep
+      If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep
       alive signal on the pipe/socket and is sent once a minute
       in the absence of other notification activity.
 
+      If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the
+      flags indicate an event which has been triggered.
+
+
       tick: the number of microseconds since system boot.  It wraps
       around after 1h12m.
 
@@ -1732,7 +1866,7 @@ class pi():
       The same clock is available on multiple GPIO.  The latest
       frequency setting will be used by all GPIO which share a clock.
 
-      The GPIO must be one of the following.
+      The GPIO must be one of the following:
 
       . .
       4   clock 0  All models
@@ -1783,7 +1917,7 @@ class pi():
       The latest frequency and dutycycle setting will be used
       by all GPIO which share a PWM channel.
 
-      The GPIO must be one of the following.
+      The GPIO must be one of the following:
 
       . .
       12  PWM channel 0  All models but A and B
@@ -2418,7 +2552,7 @@ class pi():
 
       For the SMBus commands the low level transactions are shown
       at the end of the function description.  The following
-      abbreviations are used.
+      abbreviations are used:
 
       . .
       S     (1 bit) : Start bit
@@ -3229,7 +3363,7 @@ class pi():
 
       ...
       (count, data) = pi.bb_i2c_zip(
-                         h, [4, 0x53, 2, 7, 1, 0x32, 2, 6, 6, 3, 0])
+                         SDA, [4, 0x53, 2, 7, 1, 0x32, 2, 6, 6, 3, 0])
       ...
 
       The following command codes are supported:
@@ -3293,6 +3427,261 @@ class pi():
       self.sl.l.release()
       return bytes, data
 
+   def event_trigger(self, event):
+      """
+      This function signals the occurrence of an event.
+
+      event:= 0-31, the event
+
+      Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+      An event is a signal used to inform one or more consumers
+      to start an action.  Each consumer which has registered an
+      interest in the event (e.g. by calling [*event_callback*]) will
+      be informed by a callback.
+
+      One event, EVENT_BSC (31) is predefined.  This event is
+      auto generated on BSC slave activity.
+
+      The meaning of other events is arbitrary.
+
+      Note that other than its id and its tick there is no data associated
+      with an event.
+
+      ...
+      pi.event_trigger(23)
+      ...
+      """
+      return _u2i(_pigpio_command(self.sl, _PI_CMD_EVT, event, 0))
+
+
+   def bsc_xfer(self, bsc_control, data):
+      """
+      This function provides a low-level interface to the
+      SPI/I2C Slave peripheral.  This peripheral allows the
+      Pi to act as a slave device on an I2C or SPI bus.
+
+      I can't get SPI to work properly.  I tried with a
+      control word of 0x303 and swapped MISO and MOSI.
+
+
+      The function sets the BSC mode, writes any data in
+      the transmit buffer to the BSC transmit FIFO, and
+      copies any data in the BSC receive FIFO to the
+      receive buffer.
+
+      bsc_control:= see below
+             data:= the data bytes to place in the transmit FIFO.
+
+      The returned value is a tuple of the status (see below),
+      the number of bytes read, and a bytearray containing the
+      read bytes.  If there was an error the status will be less
+      than zero (and will contain the error code).
+
+      Note that the control word sets the BSC mode.  The BSC will
+      stay in that mode until a different control word is sent.
+
+      The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL)
+      in I2C mode and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO),
+      and 21 (CE) in SPI mode.  You need to swap MISO/MOSI
+      between master and slave.
+
+      When a zero control word is received GPIO 18-21 will be reset
+      to INPUT mode.
+
+      bsc_control consists of the following bits:
+
+      . .
+      22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+       a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+      . .
+
+      Bits 0-13 are copied unchanged to the BSC CR register.  See
+      pages 163-165 of the Broadcom peripherals document for full
+      details.
+
+      aaaaaaa @ defines the I2C slave address (only relevant in I2C mode)
+      IT      @ invert transmit status flags
+      HC      @ enable host control
+      TF      @ enable test FIFO
+      IR      @ invert receive status flags
+      RE      @ enable receive
+      TE      @ enable transmit
+      BK      @ abort operation and clear FIFOs
+      EC      @ send control register as first I2C byte
+      ES      @ send status register as first I2C byte
+      PL      @ set SPI polarity high
+      PH      @ set SPI phase high
+      I2      @ enable I2C mode
+      SP      @ enable SPI mode
+      EN      @ enable BSC peripheral
+
+      The status has the following format:
+
+      . .
+      20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+       S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+      . .
+
+      Bits 0-15 are copied unchanged from the BSC FR register.  See
+      pages 165-166 of the Broadcom peripherals document for full
+      details.
+
+      SSSSS @ number of bytes successfully copied to transmit FIFO
+      RRRRR @ number of bytes in receieve FIFO
+      TTTTT @ number of bytes in transmit FIFO
+      RB    @ receive busy
+      TE    @ transmit FIFO empty
+      RF    @ receive FIFO full
+      TF    @ transmit FIFO full
+      RE    @ receive FIFO empty
+      TB    @ transmit busy
+
+      ...
+      (status, count, data) = pi.bsc_xfer(0x330305, "Hello!")
+      ...
+      """
+      # I p1 control
+      # I p2 0
+      # I p3 len
+      ## extension ##
+      # s len data bytes
+
+      # Don't raise exception.  Must release lock.
+      bytes = u2i(_pigpio_command_ext(
+         self.sl, _PI_CMD_BSCX, bsc_control, 0, len(data), [data], False))
+      if bytes > 0:
+         rx = self._rxbuf(bytes)
+         status = struct.unpack('I', rx[0:4])[0]
+         bytes -= 4
+         data = rx[4:]
+      else:
+         status = bytes
+         bytes = 0
+         data = bytearray(b'')
+      self.sl.l.release()
+      return status, bytes, data
+
+   def bsc_i2c(self, i2c_address, data=[]):
+      """
+      This function allows the Pi to act as a slave I2C device.
+
+      The data bytes (if any) are written to the BSC transmit
+      FIFO and the bytes in the BSC receive FIFO are returned.
+
+      i2c_address:= the I2C slave address.
+             data:= the data bytes to transmit.
+
+      The returned value is a tuple of the status, the number
+      of bytes read, and a bytearray containing the read bytes.
+
+      See [*bsc_xfer*] for details of the status value.
+
+      If there was an error the status will be less than zero
+      (and will contain the error code).
+
+      Note that an i2c_address of 0 may be used to close
+      the BSC device and reassign the used GPIO (18/19)
+      as inputs.
+
+      This example assumes GPIO 2/3 are connected to GPIO 18/19.
+
+      ...
+      #!/usr/bin/env python
+      import time
+      import pigpio
+
+      I2C_ADDR=0x13
+
+      def i2c(id, tick):
+          global pi
+
+          s, b, d = pi.bsc_i2c(I2C_ADDR)
+          if b:
+              if d[0] == ord('t'): # 116 send 'HH:MM:SS*'
+
+                  print("sent={} FR={} received={} [{}]".
+                     format(s>>16, s&0xfff,b,d))
+
+                  s, b, d = pi.bsc_i2c(I2C_ADDR,
+                     "{}*".format(time.asctime()[11:19]))
+
+              elif d[0] == ord('d'): # 100 send 'Sun Oct 30*'
+
+                  print("sent={} FR={} received={} [{}]".
+                     format(s>>16, s&0xfff,b,d))
+
+                  s, b, d = pi.bsc_i2c(I2C_ADDR,
+                     "{}*".format(time.asctime()[:10]))
+
+      pi = pigpio.pi()
+
+      if not pi.connected:
+          exit()
+
+      # Respond to BSC slave activity
+
+      e = pi.event_callback(pigpio.EVENT_BSC, i2c)
+
+      pi.bsc_i2c(I2C_ADDR) # Configure BSC as I2C slave
+
+      time.sleep(600)
+
+      e.cancel()
+
+      pi.bsc_i2c(0) # Disable BSC peripheral
+
+      pi.stop()
+      ...
+
+      While running the above.
+
+      . .
+      $ i2cdetect -y 1
+          0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+      00:          -- -- -- -- -- -- -- -- -- -- -- -- --
+      10: -- -- -- 13 -- -- -- -- -- -- -- -- -- -- -- --
+      20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+      30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+      40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+      50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+      60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+      70: -- -- -- -- -- -- -- --
+
+      $ pigs i2co 1 0x13 0
+      0
+
+      $ pigs i2cwd 0 116
+      $ pigs i2crd 0 9 -a
+      9 10:13:58*
+
+      $ pigs i2cwd 0 116
+      $ pigs i2crd 0 9 -a
+      9 10:14:29*
+
+      $ pigs i2cwd 0 100
+      $ pigs i2crd 0 11 -a
+      11 Sun Oct 30*
+
+      $ pigs i2cwd 0 100
+      $ pigs i2crd 0 11 -a
+      11 Sun Oct 30*
+
+      $ pigs i2cwd 0 116
+      $ pigs i2crd 0 9 -a
+      9 10:23:16*
+
+      $ pigs i2cwd 0 100
+      $ pigs i2crd 0 11 -a
+      11 Sun Oct 30*
+      . .
+      """
+      if i2c_address:
+         control = (i2c_address<<16)|0x305
+      else:
+         control = 0
+      return self.bsc_xfer(control, data)
+
    def spi_open(self, spi_channel, baud, spi_flags=0):
       """
       Returns a handle for the SPI device on channel.  Data will be
@@ -3545,6 +3934,8 @@ class pi():
 
       handle:= >=0 (as returned by a prior call to [*serial_open*]).
 
+      If no data is ready a negative error code will be returned.
+
       ...
       b = pi.serial_read_byte(h1)
       ...
@@ -3567,18 +3958,19 @@ class pi():
       return _u2i(
          _pigpio_command(self.sl, _PI_CMD_SERWB, handle, byte_val))
 
-   def serial_read(self, handle, count):
+   def serial_read(self, handle, count=1000):
       """
       Reads up to count bytes from the device associated with handle.
 
       handle:= >=0 (as returned by a prior call to [*serial_open*]).
-       count:= >0, the number of bytes to read.
+       count:= >0, the number of bytes to read (defaults to 1000).
 
-      The returned value is a tuple of the number of bytes read and a
-      bytearray containing the bytes.  If there was an error the
+      The returned value is a tuple of the number of bytes read and
+      bytearray containing the bytes.  If there was an error the
       number of bytes read will be less than zero (and will contain
       the error code).
 
+      If no data is ready a bytes read of zero is returned.
       ...
       (b, d) = pi.serial_read(h2, 100)
       if b > 0:
@@ -4079,7 +4471,7 @@ class pi():
       Where more than one entry matches a file the most specific rule
       applies.  If no entry matches a file then access is denied.
 
-      Suppose /opt/pigpio/access contains the following entries
+      Suppose /opt/pigpio/access contains the following entries:
 
       . .
       /home/* n
@@ -4100,7 +4492,7 @@ class pi():
       may be created in that directory.
 
       In an attempt to prevent risky permissions the following paths are
-      ignored in /opt/pigpio/access.
+      ignored in /opt/pigpio/access:
 
       . .
       a path containing ..
@@ -4110,14 +4502,14 @@ class pi():
 
       Mode
 
-      The mode may have the following values.
+      The mode may have the following values:
 
       Constant   @ Value @ Meaning
       FILE_READ  @   1   @ open file for reading
       FILE_WRITE @   2   @ open file for writing
       FILE_RW    @   3   @ open file for reading and writing
 
-      The following values may be or'd into the mode.
+      The following values may be or'd into the mode:
 
       Name        @ Value @ Meaning
       FILE_APPEND @ 4     @ All writes append data to the end of the file
@@ -4137,7 +4529,7 @@ class pi():
       if not pi.connected:
          exit()
 
-      # Assumes /opt/pigpio/access contains the following line.
+      # Assumes /opt/pigpio/access contains the following line:
       # /ram/*.c r
 
       handle = pi.file_open("/ram/pigpio.c", pigpio.FILE_READ)
@@ -4284,7 +4676,7 @@ class pi():
       if not pi.connected:
          exit()
 
-      # Assumes /opt/pigpio/access contains the following line.
+      # Assumes /opt/pigpio/access contains the following line:
       # /ram/*.c r
 
       c, d = pi.file_list("/ram/p*.c")
@@ -4328,7 +4720,7 @@ class pi():
       the shell script exit function.  If the script can't be
       found 32512 will be returned.
 
-      The following table gives some example returned statuses.
+      The following table gives some example returned statuses:
 
       Script exit status @ Returned system call status
       1                  @ 256
@@ -4359,6 +4751,7 @@ class pi():
       return _u2i(_pigpio_command_ext(
          self.sl, _PI_CMD_SHELL, ls, 0, ls+lp+1, [shellscr+'\x00'+pstring]))
 
+
    def callback(self, user_gpio, edge=RISING_EDGE, func=None):
       """
       Calls a user supplied function (a callback) whenever the
@@ -4400,6 +4793,45 @@ class pi():
       """
       return _callback(self._notify, user_gpio, edge, func)
 
+   def event_callback(self, event, func=None):
+      """
+      Calls a user supplied function (a callback) whenever the
+      specified event is signalled.
+
+      event:= 0-31.
+       func:= user supplied callback function.
+
+      The user supplied callback receives two parameters, the event id,
+      and the tick.
+
+      If a user callback is not specified a default tally callback is
+      provided which simply counts events.  The count may be retrieved
+      by calling the tally function.  The count may be reset to zero
+      by calling the reset_tally function.
+
+      The callback may be cancelled by calling the event_cancel function.
+
+      An event may have multiple callbacks (although I can't think of
+      a reason to do so).
+
+      ...
+      def cbf(event, tick):
+         print(event, tick)
+
+      cb1 = pi.event_callback(22, cbf)
+
+      cb2 = pi.event_callback(4)
+
+      print(cb2.tally())
+
+      cb2.reset_tally()
+
+      cb1.event_cancel() # To cancel callback cb1.
+      ...
+      """
+
+      return _event(self._notify, event, func)
+
    def wait_for_edge(self, user_gpio, edge=RISING_EDGE, wait_timeout=60.0):
       """
       Wait for an edge event on a GPIO.
@@ -4435,6 +4867,29 @@ class pi():
       a = _wait_for_edge(self._notify, user_gpio, edge, wait_timeout)
       return a.trigger
 
+   def wait_for_event(self, event, wait_timeout=60.0):
+      """
+      Wait for an event.
+
+             event:= 0-31.
+      wait_timeout:= >=0.0 (default 60.0).
+
+      The function returns when the event is signalled or after
+      the number of seconds specified by timeout has expired.
+
+      The function returns True if the event is detected,
+      otherwise False.
+
+      ...
+      if pi.wait_for_event(23):
+         print("event detected")
+      else:
+         print("wait for event timed out")
+      ...
+      """
+      a = _wait_for_event(self._notify, event, wait_timeout)
+      return a.trigger
+
    def __init__(self,
                 host = os.getenv("PIGPIO_ADDR", ''),
                 port = os.getenv("PIGPIO_PORT", 8888)):
@@ -4511,12 +4966,12 @@ class pi():
 
          s = "Can't connect to pigpio at {}({})".format(str(h), str(port))
 
-         print(except_a.format(s))
+         print(_except_a.format(s))
          if exception == 1:
-             print(except1)
+             print(_except_1)
          else:
-             print(except2)
-         print(except_z)
+             print(_except_2)
+         print(_except_z)
 
    def stop(self):
       """Release pigpio resources.
@@ -4580,6 +5035,18 @@ def xref():
 
    bits = (1<<1) | (1<<7) | (1<<23)
 
+   bsc_control:
+
+   . .
+   22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+    a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+   . .
+
+   aaaaaaa defines the I2C slave address (only relevant in I2C mode)
+
+   Bits 0-13 are copied unchanged to the BSC CR register.  See
+   pages 163-165 of the Broadcom peripherals document.
+
    byte_val: 0-255
    A whole number.
 
@@ -4615,9 +5082,12 @@ def xref():
    range_        @ Fully On
 
    edge: 0-2
+
+   . .
    EITHER_EDGE = 2 
    FALLING_EDGE = 1 
    RISING_EDGE = 0
+   . .
 
    errnum: <0
 
@@ -4732,10 +5202,17 @@ def xref():
    PI_FILE_IS_A_DIR = -138
    PI_BAD_SHELL_STATUS = -139
    PI_BAD_SCRIPT_NAME = -140
+   PI_BAD_SPI_BAUD = -141
+   PI_NOT_SPI_GPIO = -142
+   PI_BAD_EVENT_ID = -143 
    . .
 
+   event:0-31
+   An event is a signal used to inform one or more consumers
+   to start an action.
+
    file_mode:
-   The mode may have the following values.
+   The mode may have the following values
 
    . .
    FILE_READ   1
@@ -4743,7 +5220,7 @@ def xref():
    FILE_RW     3
    . .
 
-   The following values can be or'd into the file open mode.
+   The following values can be or'd into the file open mode
 
    . .
    FILE_APPEND 4
@@ -4781,7 +5258,7 @@ def xref():
 
    See [*get_hardware_revision*].
 
-   The user GPIO are marked with an X in the following table.
+   The user GPIO are marked with an X in the following table
 
    . .
              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
@@ -4808,8 +5285,13 @@ def xref():
    of a pulse.
 
    handle: >=0
-   A number referencing an object opened by one of [*file_open*],
-   [*i2c_open*], [*notify_open*], [*serial_open*], [*spi_open*].
+   A number referencing an object opened by one of the following
+
+   [*file_open*] 
+   [*i2c_open*] 
+   [*notify_open*] 
+   [*serial_open*] 
+   [*spi_open*]
 
    host:
    The name or IP address of the Pi running the pigpio daemon.
@@ -4831,6 +5313,8 @@ def xref():
    level logic.
 
    level: 0-1 (2)
+
+   . .
    CLEAR = 0 
    HIGH = 1 
    LOW = 0 
@@ -4838,6 +5322,7 @@ def xref():
    ON = 1 
    SET = 1 
    TIMEOUT = 2 # only returned for a watchdog timeout
+   . .
 
    MISO:
    The GPIO used for the MISO signal when bit banging SPI.
@@ -4846,6 +5331,7 @@ def xref():
 
    1.The operational mode of a GPIO, normally INPUT or OUTPUT.
 
+   . .
    ALT0 = 4 
    ALT1 = 5 
    ALT2 = 6 
@@ -4854,13 +5340,16 @@ def xref():
    ALT5 = 2 
    INPUT = 0 
    OUTPUT = 1
+   . .
 
    2. The mode of waveform transmission.
 
+   . .
    WAVE_MODE_ONE_SHOT = 0 
    WAVE_MODE_REPEAT = 1 
    WAVE_MODE_ONE_SHOT_SYNC = 2 
    WAVE_MODE_REPEAT_SYNC = 3
+   . .
 
    MOSI:
    The GPIO used for the MOSI signal when bit banging SPI.
@@ -4892,9 +5381,11 @@ def xref():
    The string to be passed to a [*shell*] script to be executed.
 
    pud: 0-2
+   . .
    PUD_DOWN = 1 
    PUD_OFF = 0 
    PUD_UP = 2 
+   . .
 
    pulse_len: 1-100
    The length of the trigger pulse in microseconds.
@@ -4943,9 +5434,11 @@ def xref():
    seek_from: 0-2
    Direction to seek for [*file_seek*].
 
+   . .
    FROM_START=0 
    FROM_CURRENT=1 
    FROM_END=2 
+   . .
 
    seek_offset:
    The number of bytes to move forward (positive) or backwards
@@ -5003,13 +5496,20 @@ def xref():
    The number of seconds to wait in [*wait_for_edge*] before timing out.
 
    wave_add_*:
-   One of [*wave_add_new*] , [*wave_add_generic*], [*wave_add_serial*].
+   One of the following
+
+   [*wave_add_new*] 
+   [*wave_add_generic*] 
+   [*wave_add_serial*]
 
    wave_id: >=0
    A number referencing a wave created by [*wave_create*].
 
    wave_send_*:
-   One of [*wave_send_once*], [*wave_send_repeat*].
+   One of the following
+
+   [*wave_send_once*] 
+   [*wave_send_repeat*]
 
    wdog_timeout: 0-60000
    Defines a GPIO watchdog timeout in milliseconds.  If no level
index 284a3ae19acf5bdbfd4fa820f85c41d0673f01df..2fe7ed2a468708cb6aa1b43a1be90bad4a4f8654 100644 (file)
@@ -3612,6 +3612,11 @@ handle: >=0, as returned by a call to \fBserial_open\fP.
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
 
+.br
+
+.br
+If no data is ready PI_SER_READ_NO_DATA is returned.
+
 .IP "\fBint serial_write(unsigned handle, char *buf, unsigned count)\fP"
 .IP "" 4
 This function writes count bytes from buf to the the serial port
@@ -3662,6 +3667,11 @@ handle: >=0, as returned by a call to \fBserial_open\fP.
 Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
 
+.br
+
+.br
+If no data is ready zero is returned.
+
 .IP "\fBint serial_data_available(unsigned handle)\fP"
 .IP "" 4
 Returns the number of bytes available to be read from the
index 6706b9dd6410e475f875f83ec718392675637a93..6200a798c295f7634e1488492c5b67aa702e128c 100644 (file)
@@ -2318,6 +2318,8 @@ handle: >=0, as returned by a call to [*serial_open*].
 
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
+
+If no data is ready PI_SER_READ_NO_DATA is returned.
 D*/
 
 /*F*/
@@ -2350,6 +2352,8 @@ handle: >=0, as returned by a call to [*serial_open*].
 
 Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
+
+If no data is ready zero is returned.
 D*/
 
 /*F*/
index 66ad4e05cc8791a8a3efc468d2de8d08bfd5d2e9..5b25e0c60450c6f7faf81fa307cc57b1c28da740 100644 (file)
@@ -1008,23 +1008,30 @@ by one for each report.
 .br
 
 .br
-flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE.
+flags: three flags are defined, PI_NTFY_FLAGS_WDOG,
+PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT.
 
 .br
 
 .br
-PI_NTFY_FLAGS_WDOG, if bit 5 is set then bits 0-4 of the flags
+If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags
 indicate a GPIO which has had a watchdog timeout.
 
 .br
 
 .br
-PI_NTFY_FLAGS_ALIVE, if bit 6 is set this indicates a keep alive
+If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive
 signal on the pipe/socket and is sent once a minute in the absence
 of other notification activity.
 
 .br
 
+.br
+If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the flags
+indicate an event which has been triggered.
+
+.br
+
 .br
 tick: the number of microseconds since system boot.  It wraps around
 after 1h12m.
@@ -4423,6 +4430,11 @@ handle: >=0, as returned by a call to \fBserial_open\fP.
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
 
+.br
+
+.br
+If no data is ready PI_SER_READ_NO_DATA is returned.
+
 .IP "\fBint serial_write(int pi, unsigned handle, char *buf, unsigned count)\fP"
 .IP "" 4
 This function writes count bytes from buf to the the serial port
@@ -4474,9 +4486,14 @@ handle: >=0, as returned by a call to \fBserial_open\fP.
 .br
 
 .br
-Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
 
+.br
+
+.br
+If no data is ready zero is returned.
+
 .IP "\fBint serial_data_available(int pi, unsigned handle)\fP"
 .IP "" 4
 Returns the number of bytes available to be read from the
@@ -5331,8 +5348,8 @@ pigif_duplicate_callback, or pigif_bad_callback.
 .br
 
 .br
-The callback is called with the GPIO, edge, tick, and user, whenever
-the GPIO has the identified edge.
+The callback is called with the GPIO, edge, tick, and the userdata
+pointer, whenever the GPIO has the identified edge.
 
 .IP "\fBint callback_cancel(unsigned callback_id)\fP"
 .IP "" 4
@@ -5355,7 +5372,7 @@ The function returns 0 if OK, otherwise pigif_callback_not_found.
 
 .IP "\fBint wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout)\fP"
 .IP "" 4
-This function waits for edge on the GPIO for up to timeout
+This function waits for an edge on the GPIO for up to timeout
 seconds.
 
 .br
@@ -5391,6 +5408,479 @@ a \fBcallback\fP function.
 
 .br
 The function returns 1 if the edge occurred, otherwise 0.
+
+.IP "\fBint bsc_xfer(int pi, bsc_xfer_t *bscxfer)\fP"
+.IP "" 4
+This function provides a low-level interface to the
+SPI/I2C Slave peripheral.  This peripheral allows the
+Pi to act as a slave device on an I2C or SPI bus.
+
+.br
+
+.br
+I can't get SPI to work properly.  I tried with a
+control word of 0x303 and swapped MISO and MOSI.
+
+.br
+
+.br
+The function sets the BSC mode, writes any data in
+the transmit buffer to the BSC transmit FIFO, and
+copies any data in the BSC receive FIFO to the
+receive buffer.
+
+.br
+
+.br
+
+.EX
+     pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+bscxfer: a structure defining the transfer.
+.br
+
+.br
+typedef struct
+.br
+{
+.br
+   uint32_t control;          // Write
+.br
+   int rxCnt;                 // Read only
+.br
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+.br
+   int txCnt;                 // Write
+.br
+   char txBuf[BSC_FIFO_SIZE]; // Write
+.br
+} bsc_xfer_t;
+.br
+
+.EE
+
+.br
+
+.br
+To start a transfer set control (see below) and copy the bytes to
+be sent (if any) to txBuf and set the byte count in txCnt.
+
+.br
+
+.br
+Upon return rxCnt will be set to the number of received bytes placed
+in rxBuf.
+
+.br
+
+.br
+The returned function value is the status of the transfer (see below).
+
+.br
+
+.br
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+.br
+
+.br
+The most significant word of the returned status contains the number
+of bytes actually copied from txBuf to the BSC transmit FIFO (may be
+less than requested if the FIFO already contained untransmitted data).
+
+.br
+
+.br
+Note that the control word sets the BSC mode.  The BSC will stay in
+that mode until a different control word is sent.
+
+.br
+
+.br
+The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL) in I2C mode
+and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO), and 21 (CE) in SPI mode.  You
+need to swap MISO/MOSI between master and slave.
+
+.br
+
+.br
+When a zero control word is received GPIO 18-21 will be reset
+to INPUT mode.
+
+.br
+
+.br
+control consists of the following bits.
+
+.br
+
+.br
+
+.EX
+22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+.br
+
+.EE
+
+.br
+
+.br
+Bits 0-13 are copied unchanged to the BSC CR register.  See
+pages 163-165 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.br
+aaaaaaa   defines the I2C slave address (only relevant in I2C mode)
+.br
+IT        invert transmit status flags
+.br
+HC        enable host control
+.br
+TF        enable test FIFO
+.br
+IR        invert receive status flags
+.br
+RE        enable receive
+.br
+TE        enable transmit
+.br
+BK        abort operation and clear FIFOs
+.br
+EC        send control register as first I2C byte
+.br
+ES        send status register as first I2C byte
+.br
+PL        set SPI polarity high
+.br
+PH        set SPI phase high
+.br
+I2        enable I2C mode
+.br
+SP        enable SPI mode
+.br
+EN        enable BSC peripheral
+.br
+
+.br
+
+.br
+The returned status has the following format
+
+.br
+
+.br
+
+.EX
+20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+.br
+
+.EE
+
+.br
+
+.br
+Bits 0-15 are copied unchanged from the BSC FR register.  See
+pages 165-166 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.br
+SSSSS   number of bytes successfully copied to transmit FIFO
+.br
+RRRRR   number of bytes in receieve FIFO
+.br
+TTTTT   number of bytes in transmit FIFO
+.br
+RB      receive busy
+.br
+TE      transmit FIFO empty
+.br
+RF      receive FIFO full
+.br
+TF      transmit FIFO full
+.br
+RE      receive FIFO empty
+.br
+TB      transmit busy
+.br
+
+.br
+
+.br
+The following example shows how to configure the BSC peripheral as
+an I2C slave with address 0x13 and send four bytes.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+bsc_xfer_t xfer;
+.br
+
+.br
+xfer.control = (0x13<<16) | 0x305;
+.br
+
+.br
+memcpy(xfer.txBuf, "ABCD", 4);
+.br
+xfer.txCnt = 4;
+.br
+
+.br
+status = bsc_xfer(pi, &xfer);
+.br
+
+.br
+if (status >= 0)
+.br
+{
+.br
+   // process transfer
+.br
+}
+.br
+
+.EE
+
+.IP "\fBint bsc_i2c(int pi, int i2c_addr, bsc_xfer_t *bscxfer)\fP"
+.IP "" 4
+This function allows the Pi to act as a slave I2C device.
+
+.br
+
+.br
+The data bytes (if any) are written to the BSC transmit
+FIFO and the bytes in the BSC receive FIFO are returned.
+
+.br
+
+.br
+
+.EX
+      pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+i2c_addr: 0-0x7F.
+.br
+ bscxfer: a structure defining the transfer.
+.br
+
+.br
+typedef struct
+.br
+{
+.br
+   uint32_t control;          // N/A
+.br
+   int rxCnt;                 // Read only
+.br
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+.br
+   int txCnt;                 // Write
+.br
+   char txBuf[BSC_FIFO_SIZE]; // Write
+.br
+} bsc_xfer_t;
+.br
+
+.EE
+
+.br
+
+.br
+txCnt is set to the number of bytes to be transmitted, possibly
+zero. The data itself should be copied to txBuf.
+
+.br
+
+.br
+Any received data will be written to rxBuf with rxCnt set.
+
+.br
+
+.br
+See \fBbsc_xfer\fP for details of the returned status value.
+
+.br
+
+.br
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+.br
+
+.br
+Note that an i2c_address of 0 may be used to close
+the BSC device and reassign the used GPIO (18/19)
+as inputs.
+
+.IP "\fBint event_callback(int pi, unsigned event, evtCBFunc_t f)\fP"
+.IP "" 4
+This function initialises an event callback.
+
+.br
+
+.br
+
+.EX
+   pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+event: 0-31.
+.br
+    f: the callback function.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+.br
+
+.br
+The callback is called with the event id, and tick, whenever the
+event occurs.
+
+.IP "\fBint event_callback_ex(int pi, unsigned event, evtCBFuncEx_t f, void *userdata)\fP"
+.IP "" 4
+This function initialises an event callback.
+
+.br
+
+.br
+
+.EX
+      pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+   event: 0-31.
+.br
+       f: the callback function.
+.br
+userdata: a pointer to arbitrary user data.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+.br
+
+.br
+The callback is called with the event id, the tick, and the userdata
+pointer whenever the event occurs.
+
+.IP "\fBint event_callback_cancel(unsigned callback_id)\fP"
+.IP "" 4
+This function cancels an event callback identified by its id.
+
+.br
+
+.br
+
+.EX
+callback_id: >=0, as returned by a call to \fBevent_callback\fP or
+.br
+\fBevent_callback_ex\fP.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns 0 if OK, otherwise pigif_callback_not_found.
+
+.IP "\fBint wait_for_event(int pi, unsigned event, double timeout)\fP"
+.IP "" 4
+This function waits for an event for up to timeout seconds.
+
+.br
+
+.br
+
+.EX
+     pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+  event: 0-31.
+.br
+timeout: >=0.
+.br
+
+.EE
+
+.br
+
+.br
+The function returns when the event occurs or after the timeout.
+
+.br
+
+.br
+The function returns 1 if the event occurred, otherwise 0.
+
+.IP "\fBint event_trigger(int pi, unsigned event)\fP"
+.IP "" 4
+This function signals the occurrence of an event.
+
+.br
+
+.br
+
+.EX
+   pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+event: 0-31.
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+.br
+
+.br
+An event is a signal used to inform one or more consumers
+to start an action.  Each consumer which has registered an interest
+in the event (e.g. by calling \fBevent_callback\fP) will be informed by
+a callback.
+
+.br
+
+.br
+One event, PI_EVENT_BSC (31) is predefined.  This event is
+auto generated on BSC slave activity.
+
+.br
+
+.br
+The meaning of other events is arbitrary.
+
+.br
+
+.br
+Note that other than its id and its tick there is no data associated
+with an event.
 .SH PARAMETERS
 
 .br
@@ -5484,6 +5974,43 @@ e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
 
 .br
 
+.IP "\fBbsc_xfer_t\fP" 0
+
+.br
+
+.br
+
+.EX
+typedef struct
+.br
+{
+.br
+   uint32_t control;          // Write
+.br
+   int rxCnt;                 // Read only
+.br
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+.br
+   int txCnt;                 // Write
+.br
+   char txBuf[BSC_FIFO_SIZE]; // Write
+.br
+} bsc_xfer_t;
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fB*bscxfer\fP" 0
+A pointer to a \fBbsc_xfer_t\fP object used to control a BSC transfer.
+
+.br
+
+.br
+
 .IP "\fB*buf\fP" 0
 A buffer to hold data being sent or being received.
 
@@ -5510,8 +6037,24 @@ An 8-bit byte value.
 .br
 
 .IP "\fBcallback_id\fP" 0
-A >=0, as returned by a call to \fBcallback\fP or \fBcallback_ex\fP.  This is
-passed to \fBcallback_cancel\fP to cancel the callback.
+A value >=0, as returned by a call to a callback function, one of
+
+.br
+
+.br
+\fBcallback\fP
+.br
+\fBcallback_ex\fP
+.br
+\fBevent_callback\fP
+.br
+\fBevent_callback_ex\fP
+
+.br
+
+.br
+The id is passed to \fBcallback_cancel\fP or \fBevent_callback_cancel\fP
+to cancel the callback.
 
 .br
 
@@ -5536,7 +6079,7 @@ typedef void (*CBFunc_t)
 .EX
 typedef void (*CBFuncEx_t)
 .br
-   (unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+   (unsigned user_gpio, unsigned level, uint32_t tick, void * userdata);
 .br
 
 .EE
@@ -5643,6 +6186,50 @@ of the error.
 
 .br
 
+.IP "\fBevent\fP: 0-31" 0
+An event is a signal used to inform one or more consumers
+to start an action.
+
+.br
+
+.br
+
+.IP "\fBevtCBFunc_t\fP" 0
+
+.br
+
+.br
+
+.EX
+typedef void (*evtCBFunc_t)
+.br
+   (int pi, unsigned event, uint32_t tick);
+.br
+
+.EE
+
+.br
+
+.br
+
+.IP "\fBevtCBFuncEx_t\fP" 0
+
+.br
+
+.br
+
+.EX
+typedef void (*evtCBFuncEx_t)
+.br
+   (int pi, unsigned event, uint32_t tick, void *userdata);
+.br
+
+.EE
+
+.br
+
+.br
+
 .IP "\fBf\fP" 0
 A function.
 
@@ -5745,11 +6332,11 @@ typedef struct
 .br
 {
 .br
-uint32_t gpioOn;
+   uint32_t gpioOn;
 .br
-uint32_t gpioOff;
+   uint32_t gpioOff;
 .br
-uint32_t usDelay;
+   uint32_t usDelay;
 .br
 } gpioPulse_t;
 .br
@@ -5773,8 +6360,20 @@ typedef void *(gpioThreadFunc_t) (void *);
 .br
 
 .IP "\fBhandle\fP: >=0" 0
-A number referencing an object opened by one of \fBfile_open\fP,
-\fBi2c_open\fP, \fBnotify_open\fP, \fBserial_open\fP, and \fBspi_open\fP.
+A number referencing an object opened by one of
+
+.br
+
+.br
+\fBfile_open\fP
+.br
+\fBi2c_open\fP
+.br
+\fBnotify_open\fP
+.br
+\fBserial_open\fP
+.br
+\fBspi_open\fP
 
 .br
 
@@ -6196,6 +6795,10 @@ The hardware PWM frequency.
 .IP "\fBrange\fP: 25-40000" 0
 The permissible dutycycle values are 0-range.
 
+.br
+
+.br
+
 .EX
 PI_MIN_DUTYCYCLE_RANGE 25
 .br
@@ -6404,6 +7007,10 @@ thread.
 .IP "\fBtimeout\fP" 0
 A GPIO watchdog timeout in milliseconds.
 
+.br
+
+.br
+
 .EX
 PI_MIN_WDOG_TIMEOUT 0
 .br
@@ -6472,16 +7079,24 @@ In the calling function:
 .br
 
 .br
+
+.EX
 user_type *userdata;
 .br
+.br
+.br
 user_type my_userdata;
-
 .br
 
 .br
 userdata = malloc(sizeof(user_type));
 .br
+.br
+.br
 *userdata = my_userdata;
+.br
+
+.EE
 
 .br
 
@@ -6491,12 +7106,16 @@ In the receiving function:
 .br
 
 .br
-user_type my_userdata = *(user_type*)userdata;
 
+.EX
+user_type my_userdata = *(user_type*)userdata;
 .br
 
 .br
 free(userdata);
+.br
+
+.EE
 
 .br
 
@@ -6510,7 +7129,16 @@ Denoting no parameter is required
 .br
 
 .IP "\fBwave_add_*\fP" 0
-One of \fBwave_add_new\fP, \fBwave_add_generic\fP, \fBwave_add_serial\fP.
+One of
+
+.br
+
+.br
+\fBwave_add_new\fP
+.br
+\fBwave_add_generic\fP
+.br
+\fBwave_add_serial\fP
 
 .br
 
@@ -6524,7 +7152,14 @@ A number representing a waveform created by \fBwave_create\fP.
 .br
 
 .IP "\fBwave_send_*\fP" 0
-One of \fBwave_send_once\fP, \fBwave_send_repeat\fP.
+One of
+
+.br
+
+.br
+\fBwave_send_once\fP
+.br
+\fBwave_send_repeat\fP
 
 .br
 
index 842fb4be27e17704766635e3f393ec1d85b56c38..d94732a707648b97754494c6a224b293dbcdb344 100644 (file)
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 For more information, please refer to <http://unlicense.org/>
 */
 
-/* PIGPIOD_IF2_VERSION 8 */
+/* PIGPIOD_IF2_VERSION 9 */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -74,6 +74,19 @@ struct callback_s
    callback_t *next;
 };
 
+struct evtCallback_s
+{
+
+   int id;
+   int pi;
+   int event;
+   CBF_t f;
+   void * user;
+   int ex;
+   evtCallback_t *prev;
+   evtCallback_t *next;
+};
+
 /* GLOBALS ---------------------------------------------------------------- */
 
 static int             gPiInUse     [MAX_PI];
@@ -82,6 +95,7 @@ static int             gPigCommand  [MAX_PI];
 static int             gPigHandle   [MAX_PI];
 static int             gPigNotify   [MAX_PI];
 
+static uint32_t        gEventBits   [MAX_PI];
 static uint32_t        gNotifyBits  [MAX_PI];
 static uint32_t        gLastLevel   [MAX_PI];
 
@@ -93,6 +107,9 @@ static int             gCancelState [MAX_PI];
 static callback_t *gCallBackFirst = 0;
 static callback_t *gCallBackLast  = 0;
 
+static evtCallback_t *geCallBackFirst = 0;
+static evtCallback_t *geCallBackLast  = 0;
+
 /* PRIVATE ---------------------------------------------------------------- */
 
 static void _pml(int pi)
@@ -278,6 +295,7 @@ static int pigpioOpenSocket(char *addr, char *port)
 static void dispatch_notification(int pi, gpioReport_t *r)
 {
    callback_t *p;
+   evtCallback_t *ep;
    uint32_t changed;
    int l, g;
 
@@ -310,18 +328,37 @@ static void dispatch_notification(int pi, gpioReport_t *r)
    }
    else
    {
-      g = (r->flags) & 31;
+      if ((r->flags) & PI_NTFY_FLAGS_WDOG)
+      {
+         g = (r->flags) & 31;
 
-      p = gCallBackFirst;
+         p = gCallBackFirst;
 
-      while (p)
+         while (p)
+         {
+            if (((p->pi) == pi) && ((p->gpio) == g))
+            {
+               if (p->ex) (p->f)(pi, g, PI_TIMEOUT, r->tick, p->user);
+               else       (p->f)(pi, g, PI_TIMEOUT, r->tick);
+            }
+            p = p->next;
+         }
+      }
+      else if ((r->flags) & PI_NTFY_FLAGS_EVENT)
       {
-         if (((p->pi) == pi) && ((p->gpio) == g))
+         g = (r->flags) & 31;
+
+         ep = geCallBackFirst;
+
+         while (ep)
          {
-            if (p->ex) (p->f)(pi, g, PI_TIMEOUT, r->tick, p->user);
-            else       (p->f)(pi, g, PI_TIMEOUT, r->tick);
+            if (((ep->pi) == pi) && ((ep->event) == g))
+            {
+               if (ep->ex) (ep->f)(pi, g, r->tick, ep->user);
+               else        (ep->f)(pi, g, r->tick);
+            }
+            ep = ep->next;
          }
-         p = p->next;
       }
    }
 }
@@ -447,8 +484,90 @@ static int intCallback(
    return pigif_bad_callback;
 }
 
+static void findEventBits(int pi)
+{
+   evtCallback_t *ep;
+   uint32_t bits = 0;
+
+   ep = geCallBackFirst;
+
+   while (ep)
+   {
+      if (ep->pi == pi) bits |= (1<<(ep->event));
+      ep = ep->next;
+   }
+
+   if (bits != gEventBits[pi])
+   {
+      gEventBits[pi] = bits;
+      pigpio_command(pi, PI_CMD_EVM, gPigHandle[pi], gEventBits[pi], 1);
+   }
+}
+
+static void _ewfe(
+   int pi, unsigned event, uint32_t tick, void *user)
+{
+   *(int *)user = 1;
+}
+
+static int intEventCallback(
+   int pi, unsigned event, void *f, void *user, int ex)
+{
+   static int id = 0;
+   evtCallback_t *ep;
+
+   if ((event >=0) && (event < 32) && f)
+   {
+      /* prevent duplicates */
+
+      ep = geCallBackFirst;
+
+      while (ep)
+      {
+         if ((ep->pi    == pi)    &&
+             (ep->event == event) &&
+             (ep->f     == f))
+         {
+            return pigif_duplicate_callback;
+         }
+         ep = ep->next;
+      }
+
+      ep = malloc(sizeof(evtCallback_t));
+
+      if (ep)
+      {
+         if (!geCallBackFirst) geCallBackFirst = ep;
+
+         ep->id = id++;
+         ep->pi = pi;
+         ep->event = event;
+         ep->f = f;
+         ep->user = user;
+         ep->ex = ex;
+         ep->next = 0;
+         ep->prev = geCallBackLast;
+
+         if (ep->prev) (ep->prev)->next = ep;
+         geCallBackLast = ep;
+
+         findEventBits(pi);
+
+         return ep->id;
+      }
+
+      return pigif_bad_malloc;
+   }
+
+   return pigif_bad_callback;
+}
+
 static int recvMax(int pi, void *buf, int bufsize, int sent)
 {
+   /*
+   Copy at most bufSize bytes from the receieved message to
+   buf.  Discard the rest of the message.
+   */
    uint8_t scratch[4096];
    int remaining, fetch, count;
 
@@ -1875,3 +1994,114 @@ int wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout)
    return triggered;
 }
 
+int bsc_xfer(int pi, bsc_xfer_t *bscxfer)
+{
+   int bytes;
+   int status;
+   gpioExtent_t ext[1];
+
+   /*
+   p1=control
+   p2=0
+   p3=len
+   ## extension ##
+   char buf[len]
+   */
+
+   ext[0].size = bscxfer->txCnt;
+   ext[0].ptr = bscxfer->txBuf;
+
+   bytes = pigpio_command_ext
+      (pi, PI_CMD_BSCX, bscxfer->control, 0, bscxfer->txCnt, 1, ext, 0);
+
+   if (bytes > 0)
+   {
+      recvMax(pi, &status, 4, 4);
+      status = ntohl(status);
+      bytes -= 4;
+      bytes = recvMax(pi, bscxfer->rxBuf, sizeof(bscxfer->rxBuf), bytes);
+      bscxfer->rxCnt = bytes;
+   }
+   else
+   {
+      status = bytes;
+   }
+
+   _pmu(pi);
+
+   return status;
+}
+
+
+int bsc_i2c(int pi, int i2c_addr, bsc_xfer_t *bscxfer)
+{
+   int control = 0;
+
+   if (i2c_addr) control = (i2c_addr<<16) | 0x305;
+   bscxfer->control = control;
+   return bsc_xfer(pi, bscxfer);
+}
+
+
+int event_callback(int pi, unsigned event, evtCBFunc_t f)
+   {return intEventCallback(pi, event, f, 0, 0);}
+
+int event_callback_ex(
+   int pi, unsigned event, evtCBFuncEx_t f, void *user)
+   {return intEventCallback(pi, event, f, user, 1);}
+
+int event_callback_cancel(unsigned id)
+{
+   evtCallback_t *ep;
+   int pi;
+
+   ep = geCallBackFirst;
+
+   while (ep)
+   {
+      if (ep->id == id)
+      {
+         pi = ep->pi;
+
+         if (ep->prev) {ep->prev->next = ep->next;}
+         else          {geCallBackFirst = ep->next;}
+
+         if (ep->next) {ep->next->prev = ep->prev;}
+         else          {geCallBackLast = ep->prev;}
+
+         free(ep);
+
+         findEventBits(pi);
+
+         return 0;
+      }
+      ep = ep->next;
+   }
+   return pigif_callback_not_found;
+}
+
+int wait_for_event(int pi, unsigned event, double timeout)
+{
+   int triggered = 0;
+   int id;
+   double due;
+
+   if ((pi < 0) || (pi >= MAX_PI) || !gPiInUse[pi])
+      return pigif_unconnected_pi;
+
+   if (timeout <= 0.0) return 0;
+
+   due = time_time() + timeout;
+
+   id = event_callback_ex(pi, event, _ewfe, &triggered);
+
+   while (!triggered && (time_time() < due)) time_sleep(0.05);
+
+   event_callback_cancel(id);
+
+   return triggered;
+}
+
+int event_trigger(int pi, unsigned event)
+   {return pigpio_command(pi, PI_CMD_EVM, event, 0, 1);}
+
index ced2c9adda239f404b482cc04f2a952b7d682adb..dc6f70147a8e26d2fae2eea64c2335c93408f796 100644 (file)
@@ -121,7 +121,7 @@ set_servo_pulsewidth       Start/stop servo pulses on a GPIO
 get_servo_pulsewidth       Get the servo pulsewidth in use on a GPIO
 
 callback                   Create GPIO level change callback
-callback_ex                Create GPIO level change callback
+callback_ex                Create GPIO level change callback, extended
 callback_cancel            Cancel a callback
 wait_for_edge              Wait for GPIO level change
 
@@ -257,6 +257,11 @@ bb_spi_open                Opens GPIO for bit banging SPI
 bb_spi_close               Closes GPIO for bit banging SPI
 bb_spi_xfer                Transfers bytes with bit banging SPI
 
+I2C/SPI_SLAVE
+
+bsc_xfer                   I2C/SPI as slave transfer
+bsc_i2c                    I2C as slave transfer
+
 SERIAL
 
 serial_open                Opens a serial device
@@ -278,6 +283,14 @@ file_write                 Writes bytes to a file
 file_seek                  Seeks to a position within a file
 file_list                  List files which match a pattern
 
+EVENTS
+
+event_callback            Sets a callback for an event
+event_callback_ex         Sets a callback for an event, extended
+event_callback_cancel     Cancel an event callback
+event_trigger             Triggers an event
+wait_for_event            Wait for an event
+
 CUSTOM
 
 custom_1                   User custom function 1
@@ -306,10 +319,18 @@ typedef void (*CBFunc_t)
    (int pi, unsigned user_gpio, unsigned level, uint32_t tick);
 
 typedef void (*CBFuncEx_t)
-   (int pi, unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+   (int pi, unsigned user_gpio, unsigned level, uint32_t tick, void *userdata);
 
 typedef struct callback_s callback_t;
 
+typedef void (*evtCBFunc_t)
+   (int pi, unsigned event, uint32_t tick);
+
+typedef void (*evtCBFuncEx_t)
+   (int pi, unsigned event, uint32_t tick, void *userdata);
+
+typedef struct evtCallback_s evtCallback_t;
+
 /*F*/
 double time_time(void);
 /*D
@@ -788,15 +809,19 @@ typedef struct
 seqno: starts at 0 each time the handle is opened and then increments
 by one for each report.
 
-flags: two flags are defined, PI_NTFY_FLAGS_WDOG and PI_NTFY_FLAGS_ALIVE.
+flags: three flags are defined, PI_NTFY_FLAGS_WDOG,
+PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT.
 
-PI_NTFY_FLAGS_WDOG, if bit 5 is set then bits 0-4 of the flags
+If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the flags
 indicate a GPIO which has had a watchdog timeout.
 
-PI_NTFY_FLAGS_ALIVE, if bit 6 is set this indicates a keep alive
+If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep alive
 signal on the pipe/socket and is sent once a minute in the absence
 of other notification activity.
 
+If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the flags
+indicate an event which has been triggered.
+
 tick: the number of microseconds since system boot.  It wraps around
 after 1h12m.
 
@@ -2743,6 +2768,8 @@ handle: >=0, as returned by a call to [*serial_open*].
 
 Returns the read byte (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_SER_READ_NO_DATA, or PI_SER_READ_FAILED.
+
+If no data is ready PI_SER_READ_NO_DATA is returned.
 D*/
 
 /*F*/
@@ -2775,8 +2802,10 @@ handle: >=0, as returned by a call to [*serial_open*].
  count: the maximum number of bytes to read.
 . .
 
-Returns the number of bytes read (>0) if OK, otherwise PI_BAD_HANDLE,
+Returns the number of bytes read (>=0) if OK, otherwise PI_BAD_HANDLE,
 PI_BAD_PARAM, PI_SER_READ_NO_DATA, or PI_SER_WRITE_FAILED.
+
+If no data is ready zero is returned.
 D*/
 
 /*F*/
@@ -3237,8 +3266,8 @@ user_gpio: 0-31.
 The function returns a callback id if OK, otherwise pigif_bad_malloc,
 pigif_duplicate_callback, or pigif_bad_callback.
 
-The callback is called with the GPIO, edge, tick, and user, whenever
-the GPIO has the identified edge.
+The callback is called with the GPIO, edge, tick, and the userdata
+pointer, whenever the GPIO has the identified edge.
 D*/
 
 /*F*/
@@ -3256,7 +3285,7 @@ D*/
 /*F*/
 int wait_for_edge(int pi, unsigned user_gpio, unsigned edge, double timeout);
 /*D
-This function waits for edge on the GPIO for up to timeout
+This function waits for an edge on the GPIO for up to timeout
 seconds.
 
 . .
@@ -3276,6 +3305,258 @@ a [*callback*] function.
 The function returns 1 if the edge occurred, otherwise 0.
 D*/
 
+/*F*/
+int bsc_xfer(int pi, bsc_xfer_t *bscxfer);
+/*D
+This function provides a low-level interface to the
+SPI/I2C Slave peripheral.  This peripheral allows the
+Pi to act as a slave device on an I2C or SPI bus.
+
+I can't get SPI to work properly.  I tried with a
+control word of 0x303 and swapped MISO and MOSI.
+
+The function sets the BSC mode, writes any data in
+the transmit buffer to the BSC transmit FIFO, and
+copies any data in the BSC receive FIFO to the
+receive buffer.
+
+. .
+     pi: >=0 (as returned by [*pigpio_start*]).
+bscxfer: a structure defining the transfer.
+
+typedef struct
+{
+   uint32_t control;          // Write
+   int rxCnt;                 // Read only
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+   int txCnt;                 // Write
+   char txBuf[BSC_FIFO_SIZE]; // Write
+} bsc_xfer_t;
+. .
+
+To start a transfer set control (see below) and copy the bytes to
+be sent (if any) to txBuf and set the byte count in txCnt.
+
+Upon return rxCnt will be set to the number of received bytes placed
+in rxBuf.
+
+The returned function value is the status of the transfer (see below).
+
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+The most significant word of the returned status contains the number
+of bytes actually copied from txBuf to the BSC transmit FIFO (may be
+less than requested if the FIFO already contained untransmitted data).
+
+Note that the control word sets the BSC mode.  The BSC will stay in
+that mode until a different control word is sent.
+
+The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL) in I2C mode
+and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO), and 21 (CE) in SPI mode.  You
+need to swap MISO/MOSI between master and slave.
+
+When a zero control word is received GPIO 18-21 will be reset
+to INPUT mode.
+
+control consists of the following bits.
+
+. .
+22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+ a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+. .
+
+Bits 0-13 are copied unchanged to the BSC CR register.  See
+pages 163-165 of the Broadcom peripherals document for full
+details.
+
+aaaaaaa @ defines the I2C slave address (only relevant in I2C mode)
+IT      @ invert transmit status flags
+HC      @ enable host control
+TF      @ enable test FIFO
+IR      @ invert receive status flags
+RE      @ enable receive
+TE      @ enable transmit
+BK      @ abort operation and clear FIFOs
+EC      @ send control register as first I2C byte
+ES      @ send status register as first I2C byte
+PL      @ set SPI polarity high
+PH      @ set SPI phase high
+I2      @ enable I2C mode
+SP      @ enable SPI mode
+EN      @ enable BSC peripheral
+
+The returned status has the following format
+
+. .
+20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+ S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+. .
+
+Bits 0-15 are copied unchanged from the BSC FR register.  See
+pages 165-166 of the Broadcom peripherals document for full
+details.
+
+SSSSS @ number of bytes successfully copied to transmit FIFO
+RRRRR @ number of bytes in receieve FIFO
+TTTTT @ number of bytes in transmit FIFO
+RB    @ receive busy
+TE    @ transmit FIFO empty
+RF    @ receive FIFO full
+TF    @ transmit FIFO full
+RE    @ receive FIFO empty
+TB    @ transmit busy
+
+The following example shows how to configure the BSC peripheral as
+an I2C slave with address 0x13 and send four bytes.
+
+...
+bsc_xfer_t xfer;
+
+xfer.control = (0x13<<16) | 0x305;
+
+memcpy(xfer.txBuf, "ABCD", 4);
+xfer.txCnt = 4;
+
+status = bsc_xfer(pi, &xfer);
+
+if (status >= 0)
+{
+   // process transfer
+}
+...
+D*/
+
+/*F*/
+int bsc_i2c(int pi, int i2c_addr, bsc_xfer_t *bscxfer);
+/*D
+This function allows the Pi to act as a slave I2C device.
+
+The data bytes (if any) are written to the BSC transmit
+FIFO and the bytes in the BSC receive FIFO are returned.
+
+. .
+      pi: >=0 (as returned by [*pigpio_start*]).
+i2c_addr: 0-0x7F.
+ bscxfer: a structure defining the transfer.
+
+typedef struct
+{
+   uint32_t control;          // N/A
+   int rxCnt;                 // Read only
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+   int txCnt;                 // Write
+   char txBuf[BSC_FIFO_SIZE]; // Write
+} bsc_xfer_t;
+. .
+
+txCnt is set to the number of bytes to be transmitted, possibly
+zero. The data itself should be copied to txBuf.
+
+Any received data will be written to rxBuf with rxCnt set.
+
+See [*bsc_xfer*] for details of the returned status value.
+
+If there was an error the status will be less than zero
+(and will contain the error code).
+
+Note that an i2c_address of 0 may be used to close
+the BSC device and reassign the used GPIO (18/19)
+as inputs.
+D*/
+
+/*F*/
+int event_callback(int pi, unsigned event, evtCBFunc_t f);
+/*D
+This function initialises an event callback.
+
+. .
+   pi: >=0 (as returned by [*pigpio_start*]).
+event: 0-31.
+    f: the callback function.
+. .
+
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+The callback is called with the event id, and tick, whenever the
+event occurs.
+D*/
+
+/*F*/
+int event_callback_ex(int pi, unsigned event, evtCBFuncEx_t f, void *userdata);
+/*D
+This function initialises an event callback.
+
+. .
+      pi: >=0 (as returned by [*pigpio_start*]).
+   event: 0-31.
+       f: the callback function.
+userdata: a pointer to arbitrary user data.
+. .
+
+The function returns a callback id if OK, otherwise pigif_bad_malloc,
+pigif_duplicate_callback, or pigif_bad_callback.
+
+The callback is called with the event id, the tick, and the userdata
+pointer whenever the event occurs.
+D*/
+
+/*F*/
+int event_callback_cancel(unsigned callback_id);
+/*D
+This function cancels an event callback identified by its id.
+
+. .
+callback_id: >=0, as returned by a call to [*event_callback*] or
+[*event_callback_ex*].
+. .
+
+The function returns 0 if OK, otherwise pigif_callback_not_found.
+D*/
+
+/*F*/
+int wait_for_event(int pi, unsigned event, double timeout);
+/*D
+This function waits for an event for up to timeout seconds.
+
+. .
+     pi: >=0 (as returned by [*pigpio_start*]).
+  event: 0-31.
+timeout: >=0.
+. .
+
+The function returns when the event occurs or after the timeout.
+
+The function returns 1 if the event occurred, otherwise 0.
+D*/
+
+/*F*/
+int event_trigger(int pi, unsigned event);
+/*D
+This function signals the occurrence of an event.
+
+. .
+   pi: >=0 (as returned by [*pigpio_start*]).
+event: 0-31.
+. .
+
+Returns 0 if OK, otherwise PI_BAD_EVENT_ID.
+
+An event is a signal used to inform one or more consumers
+to start an action.  Each consumer which has registered an interest
+in the event (e.g. by calling [*event_callback*]) will be informed by
+a callback.
+
+One event, PI_EVENT_BSC (31) is predefined.  This event is
+auto generated on BSC slave activity.
+
+The meaning of other events is arbitrary.
+
+Note that other than its id and its tick there is no data associated
+with an event.
+D*/
+
 /*PARAMS
 
 active :: 0-1000000
@@ -3320,6 +3601,22 @@ A convenient way to set bit n is to or in (1<<n).
 
 e.g. to select bits 5, 9, 23 you could use (1<<5) | (1<<9) | (1<<23).
 
+bsc_xfer_t::
+
+. .
+typedef struct
+{
+   uint32_t control;          // Write
+   int rxCnt;                 // Read only
+   char rxBuf[BSC_FIFO_SIZE]; // Read only
+   int txCnt;                 // Write
+   char txBuf[BSC_FIFO_SIZE]; // Write
+} bsc_xfer_t;
+. .
+
+*bscxfer::
+A pointer to a [*bsc_xfer_t*] object used to control a BSC transfer.
+
 *buf::
 A buffer to hold data being sent or being received.
 
@@ -3331,8 +3628,15 @@ bVal::0-255 (Hex 0x0-0xFF, Octal 0-0377)
 An 8-bit byte value.
 
 callback_id::
-A >=0, as returned by a call to [*callback*] or [*callback_ex*].  This is
-passed to [*callback_cancel*] to cancel the callback.
+A value >=0, as returned by a call to a callback function, one of
+
+[*callback*] 
+[*callback_ex*] 
+[*event_callback*] 
+[*event_callback_ex*]
+
+The id is passed to [*callback_cancel*] or [*event_callback_cancel*]
+to cancel the callback.
 
 CBFunc_t::
 . .
@@ -3343,7 +3647,7 @@ typedef void (*CBFunc_t)
 CBFuncEx_t::
 . .
 typedef void (*CBFuncEx_t)
-   (unsigned user_gpio, unsigned level, uint32_t tick, void * user);
+   (unsigned user_gpio, unsigned level, uint32_t tick, void * userdata);
 . .
 
 char::
@@ -3390,6 +3694,24 @@ errnum::
 A negative number indicating a function call failed and the nature
 of the error.
 
+event::0-31
+An event is a signal used to inform one or more consumers
+to start an action.
+
+evtCBFunc_t::
+
+. .
+typedef void (*evtCBFunc_t)
+   (int pi, unsigned event, uint32_t tick);
+. .
+
+evtCBFuncEx_t::
+
+. .
+typedef void (*evtCBFuncEx_t)
+   (int pi, unsigned event, uint32_t tick, void *userdata);
+. .
+
 f::
 A function.
 
@@ -3440,9 +3762,9 @@ gpioPulse_t::
 . .
 typedef struct
 {
-uint32_t gpioOn;
-uint32_t gpioOff;
-uint32_t usDelay;
+   uint32_t gpioOn;
+   uint32_t gpioOff;
+   uint32_t usDelay;
 } gpioPulse_t;
 . .
 
@@ -3452,8 +3774,13 @@ typedef void *(gpioThreadFunc_t) (void *);
 . .
 
 handle::>=0
-A number referencing an object opened by one of [*file_open*],
-[*i2c_open*], [*notify_open*], [*serial_open*], and [*spi_open*].
+A number referencing an object opened by one of
+
+[*file_open*] 
+[*i2c_open*] 
+[*notify_open*] 
+[*serial_open*] 
+[*spi_open*]
 
 i2c_addr::0-0x7F
 The address of a device on the I2C bus.
@@ -3640,6 +3967,7 @@ The hardware PWM frequency.
 
 range::25-40000
 The permissible dutycycle values are 0-range.
+
 . .
 PI_MIN_DUTYCYCLE_RANGE 25
 PI_MAX_DUTYCYCLE_RANGE 40000
@@ -3731,6 +4059,7 @@ thread.
 
 timeout::
 A GPIO watchdog timeout in milliseconds.
+
 . .
 PI_MIN_WDOG_TIMEOUT 0
 PI_MAX_WDOG_TIMEOUT 60000
@@ -3761,29 +4090,40 @@ following technique.
 
 In the calling function:
 
+. .
 user_type *userdata; 
 user_type my_userdata;
 
 userdata = malloc(sizeof(user_type)); 
 *userdata = my_userdata;
+. .
 
 In the receiving function:
 
+. .
 user_type my_userdata = *(user_type*)userdata;
 
 free(userdata);
+. .
 
 void::
 Denoting no parameter is required
 
 wave_add_*::
-One of [*wave_add_new*], [*wave_add_generic*], [*wave_add_serial*].
+One of
+
+[*wave_add_new*] 
+[*wave_add_generic*] 
+[*wave_add_serial*]
 
 wave_id::
 A number representing a waveform created by [*wave_create*].
 
 wave_send_*::
-One of [*wave_send_once*], [*wave_send_repeat*].
+One of
+
+[*wave_send_once*] 
+[*wave_send_repeat*]
 
 wVal::0-65535 (Hex 0x0-0xFFFF, Octal 0-0177777)
 A 16-bit word value.
diff --git a/pigs.1 b/pigs.1
index f8fcb7aa34e4a268fafe19fe435b6d1e4bbfaaf0..28bc9bfebdcae4602e7441d80fc033dc05233d21 100644 (file)
--- a/pigs.1
+++ b/pigs.1
@@ -484,11 +484,211 @@ ERROR: no permission to update one or more GPIO
 
 .br
 
+.IP "\fBBSCX bctl bvs\fP - BSC I2C/SPI transfer"
+.IP "" 4
+
+.br
+This command performs a BSC I2C/SPI slave transfer as defined by
+\fBbctl\fP with data \fBbvs\fP.
+
+.br
+I can't get SPI to work properly.  I tried with a
+control word of 0x303 and swapped MISO and MOSI.
+
+.br
+The command sets the BSC mode and writes any data \fBbvs\fP
+to the BSC transmit FIFO.  It returns the data count (at least 1
+for the status word), the status word, followed by any data bytes
+read from the BSC receive FIFO.
+
+.br
+Note that the control word sets the BSC mode.  The BSC will stay in
+that mode until a different control word is sent.
+
+.br
+For I2C use a control word of (I2C address << 16) + 0x305.
+
+.br
+E.g. to talk as I2C slave with address 0x13 use 0x130305.
+
+.br
+The BSC peripheral uses GPIO 18 (SDA) and 19 (SCL) in I2C mode
+and GPIO 18 (MOSI), 19 (SCLK), 20 (MISO), and 21 (CE) in SPI mode.  You
+need to swap MISO/MOSI between master and slave.
+
+.br
+When a zero control word is received GPIO 18-21 will be reset
+to INPUT mode.
+
+.br
+The control word consists of the following bits.
+
+.br
+
+.EX
+22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ a  a  a  a  a  a  a  -  - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN
+.br
+
+.EE
+
+.br
+Bits 0-13 are copied unchanged to the BSC CR register.  See
+pages 163-165 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.EX
+aaaaaaa   defines the I2C slave address (only relevant in I2C mode)
+IT        invert transmit status flags
+HC        enable host control
+TF        enable test FIFO
+IR        invert receive status flags
+RE        enable receive
+TE        enable transmit
+BK        abort operation and clear FIFOs
+EC        send control register as first I2C byte
+ES        send status register as first I2C byte
+PL        set SPI polarity high
+PH        set SPI phase high
+I2        enable I2C mode
+SP        enable SPI mode
+EN        enable BSC peripheral
+
+.EE
+
+.br
+The returned status has the following format
+
+.br
+
+.EX
+20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
+.br
+ S  S  S  S  S  R  R  R  R  R  T  T  T  T  T RB TE RF TF RE TB
+.br
+
+.EE
+
+.br
+Bits 0-15 are copied unchanged from the BSC FR register.  See
+pages 165-166 of the Broadcom peripherals document for full
+details.
+
+.br
+
+.EX
+SSSSS   number of bytes successfully copied to transmit FIFO
+RRRRR   number of bytes in receieve FIFO
+TTTTT   number of bytes in transmit FIFO
+RB      receive busy
+TE      transmit FIFO empty
+RF      receive FIFO full
+TF      transmit FIFO full
+RE      receive FIFO empty
+TB      transmit busy
+
+.EE
+
+.br
+This example assumes that GPIO 2/3 are connected to GPIO 18/19.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs bscx 0x130305 # start BSC as I2C slave 0x13
+.br
+1 18
+.br
+
+.br
+$ i2cdetect -y 1
+.br
+     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+.br
+00:          -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+10: -- -- -- 13 -- -- -- -- -- -- -- -- -- -- -- --
+.br
+20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+.br
+70: -- -- -- -- -- -- -- --
+.br
+
+.br
+$ pigs i2co 1 0x13 0 # get handle for device 0x13 on bus 1
+.br
+0
+.br
+
+.br
+$ pigs i2cwd 0 90 87 51 9 23 # write 5 bytes
+.br
+
+.br
+$ pigs bscx 0x130305 # check for data
+.br
+6 18 90 87 51 9 23
+.br
+
+.br
+$ pigs bscx 0x130305 11 13 15 17 # check for data and send 4 bytes
+.br
+1 262338
+.br
+
+.br
+$ pigs i2crd 0 4 # read 4 bytes
+.br
+4 11 13 15 17
+.br
+
+.br
+$ pigs i2cwd 0 90 87 51 9 23 # write 5 bytes
+.br
+$ pigs bscx 0x130305 11 13 15 17 # check for data and send 4 bytes
+.br
+6 262338 90 87 51 9 23
+.br
+
+.br
+$ pigs i2crd 0 4
+.br
+4 11 13 15 17
+.br
+
+.br
+$ pigs bscx 0x130305 22 33 44 55 66
+.br
+1 327938
+.br
+$ pigs i2crd 0 5
+.br
+5 22 33 44 55 66
+.br
+
+.EE
+
+.br
+
 .IP "\fBBSPIC cs\fP - Close bit bang SPI"
 .IP "" 4
 
 .br
-This function stops bit banging SPI on a set of GPIO
+This command stops bit banging SPI on a set of GPIO
 opened with \fBBSPIO\fP.
 
 .br
@@ -744,6 +944,72 @@ configuration settings to \fBv\fP.
 
 .br
 
+.IP "\fBEVM h bits\fP - Set events to monitor"
+.IP "" 4
+This command starts event reporting on handle \fBh\fP (returned by
+a prior call to \fBNO\fP).
+
+.br
+Upon success nothing is returned.  On error a negative status code
+will be returned.
+
+.br
+The notification gets reports for each event specified by \fBbits\fP.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs evm 0 -1 # Shorthand for events 0-31.
+.br
+$ pigs evm 0 0xf0 # Get notifications for events 4-7.
+.br
+
+.br
+$ pigs evm 1 0xf
+.br
+-25
+.br
+ERROR: unknown handle
+.br
+
+.EE
+
+.br
+
+.IP "\fBEVT event\fP - Trigger event"
+.IP "" 4
+This command triggers event \fBevent\fP.
+
+.br
+One event, number 31, is predefined.  This event is
+auto generated on BSC slave activity.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs evt 12
+.br
+$ pigs evt 5
+.br
+
+.br
+$ pigs evt 32
+.br
+-143
+.br
+ERROR: bad event id
+.br
+
+.EE
+
+.br
+
 .IP "\fBFC h\fP - Close file handle"
 .IP "" 4
 This command closes a file handle \fBh\fP previously opened with \fBFO\fP.
@@ -4672,6 +4938,11 @@ the transmission of serial data (I2C/SPI/serial link, waves).
 
 .br
 
+.IP "\fBbctl\fP - BSC control word" 0
+The command expects a BSC control word, see \fBBSCX\fP.
+
+.br
+
 .IP "\fBbit\fP - bit value (0-1)" 0
 The command expects 0 or 1.
 
@@ -4736,6 +5007,12 @@ The command expects the name of a tty serial device, e.g.
 
 .br
 
+.IP "\fBevent\fP - 0-31" 0
+An event is a signal used to inform one or more consumers
+to start an action.
+
+.br
+
 .IP "\fBfile\fP - a file name" 0
 The file name must match an entry in /opt/pigpio/access.
 
@@ -5343,6 +5620,7 @@ CMP x   Compare x with accumulator                    F=A-x
 DCR y   Decrement register                            --*y; F=*y
 DCRA    Decrement accumulator                         --A; F=A
 DIV x   Divide x into accumulator                     A/=x; F=A
+EVTWT   Wait for an event to occur                    A=wait(x); F=A
 HALT    Halt                                          Halt
 INR y   Increment register                            ++*y; F=*y
 INRA    Increment accumulator                         ++A; F=A
@@ -5383,6 +5661,9 @@ x may be a constant, a parameter (p0-p9), or a variable (v0-v149).
 y may be a parameter (p0-p9), or a variable (v0-v149).  If p or v isn't
 specified y is assumed to be a variable.
 
+.br
+The EVTWT command parameter is a bit-mask with 1 set for events of interest.
+
 .br
 The WAIT command parameter is a bit-mask with 1 set for GPIO of interest.
 
diff --git a/pigs.c b/pigs.c
index 3395f2f26e305bfa0e0e8a3ad51cfacf5b394e03..24f1fee27da7ed0ef052c01927d7ca27bff835af 100644 (file)
--- a/pigs.c
+++ b/pigs.c
@@ -172,8 +172,8 @@ void print_result(int sock, int rv, cmdCmd_t cmd)
          break;
 
       case 6: /*
-                 BI2CZ  CF2  FL  FR  I2CPK  I2CRD  I2CRI  I2CRK  I2CZ
-                 SERR  SLR  SPIX  SPIR
+                 BI2CZ  CF2  FL  FR  I2CPK  I2CRD  I2CRI  I2CRK
+                 I2CZ  SERR  SLR  SPIX  SPIR
               */
          printf("%d", r);
          if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
@@ -216,6 +216,41 @@ void print_result(int sock, int rv, cmdCmd_t cmd)
          }
          printf("\n");
          break;
+
+      case 8: /*
+                 BSCX
+              */
+         if (r < 0)
+         {
+            printf("%d", r);
+            fatal("ERROR: %s", cmdErrStr(r));
+         }
+
+         p = (uint32_t *)response_buf;
+         printf("%d %d", r-3, p[0]);
+
+         if (r > 4)
+         {
+            if (printFlags == PRINT_ASCII) printf(" ");
+
+            for (i=4; i<r; i++)
+            {
+               ch = response_buf[i];
+
+               if (printFlags & PRINT_HEX) printf(" %hhx", ch);
+
+               else if (printFlags & PRINT_ASCII)
+               {
+                  if (isprint(ch) || (ch == '\n') || (ch == '\r'))
+                     printf("%c", ch);
+                  else printf("\\x%02hhx", ch);
+               }
+               else printf(" %hhu", response_buf[i]);
+            }
+         }
+         printf("\n");
+         break;
+
    }
 }
 
@@ -224,6 +259,7 @@ void get_extensions(int sock, int command, int res)
    switch (command)
    {
       case PI_CMD_BI2CZ:
+      case PI_CMD_BSCX:
       case PI_CMD_BSPIX:
       case PI_CMD_CF2:
       case PI_CMD_FL:
index d4a80f5defad1d2a6664949131c01cdb173b0f55..973c3bcc590671fd04877a807169a9bdb7df55d2 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from distutils.core import setup
 
 setup(name='pigpio',
-      version='1.33',
+      version='1.34',
       author='joan',
       author_email='joan@abyz.co.uk',
       maintainer='joan',
diff --git a/x_pigs b/x_pigs
index 043bf3baf58cb258138093f6260e4c29d010f055..3e33a2a2d54948e066c298a614850686df7cc788 100755 (executable)
--- a/x_pigs
+++ b/x_pigs
@@ -50,7 +50,7 @@ s=$(pigs bs2 0)
 if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
 
 s=$(pigs h)
-if [[ ${#s} = 5273 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
+if [[ ${#s} = 5384 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
 
 s=$(pigs hwver)
 if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi