mirror of https://github.com/joan2937/pigpio
V10
This commit is contained in:
parent
a58a98d17b
commit
7f0cf5a014
|
@ -0,0 +1,47 @@
|
|||
CC = gcc
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
SIZE = size
|
||||
|
||||
CFLAGS = -O3 -Wall
|
||||
|
||||
ALL = libpigpiod_if.a pigs
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
pigs: command.o
|
||||
$(CC) -o pigs pigs.c command.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *.i *.s *~ $(ALL)
|
||||
|
||||
install: $(LIB)
|
||||
sudo install -m 0755 -d /usr/local/include
|
||||
sudo install -m 0644 pigpio.h /usr/local/include
|
||||
sudo install -m 0644 pigpiod_if.h /usr/local/include
|
||||
sudo install -m 0755 -d /usr/local/lib
|
||||
sudo install -m 0644 libpigpiod_if.a /usr/local/lib
|
||||
sudo install -m 0755 -d /usr/local/bin
|
||||
sudo install -m 0755 pigs /usr/local/bin
|
||||
sudo python setup.py install
|
||||
|
||||
uninstall:
|
||||
sudo rm -f /usr/local/include/pigpio.h
|
||||
sudo rm -f /usr/local/lib/libpigpiod_if.a
|
||||
sudo rm -f /usr/local/bin/pigs
|
||||
|
||||
LIB = libpigpiod_if.a
|
||||
OBJ = pigpiod_if.o command.o
|
||||
|
||||
$(LIB): $(OBJ)
|
||||
$(AR) rcs $(LIB) $(OBJ)
|
||||
$(RANLIB) $(LIB)
|
||||
$(SIZE) $(LIB)
|
||||
|
||||
# generated using gcc -MM *.c
|
||||
|
||||
command.o: command.c pigpio.h command.h
|
||||
pigpiod.o: pigpiod.c pigpio.h command.h
|
||||
pigpiod_if.o: pigpiod_if.c pigpio.h pigpiod_if.h
|
||||
pigs.o: pigs.c pigpio.h command.h
|
||||
|
67
Makefile
67
Makefile
|
@ -5,61 +5,74 @@ SIZE = size
|
|||
|
||||
CFLAGS = -O3 -Wall
|
||||
|
||||
ALL = libpigpio.a checklib demolib pig2vcd pigpiod pigs
|
||||
LIB1 = libpigpio.a
|
||||
OBJ1 = pigpio.o command.o
|
||||
|
||||
LIB2 = libpigpiod_if.a
|
||||
OBJ2 = pigpiod_if.o command.o
|
||||
|
||||
LIB = $(LIB1) $(LIB2)
|
||||
|
||||
ALL = $(LIB) checklib pig2vcd pigpiod pigs
|
||||
|
||||
LL = -L. -lpigpio -lpthread -lrt
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
checklib: checklib.o libpigpio.a
|
||||
$(CC) -o checklib checklib.c -L. -lpigpio -lpthread -lrt
|
||||
checklib: checklib.o $(LIB1)
|
||||
$(CC) -o checklib checklib.c $(LL)
|
||||
|
||||
demolib: demolib.o libpigpio.a
|
||||
$(CC) -o demolib demolib.c -L. -lpigpio -lpthread -lrt
|
||||
pigpiod: pigpiod.o $(LIB1)
|
||||
$(CC) -o pigpiod pigpiod.c $(LL)
|
||||
|
||||
pigs: pigs.o command.o
|
||||
$(CC) -o pigs pigs.c command.c
|
||||
|
||||
pig2vcd: pig2vcd.o
|
||||
$(CC) -o pig2vcd pig2vcd.c
|
||||
|
||||
pigpiod: pigpiod.o libpigpio.a
|
||||
$(CC) -o pigpiod pigpiod.c -L. -lpigpio -lpthread -lrt
|
||||
|
||||
pigs: command.o
|
||||
$(CC) -o pigs pigs.c command.c
|
||||
|
||||
clean:
|
||||
rm -f *.o *.i *.s *~ $(ALL)
|
||||
|
||||
install: $(LIB)
|
||||
sudo install -m 0755 -d /usr/local/include
|
||||
sudo install -m 0644 pigpio.h /usr/local/include
|
||||
sudo install -m 0755 -d /usr/local/lib
|
||||
sudo install -m 0644 libpigpio.a /usr/local/lib
|
||||
sudo install -m 0755 -d /usr/local/bin
|
||||
sudo install -m 0755 pig2vcd /usr/local/bin
|
||||
sudo install -m 0755 pigpiod /usr/local/bin
|
||||
sudo install -m 0755 pigs /usr/local/bin
|
||||
sudo install -m 0755 -d /usr/local/include
|
||||
sudo install -m 0644 pigpio.h /usr/local/include
|
||||
sudo install -m 0644 pigpiod_if.h /usr/local/include
|
||||
sudo install -m 0755 -d /usr/local/lib
|
||||
sudo install -m 0644 libpigpio.a /usr/local/lib
|
||||
sudo install -m 0644 libpigpiod_if.a /usr/local/lib
|
||||
sudo install -m 0755 -d /usr/local/bin
|
||||
sudo install -m 0755 pig2vcd /usr/local/bin
|
||||
sudo install -m 0755 pigpiod /usr/local/bin
|
||||
sudo install -m 0755 pigs /usr/local/bin
|
||||
sudo python setup.py install
|
||||
|
||||
uninstall:
|
||||
sudo rm -f /usr/local/include/pigpio.h
|
||||
sudo rm -f /usr/local/include/pigpiod_if.h
|
||||
sudo rm -f /usr/local/lib/libpigpio.a
|
||||
sudo rm -f /usr/local/lib/libpigpiod_if.a
|
||||
sudo rm -f /usr/local/bin/pig2vcd
|
||||
sudo rm -f /usr/local/bin/pigpiod
|
||||
sudo rm -f /usr/local/bin/pigs
|
||||
|
||||
LIB = libpigpio.a
|
||||
OBJ = pigpio.o command.o
|
||||
$(LIB1): $(OBJ1)
|
||||
$(AR) rcs $(LIB1) $(OBJ1)
|
||||
$(RANLIB) $(LIB1)
|
||||
$(SIZE) $(LIB1)
|
||||
|
||||
$(LIB): $(OBJ)
|
||||
$(AR) rcs $(LIB) $(OBJ)
|
||||
$(RANLIB) $(LIB)
|
||||
$(SIZE) $(LIB)
|
||||
$(LIB2): $(OBJ2)
|
||||
$(AR) rcs $(LIB2) $(OBJ2)
|
||||
$(RANLIB) $(LIB2)
|
||||
$(SIZE) $(LIB2)
|
||||
|
||||
# generated using gcc -M *.c
|
||||
# generated using gcc -MM *.c
|
||||
|
||||
checklib.o: checklib.c pigpio.h
|
||||
command.o: command.c pigpio.h command.h
|
||||
demolib.o: demolib.c pigpio.h
|
||||
pig2vcd.o: pig2vcd.c pigpio.h
|
||||
pigpio.o: pigpio.c pigpio.h command.h
|
||||
pigpiod.o: pigpiod.c pigpio.h command.h
|
||||
pigpiod_if.o: pigpiod_if.c pigpio.h command.h pigpiod_if.h
|
||||
pigs.o: pigs.c pigpio.h command.h
|
||||
|
||||
|
|
72
README
72
README
|
@ -9,13 +9,16 @@ Enter the following two commands (in this order)
|
|||
make
|
||||
make install
|
||||
|
||||
This will install:
|
||||
the library (libpigpio.a) in /usr/local/lib
|
||||
the header file (pigpio.h) in /usr/local/include
|
||||
the daemon (pigpiod) in /usr/local/bin
|
||||
the socket interface (pigs) in /usr/local/bin
|
||||
the utility pig2vcd in /usr/local/bin
|
||||
the Python module pigpio.py
|
||||
This will install
|
||||
|
||||
o the library (libpigpio.a) in /usr/local/lib
|
||||
o the library (libpigpiod_if.a) in /usr/local/lib
|
||||
o the header file (pigpio.h) in /usr/local/include
|
||||
o the header file (pigpiod_if.h) in /usr/local/include
|
||||
o the daemon (pigpiod) in /usr/local/bin
|
||||
o the socket interface (pigs) in /usr/local/bin
|
||||
o the utility pig2vcd in /usr/local/bin
|
||||
o the Python module pigpio.py
|
||||
|
||||
TEST
|
||||
|
||||
|
@ -23,8 +26,13 @@ To test the library do
|
|||
|
||||
sudo ./checklib
|
||||
|
||||
checklib.c, demolib.c, pig2vcd.c, pigpiod.c, pigs.c, and pigpio.py
|
||||
show examples of interfacing with the library.
|
||||
EXAMPLE CODE
|
||||
|
||||
checklib.c, pig2vcd.c, and pigpiod.c
|
||||
show examples of interfacing with the pigpio library.
|
||||
|
||||
pigs.c, pigpio.py, and test_pigpiod_if.c
|
||||
show examples of interfacing with the pigpiod daemon.
|
||||
|
||||
DAEMON
|
||||
|
||||
|
@ -39,7 +47,7 @@ When the library starts it locks
|
|||
|
||||
/var/run/pigpio.pid
|
||||
|
||||
The file should be deleted when the library terminates.
|
||||
The file should be automatically deleted when the library terminates.
|
||||
|
||||
SOCKET INTERFACE
|
||||
|
||||
|
@ -62,16 +70,16 @@ echo "help" >/dev/pigpio
|
|||
|
||||
PYTHON MODULE
|
||||
|
||||
By default the Python pigpio module is installed to the
|
||||
default python location. You can install it for additional
|
||||
Python versions by
|
||||
The Python pigpio module is installed to the default python location.
|
||||
|
||||
You can install it for additional Python versions by
|
||||
|
||||
pythonx.y setup.py install
|
||||
|
||||
where x.y is the Python version.
|
||||
|
||||
If the pigpiod daemon is running you can test the Python
|
||||
module by entering the following commands.
|
||||
If the pigpiod daemon is running you can test the Python module
|
||||
by entering the following commands.
|
||||
|
||||
python
|
||||
|
||||
|
@ -95,3 +103,37 @@ To stop the pigpiod daemon
|
|||
|
||||
sudo killall pigpiod
|
||||
|
||||
RUNNING ON NON Pi's
|
||||
|
||||
You can access the pigpiod daemon running on the Pi from any machine which
|
||||
can access it over the network. This access is via the socket interface.
|
||||
|
||||
In particular this allows you to use the following on non-Pi's.
|
||||
|
||||
o pigs
|
||||
o the pigpio Python module
|
||||
o the C socket I/F using libpigpiod_if (header file pigpiod_if.h)
|
||||
|
||||
On a Linux machine
|
||||
|
||||
make -f MakeRemote clean
|
||||
make -f MakeRemote
|
||||
make -f MakeRemote install
|
||||
|
||||
This will install
|
||||
|
||||
o the library (libpigpiod_if.a) in /usr/local/lib
|
||||
o the header file (pigpio.h) in /usr/local/include
|
||||
o the header file (pigpiod_if.h) in /usr/local/include
|
||||
o the socket interface (pigs) in /usr/local/bin
|
||||
o the Python module pigpio.py
|
||||
|
||||
On Windows machines (and possibly Macs)
|
||||
|
||||
The Python module should install with
|
||||
|
||||
python setup.py install
|
||||
|
||||
pigs and pigpiod_if.c will need minor mods to reflect the
|
||||
Window's/Mac's socket interface.
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
|
|||
*/
|
||||
|
||||
/*
|
||||
This version is for pigpio version 7+
|
||||
This version is for pigpio version 10+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -74,6 +74,7 @@ cmdInfo_t cmdInfo[]=
|
|||
{PI_CMD_TICK, "T", 1, 4},
|
||||
{PI_CMD_HELP, "HELP", 6, 5},
|
||||
{PI_CMD_HELP, "H", 6, 5},
|
||||
{PI_CMD_PIGPV, "PIGPV", 1, 4},
|
||||
};
|
||||
|
||||
char * cmdUsage = "\
|
||||
|
@ -93,6 +94,7 @@ NC h close notification\n\
|
|||
PWM/P u d set PWM value for gpio\n\
|
||||
PFS u d set PWM frequency for gpio\n\
|
||||
PFG u get PWM frequency for gpio\n\
|
||||
PIGPV return pigpio version\n\
|
||||
PRS u d set PWM range for gpio\n\
|
||||
PRG u get PWM range for gpio\n\
|
||||
PRRG u get PWM real range for gpio\n\
|
||||
|
@ -159,6 +161,8 @@ static errInfo_t errInfo[]=
|
|||
{PI_TOO_MANY_PULSES , "waveform has too many pulses"},
|
||||
{PI_TOO_MANY_CHARS , "waveform has too many chars"},
|
||||
{PI_NOT_SERIAL_GPIO , "no serial read in progress on gpio"},
|
||||
{PI_BAD_SERIAL_STRUC , "bad (null) serial structure parameter"},
|
||||
{PI_BAD_SERIAL_BUF , "bad (null) serial buf parameter"},
|
||||
{PI_NOT_PERMITTED , "no permission to update gpio"},
|
||||
{PI_SOME_PERMITTED , "no permission to update one or more gpios"},
|
||||
};
|
||||
|
@ -200,7 +204,7 @@ int cmdParse(char * buf, cmdCmd_t * cmd)
|
|||
|
||||
switch (cmdInfo[idx].vt)
|
||||
{
|
||||
case 1: /* BR1 BR2 HWVER NO TICK */
|
||||
case 1: /* BR1 BR2 HWVER PIGPV NO TICK */
|
||||
f = sscanf(buf, " %7s %c", str, &t);
|
||||
if (f == 1) valid = 1;
|
||||
break;
|
||||
|
|
673
demolib.c
673
demolib.c
|
@ -1,673 +0,0 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
/*
|
||||
This version is for pigpio version 3+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "pigpio.h"
|
||||
|
||||
/* ===========================================================================
|
||||
THIS PROGRAM NEEDS THE I2C DEVICE AND DEVELOPMENT LIBRARY
|
||||
|
||||
TO GET THE NEEDED FILES DO
|
||||
|
||||
sudo apt-get install libi2c-dev
|
||||
|
||||
BEFORE RUNNING THE PROGRAM ENSURE THAT THE I2C DEVICE IS PRESENT
|
||||
|
||||
sudo modprobe i2c-bcm2708
|
||||
sudo modprobe i2c-dev
|
||||
sudo chmod o+rw /dev/i2c*
|
||||
=========================================================================== */
|
||||
|
||||
/*
|
||||
|
||||
P1 Name gpio used for
|
||||
|
||||
3 SDA 0/2 i2c
|
||||
5 SCL 1/3 i2c
|
||||
7 --- 4 LASER
|
||||
8 TXD 14 LED1
|
||||
10 RXD 15 LED2
|
||||
11 --- 17 SERVO 1
|
||||
12 --- 18 SERVO 2
|
||||
13 --- 21/27 SERVO 3
|
||||
15 --- 22 LED3
|
||||
16 --- 23 TI Launchpad
|
||||
18 --- 24 Sonar trigger
|
||||
19 MOSI 10 Sonar echo
|
||||
21 MISO 9 Motor B In 1
|
||||
22 --- 25 LDR
|
||||
23 SCLK 11 Motor B In 2
|
||||
24 CE0 8 Motor A In1
|
||||
26 CE1 7 Motor A In2
|
||||
|
||||
*/
|
||||
|
||||
#define LASER 4
|
||||
#define MOTOR_A_IN2 7
|
||||
#define MOTOR_A_IN1 8
|
||||
#define MOTOR_B_IN1 9
|
||||
#define SONAR_ECHO 10
|
||||
#define MOTOR_B_IN2 11
|
||||
#define LED1 14
|
||||
#define LED2 15
|
||||
#define SERVO1 17
|
||||
#define SERVO2 18
|
||||
#define SERVO3 21
|
||||
#define LED3 22
|
||||
#define LAUNCHPAD 23
|
||||
#define SONAR_TRIGGER 24
|
||||
#define LDR 25
|
||||
|
||||
#define LEDS 4
|
||||
|
||||
short rawAcc[3];
|
||||
short rawGyr[3];
|
||||
short rawMag[3];
|
||||
|
||||
#define ROLL 0
|
||||
#define PITCH 1
|
||||
#define YAW 2
|
||||
|
||||
#define ACC_ORIENTATION(X, Y, Z) \
|
||||
{rawAcc[ROLL] = -X; rawAcc[PITCH] = -Y; rawAcc[YAW] = Z;}
|
||||
|
||||
#define GYRO_ORIENTATION(X, Y, Z) \
|
||||
{rawGyr[ROLL] = Y; rawGyr[PITCH] = -X; rawGyr[YAW] = -Z;}
|
||||
|
||||
#define MAG_ORIENTATION(X, Y, Z) \
|
||||
{rawMag[ROLL] = X; rawMag[PITCH] = Y; rawMag[YAW] = -Z;}
|
||||
|
||||
|
||||
#define CALIBRATIONS 200
|
||||
|
||||
#define ADXL345_I2C_ADDR 0x53
|
||||
#define ITG3200_I2C_ADDR 0x68
|
||||
|
||||
static int version, micros=5, millis=100;
|
||||
|
||||
static volatile unsigned long launchpadPulses;
|
||||
static volatile unsigned long launchpad5;
|
||||
static volatile unsigned long launchpad10;
|
||||
static volatile unsigned long launchpad15;
|
||||
static volatile unsigned long launchpadOutRange;
|
||||
static volatile int launchpadErr;
|
||||
static volatile uint32_t LDRrechargeTick;
|
||||
|
||||
|
||||
/* forward prototypes */
|
||||
|
||||
void LEDlaserTick (void);
|
||||
void motorTick(void);
|
||||
void i2cTick (void);
|
||||
void servoTick (void);
|
||||
void sonarLDRtick(void);
|
||||
|
||||
void launchpadAlert(int gpio, int level, uint32_t tick);
|
||||
void sonarAlert(int gpio, int level, uint32_t tick);
|
||||
void LDRalert(int gpio, int level, uint32_t tick);
|
||||
|
||||
void putTTY(char * buf);
|
||||
void putTTYstr(int row, int col, char * buf);
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char str[256];
|
||||
|
||||
if (argc > 1) micros = atoi(argv[1]);
|
||||
|
||||
if (argc > 2) millis = atoi(argv[2]);
|
||||
|
||||
putTTY("\033c"); /* clear console */
|
||||
|
||||
gpioCfgBufferSize(millis);
|
||||
|
||||
gpioCfgClock(micros, PI_CLOCK_PCM, PI_CLOCK_PLLD);
|
||||
|
||||
|
||||
/* before using the library you must call gpioInitialise */
|
||||
|
||||
version = gpioInitialise();
|
||||
|
||||
if (version >= 0)
|
||||
{
|
||||
/* initialise pins, only gpio numbers are supported */
|
||||
|
||||
gpioSetMode(SERVO1, PI_OUTPUT);
|
||||
gpioSetMode(SERVO2, PI_OUTPUT);
|
||||
gpioSetMode(SERVO3, PI_OUTPUT);
|
||||
gpioSetMode(LASER, PI_OUTPUT);
|
||||
gpioSetMode(LED1, PI_OUTPUT);
|
||||
gpioSetMode(LED2, PI_OUTPUT);
|
||||
gpioSetMode(LED3, PI_OUTPUT);
|
||||
gpioSetMode(MOTOR_A_IN1, PI_OUTPUT);
|
||||
gpioSetMode(MOTOR_A_IN2, PI_OUTPUT);
|
||||
gpioSetMode(MOTOR_B_IN1, PI_OUTPUT);
|
||||
gpioSetMode(MOTOR_B_IN2, PI_OUTPUT);
|
||||
|
||||
gpioSetMode(SONAR_TRIGGER, PI_OUTPUT);
|
||||
gpioWrite (SONAR_TRIGGER, PI_OFF);
|
||||
|
||||
gpioSetMode(SONAR_ECHO, PI_INPUT);
|
||||
gpioSetMode(LAUNCHPAD, PI_INPUT);
|
||||
gpioSetMode(LDR, PI_INPUT);
|
||||
|
||||
/* update i2c fifty times a second, timer #0 */
|
||||
|
||||
gpioSetTimerFunc(0, 20, i2cTick);
|
||||
|
||||
//gpioSetTimerFunc(0, 1000, servoTick);
|
||||
|
||||
/* update LEDs and laser once a second, timer #1 */
|
||||
|
||||
gpioSetTimerFunc(1, 1000, LEDlaserTick);
|
||||
|
||||
/* update motors every three seconds, timer #2 */
|
||||
|
||||
gpioSetTimerFunc(2, 3000, motorTick);
|
||||
|
||||
/* update sonar/LDR 10 times a second, timer #3 */
|
||||
|
||||
gpioSetTimerFunc(3, 100, sonarLDRtick);
|
||||
|
||||
/* an attachecd TI launchpad is transmitting high pulses of
|
||||
15, 35, 55, 75, ..., 975, 995 microseconds repeating with 50
|
||||
microseconds off between each pulse */
|
||||
|
||||
gpioSetAlertFunc(LAUNCHPAD, launchpadAlert);
|
||||
|
||||
/* monitor sonar echos */
|
||||
|
||||
gpioSetAlertFunc(SONAR_ECHO, sonarAlert);
|
||||
|
||||
/* monitor LDR level changes */
|
||||
|
||||
gpioSetAlertFunc(LDR, LDRalert);
|
||||
|
||||
while (1)
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
sprintf(str, "TI pulses %8ld", launchpadPulses);
|
||||
putTTYstr(9, 1, str);
|
||||
|
||||
sprintf(str, "+/-5 %8ld", launchpad5);
|
||||
putTTYstr(10, 6, str);
|
||||
|
||||
sprintf(str, "+/-10 %8ld", launchpad10);
|
||||
putTTYstr(11, 5, str);
|
||||
|
||||
sprintf(str, "+/-15 %8ld", launchpad15);
|
||||
putTTYstr(12, 5, str);
|
||||
|
||||
sprintf(str, "Others %8ld (last %d) ",
|
||||
launchpadOutRange, launchpadErr);
|
||||
putTTYstr(13, 4, str);
|
||||
}
|
||||
}
|
||||
|
||||
gpioTerminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LEDlaserTick(void)
|
||||
{
|
||||
static int gpio[LEDS]={LED1, LED2, LED3, LASER};
|
||||
static int pos [LEDS]={ 0, 3, 6, 9};
|
||||
static int inc [LEDS]={ 1, 1, 1, 1};
|
||||
|
||||
static int vals[] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 249};
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0; i<LEDS; i++)
|
||||
{
|
||||
gpioPWM(gpio[i], vals[pos[i]]);
|
||||
|
||||
pos[i] += inc[i];
|
||||
|
||||
if ( (pos[i]>=(sizeof(vals)/4)) || (pos[i]<0) )
|
||||
{
|
||||
inc[i] = -inc[i];
|
||||
pos[i] += inc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sonarLDRtick(void)
|
||||
{
|
||||
/* trigger a sonar reading */
|
||||
|
||||
gpioWrite(SONAR_TRIGGER, PI_ON);
|
||||
usleep(20);
|
||||
gpioWrite(SONAR_TRIGGER, PI_OFF);
|
||||
|
||||
/* trigger a LDR reading */
|
||||
|
||||
gpioSetMode(LDR, PI_OUTPUT); /* drain capacitor */
|
||||
|
||||
gpioWrite(LDR, PI_OFF);
|
||||
|
||||
usleep(200);
|
||||
|
||||
LDRrechargeTick = gpioTick();
|
||||
|
||||
gpioSetMode(LDR, PI_INPUT); /* start capacitor recharge */
|
||||
}
|
||||
|
||||
void motorTick(void)
|
||||
{
|
||||
static int gpio_in1[2]={MOTOR_A_IN1, MOTOR_B_IN1};
|
||||
static int gpio_in2[2]={MOTOR_A_IN2, MOTOR_B_IN2};
|
||||
static int speed [2]={ 80, 80};
|
||||
static int inc [2]={ -50, 50};
|
||||
|
||||
int i;
|
||||
char str[256];
|
||||
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
speed[i]+=inc[i];
|
||||
|
||||
if (speed[i]<0)
|
||||
{
|
||||
gpioPWM(gpio_in1[i], -speed[i]);
|
||||
gpioPWM(gpio_in2[i], 0);
|
||||
if (speed[i] < -205) inc[i] = -inc[i];
|
||||
sprintf(str, "MOT%d IN1=%3d IN2=%3d", i+1, -speed[i], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
gpioPWM(gpio_in2[i], speed[i]);
|
||||
gpioPWM(gpio_in1[i], 0);
|
||||
if (speed[i] > 205) inc[i] = -inc[i];
|
||||
sprintf(str, "MOT%d IN1=%3d IN2=%3d", i+1, 0, speed[i]);
|
||||
}
|
||||
if (i) putTTYstr(7, 1, str); else putTTYstr(5, 1, str);
|
||||
}
|
||||
}
|
||||
|
||||
/* loads of code to read/write i2c */
|
||||
|
||||
void selectDevice(int i2c, int addr, char * name)
|
||||
{
|
||||
if (ioctl(i2c, I2C_SLAVE, addr) < 0)
|
||||
{
|
||||
fprintf(stderr, "%s not present\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
void writeToDevice(int i2c, char * buf, int len)
|
||||
{
|
||||
static int reported = 0;
|
||||
if (write(i2c, buf, len) != len)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf(stderr, "Can't write to device\n");
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
else reported = 0;
|
||||
}
|
||||
|
||||
void readADXL345(int i2c)
|
||||
{
|
||||
char buf[8];
|
||||
static int reported = 0;
|
||||
|
||||
selectDevice(i2c, ADXL345_I2C_ADDR, "ADXL345");
|
||||
|
||||
writeToDevice(i2c, "\x32", 1);
|
||||
|
||||
if (read(i2c, buf, 6) != 6)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf(stderr, "Unable to read from ADXL345\n");
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reported = 0;
|
||||
|
||||
ACC_ORIENTATION (
|
||||
((buf[1]<<8) | buf[0]),
|
||||
((buf[3]<<8) | buf[2]),
|
||||
((buf[5]<<8) | buf[4]) );
|
||||
}
|
||||
}
|
||||
|
||||
void readITG3200(int i2c)
|
||||
{
|
||||
char buf[8];
|
||||
static int reported = 0;
|
||||
|
||||
selectDevice(i2c, ITG3200_I2C_ADDR, "ITG3200");
|
||||
|
||||
writeToDevice(i2c, "\x1D", 1);
|
||||
|
||||
if (read(i2c, buf, 6) != 6)
|
||||
{
|
||||
if (!reported)
|
||||
{
|
||||
fprintf(stderr, "Unable to read from ITG3200\n");
|
||||
reported = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reported = 0;
|
||||
|
||||
GYRO_ORIENTATION (
|
||||
((buf[0]<<8) | buf[1]),
|
||||
((buf[2]<<8) | buf[3]),
|
||||
((buf[4]<<8) | buf[5]) );
|
||||
}
|
||||
}
|
||||
|
||||
int initI2Cdevices(void)
|
||||
{
|
||||
int i2c;
|
||||
|
||||
if ((i2c = open("/dev/i2c-0", O_RDWR)) < 0)
|
||||
{
|
||||
perror("Failed to open i2c bus");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* initialise ADXL345 */
|
||||
|
||||
selectDevice(i2c, ADXL345_I2C_ADDR, "ADXL345");
|
||||
|
||||
writeToDevice(i2c, "\x2d\x00", 2);
|
||||
writeToDevice(i2c, "\x2d\x10", 2);
|
||||
writeToDevice(i2c, "\x2d\x08", 2);
|
||||
writeToDevice(i2c, "\x31\x00", 2);
|
||||
writeToDevice(i2c, "\x31\x0b", 2);
|
||||
|
||||
/* initialise ITG3200 */
|
||||
|
||||
selectDevice(i2c, ITG3200_I2C_ADDR, "ITG3200");
|
||||
|
||||
writeToDevice(i2c, "\x16\b00011000", 2);
|
||||
|
||||
return i2c;
|
||||
}
|
||||
|
||||
/* an attached IMU (GY-85) supplies orientation information which
|
||||
is used to position the servos */
|
||||
|
||||
float estimateAngle(int acc, int gyro, float oldAng, int elapsed)
|
||||
{
|
||||
float angleAcc, angleInc, estAngle;
|
||||
float secs;
|
||||
|
||||
secs = (float) elapsed / 1e6f;
|
||||
|
||||
angleAcc = (float) acc * 90.0f / 256.0f;
|
||||
|
||||
angleInc = (float) gyro * secs * 2000.0f / 32768.0f;
|
||||
|
||||
estAngle = 0.75 * (oldAng + angleInc) + 0.25 * angleAcc;
|
||||
|
||||
return estAngle;
|
||||
}
|
||||
|
||||
void servoTick(void)
|
||||
{
|
||||
static int wid1=1500, wid2=1500, wid3=1500;
|
||||
static int inc1=50, inc2=75, inc3=100;
|
||||
|
||||
gpioServo(SERVO1, wid1);
|
||||
gpioServo(SERVO2, wid2);
|
||||
gpioServo(SERVO3, wid3);
|
||||
|
||||
wid1+=inc1; if ((wid1<1000) || (wid1>2000)) {inc1 = -inc1; wid1+=inc1;}
|
||||
wid2+=inc2; if ((wid2<1000) || (wid2>2000)) {inc2 = -inc2; wid2+=inc2;}
|
||||
wid3+=inc3; if ((wid3<1000) || (wid3>2000)) {inc3 = -inc3; wid3+=inc3;}
|
||||
}
|
||||
|
||||
void i2cTick(void)
|
||||
{
|
||||
static int inited = 0;
|
||||
static int calibrated = 0;
|
||||
static int calibrations = 0;
|
||||
static int accCalibX = 0, accCalibY = 0, accCalibZ = 0;
|
||||
static int gyroCalibX = 0, gyroCalibY = 0, gyroCalibZ = 0;
|
||||
static int i2c;
|
||||
static float X=0.0, Y=0.0, Z=0.0;
|
||||
|
||||
static uint32_t lastTick;
|
||||
|
||||
uint32_t tick;
|
||||
int elapsed;
|
||||
int pulse;
|
||||
char str[256];
|
||||
|
||||
if (inited)
|
||||
{
|
||||
tick = gpioTick();
|
||||
elapsed = tick - lastTick;
|
||||
lastTick = tick;
|
||||
|
||||
readADXL345(i2c);
|
||||
readITG3200(i2c);
|
||||
|
||||
if (calibrated)
|
||||
{
|
||||
X = estimateAngle(
|
||||
rawAcc[ROLL], rawGyr[ROLL] -gyroCalibX, X, elapsed);
|
||||
|
||||
Y = estimateAngle(
|
||||
rawAcc[PITCH], rawGyr[PITCH] - gyroCalibY, Y, elapsed);
|
||||
|
||||
Z = estimateAngle(
|
||||
rawAcc[YAW], rawGyr[YAW] - gyroCalibZ, Z, elapsed);
|
||||
|
||||
pulse = 1500 + (Y * 1000 / 90);
|
||||
if (pulse < 500) pulse = 500;
|
||||
if (pulse > 2500) pulse = 2500;
|
||||
gpioServo(SERVO1, pulse);
|
||||
|
||||
pulse = 1500 - (X * 500 / 90);
|
||||
if (pulse < 1000) pulse = 1000;
|
||||
if (pulse > 2000) pulse = 2000;
|
||||
gpioServo(SERVO2, pulse);
|
||||
|
||||
/* prefer Z but that doesn't change much */
|
||||
pulse = 1500 - (Y * 500 / 90);
|
||||
if (pulse < 800) pulse = 800;
|
||||
if (pulse > 2200) pulse = 2200;
|
||||
gpioServo(SERVO3, pulse);
|
||||
|
||||
sprintf(str, "X=%4.0f Y=%4.0f Z=%4.0f ", X, Y, Z);
|
||||
putTTYstr(1, 1, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
accCalibX+=rawAcc[ROLL];
|
||||
accCalibY+=rawAcc[PITCH];
|
||||
accCalibZ+=rawAcc[YAW];
|
||||
|
||||
gyroCalibX+=rawGyr[ROLL];
|
||||
gyroCalibY+=rawGyr[PITCH];
|
||||
gyroCalibZ+=rawGyr[YAW];
|
||||
|
||||
if (++calibrations >= CALIBRATIONS)
|
||||
{
|
||||
accCalibX /= CALIBRATIONS;
|
||||
accCalibY /= CALIBRATIONS;
|
||||
accCalibZ /= CALIBRATIONS;
|
||||
|
||||
gyroCalibX /= CALIBRATIONS;
|
||||
gyroCalibY /= CALIBRATIONS;
|
||||
gyroCalibZ /= CALIBRATIONS;
|
||||
|
||||
calibrated = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i2c = initI2Cdevices();
|
||||
|
||||
gpioServo(SERVO1, 1500);
|
||||
gpioServo(SERVO2, 1500);
|
||||
gpioServo(SERVO3, 1500);
|
||||
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sonarAlert(int gpio, int level, uint32_t tick)
|
||||
{
|
||||
static uint32_t startTick;
|
||||
|
||||
int diffTick;
|
||||
char str[256];
|
||||
|
||||
if (level == PI_ON)
|
||||
{
|
||||
startTick = tick;
|
||||
}
|
||||
else if (level == PI_OFF)
|
||||
{
|
||||
diffTick = tick - startTick;
|
||||
|
||||
if (diffTick < 26100)
|
||||
{
|
||||
sprintf(str, "Sonar %3d cms", (diffTick+29)/58);
|
||||
putTTYstr(15, 1, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LDRalert(int pin, int level, uint32_t tick)
|
||||
{
|
||||
int diffTick;
|
||||
char str[256];
|
||||
|
||||
if (level == PI_ON)
|
||||
{
|
||||
diffTick = tick - LDRrechargeTick;
|
||||
|
||||
sprintf(str, "LDR %4d micros", diffTick);
|
||||
putTTYstr(17, 1, str);
|
||||
}
|
||||
}
|
||||
|
||||
void launchpadAlert(int pin, int level, uint32_t tick)
|
||||
{
|
||||
static int inited = 0, lastTick, lastPulseLen;
|
||||
|
||||
int pulseLen, pulseDif;
|
||||
|
||||
if (inited)
|
||||
{
|
||||
pulseLen = tick - lastTick;
|
||||
lastTick = tick;
|
||||
|
||||
if (level==0)
|
||||
{
|
||||
if (lastPulseLen)
|
||||
{
|
||||
pulseDif = pulseLen - lastPulseLen;
|
||||
|
||||
/* allow for wrap around */
|
||||
if (pulseDif < 0) pulseDif += 1096;
|
||||
|
||||
/* now centre around expected value */
|
||||
pulseDif -= 33;
|
||||
|
||||
if (pulseDif < 0) pulseDif = -pulseDif;
|
||||
|
||||
launchpadPulses++;
|
||||
|
||||
if (pulseDif <= 5)
|
||||
{
|
||||
launchpad5++;
|
||||
}
|
||||
else if (pulseDif <= 10)
|
||||
{
|
||||
launchpad10++;
|
||||
}
|
||||
else if (pulseDif <= 15)
|
||||
{
|
||||
launchpad15++;
|
||||
}
|
||||
else
|
||||
{
|
||||
launchpadOutRange++;
|
||||
launchpadErr = pulseDif;
|
||||
}
|
||||
}
|
||||
lastPulseLen = pulseLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTick = tick;
|
||||
lastPulseLen = 0;
|
||||
|
||||
launchpadPulses = 0;
|
||||
launchpad5 = 0;
|
||||
launchpad10 = 0;
|
||||
launchpad15 = 0;
|
||||
launchpadOutRange = 0;
|
||||
|
||||
inited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void putTTY(char * buf)
|
||||
{
|
||||
write(1, buf, strlen(buf));
|
||||
}
|
||||
|
||||
void putTTYstr(int row, int col, char * buf)
|
||||
{
|
||||
char str[256];
|
||||
|
||||
sprintf(str, "\033[%d;%dH%s", row, col, buf);
|
||||
|
||||
putTTY(str);
|
||||
}
|
||||
|
120
pigpio.c
120
pigpio.c
|
@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
|||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
/* pigpio version 9 */
|
||||
/* pigpio version 10 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -198,6 +198,31 @@ bit 0 READ_LAST_NOT_SET_ERROR
|
|||
} \
|
||||
while (0)
|
||||
|
||||
#define CHECK_INITED_RET_NULL_PTR \
|
||||
do \
|
||||
{ \
|
||||
if (!libInitialised) \
|
||||
{ \
|
||||
fprintf(stderr, \
|
||||
"%s %s: pigpio uninitialised, call gpioInitialise()\n",\
|
||||
myTimeStamp(), __FUNCTION__); \
|
||||
return (NULL); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define CHECK_INITED_RET_NIL \
|
||||
do \
|
||||
{ \
|
||||
if (!libInitialised) \
|
||||
{ \
|
||||
fprintf(stderr, \
|
||||
"%s %s: pigpio uninitialised, call gpioInitialise()\n",\
|
||||
myTimeStamp(), __FUNCTION__); \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define CHECK_NOT_INITED \
|
||||
do \
|
||||
{ \
|
||||
|
@ -322,16 +347,16 @@ bit 0 READ_LAST_NOT_SET_ERROR
|
|||
/* DMA CS Control and Status bits */
|
||||
#define DMA_CHANNEL_RESET (1<<31)
|
||||
#define DMA_WAIT_ON_WRITES (1<<28)
|
||||
#define DMA_PANIC_PRIORITY(x) ((x)<<20)
|
||||
#define DMA_PRIORITY(x) ((x)<<16)
|
||||
#define DMA_PANIC_PRIORITY(x) ((x)<<20)
|
||||
#define DMA_PRIORITY(x) ((x)<<16)
|
||||
#define DMA_INTERRUPT_STATUS (1<< 2)
|
||||
#define DMA_END_FLAG (1<< 1)
|
||||
#define DMA_ACTIVATE (1<< 0)
|
||||
|
||||
/* DMA control block "info" field bits */
|
||||
#define DMA_NO_WIDE_BURSTS (1<<26)
|
||||
#define DMA_PERIPHERAL_MAPPING(x) ((x)<<16)
|
||||
#define DMA_BURST_LENGTH(x) ((x)<<12)
|
||||
#define DMA_PERIPHERAL_MAPPING(x) ((x)<<16)
|
||||
#define DMA_BURST_LENGTH(x) ((x)<<12)
|
||||
#define DMA_SRC_IGNORE (1<<11)
|
||||
#define DMA_SRC_DREQ (1<<10)
|
||||
#define DMA_SRC_INC (1<< 8)
|
||||
|
@ -981,7 +1006,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPullUpDown(p1, p2);
|
||||
else
|
||||
{
|
||||
PERM_ERROR("gpioSetPullUpDown: gpio %d, no permission to update", p1);
|
||||
PERM_ERROR(
|
||||
"gpioSetPullUpDown: gpio %d, no permission to update", p1);
|
||||
res = PI_NOT_PERMITTED;
|
||||
}
|
||||
break;
|
||||
|
@ -1012,7 +1038,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMrange(p1, p2);
|
||||
else
|
||||
{
|
||||
PERM_ERROR("gpioSetPWMrange: gpio %d, no permission to update", p1);
|
||||
PERM_ERROR(
|
||||
"gpioSetPWMrange: gpio %d, no permission to update", p1);
|
||||
res = PI_NOT_PERMITTED;
|
||||
}
|
||||
break;
|
||||
|
@ -1021,7 +1048,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
if (gpioMask & (uint64_t)(1<<p1)) res = gpioSetPWMfrequency(p1, p2);
|
||||
else
|
||||
{
|
||||
PERM_ERROR("gpioSetPWMfrequency: gpio %d, no permission to update", p1);
|
||||
PERM_ERROR(
|
||||
"gpioSetPWMfrequency: gpio %d, no permission to update", p1);
|
||||
res = PI_NOT_PERMITTED;
|
||||
}
|
||||
break;
|
||||
|
@ -1054,7 +1082,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
|
||||
if ((mask | p1) != mask)
|
||||
{
|
||||
PERM_ERROR("gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
|
||||
PERM_ERROR(
|
||||
"gpioWrite_Bits_0_31_Clear: bad levels %08X (permissions %08X)",
|
||||
p1, mask);
|
||||
res = PI_SOME_PERMITTED;
|
||||
}
|
||||
|
@ -1067,7 +1096,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
|
||||
if ((mask | p1) != mask)
|
||||
{
|
||||
PERM_ERROR("gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
|
||||
PERM_ERROR(
|
||||
"gpioWrite_Bits_32_53_Clear: bad levels %08X (permissions %08X)",
|
||||
p1, mask);
|
||||
res = PI_SOME_PERMITTED;
|
||||
}
|
||||
|
@ -1080,7 +1110,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
|
||||
if ((mask | p1) != mask)
|
||||
{
|
||||
PERM_ERROR("gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
|
||||
PERM_ERROR(
|
||||
"gpioWrite_Bits_0_31_Set: bad levels %08X (permissions %08X)",
|
||||
p1, mask);
|
||||
res = PI_SOME_PERMITTED;
|
||||
}
|
||||
|
@ -1093,7 +1124,8 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
|
||||
if ((mask | p1) != mask)
|
||||
{
|
||||
PERM_ERROR("gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
|
||||
PERM_ERROR(
|
||||
"gpioWrite_Bits_32_53_Set: bad levels %08X (permissions %08X)",
|
||||
p1, mask);
|
||||
res = PI_SOME_PERMITTED;
|
||||
}
|
||||
|
@ -1138,6 +1170,10 @@ static void myDoCommand(cmdCmd_t * cmd)
|
|||
case PI_CMD_HELP:
|
||||
break;
|
||||
|
||||
case PI_CMD_PIGPV:
|
||||
res = gpioVersion();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
cmd->res = res;
|
||||
|
@ -4731,6 +4767,56 @@ int gpioSetTimerFuncEx(unsigned id, unsigned ms, gpioTimerFuncEx_t f,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
pthread_t *gpioStartThread(ThreadFunc_t func, void *arg)
|
||||
{
|
||||
pthread_t *pth;
|
||||
pthread_attr_t pthAttr;
|
||||
|
||||
DBG(DBG_USER, "func=%08X, arg=%08X", (uint32_t)func, (uint32_t)arg);
|
||||
|
||||
CHECK_INITED_RET_NULL_PTR;
|
||||
|
||||
pth = malloc(sizeof(pthread_t));
|
||||
|
||||
if (pth)
|
||||
{
|
||||
if (pthread_attr_init(&pthAttr))
|
||||
{
|
||||
free(pth);
|
||||
SOFT_ERROR(NULL, "pthread_attr_init failed");
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize(&pthAttr, STACK_SIZE))
|
||||
{
|
||||
free(pth);
|
||||
SOFT_ERROR(NULL, "pthread_attr_setstacksize failed");
|
||||
}
|
||||
|
||||
if (pthread_create(pth, &pthAttr, func, arg))
|
||||
{
|
||||
free(pth);
|
||||
SOFT_ERROR(NULL, "pthread_create failed");
|
||||
}
|
||||
}
|
||||
return pth;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
void gpioStopThread(pthread_t *pth)
|
||||
{
|
||||
DBG(DBG_USER, "pth=%08X", (uint32_t)pth);
|
||||
|
||||
CHECK_INITED_RET_NIL;
|
||||
|
||||
if (pth)
|
||||
{
|
||||
pthread_cancel(*pth);
|
||||
pthread_join(*pth, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
@ -4959,6 +5045,16 @@ uint32_t gpioTick(void)
|
|||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
unsigned gpioVersion(void)
|
||||
{
|
||||
DBG(DBG_USER, "");
|
||||
|
||||
return PIGPIO_VERSION;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
unsigned gpioHardwareRevision(void)
|
||||
|
|
119
pigpio.h
119
pigpio.h
|
@ -26,7 +26,7 @@ For more information, please refer to <http://unlicense.org/>
|
|||
*/
|
||||
|
||||
/*
|
||||
This version is for pigpio version 9
|
||||
This version is for pigpio version 10
|
||||
*/
|
||||
|
||||
#ifndef PIGPIO_H
|
||||
|
@ -51,6 +51,7 @@ This version is for pigpio version 9
|
|||
/ output gpio level changes. /
|
||||
/ 9) rudimentary permission control through the socket and pipe interfaces /
|
||||
/ so users can be prevented from "updating" inappropriate gpios. /
|
||||
/ 10) a simple interface to start and stop new threads. /
|
||||
/ /
|
||||
/ NOTE: /
|
||||
/ /
|
||||
|
@ -83,8 +84,9 @@ This version is for pigpio version 9
|
|||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define PIGPIO_VERSION 9
|
||||
#define PIGPIO_VERSION 10
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -154,6 +156,9 @@ gpioSetGetSamplesFuncEx Requests a gpio samples callback, extended.
|
|||
gpioSetTimerFunc Request a regular timed callback.
|
||||
gpioSetTimerFuncEx Request a regular timed callback, extended.
|
||||
|
||||
gpioStartThread Start a new thread.
|
||||
gpioStopThread Stop a previously started thread.
|
||||
|
||||
gpioSetSignalFunc Request a signal callback.
|
||||
gpioSetSignalFuncEx Request a signal callback, extended.
|
||||
|
||||
|
@ -175,6 +180,8 @@ gpioTick Get current tick (microseconds).
|
|||
|
||||
gpioHardwareRevision Get hardware version.
|
||||
|
||||
gpioVersion Get the pigpio version.
|
||||
|
||||
gpioCfgBufferSize Configure the gpio sample buffer size.
|
||||
gpioCfgClock Configure the gpio sample rate.
|
||||
gpioCfgDMAchannel Configure the DMA channel (DEPRECATED).
|
||||
|
@ -264,11 +271,15 @@ typedef void (*gpioGetSamplesFuncEx_t) (const gpioSample_t * samples,
|
|||
int numSamples,
|
||||
void * userdata);
|
||||
|
||||
typedef void *(ThreadFunc_t) (void *);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
All the functions which return an int return < 0 on error.
|
||||
|
||||
If the library isn't initialised all but the gpioCfg* functions
|
||||
will return error PI_NOT_INITIALISED.
|
||||
If the library isn't initialised all but the gpioCfg*, gpioVersion,
|
||||
and gpioHardwareRevision functions will return error PI_NOT_INITIALISED.
|
||||
|
||||
If the library is initialised the gpioCfg* functions will
|
||||
return error PI_INITIALISED.
|
||||
|
@ -381,9 +392,9 @@ int gpioSetPullUpDown(unsigned gpio,
|
|||
|
||||
/* pud: 0-2 */
|
||||
|
||||
#define PI_PUD_OFF 0
|
||||
#define PI_PUD_DOWN 1
|
||||
#define PI_PUD_UP 2
|
||||
#define PI_PUD_OFF 0
|
||||
#define PI_PUD_DOWN 1
|
||||
#define PI_PUD_UP 2
|
||||
|
||||
|
||||
|
||||
|
@ -406,14 +417,14 @@ int gpioRead (unsigned gpio);
|
|||
|
||||
/* level: 0-1 */
|
||||
|
||||
#define PI_OFF 0
|
||||
#define PI_ON 1
|
||||
#define PI_OFF 0
|
||||
#define PI_ON 1
|
||||
|
||||
#define PI_CLEAR 0
|
||||
#define PI_SET 1
|
||||
#define PI_CLEAR 0
|
||||
#define PI_SET 1
|
||||
|
||||
#define PI_LOW 0
|
||||
#define PI_HIGH 1
|
||||
#define PI_LOW 0
|
||||
#define PI_HIGH 1
|
||||
|
||||
/* level: only reported for gpio timeout, see gpioSetWatchdogTimeout */
|
||||
|
||||
|
@ -1255,6 +1266,68 @@ int gpioSetTimerFuncEx(unsigned timer,
|
|||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
pthread_t *gpioStartThread(ThreadFunc_t func, void *arg);
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Starts a new thread of execution with func as the main routine.
|
||||
|
||||
Returns a pointer to pthread_t if OK, otherwise NULL.
|
||||
|
||||
The function is passed the single argument arg.
|
||||
|
||||
The thread can be cancelled by passing the pointer to pthread_t to
|
||||
gpioStopThread().
|
||||
|
||||
EXAMPLE:
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pigpio.h>
|
||||
|
||||
void *myfunc(void *arg)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
printf("%s\n", arg);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pthread_t *p1, *p2, *p3;
|
||||
|
||||
if (gpioInitialise() < 0) return 1;
|
||||
|
||||
p1 = gpioStartThread(myfunc, "thread 1"); sleep(3);
|
||||
|
||||
p2 = gpioStartThread(myfunc, "thread 2"); sleep(3);
|
||||
|
||||
p3 = gpioStartThread(myfunc, "thread 3"); sleep(3);
|
||||
|
||||
gpioStopThread(p3); sleep(3);
|
||||
|
||||
gpioStopThread(p2); sleep(3);
|
||||
|
||||
gpioStopThread(p1); sleep(3);
|
||||
|
||||
gpioTerminate();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
void gpioStopThread(pthread_t *pth);
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Cancels the thread pointed at by pth.
|
||||
|
||||
No value is returned.
|
||||
|
||||
The thread to be stopped should have been started with gpioStartThread().
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int gpioSetSignalFunc(unsigned signum,
|
||||
gpioSignalFunc_t f);
|
||||
|
@ -1518,9 +1591,17 @@ unsigned gpioHardwareRevision(void);
|
|||
|
||||
EXAMPLES:
|
||||
|
||||
for "Revision : 0002" the function returns 2.
|
||||
for "Revision : 000f" the function returns 15.
|
||||
for "Revision : 000g" the function returns 0.
|
||||
for "Revision : 0002" the function returns 2.
|
||||
for "Revision : 000f" the function returns 15.
|
||||
for "Revision : 000g" the function returns 0.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
unsigned gpioVersion(void);
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Returns the pigpio version.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -1734,6 +1815,7 @@ void gpioWaveDump(void);
|
|||
#define PI_CMD_PFG 23
|
||||
#define PI_CMD_PRRG 24
|
||||
#define PI_CMD_HELP 25
|
||||
#define PI_CMD_PIGPV 26
|
||||
|
||||
/*
|
||||
The following command only works on the socket interface.
|
||||
|
@ -1792,8 +1874,8 @@ after this command is issued.
|
|||
#define PI_TOO_MANY_PULSES -36 /* waveform has too many pulses */
|
||||
#define PI_TOO_MANY_CHARS -37 /* waveform has too many chars */
|
||||
#define PI_NOT_SERIAL_GPIO -38 /* no serial read in progress on gpio */
|
||||
#define PI_BAD_SERIAL_STRUC -39 /* bad null serial structure parameter */
|
||||
#define PI_BAD_SERIAL_BUF -40 /* bad null serial buf parameter */
|
||||
#define PI_BAD_SERIAL_STRUC -39 /* bad (null) serial structure parameter */
|
||||
#define PI_BAD_SERIAL_BUF -40 /* bad (null) serial buf parameter */
|
||||
#define PI_NOT_PERMITTED -41 /* gpio operation not permitted */
|
||||
#define PI_SOME_PERMITTED -42 /* one or more gpios not permitted */
|
||||
|
||||
|
@ -1816,3 +1898,4 @@ after this command is issued.
|
|||
#define PI_DEFAULT_UPDATE_MASK_R2 0xFBC6CF9C
|
||||
|
||||
#endif
|
||||
|
||||
|
|
43
pigpio.py
43
pigpio.py
|
@ -76,7 +76,7 @@ import threading
|
|||
import os
|
||||
import atexit
|
||||
|
||||
VERSION = "1.0"
|
||||
VERSION = "1.1"
|
||||
|
||||
# gpio levels
|
||||
|
||||
|
@ -92,9 +92,9 @@ TIMEOUT = 2
|
|||
|
||||
# gpio edges
|
||||
|
||||
EITHER_EDGE = 0
|
||||
RISING_EDGE = 1
|
||||
FALLING_EDGE = 2
|
||||
RISING_EDGE = 0
|
||||
FALLING_EDGE = 1
|
||||
EITHER_EDGE = 2
|
||||
|
||||
# gpio modes
|
||||
|
||||
|
@ -338,12 +338,14 @@ class _callback_thread(threading.Thread):
|
|||
def __init__(self):
|
||||
"""Initialises notifications."""
|
||||
threading.Thread.__init__(self)
|
||||
self.go = False
|
||||
self.daemon = True
|
||||
self.monitor = 0
|
||||
self.callbacks = []
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.connect((_host,_port))
|
||||
self.handle = _pigpio_command(self.sock, _PI_CMD_NOIB, 0, 0)
|
||||
self.go = True
|
||||
self.start()
|
||||
|
||||
def stop(self):
|
||||
|
@ -376,13 +378,23 @@ class _callback_thread(threading.Thread):
|
|||
notify_begin(self.handle, self.monitor)
|
||||
|
||||
def run(self):
|
||||
|
||||
"""Execute the notification thread."""
|
||||
self.go = True
|
||||
|
||||
lastLevel = 0
|
||||
|
||||
MSG_SIZ = 12
|
||||
|
||||
while self.go:
|
||||
seq_no, flags, tick, level = (
|
||||
struct.unpack('HHII', self.sock.recv(12, socket.MSG_WAITALL)))
|
||||
|
||||
buf = self.sock.recv(MSG_SIZ)
|
||||
|
||||
while self.go and len(buf) < MSG_SIZ:
|
||||
buf += self.sock.recv(MSG_SIZ-len(buf))
|
||||
|
||||
if self.go:
|
||||
seq, flags, tick, level = (struct.unpack('HHII', buf))
|
||||
|
||||
if flags == 0:
|
||||
changed = level ^ lastLevel
|
||||
lastLevel = level
|
||||
|
@ -391,9 +403,7 @@ class _callback_thread(threading.Thread):
|
|||
newLevel = 0
|
||||
if cb.bit & level:
|
||||
newLevel = 1
|
||||
if (cb.edge == EITHER_EDGE or
|
||||
cb.edge == RISING_EDGE and newLevel == 1 or
|
||||
cb.edge == FALLING_EDGE and newLevel == 0):
|
||||
if (cb.edge ^ newLevel):
|
||||
cb.func(cb.gpio, newLevel, tick)
|
||||
else:
|
||||
gpio = flags & 31
|
||||
|
@ -404,6 +414,7 @@ class _callback_thread(threading.Thread):
|
|||
self.sock.close()
|
||||
|
||||
class _wait_for_edge:
|
||||
|
||||
"""A class to encapsulate waiting for gpio edges."""
|
||||
|
||||
def __init__(self, gpio, edge, timeout):
|
||||
|
@ -1553,20 +1564,18 @@ def start(host = os.getenv("PIGPIO_ADDR", ''),
|
|||
else:
|
||||
h = _host
|
||||
errStr = "Can't connect to pigpio on " + str(h) + "(" + str(_port) + ")"
|
||||
print("********************************************************")
|
||||
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
|
||||
print(errStr)
|
||||
print("")
|
||||
print("Did you start the pigpio daemon?")
|
||||
print("(sudo pigpiod)")
|
||||
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("E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888")
|
||||
print("")
|
||||
print("Did you specify the correct Pi host/port in the")
|
||||
print("pigpio.start() function")
|
||||
print("(e.g. pigpio.start('soft', 8888))")
|
||||
print("********************************************************")
|
||||
print("pigpio.start() function? E.g. pigpio.start('soft', 8888))")
|
||||
print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%")
|
||||
raise
|
||||
|
||||
def stop():
|
||||
|
|
|
@ -0,0 +1,688 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
/* PIGPIOD_IF_VERSION 1 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "pigpio.h"
|
||||
#include "command.h"
|
||||
|
||||
#include "pigpiod_if.h"
|
||||
|
||||
#define PISCOPE_MAX_REPORTS_PER_READ 4096
|
||||
|
||||
#define STACK_SIZE (256*1024)
|
||||
|
||||
typedef void (*CBF_t) ();
|
||||
|
||||
struct callback_s
|
||||
{
|
||||
int id;
|
||||
int gpio;
|
||||
int edge;
|
||||
CBF_t f;
|
||||
void * user;
|
||||
int ex;
|
||||
callback_t *prev;
|
||||
callback_t *next;
|
||||
};
|
||||
|
||||
/* GLOBALS ---------------------------------------------------------------- */
|
||||
|
||||
static gpioReport_t gReport[PISCOPE_MAX_REPORTS_PER_READ];
|
||||
|
||||
static int gPigCommand = -1;
|
||||
static int gPigHandle = -1;
|
||||
static int gPigNotify = -1;
|
||||
|
||||
static uint32_t gNotifyBits;
|
||||
|
||||
callback_t *gCallBackFirst = 0;
|
||||
callback_t *gCallBackLast = 0;
|
||||
|
||||
static int gPigStarted = 0;
|
||||
|
||||
static pthread_t *pthNotify;
|
||||
|
||||
/* PRIVATE ---------------------------------------------------------------- */
|
||||
|
||||
static int pigpio_command(int fd, int command, int p1, int p2)
|
||||
{
|
||||
cmdCmd_t cmd;
|
||||
|
||||
cmd.cmd = command;
|
||||
cmd.p1 = p1;
|
||||
cmd.p2 = p2;
|
||||
cmd.res = 0;
|
||||
|
||||
if (send(fd, &cmd, sizeof(cmdCmd_t), 0) != sizeof(cmdCmd_t))
|
||||
return pigif_bad_send;
|
||||
|
||||
if (recv(fd, &cmd, sizeof(cmdCmd_t), MSG_WAITALL) != sizeof(cmdCmd_t))
|
||||
return pigif_bad_recv;
|
||||
|
||||
return cmd.res;
|
||||
}
|
||||
|
||||
static int pigpioOpenSocket(char *addr, char *port)
|
||||
{
|
||||
int sock, err;
|
||||
struct addrinfo hints, *res, *rp;
|
||||
const char *addrStr, *portStr;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
addrStr = getenv(PI_ENVADDR);
|
||||
|
||||
if ((!addrStr) || (!strlen(addrStr)))
|
||||
{
|
||||
addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
|
||||
}
|
||||
}
|
||||
else addrStr = addr;
|
||||
|
||||
if (!port)
|
||||
{
|
||||
portStr = getenv(PI_ENVPORT);
|
||||
|
||||
if ((!portStr) || (!strlen(portStr)))
|
||||
{
|
||||
portStr = PI_DEFAULT_SOCKET_PORT_STR;
|
||||
}
|
||||
}
|
||||
else portStr = port;
|
||||
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags |= AI_CANONNAME;
|
||||
|
||||
err = getaddrinfo (addrStr, portStr, &hints, &res);
|
||||
|
||||
if (err) return pigif_bad_getaddrinfo;
|
||||
|
||||
for (rp=res; rp!=NULL; rp=rp->ai_next)
|
||||
{
|
||||
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
|
||||
if (sock == -1) continue;
|
||||
|
||||
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
if (rp == NULL) return pigif_bad_connect;
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void dispatch_notification(gpioReport_t *r)
|
||||
{
|
||||
static uint32_t lastLevel = 0;
|
||||
|
||||
callback_t *p;
|
||||
uint32_t changed;
|
||||
int l, g;
|
||||
|
||||
/*
|
||||
printf("s=%d f=%d l=%8X, t=%10u\n",
|
||||
r->seqno, r->flags, r->level, r->tick);
|
||||
*/
|
||||
|
||||
if (r->flags == 0)
|
||||
{
|
||||
changed = (r->level ^ lastLevel) & gNotifyBits;
|
||||
|
||||
lastLevel = r->level;
|
||||
|
||||
p = gCallBackFirst;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if (changed & (1<<(p->gpio)))
|
||||
{
|
||||
if ((r->level) & (1<<(p->gpio))) l = 1; else l = 0;
|
||||
if ((p->edge) ^ l)
|
||||
{
|
||||
if (p->ex) (p->f)(p->gpio, l, r->tick, p->user);
|
||||
else (p->f)(p->gpio, l, r->tick);
|
||||
}
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g = (r->flags) & 31;
|
||||
|
||||
p = gCallBackFirst;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if ((p->gpio) == g)
|
||||
{
|
||||
if (p->ex) (p->f)(g, PI_TIMEOUT, r->tick, p->user);
|
||||
else (p->f)(g, PI_TIMEOUT, r->tick);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *pthNotifyThread(void *x)
|
||||
{
|
||||
static int got = 0;
|
||||
|
||||
int bytes, r;
|
||||
|
||||
while (1)
|
||||
{
|
||||
bytes = read(gPigNotify, (char*)&gReport+got, sizeof(gReport)-got);
|
||||
|
||||
if (bytes > 0) got += bytes;
|
||||
else break;
|
||||
|
||||
r = 0;
|
||||
|
||||
while (got >= sizeof(gpioReport_t))
|
||||
{
|
||||
dispatch_notification(&gReport[r]);
|
||||
|
||||
r++;
|
||||
|
||||
got -= sizeof(gpioReport_t);
|
||||
}
|
||||
|
||||
/* copy any partial report to start of array */
|
||||
|
||||
if (got && r) gReport[0] = gReport[r];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void findNotifyBits(void)
|
||||
{
|
||||
callback_t *p;
|
||||
uint32_t bits = 0;
|
||||
|
||||
p = gCallBackFirst;
|
||||
|
||||
while (p)
|
||||
{
|
||||
bits |= (1<<(p->gpio));
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (bits != gNotifyBits)
|
||||
{
|
||||
gNotifyBits = bits;
|
||||
pigpio_command(gPigCommand, PI_CMD_NB, gPigHandle, gNotifyBits);
|
||||
}
|
||||
}
|
||||
|
||||
static void _wfe(int gpio, int level, uint32_t tick, void *user)
|
||||
{
|
||||
*(int *)user = 1;
|
||||
}
|
||||
|
||||
static int intCallback(int gpio, int edge, void *f, void *user, int ex)
|
||||
{
|
||||
static int id = 0;
|
||||
callback_t *p;
|
||||
|
||||
if ((gpio >=0) && (gpio < 32) && (edge >=0) && (edge <= 2) && f)
|
||||
{
|
||||
/* prevent duplicates */
|
||||
|
||||
p = gCallBackFirst;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if ((p->gpio == gpio) && (p->edge == edge) && (p->f == f))
|
||||
{
|
||||
return pigif_duplicate_callback;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
p = malloc(sizeof(callback_t));
|
||||
|
||||
if (p)
|
||||
{
|
||||
if (!gCallBackFirst) gCallBackFirst = p;
|
||||
|
||||
p->id = id++;
|
||||
p->gpio = gpio;
|
||||
p->edge = edge;
|
||||
p->f = f;
|
||||
p->user = user;
|
||||
p->ex = ex;
|
||||
p->next = 0;
|
||||
p->prev = gCallBackLast;
|
||||
|
||||
if (p->prev) (p->prev)->next = p;
|
||||
gCallBackLast = p;
|
||||
|
||||
findNotifyBits();
|
||||
|
||||
return p->id;
|
||||
}
|
||||
|
||||
return pigif_bad_malloc;
|
||||
}
|
||||
|
||||
return pigif_bad_callback;
|
||||
}
|
||||
|
||||
/* PUBLIC ----------------------------------------------------------------- */
|
||||
|
||||
double time_time(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
double t;
|
||||
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
t = (double)tv.tv_sec + ((double)tv.tv_usec / 1E6);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void time_sleep(double seconds)
|
||||
{
|
||||
struct timespec ts, rem;
|
||||
|
||||
if (seconds > 0.0)
|
||||
{
|
||||
ts.tv_sec = seconds;
|
||||
ts.tv_nsec = (seconds-(double)ts.tv_sec) * 1E9;
|
||||
|
||||
while (clock_nanosleep(CLOCK_REALTIME, 0, &ts, &rem))
|
||||
{
|
||||
/* copy remaining time to ts */
|
||||
ts.tv_sec = rem.tv_sec;
|
||||
ts.tv_nsec = rem.tv_nsec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *pigpio_error(int error)
|
||||
{
|
||||
if (error > -1000) return cmdErrStr(error);
|
||||
else
|
||||
{
|
||||
switch(error)
|
||||
{
|
||||
case pigif_bad_send:
|
||||
return "failed to send to pigpiod";
|
||||
case pigif_bad_recv:
|
||||
return "failed to receive from pigpiod";
|
||||
case pigif_bad_getaddrinfo:
|
||||
return "failed to find address of pigpiod";
|
||||
case pigif_bad_connect:
|
||||
return "failed to connect to pigpiod";
|
||||
case pigif_bad_socket:
|
||||
return "failed to create socket";
|
||||
case pigif_bad_noib:
|
||||
return "failed to open noib";
|
||||
case pigif_duplicate_callback:
|
||||
return "identical callback exists";
|
||||
case pigif_bad_malloc:
|
||||
return "failed to malloc";
|
||||
case pigif_bad_callback:
|
||||
return "bad callback parameter";
|
||||
case pigif_notify_failed:
|
||||
return "failed to create notification thread";
|
||||
case pigif_callback_not_found:
|
||||
return "callback not found";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned pigpiod_if_version(void)
|
||||
{
|
||||
return PIGPIOD_IF_VERSION;
|
||||
}
|
||||
|
||||
pthread_t *start_thread(ThreadFunc_t func, void *arg)
|
||||
{
|
||||
pthread_t *pth;
|
||||
pthread_attr_t pthAttr;
|
||||
|
||||
pth = malloc(sizeof(pthread_t));
|
||||
|
||||
if (pth)
|
||||
{
|
||||
if (pthread_attr_init(&pthAttr))
|
||||
{
|
||||
perror("pthread_attr_init failed");
|
||||
free(pth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pthread_attr_setstacksize(&pthAttr, STACK_SIZE))
|
||||
{
|
||||
perror("pthread_attr_setstacksize failed");
|
||||
free(pth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pthread_create(pth, &pthAttr, func, arg))
|
||||
{
|
||||
perror("pthread_create socket failed");
|
||||
free(pth);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return pth;
|
||||
}
|
||||
|
||||
void stop_thread(pthread_t *pth)
|
||||
{
|
||||
if (pth)
|
||||
{
|
||||
pthread_cancel(*pth);
|
||||
pthread_join(*pth, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int pigpio_start(char *addrStr, char *portStr)
|
||||
{
|
||||
if (!gPigStarted)
|
||||
{
|
||||
gPigCommand = pigpioOpenSocket(addrStr, portStr);
|
||||
|
||||
if (gPigCommand >= 0)
|
||||
{
|
||||
gPigNotify = pigpioOpenSocket(addrStr, portStr);
|
||||
|
||||
if (gPigNotify >= 0)
|
||||
{
|
||||
gPigHandle = pigpio_command(gPigNotify, PI_CMD_NOIB, 0, 0);
|
||||
|
||||
if (gPigHandle < 0) return pigif_bad_noib;
|
||||
else
|
||||
{
|
||||
pthNotify = start_thread(pthNotifyThread, 0);
|
||||
if (pthNotify)
|
||||
{
|
||||
gPigStarted = 1;
|
||||
return 0;
|
||||
}
|
||||
else return pigif_notify_failed;
|
||||
}
|
||||
}
|
||||
else return gPigNotify;
|
||||
}
|
||||
else return gPigCommand;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pigpio_stop(void)
|
||||
{
|
||||
gPigStarted = 0;
|
||||
|
||||
if (pthNotify)
|
||||
{
|
||||
stop_thread(pthNotify);
|
||||
pthNotify = 0;
|
||||
}
|
||||
|
||||
if (gPigNotify >= 0)
|
||||
{
|
||||
if (gPigHandle >= 0)
|
||||
{
|
||||
pigpio_command(gPigNotify, PI_CMD_NC, gPigHandle, 0);
|
||||
gPigHandle = -1;
|
||||
}
|
||||
|
||||
close(gPigNotify);
|
||||
gPigNotify = -1;
|
||||
}
|
||||
|
||||
if (gPigCommand >= 0)
|
||||
{
|
||||
if (gPigHandle >= 0)
|
||||
{
|
||||
pigpio_command(gPigCommand, PI_CMD_NC, gPigHandle, 0);
|
||||
gPigHandle = -1;
|
||||
}
|
||||
|
||||
close(gPigCommand);
|
||||
gPigCommand = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int set_mode(int gpio, int mode)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_MODES, gpio, mode);
|
||||
}
|
||||
|
||||
int get_mode(int gpio)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_MODEG, gpio, 0);
|
||||
}
|
||||
|
||||
int set_pull_up_down(int gpio, int pud)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PUD, gpio, pud);
|
||||
}
|
||||
|
||||
int read_gpio(int gpio)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_READ, gpio, 0);
|
||||
}
|
||||
|
||||
int write_gpio(int gpio, int level)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_WRITE, gpio, level);
|
||||
}
|
||||
|
||||
int set_PWM_dutycycle(int user_gpio, int dutycycle)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PWM, user_gpio, dutycycle);
|
||||
}
|
||||
|
||||
int set_PWM_range(int user_gpio, int range_)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PRS, user_gpio, range_);
|
||||
}
|
||||
|
||||
int get_PWM_range(int user_gpio)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PRG, user_gpio, 0);
|
||||
}
|
||||
|
||||
int get_PWM_real_range(int user_gpio)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PRRG, user_gpio, 0);
|
||||
}
|
||||
|
||||
int set_PWM_frequency(int user_gpio, int frequency)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PFS, user_gpio, frequency);
|
||||
}
|
||||
|
||||
int get_PWM_frequency(int user_gpio)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PFG, user_gpio, 0);
|
||||
}
|
||||
|
||||
int set_servo_pulsewidth(int user_gpio, int pulsewidth)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_SERVO, user_gpio, pulsewidth);
|
||||
}
|
||||
|
||||
int notify_open(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_NO, 0, 0);
|
||||
}
|
||||
|
||||
int notify_begin(int handle, uint32_t bits)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_NB, handle, bits);
|
||||
}
|
||||
|
||||
int notify_pause(int handle)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_NB, handle, 0);
|
||||
}
|
||||
|
||||
int notify_close(int handle)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_NC, handle, 0);
|
||||
}
|
||||
|
||||
int set_watchdog(int user_gpio, int timeout)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_WDOG, user_gpio, timeout);
|
||||
}
|
||||
|
||||
uint32_t read_bank_1(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BR1, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t read_bank_2(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BR2, 0, 0);
|
||||
}
|
||||
|
||||
int clear_bank_1(uint32_t levels)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BC1, levels, 0);
|
||||
}
|
||||
|
||||
int clear_bank_2(uint32_t levels)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BC2, levels, 0);
|
||||
}
|
||||
|
||||
int set_bank_1(uint32_t levels)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BS1, levels, 0);
|
||||
}
|
||||
|
||||
int set_bank_2(uint32_t levels)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_BS2, levels, 0);
|
||||
}
|
||||
|
||||
uint32_t get_current_tick(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_TICK, 0, 0);
|
||||
}
|
||||
|
||||
uint32_t get_hardware_revision(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_HWVER, 0, 0);
|
||||
}
|
||||
|
||||
unsigned get_pigpio_version(void)
|
||||
{
|
||||
return pigpio_command(gPigCommand, PI_CMD_PIGPV, 0, 0);
|
||||
}
|
||||
|
||||
int callback(int gpio, int edge, CBFunc_t f)
|
||||
{
|
||||
return intCallback(gpio, edge, f, 0, 0);
|
||||
}
|
||||
|
||||
int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user)
|
||||
{
|
||||
return intCallback(gpio, edge, f, user, 1);
|
||||
}
|
||||
|
||||
int callback_cancel(int id)
|
||||
{
|
||||
callback_t *p;
|
||||
|
||||
p = gCallBackFirst;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if (p->id == id)
|
||||
{
|
||||
if (p->prev) p->prev->next = p->next;
|
||||
else gCallBackFirst = p->next;
|
||||
|
||||
if (p->next) p->next->prev = p->prev;
|
||||
else gCallBackLast = p->prev;
|
||||
|
||||
free(p);
|
||||
|
||||
findNotifyBits();
|
||||
|
||||
return 0;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
return pigif_callback_not_found;
|
||||
}
|
||||
|
||||
int wait_for_edge(int gpio, int edge, double timeout)
|
||||
{
|
||||
int triggered = 0;
|
||||
int id;
|
||||
double due;
|
||||
|
||||
if (timeout <= 0.0) return 0;
|
||||
|
||||
due = time_time() + timeout;
|
||||
|
||||
id = callback_ex(gpio, edge, _wfe, &triggered);
|
||||
|
||||
while (!triggered && (time_time() < due)) time_sleep(0.1);
|
||||
|
||||
callback_cancel(id);
|
||||
|
||||
return triggered;
|
||||
}
|
||||
|
|
@ -0,0 +1,527 @@
|
|||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
#ifndef PIGPIOD_IF_H
|
||||
#define PIGPIOD_IF_H
|
||||
|
||||
#include "pigpio.h"
|
||||
|
||||
#define PIGPIOD_IF_VERSION 1
|
||||
|
||||
typedef enum
|
||||
{
|
||||
pigif_bad_send = -2000,
|
||||
pigif_bad_recv = -2001,
|
||||
pigif_bad_getaddrinfo = -2002,
|
||||
pigif_bad_connect = -2003,
|
||||
pigif_bad_socket = -2004,
|
||||
pigif_bad_noib = -2005,
|
||||
pigif_duplicate_callback = -2006,
|
||||
pigif_bad_malloc = -2007,
|
||||
pigif_bad_callback = -2008,
|
||||
pigif_notify_failed = -2009,
|
||||
pigif_callback_not_found = -2010,
|
||||
} piscopeError_t;
|
||||
|
||||
|
||||
typedef void (*CBFunc_t) (int gpio, int level, uint32_t tick);
|
||||
|
||||
typedef void (*CBFuncEx_t)(int gpio, int level, uint32_t tick, void * user);
|
||||
|
||||
typedef struct callback_s callback_t;
|
||||
|
||||
#define RISING_EDGE 0
|
||||
#define FALLING_EDGE 1
|
||||
#define EITHER_EDGE 2
|
||||
|
||||
double time_time(void);
|
||||
/* Return the current time in seconds since the Epoch.*/
|
||||
|
||||
void time_sleep(double seconds);
|
||||
/* Delay execution for a given number of seconds */
|
||||
|
||||
const char *pigpio_error(int error);
|
||||
/* Return a string for a pigpio library error. */
|
||||
|
||||
unsigned pigpiod_if_version(void);
|
||||
/* Return the pigpiod_if version. */
|
||||
|
||||
pthread_t *start_thread(ThreadFunc_t func, void *arg);
|
||||
/* Starts a new thread of execution with func as the main routine.
|
||||
|
||||
Returns a pointer to pthread_t if OK, otherwise NULL.
|
||||
|
||||
The function is passed the single argument arg.
|
||||
|
||||
The thread can be cancelled by passing the pointer to pthread_t to
|
||||
gpioStopThread().
|
||||
*/
|
||||
|
||||
void stop_thread(pthread_t *pth);
|
||||
/* Cancels the thread pointed at by pth.
|
||||
|
||||
No value is returned.
|
||||
|
||||
The thread to be stopped should have been started with gpioStartThread().
|
||||
*/
|
||||
|
||||
int pigpio_start(char *addrStr, char *portStr);
|
||||
/* Connect to the pigpio daemon. Reserving command and
|
||||
notification streams.
|
||||
|
||||
addrStr specifies the host or IP address of the Pi running
|
||||
the pigpio daemon. It may be NULL in which case localhost
|
||||
is used unless overriden by the PIGPIO_ADDR environment
|
||||
variable.
|
||||
|
||||
portStr specifies the port address used by the Pi running
|
||||
the pigpio daemon. It may be NULL in which case "8888"
|
||||
is used unless overriden by the PIGPIO_PORT environment
|
||||
variable.
|
||||
*/
|
||||
|
||||
void pigpio_stop(void);
|
||||
/*
|
||||
Terminates the connection to the pigpio daemon and releases
|
||||
resources used by the library.
|
||||
*/
|
||||
|
||||
int set_mode(int gpio, int mode);
|
||||
/* Set the gpio mode.
|
||||
|
||||
gpio: 0-53.
|
||||
mode: INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_MODE,
|
||||
or PI_NOT_PERMITTED.
|
||||
*/
|
||||
|
||||
int get_mode(int gpio);
|
||||
/* Get the gpio mode.
|
||||
|
||||
Returns the gpio mode if OK, otherwise PI_BAD_GPIO.
|
||||
|
||||
gpio: 0-53.
|
||||
*/
|
||||
|
||||
int set_pull_up_down(int gpio, int pud);
|
||||
/* Set or clear the gpio pull-up/down resistor.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_PUD,
|
||||
or PI_NOT_PERMITTED.
|
||||
|
||||
gpio: 0-53.
|
||||
pud: PUD_UP, PUD_DOWN, PUD_OFF.
|
||||
*/
|
||||
|
||||
int read_gpio(int gpio);
|
||||
/* Read the gpio level.
|
||||
|
||||
Returns the gpio level if OK, otherwise PI_BAD_GPIO.
|
||||
|
||||
gpio:0-53.
|
||||
*/
|
||||
|
||||
int write_gpio(int gpio, int level);
|
||||
/*
|
||||
Write the gpio level.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_GPIO, PI_BAD_LEVEL,
|
||||
or PI_NOT_PERMITTED.
|
||||
|
||||
gpio: 0-53.
|
||||
level: 0, 1.
|
||||
|
||||
Notes
|
||||
|
||||
If PWM or servo pulses are active on the gpio they are switched off.
|
||||
*/
|
||||
|
||||
int set_PWM_dutycycle(int user_gpio, int dutycycle);
|
||||
/* Start (non-zero dutycycle) or stop (0) PWM pulses on the gpio.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYCYCLE,
|
||||
or PI_NOT_PERMITTED.
|
||||
|
||||
user_gpio: 0-31.
|
||||
dutycycle: 0-range (range defaults to 255).
|
||||
|
||||
Notes
|
||||
|
||||
The set_PWM_range() function can change the default range of 255.
|
||||
*/
|
||||
|
||||
int set_PWM_range(int user_gpio, int range_);
|
||||
/* Set the range of PWM values to be used on the gpio.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
|
||||
or PI_NOT_PERMITTED.
|
||||
|
||||
user_gpio: 0-31.
|
||||
range_: 25-40000.
|
||||
|
||||
Notes
|
||||
|
||||
If PWM is currently active on the gpio its dutycycle will be
|
||||
scaled to reflect the new range.
|
||||
|
||||
The real range, the number of steps between fully off and fully on
|
||||
for each of the 18 available gpio frequencies is
|
||||
|
||||
25(#1), 50(#2), 100(#3), 125(#4), 200(#5), 250(#6), 400(#7),
|
||||
500(#8), 625(#9), 800(#10), 1000(#11), 1250(#12), 2000(#13),
|
||||
2500(#14), 4000(#15), 5000(#16), 10000(#17), 20000(#18)
|
||||
|
||||
The real value set by set_PWM_range is
|
||||
(dutycycle * real range) / range.
|
||||
|
||||
*/
|
||||
|
||||
int get_PWM_range(int user_gpio);
|
||||
/* Get the range of PWM values being used on the gpio.
|
||||
|
||||
Returns the dutycycle range used for the gpio if OK,
|
||||
otherwise PI_BAD_USER_GPIO.
|
||||
|
||||
user_gpio: 0-31.
|
||||
*/
|
||||
|
||||
int get_PWM_real_range(int user_gpio);
|
||||
/* Get the real underlying range of PWM values being used on the gpio.
|
||||
|
||||
Returns the real range used for the gpio if OK,
|
||||
otherwise PI_BAD_USER_GPIO.
|
||||
|
||||
user_gpio: 0-31.
|
||||
*/
|
||||
|
||||
int set_PWM_frequency(int user_gpio, int frequency);
|
||||
/*
|
||||
Set the frequency (in Hz) of the PWM to be used on the gpio.
|
||||
|
||||
Returns the numerically closest frequency if OK, otherwise
|
||||
PI_BAD_USER_GPIO or PI_NOT_PERMITTED.
|
||||
|
||||
user_gpio: 0-31.
|
||||
frequency: 0- (Hz).
|
||||
|
||||
The selectable frequencies depend upon the sample rate which
|
||||
may be 1, 2, 4, 5, 8, or 10 microseconds (default 5). The
|
||||
sample rate is set when the C pigpio library is started.
|
||||
|
||||
Each gpio can be independently set to one of 18 different
|
||||
PWM frequencies.
|
||||
|
||||
If PWM is currently active on the gpio it will be switched
|
||||
off and then back on at the new frequency.
|
||||
|
||||
1us 40000, 20000, 10000, 8000, 5000, 4000, 2500, 2000, 1600,
|
||||
1250, 1000, 800, 500, 400, 250, 200, 100, 50
|
||||
|
||||
2us 20000, 10000, 5000, 4000, 2500, 2000, 1250, 1000, 800,
|
||||
625, 500, 400, 250, 200, 125, 100, 50, 25
|
||||
|
||||
4us 10000, 5000, 2500, 2000, 1250, 1000, 625, 500, 400,
|
||||
313, 250, 200, 125, 100, 63, 50, 25, 13
|
||||
|
||||
5us 8000, 4000, 2000, 1600, 1000, 800, 500, 400, 320,
|
||||
250, 200, 160, 100, 80, 50, 40, 20, 10
|
||||
|
||||
8us 5000, 2500, 1250, 1000, 625, 500, 313, 250, 200,
|
||||
156, 125, 100, 63, 50, 31, 25, 13, 6
|
||||
|
||||
10us 4000, 2000, 1000, 800, 500, 400, 250, 200, 160,
|
||||
125, 100, 80, 50, 40, 25, 20, 10, 5
|
||||
*/
|
||||
|
||||
int get_PWM_frequency(int user_gpio);
|
||||
/*
|
||||
Get the frequency of PWM being used on the gpio.
|
||||
|
||||
Returns the frequency (in hertz) used for the gpio if OK,
|
||||
otherwise PI_BAD_USER_GPIO.
|
||||
|
||||
user_gpio: 0-31.
|
||||
*/
|
||||
|
||||
int set_servo_pulsewidth(int user_gpio, int pulsewidth);
|
||||
/*
|
||||
Start (500-2500) or stop (0) servo pulses on the gpio.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_PULSEWIDTH or
|
||||
PI_NOT_PERMITTED.
|
||||
|
||||
user_gpio: 0-31.
|
||||
pulsewidth: 0 (off), 500 (most anti-clockwise) - 2500 (most clockwise).
|
||||
|
||||
The selected pulsewidth will continue to be transmitted until
|
||||
changed by a subsequent call to set_servo_pulsewidth().
|
||||
|
||||
The pulsewidths supported by servos varies and should probably be
|
||||
determined by experiment. A value of 1500 should always be safe and
|
||||
represents the mid-point of rotation.
|
||||
|
||||
You can DAMAGE a servo if you command it to move beyond its limits.
|
||||
|
||||
OTHER UPDATE RATES:
|
||||
|
||||
This function updates servos at 50Hz. If you wish to use a different
|
||||
update frequency you will have to use the PWM functions.
|
||||
|
||||
Update Rate (Hz) 50 100 200 400 500
|
||||
1E6/Hz 20000 10000 5000 2500 2000
|
||||
|
||||
Firstly set the desired PWM frequency using set_PWM_frequency().
|
||||
|
||||
Then set the PWM range using set_PWM_range() to 1E6/Hz.
|
||||
Doing this allows you to use units of microseconds when setting
|
||||
the servo pulse width.
|
||||
|
||||
E.g. If you want to update a servo connected to gpio 25 at 400Hz
|
||||
|
||||
set_PWM_frequency(25, 400);
|
||||
set_PWM_range(25, 2500);
|
||||
|
||||
Thereafter use the set_PWM_dutycycle() function to move the servo,
|
||||
e.g. set_PWM_dutycycle(25, 1500) will set a 1500 us pulse.
|
||||
*/
|
||||
|
||||
int notify_open(void);
|
||||
/*
|
||||
Get a free notification handle.
|
||||
|
||||
Returns a handle greater than or equal to zero if OK,
|
||||
otherwise PI_NO_HANDLE.
|
||||
|
||||
A notification is a method for being notified of gpio state
|
||||
changes via a pipe.
|
||||
|
||||
Pipes are only accessible from the local machine so this function
|
||||
serves no purpose if you are using the library from a remote machine.
|
||||
The in-built (socket) notifications provided by callback()
|
||||
should be used instead.
|
||||
|
||||
Notifications for handle x will be available at the pipe
|
||||
named /dev/pigpiox (where x is the handle number).
|
||||
E.g. if the function returns 15 then the notifications must be
|
||||
read from /dev/pigpio15.
|
||||
*/
|
||||
|
||||
int notify_begin(int handle, uint32_t bits);
|
||||
/*
|
||||
Start notifications on a previously opened handle.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_HANDLE.
|
||||
|
||||
handle: 0-31 (as returned by notify_open())
|
||||
bits: a mask indicating the gpios to be notified.
|
||||
|
||||
The notification sends state changes for each gpio whose
|
||||
corresponding bit in bits is set.
|
||||
|
||||
Notes
|
||||
|
||||
Each notification occupies 12 bytes in the fifo as follows:
|
||||
|
||||
H (16 bit) seqno
|
||||
H (16 bit) flags
|
||||
I (32 bit) tick
|
||||
I (32 bit) level
|
||||
*/
|
||||
|
||||
int notify_pause(int handle);
|
||||
/*
|
||||
Pause notifications on a previously opened handle.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_HANDLE.
|
||||
|
||||
handle: 0-31 (as returned by notify_open())
|
||||
|
||||
Notifications for the handle are suspended until
|
||||
notify_begin() is called again.
|
||||
*/
|
||||
|
||||
int notify_close(int handle);
|
||||
/*
|
||||
Stop notifications on a previously opened handle and
|
||||
release the handle for reuse.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_HANDLE.
|
||||
|
||||
handle: 0-31 (as returned by notify_open())
|
||||
*/
|
||||
|
||||
int set_watchdog(int user_gpio, int timeout);
|
||||
/*
|
||||
Sets a watchdog for a gpio.
|
||||
|
||||
Returns 0 if OK, otherwise PI_BAD_USER_GPIO
|
||||
or PI_BAD_WDOG_TIMEOUT.
|
||||
|
||||
user_gpio: 0-31.
|
||||
timeout: 0-60000.
|
||||
|
||||
The watchdog is nominally in milliseconds.
|
||||
|
||||
Only one watchdog may be registered per gpio.
|
||||
|
||||
The watchdog may be cancelled by setting timeout to 0.
|
||||
|
||||
If no level change has been detected for the gpio for timeout
|
||||
milliseconds any notification for the gpio has a report written
|
||||
to the fifo with the flags set to indicate a watchdog timeout.
|
||||
|
||||
The callback() and callback_ex functions interpret the flags and will
|
||||
call registered callbacks for the gpio with level TIMEOUT.
|
||||
*/
|
||||
|
||||
uint32_t read_bank_1(void);
|
||||
/*
|
||||
Read the levels of the bank 1 gpios (gpios 0-31).
|
||||
|
||||
The returned 32 bit integer has a bit set if the corresponding
|
||||
gpio is logic 1. Gpio n has bit value (1<<n).
|
||||
*/
|
||||
|
||||
uint32_t read_bank_2(void);
|
||||
/*
|
||||
Read the levels of the bank 2 gpios (gpios 32-53).
|
||||
|
||||
The returned 32 bit integer has a bit set if the corresponding
|
||||
gpio is logic 1. Gpio n has bit value (1<<(n-32)).
|
||||
*/
|
||||
|
||||
int clear_bank_1(uint32_t levels);
|
||||
/*
|
||||
Clears gpios 0-31 if the corresponding bit in levels is set.
|
||||
|
||||
Returns 0 if OK, otherwise PI_SOME_PERMITTED.
|
||||
|
||||
A status of PI_SOME_PERMITTED indicates that the user is not
|
||||
allowed to write to one or more of the gpios.
|
||||
|
||||
levels: a bit mask with 1 set if the corresponding gpio is
|
||||
to be cleared.
|
||||
*/
|
||||
|
||||
int clear_bank_2(uint32_t levels);
|
||||
/*
|
||||
Clears gpios 32-53 if the corresponding bit (0-21) in levels is set.
|
||||
|
||||
Returns 0 if OK, otherwise PI_SOME_PERMITTED.
|
||||
|
||||
A status of PI_SOME_PERMITTED indicates that the user is not
|
||||
allowed to write to one or more of the gpios.
|
||||
|
||||
levels: a bit mask with 1 set if the corresponding gpio is
|
||||
to be cleared.
|
||||
*/
|
||||
|
||||
int set_bank_1(uint32_t levels);
|
||||
/*
|
||||
Sets gpios 0-31 if the corresponding bit in levels is set.
|
||||
|
||||
Returns 0 if OK, otherwise PI_SOME_PERMITTED.
|
||||
|
||||
A status of PI_SOME_PERMITTED indicates that the user is not
|
||||
allowed to write to one or more of the gpios.
|
||||
|
||||
levels: a bit mask with 1 set if the corresponding gpio is
|
||||
to be set.
|
||||
*/
|
||||
|
||||
int set_bank_2(uint32_t levels);
|
||||
/*
|
||||
Sets gpios 32-53 if the corresponding bit (0-21) in levels is set.
|
||||
|
||||
Returns 0 if OK, otherwise PI_SOME_PERMITTED.
|
||||
|
||||
A status of PI_SOME_PERMITTED indicates that the user is not
|
||||
allowed to write to one or more of the gpios.
|
||||
|
||||
levels: a bit mask with 1 set if the corresponding gpio is
|
||||
to be set.
|
||||
*/
|
||||
|
||||
uint32_t get_current_tick(void);
|
||||
/*
|
||||
|
||||
Gets the current system tick.
|
||||
|
||||
Tick is the number of microseconds since system boot.
|
||||
|
||||
As tick is an unsigned 32 bit quantity it wraps around after
|
||||
2**32 microseconds, which is approximately 1 hour 12 minutes.
|
||||
|
||||
*/
|
||||
|
||||
uint32_t get_hardware_revision(void);
|
||||
/*
|
||||
Get the Pi's hardware revision number.
|
||||
|
||||
It is unfortunate that Pi boards have been named Revision.1 and
|
||||
Revision.2. That use of the word revision is distinct from the
|
||||
Pi's hardware revision number.'
|
||||
|
||||
The hardware revision is the last 4 characters on the Revision line
|
||||
of /proc/cpuinfo.
|
||||
|
||||
The revision number can be used to determine the assignment of gpios
|
||||
to pins.
|
||||
|
||||
There are at least two types of board.
|
||||
|
||||
Type 1 has gpio 0 on P1-3, gpio 1 on P1-5, and gpio 21 on P1-13.
|
||||
Type 2 has gpio 2 on P1-3, gpio 3 on P1-5, gpio 27 on P1-13, and
|
||||
gpios 28-31 on P5.
|
||||
|
||||
Type 1 boards have hardware revision numbers of 2 and 3.
|
||||
|
||||
Type 2 boards have hardware revision numbers of 4, 5, 6, and 15.
|
||||
|
||||
If the hardware revision can not be found or is not a valid
|
||||
hexadecimal number the function returns 0.
|
||||
*/
|
||||
|
||||
int callback(int gpio, int edge, CBFunc_t f);
|
||||
/*
|
||||
*/
|
||||
|
||||
int callback_ex(int gpio, int edge, CBFuncEx_t f, void *user);
|
||||
/*
|
||||
*/
|
||||
|
||||
int callback_cancel(int id);
|
||||
/*
|
||||
*/
|
||||
|
||||
int wait_for_edge(int gpio, int edge, double timeout);
|
||||
/*
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue