Browse Source

Bumped the version to 2.40 - correctly this time, I hope.

Added fixed for a few minor things. pin driver for rht03/dht type
sensors. Network stuff is experimental - for now.
Gordon Henderson 7 years ago
parent
commit
70fa99a127

+ 1 - 1
VERSION

@@ -1 +1 @@
-2.39
+2.40

+ 8 - 0
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

+ 1 - 1
debian-template/wiringPi/DEBIAN/control

@@ -1,5 +1,5 @@
 Package: wiringpi
-Version: 2.38
+Version: 2.40
 Section: libraries
 Priority: optional
 Architecture: armhf

+ 1 - 1
examples/Makefile

@@ -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
 ###############################################################################

+ 61 - 0
examples/blink8-drcn.c

@@ -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) ;
+    }
+  }
+}

+ 1 - 1
gpio/Makefile

@@ -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
 ###############################################################################

+ 19 - 9
gpio/gpio.1

@@ -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
@@ -118,11 +118,23 @@ respective logic levels.
 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

+ 15 - 2
gpio/gpio.c

@@ -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
 

+ 2 - 2
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

+ 2 - 2
wiringPi/Makefile

@@ -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
 

+ 405 - 0
wiringPi/drcNet.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 ;
+}

+ 42 - 0
wiringPi/drcNet.h

@@ -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

+ 126 - 0
wiringPi/rht03.c

@@ -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 ;
+}

+ 25 - 0
wiringPi/rht03.h

@@ -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) ;

+ 29 - 22
wiringPi/softPwm.c

@@ -1,7 +1,7 @@
 /*
  * softPwm.c:
- *	Provide 2 channels of software driven PWM.
- *	Copyright (c) 2012-2014 Gordon Henderson
+ *	Provide many channels of software driven PWM.
+ *	Copyright (c) 2012-2017 Gordon Henderson
  ***********************************************************************
  * This file is part of wiringPi:
  *	https://projects.drogon.net/raspberry-pi/wiringpi/
@@ -30,11 +30,11 @@
 #include "softPwm.h"
 
 // MAX_PINS:
-//	This is more than the number of Pi pins because we can actually softPwm
-//	pins that are on GPIO expanders. It's not that efficient and more than 1 or
-//	2 pins on e.g. (SPI) mcp23s17 won't really be that effective, however...
+//	This is more than the number of Pi pins because we can actually softPwm.
+//	Once upon a time I let pins on gpio expanders be softPwm'd, but it's really
+//	really not a good thing.
 
-#define	MAX_PINS	1024
+#define	MAX_PINS	64
 
 // The PWM Frequency is derived from the "pulse time" below. Essentially,
 //	the frequency is a function of the range and this pulse time.
@@ -45,7 +45,7 @@
 //	It's possible to get a higher frequency by lowering the pulse time,
 //	however CPU uage will skyrocket as wiringPi uses a hard-loop to time
 //	periods under 100µS - this is because the Linux timer calls are just
-//	accurate at all, and have an overhead.
+//	not accurate at all, and have an overhead.
 //
 //	Another way to increase the frequency is to reduce the range - however
 //	that reduces the overall output accuracy...
@@ -106,14 +106,15 @@ static void *softPwmThread (void *arg)
 
 void softPwmWrite (int pin, int value)
 {
-  pin &= (MAX_PINS - 1) ;
-
-  /**/ if (value < 0)
-    value = 0 ;
-  else if (value > range [pin])
-    value = range [pin] ;
+  if (pin < MAX_PINS)
+  {
+    /**/ if (value < 0)
+      value = 0 ;
+    else if (value > range [pin])
+      value = range [pin] ;
 
-  marks [pin] = value ;
+    marks [pin] = value ;
+  }
 }
 
 
@@ -129,6 +130,9 @@ int softPwmCreate (int pin, int initialValue, int pwmRange)
   pthread_t myThread ;
   int *passPin ;
 
+  if (pin >= MAX_PINS)
+    return -1 ;
+
   if (range [pin] != 0)	// Already running on this pin
     return -1 ;
 
@@ -139,15 +143,15 @@ int softPwmCreate (int pin, int initialValue, int pwmRange)
   if (passPin == NULL)
     return -1 ;
 
-  pinMode      (pin, OUTPUT) ;
   digitalWrite (pin, LOW) ;
+  pinMode      (pin, OUTPUT) ;
 
   marks [pin] = initialValue ;
   range [pin] = pwmRange ;
 
   *passPin = pin ;
-  newPin = pin ;
-  res    = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ;
+  newPin   = pin ;
+  res      = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ;
 
   while (newPin != -1)
     delay (1) ;
