diff --git a/command.c b/command.c index 2a5d0dc..82e1c74 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 56+ +This version is for pigpio version 57+ */ #include @@ -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; diff --git a/command.h b/command.h index c27d64f..eede592 100644 --- a/command.h +++ b/command.h @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 56+ +This version is for pigpio version 57+ */ #ifndef COMMAND_H diff --git a/pigpio.3 b/pigpio.3 index 6902953..47e6a8a 100644 --- 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 diff --git a/pigpio.c b/pigpio.c index 4ad429b..912f689 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* 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); - return ((int)x) & 0xFF; + 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; + + 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<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; iI.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 #include #include -#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<=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 diff --git a/pigpio.py b/pigpio.py index b0962d5..b22202e 100644 --- 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< 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 + a 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 diff --git a/pigpiod_if.3 b/pigpiod_if.3 index 284a3ae..2fe7ed2 100644 --- a/pigpiod_if.3 +++ b/pigpiod_if.3 @@ -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 diff --git a/pigpiod_if.h b/pigpiod_if.h index 6706b9d..6200a79 100644 --- a/pigpiod_if.h +++ b/pigpiod_if.h @@ -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*/ diff --git a/pigpiod_if2.3 b/pigpiod_if2.3 index 66ad4e0..5b25e0c 100644 --- a/pigpiod_if2.3 +++ b/pigpiod_if2.3 @@ -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 diff --git a/pigpiod_if2.c b/pigpiod_if2.c index 842fb4b..d94732a 100644 --- a/pigpiod_if2.c +++ b/pigpiod_if2.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* PIGPIOD_IF2_VERSION 8 */ +/* PIGPIOD_IF2_VERSION 9 */ #include #include @@ -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; - - p = gCallBackFirst; - - while (p) + if ((r->flags) & PI_NTFY_FLAGS_WDOG) { - if (((p->pi) == pi) && ((p->gpio) == g)) + g = (r->flags) & 31; + + p = gCallBackFirst; + + while (p) { - if (p->ex) (p->f)(pi, g, PI_TIMEOUT, r->tick, p->user); - else (p->f)(pi, g, PI_TIMEOUT, r->tick); + 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) + { + g = (r->flags) & 31; + + ep = geCallBackFirst; + + while (ep) + { + 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);} + diff --git a/pigpiod_if2.h b/pigpiod_if2.h index ced2c9a..dc6f701 100644 --- a/pigpiod_if2.h +++ b/pigpiod_if2.h @@ -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<=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 f8fcb7a..28bc9bf 100644 --- 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 3395f2f..24f1fee 100644 --- 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