@@ -1 +1 @@ | |||
2.39 | |||
2.44 |
@@ -161,6 +161,14 @@ fi | |||
check_make_ok | |||
# echo | |||
# echo "wiringPi Daemon" | |||
# cd ../wiringPiD | |||
# make -j5 | |||
# check_make_ok | |||
# $sudo make install | |||
# check_make_ok | |||
# echo | |||
# echo "Examples" | |||
# cd ../examples | |||
# make | |||
@@ -1,5 +1,5 @@ | |||
Package: wiringpi | |||
Version: 2.38 | |||
Version: 2.44 | |||
Section: libraries | |||
Priority: optional | |||
Architecture: armhf | |||
@@ -33,7 +33,7 @@ INCLUDE = -I/usr/local/include | |||
CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe | |||
LDFLAGS = -L/usr/local/lib | |||
LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm | |||
LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt | |||
# Should not alter anything below this line | |||
############################################################################### | |||
@@ -0,0 +1,61 @@ | |||
/* | |||
* blink8-drcn.c: | |||
* Simple sequence over the first 8 GPIO pins - LEDs | |||
* Aimed at the Ladder board, but it's fairly generic. | |||
* | |||
* Copyright (c) 2012-2013 Gordon Henderson. <projects@drogon.net> | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <stdio.h> | |||
#include <wiringPi.h> | |||
#include <drcNet.h> | |||
int main (void) | |||
{ | |||
int i, led ; | |||
printf ("Raspberry Pi - 8-LED Sequencer\n") ; | |||
printf ("==============================\n") ; | |||
printf ("\n") ; | |||
printf ("Connect LEDs to the first 8 GPIO pins and watch ...\n") ; | |||
int pinBase = 100 ; | |||
// wiringPiSetup () ; | |||
drcSetupNet (pinBase, 100, "192.168.254.21", "6124", "123456") ; | |||
for (i = 0 ; i < 8 ; ++i) | |||
pinMode (i + pinBase, OUTPUT) ; | |||
for (;;) | |||
{ | |||
for (led = 0 ; led < 8 ; ++led) | |||
{ | |||
digitalWrite (led + pinBase, 1) ; | |||
delay (10) ; | |||
} | |||
for (led = 0 ; led < 8 ; ++led) | |||
{ | |||
digitalWrite (led + pinBase, 0) ; | |||
delay (10) ; | |||
} | |||
} | |||
} |
@@ -37,7 +37,7 @@ INCLUDE = -I$(DESTDIR)$(PREFIX)/include | |||
CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe | |||
LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib | |||
LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm | |||
LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt | |||
# May not need to alter anything below this line | |||
############################################################################### | |||
@@ -9,15 +9,15 @@ gpio \- Command-line access to Raspberry Pi's GPIO | |||
.PP | |||
.B gpio | |||
.B [ \-g | \-1 ] | |||
.B mode/read/write/aread/awrite/wb/pwm/clock ... | |||
.B mode/read/write/aread/awrite/wb/pwm/clock/toggle/blink ... | |||
.PP | |||
.B gpio | |||
.B [ \-x extension:params ] | |||
.B mode/read/write/aread/awrite/pwm/pwmTone ... | |||
.B mode/read/write/aread/awrite/pwm/toggle/blink ... | |||
.PP | |||
.B gpio | |||
.B [ \-p ] | |||
.B read/write/toggle/wb | |||
.B read/write/toggle/blink | |||
.B ... | |||
.PP | |||
.B gpio | |||
@@ -119,10 +119,22 @@ Write the given value (0 or 1) to the pin. You need to set the pin | |||
to output mode first. | |||
.TP | |||
.B toggle <pin> | |||
Changes the state of a GPIO pin; 0 to 1, or 1 to 0. | |||
Note unlike the blink command, the pin must be in output mode first. | |||
.TP | |||
.B blink <pin> | |||
Blinks the given pin on/off. Press Control-C to exit. | |||
Note: This command explicitly sets the pin to output mode. | |||
.TP | |||
.B aread <pin> | |||
Read the analog value of the given pin. This needs to be uses in | |||
Read the analog value of the given pin. This needs to be used in | |||
conjunction with a -x flag to add in an extension that handles analog | |||
inputs. respective logic levels. | |||
inputs. | |||
e.g. gpio -x mcp3002:200:0 aread 200 | |||
@@ -132,7 +144,7 @@ will read the first analog input on an mcp3002 SPI ADC chip. | |||
.B awrite <pin> <value> | |||
Write the analog value to the given pin. This needs to be used in | |||
conjunction with a -x flag to add in an extension that handles analog | |||
inputs. respective logic levels. | |||
inputs. | |||
e.g. gpio -x mcp4802:200:0 awrite 200 128 | |||
@@ -234,7 +246,7 @@ absolutely sure you know what you're doing. | |||
high | low | |||
Change the USB current limiter to high (1.2 amps) or low (the default, 600mA) | |||
This is only applicable to the model B+ | |||
This is only applicable to the Model B+ and the Model B, v2. | |||
.TP | |||
.B pwm-bal/pwm-ms | |||
@@ -253,7 +265,6 @@ them. Optionally it will set the I2C baudrate to that supplied in Kb/sec | |||
Note: On recent kernels with the device tree enabled you should use the | |||
raspi-config program to load/unload the I2C device at boot time. | |||
(or disable the device tree to continue to use this method) | |||
.TP | |||
.B load spi | |||
@@ -268,7 +279,6 @@ e.g. 8192 bytes then reboot. | |||
Note: On recent kernels with the device tree enabled you should use the | |||
raspi-config program to load/unload the SPI device at boot time. | |||
(or disable the device tree to continue to use this method) | |||
.TP | |||
.B gbr | |||
@@ -1443,6 +1443,16 @@ int main (int argc, char *argv []) | |||
wpMode = WPI_MODE_PIFACE ; | |||
} | |||
// Check for -z argument so we don't actually initialise wiringPi | |||
else if (strcasecmp (argv [1], "-z") == 0) | |||
{ | |||
for (i = 2 ; i < argc ; ++i) | |||
argv [i - 1] = argv [i] ; | |||
--argc ; | |||
wpMode = WPI_MODE_UNINITIALISED ; | |||
} | |||
// Default to wiringPi mode | |||
else | |||
@@ -1460,12 +1470,15 @@ int main (int argc, char *argv []) | |||
{ | |||
if (argc < 3) | |||
{ | |||
fprintf (stderr, "%s: -x missing extension specification.\n", argv [0]) ; | |||
fprintf (stderr, "%s: -x missing extension command.\n", argv [0]) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
if (!loadWPiExtension (argv [0], argv [2], TRUE)) // Prints its own error messages | |||
if (!loadWPiExtension (argv [0], argv [2], TRUE)) | |||
{ | |||
fprintf (stderr, "%s: Extension load failed: %s\n", argv [0], strerror (errno)) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Shift args down by 2 | |||
@@ -299,6 +299,8 @@ static void plus2header (int model) | |||
printf (" +-----+-----+---------+------+---+--B Plus--+---+------+---------+-----+-----+\n") ; | |||
else if (model == PI_MODEL_ZERO) | |||
printf (" +-----+-----+---------+------+---+-Pi Zero--+---+------+---------+-----+-----+\n") ; | |||
else if (model == PI_MODEL_ZERO_W) | |||
printf (" +-----+-----+---------+------+---+-Pi ZeroW-+---+------+---------+-----+-----+\n") ; | |||
else if (model == PI_MODEL_2) | |||
printf (" +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+\n") ; | |||
else if (model == PI_MODEL_3) | |||
@@ -346,7 +348,7 @@ void doReadall (void) | |||
/**/ if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) | |||
abReadall (model, rev) ; | |||
else if ((model == PI_MODEL_BP) || (model == PI_MODEL_AP) || (model == PI_MODEL_2) || (model == PI_MODEL_3) || (model == PI_MODEL_ZERO)) | |||
else if ((model == PI_MODEL_BP) || (model == PI_MODEL_AP) || (model == PI_MODEL_2) || (model == PI_MODEL_3) || (model == PI_MODEL_ZERO) || (model == PI_MODEL_ZERO_W)) | |||
piPlusReadall (model) ; | |||
else if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) | |||
allReadall () ; | |||
@@ -1,3 +1,3 @@ | |||
#define VERSION "2.38" | |||
#define VERSION "2.44" | |||
#define VERSION_MAJOR 2 | |||
#define VERSION_MINOR 38 | |||
#define VERSION_MINOR 44 |
@@ -41,7 +41,7 @@ INCLUDE = -I. | |||
DEFS = -D_GNU_SOURCE | |||
CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Wextra -Winline $(INCLUDE) -pipe -fPIC | |||
LIBS = -lm -lpthread -lrt | |||
LIBS = -lm -lpthread -lrt -lcrypt | |||
############################################################################### | |||
@@ -57,8 +57,8 @@ SRC = wiringPi.c \ | |||
mcp3002.c mcp3004.c mcp4802.c mcp3422.c \ | |||
max31855.c max5322.c ads1115.c \ | |||
sn3218.c \ | |||
bmp180.c htu21d.c ds18b20.c \ | |||
drcSerial.c \ | |||
bmp180.c htu21d.c ds18b20.c rht03.c \ | |||
drcSerial.c drcNet.c \ | |||
pseudoPins.c \ | |||
wpiExtensions.c | |||
@@ -0,0 +1,405 @@ | |||
/* | |||
* drcNet.h: | |||
* Extend wiringPi with the DRC Network protocol (e.g. to another Pi) | |||
* Copyright (c) 2016-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with wiringPi. | |||
* If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <stdio.h> | |||
#include <stdint.h> | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
#include <sys/socket.h> | |||
#include <arpa/inet.h> | |||
#include <netdb.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <crypt.h> | |||
#include "wiringPi.h" | |||
#include "drcNet.h" | |||
#include "../wiringPiD/drcNetCmd.h" | |||
/* | |||
* remoteReadline: | |||
* Read in a line of data from the remote server, ending with a newline | |||
* character which is not stored. Returns the length or < 0 on | |||
* any sort of failure. | |||
********************************************************************************* | |||
*/ | |||
static int remoteReadline (int fd, char *buf, int max) | |||
{ | |||
int len = 0 ; | |||
char c ; | |||
for (;;) | |||
{ | |||
if (read (fd, &c, 1) < 1) | |||
return -1 ; | |||
if (c == '\n') | |||
return len ; | |||
*buf++ = c ; | |||
if (++len == max) | |||
return len ; | |||
} | |||
} | |||
/* | |||
* getChallenge: | |||
* Read in lines from the remote site until we get one identified | |||
* as the challenge. This line contains the password salt. | |||
********************************************************************************* | |||
*/ | |||
static char *getChallenge (int fd) | |||
{ | |||
static char buf [1024] ; | |||
int num ; | |||
for (;;) | |||
{ | |||
if ((num = remoteReadline (fd, buf, 1023)) < 0) | |||
return NULL ; | |||
buf [num] = 0 ; | |||
if (strncmp (buf, "Challenge ", 10) == 0) | |||
return &buf [10] ; | |||
} | |||
} | |||
/* | |||
* authenticate: | |||
* Read in the challenge from the server, use it to encrypt our password | |||
* and send it back to the server. Wait for a reply back from the server | |||
* to say that we're good to go. | |||
* The server will simply disconnect on a bad response. No 3 chances here. | |||
********************************************************************************* | |||
*/ | |||
static int authenticate (int fd, const char *pass) | |||
{ | |||
char *challenge ; | |||
char *encrypted ; | |||
char salted [1024] ; | |||
if ((challenge = getChallenge (fd)) == NULL) | |||
return -1 ; | |||
sprintf (salted, "$6$%s$", challenge) ; | |||
encrypted = crypt (pass, salted) ; | |||
// This is an assertion, or sanity check on my part... | |||
// The '20' comes from the $6$ then the 16 characters of the salt, | |||
// then the terminating $. | |||
if (strncmp (encrypted, salted, 20) != 0) | |||
{ | |||
errno = EBADE ; | |||
return -1 ; | |||
} | |||
// 86 characters is the length of the SHA-256 hash | |||
if (write (fd, encrypted + 20, 86) == 86) | |||
return 0 ; | |||
else | |||
return -1 ; | |||
} | |||
/* | |||
* _drcSetupNet: | |||
* Do the hard work of establishing a network connection and authenticating | |||
* the password. | |||
********************************************************************************* | |||
*/ | |||
int _drcSetupNet (const char *ipAddress, const char *port, const char *password) | |||
{ | |||
struct addrinfo hints; | |||
struct addrinfo *result, *rp ; | |||
struct in6_addr serveraddr ; | |||
int remoteFd ; | |||
// Start by seeing if we've been given a (textual) numeric IP address | |||
// which will save lookups in getaddrinfo() | |||
memset (&hints, 0, sizeof (hints)) ; | |||
hints.ai_flags = AI_NUMERICSERV ; | |||
hints.ai_family = AF_UNSPEC ; | |||
hints.ai_socktype = SOCK_STREAM ; | |||
hints.ai_protocol = 0 ; | |||
if (inet_pton (AF_INET, ipAddress, &serveraddr) == 1) // Valid IPv4 | |||
{ | |||
hints.ai_family = AF_INET ; | |||
hints.ai_flags |= AI_NUMERICHOST ; | |||
} | |||
else | |||
{ | |||
if (inet_pton (AF_INET6, ipAddress, &serveraddr) == 1) // Valid IPv6 | |||
{ | |||
hints.ai_family = AF_INET6 ; | |||
hints.ai_flags |= AI_NUMERICHOST ; | |||
} | |||
} | |||
// Now use getaddrinfo() with the newly supplied hints | |||
if (getaddrinfo (ipAddress, port, &hints, &result) != 0) | |||
return -1 ; | |||
// Now try each address in-turn until we get one that connects... | |||
for (rp = result; rp != NULL; rp = rp->ai_next) | |||
{ | |||
if ((remoteFd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) | |||
continue ; | |||
if (connect (remoteFd, rp->ai_addr, rp->ai_addrlen) < 0) | |||
continue ; | |||
if (authenticate (remoteFd, password) < 0) | |||
{ | |||
close (remoteFd) ; | |||
errno = EACCES ; // Permission denied | |||
return -1 ; | |||
} | |||
else | |||
return remoteFd ; | |||
} | |||
errno = EHOSTUNREACH ; // Host unreachable - may not be right, but good enough | |||
return -1 ; // Nothing connected | |||
} | |||
/* | |||
* myPinMode: | |||
* Change the pin mode on the remote DRC device | |||
********************************************************************************* | |||
*/ | |||
static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_PIN_MODE ; | |||
cmd.data = mode ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
/* | |||
* myPullUpDnControl: | |||
********************************************************************************* | |||
*/ | |||
static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_PULL_UP_DN ; | |||
cmd.data = mode ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
/* | |||
* myDigitalWrite: | |||
********************************************************************************* | |||
*/ | |||
static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_DIGITAL_WRITE ; | |||
cmd.data = value ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
/* | |||
* myDigitalWrite8: | |||
********************************************************************************* | |||
static void myDigitalWrite8 (struct wiringPiNodeStruct *node, int pin, int value) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_DIGITAL_WRITE8 ; | |||
cmd.data = value ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
*/ | |||
/* | |||
* myAnalogWrite: | |||
********************************************************************************* | |||
*/ | |||
static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_ANALOG_WRITE ; | |||
cmd.data = value ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
/* | |||
* myPwmWrite: | |||
********************************************************************************* | |||
*/ | |||
static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_PWM_WRITE ; | |||
cmd.data = value ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
} | |||
/* | |||
* myAnalogRead: | |||
********************************************************************************* | |||
*/ | |||
static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_ANALOG_READ ; | |||
cmd.data = 0 ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
return cmd.data ; | |||
} | |||
/* | |||
* myDigitalRead: | |||
********************************************************************************* | |||
*/ | |||
static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_DIGITAL_READ ; | |||
cmd.data = 0 ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
return cmd.data ; | |||
} | |||
/* | |||
* myDigitalRead8: | |||
********************************************************************************* | |||
static unsigned int myDigitalRead8 (struct wiringPiNodeStruct *node, int pin) | |||
{ | |||
struct drcNetComStruct cmd ; | |||
cmd.pin = pin - node->pinBase ; | |||
cmd.cmd = DRCN_DIGITAL_READ8 ; | |||
cmd.data = 0 ; | |||
(void)send (node->fd, &cmd, sizeof (cmd), 0) ; | |||
(void)recv (node->fd, &cmd, sizeof (cmd), 0) ; | |||
return cmd.data ; | |||
} | |||
*/ | |||
/* | |||
* drcNet: | |||
* Create a new instance of an DRC GPIO interface. | |||
* Could be a variable nunber of pins here - we might not know in advance. | |||
********************************************************************************* | |||
*/ | |||
int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) | |||
{ | |||
int fd, len ; | |||
struct wiringPiNodeStruct *node ; | |||
if ((fd = _drcSetupNet (ipAddress, port, password)) < 0) | |||
return FALSE ; | |||
len = sizeof (struct drcNetComStruct) ; | |||
if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) | |||
return FALSE ; | |||
node = wiringPiNewNode (pinBase, numPins) ; | |||
node->fd = fd ; | |||
node->pinMode = myPinMode ; | |||
node->pullUpDnControl = myPullUpDnControl ; | |||
node->analogRead = myAnalogRead ; | |||
node->analogRead = myAnalogRead ; | |||
node->analogWrite = myAnalogWrite ; | |||
node->digitalRead = myDigitalRead ; | |||
node->digitalWrite = myDigitalWrite ; | |||
//node->digitalRead8 = myDigitalRead8 ; | |||
//node->digitalWrite8 = myDigitalWrite8 ; | |||
node->pwmWrite = myPwmWrite ; | |||
return TRUE ; | |||
} |
@@ -0,0 +1,42 @@ | |||
/* | |||
* drcNet.h: | |||
* Extend wiringPi with the DRC Network protocol (e.g. to another Pi) | |||
* Copyright (c) 2016-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with wiringPi. | |||
* If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
/********* | |||
struct drcNetStruct | |||
{ | |||
uint32_t pin ; | |||
uint32_t cmd ; | |||
uint32_t data ; | |||
} ; | |||
**************/ | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
extern int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) ; | |||
#ifdef __cplusplus | |||
} | |||
#endif |
@@ -0,0 +1,252 @@ | |||
/* | |||
* rht03.c: | |||
* Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. | |||
* Copyright (c) 2016-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with wiringPi. | |||
* If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <sys/time.h> | |||
#include <stdio.h> | |||
#include <stdio.h> | |||
#include <time.h> | |||
#include "wiringPi.h" | |||
#include "rht03.h" | |||
/* | |||
* maxDetectLowHighWait: | |||
* Wait for a transition from low to high on the bus | |||
********************************************************************************* | |||
*/ | |||
static int maxDetectLowHighWait (const int pin) | |||
{ | |||
struct timeval now, timeOut, timeUp ; | |||
// If already high then wait for pin to go low | |||
gettimeofday (&now, NULL) ; | |||
timerclear (&timeOut) ; | |||
timeOut.tv_usec = 1000 ; | |||
timeradd (&now, &timeOut, &timeUp) ; | |||
while (digitalRead (pin) == HIGH) | |||
{ | |||
gettimeofday (&now, NULL) ; | |||
if (timercmp (&now, &timeUp, >)) | |||
return FALSE ; | |||
} | |||
// Wait for it to go HIGH | |||
gettimeofday (&now, NULL) ; | |||
timerclear (&timeOut) ; | |||
timeOut.tv_usec = 1000 ; | |||
timeradd (&now, &timeOut, &timeUp) ; | |||
while (digitalRead (pin) == LOW) | |||
{ | |||
gettimeofday (&now, NULL) ; | |||
if (timercmp (&now, &timeUp, >)) | |||
return FALSE ; | |||
} | |||
return TRUE ; | |||
} | |||
/* | |||
* maxDetectClockByte: | |||
* Read in a single byte from the MaxDetect bus | |||
********************************************************************************* | |||
*/ | |||
static unsigned int maxDetectClockByte (const int pin) | |||
{ | |||
unsigned int byte = 0 ; | |||
int bit ; | |||
for (bit = 0 ; bit < 8 ; ++bit) | |||
{ | |||
if (!maxDetectLowHighWait (pin)) | |||
return 0 ; | |||
// bit starting now - we need to time it. | |||
delayMicroseconds (30) ; | |||
byte <<= 1 ; | |||
if (digitalRead (pin) == HIGH) // It's a 1 | |||
byte |= 1 ; | |||
} | |||
return byte ; | |||
} | |||
/* | |||
* maxDetectRead: | |||
* Read in and return the 4 data bytes from the MaxDetect sensor. | |||
* Return TRUE/FALSE depending on the checksum validity | |||
********************************************************************************* | |||
*/ | |||
static int maxDetectRead (const int pin, unsigned char buffer [4]) | |||
{ | |||
int i ; | |||
unsigned int checksum ; | |||
unsigned char localBuf [5] ; | |||
struct timeval now, then, took ; | |||
// See how long we took | |||
gettimeofday (&then, NULL) ; | |||
// Wake up the RHT03 by pulling the data line low, then high | |||
// Low for 10mS, high for 40uS. | |||
pinMode (pin, OUTPUT) ; | |||
digitalWrite (pin, 0) ; delay (10) ; | |||
digitalWrite (pin, 1) ; delayMicroseconds (40) ; | |||
pinMode (pin, INPUT) ; | |||
// Now wait for sensor to pull pin low | |||
if (!maxDetectLowHighWait (pin)) | |||
return FALSE ; | |||
// and read in 5 bytes (40 bits) | |||
for (i = 0 ; i < 5 ; ++i) | |||
localBuf [i] = maxDetectClockByte (pin) ; | |||
checksum = 0 ; | |||
for (i = 0 ; i < 4 ; ++i) | |||
{ | |||
buffer [i] = localBuf [i] ; | |||
checksum += localBuf [i] ; | |||
} | |||
checksum &= 0xFF ; | |||
// See how long we took | |||
gettimeofday (&now, NULL) ; | |||
timersub (&now, &then, &took) ; | |||
// Total time to do this should be: | |||
// 10mS + 40µS - reset | |||
// + 80µS + 80µS - sensor doing its low -> high thing | |||
// + 40 * (50µS + 27µS (0) or 70µS (1) ) | |||
// = 15010µS | |||
// so if we take more than that, we've had a scheduling interruption and the | |||
// reading is probably bogus. | |||
if ((took.tv_sec != 0) || (took.tv_usec > 16000)) | |||
return FALSE ; | |||
return checksum == localBuf [4] ; | |||
} | |||
/* | |||
* myReadRHT03: | |||
* Read the Temperature & Humidity from an RHT03 sensor | |||
* Values returned are *10, so 123 is 12.3. | |||
********************************************************************************* | |||
*/ | |||
static int myReadRHT03 (const int pin, int *temp, int *rh) | |||
{ | |||
int result ; | |||
unsigned char buffer [4] ; | |||
// Read ... | |||
result = maxDetectRead (pin, buffer) ; | |||
if (!result) | |||
return FALSE ; | |||
*rh = (buffer [0] * 256 + buffer [1]) ; | |||
*temp = (buffer [2] * 256 + buffer [3]) ; | |||
if ((*temp & 0x8000) != 0) // Negative | |||
{ | |||
*temp &= 0x7FFF ; | |||
*temp = -*temp ; | |||
} | |||
// Discard obviously bogus readings - the checksum can't detect a 2-bit error | |||
// (which does seem to happen - no realtime here) | |||
if ((*rh > 999) || (*temp > 800) || (*temp < -400)) | |||
return FALSE ; | |||
return TRUE ; | |||
} | |||
/* | |||
* myAnalogRead: | |||
********************************************************************************* | |||
*/ | |||
static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) | |||
{ | |||
int piPin = node->fd ; | |||
int chan = pin - node->pinBase ; | |||
int temp = -9997 ; | |||
int rh = -9997 ; | |||
int try ; | |||
if (chan > 1) | |||
return -9999 ; // Bad parameters | |||
for (try = 0 ; try < 10 ; ++try) | |||
{ | |||
if (myReadRHT03 (piPin, &temp, &rh)) | |||
return chan == 0 ? temp : rh ; | |||
} | |||
return -9998 ; | |||
} | |||
/* | |||
* rht03Setup: | |||
* Create a new instance of an RHT03 temperature sensor. | |||
********************************************************************************* | |||
*/ | |||
int rht03Setup (const int pinBase, const int piPin) | |||
{ | |||
struct wiringPiNodeStruct *node ; | |||
if ((piPin & PI_GPIO_MASK) != 0) // Must be an on-board pin | |||
return FALSE ; | |||
// 2 pins - temperature and humidity | |||
node = wiringPiNewNode (pinBase, 2) ; | |||
node->fd = piPin ; | |||
node->analogRead = myAnalogRead ; | |||
return TRUE ; | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* rht03.h: | |||
* Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. | |||
* Copyright (c) 2016-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with wiringPi. | |||
* If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
extern int rht03Setup (const int pinBase, const int devicePin) ; |
@@ -1,7 +1,7 @@ | |||
/* | |||
* softPwm.c: | |||
* Provide 2 channels of software driven PWM. | |||
* Copyright (c) 2012-2014 Gordon Henderson | |||
* Provide many channels of software driven PWM. | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
@@ -30,11 +30,11 @@ | |||
#include "softPwm.h" | |||
// MAX_PINS: | |||
// This is more than the number of Pi pins because we can actually softPwm | |||
// pins that are on GPIO expanders. It's not that efficient and more than 1 or | |||
// 2 pins on e.g. (SPI) mcp23s17 won't really be that effective, however... | |||
// This is more than the number of Pi pins because we can actually softPwm. | |||
// Once upon a time I let pins on gpio expanders be softPwm'd, but it's really | |||
// really not a good thing. | |||
#define MAX_PINS 1024 | |||
#define MAX_PINS 64 | |||
// The PWM Frequency is derived from the "pulse time" below. Essentially, | |||
// the frequency is a function of the range and this pulse time. | |||
@@ -45,7 +45,7 @@ | |||
// It's possible to get a higher frequency by lowering the pulse time, | |||
// however CPU uage will skyrocket as wiringPi uses a hard-loop to time | |||
// periods under 100µS - this is because the Linux timer calls are just | |||
// accurate at all, and have an overhead. | |||
// not accurate at all, and have an overhead. | |||
// | |||
// Another way to increase the frequency is to reduce the range - however | |||
// that reduces the overall output accuracy... | |||
@@ -106,14 +106,15 @@ static void *softPwmThread (void *arg) | |||
void softPwmWrite (int pin, int value) | |||
{ | |||
pin &= (MAX_PINS - 1) ; | |||
/**/ if (value < 0) | |||
value = 0 ; | |||
else if (value > range [pin]) | |||
value = range [pin] ; | |||
if (pin < MAX_PINS) | |||
{ | |||
/**/ if (value < 0) | |||
value = 0 ; | |||
else if (value > range [pin]) | |||
value = range [pin] ; | |||
marks [pin] = value ; | |||
marks [pin] = value ; | |||
} | |||
} | |||
@@ -129,6 +130,9 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) | |||
pthread_t myThread ; | |||
int *passPin ; | |||
if (pin >= MAX_PINS) | |||
return -1 ; | |||
if (range [pin] != 0) // Already running on this pin | |||
return -1 ; | |||
@@ -139,15 +143,15 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) | |||
if (passPin == NULL) | |||
return -1 ; | |||
pinMode (pin, OUTPUT) ; | |||
digitalWrite (pin, LOW) ; | |||
pinMode (pin, OUTPUT) ; | |||
marks [pin] = initialValue ; | |||
range [pin] = pwmRange ; | |||
*passPin = pin ; | |||
newPin = pin ; | |||
res = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ; | |||
newPin = pin ; | |||
res = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ; | |||
while (newPin != -1) | |||
delay (1) ; | |||
@@ -166,11 +170,14 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) | |||
void softPwmStop (int pin) | |||
{ | |||
if (range [pin] != 0) | |||
if (pin < MAX_PINS) | |||
{ | |||
pthread_cancel (threads [pin]) ; | |||
pthread_join (threads [pin], NULL) ; | |||
range [pin] = 0 ; | |||
digitalWrite (pin, LOW) ; | |||
if (range [pin] != 0) | |||
{ | |||
pthread_cancel (threads [pin]) ; | |||
pthread_join (threads [pin], NULL) ; | |||
range [pin] = 0 ; | |||
digitalWrite (pin, LOW) ; | |||
} | |||
} | |||
} |
@@ -84,10 +84,8 @@ | |||
#define ENV_GPIOMEM "WIRINGPI_GPIOMEM" | |||
// Mask for the bottom 64 pins which belong to the Raspberry Pi | |||
// The others are available for the other devices | |||
#define PI_GPIO_MASK (0xFFFFFFC0) | |||
// Extend wiringPi with other pin-based devices and keep track of | |||
// them in this structure | |||
struct wiringPiNodeStruct *wiringPiNodes = NULL ; | |||
@@ -224,7 +222,7 @@ const char *piModelNames [16] = | |||
"Pi Zero", // 09 | |||
"CM3", // 10 | |||
"Unknown11", // 11 | |||
"Unknown12", // 12 | |||
"Pi Zero-W", // 12 | |||
"Unknown13", // 13 | |||
"Unknown14", // 14 | |||
"Unknown15", // 15 | |||
@@ -1244,13 +1242,15 @@ struct wiringPiNodeStruct *wiringPiFindNode (int pin) | |||
********************************************************************************* | |||
*/ | |||
static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } | |||
static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } | |||
static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } | |||
static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } | |||
static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } | |||
static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } | |||
static unsigned int digitalRead8Dummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return 0 ; } | |||
static void digitalWrite8Dummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } | |||
static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } | |||
static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } | |||
struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) | |||
{ | |||
@@ -1272,17 +1272,19 @@ struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) | |||
if (node == NULL) | |||
(void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ; | |||
node->pinBase = pinBase ; | |||
node->pinMax = pinBase + numPins - 1 ; | |||
node->pinMode = pinModeDummy ; | |||
node->pullUpDnControl = pullUpDnControlDummy ; | |||
node->digitalRead = digitalReadDummy ; | |||
node->digitalWrite = digitalWriteDummy ; | |||
node->pwmWrite = pwmWriteDummy ; | |||
node->analogRead = analogReadDummy ; | |||
node->analogWrite = analogWriteDummy ; | |||
node->next = wiringPiNodes ; | |||
wiringPiNodes = node ; | |||
node->pinBase = pinBase ; | |||
node->pinMax = pinBase + numPins - 1 ; | |||
node->pinMode = pinModeDummy ; | |||
node->pullUpDnControl = pullUpDnControlDummy ; | |||
node->digitalRead = digitalReadDummy ; | |||
//node->digitalRead8 = digitalRead8Dummy ; | |||
node->digitalWrite = digitalWriteDummy ; | |||
//node->digitalWrite8 = digitalWrite8Dummy ; | |||
node->pwmWrite = pwmWriteDummy ; | |||
node->analogRead = analogReadDummy ; | |||
node->analogWrite = analogWriteDummy ; | |||
node->next = wiringPiNodes ; | |||
wiringPiNodes = node ; | |||
return node ; | |||
} | |||
@@ -1493,6 +1495,27 @@ int digitalRead (int pin) | |||
/* | |||
* digitalRead8: | |||
* Read 8-bits (a byte) from given start pin. | |||
********************************************************************************* | |||
unsigned int digitalRead8 (int pin) | |||
{ | |||
struct wiringPiNodeStruct *node = wiringPiNodes ; | |||
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin | |||
return 0 ; | |||
else | |||
{ | |||
if ((node = wiringPiFindNode (pin)) == NULL) | |||
return LOW ; | |||
return node->digitalRead8 (node, pin) ; | |||
} | |||
} | |||
*/ | |||
/* | |||
* digitalWrite: | |||
* Set an output bit | |||
********************************************************************************* | |||
@@ -1536,6 +1559,26 @@ void digitalWrite (int pin, int value) | |||
/* | |||
* digitalWrite8: | |||
* Set an output 8-bit byte on the device from the given pin number | |||
********************************************************************************* | |||
void digitalWrite8 (int pin, int value) | |||
{ | |||
struct wiringPiNodeStruct *node = wiringPiNodes ; | |||
if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin | |||
return ; | |||
else | |||
{ | |||
if ((node = wiringPiFindNode (pin)) != NULL) | |||
node->digitalWrite8 (node, pin, value) ; | |||
} | |||
} | |||
*/ | |||
/* | |||
* pwmWrite: | |||
* Set an output PWM value | |||
********************************************************************************* | |||
@@ -2144,9 +2187,10 @@ int wiringPiSetup (void) | |||
switch (model) | |||
{ | |||
case PI_MODEL_A: case PI_MODEL_B: | |||
case PI_MODEL_AP: case PI_MODEL_BP: | |||
case PI_ALPHA: case PI_MODEL_CM: case PI_MODEL_ZERO: | |||
case PI_MODEL_A: case PI_MODEL_B: | |||
case PI_MODEL_AP: case PI_MODEL_BP: | |||
case PI_ALPHA: case PI_MODEL_CM: | |||
case PI_MODEL_ZERO: case PI_MODEL_ZERO_W: | |||
piGpioBase = GPIO_PERI_BASE_OLD ; | |||
break ; | |||
@@ -26,6 +26,7 @@ | |||
// C doesn't have true/false by default and I can never remember which | |||
// way round they are, so ... | |||
// (and yes, I know about stdbool.h but I like capitals for these and I'm old) | |||
#ifndef TRUE | |||
# define TRUE (1==1) | |||
@@ -36,6 +37,11 @@ | |||
#define UNU __attribute__((unused)) | |||
// Mask for the bottom 64 pins which belong to the Raspberry Pi | |||
// The others are available for the other devices | |||
#define PI_GPIO_MASK (0xFFFFFFC0) | |||
// Handy defines | |||
// wiringPi modes | |||
@@ -92,6 +98,7 @@ | |||
#define PI_MODEL_3 8 | |||
#define PI_MODEL_ZERO 9 | |||
#define PI_MODEL_CM3 10 | |||
#define PI_MODEL_ZERO_W 12 | |||
#define PI_VERSION_1 0 | |||
#define PI_VERSION_1_1 1 | |||
@@ -140,13 +147,15 @@ struct wiringPiNodeStruct | |||
unsigned int data2 ; // ditto | |||
unsigned int data3 ; // ditto | |||
void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; | |||
void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; | |||
int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; | |||
void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; | |||
void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; | |||
void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; | |||
int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; | |||
//unsigned int (*digitalRead8) (struct wiringPiNodeStruct *node, int pin) ; | |||
void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
// void (*digitalWrite8) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; | |||
void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; | |||
struct wiringPiNodeStruct *next ; | |||
} ; | |||
@@ -179,14 +188,16 @@ extern int wiringPiSetupSys (void) ; | |||
extern int wiringPiSetupGpio (void) ; | |||
extern int wiringPiSetupPhys (void) ; | |||
extern void pinModeAlt (int pin, int mode) ; | |||
extern void pinMode (int pin, int mode) ; | |||
extern void pullUpDnControl (int pin, int pud) ; | |||
extern int digitalRead (int pin) ; | |||
extern void digitalWrite (int pin, int value) ; | |||
extern void pwmWrite (int pin, int value) ; | |||
extern int analogRead (int pin) ; | |||
extern void analogWrite (int pin, int value) ; | |||
extern void pinModeAlt (int pin, int mode) ; | |||
extern void pinMode (int pin, int mode) ; | |||
extern void pullUpDnControl (int pin, int pud) ; | |||
extern int digitalRead (int pin) ; | |||
extern void digitalWrite (int pin, int value) ; | |||
extern unsigned int digitalRead8 (int pin) ; | |||
extern void digitalWrite8 (int pin, int value) ; | |||
extern void pwmWrite (int pin, int value) ; | |||
extern int analogRead (int pin) ; | |||
extern void analogWrite (int pin, int value) ; | |||
// PiFace specifics | |||
// (Deprecated) | |||
@@ -204,12 +215,14 @@ extern int physPinToGpio (int physPin) ; | |||
extern void setPadDrive (int group, int value) ; | |||
extern int getAlt (int pin) ; | |||
extern void pwmToneWrite (int pin, int freq) ; | |||
extern void digitalWriteByte (int value) ; | |||
extern unsigned int digitalReadByte (void) ; | |||
extern void pwmSetMode (int mode) ; | |||
extern void pwmSetRange (unsigned int range) ; | |||
extern void pwmSetClock (int divisor) ; | |||
extern void gpioClockSet (int pin, int freq) ; | |||
extern unsigned int digitalReadByte (void) ; | |||
extern unsigned int digitalReadByte2 (void) ; | |||
extern void digitalWriteByte (int value) ; | |||
extern void digitalWriteByte2 (int value) ; | |||
// Interrupts | |||
// (Also Pi hardware specific) | |||
@@ -55,10 +55,13 @@ | |||
#include "ads1115.h" | |||
#include "sn3218.h" | |||
#include "drcSerial.h" | |||
#include "drcNet.h" | |||
#include "../wiringPiD/drcNetCmd.h" | |||
#include "pseudoPins.h" | |||
#include "bmp180.h" | |||
#include "htu21d.h" | |||
#include "ds18b20.h" | |||
#include "rht03.h" | |||
#include "wpiExtensions.h" | |||
@@ -134,12 +137,16 @@ static char *extractInt (char *progName, char *p, int *num) | |||
/* | |||
* extractStr: | |||
* Check & return a string at the given location (prefixed by a :) | |||
* Note: The string can be enclosed in []'s to escape colons. This is | |||
* so we can handle IPv6 addresses which contain colons and the []'s is | |||
* a common way to prepresent them. | |||
********************************************************************************* | |||
*/ | |||
static char *extractStr (char *progName, char *p, char **str) | |||
{ | |||
char *q, *r ; | |||
int quoted = FALSE ; | |||
if (*p != ':') | |||
{ | |||
@@ -149,21 +156,38 @@ static char *extractStr (char *progName, char *p, char **str) | |||
++p ; | |||
if (!isprint (*p)) | |||
if (*p == '[') | |||
{ | |||
quoted = TRUE ; | |||
++p ; | |||
} | |||
if (!isprint (*p)) // Is this needed? | |||
{ | |||
verbError ("%s: character expected", progName) ; | |||
return NULL ; | |||
} | |||
q = p ; | |||
while ((*q != 0) && (*q != ':')) | |||
++q ; | |||
if (quoted) | |||
{ | |||
while ((*q != 0) && (*q != ']')) | |||
++q ; | |||
} | |||
else | |||
{ | |||
while ((*q != 0) && (*q != ':')) | |||
++q ; | |||
} | |||
*str = r = calloc (q - p + 2, 1) ; // Zeros it | |||
while (p != q) | |||
*r++ = *p++ ; | |||
if (quoted) // Skip over the ] to the : | |||
++p ; | |||
return p ; | |||
} | |||
@@ -496,6 +520,24 @@ static int doExtensionDs18b20 (char *progName, int pinBase, char *params) | |||
/* | |||
* doExtensionRht03: | |||
* Maxdetect 1-Wire Temperature & Humidity | |||
* rht03:base:piPin | |||
********************************************************************************* | |||
*/ | |||
static int doExtensionRht03 (char *progName, int pinBase, char *params) | |||
{ | |||
int piPin ; | |||
if ((params = extractInt (progName, params, &piPin)) == NULL) | |||
return FALSE ; | |||
return rht03Setup (pinBase, piPin) ; | |||
} | |||
/* | |||
* doExtensionMax31855: | |||
* Analog IO | |||
* max31855:base:spiChan | |||
@@ -698,9 +740,9 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params) | |||
if ((params = extractInt (progName, params, &pins)) == NULL) | |||
return FALSE ; | |||
if ((pins < 1) || (pins > 100)) | |||
if ((pins < 1) || (pins > 1000)) | |||
{ | |||
verbError ("%s: pins (%d) out of range (2-100)", progName, pins) ; | |||
verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; | |||
return FALSE ; | |||
} | |||
@@ -728,6 +770,59 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params) | |||
} | |||
/* | |||
* doExtensionDrcNet: | |||
* Interface to a DRC Network system | |||
* drcn:base:pins:ipAddress:port:password | |||
********************************************************************************* | |||
*/ | |||
static int doExtensionDrcNet (char *progName, int pinBase, char *params) | |||
{ | |||
int pins ; | |||
char *ipAddress, *port, *password ; | |||
char pPort [1024] ; | |||
if ((params = extractInt (progName, params, &pins)) == NULL) | |||
return FALSE ; | |||
if ((pins < 1) || (pins > 1000)) | |||
{ | |||
verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; | |||
return FALSE ; | |||
} | |||
if ((params = extractStr (progName, params, &ipAddress)) == NULL) | |||
return FALSE ; | |||
if (strlen (ipAddress) == 0) | |||
{ | |||
verbError ("%s: ipAddress required", progName) ; | |||
return FALSE ; | |||
} | |||
if ((params = extractStr (progName, params, &port)) == NULL) | |||
return FALSE ; | |||
if (strlen (port) == 0) | |||
{ | |||
sprintf (pPort, "%d", DEFAULT_SERVER_PORT) ; | |||
port = pPort ; | |||
} | |||
if ((params = extractStr (progName, params, &password)) == NULL) | |||
return FALSE ; | |||
if (strlen (password) == 0) | |||
{ | |||
verbError ("%s: password required", progName) ; | |||
return FALSE ; | |||
} | |||
return drcSetupNet (pinBase, pins, ipAddress, port, password) ; | |||
} | |||
/* | |||
* Function list | |||
@@ -748,6 +843,7 @@ static struct extensionFunctionStruct extensionFunctions [] = | |||
{ "pseudoPins", &doExtensionPseudoPins }, | |||
{ "htu21d", &doExtensionHtu21d }, | |||
{ "ds18b20", &doExtensionDs18b20 }, | |||
{ "rht03", &doExtensionRht03 }, | |||
{ "mcp3002", &doExtensionMcp3002 }, | |||
{ "mcp3004", &doExtensionMcp3004 }, | |||
{ "mcp4802", &doExtensionMcp4802 }, | |||
@@ -757,6 +853,7 @@ static struct extensionFunctionStruct extensionFunctions [] = | |||
{ "max5322", &doExtensionMax5322 }, | |||
{ "sn3218", &doExtensionSn3218 }, | |||
{ "drcs", &doExtensionDrcS }, | |||
{ "drcn", &doExtensionDrcNet }, | |||
{ NULL, NULL }, | |||
} ; | |||
@@ -826,6 +923,6 @@ int loadWPiExtension (char *progName, char *extensionData, int printErrors) | |||
return extensionFn->function (progName, pinBase, p) ; | |||
} | |||
verbError ("%s: extension %s not found", progName, extension) ; | |||
fprintf (stderr, "%s: extension %s not found", progName, extension) ; | |||
return FALSE ; | |||
} |
@@ -0,0 +1,100 @@ | |||
# | |||
# Makefile: | |||
# The wiringPiD utility: | |||
# https://projects.drogon.net/wiring-pi | |||
# | |||
# Copyright (c) 2012-2017 Gordon Henderson | |||
################################################################################# | |||
# This file is part of wiringPi: | |||
# A "wiring" library for the Raspberry Pi | |||
# | |||
# wiringPi is free software: you can redistribute it and/or modify | |||
# it under the terms of the GNU Lesser General Public License as published by | |||
# the Free Software Foundation, either version 3 of the License, or | |||
# (at your option) any later version. | |||
# | |||
# wiringPi is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU Lesser General Public License for more details. | |||
# | |||
# You should have received a copy of the GNU Lesser General Public License | |||
# along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
################################################################################# | |||
DESTDIR?=/usr | |||
PREFIX?=/local | |||
ifneq ($V,1) | |||
Q ?= @ | |||
endif | |||
#DEBUG = -g -O0 | |||
DEBUG = -O2 | |||
CC = gcc | |||
INCLUDE = -I$(DESTDIR)$(PREFIX)/include | |||
CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe | |||
LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib | |||
LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt | |||
# May not need to alter anything below this line | |||
############################################################################### | |||
SRC = wiringpid.c network.c runRemote.c daemonise.c | |||
OBJ = $(SRC:.c=.o) | |||
all: wiringpid | |||
wiringpid: $(OBJ) | |||
$Q echo [Link] | |||
$Q $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS) | |||
.c.o: | |||
$Q echo [Compile] $< | |||
$Q $(CC) -c $(CFLAGS) $< -o $@ | |||
.PHONY: clean | |||
clean: | |||
$Q echo "[Clean]" | |||
$Q rm -f $(OBJ) wiringpid *~ core tags *.bak | |||
.PHONY: tags | |||
tags: $(SRC) | |||
$Q echo [ctags] | |||
$Q ctags $(SRC) | |||
.PHONY: install | |||
install: wiringpid | |||
$Q echo "[Install]" | |||
$Q mkdir -p $(DESTDIR)$(PREFIX)/sbin | |||
$Q cp wiringpid $(DESTDIR)$(PREFIX)/sbin | |||
$Q chown root.root $(DESTDIR)$(PREFIX)/sbin/wiringpid | |||
# $Q mkdir -p $(DESTDIR)$(PREFIX)/man/man8 | |||
# $Q cp gpio.1 $(DESTDIR)$(PREFIX)/man/man8 | |||
.PHONY: install-deb | |||
install-deb: gpio | |||
$Q echo "[Install: deb]" | |||
$Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/bin | |||
$Q install -m 0755 gpio ~/wiringPi/debian-template/wiringPi/usr/bin | |||
$Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/man/man1 | |||
$Q install -m 0644 gpio.1 ~/wiringPi/debian-template/wiringPi/man/man1 | |||
.PHONY: uninstall | |||
uninstall: | |||
$Q echo "[UnInstall]" | |||
$Q rm -f $(DESTDIR)$(PREFIX)/sbin/wiringpid | |||
$Q rm -f $(DESTDIR)$(PREFIX)/man/man8/wiringpid.8 | |||
.PHONY: depend | |||
depend: | |||
makedepend -Y $(SRC) | |||
# DO NOT DELETE | |||
wiringpid.o: drcNetCmd.h network.h runRemote.h daemonise.h | |||
network.o: network.h | |||
runRemote.o: drcNetCmd.h network.h runRemote.h | |||
daemonise.o: daemonise.h |
@@ -0,0 +1,82 @@ | |||
/* | |||
* daemonise.c: | |||
* Fairly generic "Turn the current process into a daemon" code. | |||
* | |||
* Copyright (c) 2016-2017 Gordon Henderson. | |||
********************************************************************************* | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <syslog.h> | |||
#include <signal.h> | |||
#include <sys/stat.h> | |||
#include "daemonise.h" | |||
void daemonise (const char *pidFile) | |||
{ | |||
pid_t pid ; | |||
int i ; | |||
FILE *fd ; | |||
syslog (LOG_DAEMON | LOG_INFO, "Becoming daemon") ; | |||
// Fork from the parent | |||
if ((pid = fork ()) < 0) | |||
{ | |||
syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 1 failed: %m") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
if (pid > 0) // Parent - terminate | |||
exit (EXIT_SUCCESS) ; | |||
// Now running on the child - become session leader | |||
if (setsid() < 0) | |||
{ | |||
syslog (LOG_DAEMON | LOG_ALERT, "setsid failed: %m") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Ignore a few signals | |||
signal (SIGCHLD, SIG_IGN) ; | |||
signal (SIGHUP, SIG_IGN) ; | |||
// Fork again | |||
if ((pid = fork ()) < 0) | |||
{ | |||
syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 2 failed: %m") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
if (pid > 0) // parent - terminate | |||
exit (EXIT_SUCCESS) ; | |||
// Tidying up - reset umask, change to / and close all files | |||
umask (0) ; | |||
chdir ("/") ; | |||
for (i = 0 ; i < sysconf (_SC_OPEN_MAX) ; ++i) | |||
close (i) ; | |||
// Write PID into /var/run | |||
if (pidFile != NULL) | |||
{ | |||
if ((fd = fopen (pidFile, "w")) == NULL) | |||
{ | |||
syslog (LOG_DAEMON | LOG_ALERT, "Unable to write PID file: %m") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
fprintf (fd, "%d\n", getpid ()) ; | |||
fclose (fd) ; | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
/* | |||
* daemonise.h: | |||
* Fairly generic "Turn the current process into a daemon" code. | |||
* | |||
* Copyright (c) 2016-2017 Gordon Henderson. | |||
********************************************************************************* | |||
*/ | |||
extern void daemonise (const char *pidFile) ; |
@@ -0,0 +1,44 @@ | |||
/* | |||
* drcNetCmd.c: | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#define DEFAULT_SERVER_PORT 6124 | |||
#define DRCN_PIN_MODE 1 | |||
#define DRCN_PULL_UP_DN 2 | |||
#define DRCN_DIGITAL_WRITE 3 | |||
#define DRCN_DIGITAL_WRITE8 4 | |||
#define DRCN_ANALOG_WRITE 5 | |||
#define DRCN_PWM_WRITE 6 | |||
#define DRCN_DIGITAL_READ 7 | |||
#define DRCN_DIGITAL_READ8 8 | |||
#define DRCN_ANALOG_READ 9 | |||
struct drcNetComStruct | |||
{ | |||
uint32_t pin ; | |||
uint32_t cmd ; | |||
uint32_t data ; | |||
} comDat ; | |||
@@ -0,0 +1,330 @@ | |||
/* | |||
* network.c: | |||
* Part of wiringPiD | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <sys/socket.h> | |||
#include <netinet/in.h> | |||
#include <arpa/inet.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <stdarg.h> | |||
#include <malloc.h> | |||
#include <fcntl.h> | |||
#include <crypt.h> | |||
#include "network.h" | |||
#define TRUE (1==1) | |||
#define FALSE (!TRUE) | |||
// Local data | |||
#define SALT_LEN 16 | |||
static char salt [SALT_LEN + 1] ; | |||
static char *returnedHash = NULL ; | |||
static int serverFd = -1 ; | |||
// Union for the server Socket Address | |||
static union | |||
{ | |||
struct sockaddr_in sin ; | |||
struct sockaddr_in6 sin6 ; | |||
} serverSockAddr ; | |||
// and client address | |||
static union | |||
{ | |||
struct sockaddr_in sin ; | |||
struct sockaddr_in6 sin6 ; | |||
} clientSockAddr ; | |||
/* | |||
* getClientIP: | |||
* Returns a pointer to a static string containing the clients IP address | |||
********************************************************************************* | |||
*/ | |||
char *getClientIP (void) | |||
{ | |||
char buf [INET6_ADDRSTRLEN] ; | |||
static char ipAddress [1024] ; | |||
if (clientSockAddr.sin.sin_family == AF_INET) // IPv4 | |||
{ | |||
if (snprintf (ipAddress, 1024, "IPv4: %s", | |||
inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024) | |||
strcpy (ipAddress, "Too long") ; | |||
} | |||
else // IPv6 | |||
{ | |||
if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr)) | |||
{ | |||
if (snprintf (ipAddress, 1024, "IPv4in6: %s", | |||
inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024) | |||
strcpy (ipAddress, "Too long") ; | |||
} | |||
else | |||
{ | |||
if (snprintf (ipAddress, 1024, "IPv6: %s", | |||
inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024) | |||
strcpy (ipAddress, "Too long") ; | |||
} | |||
} | |||
return ipAddress ; | |||
} | |||
/* | |||
* clientPstr: clientPrintf: | |||
* Print over a network socket | |||
********************************************************************************* | |||
*/ | |||
static int clientPstr (int fd, char *s) | |||
{ | |||
int len = strlen (s) ; | |||
return (write (fd, s, len) == len) ? 0 : -1 ; | |||
} | |||
static int clientPrintf (const int fd, const char *message, ...) | |||
{ | |||
va_list argp ; | |||
char buffer [1024] ; | |||
va_start (argp, message) ; | |||
vsnprintf (buffer, 1023, message, argp) ; | |||
va_end (argp) ; | |||
return clientPstr (fd, buffer) ; | |||
} | |||
/* | |||
* sendGreeting: | |||
* Send some text to the client device | |||
********************************************************************************* | |||
*/ | |||
int sendGreeting (int clientFd) | |||
{ | |||
if (clientPrintf (clientFd, "200 Welcome to wiringPiD - http://wiringpi.com/\n") < 0) | |||
return -1 ; | |||
return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ; | |||
} | |||
/* | |||
* getSalt: | |||
* Create a random 'salt' value for the password encryption process | |||
********************************************************************************* | |||
*/ | |||
static int getSalt (char drySalt []) | |||
{ | |||
static const char *seaDog = "abcdefghijklmnopqrstuvwxyz" | |||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
"0123456789/." ; | |||
unsigned char wetSalt [SALT_LEN] ; | |||
int i, fd ; | |||
if ((fd = open ("/dev/urandom", O_RDONLY)) < 0) | |||
return fd ; | |||
if (read (fd, wetSalt, SALT_LEN) != SALT_LEN) | |||
return -1 ; | |||
close (fd) ; | |||
for (i = 0 ; i < SALT_LEN ; ++i) | |||
drySalt [i] = seaDog [wetSalt [i] & 63] ; | |||
drySalt [SALT_LEN] = 0 ; | |||
return 0 ; | |||
} | |||
/* | |||
* sendChallenge: | |||
* Create and send our salt (aka nonce) to the remote device | |||
********************************************************************************* | |||
*/ | |||
int sendChallenge (int clientFd) | |||
{ | |||
if (getSalt (salt) < 0) | |||
return -1 ; | |||
return clientPrintf (clientFd, "Challenge %s\n", salt) ; | |||
} | |||
/* | |||
* getResponse: | |||
* Read the encrypted password from the remote device. | |||
********************************************************************************* | |||
*/ | |||
int getResponse (int clientFd) | |||
{ | |||
char reply [1024] ; | |||
int len ; | |||
// Being sort of lazy about this. I'm expecting an SHA-512 hash back and these | |||
// are exactly 86 characters long, so no reason not to, I guess... | |||
len = 86 ; | |||
if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) | |||
return -1 ; | |||
len = recv (clientFd, reply, 86, 0) ; | |||
if (len != 86) | |||
return -1 ; | |||
reply [len] = 0 ; | |||
if ((returnedHash = malloc (len + 1)) == NULL) | |||
return -1 ; | |||
strcpy (returnedHash, reply) ; | |||
return 0 ; | |||
} | |||
/* | |||
* passwordMatch: | |||
* See if there's a match. If not, we simply dump them. | |||
********************************************************************************* | |||
*/ | |||
int passwordMatch (const char *password) | |||
{ | |||
char *encrypted ; | |||
char salted [1024] ; | |||
sprintf (salted, "$6$%s$", salt) ; | |||
encrypted = crypt (password, salted) ; | |||
// 20: $6$ then 16 characters of salt, then $ | |||
// 86 is the length of an SHA-512 hash | |||
return strncmp (encrypted + 20, returnedHash, 86) == 0 ; | |||
} | |||
/* | |||
* setupServer: | |||
* Do what's needed to create a local server socket instance that can listen | |||
* on both IPv4 and IPv6 interfaces. | |||
********************************************************************************* | |||
*/ | |||
int setupServer (int serverPort) | |||
{ | |||
socklen_t clientSockAddrSize = sizeof (clientSockAddr) ; | |||
int on = 1 ; | |||
int family ; | |||
socklen_t serverSockAddrSize ; | |||
int clientFd ; | |||
// Try to create an IPv6 socket | |||
serverFd = socket (PF_INET6, SOCK_STREAM, 0) ; | |||
// If it didn't work, then fall-back to IPv4. | |||
if (serverFd < 0) | |||
{ | |||
if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0) | |||
return -1 ; | |||
family = AF_INET ; | |||
serverSockAddrSize = sizeof (struct sockaddr_in) ; | |||
} | |||
else // We got an IPv6 socket | |||
{ | |||
family = AF_INET6 ; | |||
serverSockAddrSize = sizeof (struct sockaddr_in6) ; | |||
} | |||
if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) | |||
return -1 ; | |||
// Setup the servers socket address - cope with IPv4 and v6. | |||
memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ; | |||
switch (family) | |||
{ | |||
case AF_INET: | |||
serverSockAddr.sin.sin_family = AF_INET ; | |||
serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ; | |||
serverSockAddr.sin.sin_port = htons (serverPort) ; | |||
break; | |||
case AF_INET6: | |||
serverSockAddr.sin6.sin6_family = AF_INET6 ; | |||
serverSockAddr.sin6.sin6_addr = in6addr_any ; | |||
serverSockAddr.sin6.sin6_port = htons (serverPort) ; | |||
} | |||
// Bind, listen and accept | |||
if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0) | |||
return -1 ; | |||
if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time... | |||
return -1 ; | |||
if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0) | |||
return -1 ; | |||
return clientFd ; | |||
} | |||
/* | |||
* closeServer: | |||
********************************************************************************* | |||
*/ | |||
void closeServer (int clientFd) | |||
{ | |||
if (serverFd != -1) close (serverFd) ; | |||
if (clientFd != -1) close (clientFd) ; | |||
serverFd = clientFd = -1 ; | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
* network.h: | |||
* Part of wiringPiD | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
extern char *getClientIP (void) ; | |||
extern int getResponce (int clientFd) ; | |||
extern int setupServer (int serverPort) ; | |||
extern int sendGreeting (int clientFd) ; | |||
extern int sendChallenge (int clientFd) ; | |||
extern int getResponse (int clientFd) ; | |||
extern int passwordMatch (const char *password) ; | |||
extern void closeServer (int clientFd) ; |
@@ -0,0 +1,126 @@ | |||
/* | |||
* runRemote.c: | |||
* Run the remote commands passed over the network link. | |||
* | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <arpa/inet.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <stdint.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
//#include <stdarg.h> | |||
#include <wiringPi.h> | |||
#include <wpiExtensions.h> | |||
#include "drcNetCmd.h" | |||
#include "network.h" | |||
#include "runRemote.h" | |||
int noLocalPins = FALSE ; | |||
void runRemoteCommands (int fd) | |||
{ | |||
register uint32_t pin ; | |||
int len ; | |||
struct drcNetComStruct cmd ; | |||
len = sizeof (struct drcNetComStruct) ; | |||
if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) | |||
return ; | |||
for (;;) | |||
{ | |||
if (recv (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) // Probably remote hangup | |||
return ; | |||
pin = cmd.pin ; | |||
if (noLocalPins && ((pin & PI_GPIO_MASK) == 0)) | |||
{ | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
continue ; | |||
} | |||
switch (cmd.cmd) | |||
{ | |||
case DRCN_PIN_MODE: | |||
pinMode (pin, cmd.data) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_PULL_UP_DN: | |||
pullUpDnControl (pin, cmd.data) ; | |||
break ; | |||
case DRCN_PWM_WRITE: | |||
pwmWrite (pin, cmd.data) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_DIGITAL_WRITE: | |||
digitalWrite (pin, cmd.data) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_DIGITAL_WRITE8: | |||
//digitalWrite8 (pin, cmd.data) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_DIGITAL_READ: | |||
cmd.data = digitalRead (pin) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_DIGITAL_READ8: | |||
//cmd.data = digitalRead8 (pin) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_ANALOG_WRITE: | |||
analogWrite (pin, cmd.data) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
case DRCN_ANALOG_READ: | |||
cmd.data = analogRead (pin) ; | |||
if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) | |||
return ; | |||
break ; | |||
} | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* runRemote.h: | |||
* Run the remote commands passed over the network link. | |||
* | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
// Globals | |||
extern int noLocalPins ; | |||
extern void runRemoteCommands (int fd) ; |
@@ -0,0 +1,382 @@ | |||
/* | |||
* wiringPiD.c: | |||
* Copyright (c) 2012-2017 Gordon Henderson | |||
*********************************************************************** | |||
* This file is part of wiringPi: | |||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | |||
* | |||
* wiringPi is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* wiringPi is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>. | |||
*********************************************************************** | |||
*/ | |||
#include <arpa/inet.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <stdint.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <stdarg.h> | |||
#include <syslog.h> | |||
#include <signal.h> | |||
#include <errno.h> | |||
#include <wiringPi.h> | |||
#include <wpiExtensions.h> | |||
#include "drcNetCmd.h" | |||
#include "network.h" | |||
#include "runRemote.h" | |||
#include "daemonise.h" | |||
#define PIDFILE "/var/run/wiringPiD.pid" | |||
// Globals | |||
static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ; | |||
static int doDaemon = FALSE ; | |||
// | |||
static void logMsg (const char *message, ...) | |||
{ | |||
va_list argp ; | |||
char buffer [1024] ; | |||
va_start (argp, message) ; | |||
vsnprintf (buffer, 1023, message, argp) ; | |||
va_end (argp) ; | |||
if (doDaemon) | |||
syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ; | |||
else | |||
printf ("%s\n", buffer) ; | |||
} | |||
/* | |||
* sigHandler: | |||
* setupSigHandler: | |||
* Somehing has happened that would normally terminate the program so try | |||
* to close down nicely. | |||
********************************************************************************* | |||
*/ | |||
void sigHandler (int sig) | |||
{ | |||
logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ; | |||
(void)unlink (PIDFILE) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
void setupSigHandler (void) | |||
{ | |||
struct sigaction action ; | |||
sigemptyset (&action.sa_mask) ; | |||
action.sa_flags = 0 ; | |||
// Ignore what we can | |||
action.sa_handler = SIG_IGN ; | |||
sigaction (SIGHUP, &action, NULL) ; | |||
sigaction (SIGTTIN, &action, NULL) ; | |||
sigaction (SIGTTOU, &action, NULL) ; | |||
// Trap what we can to exit gracefully | |||
action.sa_handler = sigHandler ; | |||
sigaction (SIGINT, &action, NULL) ; | |||
sigaction (SIGQUIT, &action, NULL) ; | |||
sigaction (SIGILL, &action, NULL) ; | |||
sigaction (SIGABRT, &action, NULL) ; | |||
sigaction (SIGFPE, &action, NULL) ; | |||
sigaction (SIGSEGV, &action, NULL) ; | |||
sigaction (SIGPIPE, &action, NULL) ; | |||
sigaction (SIGALRM, &action, NULL) ; | |||
sigaction (SIGTERM, &action, NULL) ; | |||
sigaction (SIGUSR1, &action, NULL) ; | |||
sigaction (SIGUSR2, &action, NULL) ; | |||
sigaction (SIGCHLD, &action, NULL) ; | |||
sigaction (SIGTSTP, &action, NULL) ; | |||
sigaction (SIGBUS, &action, NULL) ; | |||
} | |||
/* | |||
* The works... | |||
********************************************************************************* | |||
*/ | |||
int main (int argc, char *argv []) | |||
{ | |||
int clientFd ; | |||
char *p, *password ; | |||
int i ; | |||
int port = DEFAULT_SERVER_PORT ; | |||
int wpiSetup = 0 ; | |||
if (argc < 2) | |||
{ | |||
fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Help? | |||
if (strcasecmp (argv [1], "-h") == 0) | |||
{ | |||
printf ("Usage: %s %s\n", argv [0], usage) ; | |||
return 0 ; | |||
} | |||
// Daemonize? | |||
// Must come before the other args as e.g. some extensions | |||
// open files which get closed on daemonise... | |||
if (strcasecmp (argv [1], "-d") == 0) | |||
{ | |||
if (geteuid () != 0) | |||
{ | |||
fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
doDaemon = TRUE ; | |||
daemonise (PIDFILE) ; | |||
for (i = 2 ; i < argc ; ++i) | |||
argv [i - 1] = argv [i] ; | |||
--argc ; | |||
} | |||
// Scan all other arguments | |||
while (*argv [1] == '-') | |||
{ | |||
// Look for wiringPi setup arguments: | |||
// Same as the gpio command and rtb. | |||
// -g - bcm_gpio | |||
if (strcasecmp (argv [1], "-g") == 0) | |||
{ | |||
if (wpiSetup == 0) | |||
{ | |||
logMsg ("BCM_GPIO mode selected") ; | |||
wiringPiSetupGpio () ; | |||
} | |||
for (i = 2 ; i < argc ; ++i) | |||
argv [i - 1] = argv [i] ; | |||
--argc ; | |||
++wpiSetup ; | |||
continue ; | |||
} | |||
// -1 - physical pins | |||
if (strcasecmp (argv [1], "-1") == 0) | |||
{ | |||
if (wpiSetup == 0) | |||
{ | |||
logMsg ("GPIO-PHYS mode selected") ; | |||
wiringPiSetupPhys () ; | |||
} | |||
for (i = 2 ; i < argc ; ++i) | |||
argv [i - 1] = argv [i] ; | |||
--argc ; | |||
++wpiSetup ; | |||
continue ; | |||
} | |||
// -z - no wiringPi - blocks remotes accessing local pins | |||
if (strcasecmp (argv [1], "-z") == 0) | |||
{ | |||
if (wpiSetup == 0) | |||
logMsg ("No GPIO mode selected") ; | |||
for (i = 2 ; i < argc ; ++i) | |||
argv [i - 1] = argv [i] ; | |||
--argc ; | |||
noLocalPins = TRUE ; | |||
++wpiSetup ; | |||
continue ; | |||
} | |||
// -p to select the port | |||
if (strcasecmp (argv [1], "-p") == 0) | |||
{ | |||
if (argc < 3) | |||
{ | |||
logMsg ("-p missing extension port") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
logMsg ("Setting port to: %s", argv [2]) ; | |||
port = atoi (argv [2]) ; | |||
if ((port < 1) || (port > 65535)) | |||
{ | |||
logMsg ("Invalid server port: %d", port) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Shift args down by 2 | |||
for (i = 3 ; i < argc ; ++i) | |||
argv [i - 2] = argv [i] ; | |||
argc -= 2 ; | |||
continue ; | |||
} | |||
// Check for -x argument to load in a new extension | |||
// -x extension:base:args | |||
// Can load many modules to extend the daemon. | |||
if (strcasecmp (argv [1], "-x") == 0) | |||
{ | |||
if (argc < 3) | |||
{ | |||
logMsg ("-x missing extension name:data:etc.") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
logMsg ("Loading extension: %s", argv [2]) ; | |||
if (!loadWPiExtension (argv [0], argv [2], TRUE)) | |||
{ | |||
logMsg ("Extension load failed: %s", strerror (errno)) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Shift args down by 2 | |||
for (i = 3 ; i < argc ; ++i) | |||
argv [i - 2] = argv [i] ; | |||
argc -= 2 ; | |||
continue ; | |||
} | |||
logMsg ("Invalid parameter: %s", argv [1]) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
// Default to wiringPi mode | |||
if (wpiSetup == 0) | |||
{ | |||
logMsg ("WiringPi GPIO mode selected") ; | |||
wiringPiSetup () ; | |||
} | |||
// Finally, should just be one arg left - the password... | |||
if (argc != 2) | |||
{ | |||
logMsg ("No password supplied") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
if (strlen (argv [1]) < 6) | |||
{ | |||
logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
if ((password = malloc (strlen (argv [1]) + 1)) == NULL) | |||
{ | |||
logMsg ("Out of memory") ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
strcpy (password, argv [1]) ; | |||
// Wipe out the password on the command-line in a vague attempt to try to | |||
// hide it from snoopers | |||
for (p = argv [1] ; *p ; ++p) | |||
*p = ' ' ; | |||
setupSigHandler () ; | |||
// Enter our big loop | |||
for (;;) | |||
{ | |||
if (!doDaemon) | |||
printf ("-=-\nWaiting for a new connection...\n") ; | |||
if ((clientFd = setupServer (port)) < 0) | |||
{ | |||
logMsg ("Unable to setup server: %s", strerror (errno)) ; | |||
exit (EXIT_FAILURE) ; | |||
} | |||
logMsg ("New connection from: %s.", getClientIP ()) ; | |||
if (!doDaemon) | |||
printf ("Sending Greeting.\n") ; | |||
if (sendGreeting (clientFd) < 0) | |||
{ | |||
logMsg ("Unable to send greeting message: %s", strerror (errno)) ; | |||
closeServer (clientFd) ; | |||
continue ; | |||
} | |||
if (!doDaemon) | |||
printf ("Sending Challenge.\n") ; | |||
if (sendChallenge (clientFd) < 0) | |||
{ | |||
logMsg ("Unable to send challenge message: %s", strerror (errno)) ; | |||
closeServer (clientFd) ; | |||
continue ; | |||
} | |||
if (!doDaemon) | |||
printf ("Waiting for response.\n") ; | |||
if (getResponse (clientFd) < 0) | |||
{ | |||
logMsg ("Connection closed waiting for response: %s", strerror (errno)) ; | |||
closeServer (clientFd) ; | |||
continue ; | |||
} | |||
if (!passwordMatch (password)) | |||
{ | |||
logMsg ("Password failure") ; | |||
closeServer (clientFd) ; | |||
continue ; | |||
} | |||
logMsg ("Password OK - Starting") ; | |||
runRemoteCommands (clientFd) ; | |||
closeServer (clientFd) ; | |||
} | |||
return 0 ; | |||
} |