@@ -166,11 +170,14 @@ int softPwmCreate (int pin, int initialValue, int pwmRange)
 
 void softPwmStop (int pin)
 {
-  if (range [pin] != 0)
+  if (pin < MAX_PINS)
   {
-    pthread_cancel (threads [pin]) ;
-    pthread_join   (threads [pin], NULL) ;
-    range [pin] = 0 ;
-    digitalWrite (pin, LOW) ;
+    if (range [pin] != 0)
+    {
+      pthread_cancel (threads [pin]) ;
+      pthread_join   (threads [pin], NULL) ;
+      range [pin] = 0 ;
+      digitalWrite (pin, LOW) ;
+    }
   }
 }

+ 65 - 22
wiringPi/wiringPi.c

@@ -84,10 +84,8 @@
 #define	ENV_GPIOMEM	"WIRINGPI_GPIOMEM"
 
 
-// Mask for the bottom 64 pins which belong to the Raspberry Pi
-//	The others are available for the other devices
-
-#define	PI_GPIO_MASK	(0xFFFFFFC0)
+// Extend wiringPi with other pin-based devices and keep track of
+//	them in this structure
 
 struct wiringPiNodeStruct *wiringPiNodes = NULL ;
 
@@ -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 ;
 }
@@ -1492,6 +1494,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
@@ -1535,6 +1558,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

+ 29 - 17
wiringPi/wiringPi.h

@@ -26,6 +26,7 @@
 
 // C doesn't have true/false by default and I can never remember which
 //	way round they are, so ...
+//	(and yes, I know about stdbool.h but I like capitals for these and I'm old)
 
 #ifndef	TRUE
 #  define	TRUE	(1==1)
@@ -36,6 +37,11 @@
 
 #define	UNU	__attribute__((unused))
 
+// Mask for the bottom 64 pins which belong to the Raspberry Pi
+//	The others are available for the other devices
+
+#define	PI_GPIO_MASK	(0xFFFFFFC0)
+
 // Handy defines
 
 // wiringPi modes
@@ -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)

+ 104 - 7
wiringPi/wpiExtensions.c

@@ -55,10 +55,13 @@
 #include "ads1115.h"
 #include "sn3218.h"
 #include "drcSerial.h"
+#include "drcNet.h"
+#include "../wiringPiD/drcNetCmd.h"
 #include "pseudoPins.h"
 #include "bmp180.h"
 #include "htu21d.h"
 #include "ds18b20.h"
+#include "rht03.h"
 
 #include "wpiExtensions.h"
 
@@ -134,12 +137,16 @@ static char *extractInt (char *progName, char *p, int *num)
 /*
  * extractStr:
  *	Check & return a string at the given location (prefixed by a :)
+ *	Note: The string can be enclosed in []'s to escape colons. This is
+ *	so we can handle IPv6 addresses which contain colons and the []'s is
+ *	a common way to prepresent them.
  *********************************************************************************
  */
 
 static char *extractStr (char *progName, char *p, char **str)
 {
   char *q, *r ;
+  int quoted = FALSE ;
 
   if (*p != ':')
   {
@@ -149,21 +156,38 @@ static char *extractStr (char *progName, char *p, char **str)
 
   ++p ;
 
-  if (!isprint (*p))
+  if (*p == '[')
+  {
+    quoted = TRUE ;
+    ++p ;
+  }
+
+  if (!isprint (*p))	// Is this needed?
   {
     verbError ("%s: character expected", progName) ;
     return NULL ;
   }
 
   q = p ;
-  while ((*q != 0) && (*q != ':'))
-    ++q ;
+  if (quoted)
+  {
+    while ((*q != 0) && (*q != ']'))
+      ++q ;
+  }
+  else
+  {
+    while ((*q != 0) && (*q != ':'))
+      ++q ;
+  }
 
   *str = r = calloc (q - p + 2, 1) ;	// Zeros it
 
   while (p != q)
     *r++ = *p++ ;
-    
+
+  if (quoted)				// Skip over the ] to the :
+    ++p ;
+
   return p ;
 }
 
@@ -495,6 +519,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
@@ -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 ;
 }

+ 100 - 0
wiringPiD/Makefile

@@ -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

+ 82 - 0
wiringPiD/daemonise.c

@@ -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) ;
+  }
+}

+ 9 - 0
wiringPiD/daemonise.h

@@ -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) ;

+ 44 - 0
wiringPiD/drcNetCmd.h

@@ -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 ;
+

+ 330 - 0
wiringPiD/network.c

@@ -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 ;
+}

+ 31 - 0
wiringPiD/network.h

@@ -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) ;

+ 126 - 0
wiringPiD/runRemote.c

@@ -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 ;
+    }
+  }
+
+}

+ 29 - 0
wiringPiD/runRemote.h

@@ -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) ;

BIN
wiringPiD/wiringpid


+ 382 - 0
wiringPiD/wiringpid.c

@@ -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 ;
+}