diff --git a/README.md b/README.md
index 30ff61b..43a1f2f 100644
--- a/README.md
+++ b/README.md
@@ -1,96 +1,97 @@
-# pigpio
-pigpio is a C library for the Raspberry which allows control of the
-general purpose input outputs (gpios).
-
-Features
-
- sampling and time-stamping of gpios 0-31 between 100,000 and 1,000,000 times per second.
-
- provision of PWM on any number of the user gpios simultaneously.
-
- provision of servo pulses on any number of the user gpios simultaneously.
-
- callbacks when any of gpios 0-31 change state (callbacks receive the time of the event
- accurate to a few microseconds).
-
- notifications via pipe when any of gpios 0-31 change state.
-
- callbacks at timed intervals.
-
- reading/writing all of the gpios in a bank (0-31, 32-53) as a single operation.
-
- individually setting gpio modes, reading and writing.
-
- socket and pipe interfaces for the bulk of the functionality in addition to the
- underlying C library calls.
-
- the construction of arbitrary waveforms to give precise timing of output gpio
- level changes (accurate to a few microseconds).
-
- software serial links using any user gpio.
-
- rudimentary permission control through the socket and pipe interfaces so users
- can be prevented from "updating" inappropriate gpios.
-
- creating and running scripts on the pigpio daemon.
-
-Interfaces
-
-The library provides a number of control interfaces
-
- the C function interface
-
- the /dev/pigpio pipe interface
-
- the socket interface (used by the pigs utility and the Python module)
-
-Utilities
-
-A number of utility programs are provided
-
- the pigpiod daemon.
- the Python module.
-
- the pigs command line utility.
-
- the pig2vcd utility which converts notifications into the value change dump (VCD)
- format (useful for viewing digital waveforms with GTKWave).
-
-gpios
-
-ALL gpios are identified by their Broadcom number. See elinux.org
-
-There are 54 gpios in total, arranged in two banks.
-
-Bank 1 contains gpios 0-31. Bank 2 contains gpios 32-54.
-
-A user should only manipulate gpios in bank 1.
-
-There are at least three types of board.
-
-Type 1
-
- 26 pin header (P1).
-
- Hardware revision numbers of 2 and 3.
-
- User gpios 0-1, 4, 7-11, 14-15, 17-18, 21-25.
-
-Type 2
-
- 26 pin header (P1) and an additional 8 pin header (P5).
-
- Hardware revision numbers of 4, 5, 6, and 15.
-
- User gpios 2-4, 7-11, 14-15, 17-18, 22-25, 27-31.
-
-Type 3
-
- 40 pin expansion header (J8).
-
- Hardware revision numbers of 16 or greater.
-
- User gpios 2-27 (0 and 1 are reserved).
-
-It is safe to read all the gpios. If you try to write a system gpio or change
-its mode you can crash the Pi or corrupt the data on the SD card.
+# pigpio
+pigpio is a C library for the Raspberry which allows control of the
+general purpose input outputs (gpios).
+
+Features
+
+ sampling and time-stamping of gpios 0-31 between 100,000 and 1,000,000 times per second.
+
+ provision of PWM on any number of the user gpios simultaneously.
+
+ provision of servo pulses on any number of the user gpios simultaneously.
+
+ callbacks when any of gpios 0-31 change state (callbacks receive the time of the event
+ accurate to a few microseconds).
+
+ notifications via pipe when any of gpios 0-31 change state.
+
+ callbacks at timed intervals.
+
+ reading/writing all of the gpios in a bank (0-31, 32-53) as a single operation.
+
+ individually setting gpio modes, reading and writing.
+
+ socket and pipe interfaces for the bulk of the functionality in addition to the
+ underlying C library calls.
+
+ the construction of arbitrary waveforms to give precise timing of output gpio
+ level changes (accurate to a few microseconds).
+
+ software serial links using any user gpio.
+
+ rudimentary permission control through the socket and pipe interfaces so users
+ can be prevented from "updating" inappropriate gpios.
+
+ creating and running scripts on the pigpio daemon.
+
+Interfaces
+
+The library provides a number of control interfaces
+
+ the C function interface
+
+ the /dev/pigpio pipe interface
+
+ the socket interface (used by the pigs utility and the Python module)
+
+Utilities
+
+A number of utility programs are provided
+
+ the pigpiod daemon.
+ the Python module.
+
+ the pigs command line utility.
+
+ the pig2vcd utility which converts notifications into the value change dump (VCD)
+ format (useful for viewing digital waveforms with GTKWave).
+
+gpios
+
+ALL gpios are identified by their Broadcom number. See elinux.org
+
+There are 54 gpios in total, arranged in two banks.
+
+Bank 1 contains gpios 0-31. Bank 2 contains gpios 32-54.
+
+A user should only manipulate gpios in bank 1.
+
+There are at least three types of board.
+
+Type 1
+
+ 26 pin header (P1).
+
+ Hardware revision numbers of 2 and 3.
+
+ User gpios 0-1, 4, 7-11, 14-15, 17-18, 21-25.
+
+Type 2
+
+ 26 pin header (P1) and an additional 8 pin header (P5).
+
+ Hardware revision numbers of 4, 5, 6, and 15.
+
+ User gpios 2-4, 7-11, 14-15, 17-18, 22-25, 27-31.
+
+Type 3
+
+ 40 pin expansion header (J8).
+
+ Hardware revision numbers of 16 or greater.
+
+ User gpios 2-27 (0 and 1 are reserved).
+
+It is safe to read all the gpios. If you try to write a system gpio or change
+its mode you can crash the Pi or corrupt the data on the SD card.
+
diff --git a/command.c b/command.c
index ead8879..2a5d0dc 100644
--- a/command.c
+++ b/command.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 55+
+This version is for pigpio version 56+
*/
#include
@@ -49,16 +49,16 @@ cmdInfo_t cmdInfo[]=
{PI_CMD_BI2CO, "BI2CO", 131, 0}, // bbI2COpen
{PI_CMD_BI2CZ, "BI2CZ", 193, 6}, // bbI2CZip
- {PI_CMD_BSPIC, "BSPIC", 112, 0}, // bbSPIClose
- {PI_CMD_BSPIO, "BSPIO", 134, 0}, // bbSPIOpen
- {PI_CMD_BSPIX, "BSPIX", 193, 6}, // bbSPIXfer
-
{PI_CMD_BR1, "BR1", 101, 3}, // gpioRead_Bits_0_31
{PI_CMD_BR2, "BR2", 101, 3}, // gpioRead_Bits_32_53
{PI_CMD_BS1, "BS1", 111, 1}, // gpioWrite_Bits_0_31_Set
{PI_CMD_BS2, "BS2", 111, 1}, // gpioWrite_Bits_32_53_Set
+ {PI_CMD_BSPIC, "BSPIC", 112, 0}, // bbSPIClose
+ {PI_CMD_BSPIO, "BSPIO", 134, 0}, // bbSPIOpen
+ {PI_CMD_BSPIX, "BSPIX", 193, 6}, // bbSPIXfer
+
{PI_CMD_CF1, "CF1", 195, 2}, // gpioCustom1
{PI_CMD_CF2, "CF2", 195, 6}, // gpioCustom2
@@ -384,11 +384,18 @@ WVTX wid Transmit wave as one-shot\n\
WVTXM wid wmde Transmit wave using mode\n\
WVTXR wid Transmit wave repeatedly\n\
\n\
-\n\
Numbers may be entered as hex (prefix 0x), octal (prefix 0),\n\
otherwise they are assumed to be decimal.\n\
\n\
-man pigs for full details.\n\n";
+Examples\n\
+\n\
+pigs w 4 1 # set GPIO 4 high\n\
+pigs r 5 # read GPIO 5\n\
+pigs t # get current tick\n\
+pigs i2co 1 0x20 0 # get handle to device 0x20 on I2C bus 1\n\
+\n\
+man pigs for full details.\n\
+\n";
typedef struct
{
@@ -945,11 +952,11 @@ int cmdParse(
(to5 == CMD_NUMERIC))
{
p[3] = 5 * 4;
- memcpy(ext, &tp1, 4);
- memcpy(ext, &tp2, 4);
- memcpy(ext, &tp3, 4);
- memcpy(ext, &tp4, 4);
- memcpy(ext, &tp5, 4);
+ memcpy(ext+ 0, &tp1, 4);
+ memcpy(ext+ 4, &tp2, 4);
+ memcpy(ext+ 8, &tp3, 4);
+ memcpy(ext+12, &tp4, 4);
+ memcpy(ext+16, &tp5, 4);
valid = 1;
}
diff --git a/command.h b/command.h
index 7c6efcd..c27d64f 100644
--- a/command.h
+++ b/command.h
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 55+
+This version is for pigpio version 56+
*/
#ifndef COMMAND_H
diff --git a/pigpio.3 b/pigpio.3
index 16b0ddf..6902953 100644
--- a/pigpio.3
+++ b/pigpio.3
@@ -1372,7 +1372,7 @@ if (h >= 0)
.br
.br
- fd = open(str, "r");
+ fd = open(str, O_RDONLY);
.br
.br
@@ -3453,6 +3453,301 @@ End
.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
+a specified baud rate and mode.
+
+.br
+
+.br
+
+.EX
+ CS: 0-31
+.br
+ MISO: 0-31
+.br
+ MOSI: 0-31
+.br
+ SCLK: 0-31
+.br
+ baud: 50-250000
+.br
+spiFlags: see below
+.br
+
+.EE
+
+.br
+
+.br
+spiFlags consists of the least significant 22 bits.
+
+.br
+
+.br
+
+.EX
+21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+.br
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+.br
+
+.EE
+
+.br
+
+.br
+mm defines the SPI mode, defaults to 0
+
+.br
+
+.br
+
+.EX
+Mode CPOL CPHA
+.br
+ 0 0 0
+.br
+ 1 0 1
+.br
+ 2 1 0
+.br
+ 3 1 1
+.br
+
+.EE
+
+.br
+
+.br
+p is 0 if CS is active low (default) and 1 for active high.
+
+.br
+
+.br
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.
+
+.br
+
+.br
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.
+
+.br
+
+.br
+The other bits in flags should be set to zero.
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
+PI_GPIO_IN_USE.
+
+.br
+
+.br
+If more than one device is connected to the SPI bus (defined by
+SCLK, MOSI, and MISO) each must have its own CS.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+bbSPIOpen(10, MISO, MOSI, SCLK, 10000, 0); // device 1
+.br
+bbSPIOpen(11, MISO, MOSI, SCLK, 20000, 3); // device 2
+.br
+
+.EE
+
+.IP "\fBint bbSPIClose(unsigned CS)\fP"
+.IP "" 4
+This function stops bit banging SPI on a set of GPIO
+opened with \fBbbSPIOpen\fP.
+
+.br
+
+.br
+
+.EX
+CS: 0-31, the CS GPIO used in a prior call to \fBbbSPIOpen\fP
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
+
+.IP "\fBint bbSPIXfer(unsigned CS, char *inBuf, char *outBuf, unsigned count)\fP"
+.IP "" 4
+This function executes a bit banged SPI transfer.
+
+.br
+
+.br
+
+.EX
+ CS: 0-31 (as used in a prior call to \fBbbSPIOpen\fP)
+.br
+ inBuf: pointer to buffer to hold data to be sent
+.br
+outBuf: pointer to buffer to hold returned data
+.br
+ count: size of data transfer
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+// gcc -Wall -pthread -o bbSPIx_test bbSPIx_test.c -lpigpio
+.br
+// sudo ./bbSPIx_test
+.br
+
+.br
+
+.br
+#include
+.br
+
+.br
+#include "pigpio.h"
+.br
+
+.br
+#define CE0 5
+.br
+#define CE1 6
+.br
+#define MISO 13
+.br
+#define MOSI 19
+.br
+#define SCLK 12
+.br
+
+.br
+int main(int argc, char *argv[])
+.br
+{
+.br
+ int i, count, set_val, read_val;
+.br
+ unsigned char inBuf[3];
+.br
+ char cmd1[] = {0, 0};
+.br
+ char cmd2[] = {12, 0};
+.br
+ char cmd3[] = {1, 128, 0};
+.br
+
+.br
+ if (gpioInitialise() < 0)
+.br
+ {
+.br
+ fprintf(stderr, "pigpio initialisation failed.\n");
+.br
+ return 1;
+.br
+ }
+.br
+
+.br
+ bbSPIOpen(CE0, MISO, MOSI, SCLK, 10000, 0); // MCP4251 DAC
+.br
+ bbSPIOpen(CE1, MISO, MOSI, SCLK, 20000, 3); // MCP3008 ADC
+.br
+
+.br
+ for (i=0; i<256; i++)
+.br
+ {
+.br
+ cmd1[1] = i;
+.br
+
+.br
+ count = bbSPIXfer(CE0, cmd1, (char *)inBuf, 2); // > DAC
+.br
+
+.br
+ if (count == 2)
+.br
+ {
+.br
+ count = bbSPIXfer(CE0, cmd2, (char *)inBuf, 2); // < DAC
+.br
+
+.br
+ if (count == 2)
+.br
+ {
+.br
+ set_val = inBuf[1];
+.br
+
+.br
+ count = bbSPIXfer(CE1, cmd3, (char *)inBuf, 3); // < ADC
+.br
+
+.br
+ if (count == 3)
+.br
+ {
+.br
+ read_val = ((inBuf[1]&3)<<8) | inBuf[2];
+.br
+ printf("%d %d\n", set_val, read_val);
+.br
+ }
+.br
+ }
+.br
+ }
+.br
+ }
+.br
+
+.br
+ bbSPIClose(CE0);
+.br
+ bbSPIClose(CE1);
+.br
+
+.br
+ gpioTerminate();
+.br
+
+.br
+ return 0;
+.br
+}
+.br
+
+.EE
+
.IP "\fBint spiOpen(unsigned spiChan, unsigned baud, unsigned spiFlags)\fP"
.IP "" 4
This function returns a handle for the SPI device on the channel.
@@ -6156,6 +6451,28 @@ method uses the mailbox property interface to allocate bus memory.
Auto will use the mailbox method unless a larger than default buffer
size is requested with \fBgpioCfgBufferSize\fP.
+.IP "\fBint gpioCfgNetAddr(int numSockAddr, uint32_t *sockAddr)\fP"
+.IP "" 4
+Sets the network addresses which are allowed to talk over the
+socket interface.
+
+.br
+
+.br
+This function is only effective if called before \fBgpioInitialise\fP.
+
+.br
+
+.br
+
+.EX
+numSockAddr: 0-256 (0 means all addresses allowed)
+.br
+ sockAddr: an array of permitted network addresses.
+.br
+
+.EE
+
.IP "\fBint gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal)\fP"
.IP "" 4
Used to tune internal settings.
@@ -6363,7 +6680,7 @@ Not intended for general use.
.IP "\fBrawCbs_t *rawWaveCBAdr(int cbNum)\fP"
.IP "" 4
-Return the Linux address of contol block cbNum.
+Return the (Linux) address of contol block cbNum.
.br
@@ -6380,12 +6697,57 @@ cbNum: the cb of interest
.br
Not intended for general use.
+.IP "\fBuint32_t rawWaveGetOOL(int pos)\fP"
+.IP "" 4
+Gets the OOL parameter stored at pos.
+
+.br
+
+.br
+
+.EX
+pos: the position of interest.
+.br
+
+.EE
+
+.br
+
+.br
+Not intended for general use.
+
+.IP "\fBvoid rawWaveSetOOL(int pos, uint32_t lVal)\fP"
+.IP "" 4
+Sets the OOL parameter stored at pos to value.
+
+.br
+
+.br
+
+.EX
+ pos: the position of interest
+.br
+lVal: the value to write
+.br
+
+.EE
+
+.br
+
+.br
+Not intended for general use.
+
.IP "\fBuint32_t rawWaveGetOut(int pos)\fP"
.IP "" 4
Gets the wave output parameter stored at pos.
.br
+.br
+DEPRECATED: use rawWaveGetOOL instead.
+
+.br
+
.br
.EX
@@ -6405,6 +6767,11 @@ Sets the wave output parameter stored at pos to value.
.br
+.br
+DEPRECATED: use rawWaveSetOOL instead.
+
+.br
+
.br
.EX
@@ -6426,6 +6793,11 @@ Gets the wave input value parameter stored at pos.
.br
+.br
+DEPRECATED: use rawWaveGetOOL instead.
+
+.br
+
.br
.EX
@@ -6445,6 +6817,11 @@ Sets the wave input value stored at pos to value.
.br
+.br
+DEPRECATED: use rawWaveSetOOL instead.
+
+.br
+
.br
.EX
@@ -6831,6 +7208,13 @@ command.
.br
+.IP "\fBCS\fP" 0
+The GPIO used for the slave select signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fBdata_bits\fP: 1-32" 0
.br
@@ -7481,6 +7865,13 @@ A value representing milliseconds.
.br
+.IP "\fBMISO\fP" 0
+The GPIO used for the MISO signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fBmode\fP" 0
.br
@@ -7554,6 +7945,13 @@ PI_FILE_TRUNC 16
.br
+.IP "\fBMOSI\fP" 0
+The GPIO used for the MOSI signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fBnumBits\fP" 0
.br
@@ -7595,6 +7993,18 @@ The number of segments in a combined I2C transaction.
.br
+.IP "\fBnumSockAddr\fP" 0
+The number of network addresses allowed to use the socket interface.
+
+.br
+
+.br
+0 means all addresses allowed.
+
+.br
+
+.br
+
.IP "\fBoffset\fP" 0
The associated data starts this number of microseconds from the start of
the waveform.
@@ -7987,6 +8397,13 @@ The user GPIO to use for the clock when bit banging I2C.
.br
+.IP "\fBSCLK\fP" 0
+The GPIO used for the SCLK signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fB*script\fP" 0
A pointer to the text of a script.
@@ -8134,6 +8551,19 @@ A standard type used to indicate the size of an object in bytes.
.br
+.IP "\fB*sockAddr\fP" 0
+An array of network addresses allowed to use the socket interface encoded
+as 32 bit numbers.
+
+.br
+
+.br
+E.g. address 192.168.1.66 would be encoded as 0x4201a8c0.
+
+.br
+
+.br
+
.IP "\fB*spi\fP" 0
A pointer to a \fBrawSPI_t\fP structure.
@@ -8174,7 +8604,7 @@ A SPI channel, 0-2.
.br
.IP "\fBspiFlags\fP" 0
-See \fBspiOpen\fP.
+See \fBspiOpen\fP and \fBbbSPIOpen\fP.
.br
@@ -8744,6 +9174,14 @@ A 16-bit word value.
#define PI_CMD_SHELL 110
.br
+.br
+#define PI_CMD_BSPIC 111
+.br
+#define PI_CMD_BSPIO 112
+.br
+#define PI_CMD_BSPIX 113
+.br
+
.br
.EE
@@ -9038,6 +9476,10 @@ A 16-bit word value.
.br
#define PI_BAD_SCRIPT_NAME -140 // bad script name
.br
+#define PI_BAD_SPI_BAUD -141 // bad SPI baud rate, not 50-500k
+.br
+#define PI_NOT_SPI_GPIO -142 // no bit bang SPI in progress on GPIO
+.br
.br
#define PI_PIGIF_ERR_0 -2000
diff --git a/pigpio.c b/pigpio.c
index 2ce81da..4ad429b 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* pigpio version 55 */
+/* pigpio version 56 */
/* include ------------------------------------------------------- */
@@ -750,12 +750,12 @@ Assumes two counters per block. Each counter 4 * 16 (16^4=65536)
#define PI_WFRX_NONE 0
#define PI_WFRX_SERIAL 1
-#define PI_WFRX_I2C 2
-#define PI_WFRX_I2C_CLK 3
-#define PI_WFRX_SPI_MISO 4
-#define PI_WFRX_SPI_MOSI 5
-#define PI_WFRX_SPI_CS 6
-#define PI_WFRX_SPI_SCLK 7
+#define PI_WFRX_I2C_SDA 2
+#define PI_WFRX_I2C_SCL 3
+#define PI_WFRX_SPI_SCLK 4
+#define PI_WFRX_SPI_MISO 5
+#define PI_WFRX_SPI_MOSI 6
+#define PI_WFRX_SPI_CS 7
#define PI_WF_MICROS 1
@@ -850,8 +850,10 @@ Assumes two counters per block. Each counter 4 * 16 (16^4=65536)
#define PI_SPI_FLAGS_GET_RESVD(x) (((x)>>5)&7)
#define PI_SPI_FLAGS_GET_CSPOLS(x) (((x)>>2)&7)
#define PI_SPI_FLAGS_GET_MODE(x) ((x)&3)
-#define PI_SPI_FLAGS_GET_CPHA(x) ((x)&1)
-#define PI_SPI_FLAGS_GET_CPOL(x) ((x)&2)
+
+#define PI_SPI_FLAGS_GET_CPHA(x) ((x)&1)
+#define PI_SPI_FLAGS_GET_CPOL(x) ((x)&2)
+#define PI_SPI_FLAGS_GET_CSPOL(x) ((x)&4)
#define PI_STARTING 0
#define PI_RUNNING 1
@@ -1103,17 +1105,17 @@ typedef struct
typedef struct
{
+ int CS;
int MISO;
int MOSI;
- int CS;
int SCLK;
+ int usage;
int delay;
int spiFlags;
int MISOMode;
int MOSIMode;
int CSMode;
int SCLKMode;
- int started;
} wfRxSPI_t;
typedef struct
@@ -1121,6 +1123,7 @@ typedef struct
int mode;
int gpio;
uint32_t baud;
+ pthread_mutex_t mutex;
union
{
wfRxSerial_t s;
@@ -1180,6 +1183,10 @@ static int libInitialised = 0;
static struct timespec libStarted;
+static uint32_t sockNetAddr[MAX_CONNECT_ADDRESSES];
+
+static int numSockNetAddr = 0;
+
static uint32_t reportedLevel = 0;
static int waveClockInited = 0;
@@ -1254,6 +1261,9 @@ static gpioTimer_t gpioTimer [PI_MAX_TIMER+1];
static int pwmFreq[PWM_FREQS];
+static pthread_mutex_t spi_main_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t spi_aux_mutex = PTHREAD_MUTEX_INITIALIZER;
+
/* reset after gpioTerminated */
/* resources which must be released on gpioTerminate */
@@ -1764,6 +1774,20 @@ static void flushMemory(void)
/* ----------------------------------------------------------------------- */
+static void wfRx_lock(int i)
+{
+ pthread_mutex_lock(&wfRx[i].mutex);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void wfRx_unlock(int i)
+{
+ pthread_mutex_unlock(&wfRx[i].mutex);
+}
+
+/* ----------------------------------------------------------------------- */
+
static void spinWhileStarting(void)
{
while (runState == PI_STARTING)
@@ -1834,13 +1858,42 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
break;
case PI_CMD_BSPIO:
- memcpy(&tmp1, buf, 4); // MISO
- memcpy(&tmp2, buf+4, 4); // MOSI
- memcpy(&tmp3, buf+8, 4); // SCLK
- memcpy(&tmp4, buf+12, 4);// baud
- memcpy(&tmp5, buf+16, 4);// flags
-
- res = bbSPIOpen(p[1], tmp1, tmp2, tmp3, tmp4, tmp5);
+
+ memcpy(&tmp1, buf+ 0, 4); // MISO
+ memcpy(&tmp2, buf+ 4, 4); // MOSI
+ memcpy(&tmp3, buf+ 8, 4); // SCLK
+ memcpy(&tmp4, buf+12, 4); // baud
+ memcpy(&tmp5, buf+16, 4); // flags
+
+ if (!myPermit(p[1]))
+ {
+ DBG(DBG_USER,
+ "bbSPIOpen: gpio %d, no permission to update CS", p[1]);
+ res = PI_NOT_PERMITTED;
+ }
+
+ if (!myPermit(tmp1))
+ {
+ DBG(DBG_USER,
+ "bbSPIOpen: gpio %d, no permission to update MISO", tmp1);
+ res = PI_NOT_PERMITTED;
+ }
+
+ if (!myPermit(tmp2))
+ {
+ DBG(DBG_USER,
+ "bbSPIOpen: gpio %d, no permission to update MOSI", tmp2);
+ res = PI_NOT_PERMITTED;
+ }
+
+ if (!myPermit(tmp3))
+ {
+ DBG(DBG_USER,
+ "bbSPIOpen: gpio %d, no permission to update SCLK", tmp3);
+ res = PI_NOT_PERMITTED;
+ }
+
+ if (!res) res = bbSPIOpen(p[1], tmp1, tmp2, tmp3, tmp4, tmp5);
break;
case PI_CMD_BSPIC:
@@ -4339,11 +4392,15 @@ static void spiGo(
{
if (PI_SPI_FLAGS_GET_AUX_SPI(flags))
{
+ pthread_mutex_lock(&spi_aux_mutex);
spiGoA(speed, flags, txBuf, rxBuf, count);
+ pthread_mutex_unlock(&spi_aux_mutex);
}
else
{
+ pthread_mutex_lock(&spi_main_mutex);
spiGoS(speed, flags, txBuf, rxBuf, count);
+ pthread_mutex_unlock(&spi_main_mutex);
}
}
@@ -6692,7 +6749,7 @@ static void *pthSocketThreadHandler(void *fdC)
case PI_CMD_SLR:
case PI_CMD_SPIX:
case PI_CMD_SPIR:
- case PI_CMD_BSPIX:
+ case PI_CMD_BSPIX:
if (((int)p[3]) > 0)
{
@@ -6712,11 +6769,24 @@ static void *pthSocketThreadHandler(void *fdC)
return 0;
}
+static int addrAllowed(uint32_t addr)
+{
+ int i;
+
+ if (!numSockNetAddr) return 1;
+
+ for (i=0; i= 0)
{
pthread_t thr;
+ fdC = accept(fdSock, (struct sockaddr *)&client, (socklen_t*)&c);
+
closeOrphanedNotifications(-1, fdC);
- sock = malloc(sizeof(int));
+ if (addrAllowed(client.sin_addr.s_addr))
+ {
+ sock = malloc(sizeof(int));
- *sock = fdC;
+ *sock = fdC;
- if (pthread_create
- (&thr, &attr, pthSocketThreadHandler, (void*) sock) < 0)
- SOFT_ERROR((void*)PI_INIT_FAILED,
- "socket pthread_create failed (%m)");
+ if (pthread_create
+ (&thr, &attr, pthSocketThreadHandler, (void*) sock) < 0)
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "socket pthread_create failed (%m)");
+ }
+ else
+ {
+ close(fdC);
+ }
}
if (fdC < 0)
@@ -7466,9 +7544,9 @@ static void initClearGlobals(void)
for (i=0; i<=PI_MAX_USER_GPIO; i++)
{
- wfRx[i].mode = PI_WFRX_NONE;
-
- gpioAlert[i].func = NULL;
+ wfRx[i].mode = PI_WFRX_NONE;
+ pthread_mutex_init(&wfRx[i].mutex, NULL);
+ gpioAlert[i].func = NULL;
}
for (i=0; i<=PI_MAX_GPIO; i++)
@@ -7700,6 +7778,8 @@ static void initReleaseResources(void)
gpioStats.DMARestarts = 0;
gpioStats.dmaInitCbsCount = 0;
+
+ numSockNetAddr = 0;
}
int initInitialise(void)
@@ -7882,6 +7962,35 @@ void putBitInBytes(int bitPos, char *buf, int bit)
else buf[bufp] &= (~(1<= 0) && (pos < NUM_WAVE_OOL))
+ {
+ waveOOLPageSlot(pos, &page, &slot);
+ return (dmaOVirt[page]->OOL[slot]);
+ }
+
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+void rawWaveSetOOL(int pos, uint32_t value)
+{
+ int page, slot;
+
+ if ((pos >= 0) && (pos < NUM_WAVE_OOL))
+ {
+ waveOOLPageSlot(pos, &page, &slot);
+ dmaOVirt[page]->OOL[slot] = value;
+ }
+}
+
+
/* ----------------------------------------------------------------------- */
uint32_t rawWaveGetOut(int pos)
@@ -7943,7 +8052,7 @@ void rawWaveSetIn(int pos, uint32_t value)
rawWaveInfo_t rawWaveInfo(int wave_id)
{
- rawWaveInfo_t dummy = {-1, -1, -1, -1};
+ rawWaveInfo_t dummy = {0, 0, 0, 0, 0, 0, 0, 0};
if ((wave_id >=0) && (wave_id < PI_MAX_WAVES)) return waveInfo[wave_id];
else return dummy;
@@ -9042,7 +9151,7 @@ int gpioWaveCreate(void)
(numBOOL != (BOOL-waveInfo[wid].botOOL)) ||
(numTOOL != (waveInfo[wid].topOOL-TOOL)) )
{
- DBG(0, "ERROR wid=%d CBs %d=%d BOOL %d=%d TOOL %d=%d", wid,
+ DBG(DBG_ALWAYS, "ERROR wid=%d CBs %d=%d BOOL %d=%d TOOL %d=%d", wid,
numCB, CB-waveInfo[wid].botCB,
numBOOL, BOOL-waveInfo[wid].botOOL,
numTOOL, waveInfo[wid].topOOL-TOOL);
@@ -9780,32 +9889,14 @@ int gpioWaveGetMaxCbs(void)
return wfStats.maxCbs;
}
+/* ----------------------------------------------------------------------- */
+
static int read_SDA(wfRx_t *w)
{
myGpioSetMode(w->I.SDA, PI_INPUT);
return gpioRead(w->I.SDA);
}
-static void set_CS(wfRx_t *w)
-{
- myGpioWrite(w->S.CS, PI_SPI_FLAGS_GET_CSPOLS(w->S.spiFlags));
-}
-
-static void clear_CS(wfRx_t *w)
-{
- myGpioWrite(w->S.CS, !PI_SPI_FLAGS_GET_CSPOLS(w->S.spiFlags));
-}
-
-static void set_SCLK(wfRx_t *w)
-{
- myGpioWrite(w->S.SCLK, !PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
-}
-
-static void clear_SCLK(wfRx_t *w)
-{
- myGpioWrite(w->S.SCLK, PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
-}
-
static void set_SDA(wfRx_t *w)
{
myGpioSetMode(w->I.SDA, PI_INPUT);
@@ -9828,11 +9919,6 @@ static void I2C_delay(wfRx_t *w)
myGpioDelay(w->I.delay);
}
-static void SPI_delay(wfRx_t *w)
-{
- myGpioDelay(w->S.delay);
-}
-
static void I2C_clock_stretch(wfRx_t *w)
{
uint32_t now, max_stretch=10000;
@@ -9842,30 +9928,6 @@ static void I2C_clock_stretch(wfRx_t *w)
while ((gpioRead(w->I.SCL) == 0) && ((gpioTick()-now) < max_stretch));
}
-static void bbSPIStart(wfRx_t *w)
-{
- if (w->S.started)
- {
- clear_SCLK(w);
- clear_CS(w);
- SPI_delay(w);
- }
-
- clear_SCLK(w);
- set_CS(w);
-
- w->S.started = 1;
-}
-
-static void bbSPIStop(wfRx_t *w)
-{
- clear_CS(w);
- clear_SCLK(w);
- SPI_delay(w);
-
- w->S.started = 0;
-}
-
static void I2CStart(wfRx_t *w)
{
if (w->I.started)
@@ -9950,72 +10012,7 @@ static uint8_t I2CGetByte(wfRx_t *w, int nack)
return byte;
}
-static uint8_t bbSPIXferByte(wfRx_t *w, char txByte)
-{
- uint8_t bit, rxByte=0;
-
- if (PI_SPI_FLAGS_GET_CPHA(w->S.spiFlags))
- {
- for (bit=0; bit<8; bit++)
- {
- if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
- {
- myGpioWrite(w->S.MOSI, txByte & 0x01);
- txByte >>= 1;
- }
- else
- {
- myGpioWrite(w->S.MOSI, txByte & 0x80);
- txByte <<= 1;
- }
-
- set_SCLK(w);
- SPI_delay(w);
-
- if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
- {
- rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
- }
- else
- {
- rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
- }
- clear_SCLK(w);
- SPI_delay(w);
- }
- }
- else
- {
- for (bit=0; bit<8; bit++)
- {
- if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
- {
- myGpioWrite(w->S.MOSI, txByte & 0x01);
- txByte >>= 1;
- }
- else
- {
- myGpioWrite(w->S.MOSI, txByte & 0x80);
- txByte <<= 1;
- }
-
- if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
- {
- rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
- }
- else
- {
- rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
- }
- set_SCLK(w);
- SPI_delay(w);
- clear_SCLK(w);
- SPI_delay(w);
- }
- }
-
- return rxByte;
-}
+/*-------------------------------------------------------------------------*/
int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
{
@@ -10040,7 +10037,7 @@ int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used", SCL);
wfRx[SDA].gpio = SDA;
- wfRx[SDA].mode = PI_WFRX_I2C;
+ wfRx[SDA].mode = PI_WFRX_I2C_SDA;
wfRx[SDA].baud = baud;
wfRx[SDA].I.started = 0;
@@ -10051,7 +10048,7 @@ int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
wfRx[SDA].I.SCLMode = gpioGetMode(SCL);
wfRx[SCL].gpio = SCL;
- wfRx[SCL].mode = PI_WFRX_I2C_CLK;
+ wfRx[SCL].mode = PI_WFRX_I2C_SCL;
myGpioSetMode(SDA, PI_INPUT);
myGpioSetMode(SCL, PI_INPUT);
@@ -10059,77 +10056,8 @@ int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
return 0;
}
-int bbSPIOpen(unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spiFlags)
-{
- DBG(DBG_USER, "MISO=%d MOSI=%d CS=%d SCLK=%d baud=%d", MISO, MOSI, CS, SCLK, baud);
-
- CHECK_INITED;
-
- if (CS > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad CS (%d)", CS);
-
- if (MISO > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad MISO (%d)", MISO);
-
- if (MOSI > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad MOSI (%d)", MOSI);
-
- if (SCLK > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad SCLK (%d)", SCLK);
-
- if ((baud < PI_BB_SPI_MIN_BAUD) || (baud > PI_BB_SPI_MAX_BAUD))
- SOFT_ERROR(PI_BAD_SPI_BAUD,
- "CS %d, bad baud rate (%d)", CS, baud);
-
- if (wfRx[CS].mode != PI_WFRX_NONE)
- SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", CS, wfRx[CS].mode);
-
- if (!((wfRx[MISO].mode == PI_WFRX_NONE) || (wfRx[MISO].mode == PI_WFRX_SPI_MISO)) || (MISO == CS))
- SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", MISO, wfRx[MISO].mode);
-
- if (!((wfRx[MOSI].mode == PI_WFRX_NONE) || (wfRx[MOSI].mode == PI_WFRX_SPI_MOSI)) || (MOSI == CS) || (MOSI == MISO))
- SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", MOSI, wfRx[MOSI].mode);
-
- if (!((wfRx[SCLK].mode == PI_WFRX_NONE) || (wfRx[SCLK].mode == PI_WFRX_SPI_SCLK)) || (SCLK == CS) || (SCLK == MISO) || (SCLK == MOSI))
- SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", SCLK, wfRx[SCLK].mode);
-
- wfRx[MISO].gpio = MISO;
- wfRx[MISO].mode = PI_WFRX_SPI_MISO;
-
- wfRx[MOSI].gpio = MOSI;
- wfRx[MOSI].mode = PI_WFRX_SPI_MOSI;
-
- wfRx[SCLK].gpio = SCLK;
- wfRx[SCLK].mode = PI_WFRX_SPI_SCLK;
-
- wfRx[CS].gpio = CS;
- wfRx[CS].mode = PI_WFRX_SPI_CS;
- wfRx[CS].baud = baud;
-
- wfRx[CS].S.started = 0;
- wfRx[CS].S.MISO = MISO;
- wfRx[CS].S.MOSI = MOSI;
- wfRx[CS].S.CS = CS;
- wfRx[CS].S.SCLK = SCLK;
- wfRx[CS].S.delay = (500000 / baud) - 1;
- wfRx[CS].S.spiFlags = spiFlags;
- wfRx[CS].S.MISOMode = gpioGetMode(MISO);
- wfRx[CS].S.MOSIMode = gpioGetMode(MOSI);
- wfRx[CS].S.CSMode = gpioGetMode(CS);
- wfRx[CS].S.SCLKMode = gpioGetMode(SCLK);
-
- myGpioSetMode(MISO, PI_INPUT);
- myGpioSetMode(MOSI, PI_OUTPUT);
- myGpioSetMode(CS, PI_OUTPUT);
- myGpioSetMode(SCLK, PI_OUTPUT);
-
- return 0;
-}
-
-
/* ----------------------------------------------------------------------- */
-
int bbI2CClose(unsigned SDA)
{
DBG(DBG_USER, "SDA=%d", SDA);
@@ -10141,7 +10069,7 @@ int bbI2CClose(unsigned SDA)
switch(wfRx[SDA].mode)
{
- case PI_WFRX_I2C:
+ case PI_WFRX_I2C_SDA:
myGpioSetMode(wfRx[SDA].I.SDA, wfRx[SDA].I.SDAMode);
myGpioSetMode(wfRx[SDA].I.SCL, wfRx[SDA].I.SCLMode);
@@ -10162,103 +10090,6 @@ int bbI2CClose(unsigned SDA)
return 0;
}
-int bbSPIClose(unsigned CS)
-{
- DBG(DBG_USER, "CS=%d", CS);
-
- CHECK_INITED;
-
- if (CS > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
-
- switch(wfRx[CS].mode)
- {
- case PI_WFRX_SPI_CS:
-
- myGpioSetMode(wfRx[CS].S.MISO, wfRx[CS].S.MISOMode);
- myGpioSetMode(wfRx[CS].S.MOSI, wfRx[CS].S.MOSIMode);
- myGpioSetMode(wfRx[CS].S.CS, wfRx[CS].S.CSMode);
- myGpioSetMode(wfRx[CS].S.SCLK, wfRx[CS].S.SCLKMode);
-
- wfRx[wfRx[CS].S.MISO].mode = PI_WFRX_NONE;
- wfRx[wfRx[CS].S.MOSI].mode = PI_WFRX_NONE;
- wfRx[wfRx[CS].S.CS].mode = PI_WFRX_NONE;
- wfRx[wfRx[CS].S.SCLK].mode = PI_WFRX_NONE;
-
- break;
-
- default:
-
- SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
-
- break;
-
- }
-
- return 0;
-}
-/*-------------------------------------------------------------------------*/
-
-int bbSPIXfer(
- unsigned CS,
- char *inBuf,
- char *outBuf,
- unsigned len)
-{
- int pos, status;
- char txByte, rxByte;
- wfRx_t *w;
-
- DBG(DBG_USER, "CS=%d inBuf=%s outBuf=%08X len=%d",
- CS, myBuf2Str(len, (char *)inBuf), (int)outBuf, len);
-
- CHECK_INITED;
-
- if (CS > PI_MAX_USER_GPIO)
- SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
-
- if (wfRx[CS].mode != PI_WFRX_SPI_CS)
- SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
-
- if (!inBuf || !len)
- SOFT_ERROR(PI_BAD_POINTER, "input buffer can't be NULL");
-
- if (!outBuf && len)
- SOFT_ERROR(PI_BAD_POINTER, "output buffer can't be NULL");
-
- w = &wfRx[CS];
-
- status = 0;
-
- bbSPIStart(w);
-
- for (pos=0; pos < len; pos++)
- {
- if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
- {
- txByte = inBuf[pos];
- }
- else
- {
- txByte = inBuf[len - pos - 1];
- }
- rxByte = bbSPIXferByte(w, txByte);
- if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
- {
- outBuf[pos] = rxByte;
- }
- else
- {
- outBuf[len - pos - 1] = rxByte;
- }
- DBG(DBG_INTERNAL, "pos=%d len=%d sent=%d recvd=%d", pos, len, txByte, rxByte);
- }
- bbSPIStop(w);
-
- status = len;
-
- return status;
-}
/*-------------------------------------------------------------------------*/
int bbI2CZip(
@@ -10280,7 +10111,7 @@ int bbI2CZip(
if (SDA > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", SDA);
- if (wfRx[SDA].mode != PI_WFRX_I2C)
+ if (wfRx[SDA].mode != PI_WFRX_I2C_SDA)
SOFT_ERROR(PI_NOT_I2C_GPIO, "no I2C on gpio (%d)", SDA);
if (!inBuf || !inLen)
@@ -10300,6 +10131,8 @@ int bbI2CZip(
esc = 0;
setesc = 0;
+ wfRx_lock(SDA);
+
while (!status && (inPos < inLen))
{
DBG(DBG_INTERNAL, "status=%d inpos=%d inlen=%d cmd=%d addr=%d flags=%x",
@@ -10394,11 +10227,362 @@ int bbI2CZip(
setesc = 0;
}
+ wfRx_unlock(SDA);
+
if (status >= 0) status = outPos;
return status;
}
+/* ----------------------------------------------------------------------- */
+
+static void set_CS(wfRx_t *w)
+{
+ myGpioWrite(w->S.CS, PI_SPI_FLAGS_GET_CSPOL(w->S.spiFlags));
+}
+
+static void clear_CS(wfRx_t *w)
+{
+ myGpioWrite(w->S.CS, !PI_SPI_FLAGS_GET_CSPOL(w->S.spiFlags));
+}
+
+static void set_SCLK(wfRx_t *w)
+{
+ myGpioWrite(w->S.SCLK, !PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
+}
+
+static void clear_SCLK(wfRx_t *w)
+{
+ myGpioWrite(w->S.SCLK, PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
+}
+
+static void SPI_delay(wfRx_t *w)
+{
+ myGpioDelay(w->S.delay);
+}
+
+static void bbSPIStart(wfRx_t *w)
+{
+ clear_SCLK(w);
+
+ SPI_delay(w);
+
+ set_CS(w);
+
+ SPI_delay(w);
+}
+
+static void bbSPIStop(wfRx_t *w)
+{
+ SPI_delay(w);
+
+ clear_CS(w);
+
+ SPI_delay(w);
+
+ clear_SCLK(w);
+}
+
+static uint8_t bbSPIXferByte(wfRx_t *w, char txByte)
+{
+ uint8_t bit, rxByte=0;
+
+ if (PI_SPI_FLAGS_GET_CPHA(w->S.spiFlags))
+ {
+ /*
+ CPHA = 1
+ write on set clock
+ read on clear clock
+ */
+
+ for (bit=0; bit<8; bit++)
+ {
+ set_SCLK(w);
+
+ if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
+ {
+ myGpioWrite(w->S.MOSI, txByte & 0x01);
+ txByte >>= 1;
+ }
+ else
+ {
+ myGpioWrite(w->S.MOSI, txByte & 0x80);
+ txByte <<= 1;
+ }
+
+ SPI_delay(w);
+
+ clear_SCLK(w);
+
+ if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
+ {
+ rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
+ }
+ else
+ {
+ rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
+ }
+
+ SPI_delay(w);
+ }
+ }
+ else
+ {
+ /*
+ CPHA = 0
+ read on set clock
+ write on clear clock
+ */
+
+ for (bit=0; bit<8; bit++)
+ {
+ if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
+ {
+ myGpioWrite(w->S.MOSI, txByte & 0x01);
+ txByte >>= 1;
+ }
+ else
+ {
+ myGpioWrite(w->S.MOSI, txByte & 0x80);
+ txByte <<= 1;
+ }
+
+ SPI_delay(w);
+
+ set_SCLK(w);
+
+ if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
+ {
+ rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
+ }
+ else
+ {
+ rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
+ }
+
+ SPI_delay(w);
+
+ clear_SCLK(w);
+ }
+ }
+
+ return rxByte;
+}
+
+/*-------------------------------------------------------------------------*/
+
+int bbSPIOpen(
+ unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK,
+ unsigned baud, unsigned spiFlags)
+{
+ int valid;
+ uint32_t bits;
+
+ DBG(DBG_USER, "CS=%d MISO=%d MOSI=%d SCLK=%d baud=%d flags=%d",
+ CS, MISO, MOSI, SCLK, baud, spiFlags);
+
+ CHECK_INITED;
+
+ if (CS > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad CS (%d)", CS);
+
+ if (MISO > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad MISO (%d)", MISO);
+
+ if (MOSI > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad MOSI (%d)", MOSI);
+
+ if (SCLK > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad SCLK (%d)", SCLK);
+
+ if ((baud < PI_BB_SPI_MIN_BAUD) || (baud > PI_BB_SPI_MAX_BAUD))
+ SOFT_ERROR(PI_BAD_SPI_BAUD, "CS %d, bad baud (%d)", CS, baud);
+
+ if (wfRx[CS].mode != PI_WFRX_NONE)
+ SOFT_ERROR(PI_GPIO_IN_USE,
+ "CS %d is already being used, mode %d", CS, wfRx[CS].mode);
+
+ valid = 0;
+
+ /* check all GPIO unique */
+
+ bits = (1< PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
+
+ switch(wfRx[CS].mode)
+ {
+ case PI_WFRX_SPI_CS:
+
+ myGpioSetMode(wfRx[CS].S.CS, wfRx[CS].S.CSMode);
+ wfRx[CS].mode = PI_WFRX_NONE;
+
+ SCLK = wfRx[CS].S.SCLK;
+
+ if (--wfRx[SCLK].S.usage <= 0)
+ {
+ myGpioSetMode(wfRx[SCLK].S.MISO, wfRx[SCLK].S.MISOMode);
+ myGpioSetMode(wfRx[SCLK].S.MOSI, wfRx[SCLK].S.MOSIMode);
+ myGpioSetMode(wfRx[SCLK].S.SCLK, wfRx[SCLK].S.SCLKMode);
+
+ wfRx[wfRx[SCLK].S.MISO].mode = PI_WFRX_NONE;
+ wfRx[wfRx[SCLK].S.MOSI].mode = PI_WFRX_NONE;
+ wfRx[wfRx[SCLK].S.SCLK].mode = PI_WFRX_NONE;
+ }
+
+ break;
+
+ default:
+
+ SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
+
+ break;
+
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+int bbSPIXfer(
+ unsigned CS,
+ char *inBuf,
+ char *outBuf,
+ unsigned count)
+{
+ int SCLK;
+ int pos;
+ wfRx_t *w;
+
+ DBG(DBG_USER, "CS=%d inBuf=%s outBuf=%08X count=%d",
+ CS, myBuf2Str(count, (char *)inBuf), (int)outBuf, count);
+
+ CHECK_INITED;
+
+ if (CS > PI_MAX_USER_GPIO)
+ SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
+
+ if (wfRx[CS].mode != PI_WFRX_SPI_CS)
+ SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
+
+ if (!inBuf || !count)
+ SOFT_ERROR(PI_BAD_POINTER, "input buffer can't be NULL");
+
+ if (!outBuf && count)
+ SOFT_ERROR(PI_BAD_POINTER, "output buffer can't be NULL");
+
+ SCLK = wfRx[CS].S.SCLK;
+
+ wfRx[SCLK].S.CS = CS;
+ wfRx[SCLK].baud = wfRx[CS].baud;
+ wfRx[SCLK].S.delay = wfRx[CS].S.delay;
+ wfRx[SCLK].S.spiFlags = wfRx[CS].S.spiFlags;
+
+ w = &wfRx[SCLK];
+
+ wfRx_lock(SCLK);
+
+ bbSPIStart(w);
+
+ for (pos=0; pos < count; pos++)
+ {
+ outBuf[pos] = bbSPIXferByte(w, inBuf[pos]);
+ }
+
+ bbSPIStop(w);
+
+ wfRx_unlock(SCLK);
+
+ return count;
+}
/*-------------------------------------------------------------------------*/
@@ -12665,6 +12849,30 @@ int gpioCfgMemAlloc(unsigned memAllocMode)
return 0;
}
+/* ----------------------------------------------------------------------- */
+
+int gpioCfgNetAddr(int numSockAddr, uint32_t *sockAddr)
+{
+ int i;
+
+ DBG(DBG_USER, "numSockAddr=%d sockAddr=%08X",
+ numSockAddr, (unsigned)sockAddr);
+
+ CHECK_NOT_INITED;
+
+ if (numSockAddr <= 0) numSockNetAddr = 0;
+ else
+ {
+ if (numSockAddr >= MAX_CONNECT_ADDRESSES)
+ numSockAddr = MAX_CONNECT_ADDRESSES;
+
+ for (i=0; i
#include
#include
-#define PIGPIO_VERSION 55
+#define PIGPIO_VERSION 56
/*TEXT
@@ -320,6 +320,7 @@ gpioCfgPermissions Configure the GPIO access permissions
gpioCfgInterfaces Configure user interfaces
gpioCfgSocketPort Configure socket port
gpioCfgMemAlloc Configure DMA memory allocation mode
+gpioCfgNetAddr Configure allowed network addresses
gpioCfgInternals Configure miscellaneous internals (DEPRECATED)
gpioCfgGetInternals Get internal configuration settings
@@ -352,6 +353,8 @@ rawWaveAddSPI Not intended for general use
rawWaveAddGeneric Not intended for general use
rawWaveCB Not intended for general use
rawWaveCBAdr Not intended for general use
+rawWaveGetOOL Not intended for general use
+rawWaveSetOOL Not intended for general use
rawWaveGetOut Not intended for general use
rawWaveSetOut Not intended for general use
rawWaveGetIn Not intended for general use
@@ -440,7 +443,7 @@ typedef struct
uint16_t botCB; /* first CB used by wave */
uint16_t topCB; /* last CB used by wave */
uint16_t botOOL; /* first bottom OOL used by wave */
- /* botOOL to botOOL + numBOOL -1 are in use */
+ /* botOOL to botOOL + numBOOL - 1 are in use */
uint16_t topOOL; /* last top OOL used by wave */
/* topOOL - numTOOL to topOOL are in use.*/
uint16_t deleted;
@@ -818,6 +821,10 @@ typedef void *(gpioThreadFunc_t) (void *);
#define PI_FROM_CURRENT 1
#define PI_FROM_END 2
+/* Allowed socket connect addresses */
+
+#define MAX_CONNECT_ADDRESSES 256
+
/*F*/
int gpioInitialise(void);
/*D
@@ -1456,7 +1463,7 @@ if (h >= 0)
{
sprintf(str, "/dev/pigpio%d", h);
- fd = open(str, "r");
+ fd = open(str, O_RDONLY);
if (fd >= 0)
{
@@ -2626,92 +2633,6 @@ SDA: 0-31, the SDA GPIO used in a prior call to [*bbI2COpen*]
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO.
D*/
-/*F*/
-int bbSPIOpen(unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spiFlags);
-/*D
-This function selects a set of GPIO for bit banging SPI at a
-specified baud rate.
-
-Bit banging SPI allows the use of different GPIO for SPI than
-for the hardware SPI ports.
-
-. .
- CS: 0-31
- MISO: 0-31
- MOSI: 0-31
- SCLK: 0-31
-baud: 50-250000
-spiFlags: see below
-. .
-spiFlags consists of the least significant 22 bits.
-
-. .
-21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m
-. .
-
-mm defines the SPI mode.
-
-. .
-Mode POL PHA
- 0 0 0
- 1 0 1
- 2 1 0
- 3 1 1
-. .
-
-p0 is 0 if CEx is active low (default) and 1 for active high.
-
-T is 1 if the least significant bit is transmitted on MOSI first, the
-default (0) shifts the most significant bit out first.
-
-R is 1 if the least significant bit is received on MISO first, the
-default (0) receives the most significant bit first.
-
-The other bits in flags should be set to zero.
-
-Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
-PI_GPIO_IN_USE.
-D*/
-
-/*F*/
-int bbSPIClose(unsigned CS);
-/*D
-This function stops bit banging SPI on a set of GPIO previously
-opened with [*bbSPIOpen*].
-
-. .
-CS: 0-31, the CS GPIO used in a prior call to [*bbSPIOpen*]
-. .
-
-Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
-D*/
-
-/*F*/
-int bbSPIXfer(
- unsigned CS,
- char *inBuf,
- char *outBuf,
- unsigned len);
-/*D
-This function executes an bit banged SPI transfer. The data
-to be sent is specified by the contents of inBuf, received data
-is stored into outBuf.
-len specifies the amount of bytes to be transferred.
-
-. .
- CS: 0-31 (as used in a prior call to [*bbSPIOpen*])
- inBuf: pointer to buffer to hold data to be sent
-outBuf: pointer to buffer to hold returned data
-len: size of data transfer
-. .
-
-Returns >= 0 if OK (the number of bytes read), otherwise
-PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
-
-The returned SPI data is stored in consecutive locations of outBuf.
-D*/
-
/*F*/
int bbI2CZip(
unsigned SDA,
@@ -2783,6 +2704,161 @@ End
...
D*/
+/*F*/
+int bbSPIOpen(
+ unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK,
+ unsigned baud, unsigned spiFlags);
+/*D
+This function selects a set of GPIO for bit banging SPI with
+a specified baud rate and mode.
+
+. .
+ CS: 0-31
+ MISO: 0-31
+ MOSI: 0-31
+ SCLK: 0-31
+ baud: 50-250000
+spiFlags: see below
+. .
+
+spiFlags consists of the least significant 22 bits.
+
+. .
+21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+. .
+
+mm defines the SPI mode, defaults to 0
+
+. .
+Mode CPOL CPHA
+ 0 0 0
+ 1 0 1
+ 2 1 0
+ 3 1 1
+. .
+
+p is 0 if CS is active low (default) and 1 for active high.
+
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.
+
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.
+
+The other bits in flags should be set to zero.
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
+PI_GPIO_IN_USE.
+
+If more than one device is connected to the SPI bus (defined by
+SCLK, MOSI, and MISO) each must have its own CS.
+
+...
+bbSPIOpen(10, MISO, MOSI, SCLK, 10000, 0); // device 1
+bbSPIOpen(11, MISO, MOSI, SCLK, 20000, 3); // device 2
+...
+D*/
+
+/*F*/
+int bbSPIClose(unsigned CS);
+/*D
+This function stops bit banging SPI on a set of GPIO
+opened with [*bbSPIOpen*].
+
+. .
+CS: 0-31, the CS GPIO used in a prior call to [*bbSPIOpen*]
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
+D*/
+
+/*F*/
+int bbSPIXfer(
+ unsigned CS,
+ char *inBuf,
+ char *outBuf,
+ unsigned count);
+/*D
+This function executes a bit banged SPI transfer.
+
+. .
+ CS: 0-31 (as used in a prior call to [*bbSPIOpen*])
+ inBuf: pointer to buffer to hold data to be sent
+outBuf: pointer to buffer to hold returned data
+ count: size of data transfer
+. .
+
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
+
+...
+// gcc -Wall -pthread -o bbSPIx_test bbSPIx_test.c -lpigpio
+// sudo ./bbSPIx_test
+
+
+#include
+
+#include "pigpio.h"
+
+#define CE0 5
+#define CE1 6
+#define MISO 13
+#define MOSI 19
+#define SCLK 12
+
+int main(int argc, char *argv[])
+{
+ int i, count, set_val, read_val;
+ unsigned char inBuf[3];
+ char cmd1[] = {0, 0};
+ char cmd2[] = {12, 0};
+ char cmd3[] = {1, 128, 0};
+
+ if (gpioInitialise() < 0)
+ {
+ fprintf(stderr, "pigpio initialisation failed.\n");
+ return 1;
+ }
+
+ bbSPIOpen(CE0, MISO, MOSI, SCLK, 10000, 0); // MCP4251 DAC
+ bbSPIOpen(CE1, MISO, MOSI, SCLK, 20000, 3); // MCP3008 ADC
+
+ for (i=0; i<256; i++)
+ {
+ cmd1[1] = i;
+
+ count = bbSPIXfer(CE0, cmd1, (char *)inBuf, 2); // > DAC
+
+ if (count == 2)
+ {
+ count = bbSPIXfer(CE0, cmd2, (char *)inBuf, 2); // < DAC
+
+ if (count == 2)
+ {
+ set_val = inBuf[1];
+
+ count = bbSPIXfer(CE1, cmd3, (char *)inBuf, 3); // < ADC
+
+ if (count == 3)
+ {
+ read_val = ((inBuf[1]&3)<<8) | inBuf[2];
+ printf("%d %d\n", set_val, read_val);
+ }
+ }
+ }
+ }
+
+ bbSPIClose(CE0);
+ bbSPIClose(CE1);
+
+ gpioTerminate();
+
+ return 0;
+}
+...
+D*/
+
/*F*/
int spiOpen(unsigned spiChan, unsigned baud, unsigned spiFlags);
/*D
@@ -4314,6 +4390,22 @@ Auto will use the mailbox method unless a larger than default buffer
size is requested with [*gpioCfgBufferSize*].
D*/
+
+/*F*/
+int gpioCfgNetAddr(int numSockAddr, uint32_t *sockAddr);
+/*D
+Sets the network addresses which are allowed to talk over the
+socket interface.
+
+This function is only effective if called before [*gpioInitialise*].
+
+. .
+numSockAddr: 0-256 (0 means all addresses allowed)
+ sockAddr: an array of permitted network addresses.
+. .
+D*/
+
+
/*F*/
int gpioCfgInternals(unsigned cfgWhat, unsigned cfgVal);
/*D
@@ -4325,6 +4417,7 @@ cfgWhat: see source code
. .
D*/
+
/*F*/
uint32_t gpioCfgGetInternals(void);
/*D
@@ -4456,7 +4549,7 @@ D*/
/*F*/
rawCbs_t *rawWaveCBAdr(int cbNum);
/*D
-Return the Linux address of contol block cbNum.
+Return the (Linux) address of contol block cbNum.
. .
cbNum: the cb of interest
@@ -4465,11 +4558,39 @@ cbNum: the cb of interest
Not intended for general use.
D*/
+/*F*/
+uint32_t rawWaveGetOOL(int pos);
+/*D
+Gets the OOL parameter stored at pos.
+
+. .
+pos: the position of interest.
+. .
+
+Not intended for general use.
+D*/
+
+
+/*F*/
+void rawWaveSetOOL(int pos, uint32_t lVal);
+/*D
+Sets the OOL parameter stored at pos to value.
+
+. .
+ pos: the position of interest
+lVal: the value to write
+. .
+
+Not intended for general use.
+D*/
+
/*F*/
uint32_t rawWaveGetOut(int pos);
/*D
Gets the wave output parameter stored at pos.
+DEPRECATED: use rawWaveGetOOL instead.
+
. .
pos: the position of interest.
. .
@@ -4483,6 +4604,8 @@ void rawWaveSetOut(int pos, uint32_t lVal);
/*D
Sets the wave output parameter stored at pos to value.
+DEPRECATED: use rawWaveSetOOL instead.
+
. .
pos: the position of interest
lVal: the value to write
@@ -4496,6 +4619,8 @@ uint32_t rawWaveGetIn(int pos);
/*D
Gets the wave input value parameter stored at pos.
+DEPRECATED: use rawWaveGetOOL instead.
+
. .
pos: the position of interest
. .
@@ -4509,6 +4634,8 @@ void rawWaveSetIn(int pos, uint32_t lVal);
/*D
Sets the wave input value stored at pos to value.
+DEPRECATED: use rawWaveSetOOL instead.
+
. .
pos: the position of interest
lVal: the value to write
@@ -4708,6 +4835,9 @@ count::
The number of bytes to be transferred in an I2C, SPI, or Serial
command.
+CS::
+The GPIO used for the slave select signal when bit banging SPI.
+
data_bits::1-32
The number of data bits to be used when adding serial data to a
@@ -4983,6 +5113,9 @@ millis::
A value representing milliseconds.
+MISO::
+The GPIO used for the MISO signal when bit banging SPI.
+
mode::
1. The operational mode of a GPIO, normally INPUT or OUTPUT.
@@ -5014,6 +5147,9 @@ PI_FILE_CREATE 8
PI_FILE_TRUNC 16
. .
+MOSI::
+The GPIO used for the MOSI signal when bit banging SPI.
+
numBits::
The number of bits stored in a buffer.
@@ -5032,6 +5168,11 @@ The number of pulses to be added to a waveform.
numSegs::
The number of segments in a combined I2C transaction.
+numSockAddr::
+The number of network addresses allowed to use the socket interface.
+
+0 means all addresses allowed.
+
offset::
The associated data starts this number of microseconds from the start of
the waveform.
@@ -5202,6 +5343,9 @@ A pointer to a buffer to receive data.
SCL::
The user GPIO to use for the clock when bit banging I2C.
+SCLK::
+The GPIO used for the SCLK signal when bit banging SPI.
+
*script::
A pointer to the text of a script.
@@ -5264,6 +5408,12 @@ size_t::
A standard type used to indicate the size of an object in bytes.
+*sockAddr::
+An array of network addresses allowed to use the socket interface encoded
+as 32 bit numbers.
+
+E.g. address 192.168.1.66 would be encoded as 0x4201a8c0.
+
*spi::
A pointer to a [*rawSPI_t*] structure.
@@ -5281,7 +5431,7 @@ spiChan::
A SPI channel, 0-2.
spiFlags::
-See [*spiOpen*].
+See [*spiOpen*] and [*bbSPIOpen*].
spiSS::
The SPI slave select GPIO in a raw SPI transaction.
diff --git a/pigpio.py b/pigpio.py
index 73b6c6e..b0962d5 100644
--- a/pigpio.py
+++ b/pigpio.py
@@ -288,7 +288,7 @@ import threading
import os
import atexit
-VERSION = "1.32"
+VERSION = "1.33"
exceptions = True
@@ -363,18 +363,18 @@ FROM_START=0
FROM_CURRENT=1
FROM_END=2
-SPI_CS_HIGH_ACTIVE = 1 << 2
-SPI_CS0_HIGH_ACTIVE = 1 << 2
-SPI_CS1_HIGH_ACTIVE = 1 << 3
-SPI_CS2_HIGH_ACTIVE = 1 << 4
-SPI_RX_LSBFIRST = 1 << 15
-SPI_TX_LSBFIRST = 1 << 14
SPI_MODE_0 = 0
SPI_MODE_1 = 1
SPI_MODE_2 = 2
SPI_MODE_3 = 3
-SPI_CPOL = 2
-SPI_CPHA = 1
+
+SPI_CPHA = 1 << 0
+SPI_CPOL = 1 << 1
+
+SPI_CS_HIGH_ACTIVE = 1 << 2
+
+SPI_TX_LSBFIRST = 1 << 14
+SPI_RX_LSBFIRST = 1 << 15
# pigpio command numbers
@@ -809,6 +809,24 @@ _errors=[
[PI_NOT_SPI_GPIO , "no bit bang SPI in progress on GPIO"],
]
+except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}"
+
+except_z = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
+
+except1 = """
+Did you start the pigpio daemon? E.g. sudo pigpiod
+
+Did you specify the correct Pi host/port in the environment
+variables PIGPIO_ADDR/PIGPIO_PORT?
+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 = """
+Do you have permission to access the pigpio daemon?
+Perhaps it was started with sudo pigpiod -nlocalhost"""
+
class _socklock:
"""
A class to store socket and lock.
@@ -2974,62 +2992,65 @@ class pi():
"""
This function selects a set of GPIO for bit banging SPI at a
specified baud rate.
-
- Bit banging SPI allows the use of different GPIO for SPI than
- for the hardware SPI ports.
- CS := 0-31
- MISO := 0-31
- MOSI := 0-31
- SCLK := 0-31
- baud := 50-250000
+ CS := 0-31
+ MISO := 0-31
+ MOSI := 0-31
+ SCLK := 0-31
+ baud := 50-250000
spiFlags := see below
spiFlags consists of the least significant 22 bits.
- ...
+ . .
21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m
- ...
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+ . .
mm defines the SPI mode, defaults to 0
-
- ...
+
+ . .
Mode CPOL CPHA
0 0 0
1 0 1
2 1 0
3 1 1
- ...
-
- Use the following constants to set the Mode:
- pigpio.SPI_MODE_0,
- pigpio.SPI_MODE_1,
- pigpio.SPI_MODE_2 or
+ . .
+
+ The following constants may be used to set the mode:
+
+ . .
+ pigpio.SPI_MODE_0
+ pigpio.SPI_MODE_1
+ pigpio.SPI_MODE_2
pigpio.SPI_MODE_3
- or use
- pigpio.SPI_CPOL and/ or
- pigpio.SPI_CPHA
-
- p0 is 0 if CS is active low (default) and 1 for active high.
- Use pigpio.SPI_CS_HIGH_ACTIVE to set this flag.
+ . .
+
+ Alternatively pigpio.SPI_CPOL and/or pigpio.SPI_CPHA
+ may be used.
+
+ p is 0 if CS is active low (default) and 1 for active high.
+ pigpio.SPI_CS_HIGH_ACTIVE may be used to set this flag.
T is 1 if the least significant bit is transmitted on MOSI first,
the default (0) shifts the most significant bit out first.
- Use pigpio.SPI_TX_LSBFIRST to set this flag.
+ pigpio.SPI_TX_LSBFIRST may be used to set this flag.
R is 1 if the least significant bit is received on MISO first,
the default (0) receives the most significant bit first.
- Use pigpio.SPI_RX_LSBFIRST to set this flag.
+ pigpio.SPI_RX_LSBFIRST may be used to set this flag.
The other bits in spiFlags should be set to zero.
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
PI_GPIO_IN_USE.
+
+ If more than one device is connected to the SPI bus (defined by
+ SCLK, MOSI, and MISO) each must have its own CS.
+
...
- pi.bb_spi_open(CS, MISO, MOSI, SCLK,
- baud=100000,
- spi_flags=pigpio.SPI_MODE_1 | pigpio.SPI_CS_HIGH_ACTIVE)
+ bb_spi_open(10, MISO, MOSI, SCLK, 10000, 0); // device 1
+ bb_spi_open(11, MISO, MOSI, SCLK, 20000, 3); // device 2
...
"""
# I p1 CS
@@ -3050,9 +3071,9 @@ class pi():
def bb_spi_close(self, CS):
"""
This function stops bit banging SPI on a set of GPIO
- previously opened with [*bb_spi_open*].
+ opened with [*bb_spi_open*].
- CS:= 0-31, the CS GPIO used in a prior call to [*bb_ispi_open*]
+ CS:= 0-31, the CS GPIO used in a prior call to [*bb_spi_open*]
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
@@ -3065,22 +3086,61 @@ class pi():
def bb_spi_xfer(self, CS, data):
"""
- This function executes an bit banged SPI transfer. The data
- to be sent is specified by the contents of data, received data
- is returned as a bytestring.
+ This function executes a bit banged SPI transfer.
- CS:= 0-31 (as used in a prior call to [*bbSPIOpen*])
+ CS:= 0-31 (as used in a prior call to [*bb_spi_open*])
data:= data to be sent
- Returns >= 0 if OK (the number of bytes read), otherwise
- PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
+ 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).
- The received SPI data returned as ab bytearray
...
- pi.bb_spi_xfer(CS, data)
+ #!/usr/bin/env python
+
+ import pigpio
+
+ CE0=5
+ CE1=6
+ MISO=13
+ MOSI=19
+ SCLK=12
+
+ pi = pigpio.pi()
+ if not pi.connected:
+ exit()
+
+ pi.bb_spi_open(CE0, MISO, MOSI, SCLK, 10000, 0) # MCP4251 DAC
+ pi.bb_spi_open(CE1, MISO, MOSI, SCLK, 20000, 3) # MCP3008 ADC
+
+ for i in range(256):
+
+ count, data = pi.bb_spi_xfer(CE0, [0, i]) # Set DAC value
+
+ if count == 2:
+
+ count, data = pi.bb_spi_xfer(CE0, [12, 0]) # Read back DAC
+
+ if count == 2:
+
+ set_val = data[1]
+
+ count, data = pi.bb_spi_xfer(CE1, [1, 128, 0]) # Read ADC
+
+ if count == 3:
+
+ read_val = ((data[1]&3)<<8) | data[2]
+
+ print("{} {}".format(set_val, read_val))
+
+ pi.bb_spi_close(CE0)
+ pi.bb_spi_close(CE1)
+
+ pi.stop()
...
"""
- # I p1 SDA
+ # I p1 CS
# I p2 0
# I p3 len
## extension ##
@@ -4428,9 +4488,22 @@ class pi():
self._notify = _callback_thread(self.sl, host, port)
except socket.error:
+ exception = 1
+
+ except struct.error:
+ exception = 2
+
+ else:
+ exception = 0
+ atexit.register(self.stop)
+
+ if exception != 0:
+
self.connected = False
+
if self.sl.s is not None:
self.sl.s = None
+
if host == '':
h = "localhost"
else:
@@ -4438,20 +4511,12 @@ class pi():
s = "Can't connect to pigpio at {}({})".format(str(h), str(port))
- print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
- print(s)
- print("")
- print("Did you start the pigpio daemon? E.g. sudo pigpiod")
- print("")
- print("Did you specify the correct Pi host/port in the environment")
- print("variables PIGPIO_ADDR/PIGPIO_PORT?")
- print("E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888")
- print("")
- print("Did you specify the correct Pi host/port in the")
- print("pigpio.pi() function? E.g. pigpio.pi('soft', 8888))")
- print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
- else:
- atexit.register(self.stop)
+ print(except_a.format(s))
+ if exception == 1:
+ print(except1)
+ else:
+ print(except2)
+ print(except_z)
def stop(self):
"""Release pigpio resources.
@@ -4527,6 +4592,9 @@ def xref():
count:
The number of bytes of data to be transferred.
+ CS:
+ The GPIO used for the slave select signal when bit banging SPI.
+
data:
Data to be transmitted, a series of bytes.
@@ -4771,6 +4839,9 @@ def xref():
SET = 1
TIMEOUT = 2 # only returned for a watchdog timeout
+ MISO:
+ The GPIO used for the MISO signal when bit banging SPI.
+
mode:
1.The operational mode of a GPIO, normally INPUT or OUTPUT.
@@ -4791,6 +4862,9 @@ def xref():
WAVE_MODE_ONE_SHOT_SYNC = 2
WAVE_MODE_REPEAT_SYNC = 3
+ MOSI:
+ The GPIO used for the MOSI signal when bit banging SPI.
+
offset: >=0
The offset wave data starts from the beginning of the waveform
being currently defined.
@@ -4854,6 +4928,9 @@ def xref():
SCL:
The user GPIO to use for the clock when bit banging I2C.
+ SCLK::
+ The GPIO used for the SCLK signal when bit banging SPI.
+
script:
The text of a script to store on the pigpio daemon.
diff --git a/pigpiod.1 b/pigpiod.1
index c32a4bb..188f352 100644
--- a/pigpiod.1
+++ b/pigpiod.1
@@ -34,70 +34,75 @@ pigpiod accepts the following configuration options
.SH OPTIONS
.IP "\fB-a value\fP"
-DMA memory allocation mode
-0=AUTO, 1=PMAP, 2=MBOX
-default AUTO
-
+DMA memory allocation mode.
+0=AUTO, 1=PMAP, 2=MBOX.
+Default AUTO
+.
.IP "\fB-b value\fP"
-GPIO sample buffer in milliseconds
-100-10000
-default 120
-
+GPIO sample buffer size in milliseconds.
+100-10000.
+Default 120
+.
.IP "\fB-c value\fP"
-library internal settings
-
-default 0
-
+Library internal settings.
+.
+Default 0
+.
.IP "\fB-d value\fP"
-primary DMA channel
-0-14
-default 14
-
+Primary DMA channel.
+0-14.
+Default 14
+.
.IP "\fB-e value\fP"
-secondary DMA channel
-0-14
-default 6
-
+Secondary DMA channel.
+0-14.
+Default 6. Preferably use one of DMA channels 0 to 6 for the secondary channel
+.
.IP "\fB-f\fP"
-disable fifo interface
-
-default enabled
-
+Disable fifo interface.
+.
+Default enabled
+.
.IP "\fB-k\fP"
-disable local and remote socket interface
-
-default enabled
-
+Disable local and remote socket interface.
+.
+Default enabled
+.
.IP "\fB-l\fP"
-disable remote socket interface
-
-default enabled
-
+Disable remote socket interface.
+.
+Default enabled
+.
+.IP "\fB-n IP address\fP"
+Allow IP address to use the socket interface.
+Name (e.g. paul) or dotted quad (e.g. 192.168.1.66).
+If the -n option is not used all addresses are allowed (unless overridden by the -k or -l options). Multiple -n options are allowed. If -k has been used -n has no effect. If -l has been used only -n localhost has any effect
+.
.IP "\fB-p value\fP"
-socket port
-1024-32000
-default 8888
-
+Socket port.
+1024-32000.
+Default 8888
+.
.IP "\fB-s value\fP"
-sample rate
-1, 2, 4, 5, 8, 10
-default 5
-
+Sample rate.
+1, 2, 4, 5, 8, or 10 microseconds.
+Default 5
+.
.IP "\fB-t value\fP"
-clock peripheral
-0=PWM 1=PCM
-default PCM
-
+Clock peripheral.
+0=PWM 1=PCM.
+Default PCM. pigpio uses one or both of PCM and PWM. If PCM is used then PWM is available for audio. If PWM is used then PCM is available for audio. If waves or hardware PWM are used neither PWM nor PCM will be available for audio.
+.
.IP "\fB-v -V\fP"
-display pigpio version and exit
-
-
+Display pigpio version and exit.
+.
+.
.IP "\fB-x mask\fP"
-GPIO which may be updated
+GPIO which may be updated.
A 54 bit mask with (1<
*/
/*
-This version is for pigpio version 48+
+This version is for pigpio version 56+
*/
#include
@@ -42,6 +42,8 @@ This version is for pigpio version 48+
#include
#include
#include
+#include
+#include
#include "pigpio.h"
@@ -65,6 +67,10 @@ static int updateMaskSet = 0;
static FILE * errFifo;
+static uint32_t sockNetAddr[MAX_CONNECT_ADDRESSES];
+
+static int numSockNetAddr = 0;
+
void fatal(char *fmt, ...)
{
char buf[128];
@@ -86,19 +92,20 @@ void usage()
fprintf(stderr, "\n" \
"pigpio V%d\n" \
"Usage: sudo pigpiod [OPTION] ...\n" \
- " -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \
- " -b value, gpio sample buffer in milliseconds, default 120\n" \
- " -c value, library internal settings, default 0\n" \
- " -d value, primary DMA channel, 0-14, default 14\n" \
- " -e value, secondary DMA channel, 0-14, default 6\n" \
- " -f, disable fifo interface, default enabled\n" \
- " -k, disable socket interface, default enabled\n" \
- " -l, localhost socket only default all interfaces\n" \
- " -p value, socket port, 1024-32000, default 8888\n" \
- " -s value, sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
- " -t value, clock peripheral, 0=PWM 1=PCM, default PCM\n" \
- " -v, -V, display pigpio version and exit\n" \
- " -x mask, gpios which may be updated, default board user gpios\n" \
+ " -a value, DMA mode, 0=AUTO, 1=PMAP, 2=MBOX, default AUTO\n" \
+ " -b value, sample buffer size in ms, default 120\n" \
+ " -c value, library internal settings, default 0\n" \
+ " -d value, primary DMA channel, 0-14, default 14\n" \
+ " -e value, secondary DMA channel, 0-14, default 6\n" \
+ " -f, disable fifo interface, default enabled\n" \
+ " -k, disable socket interface, default enabled\n" \
+ " -l, localhost socket only default local+remote\n" \
+ " -n IP addr, allow address, name or dotted, default allow all\n" \
+ " -p value, socket port, 1024-32000, default 8888\n" \
+ " -s value, sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
+ " -t value, clock peripheral, 0=PWM 1=PCM, default PCM\n" \
+ " -v, -V, display pigpio version and exit\n" \
+ " -x mask, GPIO which may be updated, default board GPIO\n" \
"EXAMPLE\n" \
"sudo pigpiod -s 2 -b 200 -f\n" \
" Set a sample rate of 2 microseconds with a 200 millisecond\n" \
@@ -117,12 +124,43 @@ static uint64_t getNum(char *str, int *err)
return val;
}
+static uint32_t checkAddr(char *addrStr)
+{
+ int err;
+ struct addrinfo hints, *res;
+ struct sockaddr_in *sin;
+ const char *portStr;
+ uint32_t addr;
+
+ portStr = getenv(PI_ENVPORT);
+
+ if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
+
+ memset (&hints, 0, sizeof (hints));
+
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags |= AI_CANONNAME;
+
+ err = getaddrinfo(addrStr, portStr, &hints, &res);
+
+ if (err) return 0;
+
+ sin = (struct sockaddr_in *)res->ai_addr;
+ addr = sin->sin_addr.s_addr;
+
+ freeaddrinfo(res);
+
+ return addr;
+}
+
static void initOpts(int argc, char *argv[])
{
int opt, err, i;
+ uint32_t addr;
int64_t mask;
- while ((opt = getopt(argc, argv, "a:b:c:d:e:fklp:s:t:x:vV")) != -1)
+ while ((opt = getopt(argc, argv, "a:b:c:d:e:fkln:p:s:t:x:vV")) != -1)
{
switch (opt)
{
@@ -173,6 +211,13 @@ static void initOpts(int argc, char *argv[])
ifFlags |= PI_LOCALHOST_SOCK_IF;
break;
+ case 'n':
+ addr = checkAddr(optarg);
+ if (addr && (numSockNetAddr= PI_MIN_SOCKET_PORT) && (i <= PI_MAX_SOCKET_PORT))
@@ -304,6 +349,8 @@ int main(int argc, char **argv)
if (updateMaskSet) gpioCfgPermissions(updateMask);
+ gpioCfgNetAddr(numSockNetAddr, sockNetAddr);
+
gpioCfgSetInternals(cfgInternals);
/* start library */
diff --git a/pigpiod_if2.3 b/pigpiod_if2.3
index 2583890..66ad4e0 100644
--- a/pigpiod_if2.3
+++ b/pigpiod_if2.3
@@ -3757,6 +3757,301 @@ End
.EE
+.IP "\fBint bb_spi_open(int pi, unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spi_flags)\fP"
+.IP "" 4
+This function selects a set of GPIO for bit banging SPI at a
+specified baud rate.
+
+.br
+
+.br
+
+.EX
+ pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+ CS: 0-31
+.br
+ MISO: 0-31
+.br
+ MOSI: 0-31
+.br
+ SCLK: 0-31
+.br
+ baud: 50-250000
+.br
+spi_flags: see below
+.br
+
+.EE
+
+.br
+
+.br
+spi_flags consists of the least significant 22 bits.
+
+.br
+
+.br
+
+.EX
+21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+.br
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+.br
+
+.EE
+
+.br
+
+.br
+mm defines the SPI mode, defaults to 0
+
+.br
+
+.br
+
+.EX
+Mode CPOL CPHA
+.br
+ 0 0 0
+.br
+ 1 0 1
+.br
+ 2 1 0
+.br
+ 3 1 1
+.br
+
+.EE
+
+.br
+
+.br
+p is 0 if CS is active low (default) and 1 for active high.
+
+.br
+
+.br
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.
+
+.br
+
+.br
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.
+
+.br
+
+.br
+The other bits in flags should be set to zero.
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
+PI_GPIO_IN_USE.
+
+.br
+
+.br
+If more than one device is connected to the SPI bus (defined by
+SCLK, MOSI, and MISO) each must have its own CS.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+bb_spi_open(pi,10, MISO, MOSI, SCLK, 10000, 0); // device 1
+.br
+bb_spi_open(pi,11, MISO, MOSI, SCLK, 20000, 3); // device 2
+.br
+
+.EE
+
+.IP "\fBint bb_spi_close(int pi, unsigned CS)\fP"
+.IP "" 4
+This function stops bit banging SPI on a set of GPIO
+opened with \fBbbSPIOpen\fP.
+
+.br
+
+.br
+
+.EX
+pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+CS: 0-31, the CS GPIO used in a prior call to \fBbb_spi_open\fP
+.br
+
+.EE
+
+.br
+
+.br
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
+
+.IP "\fBint bb_spi_xfer(int pi, unsigned CS, char *txBuf, char *rxBuf, unsigned count)\fP"
+.IP "" 4
+This function executes a bit banged SPI transfer.
+
+.br
+
+.br
+
+.EX
+ pi: >=0 (as returned by \fBpigpio_start\fP).
+.br
+ CS: 0-31 (as used in a prior call to \fBbb_spi_open\fP)
+.br
+txBuf: pointer to buffer to hold data to be sent
+.br
+rxBuf: pointer to buffer to hold returned data
+.br
+count: size of data transfer
+.br
+
+.EE
+
+.br
+
+.br
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
+
+.br
+
+.br
+\fBExample\fP
+.br
+
+.EX
+// gcc -Wall -pthread -o bb_spi_x_test bb_spi_x_test.c -lpigpiod_if2
+.br
+// ./bb_spi_x_test
+.br
+
+.br
+#include
+.br
+
+.br
+#include "pigpiod_if2.h"
+.br
+
+.br
+#define CE0 5
+.br
+#define CE1 6
+.br
+#define MISO 13
+.br
+#define MOSI 19
+.br
+#define SCLK 12
+.br
+
+.br
+int main(int argc, char *argv[])
+.br
+{
+.br
+ int i, pi, count, set_val, read_val;
+.br
+ unsigned char inBuf[3];
+.br
+ char cmd1[] = {0, 0};
+.br
+ char cmd2[] = {12, 0};
+.br
+ char cmd3[] = {1, 128, 0};
+.br
+
+.br
+ if ((pi = pigpio_start(0, 0)) < 0)
+.br
+ {
+.br
+ fprintf(stderr, "pigpio initialisation failed (%d).\n", pi);
+.br
+ return 1;
+.br
+ }
+.br
+
+.br
+ bb_spi_open(pi, CE0, MISO, MOSI, SCLK, 10000, 0); // MCP4251 DAC
+.br
+ bb_spi_open(pi, CE1, MISO, MOSI, SCLK, 20000, 3); // MCP3008 ADC
+.br
+
+.br
+ for (i=0; i<256; i++)
+.br
+ {
+.br
+ cmd1[1] = i;
+.br
+
+.br
+ count = bb_spi_xfer(pi, CE0, cmd1, (char *)inBuf, 2); // > DAC
+.br
+
+.br
+ if (count == 2)
+.br
+ {
+.br
+ count = bb_spi_xfer(pi, CE0, cmd2, (char *)inBuf, 2); // < DAC
+.br
+
+.br
+ if (count == 2)
+.br
+ {
+.br
+ set_val = inBuf[1];
+.br
+
+.br
+ count = bb_spi_xfer(pi, CE1, cmd3, (char *)inBuf, 3); // < ADC
+.br
+
+.br
+ if (count == 3)
+.br
+ {
+.br
+ read_val = ((inBuf[1]&3)<<8) | inBuf[2];
+.br
+ printf("%d %d\n", set_val, read_val);
+.br
+ }
+.br
+ }
+.br
+ }
+.br
+ }
+.br
+
+.br
+ bb_spi_close(pi, CE0);
+.br
+ bb_spi_close(pi, CE1);
+.br
+
+.br
+ pigpio_stop(pi);
+.br
+}
+.br
+
+.EE
+
.IP "\fBint spi_open(int pi, unsigned spi_channel, unsigned baud, unsigned spi_flags)\fP"
.IP "" 4
This function returns a handle for the SPI device on channel.
@@ -5272,6 +5567,13 @@ command.
.br
+.IP "\fBCS\fP" 0
+The GPIO used for the slave select signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fBdata_bits\fP: 1-32" 0
The number of data bits in each character of serial data.
@@ -5588,6 +5890,13 @@ PI_TIMEOUT 2
.br
+.IP "\fBMISO\fP" 0
+The GPIO used for the MISO signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fBmode\fP" 0
1. The operational mode of a GPIO, normally INPUT or OUTPUT.
@@ -5678,6 +5987,9 @@ PI_FILE_TRUNC 16
.br
+.IP "\fBMOSI\fP" 0
+The GPIO used for the MOSI signal when bit banging SPI.
+
.br
.br
@@ -5928,6 +6240,13 @@ The user GPIO to use for the clock when bit banging I2C.
.br
+.IP "\fBSCLK\fP" 0
+The GPIO used for the SCLK signal when bit banging SPI.
+
+.br
+
+.br
+
.IP "\fB*script\fP" 0
A pointer to the text of a script.
@@ -6028,7 +6347,7 @@ A SPI channel, 0-2.
.br
.IP "\fBspi_flags\fP" 0
-See \fBspi_open\fP.
+See \fBspi_open\fP and \fBbb_spi_open\fP.
.br
diff --git a/pigpiod_if2.c b/pigpiod_if2.c
index bc3d496..842fb4b 100644
--- a/pigpiod_if2.c
+++ b/pigpiod_if2.c
@@ -1397,6 +1397,76 @@ int bb_i2c_zip(
return bytes;
}
+int bb_spi_open(
+ int pi,
+ unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK,
+ unsigned baud, unsigned spiFlags)
+{
+ uint8_t buf[20];
+ gpioExtent_t ext[1];
+
+ /*
+ p1=CS
+ p2=0
+ p3=20
+ ## extension ##
+ uint32_t MISO
+ uint32_t MOSI
+ uint32_t SCLK
+ uint32_t baud
+ uint32_t spiFlags
+ */
+
+ ext[0].size = 20;
+ ext[0].ptr = &buf;
+
+ memcpy(buf + 0, &MISO, 4);
+ memcpy(buf + 4, &MOSI, 4);
+ memcpy(buf + 8, &SCLK, 4);
+ memcpy(buf + 12, &baud, 4);
+ memcpy(buf + 16, &spiFlags, 4);
+
+ return pigpio_command_ext
+ (pi, PI_CMD_BSPIO, CS, 0, 20, 1, ext, 1);
+}
+
+int bb_spi_close(int pi, unsigned CS)
+ {return pigpio_command(pi, PI_CMD_BSPIC, CS, 0, 1);}
+
+int bb_spi_xfer(
+ int pi,
+ unsigned CS,
+ char *txBuf,
+ char *rxBuf,
+ unsigned count)
+{
+ int bytes;
+ gpioExtent_t ext[1];
+
+ /*
+ p1=CS
+ p2=0
+ p3=count
+ ## extension ##
+ char txBuf[count]
+ */
+
+ ext[0].size = count;
+ ext[0].ptr = txBuf;
+
+ bytes = pigpio_command_ext
+ (pi, PI_CMD_BSPIX, CS, 0, count, 1, ext, 0);
+
+ if (bytes > 0)
+ {
+ bytes = recvMax(pi, rxBuf, count, bytes);
+ }
+
+ _pmu(pi);
+
+ return bytes;
+}
+
int spi_open(int pi, unsigned channel, unsigned speed, uint32_t flags)
{
gpioExtent_t ext[1];
diff --git a/pigpiod_if2.h b/pigpiod_if2.h
index c41d5a1..ced2c9a 100644
--- a/pigpiod_if2.h
+++ b/pigpiod_if2.h
@@ -30,7 +30,7 @@ For more information, please refer to
#include "pigpio.h"
-#define PIGPIOD_IF2_VERSION 8
+#define PIGPIOD_IF2_VERSION 9
/*TEXT
@@ -253,6 +253,10 @@ spi_read Reads bytes from a SPI device
spi_write Writes bytes to a SPI device
spi_xfer Transfers bytes with a SPI device
+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
+
SERIAL
serial_open Opens a serial device
@@ -2371,6 +2375,163 @@ End
...
D*/
+/*F*/
+int bb_spi_open(
+ int pi,
+ unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK,
+ unsigned baud, unsigned spi_flags);
+/*D
+This function selects a set of GPIO for bit banging SPI at a
+specified baud rate.
+
+. .
+ pi: >=0 (as returned by [*pigpio_start*]).
+ CS: 0-31
+ MISO: 0-31
+ MOSI: 0-31
+ SCLK: 0-31
+ baud: 50-250000
+spi_flags: see below
+. .
+
+spi_flags consists of the least significant 22 bits.
+
+. .
+21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+. .
+
+mm defines the SPI mode, defaults to 0
+
+. .
+Mode CPOL CPHA
+ 0 0 0
+ 1 0 1
+ 2 1 0
+ 3 1 1
+. .
+
+p is 0 if CS is active low (default) and 1 for active high.
+
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.
+
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.
+
+The other bits in flags should be set to zero.
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
+PI_GPIO_IN_USE.
+
+If more than one device is connected to the SPI bus (defined by
+SCLK, MOSI, and MISO) each must have its own CS.
+
+...
+bb_spi_open(pi,10, MISO, MOSI, SCLK, 10000, 0); // device 1
+bb_spi_open(pi,11, MISO, MOSI, SCLK, 20000, 3); // device 2
+...
+D*/
+
+/*F*/
+int bb_spi_close(int pi, unsigned CS);
+/*D
+This function stops bit banging SPI on a set of GPIO
+opened with [*bbSPIOpen*].
+
+. .
+pi: >=0 (as returned by [*pigpio_start*]).
+CS: 0-31, the CS GPIO used in a prior call to [*bb_spi_open*]
+. .
+
+Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
+D*/
+
+/*F*/
+int bb_spi_xfer(
+ int pi,
+ unsigned CS,
+ char *txBuf,
+ char *rxBuf,
+ unsigned count);
+/*D
+This function executes a bit banged SPI transfer.
+
+. .
+ pi: >=0 (as returned by [*pigpio_start*]).
+ CS: 0-31 (as used in a prior call to [*bb_spi_open*])
+txBuf: pointer to buffer to hold data to be sent
+rxBuf: pointer to buffer to hold returned data
+count: size of data transfer
+. .
+
+Returns >= 0 if OK (the number of bytes read), otherwise
+PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
+
+...
+// gcc -Wall -pthread -o bb_spi_x_test bb_spi_x_test.c -lpigpiod_if2
+// ./bb_spi_x_test
+
+#include
+
+#include "pigpiod_if2.h"
+
+#define CE0 5
+#define CE1 6
+#define MISO 13
+#define MOSI 19
+#define SCLK 12
+
+int main(int argc, char *argv[])
+{
+ int i, pi, count, set_val, read_val;
+ unsigned char inBuf[3];
+ char cmd1[] = {0, 0};
+ char cmd2[] = {12, 0};
+ char cmd3[] = {1, 128, 0};
+
+ if ((pi = pigpio_start(0, 0)) < 0)
+ {
+ fprintf(stderr, "pigpio initialisation failed (%d).\n", pi);
+ return 1;
+ }
+
+ bb_spi_open(pi, CE0, MISO, MOSI, SCLK, 10000, 0); // MCP4251 DAC
+ bb_spi_open(pi, CE1, MISO, MOSI, SCLK, 20000, 3); // MCP3008 ADC
+
+ for (i=0; i<256; i++)
+ {
+ cmd1[1] = i;
+
+ count = bb_spi_xfer(pi, CE0, cmd1, (char *)inBuf, 2); // > DAC
+
+ if (count == 2)
+ {
+ count = bb_spi_xfer(pi, CE0, cmd2, (char *)inBuf, 2); // < DAC
+
+ if (count == 2)
+ {
+ set_val = inBuf[1];
+
+ count = bb_spi_xfer(pi, CE1, cmd3, (char *)inBuf, 3); // < ADC
+
+ if (count == 3)
+ {
+ read_val = ((inBuf[1]&3)<<8) | inBuf[2];
+ printf("%d %d\n", set_val, read_val);
+ }
+ }
+ }
+ }
+
+ bb_spi_close(pi, CE0);
+ bb_spi_close(pi, CE1);
+
+ pigpio_stop(pi);
+}
+...
+D*/
+
/*F*/
int spi_open(int pi, unsigned spi_channel, unsigned baud, unsigned spi_flags);
/*D
@@ -3195,6 +3356,9 @@ count::
The number of bytes to be transferred in a file, I2C, SPI, or serial
command.
+CS::
+The GPIO used for the slave select signal when bit banging SPI.
+
data_bits::1-32
The number of data bits in each character of serial data.
@@ -3339,6 +3503,9 @@ reported as PI_TIMEOUT. See [*set_watchdog*].
PI_TIMEOUT 2
. .
+MISO::
+The GPIO used for the MISO signal when bit banging SPI.
+
mode::
1. The operational mode of a GPIO, normally INPUT or OUTPUT.
@@ -3378,6 +3545,8 @@ PI_FILE_CREATE 8
PI_FILE_TRUNC 16
. .
+MOSI::
+The GPIO used for the MOSI signal when bit banging SPI.
numBytes::
The number of bytes used to store characters in a string. Depending
@@ -3489,6 +3658,9 @@ A pointer to a buffer to receive data.
SCL::
The user GPIO to use for the clock when bit banging I2C.
+SCLK::
+The GPIO used for the SCLK signal when bit banging SPI.
+
*script::
A pointer to the text of a script.
@@ -3533,7 +3705,7 @@ spi_channel::
A SPI channel, 0-2.
spi_flags::
-See [*spi_open*].
+See [*spi_open*] and [*bb_spi_open*].
steady:: 0-300000
diff --git a/pigs.1 b/pigs.1
index 28af561..f8fcb7a 100644
--- a/pigs.1
+++ b/pigs.1
@@ -484,6 +484,232 @@ ERROR: no permission to update one or more GPIO
.br
+.IP "\fBBSPIC cs\fP - Close bit bang SPI"
+.IP "" 4
+
+.br
+This function stops bit banging SPI on a set of GPIO
+opened with \fBBSPIO\fP.
+
+.br
+The set of GPIO is specifed by \fBcs\fP.
+
+.br
+Upon success nothing is returned. On error a negative status code
+will be returned.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs bspic 10
+.br
+
+.br
+$ pigs bspic 10
+.br
+-142
+.br
+ERROR: no bit bang SPI in progress on GPIO
+.br
+
+.EE
+
+.br
+
+.IP "\fBBSPIO cs miso mosi sclk b spf\fP - Open bit bang SPI"
+.IP "" 4
+
+.br
+This command starts bit banging SPI on a group of GPIO with slave
+select \fBcs\fP, MISO \fBmiso\fP, MOSI \fBmosi\fP, and clock \fBsclk\fP.
+
+.br
+Data will be transferred at baud \fBb\fP bits per second (which may
+be set in the range 50-250000).
+
+.br
+The flags \fBspf\fP may be used to modify the default behaviour of
+mode 0, active low chip select.
+
+.br
+The flags consists of the least significant 22 bits.
+
+.br
+
+.EX
+21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+.br
+ 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m
+.br
+
+.EE
+
+.br
+mm defines the SPI mode.
+
+.br
+
+.EX
+Mode POL PHA
+.br
+ 0 0 0
+.br
+ 1 0 1
+.br
+ 2 1 0
+.br
+ 3 1 1
+.br
+
+.EE
+
+.br
+p is 0 if CS is active low (default) and 1 for active high.
+
+.br
+T is 1 if the least significant bit is transmitted on MOSI first, the
+default (0) shifts the most significant bit out first.
+
+.br
+R is 1 if the least significant bit is received on MISO first, the
+default (0) receives the most significant bit first.
+
+.br
+The other bits in flags should be set to zero.
+
+.br
+Upon success 0 is returned. On error a negative status code
+will be returned.
+
+.br
+If more than one device is connected to the SPI bus (defined by
+SCLK, MOSI, and MISO) each must have its own CS.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs bspio 9 11 12 13 50000 0
+.br
+
+.br
+$ pigs bspio 10 11 12 13 50000 0
+.br
+
+.br
+$ pigs bspio 29 19 20 21 50000 0 # GPIO 29 not avaialble on this Pi
+.br
+-41
+.br
+ERROR: no permission to update GPIO
+.br
+
+.EE
+
+.br
+
+.IP "\fBBSPIX cs bvs\fP - SPI bit bang transfer"
+.IP "" 4
+
+.br
+This command writes bytes \fBbvs\fP to the bit bang SPI device
+associated with slave select \fBcs\fP. It returns the same
+number of bytes read from the device.
+
+.br
+Upon success the count of returned bytes followed by the bytes themselves
+is returned. On error a negative status code will be returned.
+
+.br
+
+\fBExample\fP
+.br
+
+.EX
+$ pigs bspio 5 13 19 12 10000 0 # MCP4251 DAC
+.br
+$ pigs bspio 6 13 19 12 20000 3 # MCP3008 ADC
+.br
+
+.br
+$ pigs bspix 5 0 16 # set DAC to 16
+.br
+2 255 255
+.br
+
+.br
+$ pigs bspix 5 12 0 # read back DAC
+.br
+2 254 16
+.br
+
+.br
+$ pigs bspix 6 1 128 0 # read ADC input 0
+.br
+3 0 3 184 # 952
+.br
+
+.br
+$ pigs bspix 5 0 240 # set DAC to 240
+.br
+2 255 255
+.br
+
+.br
+$ pigs bspix 5 12 0 # read back DAC
+.br
+2 254 240
+.br
+
+.br
+$ pigs bspix 6 1 128 0 # read ADC input 0
+.br
+3 0 0 63 # 63
+.br
+
+.br
+$ pigs bspix 5 0 128 # set DAC to 128
+.br
+2 255 255
+.br
+
+.br
+$ pigs bspix 5 12 0 # read back DAC
+.br
+2 254 128
+.br
+
+.br
+$ pigs bspix 6 1 128 0 # read ADC input 0
+.br
+3 0 1 255 # 511
+.br
+
+.br
+$ pigs bspic 5 # close SPI CS 5
+.br
+$ pigs bspic 6 # close SPI CS 6
+.br
+
+.br
+$ pigs bspic 5 # try to close SPI CS 5 again
+.br
+-142
+.br
+ERROR: no bit bang SPI in progress on GPIO
+.br
+
+.EE
+
+.br
+
+.br
+
.IP "\fBCF1 uvs\fP - Custom function 1"
.IP "" 4
@@ -906,7 +1132,7 @@ returned. On error a negative status code will be returned.
.br
.EX
-$ pigs fs 0 0 0 # Seek to start of file plus 200
+$ pigs fs 0 200 0 # Seek to start of file plus 200
.br
200
.br
@@ -4481,6 +4707,11 @@ The command expects a frequency.
.br
+.IP "\fBcs\fP - GPIO (0-31)" 0
+The GPIO used for the slave select signal when bit banging SPI.
+
+.br
+
.IP "\fBdb\fP - serial data bits (1-32)" 0
The command expects the number of data bits per serial character.
@@ -4620,6 +4851,11 @@ Value 0 1 4 5 6 7 3 2
.br
+.IP "\fBmiso\fP - GPIO (0-31)" 0
+The GPIO used for the MISO signal when bit banging SPI.
+
+.br
+
.IP "\fBmode\fP - file open mode" 0
One of the following values.
@@ -4648,6 +4884,11 @@ TRUNC 16 The file is truncated
.br
+.IP "\fBmosi\fP - GPIO (0-31)" 0
+The GPIO used for the MOSI signal when bit banging SPI.
+
+.br
+
.IP "\fBname\fP - the name of a script" 0
Only alphanumeric characters, '-' and '_' are allowed in the name.
@@ -4764,6 +5005,11 @@ when bit banging I2C.
.br
+.IP "\fBsclk\fP - user GPIO (0-31)" 0
+The GPIO used for the SCLK signal when bit banging SPI.
+
+.br
+
.IP "\fBsda\fP - user GPIO (0-31)" 0
The command expects the number of the GPIO to be used for SDA
when bit banging I2C.
@@ -4781,7 +5027,7 @@ The command expects a script id as returned by a call to \fBPROC\fP.
.br
.IP "\fBspf\fP - SPI flags (32 bits)" 0
-See \fBSPIO\fP.
+See \fBSPIO\fP and \fBBSPIO\fP.
.br
diff --git a/pigs.c b/pigs.c
index d4c91d0..3395f2f 100644
--- a/pigs.c
+++ b/pigs.c
@@ -26,7 +26,7 @@ For more information, please refer to
*/
/*
-This version is for pigpio version 55+
+This version is for pigpio version 56+
*/
#include
@@ -224,6 +224,7 @@ void get_extensions(int sock, int command, int res)
switch (command)
{
case PI_CMD_BI2CZ:
+ case PI_CMD_BSPIX:
case PI_CMD_CF2:
case PI_CMD_FL:
case PI_CMD_FR:
diff --git a/setup.py b/setup.py
index a10af60..d4a80f5 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
from distutils.core import setup
setup(name='pigpio',
- version='1.32',
+ version='1.33',
author='joan',
author_email='joan@abyz.co.uk',
maintainer='joan',
diff --git a/x_pigs b/x_pigs
index 38fe120..043bf3b 100755
--- a/x_pigs
+++ b/x_pigs
@@ -50,7 +50,7 @@ s=$(pigs bs2 0)
if [[ $s = "" ]]; then echo "BS2 ok"; else echo "BS2 fail ($s)"; fi
s=$(pigs h)
-if [[ ${#s} = 4966 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
+if [[ ${#s} = 5273 ]]; then echo "HELP ok"; else echo "HELP fail (${#s})"; fi
s=$(pigs hwver)
if [[ $s -ne 0 ]]; then echo "HWVER ok"; else echo "HWVER fail ($s)"; fi