Gordons Projects

--> Projects Top-Level GIT

Bumped the version to 2.40 - correctly this time, I hope. 2.40
authorGordon Henderson <projects@drogon.net>
Mon, 27 Feb 2017 19:51:32 +0000 (19:51 +0000)
committerGordon Henderson <projects@drogon.net>
Mon, 27 Feb 2017 19:51:32 +0000 (19:51 +0000)
Added fixed for a few minor things. pin driver for rht03/dht type
sensors. Network stuff is experimental - for now.

28 files changed:
VERSION
build
debian-template/wiringPi/DEBIAN/control
examples/Makefile
examples/blink8-drcn.c [new file with mode: 0644]
gpio/Makefile
gpio/gpio.1
gpio/gpio.c
version.h
wiringPi/Makefile
wiringPi/drcNet.c [new file with mode: 0644]
wiringPi/drcNet.h [new file with mode: 0644]
wiringPi/rht03.c [new file with mode: 0644]
wiringPi/rht03.h [new file with mode: 0644]
wiringPi/softPwm.c
wiringPi/wiringPi.c
wiringPi/wiringPi.h
wiringPi/wpiExtensions.c
wiringPiD/Makefile [new file with mode: 0644]
wiringPiD/daemonise.c [new file with mode: 0644]
wiringPiD/daemonise.h [new file with mode: 0644]
wiringPiD/drcNetCmd.h [new file with mode: 0644]
wiringPiD/network.c [new file with mode: 0644]
wiringPiD/network.h [new file with mode: 0644]
wiringPiD/runRemote.c [new file with mode: 0644]
wiringPiD/runRemote.h [new file with mode: 0644]
wiringPiD/wiringpid [new file with mode: 0755]
wiringPiD/wiringpid.c [new file with mode: 0644]

diff --git a/VERSION b/VERSION
index 23f3620..4bdd32f 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.39
+2.40
diff --git a/build b/build
index b42a25a..070ea3f 100755 (executable)
--- a/build
+++ b/build
@@ -160,6 +160,14 @@ fi
   $sudo make install
   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
index 80cd3f8..75cedfa 100644 (file)
@@ -1,5 +1,5 @@
 Package: wiringpi
-Version: 2.38
+Version: 2.40
 Section: libraries
 Priority: optional
 Architecture: armhf
index d6195b3..4725d85 100644 (file)
@@ -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
 
 # Should not alter anything below this line
 ###############################################################################
diff --git a/examples/blink8-drcn.c b/examples/blink8-drcn.c
new file mode 100644 (file)
index 0000000..96c775b
--- /dev/null
@@ -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) ;
+    }
+  }
+}
index 9152ea8..f41a005 100644 (file)
@@ -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
 ###############################################################################
index e5fe181..e5490d6 100644 (file)
@@ -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
index 3327308..6fd71f8 100644 (file)
@@ -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
 
index fde08f3..2c359b6 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1,3 +1,3 @@
-#define VERSION "2.38"
+#define VERSION "2.40"
 #define VERSION_MAJOR 2
-#define VERSION_MINOR 38
+#define VERSION_MINOR 40
index 13d006f..0a1283f 100644 (file)
@@ -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
 
diff --git a/wiringPi/drcNet.c b/wiringPi/drcNet.c
new file mode 100644 (file)
index 0000000..0964ff7
--- /dev/null
@@ -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 ;
+}
diff --git a/wiringPi/drcNet.h b/wiringPi/drcNet.h
new file mode 100644 (file)
index 0000000..00f9b05
--- /dev/null
@@ -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
diff --git a/wiringPi/rht03.c b/wiringPi/rht03.c
new file mode 100644 (file)
index 0000000..9fa5702
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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/types.h>
+//#include <sys/stat.h>
+//#include <fcntl.h>
+
+//#include <unistd.h>
+//#include <stdint.h>
+#include <stdio.h>
+//#include <string.h>
+#include <time.h>
+//#include <ctype.h>
+
+#include "wiringPi.h"
+#include "../devLib/maxdetect.h"
+
+#include "rht03.h"
+
+
+/*
+ * 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 ;
+}
diff --git a/wiringPi/rht03.h b/wiringPi/rht03.h
new file mode 100644 (file)
index 0000000..9523fbf
--- /dev/null
@@ -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) ;
index 5999cc0..d99fa00 100644 (file)
@@ -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/
 #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) ;
+    }
   }
 }
index ba86f41..e018100 100644 (file)
 #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 ;
 
@@ -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
  *********************************************************************************
index 1b50470..0788bf2 100644 (file)
@@ -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)
 
 #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
@@ -140,13 +146,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 +187,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 +214,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)
index 2761945..53fafc0 100644 (file)
 #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 ;
 }
diff --git a/wiringPiD/Makefile b/wiringPiD/Makefile
new file mode 100644 (file)
index 0000000..6b2cc9e
--- /dev/null
@@ -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
diff --git a/wiringPiD/daemonise.c b/wiringPiD/daemonise.c
new file mode 100644 (file)
index 0000000..134a6bb
--- /dev/null
@@ -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) ;
+  }
+}
diff --git a/wiringPiD/daemonise.h b/wiringPiD/daemonise.h
new file mode 100644 (file)
index 0000000..8d13319
--- /dev/null
@@ -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) ;
diff --git a/wiringPiD/drcNetCmd.h b/wiringPiD/drcNetCmd.h
new file mode 100644 (file)
index 0000000..23f7dc1
--- /dev/null
@@ -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 ;
+
diff --git a/wiringPiD/network.c b/wiringPiD/network.c
new file mode 100644 (file)
index 0000000..9f6bb88
--- /dev/null
@@ -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 ;
+}
diff --git a/wiringPiD/network.h b/wiringPiD/network.h
new file mode 100644 (file)
index 0000000..94c3380
--- /dev/null
@@ -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) ;
diff --git a/wiringPiD/runRemote.c b/wiringPiD/runRemote.c
new file mode 100644 (file)
index 0000000..cd7432b
--- /dev/null
@@ -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 ;
+    }
+  }
+
+}
diff --git a/wiringPiD/runRemote.h b/wiringPiD/runRemote.h
new file mode 100644 (file)
index 0000000..57d5018
--- /dev/null
@@ -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) ;
diff --git a/wiringPiD/wiringpid b/wiringPiD/wiringpid
new file mode 100755 (executable)
index 0000000..529e286
Binary files /dev/null and b/wiringPiD/wiringpid differ
diff --git a/wiringPiD/wiringpid.c b/wiringPiD/wiringpid.c
new file mode 100644 (file)
index 0000000..8dde1cd
--- /dev/null
@@ -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 ;
+}