@@ -1 +1 @@ | |||||
2.39 | |||||
2.44 |
@@ -161,6 +161,14 @@ fi | |||||
check_make_ok | check_make_ok | ||||
# echo | # echo | ||||
# echo "wiringPi Daemon" | |||||
# cd ../wiringPiD | |||||
# make -j5 | |||||
# check_make_ok | |||||
# $sudo make install | |||||
# check_make_ok | |||||
# echo | |||||
# echo "Examples" | # echo "Examples" | ||||
# cd ../examples | # cd ../examples | ||||
# make | # make | ||||
@@ -1,5 +1,5 @@ | |||||
Package: wiringpi | Package: wiringpi | ||||
Version: 2.38 | |||||
Version: 2.44 | |||||
Section: libraries | Section: libraries | ||||
Priority: optional | Priority: optional | ||||
Architecture: armhf | Architecture: armhf | ||||
@@ -33,7 +33,7 @@ INCLUDE = -I/usr/local/include | |||||
CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe | CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe | ||||
LDFLAGS = -L/usr/local/lib | LDFLAGS = -L/usr/local/lib | ||||
LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm | |||||
LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt | |||||
# Should not alter anything below this line | # 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 | CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe | ||||
LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib | 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 | # May not need to alter anything below this line | ||||
############################################################################### | ############################################################################### | ||||
@@ -9,15 +9,15 @@ gpio \- Command-line access to Raspberry Pi's GPIO | |||||
.PP | .PP | ||||
.B gpio | .B gpio | ||||
.B [ \-g | \-1 ] | .B [ \-g | \-1 ] | ||||
.B mode/read/write/aread/awrite/wb/pwm/clock ... | |||||
.B mode/read/write/aread/awrite/wb/pwm/clock/toggle/blink ... | |||||
.PP | .PP | ||||
.B gpio | .B gpio | ||||
.B [ \-x extension:params ] | .B [ \-x extension:params ] | ||||
.B mode/read/write/aread/awrite/pwm/pwmTone ... | |||||
.B mode/read/write/aread/awrite/pwm/toggle/blink ... | |||||
.PP | .PP | ||||
.B gpio | .B gpio | ||||
.B [ \-p ] | .B [ \-p ] | ||||
.B read/write/toggle/wb | |||||
.B read/write/toggle/blink | |||||
.B ... | .B ... | ||||
.PP | .PP | ||||
.B gpio | .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. | to output mode first. | ||||
.TP | .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> | .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 | 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 | 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> | .B awrite <pin> <value> | ||||
Write the analog value to the given pin. This needs to be used in | 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 | 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 | e.g. gpio -x mcp4802:200:0 awrite 200 128 | ||||
@@ -234,7 +246,7 @@ absolutely sure you know what you're doing. | |||||
high | low | high | low | ||||
Change the USB current limiter to high (1.2 amps) or low (the default, 600mA) | 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 | .TP | ||||
.B pwm-bal/pwm-ms | .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 | 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. | raspi-config program to load/unload the I2C device at boot time. | ||||
(or disable the device tree to continue to use this method) | |||||
.TP | .TP | ||||
.B load spi | .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 | 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. | raspi-config program to load/unload the SPI device at boot time. | ||||
(or disable the device tree to continue to use this method) | |||||
.TP | .TP | ||||
.B gbr | .B gbr | ||||
@@ -1443,6 +1443,16 @@ int main (int argc, char *argv []) | |||||
wpMode = WPI_MODE_PIFACE ; | 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 | // Default to wiringPi mode | ||||
else | else | ||||
@@ -1460,12 +1470,15 @@ int main (int argc, char *argv []) | |||||
{ | { | ||||
if (argc < 3) | 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) ; | 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) ; | exit (EXIT_FAILURE) ; | ||||
} | |||||
// Shift args down by 2 | // Shift args down by 2 | ||||
@@ -299,6 +299,8 @@ static void plus2header (int model) | |||||
printf (" +-----+-----+---------+------+---+--B Plus--+---+------+---------+-----+-----+\n") ; | printf (" +-----+-----+---------+------+---+--B Plus--+---+------+---------+-----+-----+\n") ; | ||||
else if (model == PI_MODEL_ZERO) | else if (model == PI_MODEL_ZERO) | ||||
printf (" +-----+-----+---------+------+---+-Pi Zero--+---+------+---------+-----+-----+\n") ; | printf (" +-----+-----+---------+------+---+-Pi Zero--+---+------+---------+-----+-----+\n") ; | ||||
else if (model == PI_MODEL_ZERO_W) | |||||
printf (" +-----+-----+---------+------+---+-Pi ZeroW-+---+------+---------+-----+-----+\n") ; | |||||
else if (model == PI_MODEL_2) | else if (model == PI_MODEL_2) | ||||
printf (" +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+\n") ; | printf (" +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+\n") ; | ||||
else if (model == PI_MODEL_3) | else if (model == PI_MODEL_3) | ||||
@@ -346,7 +348,7 @@ void doReadall (void) | |||||
/**/ if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) | /**/ if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) | ||||
abReadall (model, rev) ; | 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) ; | piPlusReadall (model) ; | ||||
else if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) | else if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) | ||||
allReadall () ; | allReadall () ; | ||||
@@ -1,3 +1,3 @@ | |||||
#define VERSION "2.38" | |||||
#define VERSION "2.44" | |||||
#define VERSION_MAJOR 2 | #define VERSION_MAJOR 2 | ||||
#define VERSION_MINOR 38 | |||||
#define VERSION_MINOR 44 |
@@ -41,7 +41,7 @@ INCLUDE = -I. | |||||
DEFS = -D_GNU_SOURCE | DEFS = -D_GNU_SOURCE | ||||
CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Wextra -Winline $(INCLUDE) -pipe -fPIC | 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 \ | mcp3002.c mcp3004.c mcp4802.c mcp3422.c \ | ||||
max31855.c max5322.c ads1115.c \ | max31855.c max5322.c ads1115.c \ | ||||
sn3218.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 \ | pseudoPins.c \ | ||||
wpiExtensions.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: | * 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: | * This file is part of wiringPi: | ||||
* https://projects.drogon.net/raspberry-pi/wiringpi/ | * https://projects.drogon.net/raspberry-pi/wiringpi/ | ||||
@@ -30,11 +30,11 @@ | |||||
#include "softPwm.h" | #include "softPwm.h" | ||||
// MAX_PINS: | // 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 PWM Frequency is derived from the "pulse time" below. Essentially, | ||||
// the frequency is a function of the range and this pulse time. | // 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, | // 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 | // 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 | // 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 | // Another way to increase the frequency is to reduce the range - however | ||||
// that reduces the overall output accuracy... | // that reduces the overall output accuracy... | ||||
@@ -106,14 +106,15 @@ static void *softPwmThread (void *arg) | |||||
void softPwmWrite (int pin, int value) | 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 ; | pthread_t myThread ; | ||||
int *passPin ; | int *passPin ; | ||||
if (pin >= MAX_PINS) | |||||
return -1 ; | |||||
if (range [pin] != 0) // Already running on this pin | if (range [pin] != 0) // Already running on this pin | ||||
return -1 ; | return -1 ; | ||||
@@ -139,15 +143,15 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) | |||||
if (passPin == NULL) | if (passPin == NULL) | ||||
return -1 ; | return -1 ; | ||||
pinMode (pin, OUTPUT) ; | |||||
digitalWrite (pin, LOW) ; | digitalWrite (pin, LOW) ; | ||||
pinMode (pin, OUTPUT) ; | |||||
marks [pin] = initialValue ; | marks [pin] = initialValue ; | ||||
range [pin] = pwmRange ; | range [pin] = pwmRange ; | ||||
*passPin = pin ; | *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) | while (newPin != -1) | ||||
delay (1) ; | delay (1) ; | ||||
@@ -166,11 +170,14 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) | |||||
void softPwmStop (int pin) | 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" | #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 ; | struct wiringPiNodeStruct *wiringPiNodes = NULL ; | ||||
@@ -224,7 +222,7 @@ const char *piModelNames [16] = | |||||
"Pi Zero", // 09 | "Pi Zero", // 09 | ||||
"CM3", // 10 | "CM3", // 10 | ||||
"Unknown11", // 11 | "Unknown11", // 11 | ||||
"Unknown12", // 12 | |||||
"Pi Zero-W", // 12 | |||||
"Unknown13", // 13 | "Unknown13", // 13 | ||||
"Unknown14", // 14 | "Unknown14", // 14 | ||||
"Unknown15", // 15 | "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) | struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) | ||||
{ | { | ||||
@@ -1272,17 +1272,19 @@ struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) | |||||
if (node == NULL) | if (node == NULL) | ||||
(void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ; | (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 ; | 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: | * digitalWrite: | ||||
* Set an output bit | * 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: | * pwmWrite: | ||||
* Set an output PWM value | * Set an output PWM value | ||||
********************************************************************************* | ********************************************************************************* | ||||
@@ -2144,9 +2187,10 @@ int wiringPiSetup (void) | |||||
switch (model) | 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 ; | piGpioBase = GPIO_PERI_BASE_OLD ; | ||||
break ; | break ; | ||||
@@ -26,6 +26,7 @@ | |||||
// C doesn't have true/false by default and I can never remember which | // C doesn't have true/false by default and I can never remember which | ||||
// way round they are, so ... | // way round they are, so ... | ||||
// (and yes, I know about stdbool.h but I like capitals for these and I'm old) | |||||
#ifndef TRUE | #ifndef TRUE | ||||
# define TRUE (1==1) | # define TRUE (1==1) | ||||
@@ -36,6 +37,11 @@ | |||||
#define UNU __attribute__((unused)) | #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 | // Handy defines | ||||
// wiringPi modes | // wiringPi modes | ||||
@@ -92,6 +98,7 @@ | |||||
#define PI_MODEL_3 8 | #define PI_MODEL_3 8 | ||||
#define PI_MODEL_ZERO 9 | #define PI_MODEL_ZERO 9 | ||||
#define PI_MODEL_CM3 10 | #define PI_MODEL_CM3 10 | ||||
#define PI_MODEL_ZERO_W 12 | |||||
#define PI_VERSION_1 0 | #define PI_VERSION_1 0 | ||||
#define PI_VERSION_1_1 1 | #define PI_VERSION_1_1 1 | ||||
@@ -140,13 +147,15 @@ struct wiringPiNodeStruct | |||||
unsigned int data2 ; // ditto | unsigned int data2 ; // ditto | ||||
unsigned int data3 ; // 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 ; | struct wiringPiNodeStruct *next ; | ||||
} ; | } ; | ||||
@@ -179,14 +188,16 @@ extern int wiringPiSetupSys (void) ; | |||||
extern int wiringPiSetupGpio (void) ; | extern int wiringPiSetupGpio (void) ; | ||||
extern int wiringPiSetupPhys (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 | // PiFace specifics | ||||
// (Deprecated) | // (Deprecated) | ||||
@@ -204,12 +215,14 @@ extern int physPinToGpio (int physPin) ; | |||||
extern void setPadDrive (int group, int value) ; | extern void setPadDrive (int group, int value) ; | ||||
extern int getAlt (int pin) ; | extern int getAlt (int pin) ; | ||||
extern void pwmToneWrite (int pin, int freq) ; | extern void pwmToneWrite (int pin, int freq) ; | ||||
extern void digitalWriteByte (int value) ; | |||||
extern unsigned int digitalReadByte (void) ; | |||||
extern void pwmSetMode (int mode) ; | extern void pwmSetMode (int mode) ; | ||||
extern void pwmSetRange (unsigned int range) ; | extern void pwmSetRange (unsigned int range) ; | ||||
extern void pwmSetClock (int divisor) ; | extern void pwmSetClock (int divisor) ; | ||||
extern void gpioClockSet (int pin, int freq) ; | 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 | // Interrupts | ||||
// (Also Pi hardware specific) | // (Also Pi hardware specific) | ||||
@@ -55,10 +55,13 @@ | |||||
#include "ads1115.h" | #include "ads1115.h" | ||||
#include "sn3218.h" | #include "sn3218.h" | ||||
#include "drcSerial.h" | #include "drcSerial.h" | ||||
#include "drcNet.h" | |||||
#include "../wiringPiD/drcNetCmd.h" | |||||
#include "pseudoPins.h" | #include "pseudoPins.h" | ||||
#include "bmp180.h" | #include "bmp180.h" | ||||
#include "htu21d.h" | #include "htu21d.h" | ||||
#include "ds18b20.h" | #include "ds18b20.h" | ||||
#include "rht03.h" | |||||
#include "wpiExtensions.h" | #include "wpiExtensions.h" | ||||
@@ -134,12 +137,16 @@ static char *extractInt (char *progName, char *p, int *num) | |||||
/* | /* | ||||
* extractStr: | * extractStr: | ||||
* Check & return a string at the given location (prefixed by a :) | * 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) | static char *extractStr (char *progName, char *p, char **str) | ||||
{ | { | ||||
char *q, *r ; | char *q, *r ; | ||||
int quoted = FALSE ; | |||||
if (*p != ':') | if (*p != ':') | ||||
{ | { | ||||
@@ -149,21 +156,38 @@ static char *extractStr (char *progName, char *p, char **str) | |||||
++p ; | ++p ; | ||||
if (!isprint (*p)) | |||||
if (*p == '[') | |||||
{ | |||||
quoted = TRUE ; | |||||
++p ; | |||||
} | |||||
if (!isprint (*p)) // Is this needed? | |||||
{ | { | ||||
verbError ("%s: character expected", progName) ; | verbError ("%s: character expected", progName) ; | ||||
return NULL ; | return NULL ; | ||||
} | } | ||||
q = p ; | 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 | *str = r = calloc (q - p + 2, 1) ; // Zeros it | ||||
while (p != q) | while (p != q) | ||||
*r++ = *p++ ; | *r++ = *p++ ; | ||||
if (quoted) // Skip over the ] to the : | |||||
++p ; | |||||
return 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: | * doExtensionMax31855: | ||||
* Analog IO | * Analog IO | ||||
* max31855:base:spiChan | * max31855:base:spiChan | ||||
@@ -698,9 +740,9 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params) | |||||
if ((params = extractInt (progName, params, &pins)) == NULL) | if ((params = extractInt (progName, params, &pins)) == NULL) | ||||
return FALSE ; | 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 ; | 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 | * Function list | ||||
@@ -748,6 +843,7 @@ static struct extensionFunctionStruct extensionFunctions [] = | |||||
{ "pseudoPins", &doExtensionPseudoPins }, | { "pseudoPins", &doExtensionPseudoPins }, | ||||
{ "htu21d", &doExtensionHtu21d }, | { "htu21d", &doExtensionHtu21d }, | ||||
{ "ds18b20", &doExtensionDs18b20 }, | { "ds18b20", &doExtensionDs18b20 }, | ||||
{ "rht03", &doExtensionRht03 }, | |||||
{ "mcp3002", &doExtensionMcp3002 }, | { "mcp3002", &doExtensionMcp3002 }, | ||||
{ "mcp3004", &doExtensionMcp3004 }, | { "mcp3004", &doExtensionMcp3004 }, | ||||
{ "mcp4802", &doExtensionMcp4802 }, | { "mcp4802", &doExtensionMcp4802 }, | ||||
@@ -757,6 +853,7 @@ static struct extensionFunctionStruct extensionFunctions [] = | |||||
{ "max5322", &doExtensionMax5322 }, | { "max5322", &doExtensionMax5322 }, | ||||
{ "sn3218", &doExtensionSn3218 }, | { "sn3218", &doExtensionSn3218 }, | ||||
{ "drcs", &doExtensionDrcS }, | { "drcs", &doExtensionDrcS }, | ||||
{ "drcn", &doExtensionDrcNet }, | |||||
{ NULL, NULL }, | { NULL, NULL }, | ||||
} ; | } ; | ||||
@@ -826,6 +923,6 @@ int loadWPiExtension (char *progName, char *extensionData, int printErrors) | |||||
return extensionFn->function (progName, pinBase, p) ; | 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 ; | 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 ; | |||||
} |