mirror of https://github.com/joan2937/pigpio
V12
This commit is contained in:
parent
23e3b179ab
commit
8794220811
|
@ -5,9 +5,9 @@ SIZE = size
|
||||||
|
|
||||||
CFLAGS = -O3 -Wall
|
CFLAGS = -O3 -Wall
|
||||||
|
|
||||||
ALL = libpigpiod_if.a pigs pigpio.py setup.py
|
ALL = libpigpiod_if.a pigs
|
||||||
|
|
||||||
all: $(ALL)
|
all: $(ALL) pigpio.py setup.py
|
||||||
|
|
||||||
pigs: command.o pigs.o
|
pigs: command.o pigs.o
|
||||||
$(CC) -o pigs pigs.c command.c
|
$(CC) -o pigs pigs.c command.c
|
||||||
|
|
201
command.c
201
command.c
|
@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version is for pigpio version 11+
|
This version is for pigpio version 12+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -46,6 +46,7 @@ This version is for pigpio version 11+
|
||||||
3 %08X %08X
|
3 %08X %08X
|
||||||
4 %u %u
|
4 %u %u
|
||||||
5 HELP HELP
|
5 HELP HELP
|
||||||
|
6 %s <0 ERR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* vfyt
|
/* vfyt
|
||||||
|
@ -58,6 +59,7 @@ This version is for pigpio version 11+
|
||||||
8 MODES %d %c
|
8 MODES %d %c
|
||||||
9 PUD %d %c
|
9 PUD %d %c
|
||||||
10 PROG %s
|
10 PROG %s
|
||||||
|
11 WVAS %d %d %d %s
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cmdInfo_t cmdInfo[]=
|
cmdInfo_t cmdInfo[]=
|
||||||
|
@ -98,6 +100,9 @@ cmdInfo_t cmdInfo[]=
|
||||||
{PI_CMD_READ, "READ", 2, 2, 0},
|
{PI_CMD_READ, "READ", 2, 2, 0},
|
||||||
{PI_CMD_SERVO, "S", 3, 0, 0},
|
{PI_CMD_SERVO, "S", 3, 0, 0},
|
||||||
{PI_CMD_SERVO, "SERVO", 3, 0, 0},
|
{PI_CMD_SERVO, "SERVO", 3, 0, 0},
|
||||||
|
{PI_CMD_SLR, "SLR", 3, 6, 0},
|
||||||
|
{PI_CMD_SLRC, "SLRC", 2, 2, 0},
|
||||||
|
{PI_CMD_SLRO, "SLRO", 3, 2, 0},
|
||||||
{PI_CMD_WDOG, "WDOG", 3, 0, 0},
|
{PI_CMD_WDOG, "WDOG", 3, 0, 0},
|
||||||
{PI_CMD_WRITE, "W", 3, 0, 0},
|
{PI_CMD_WRITE, "W", 3, 0, 0},
|
||||||
{PI_CMD_WRITE, "WRITE", 3, 0, 0},
|
{PI_CMD_WRITE, "WRITE", 3, 0, 0},
|
||||||
|
@ -116,68 +121,72 @@ cmdInfo_t cmdInfo[]=
|
||||||
};
|
};
|
||||||
|
|
||||||
char * cmdUsage = "\
|
char * cmdUsage = "\
|
||||||
BC1 x clear gpios in bank 1\n\
|
BC1 x Clear gpios x in bank 1.\n\
|
||||||
BC2 x clear gpios in bank 2\n\
|
BC2 x Clear gpios x in bank 2.\n\
|
||||||
BR1 read gpios bank 1\n\
|
BR1 Read gpios bank 1.\n\
|
||||||
BR2 read gpios bank 2\n\
|
BR2 Read gpios bank 2.\n\
|
||||||
BS1 x set gpios in bank 1\n\
|
BS1 x Set gpios x in bank 1.\n\
|
||||||
BS2 x set gpios in bank 2\n\
|
BS2 x Set gpios x in bank 2.\n\
|
||||||
H displays command help\n\
|
H Displays command help.\n\
|
||||||
HELP displays command help\n\
|
HELP Displays command help.\n\
|
||||||
HWVER return hardware version\n\
|
HWVER Return hardware version.\n\
|
||||||
M g m set gpio mode\n\
|
M g m Set gpio g to mode m.\n\
|
||||||
MG g get gpio mode\n\
|
MG g Get gpio g mode.\n\
|
||||||
MODEG g get gpio mode\n\
|
MODEG g Get gpio g mode.\n\
|
||||||
MODES g m set gpio mode\n\
|
MODES g m Set gpio g to mode m.\n\
|
||||||
NB h x start notification\n\
|
NB h x Start notifications on handle h with x.\n\
|
||||||
NC h close notification\n\
|
NC h Close notification handle h.\n\
|
||||||
NO request notification handle\n\
|
NO Request notification handle.\n\
|
||||||
NP h pause notification\n\
|
NP h Pause notifications on handle h.\n\
|
||||||
P u d set PWM value for gpio\n\
|
P u d Set PWM value for user gpio u to d.\n\
|
||||||
PFG u get PWM frequency for gpio\n\
|
PFG u Get PWM frequency for user gpio u.\n\
|
||||||
PFS u d set PWM frequency for gpio\n\
|
PFS u d Set PWM frequency for user gpio u to d.\n\
|
||||||
PIGPV return pigpio version\n\
|
PIGPV Return pigpio version.\n\
|
||||||
PRG u get PWM range for gpio\n\
|
PRG u Get PWM range for user gpio u.\n\
|
||||||
PROC t validate and store script\n\
|
PROC t Store text t of script.\n\
|
||||||
PROCD s delete script\n\
|
PROCD s Delete script s.\n\
|
||||||
PROCR s run script\n\
|
PROCR s Run script s.\n\
|
||||||
PROCS s stop script\n\
|
PROCS s Stop script s.\n\
|
||||||
PRRG u get PWM real range for gpio\n\
|
PRRG u Get PWM real range for user gpio u.\n\
|
||||||
PRS u d set PWM range for gpio\n\
|
PRS u d Set PWM range for user gpio u to d.\n\
|
||||||
PUD g p set gpio pull up/down\n\
|
PUD g p Set gpio pull up/down for gpio g to p.\n\
|
||||||
PWM u d set PWM value for gpio\n\
|
PWM u d Set PWM value for user gpio u to d.\n\
|
||||||
R g read gpio\n\
|
R g Read gpio g.\n\
|
||||||
READ g read gpio\n\
|
READ g Read gpio g.\n\
|
||||||
S u d set servo value for gpio\n\
|
S u d Set servo value for user gpio u to d microseconds.\n\
|
||||||
SERVO u d set servo value for gpio\n\
|
SERVO u d Set servo value for user gpio u to d microseconds.\n\
|
||||||
T return current tick\n\
|
SLR u d Read up to d bytes of serial data from user gpio u.\n\
|
||||||
TICK return current tick\n\
|
SLRC u Close user gpio u for serial data.\n\
|
||||||
TRIG u pl l trigger level l for pl micros on gpio\n\
|
SLRO u b Open user gpio u for serial data at b baud.\n\
|
||||||
W g l write level to gpio\n\
|
T Return current tick.\n\
|
||||||
WDOG u d set watchdog on gpio\n\
|
TICK Return current tick.\n\
|
||||||
WRITE g l write level to gpio\n\
|
TRIG u pl L Trigger level L for pl micros on user gpio u.\n\
|
||||||
WVAS u b t wave add serial data\n\
|
W g L Write level L to gpio g.\n\
|
||||||
WVBSY check if wave busy\n\
|
WDOG u d Set watchdog of d milliseconds on user gpio u.\n\
|
||||||
WVCLR wave clear\n\
|
WRITE g L Write level L to gpio g.\n\
|
||||||
WVGO wave transmit\n\
|
WVAS u b o t Wave add serial data t to user gpio u at b baud.\n\
|
||||||
WVGOR wave transmit repeat\n\
|
WVBSY Check if wave busy.\n\
|
||||||
WVHLT wave stop\n\
|
WVCLR Wave clear.\n\
|
||||||
WVSC ws wave get cbs stats\n\
|
WVGO Wave transmit.\n\
|
||||||
WVSM ws wave get micros stats\n\
|
WVGOR Wave transmit repeatedly.\n\
|
||||||
WVSP ws wave get pulses stats\n\
|
WVHLT Wave stop.\n\
|
||||||
\n\
|
WVSC ws Wave get DMA control block stats.\n\
|
||||||
b = baud rate\n\
|
WVSM ws Wave get micros stats.\n\
|
||||||
d = decimal value\n\
|
WVSP ws Wave get pulses stats.\n\
|
||||||
g = gpio (0-53)\n\
|
.\n\
|
||||||
h = handle (0-31)\n\
|
b = baud rate.\n\
|
||||||
l = level (0-1)\n\
|
d = decimal value.\n\
|
||||||
m = mode (RW540123)\n\
|
g = gpio (0-53).\n\
|
||||||
p = pud (ODU)\n\
|
h = handle (0-31).\n\
|
||||||
pl = pulse length (0-100)\n\
|
L = level (0-1).\n\
|
||||||
s = script id\n\
|
m = mode (RW540123).\n\
|
||||||
t = text\n\
|
o = offset (0-).\n\
|
||||||
u = user gpio (0-31)\n\
|
p = pud (ODU).\n\
|
||||||
x = hex value\n\
|
pl = pulse length (0-100).\n\
|
||||||
|
s = script id.\n\
|
||||||
|
t = text.\n\
|
||||||
|
u = user gpio (0-31).\n\
|
||||||
|
x = hex value.\n\
|
||||||
";
|
";
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -237,6 +246,8 @@ static errInfo_t errInfo[]=
|
||||||
{PI_BAD_SCRIPT , "invalid script"},
|
{PI_BAD_SCRIPT , "invalid script"},
|
||||||
{PI_BAD_SCRIPT_ID , "unknown script id"},
|
{PI_BAD_SCRIPT_ID , "unknown script id"},
|
||||||
{PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"},
|
{PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"},
|
||||||
|
{PI_GPIO_IN_USE , "gpio already in use"},
|
||||||
|
{PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static char * fmtMdeStr="RW540123";
|
static char * fmtMdeStr="RW540123";
|
||||||
|
@ -256,7 +267,7 @@ static int cmdMatch(char * str)
|
||||||
int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext)
|
int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext)
|
||||||
{
|
{
|
||||||
char str[8];
|
char str[8];
|
||||||
int f, valid, idx, val;
|
int f, valid, idx, val, p;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
char c, t;
|
char c, t;
|
||||||
|
|
||||||
|
@ -276,21 +287,21 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
|
||||||
|
|
||||||
switch (cmdInfo[idx].vt)
|
switch (cmdInfo[idx].vt)
|
||||||
{
|
{
|
||||||
case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO WVGOR
|
case 1: /* BR1 BR2 HWVER NO PIGPV TICK WVBSY WVCLR WVGO
|
||||||
WVHLT
|
WVGOR WVHLT
|
||||||
*/
|
*/
|
||||||
f = sscanf(buf, " %7s %c", str, &t);
|
f = sscanf(buf, " %7s %c", str, &t);
|
||||||
if (f == 1) valid = 1;
|
if (f == 1) valid = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG READ
|
case 2: /* MODEG NC NP PFG PRG PROCD PROCR PROCS PRRG
|
||||||
WVSC WVSM WVSP
|
SLRC READ WVSC WVSM WVSP
|
||||||
*/
|
*/
|
||||||
f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t);
|
f = sscanf(buf, " %7s %d %c", str, &cmd->p1, &t);
|
||||||
if (f == 2) valid = 1;
|
if (f == 2) valid = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: /* PFS PRS PWM SERVO WDOG WRITE
|
case 3: /* PFS PRS PWM SERVO SLR SLRO WDOG WRITE
|
||||||
*/
|
*/
|
||||||
f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t);
|
f = sscanf(buf, " %7s %d %d %c", str, &cmd->p1, &cmd->p2, &t);
|
||||||
if (f == 3) valid = 1;
|
if (f == 3) valid = 1;
|
||||||
|
@ -308,7 +319,7 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
|
||||||
str, &cmd->p1, &cmd->p2, &ext[0].data, &t);
|
str, &cmd->p1, &cmd->p2, &ext[0].data, &t);
|
||||||
if (f == 4)
|
if (f == 4)
|
||||||
{
|
{
|
||||||
ext[0].n = sizeof(unsigned);
|
ext[0].size = sizeof(unsigned);
|
||||||
ext[0].ptr = &ext[0].data;
|
ext[0].ptr = &ext[0].data;
|
||||||
valid = 1;
|
valid = 1;
|
||||||
}
|
}
|
||||||
|
@ -319,7 +330,7 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
|
||||||
valid = 1;
|
valid = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: /* BC1 BC2 BS1 BS2
|
case 7: /* BC1 BC2 BS1 BS2
|
||||||
*/
|
*/
|
||||||
f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t);
|
f = sscanf(buf, " %7s %x %c", str, &cmd->p1, &t);
|
||||||
if (f == 2) valid = 1;
|
if (f == 2) valid = 1;
|
||||||
|
@ -359,38 +370,56 @@ int cmdParse(char *buf, cmdCmd_t *cmd, int argc, char *argv[], gpioExtent_t *ext
|
||||||
|
|
||||||
case 10: /* PROC
|
case 10: /* PROC
|
||||||
*/
|
*/
|
||||||
if (argc == 3)
|
if ((argc == 0) || (argc == 3))
|
||||||
{
|
{
|
||||||
cmd->p1 = strlen(argv[2]);
|
if (argc == 3)
|
||||||
ext[0].n = cmd->p1;
|
{
|
||||||
ext[0].ptr = argv[2];
|
cmd->p1 = strlen(argv[2]);
|
||||||
|
ext[0].ptr = argv[2];
|
||||||
|
}
|
||||||
|
else /* pipe i/f */
|
||||||
|
{
|
||||||
|
sscanf(buf, "%*s %n", &p);
|
||||||
|
cmd->p1 = strlen(buf+p);
|
||||||
|
ext[0].ptr = buf+p;
|
||||||
|
}
|
||||||
|
ext[0].size = cmd->p1;
|
||||||
valid = 1;
|
valid = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11: /* WVAS
|
case 11: /* WVAS
|
||||||
*/
|
*/
|
||||||
if (argc == 6)
|
if ((argc == 0) || (argc == 6))
|
||||||
{
|
{
|
||||||
f = sscanf(buf, " %7s %d %d %d ",
|
f = sscanf(buf, " %*s %d %d %d %n",
|
||||||
str, &cmd->p1, &ext[0].data, &ext[1].data);
|
&cmd->p1, &ext[0].data, &ext[1].data, &p);
|
||||||
if (f == 4)
|
if (f == 3)
|
||||||
{
|
{
|
||||||
ext[0].n = sizeof(unsigned);
|
ext[0].size = sizeof(unsigned);
|
||||||
ext[0].ptr = &ext[0].data;
|
ext[0].ptr = &ext[0].data;
|
||||||
ext[1].n = sizeof(unsigned);
|
ext[1].size = sizeof(unsigned);
|
||||||
ext[1].ptr = &ext[1].data;
|
ext[1].ptr = &ext[1].data;
|
||||||
cmd->p2 = strlen(argv[5]);
|
|
||||||
ext[2].n = cmd->p2;
|
if (argc) /* pigs */
|
||||||
ext[2].ptr = argv[5];
|
{
|
||||||
|
cmd->p2 = strlen(argv[5]);
|
||||||
|
ext[2].ptr = argv[5];
|
||||||
|
}
|
||||||
|
else /* pipe i/f */
|
||||||
|
{
|
||||||
|
cmd->p2 = strlen(buf+p);
|
||||||
|
ext[2].ptr = buf+p;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext[2].size = cmd->p2;
|
||||||
valid = 1;
|
valid = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid) return idx;
|
if (valid) return idx; else return -1;
|
||||||
else return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char * cmdErrStr(int error)
|
char * cmdErrStr(int error)
|
||||||
|
|
304
pigpio.c
304
pigpio.c
|
@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
For more information, please refer to <http://unlicense.org/>
|
For more information, please refer to <http://unlicense.org/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* pigpio version 11 */
|
/* pigpio version 12 */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -557,6 +557,9 @@ bit 0 READ_LAST_NOT_SET_ERROR
|
||||||
|
|
||||||
#define MAX_EMITS (PIPE_BUF / sizeof(gpioReport_t))
|
#define MAX_EMITS (PIPE_BUF / sizeof(gpioReport_t))
|
||||||
|
|
||||||
|
#define SRX_BUF_SIZE 8192
|
||||||
|
#define CMD_BUF_SIZE 2048
|
||||||
|
|
||||||
/* --------------------------------------------------------------- */
|
/* --------------------------------------------------------------- */
|
||||||
|
|
||||||
typedef void (*callbk_t) ();
|
typedef void (*callbk_t) ();
|
||||||
|
@ -701,16 +704,21 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
gpioRx_t * rxp;
|
int gpio;
|
||||||
uint32_t baud;
|
char * buf;
|
||||||
uint32_t fullBit;
|
uint32_t bufSize;
|
||||||
uint32_t halfBit;
|
int readPos;
|
||||||
uint32_t startBitTick;
|
int writePos;
|
||||||
uint32_t nextBitDiff;
|
uint32_t baud;
|
||||||
int bit;
|
uint32_t fullBit;
|
||||||
int byte;
|
uint32_t halfBit;
|
||||||
int level;
|
int timeout;
|
||||||
int mode;
|
uint32_t startBitTick;
|
||||||
|
uint32_t nextBitDiff;
|
||||||
|
int bit;
|
||||||
|
int byte;
|
||||||
|
int level;
|
||||||
|
int mode;
|
||||||
} wfRx_t;
|
} wfRx_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -757,7 +765,7 @@ static wfStats_t wfStats=
|
||||||
0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE)
|
0, 0, (PAGES_PER_BLOCK * CBS_PER_OPAGE)
|
||||||
};
|
};
|
||||||
|
|
||||||
static wfRx_t wfRx[PI_MAX_USER_GPIO+1];
|
static volatile wfRx_t wfRx[PI_MAX_USER_GPIO+1];
|
||||||
|
|
||||||
static volatile uint32_t alertBits = 0;
|
static volatile uint32_t alertBits = 0;
|
||||||
static volatile uint32_t monitorBits = 0;
|
static volatile uint32_t monitorBits = 0;
|
||||||
|
@ -977,7 +985,8 @@ static uint32_t myGetTick(int pos)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
|
static void myDoCommand
|
||||||
|
(cmdCmd_t *cmd, gpioExtent_t *iExt, gpioExtent_t *oExt)
|
||||||
{
|
{
|
||||||
int p1, p2, res, i;
|
int p1, p2, res, i;
|
||||||
uint32_t mask, tmp;
|
uint32_t mask, tmp;
|
||||||
|
@ -1090,7 +1099,7 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
|
||||||
case PI_CMD_PRG: res = gpioGetPWMrange(p1); break;
|
case PI_CMD_PRG: res = gpioGetPWMrange(p1); break;
|
||||||
|
|
||||||
case PI_CMD_PROC:
|
case PI_CMD_PROC:
|
||||||
res = gpioStoreScript(ext[0].ptr);
|
res = gpioStoreScript(iExt[0].ptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_CMD_PROCD: res = gpioDeleteScript(p1); break;
|
case PI_CMD_PROCD: res = gpioDeleteScript(p1); break;
|
||||||
|
@ -1132,6 +1141,36 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
|
||||||
|
|
||||||
case PI_CMD_READ: res = gpioRead(p1); break;
|
case PI_CMD_READ: res = gpioRead(p1); break;
|
||||||
|
|
||||||
|
case PI_CMD_SERVO:
|
||||||
|
if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
|
||||||
|
res = PI_NOT_PERMITTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PI_CMD_SLRO: res = gpioSerialReadOpen(p1, p2); break;
|
||||||
|
|
||||||
|
case PI_CMD_SLR:
|
||||||
|
if (p2 < oExt[0].size) oExt[0].size = p2;
|
||||||
|
res = gpioSerialRead(p1, oExt[0].ptr, oExt[0].size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PI_CMD_SLRC: res = gpioSerialReadClose(p1); break;
|
||||||
|
|
||||||
|
case PI_CMD_TICK: res = gpioTick(); break;
|
||||||
|
|
||||||
|
case PI_CMD_TRIG:
|
||||||
|
if (gpioMask & (uint64_t)(1<<p1))
|
||||||
|
res = gpioTrigger(p1, p2, *(int *) (iExt[0].ptr));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PERM_ERROR("gpioTrigger: gpio %d, no permission to update", p1);
|
||||||
|
res = PI_NOT_PERMITTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PI_CMD_WDOG: res = gpioSetWatchdog(p1, p2); break;
|
case PI_CMD_WDOG: res = gpioSetWatchdog(p1, p2); break;
|
||||||
|
|
||||||
case PI_CMD_WRITE:
|
case PI_CMD_WRITE:
|
||||||
|
@ -1143,33 +1182,12 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PI_CMD_SERVO:
|
|
||||||
if (gpioMask & (uint64_t)(1<<p1)) res = gpioServo(p1, p2);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PERM_ERROR("gpioServo: gpio %d, no permission to update", p1);
|
|
||||||
res = PI_NOT_PERMITTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PI_CMD_TICK: res = gpioTick(); break;
|
|
||||||
|
|
||||||
case PI_CMD_TRIG:
|
|
||||||
if (gpioMask & (uint64_t)(1<<p1))
|
|
||||||
res = gpioTrigger(p1, p2, *(int *) (ext[0].ptr));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PERM_ERROR("gpioTrigger: gpio %d, no permission to update", p1);
|
|
||||||
res = PI_NOT_PERMITTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PI_CMD_WVAG:
|
case PI_CMD_WVAG:
|
||||||
|
|
||||||
/* need to mask off any non permitted gpios */
|
/* need to mask off any non permitted gpios */
|
||||||
|
|
||||||
mask = gpioMask;
|
mask = gpioMask;
|
||||||
pulse = ext[0].ptr;
|
pulse = iExt[0].ptr;
|
||||||
masked = 0;
|
masked = 0;
|
||||||
|
|
||||||
for (i=0; i<p1; i++)
|
for (i=0; i<p1; i++)
|
||||||
|
@ -1200,10 +1218,10 @@ static void myDoCommand(cmdCmd_t *cmd, gpioExtent_t *ext)
|
||||||
if (gpioMask & (uint64_t)(1<<p1))
|
if (gpioMask & (uint64_t)(1<<p1))
|
||||||
res = gpioWaveAddSerial
|
res = gpioWaveAddSerial
|
||||||
(p1,
|
(p1,
|
||||||
*(int *)(ext[0].ptr),
|
*(int *)(iExt[0].ptr),
|
||||||
*(int *)(ext[1].ptr),
|
*(int *)(iExt[1].ptr),
|
||||||
p2,
|
p2,
|
||||||
ext[2].ptr);
|
iExt[2].ptr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PERM_ERROR
|
PERM_ERROR
|
||||||
|
@ -1655,9 +1673,10 @@ static int wave2Cbs(unsigned mode)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void waveRxSerial(wfRx_t * s, int level, uint32_t tick)
|
static void waveRxSerial(volatile wfRx_t *s, int level, uint32_t tick)
|
||||||
{
|
{
|
||||||
int diffTicks;
|
int diffTicks;
|
||||||
|
int newWritePos;
|
||||||
|
|
||||||
if (s->bit >= 0)
|
if (s->bit >= 0)
|
||||||
{
|
{
|
||||||
|
@ -1680,9 +1699,15 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick)
|
||||||
|
|
||||||
if (s->bit == 9)
|
if (s->bit == 9)
|
||||||
{
|
{
|
||||||
s->rxp->buf[s->rxp->writePos] = s->byte;
|
s->buf[s->writePos] = s->byte;
|
||||||
|
|
||||||
if (++s->rxp->writePos >= s->rxp->bufSize) s->rxp->writePos = 0;
|
/* don't let writePos catch readPos */
|
||||||
|
|
||||||
|
newWritePos = s->writePos;
|
||||||
|
|
||||||
|
if (++newWritePos >= s->bufSize) newWritePos = 0;
|
||||||
|
|
||||||
|
if (newWritePos != s->readPos) s->writePos = newWritePos;
|
||||||
|
|
||||||
if (level == 0) /* true transition high->low, not a timeout */
|
if (level == 0) /* true transition high->low, not a timeout */
|
||||||
{
|
{
|
||||||
|
@ -1690,7 +1715,11 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick)
|
||||||
s->startBitTick = tick;
|
s->startBitTick = tick;
|
||||||
s->nextBitDiff = s->halfBit;
|
s->nextBitDiff = s->halfBit;
|
||||||
}
|
}
|
||||||
else s->bit = -1;
|
else
|
||||||
|
{
|
||||||
|
s->bit = -1;
|
||||||
|
gpioSetWatchdog(s->gpio, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1699,6 +1728,7 @@ static void waveRxSerial(wfRx_t * s, int level, uint32_t tick)
|
||||||
|
|
||||||
if (level == 0)
|
if (level == 0)
|
||||||
{
|
{
|
||||||
|
gpioSetWatchdog(s->gpio, s->timeout);
|
||||||
s->level = 0;
|
s->level = 0;
|
||||||
s->bit = 0;
|
s->bit = 0;
|
||||||
s->startBitTick = tick;
|
s->startBitTick = tick;
|
||||||
|
@ -2621,10 +2651,12 @@ static void * pthTimerTick(void *x)
|
||||||
|
|
||||||
static void * pthFifoThread(void *x)
|
static void * pthFifoThread(void *x)
|
||||||
{
|
{
|
||||||
char inBuf[256];
|
char buf[CMD_BUF_SIZE];
|
||||||
int idx, flags;
|
int idx, flags, len;
|
||||||
cmdCmd_t cmd;
|
cmdCmd_t cmd;
|
||||||
gpioExtent_t ext[3];
|
gpioExtent_t iExt[3];
|
||||||
|
gpioExtent_t oExt[3];
|
||||||
|
char *p;
|
||||||
|
|
||||||
myCreatePipe(PI_INPFIFO, 0662);
|
myCreatePipe(PI_INPFIFO, 0662);
|
||||||
|
|
||||||
|
@ -2643,12 +2675,23 @@ static void * pthFifoThread(void *x)
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (fgets(inBuf, sizeof(inBuf), inpFifo) == NULL)
|
if (fgets(buf, sizeof(buf), inpFifo) == NULL)
|
||||||
SOFT_ERROR((void*)PI_INIT_FAILED, "fifo fgets failed (%m)");
|
SOFT_ERROR((void*)PI_INIT_FAILED, "fifo fgets failed (%m)");
|
||||||
|
|
||||||
if ((idx=cmdParse(inBuf, &cmd, 0, NULL, ext)) >= 0)
|
len = strlen(buf);
|
||||||
|
|
||||||
|
if (len)
|
||||||
{
|
{
|
||||||
myDoCommand(&cmd, NULL);
|
--len;
|
||||||
|
buf[len] = 0; /* replace terminating */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((idx=cmdParse(buf, &cmd, 0, NULL, iExt)) >= 0)
|
||||||
|
{
|
||||||
|
oExt[0].ptr = buf;
|
||||||
|
oExt[0].size = CMD_BUF_SIZE-1;
|
||||||
|
|
||||||
|
myDoCommand(&cmd, iExt, oExt);
|
||||||
|
|
||||||
switch (cmdInfo[idx].rv)
|
switch (cmdInfo[idx].rv)
|
||||||
{
|
{
|
||||||
|
@ -2675,6 +2718,17 @@ static void * pthFifoThread(void *x)
|
||||||
case 5:
|
case 5:
|
||||||
fprintf(outFifo, cmdUsage);
|
fprintf(outFifo, cmdUsage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
if (cmd.res < 0) fprintf(outFifo, "%d\n", cmd.res);
|
||||||
|
else if (cmd.res > 0)
|
||||||
|
{
|
||||||
|
p = oExt[0].ptr;
|
||||||
|
p[cmd.res] = 0;
|
||||||
|
fprintf(outFifo, "%s", (char *)oExt[0].ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2694,8 +2748,13 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
cmdCmd_t cmd;
|
cmdCmd_t cmd;
|
||||||
unsigned bytes;
|
unsigned bytes;
|
||||||
char *memPtr;
|
char *memPtr;
|
||||||
gpioExtent_t ext[3];
|
gpioExtent_t iExt[3];
|
||||||
|
gpioExtent_t oExt[3];
|
||||||
unsigned tmp;
|
unsigned tmp;
|
||||||
|
char buf[CMD_BUF_SIZE];
|
||||||
|
|
||||||
|
oExt[0].size = CMD_BUF_SIZE-1;
|
||||||
|
oExt[0].ptr = buf;
|
||||||
|
|
||||||
free(fdC);
|
free(fdC);
|
||||||
|
|
||||||
|
@ -2719,13 +2778,14 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
bytes = cmd.p1 * sizeof(gpioPulse_t);
|
bytes = cmd.p1 * sizeof(gpioPulse_t);
|
||||||
|
|
||||||
memPtr = malloc(bytes);
|
memPtr = malloc(bytes);
|
||||||
|
|
||||||
if (memPtr)
|
if (memPtr)
|
||||||
{
|
{
|
||||||
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
|
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
|
||||||
{
|
{
|
||||||
ext[0].n = bytes;
|
iExt[0].size = bytes;
|
||||||
ext[0].ptr = memPtr;
|
iExt[0].ptr = memPtr;
|
||||||
myDoCommand(&cmd, ext);
|
myDoCommand(&cmd, iExt, oExt);
|
||||||
free(memPtr);
|
free(memPtr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2756,14 +2816,14 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
{
|
{
|
||||||
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
|
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
|
||||||
{
|
{
|
||||||
ext[0].n = sizeof(unsigned);
|
iExt[0].size = sizeof(unsigned);
|
||||||
ext[0].ptr = memPtr;
|
iExt[0].ptr = memPtr;
|
||||||
ext[1].n = sizeof(unsigned);
|
iExt[1].size = sizeof(unsigned);
|
||||||
ext[1].ptr = memPtr + sizeof(unsigned);
|
iExt[1].ptr = memPtr + sizeof(unsigned);
|
||||||
ext[2].n = cmd.p2;
|
iExt[2].size = cmd.p2;
|
||||||
ext[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned);
|
iExt[2].ptr = memPtr + sizeof(unsigned) + sizeof(unsigned);
|
||||||
memPtr[bytes] = 0; /* may be duplicate terminator */
|
memPtr[bytes] = 0; /* may be duplicate terminator */
|
||||||
myDoCommand(&cmd, ext);
|
myDoCommand(&cmd, iExt, oExt);
|
||||||
free(memPtr);
|
free(memPtr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2787,24 +2847,24 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
bytes = cmd.p1;
|
bytes = cmd.p1;
|
||||||
|
|
||||||
memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
|
memPtr = malloc(bytes+1); /* add 1 for a nul terminator */
|
||||||
|
|
||||||
if (memPtr)
|
if (memPtr)
|
||||||
{
|
{
|
||||||
if (recv(sock, memPtr, bytes, MSG_WAITALL) == bytes)
|
if (bytes) /* script appended */
|
||||||
{
|
{
|
||||||
ext[0].n = bytes;
|
if (recv(sock, memPtr, bytes, MSG_WAITALL) != bytes)
|
||||||
ext[0].ptr = memPtr;
|
{
|
||||||
memPtr[bytes] = 0; /* may be duplicate terminator */
|
free(memPtr);
|
||||||
myDoCommand(&cmd, ext);
|
break;
|
||||||
free(memPtr);
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
free(memPtr);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
iExt[0].size = bytes;
|
||||||
|
iExt[0].ptr = memPtr;
|
||||||
|
memPtr[bytes] = 0; /* may be duplicate terminator */
|
||||||
|
myDoCommand(&cmd, iExt, oExt);
|
||||||
|
free(memPtr);
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2817,8 +2877,8 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
## extension ##
|
## extension ##
|
||||||
unsigned level
|
unsigned level
|
||||||
*/
|
*/
|
||||||
ext[0].n = 4;
|
iExt[0].size = 4;
|
||||||
ext[0].ptr = &tmp;
|
iExt[0].ptr = &tmp;
|
||||||
|
|
||||||
if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) !=
|
if (recv(sock, &tmp, sizeof(unsigned), MSG_WAITALL) !=
|
||||||
sizeof(unsigned))
|
sizeof(unsigned))
|
||||||
|
@ -2831,11 +2891,26 @@ static void *pthSocketThreadHandler(void *fdC)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
myDoCommand(&cmd, ext);
|
myDoCommand(&cmd, iExt, oExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
write(sock, &cmd, sizeof(cmdCmd_t));
|
write(sock, &cmd, sizeof(cmdCmd_t));
|
||||||
|
|
||||||
|
switch (cmd.cmd)
|
||||||
|
{
|
||||||
|
case PI_CMD_SLR: /* extension */
|
||||||
|
|
||||||
|
if (cmd.res > 0)
|
||||||
|
{
|
||||||
|
write(sock, oExt[0].ptr, cmd.res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
|
@ -4347,6 +4422,9 @@ int gpioWaveAddSerial(unsigned gpio,
|
||||||
DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s",
|
DBG(DBG_USER, "gpio=%d baud=%d offset=%d numChar=%d str=%s",
|
||||||
gpio, baud, offset, numChar, str);
|
gpio, baud, offset, numChar, str);
|
||||||
|
|
||||||
|
DBG(DBG_USER, "l=%d s=%X e=%X",
|
||||||
|
strlen(str), str[0], str[strlen(str)-1]);
|
||||||
|
|
||||||
CHECK_INITED;
|
CHECK_INITED;
|
||||||
|
|
||||||
if (gpio > PI_MAX_USER_GPIO)
|
if (gpio > PI_MAX_USER_GPIO)
|
||||||
|
@ -4439,13 +4517,11 @@ int gpioWaveAddSerial(unsigned gpio,
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
int gpioWaveSerialReadStart(unsigned gpio,
|
int gpioSerialReadOpen(unsigned gpio, unsigned baud)
|
||||||
unsigned baud,
|
|
||||||
gpioRx_t *rxp)
|
|
||||||
{
|
{
|
||||||
int bitTime, timeoutMs;
|
int bitTime, timeout;
|
||||||
|
|
||||||
DBG(DBG_USER, "gpio=%d baud=%d rxp*=%08X", gpio, baud, (uint32_t)rxp);
|
DBG(DBG_USER, "gpio=%d baud=%d", gpio, baud);
|
||||||
|
|
||||||
CHECK_INITED;
|
CHECK_INITED;
|
||||||
|
|
||||||
|
@ -4456,37 +4532,75 @@ int gpioWaveSerialReadStart(unsigned gpio,
|
||||||
SOFT_ERROR(PI_BAD_WAVE_BAUD,
|
SOFT_ERROR(PI_BAD_WAVE_BAUD,
|
||||||
"gpio %d, bad baud rate (%d)", gpio, baud);
|
"gpio %d, bad baud rate (%d)", gpio, baud);
|
||||||
|
|
||||||
if (rxp == NULL)
|
if (wfRx[gpio].mode != PI_WFRX_NONE)
|
||||||
SOFT_ERROR(PI_BAD_SERIAL_STRUC, "Null structure pointer");
|
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used", gpio);
|
||||||
|
|
||||||
if (rxp->buf == NULL)
|
|
||||||
SOFT_ERROR(PI_BAD_SERIAL_BUF, "Null buffer pointer");
|
|
||||||
|
|
||||||
bitTime = MILLION / baud;
|
bitTime = MILLION / baud;
|
||||||
|
|
||||||
timeoutMs = ((12 * bitTime)+1000)/1000;
|
timeout = (10 * bitTime)/1000;
|
||||||
|
if (timeout < 1) timeout = 1;
|
||||||
|
|
||||||
|
wfRx[gpio].gpio = gpio;
|
||||||
|
wfRx[gpio].buf = malloc(SRX_BUF_SIZE);
|
||||||
|
wfRx[gpio].bufSize = SRX_BUF_SIZE;
|
||||||
wfRx[gpio].mode = PI_WFRX_SERIAL;
|
wfRx[gpio].mode = PI_WFRX_SERIAL;
|
||||||
wfRx[gpio].baud = baud;
|
wfRx[gpio].baud = baud;
|
||||||
wfRx[gpio].rxp = rxp;
|
wfRx[gpio].timeout = timeout;
|
||||||
wfRx[gpio].baud = baud;
|
|
||||||
wfRx[gpio].fullBit = bitTime;
|
wfRx[gpio].fullBit = bitTime;
|
||||||
wfRx[gpio].halfBit = bitTime/2;
|
wfRx[gpio].halfBit = bitTime/2;
|
||||||
wfRx[gpio].rxp->readPos = 0;
|
wfRx[gpio].readPos = 0;
|
||||||
wfRx[gpio].rxp->writePos = 0;
|
wfRx[gpio].writePos = 0;
|
||||||
wfRx[gpio].bit = -1;
|
wfRx[gpio].bit = -1;
|
||||||
|
|
||||||
gpioSetWatchdog(gpio, timeoutMs); /* get a nudge if no change */
|
|
||||||
|
|
||||||
gpioSetAlertFunc(gpio, waveRxBit);
|
gpioSetAlertFunc(gpio, waveRxBit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int gpioSerialRead(unsigned gpio, void *buf, size_t bufSize)
|
||||||
|
{
|
||||||
|
unsigned bytes=0, wpos;
|
||||||
|
volatile wfRx_t *p;
|
||||||
|
|
||||||
|
DBG(DBG_USER, "gpio=%d buf=%08X bufSize=%d", gpio, (int)buf, bufSize);
|
||||||
|
|
||||||
|
CHECK_INITED;
|
||||||
|
|
||||||
|
if (gpio > PI_MAX_USER_GPIO)
|
||||||
|
SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", gpio);
|
||||||
|
|
||||||
|
if (bufSize == 0)
|
||||||
|
SOFT_ERROR(PI_BAD_SERIAL_COUNT, "buffer size can't be zero");
|
||||||
|
|
||||||
|
if (wfRx[gpio].mode != PI_WFRX_SERIAL)
|
||||||
|
SOFT_ERROR(PI_NOT_SERIAL_GPIO, "no serial read on gpio (%d)", gpio);
|
||||||
|
|
||||||
|
p = &wfRx[gpio];
|
||||||
|
|
||||||
|
if (p->readPos != p->writePos)
|
||||||
|
{
|
||||||
|
wpos = p->writePos;
|
||||||
|
|
||||||
|
if (wpos > p->readPos) bytes = wpos - p->readPos;
|
||||||
|
else bytes = p->bufSize - p->readPos;
|
||||||
|
|
||||||
|
if (bytes > bufSize) bytes = bufSize;
|
||||||
|
|
||||||
|
memcpy(buf, p->buf+p->readPos, bytes);
|
||||||
|
|
||||||
|
p->readPos += bytes;
|
||||||
|
|
||||||
|
if (p->readPos >= p->bufSize) p->readPos = 0;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
int gpioWaveSerialReadStop(unsigned gpio)
|
int gpioSerialReadClose(unsigned gpio)
|
||||||
{
|
{
|
||||||
DBG(DBG_USER, "gpio=%d", gpio);
|
DBG(DBG_USER, "gpio=%d", gpio);
|
||||||
|
|
||||||
|
@ -4505,6 +4619,8 @@ int gpioWaveSerialReadStop(unsigned gpio)
|
||||||
|
|
||||||
case PI_WFRX_SERIAL:
|
case PI_WFRX_SERIAL:
|
||||||
|
|
||||||
|
free(wfRx[gpio].buf);
|
||||||
|
|
||||||
gpioSetWatchdog(gpio, 0); /* switch off timeouts */
|
gpioSetWatchdog(gpio, 0); /* switch off timeouts */
|
||||||
|
|
||||||
gpioSetAlertFunc(gpio, NULL); /* cancel alert */
|
gpioSetAlertFunc(gpio, NULL); /* cancel alert */
|
||||||
|
@ -5067,6 +5183,8 @@ void gpioStopThread(pthread_t *pth)
|
||||||
int gpioStoreScript(char *script)
|
int gpioStoreScript(char *script)
|
||||||
{
|
{
|
||||||
DBG(DBG_USER, "script=%s", script);
|
DBG(DBG_USER, "script=%s", script);
|
||||||
|
DBG(DBG_USER, "l=%d s=%X e=%X",
|
||||||
|
strlen(script), script[0], script[strlen(script)-1]);
|
||||||
|
|
||||||
CHECK_INITED;
|
CHECK_INITED;
|
||||||
|
|
||||||
|
|
102
pigpio.h
102
pigpio.h
|
@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version is for pigpio version 11
|
This version is for pigpio version 12
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PIGPIO_H
|
#ifndef PIGPIO_H
|
||||||
|
@ -86,7 +86,7 @@ This version is for pigpio version 11
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#define PIGPIO_VERSION 11
|
#define PIGPIO_VERSION 12
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -133,8 +133,9 @@ gpioWaveTxStart Transmits the waveform.
|
||||||
gpioWaveTxBusy Checks to see if the waveform has ended.
|
gpioWaveTxBusy Checks to see if the waveform has ended.
|
||||||
gpioWaveTxStop Aborts the current waveform.
|
gpioWaveTxStop Aborts the current waveform.
|
||||||
|
|
||||||
gpioWaveSerialReadStart Reads serial data from a user gpio.
|
gpioSerialReadOpen Opens a gpio for reading serial data.
|
||||||
gpioWaveSerialReadStop Stops reading serial data from a user gpio.
|
gpioSerialRead Reads serial data from a gpio.
|
||||||
|
gpioSerialReadClose Closes a gpio for reading serial data.
|
||||||
|
|
||||||
gpioWaveGetMicros Length in microseconds of the current waveform.
|
gpioWaveGetMicros Length in microseconds of the current waveform.
|
||||||
gpioWaveGetHighMicros Length of longest waveform so far.
|
gpioWaveGetHighMicros Length of longest waveform so far.
|
||||||
|
@ -226,7 +227,7 @@ typedef struct
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t size;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
int data;
|
int data;
|
||||||
} gpioExtent_t;
|
} gpioExtent_t;
|
||||||
|
@ -252,14 +253,6 @@ typedef struct
|
||||||
uint32_t usDelay;
|
uint32_t usDelay;
|
||||||
} gpioPulse_t;
|
} gpioPulse_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char * buf;
|
|
||||||
uint32_t bufSize;
|
|
||||||
int readPos;
|
|
||||||
int writePos;
|
|
||||||
} gpioRx_t;
|
|
||||||
|
|
||||||
typedef void (*gpioAlertFunc_t) (int gpio,
|
typedef void (*gpioAlertFunc_t) (int gpio,
|
||||||
int level,
|
int level,
|
||||||
uint32_t tick);
|
uint32_t tick);
|
||||||
|
@ -974,76 +967,38 @@ int gpioWaveTxStop(void);
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
int gpioWaveSerialReadStart(unsigned user_gpio,
|
int gpioSerialReadOpen(unsigned user_gpio, unsigned baud);
|
||||||
unsigned baud,
|
|
||||||
gpioRx_t * rxp);
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
/* This function starts the reception of serial data with the
|
/* This function opens a gpio for reading serial data.
|
||||||
specified baud rate on a gpio.
|
|
||||||
|
|
||||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
|
||||||
PI_BAD_SERIAL_STRUC, or PI_BAD_SERIAL_BUF.
|
or PI_GPIO_IN_USE.
|
||||||
|
|
||||||
NOTES:
|
The serial data is returned in a cyclic buffer and is read using
|
||||||
|
gpioSerialRead().
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char * buf;
|
|
||||||
uint32_t bufSize;
|
|
||||||
int readPos;
|
|
||||||
int writePos;
|
|
||||||
} gpioRx_t;
|
|
||||||
|
|
||||||
The serial data is returned in a cyclic buffer which MUST be allocated
|
|
||||||
by the caller. The caller specifies the location and size of the
|
|
||||||
buffer in buf and bufSize.
|
|
||||||
|
|
||||||
It is the caller's responsibility to read data from the cyclic buffer
|
It is the caller's responsibility to read data from the cyclic buffer
|
||||||
in a timely fashion. Data is available when readPos is not equal to
|
in a timely fashion.
|
||||||
writePos.
|
|
||||||
|
|
||||||
EXAMPLE:
|
|
||||||
|
|
||||||
#define BUFSIZE 1000
|
|
||||||
|
|
||||||
char buf[BUFSIZE];
|
|
||||||
int bytes, wpos;
|
|
||||||
FILE * outFile;
|
|
||||||
|
|
||||||
gpioRx_t rx;
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
rx.buf = buf;
|
|
||||||
rx.bufSize = sizeof(buf);
|
|
||||||
|
|
||||||
if (gpioWaveSerialReadStart(4, 38400, &rx) == 0)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
|
|
||||||
while (rx.readPos != rx.writePos)
|
|
||||||
{
|
|
||||||
wpos = rx.writePos;
|
|
||||||
|
|
||||||
if (wpos > rx.readPos) bytes = wpos - rx.readPos;
|
|
||||||
else bytes = rx.bufSize - rx.readPos;
|
|
||||||
|
|
||||||
fwrite(rx.buf+rx.readPos, 1, bytes, outFile);
|
|
||||||
|
|
||||||
rx.readPos += bytes;
|
|
||||||
|
|
||||||
if (rx.readPos >= rx.bufSize) rx.readPos = 0;
|
|
||||||
}
|
|
||||||
...
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
int gpioWaveSerialReadStop(unsigned user_gpio);
|
int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize);
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
/* This function stops reading serial data from a gpio.
|
/* This function copies up to bufSize bytes of data read from the
|
||||||
|
serial cyclic buffer to the buffer starting at buf.
|
||||||
|
|
||||||
|
Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
|
||||||
|
or PI_NOT_SERIAL_GPIO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
int gpioSerialReadClose(unsigned user_gpio);
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
/* This function closes a gpio for reading serial data.
|
||||||
|
|
||||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
|
||||||
*/
|
*/
|
||||||
|
@ -1901,6 +1856,9 @@ void gpioWaveDump(void);
|
||||||
#define PI_CMD_PROCD 39
|
#define PI_CMD_PROCD 39
|
||||||
#define PI_CMD_PROCR 40
|
#define PI_CMD_PROCR 40
|
||||||
#define PI_CMD_PROCS 41
|
#define PI_CMD_PROCS 41
|
||||||
|
#define PI_CMD_SLRO 42
|
||||||
|
#define PI_CMD_SLR 43
|
||||||
|
#define PI_CMD_SLRC 44
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following command only works on the socket interface.
|
The following command only works on the socket interface.
|
||||||
|
@ -1970,6 +1928,8 @@ after this command is issued.
|
||||||
#define PI_BAD_SCRIPT -47 /* invalid script */
|
#define PI_BAD_SCRIPT -47 /* invalid script */
|
||||||
#define PI_BAD_SCRIPT_ID -48 /* unknown script id */
|
#define PI_BAD_SCRIPT_ID -48 /* unknown script id */
|
||||||
#define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */
|
#define PI_BAD_SER_OFFSET -49 /* add serial data offset > 30 minutes */
|
||||||
|
#define PI_GPIO_IN_USE -50 /* gpio already in use */
|
||||||
|
#define PI_BAD_SERIAL_COUNT -51 /* must read at least a byte at a time */
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
57
pigpio.py
57
pigpio.py
|
@ -76,7 +76,7 @@ import threading
|
||||||
import os
|
import os
|
||||||
import atexit
|
import atexit
|
||||||
|
|
||||||
VERSION = "1.2"
|
VERSION = "1.3"
|
||||||
|
|
||||||
# gpio levels
|
# gpio levels
|
||||||
|
|
||||||
|
@ -157,6 +157,9 @@ _PI_CMD_PROC= 38
|
||||||
_PI_CMD_PROCD=39
|
_PI_CMD_PROCD=39
|
||||||
_PI_CMD_PROCR=40
|
_PI_CMD_PROCR=40
|
||||||
_PI_CMD_PROCS=41
|
_PI_CMD_PROCS=41
|
||||||
|
_PI_CMD_SLRO= 42
|
||||||
|
_PI_CMD_SLR= 43
|
||||||
|
_PI_CMD_SLRC= 44
|
||||||
|
|
||||||
|
|
||||||
_PI_CMD_NOIB= 99
|
_PI_CMD_NOIB= 99
|
||||||
|
@ -202,7 +205,7 @@ _PI_BAD_CFG_INTERNAL=-34
|
||||||
PI_BAD_WAVE_BAUD =-35
|
PI_BAD_WAVE_BAUD =-35
|
||||||
PI_TOO_MANY_PULSES =-36
|
PI_TOO_MANY_PULSES =-36
|
||||||
PI_TOO_MANY_CHARS =-37
|
PI_TOO_MANY_CHARS =-37
|
||||||
_PI_NOT_SERIAL_GPIO =-38
|
PI_NOT_SERIAL_GPIO =-38
|
||||||
_PI_BAD_SERIAL_STRUC=-39
|
_PI_BAD_SERIAL_STRUC=-39
|
||||||
_PI_BAD_SERIAL_BUF =-40
|
_PI_BAD_SERIAL_BUF =-40
|
||||||
PI_NOT_PERMITTED =-41
|
PI_NOT_PERMITTED =-41
|
||||||
|
@ -214,6 +217,7 @@ PI_BAD_PULSELEN =-46
|
||||||
PI_BAD_SCRIPT =-47
|
PI_BAD_SCRIPT =-47
|
||||||
PI_BAD_SCRIPT_ID =-48
|
PI_BAD_SCRIPT_ID =-48
|
||||||
PI_BAD_SER_OFFSET =-49
|
PI_BAD_SER_OFFSET =-49
|
||||||
|
PI_GPIO_IN_USE =-50
|
||||||
|
|
||||||
# pigpio error text
|
# pigpio error text
|
||||||
|
|
||||||
|
@ -252,10 +256,10 @@ _errors=[
|
||||||
[_PI_INITIALISED , "function called after gpioInitialise"],
|
[_PI_INITIALISED , "function called after gpioInitialise"],
|
||||||
[_PI_BAD_WAVE_MODE , "waveform mode not 0-1"],
|
[_PI_BAD_WAVE_MODE , "waveform mode not 0-1"],
|
||||||
[_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"],
|
[_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"],
|
||||||
[PI_BAD_WAVE_BAUD , "baud rate not 100-250000"],
|
[PI_BAD_WAVE_BAUD , "baud rate not 100-250000"],
|
||||||
[PI_TOO_MANY_PULSES , "waveform has too many pulses"],
|
[PI_TOO_MANY_PULSES , "waveform has too many pulses"],
|
||||||
[PI_TOO_MANY_CHARS , "waveform has too many chars"],
|
[PI_TOO_MANY_CHARS , "waveform has too many chars"],
|
||||||
[_PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"],
|
[PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"],
|
||||||
[PI_NOT_PERMITTED , "no permission to update gpio"],
|
[PI_NOT_PERMITTED , "no permission to update gpio"],
|
||||||
[PI_SOME_PERMITTED , "no permission to update one or more gpios"],
|
[PI_SOME_PERMITTED , "no permission to update one or more gpios"],
|
||||||
[PI_BAD_WVSC_COMMND , "bad WVSC subcommand"],
|
[PI_BAD_WVSC_COMMND , "bad WVSC subcommand"],
|
||||||
|
@ -265,6 +269,7 @@ _errors=[
|
||||||
[PI_BAD_SCRIPT , "invalid script"],
|
[PI_BAD_SCRIPT , "invalid script"],
|
||||||
[PI_BAD_SCRIPT_ID , "unknown script id"],
|
[PI_BAD_SCRIPT_ID , "unknown script id"],
|
||||||
[PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"],
|
[PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"],
|
||||||
|
[PI_GPIO_IN_USE , "gpio already in use"],
|
||||||
]
|
]
|
||||||
|
|
||||||
_control = None
|
_control = None
|
||||||
|
@ -1701,6 +1706,46 @@ def delete_script(script_id):
|
||||||
"""
|
"""
|
||||||
return _u2i(_pigpio_command(_control, _PI_CMD_PROCD, script_id, 0))
|
return _u2i(_pigpio_command(_control, _PI_CMD_PROCD, script_id, 0))
|
||||||
|
|
||||||
|
def serial_read_open(user_gpio, baud):
|
||||||
|
"""
|
||||||
|
This function opens a gpio for reading serial data.
|
||||||
|
|
||||||
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
|
||||||
|
or PI_GPIO_IN_USE.
|
||||||
|
|
||||||
|
The serial data is held in a cyclic buffer and is read using
|
||||||
|
gpioSerialRead().
|
||||||
|
|
||||||
|
It is the caller's responsibility to read data from the cyclic buffer
|
||||||
|
in a timely fashion.
|
||||||
|
"""
|
||||||
|
return _u2i(_pigpio_command(_control, _PI_CMD_SLRO, user_gpio, baud))
|
||||||
|
|
||||||
|
def serial_read(user_gpio):
|
||||||
|
"""
|
||||||
|
This function returns data from the serial cyclic buffer.
|
||||||
|
|
||||||
|
It returns a tuple of status and string. The status will be the
|
||||||
|
length, possibly 0, of the returned string if OK. Otherwise a
|
||||||
|
negative error code will be returned in which case the string
|
||||||
|
will be null.
|
||||||
|
"""
|
||||||
|
bytes = _u2i(_pigpio_command(_control, _PI_CMD_SLR, user_gpio, 10000))
|
||||||
|
if bytes > 0:
|
||||||
|
buf = ""
|
||||||
|
while len(buf) < bytes: buf += _control.recv(bytes-len(buf))
|
||||||
|
return bytes, buf
|
||||||
|
return bytes, ""
|
||||||
|
|
||||||
|
|
||||||
|
def serial_read_close(user_gpio):
|
||||||
|
"""
|
||||||
|
This function closes a gpio for reading serial data.
|
||||||
|
|
||||||
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
|
||||||
|
"""
|
||||||
|
return _u2i(_pigpio_command(_control, _PI_CMD_SLRC, user_gpio, 0))
|
||||||
|
|
||||||
|
|
||||||
class callback:
|
class callback:
|
||||||
"""A class to provide gpio level change callbacks."""
|
"""A class to provide gpio level change callbacks."""
|
||||||
|
|
87
pigpiod_if.c
87
pigpiod_if.c
|
@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
For more information, please refer to <http://unlicense.org/>
|
For more information, please refer to <http://unlicense.org/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* PIGPIOD_IF_VERSION 2 */
|
/* PIGPIOD_IF_VERSION 3 */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -59,6 +59,7 @@ typedef void (*CBF_t) ();
|
||||||
|
|
||||||
struct callback_s
|
struct callback_s
|
||||||
{
|
{
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
int gpio;
|
int gpio;
|
||||||
int edge;
|
int edge;
|
||||||
|
@ -120,7 +121,7 @@ static int pigpio_command_ext
|
||||||
|
|
||||||
for (i=0; i<extents; i++)
|
for (i=0; i<extents; i++)
|
||||||
{
|
{
|
||||||
if (send(fd, ext[i].ptr, ext[i].n, 0) != ext[i].n)
|
if (send(fd, ext[i].ptr, ext[i].size, 0) != ext[i].size)
|
||||||
return pigif_bad_send;
|
return pigif_bad_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,12 +289,12 @@ static void findNotifyBits(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _wfe(int gpio, int level, uint32_t tick, void *user)
|
static void _wfe(unsigned gpio, unsigned level, uint32_t tick, void *user)
|
||||||
{
|
{
|
||||||
*(int *)user = 1;
|
*(int *)user = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intCallback(int gpio, int edge, void *f, void *user, int ex)
|
static int intCallback(unsigned gpio, unsigned edge, void *f, void *user, int ex)
|
||||||
{
|
{
|
||||||
static int id = 0;
|
static int id = 0;
|
||||||
callback_t *p;
|
callback_t *p;
|
||||||
|
@ -524,55 +525,55 @@ void pigpio_stop(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_mode(int gpio, int mode)
|
int set_mode(unsigned gpio, unsigned mode)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);}
|
{return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);}
|
||||||
|
|
||||||
int get_mode(int gpio)
|
int get_mode(unsigned gpio)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);}
|
||||||
|
|
||||||
int set_pull_up_down(int gpio, int pud)
|
int set_pull_up_down(unsigned gpio, unsigned pud)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);}
|
{return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);}
|
||||||
|
|
||||||
int read_gpio(int gpio)
|
int read_gpio(unsigned gpio)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);}
|
||||||
|
|
||||||
int write_gpio(int gpio, int level)
|
int write_gpio(unsigned gpio, unsigned level)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);}
|
{return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);}
|
||||||
|
|
||||||
int set_PWM_dutycycle(int user_gpio, int dutycycle)
|
int set_PWM_dutycycle(unsigned user_gpio, unsigned dutycycle)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);}
|
{return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);}
|
||||||
|
|
||||||
int set_PWM_range(int user_gpio, int range_)
|
int set_PWM_range(unsigned user_gpio, unsigned range_)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);}
|
{return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);}
|
||||||
|
|
||||||
int get_PWM_range(int user_gpio)
|
int get_PWM_range(unsigned user_gpio)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);}
|
||||||
|
|
||||||
int get_PWM_real_range(int user_gpio)
|
int get_PWM_real_range(unsigned user_gpio)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);}
|
||||||
|
|
||||||
int set_PWM_frequency(int user_gpio, int frequency)
|
int set_PWM_frequency(unsigned user_gpio, unsigned frequency)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);}
|
{return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);}
|
||||||
|
|
||||||
int get_PWM_frequency(int user_gpio)
|
int get_PWM_frequency(unsigned user_gpio)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);}
|
||||||
|
|
||||||
int set_servo_pulsewidth(int user_gpio, int pulsewidth)
|
int set_servo_pulsewidth(unsigned user_gpio, unsigned pulsewidth)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);}
|
{return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);}
|
||||||
|
|
||||||
int notify_open(void)
|
int notify_open(void)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);}
|
||||||
|
|
||||||
int notify_begin(int handle, uint32_t bits)
|
int notify_begin(unsigned handle, uint32_t bits)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);}
|
{return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);}
|
||||||
|
|
||||||
int notify_pause(int handle)
|
int notify_pause(unsigned handle)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);}
|
||||||
|
|
||||||
int notify_close(int handle)
|
int notify_close(unsigned handle)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);}
|
||||||
|
|
||||||
int set_watchdog(int user_gpio, int timeout)
|
int set_watchdog(unsigned user_gpio, unsigned timeout)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);}
|
{return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);}
|
||||||
|
|
||||||
uint32_t read_bank_1(void)
|
uint32_t read_bank_1(void)
|
||||||
|
@ -616,7 +617,7 @@ int wave_add_generic(unsigned numPulses, gpioPulse_t *pulses)
|
||||||
gpioPulse_t[] pulses
|
gpioPulse_t[] pulses
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ext[0].n = numPulses * sizeof(gpioPulse_t);
|
ext[0].size = numPulses * sizeof(gpioPulse_t);
|
||||||
ext[0].ptr = pulses;
|
ext[0].ptr = pulses;
|
||||||
|
|
||||||
return pigpio_command_ext(gPigCommand, PI_CMD_WVAG, numPulses, 0, 1, ext);
|
return pigpio_command_ext(gPigCommand, PI_CMD_WVAG, numPulses, 0, 1, ext);
|
||||||
|
@ -636,13 +637,13 @@ int wave_add_serial(
|
||||||
char[] str
|
char[] str
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ext[0].n = sizeof(unsigned);
|
ext[0].size = sizeof(unsigned);
|
||||||
ext[0].ptr = &baud;
|
ext[0].ptr = &baud;
|
||||||
|
|
||||||
ext[1].n = sizeof(unsigned);
|
ext[1].size = sizeof(unsigned);
|
||||||
ext[1].ptr = &offset;
|
ext[1].ptr = &offset;
|
||||||
|
|
||||||
ext[2].n = numChar;
|
ext[2].size = numChar;
|
||||||
ext[2].ptr = str;
|
ext[2].ptr = str;
|
||||||
|
|
||||||
return pigpio_command_ext(gPigCommand, PI_CMD_WVAS, gpio, numChar, 3, ext);
|
return pigpio_command_ext(gPigCommand, PI_CMD_WVAS, gpio, numChar, 3, ext);
|
||||||
|
@ -698,7 +699,7 @@ int gpio_trigger(unsigned gpio, unsigned pulseLen, unsigned level)
|
||||||
unsigned level
|
unsigned level
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ext[0].n = sizeof(level);
|
ext[0].size = sizeof(level);
|
||||||
ext[0].ptr = &level;
|
ext[0].ptr = &level;
|
||||||
|
|
||||||
return pigpio_command_ext(gPigCommand, PI_CMD_TRIG, gpio, pulseLen, 1, ext);
|
return pigpio_command_ext(gPigCommand, PI_CMD_TRIG, gpio, pulseLen, 1, ext);
|
||||||
|
@ -718,28 +719,48 @@ int store_script(char *script)
|
||||||
|
|
||||||
len = strlen(script);
|
len = strlen(script);
|
||||||
|
|
||||||
ext[0].n = len;
|
ext[0].size = len;
|
||||||
ext[0].ptr = script;
|
ext[0].ptr = script;
|
||||||
|
|
||||||
return pigpio_command_ext(gPigCommand, PI_CMD_PROC, len, 0, 1, ext);
|
return pigpio_command_ext(gPigCommand, PI_CMD_PROC, len, 0, 1, ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_script(int script_id)
|
int run_script(unsigned script_id)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PROCR, script_id, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PROCR, script_id, 0);}
|
||||||
|
|
||||||
int stop_script(int script_id)
|
int stop_script(unsigned script_id)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PROCS, script_id, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PROCS, script_id, 0);}
|
||||||
|
|
||||||
int delete_script(int script_id)
|
int delete_script(unsigned script_id)
|
||||||
{return pigpio_command(gPigCommand, PI_CMD_PROCD, script_id, 0);}
|
{return pigpio_command(gPigCommand, PI_CMD_PROCD, script_id, 0);}
|
||||||
|
|
||||||
int callback(int gpio, int edge, CBFunc_t f)
|
int serial_read_open(unsigned gpio, unsigned baud)
|
||||||
|
{return pigpio_command(gPigCommand, PI_CMD_SLRO, gpio, baud);}
|
||||||
|
|
||||||
|
int serial_read(unsigned gpio, void *buf, size_t bufSize)
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
bytes = pigpio_command(gPigCommand, PI_CMD_SLR, gpio, bufSize);
|
||||||
|
|
||||||
|
if (bytes > 0)
|
||||||
|
{
|
||||||
|
/* get the data */
|
||||||
|
recv(gPigCommand, buf, bytes, MSG_WAITALL);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int serial_read_close(unsigned gpio)
|
||||||
|
{return pigpio_command(gPigCommand, PI_CMD_SLRC, gpio, 0);}
|
||||||
|
|
||||||
|
int callback(unsigned gpio, unsigned edge, CBFunc_t f)
|
||||||
{return intCallback(gpio, edge, f, 0, 0);}
|
{return intCallback(gpio, edge, f, 0, 0);}
|
||||||
|
|
||||||
int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
|
int callback_ex(unsigned gpio, unsigned edge, CBFuncEx_t f, void *user)
|
||||||
{return intCallback(gpio, edge, f, user, 1);}
|
{return intCallback(gpio, edge, f, user, 1);}
|
||||||
|
|
||||||
int callback_cancel(int id)
|
int callback_cancel(unsigned id)
|
||||||
{
|
{
|
||||||
callback_t *p;
|
callback_t *p;
|
||||||
|
|
||||||
|
@ -766,7 +787,7 @@ int callback_cancel(int id)
|
||||||
return pigif_callback_not_found;
|
return pigif_callback_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wait_for_edge(int gpio, int edge, double timeout)
|
int wait_for_edge(unsigned gpio, unsigned edge, double timeout)
|
||||||
{
|
{
|
||||||
int triggered = 0;
|
int triggered = 0;
|
||||||
int id;
|
int id;
|
||||||
|
|
82
pigpiod_if.h
82
pigpiod_if.h
|
@ -30,7 +30,7 @@ For more information, please refer to <http://unlicense.org/>
|
||||||
|
|
||||||
#include "pigpio.h"
|
#include "pigpio.h"
|
||||||
|
|
||||||
#define PIGPIOD_IF_VERSION 2
|
#define PIGPIOD_IF_VERSION 3
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -45,12 +45,13 @@ typedef enum
|
||||||
pigif_bad_callback = -2008,
|
pigif_bad_callback = -2008,
|
||||||
pigif_notify_failed = -2009,
|
pigif_notify_failed = -2009,
|
||||||
pigif_callback_not_found = -2010,
|
pigif_callback_not_found = -2010,
|
||||||
} piscopeError_t;
|
} pigifError_t;
|
||||||
|
|
||||||
|
|
||||||
typedef void (*CBFunc_t) (int gpio, int level, uint32_t tick);
|
typedef void (*CBFunc_t) (unsigned gpio, unsigned level, uint32_t tick);
|
||||||
|
|
||||||
typedef void (*CBFuncEx_t)(int gpio, int level, uint32_t tick, void * user);
|
typedef void (*CBFuncEx_t)
|
||||||
|
(unsigned gpio, unsigned level, uint32_t tick, void * user);
|
||||||
|
|
||||||
typedef struct callback_s callback_t;
|
typedef struct callback_s callback_t;
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ void pigpio_stop(void);
|
||||||
resources used by the library.
|
resources used by the library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_mode(int gpio, int mode);
|
int set_mode(unsigned gpio, unsigned mode);
|
||||||
/* Set the gpio mode.
|
/* Set the gpio mode.
|
||||||
|
|
||||||
gpio: 0-53.
|
gpio: 0-53.
|
||||||
|
@ -120,7 +121,7 @@ int set_mode(int gpio, int mode);
|
||||||
or PI_NOT_PERMITTED.
|
or PI_NOT_PERMITTED.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int get_mode(int gpio);
|
int get_mode(unsigned gpio);
|
||||||
/* Get the gpio mode.
|
/* Get the gpio mode.
|
||||||
|
|
||||||
Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
|
Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
|
||||||
|
@ -128,7 +129,7 @@ int get_mode(int gpio);
|
||||||
gpio: 0-53.
|
gpio: 0-53.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_pull_up_down(int gpio, int pud);
|
int set_pull_up_down(unsigned gpio, unsigned pud);
|
||||||
/* Set or clear the gpio pull-up/down resistor.
|
/* Set or clear the gpio pull-up/down resistor.
|
||||||
|
|
||||||
Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
|
Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
|
||||||
|
@ -138,7 +139,7 @@ int set_pull_up_down(int gpio, int pud);
|
||||||
pud: PUD_UP, PUD_DOWN, PUD_OFF.
|
pud: PUD_UP, PUD_DOWN, PUD_OFF.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int read_gpio(int gpio);
|
int read_gpio(unsigned gpio);
|
||||||
/* Read the gpio level.
|
/* Read the gpio level.
|
||||||
|
|
||||||
Returns the gpio level if OK, otherwise PI_BAD_GPIO.
|
Returns the gpio level if OK, otherwise PI_BAD_GPIO.
|
||||||
|
@ -146,7 +147,7 @@ int read_gpio(int gpio);
|
||||||
gpio:0-53.
|
gpio:0-53.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int write_gpio(int gpio, int level);
|
int write_gpio(unsigned gpio, unsigned level);
|
||||||
/*
|
/*
|
||||||
Write the gpio level.
|
Write the gpio level.
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ int write_gpio(int gpio, int level);
|
||||||
If PWM or servo pulses are active on the gpio they are switched off.
|
If PWM or servo pulses are active on the gpio they are switched off.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_PWM_dutycycle(int user_gpio, int dutycycle);
|
int set_PWM_dutycycle(unsigned user_gpio, unsigned dutycycle);
|
||||||
/* Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
|
/* Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
|
||||||
|
|
||||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
|
||||||
|
@ -175,7 +176,7 @@ int set_PWM_dutycycle(int user_gpio, int dutycycle);
|
||||||
The set_PWM_range() function can change the default range of 255.
|
The set_PWM_range() function can change the default range of 255.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_PWM_range(int user_gpio, int range_);
|
int set_PWM_range(unsigned user_gpio, unsigned range_);
|
||||||
/* Set the range of PWM values to be used on the gpio.
|
/* Set the range of PWM values to be used on the gpio.
|
||||||
|
|
||||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
|
||||||
|
@ -200,7 +201,7 @@ int set_PWM_range(int user_gpio, int range_);
|
||||||
(dutycycle * real range) / range.
|
(dutycycle * real range) / range.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int get_PWM_range(int user_gpio);
|
int get_PWM_range(unsigned user_gpio);
|
||||||
/* Get the range of PWM values being used on the gpio.
|
/* Get the range of PWM values being used on the gpio.
|
||||||
|
|
||||||
Returns the dutycycle range used for the gpio if OK,
|
Returns the dutycycle range used for the gpio if OK,
|
||||||
|
@ -209,7 +210,7 @@ int get_PWM_range(int user_gpio);
|
||||||
user_gpio: 0-31.
|
user_gpio: 0-31.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int get_PWM_real_range(int user_gpio);
|
int get_PWM_real_range(unsigned user_gpio);
|
||||||
/* Get the real underlying range of PWM values being used on the gpio.
|
/* Get the real underlying range of PWM values being used on the gpio.
|
||||||
|
|
||||||
Returns the real range used for the gpio if OK,
|
Returns the real range used for the gpio if OK,
|
||||||
|
@ -218,7 +219,7 @@ int get_PWM_real_range(int user_gpio);
|
||||||
user_gpio: 0-31.
|
user_gpio: 0-31.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_PWM_frequency(int user_gpio, int frequency);
|
int set_PWM_frequency(unsigned user_gpio, unsigned frequency);
|
||||||
/*
|
/*
|
||||||
Set the frequency (in Hz) of the PWM to be used on the gpio.
|
Set the frequency (in Hz) of the PWM to be used on the gpio.
|
||||||
|
|
||||||
|
@ -257,7 +258,7 @@ int set_PWM_frequency(int user_gpio, int frequency);
|
||||||
125, 100, 80, 50, 40, 25, 20, 10, 5
|
125, 100, 80, 50, 40, 25, 20, 10, 5
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int get_PWM_frequency(int user_gpio);
|
int get_PWM_frequency(unsigned user_gpio);
|
||||||
/*
|
/*
|
||||||
Get the frequency of PWM being used on the gpio.
|
Get the frequency of PWM being used on the gpio.
|
||||||
|
|
||||||
|
@ -267,7 +268,7 @@ int get_PWM_frequency(int user_gpio);
|
||||||
user_gpio: 0-31.
|
user_gpio: 0-31.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_servo_pulsewidth(int user_gpio, int pulsewidth);
|
int set_servo_pulsewidth(unsigned user_gpio, unsigned pulsewidth);
|
||||||
/*
|
/*
|
||||||
Start (500-2500) or stop (0) servo pulses on the gpio.
|
Start (500-2500) or stop (0) servo pulses on the gpio.
|
||||||
|
|
||||||
|
@ -330,7 +331,7 @@ int notify_open(void);
|
||||||
read from /dev/pigpio15.
|
read from /dev/pigpio15.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int notify_begin(int handle, uint32_t bits);
|
int notify_begin(unsigned handle, uint32_t bits);
|
||||||
/*
|
/*
|
||||||
Start notifications on a previously opened handle.
|
Start notifications on a previously opened handle.
|
||||||
|
|
||||||
|
@ -352,7 +353,7 @@ int notify_begin(int handle, uint32_t bits);
|
||||||
I (32 bit) level
|
I (32 bit) level
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int notify_pause(int handle);
|
int notify_pause(unsigned handle);
|
||||||
/*
|
/*
|
||||||
Pause notifications on a previously opened handle.
|
Pause notifications on a previously opened handle.
|
||||||
|
|
||||||
|
@ -364,7 +365,7 @@ int notify_pause(int handle);
|
||||||
notify_begin() is called again.
|
notify_begin() is called again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int notify_close(int handle);
|
int notify_close(unsigned handle);
|
||||||
/*
|
/*
|
||||||
Stop notifications on a previously opened handle and
|
Stop notifications on a previously opened handle and
|
||||||
release the handle for reuse.
|
release the handle for reuse.
|
||||||
|
@ -374,7 +375,7 @@ int notify_close(int handle);
|
||||||
handle: 0-31 (as returned by notify_open())
|
handle: 0-31 (as returned by notify_open())
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int set_watchdog(int user_gpio, int timeout);
|
int set_watchdog(unsigned user_gpio, unsigned timeout);
|
||||||
/*
|
/*
|
||||||
Sets a watchdog for a gpio.
|
Sets a watchdog for a gpio.
|
||||||
|
|
||||||
|
@ -658,25 +659,52 @@ int store_script(char *script);
|
||||||
otherwise PI_BAD_SCRIPT.
|
otherwise PI_BAD_SCRIPT.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int run_script(int script_id);
|
int run_script(unsigned script_id);
|
||||||
/* This function runs a stored script.
|
/* This function runs a stored script.
|
||||||
|
|
||||||
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int stop_script(int script_id);
|
int stop_script(unsigned script_id);
|
||||||
/* This function stops a running script.
|
/* This function stops a running script.
|
||||||
|
|
||||||
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int delete_script(int script_id);
|
int delete_script(unsigned script_id);
|
||||||
/* This function deletes a stored script.
|
/* This function deletes a stored script.
|
||||||
|
|
||||||
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
The function returns 0 if OK, otherwise PI_BAD_SCRIPT_ID.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int callback(int gpio, int edge, CBFunc_t f);
|
int serial_read_open(unsigned user_gpio, unsigned baud);
|
||||||
|
/* This function opens a gpio for reading serial data.
|
||||||
|
|
||||||
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_WAVE_BAUD,
|
||||||
|
or PI_GPIO_IN_USE.
|
||||||
|
|
||||||
|
The serial data is returned in a cyclic buffer and is read using
|
||||||
|
gpioSerialRead().
|
||||||
|
|
||||||
|
It is the caller's responsibility to read data from the cyclic buffer
|
||||||
|
in a timely fashion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int serial_read(unsigned user_gpio, void *buf, size_t bufSize);
|
||||||
|
/* This function copies up to bufSize bytes of data read from the
|
||||||
|
serial cyclic buffer to the buffer starting at buf.
|
||||||
|
|
||||||
|
Returns the number of bytes copied if OK, otherwise PI_BAD_USER_GPIO
|
||||||
|
or PI_NOT_SERIAL_GPIO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int serial_read_close(unsigned user_gpio);
|
||||||
|
/* This function closes a gpio for reading serial data.
|
||||||
|
|
||||||
|
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SERIAL_GPIO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int callback(unsigned gpio, unsigned edge, CBFunc_t f);
|
||||||
/*
|
/*
|
||||||
This function initialises a new callback.
|
This function initialises a new callback.
|
||||||
|
|
||||||
|
@ -687,7 +715,7 @@ int callback(int gpio, int edge, CBFunc_t f);
|
||||||
gpio has the identified edge.
|
gpio has the identified edge.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user);
|
int callback_ex(unsigned gpio, unsigned edge, CBFuncEx_t f, void *user);
|
||||||
/*
|
/*
|
||||||
This function initialises a new callback.
|
This function initialises a new callback.
|
||||||
|
|
||||||
|
@ -698,14 +726,14 @@ int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user);
|
||||||
the gpio has the identified edge.
|
the gpio has the identified edge.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int callback_cancel(int id);
|
int callback_cancel(unsigned id);
|
||||||
/*
|
/*
|
||||||
This function cancels a callback identified by its id.
|
This function cancels a callback identified by its id.
|
||||||
|
|
||||||
The function returns 0 if OK, otherwise pigif_callback_not_found.
|
The function returns 0 if OK, otherwise pigif_callback_not_found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int wait_for_edge(int gpio, int edge, double timeout);
|
int wait_for_edge(unsigned gpio, unsigned edge, double timeout);
|
||||||
/*
|
/*
|
||||||
This function waits for edge on the gpio for up to timeout
|
This function waits for edge on the gpio for up to timeout
|
||||||
seconds.
|
seconds.
|
||||||
|
|
18
pigs.c
18
pigs.c
|
@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This version is for pigpio version 11+
|
This version is for pigpio version 12+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -153,10 +153,11 @@ int main(int argc , char *argv[])
|
||||||
|
|
||||||
for (i=0; i<cmdInfo[idx].ext; i++)
|
for (i=0; i<cmdInfo[idx].ext; i++)
|
||||||
{
|
{
|
||||||
send(sock, ext[i].ptr, ext[i].n, 0);
|
send(sock, ext[i].ptr, ext[i].size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv(sock, &cmd, sizeof(cmdCmd_t), 0) == sizeof(cmdCmd_t))
|
if (recv(sock, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) ==
|
||||||
|
sizeof(cmdCmd_t))
|
||||||
{
|
{
|
||||||
switch (cmdInfo[idx].rv)
|
switch (cmdInfo[idx].rv)
|
||||||
{
|
{
|
||||||
|
@ -187,6 +188,17 @@ int main(int argc , char *argv[])
|
||||||
case 5:
|
case 5:
|
||||||
printf(cmdUsage);
|
printf(cmdUsage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
r = cmd.res;
|
||||||
|
if (r < 0) fatal("ERROR: %s", cmdErrStr(r));
|
||||||
|
else if (r > 0)
|
||||||
|
{
|
||||||
|
recv(sock, &buf, r, MSG_WAITALL);
|
||||||
|
buf[r] = 0;
|
||||||
|
printf("%s", buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else fatal("recv failed, %m");
|
else fatal("recv failed, %m");
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -3,7 +3,7 @@
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
|
|
||||||
setup(name='pigpio',
|
setup(name='pigpio',
|
||||||
version='1.2',
|
version='1.3',
|
||||||
author='joan',
|
author='joan',
|
||||||
author_email='joan@abyz.me.uk',
|
author_email='joan@abyz.me.uk',
|
||||||
maintainer='joan',
|
maintainer='joan',
|
||||||
|
|
Loading…
Reference in New Issue