浏览代码

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 年之前
父节点
当前提交
70fa99a127

+ 1 - 1
VERSION

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

+ 8 - 0
build

@@ -160,6 +160,14 @@ fi
   $sudo make install
   $sudo make install
   check_make_ok
   check_make_ok
 
 
+  echo
+  echo "wiringPi Daemon"
+  cd ../wiringPiD
+  make -j5
+  check_make_ok
+  $sudo make install
+  check_make_ok
+
 # echo
 # echo
 # echo "Examples"
 # echo "Examples"
 # cd ../examples
 # cd ../examples

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

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

+ 1 - 1
examples/Makefile

@@ -33,7 +33,7 @@ INCLUDE	= -I/usr/local/include
 CFLAGS	= $(DEBUG) -Wall $(INCLUDE) -Winline -pipe
 CFLAGS	= $(DEBUG) -Wall $(INCLUDE) -Winline -pipe
 
 
 LDFLAGS	= -L/usr/local/lib
 LDFLAGS	= -L/usr/local/lib
-LDLIBS    = -lwiringPi -lwiringPiDev -lpthread -lm
+LDLIBS    = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt
 
 
 # Should not alter anything below this line
 # 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
 CFLAGS	= $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe
 
 
 LDFLAGS	= -L$(DESTDIR)$(PREFIX)/lib
 LDFLAGS	= -L$(DESTDIR)$(PREFIX)/lib
-LIBS    = -lwiringPi -lwiringPiDev -lpthread -lrt -lm
+LIBS    = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt
 
 
 # May not need to  alter anything below this line
 # May not need to  alter anything below this line
 ###############################################################################
 ###############################################################################

+ 19 - 9
gpio/gpio.1

@@ -9,15 +9,15 @@ gpio \- Command-line access to Raspberry Pi's GPIO
 .PP
 .PP
 .B gpio
 .B gpio
 .B [ \-g | \-1 ]
 .B [ \-g | \-1 ]
-.B mode/read/write/aread/awrite/wb/pwm/clock ...
+.B mode/read/write/aread/awrite/wb/pwm/clock/toggle/blink ...
 .PP
 .PP
 .B gpio
 .B gpio
 .B [ \-x extension:params ]
 .B [ \-x extension:params ]
-.B mode/read/write/aread/awrite/pwm/pwmTone ...
+.B mode/read/write/aread/awrite/pwm/toggle/blink ...
 .PP
 .PP
 .B gpio
 .B gpio
 .B [ \-p ]
 .B [ \-p ]
-.B read/write/toggle/wb
+.B read/write/toggle/blink
 .B ...
 .B ...
 .PP
 .PP
 .B gpio
 .B gpio
@@ -118,11 +118,23 @@ respective logic levels.
 Write the given value (0 or 1) to the pin. You need to set the pin
 Write the given value (0 or 1) to the pin. You need to set the pin
 to output mode first.
 to output mode first.
 
 
+.TP
+.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
 .TP
 .B aread <pin>
 .B aread <pin>
-Read the analog value of the given pin. This needs to be uses in
+Read the analog value of the given pin. This needs to be used in
 conjunction with a -x flag to add in an extension that handles analog
 conjunction with a -x flag to add in an extension that handles analog
-inputs.  respective logic levels.
+inputs.
 
 
 e.g. gpio -x mcp3002:200:0 aread 200
 e.g. gpio -x mcp3002:200:0 aread 200
 
 
@@ -132,7 +144,7 @@ will read the first analog input on an mcp3002 SPI ADC chip.
 .B awrite <pin> <value>
 .B awrite <pin> <value>
 Write the analog value to the given pin. This needs to be used in
 Write the analog value to the given pin. This needs to be used in
 conjunction with a -x flag to add in an extension that handles analog
 conjunction with a -x flag to add in an extension that handles analog
-inputs.  respective logic levels.
+inputs. 
 
 
 e.g. gpio -x mcp4802:200:0 awrite 200 128
 e.g. gpio -x mcp4802:200:0 awrite 200 128
 
 
@@ -234,7 +246,7 @@ absolutely sure you know what you're doing.
 high | low
 high | low
 
 
 Change the USB current limiter to high (1.2 amps) or low (the default, 600mA)
 Change the USB current limiter to high (1.2 amps) or low (the default, 600mA)
-This is only applicable to the model B+
+This is only applicable to the Model B+ and the Model B, v2.
 
 
 .TP
 .TP
 .B pwm-bal/pwm-ms 
 .B pwm-bal/pwm-ms 
@@ -253,7 +265,6 @@ them. Optionally it will set the I2C baudrate to that supplied in Kb/sec
 
 
 Note: On recent kernels with the device tree enabled you should use the
 Note: On recent kernels with the device tree enabled you should use the
 raspi-config program to load/unload the I2C device at boot time.
 raspi-config program to load/unload the I2C device at boot time.
-(or disable the device tree to continue to use this method)
 
 
 .TP
 .TP
 .B load spi
 .B load spi
@@ -268,7 +279,6 @@ e.g. 8192 bytes then reboot.
 
 
 Note: On recent kernels with the device tree enabled you should use the
 Note: On recent kernels with the device tree enabled you should use the
 raspi-config program to load/unload the SPI device at boot time.
 raspi-config program to load/unload the SPI device at boot time.
-(or disable the device tree to continue to use this method)
 
 
 .TP
 .TP
 .B gbr
 .B gbr

+ 15 - 2
gpio/gpio.c

@@ -1443,6 +1443,16 @@ int main (int argc, char *argv [])
     wpMode = WPI_MODE_PIFACE ;
     wpMode = WPI_MODE_PIFACE ;
   }
   }
 
 
+// Check for -z argument so we don't actually initialise wiringPi
+
+  else if (strcasecmp (argv [1], "-z") == 0)
+  {
+    for (i = 2 ; i < argc ; ++i)
+      argv [i - 1] = argv [i] ;
+    --argc ;
+    wpMode = WPI_MODE_UNINITIALISED ;
+  }
+
 // Default to wiringPi mode
 // Default to wiringPi mode
 
 
   else
   else
@@ -1460,12 +1470,15 @@ int main (int argc, char *argv [])
   {
   {
     if (argc < 3)
     if (argc < 3)
     {
     {
-      fprintf (stderr, "%s: -x missing extension specification.\n", argv [0]) ;
+      fprintf (stderr, "%s: -x missing extension command.\n", argv [0]) ;
       exit (EXIT_FAILURE) ;
       exit (EXIT_FAILURE) ;
     }
     }
 
 
-    if (!loadWPiExtension (argv [0], argv [2], TRUE))	// Prints its own error messages
+    if (!loadWPiExtension (argv [0], argv [2], TRUE))
+    {
+      fprintf (stderr, "%s: Extension load failed: %s\n", argv [0], strerror (errno)) ;
       exit (EXIT_FAILURE) ;
       exit (EXIT_FAILURE) ;
+    }
 
 
 // Shift args down by 2
 // Shift args down by 2
 
 

+ 2 - 2
version.h

@@ -1,3 +1,3 @@
-#define VERSION "2.38"
+#define VERSION "2.40"
 #define VERSION_MAJOR 2
 #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			\
 		mcp3002.c mcp3004.c mcp4802.c mcp3422.c			\
 		max31855.c max5322.c ads1115.c				\
 		max31855.c max5322.c ads1115.c				\
 		sn3218.c						\
 		sn3218.c						\
-		bmp180.c htu21d.c ds18b20.c				\
-		drcSerial.c						\
+		bmp180.c htu21d.c ds18b20.c rht03.c			\
+		drcSerial.c drcNet.c					\
 		pseudoPins.c						\
 		pseudoPins.c						\
 		wpiExtensions.c
 		wpiExtensions.c
 
 

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

+ 65 - 22
wiringPi/wiringPi.c

@@ -84,10 +84,8 @@
 #define	ENV_GPIOMEM	"WIRINGPI_GPIOMEM"
 #define	ENV_GPIOMEM	"WIRINGPI_GPIOMEM"
 
 
 
 
-// Mask for the bottom 64 pins which belong to the Raspberry Pi
-//	The others are available for the other devices
-
-#define	PI_GPIO_MASK	(0xFFFFFFC0)
+// Extend wiringPi with other pin-based devices and keep track of
+//	them in this structure
 
 
 struct wiringPiNodeStruct *wiringPiNodes = NULL ;
 struct wiringPiNodeStruct *wiringPiNodes = NULL ;
 
 
@@ -1244,13 +1242,15 @@ struct wiringPiNodeStruct *wiringPiFindNode (int pin)
  *********************************************************************************
  *********************************************************************************
  */
  */
 
 
-static void pinModeDummy             (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode)  { return ; }
-static void pullUpDnControlDummy     (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud)   { return ; }
-static int  digitalReadDummy         (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return LOW ; }
-static void digitalWriteDummy        (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
-static void pwmWriteDummy            (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
-static int  analogReadDummy          (UNU struct wiringPiNodeStruct *node, UNU int pin)            { return 0 ; }
-static void analogWriteDummy         (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
+static         void pinModeDummy             (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode)  { return ; }
+static         void pullUpDnControlDummy     (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud)   { return ; }
+static unsigned int digitalRead8Dummy        (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return 0 ; }
+static         void digitalWrite8Dummy       (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
+static          int digitalReadDummy         (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return LOW ; }
+static         void digitalWriteDummy        (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
+static         void pwmWriteDummy            (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
+static          int analogReadDummy          (UNU struct wiringPiNodeStruct *node, UNU int pin)            { return 0 ; }
+static         void analogWriteDummy         (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
 
 
 struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins)
 struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins)
 {
 {
@@ -1272,17 +1272,19 @@ struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins)
   if (node == NULL)
   if (node == NULL)
     (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ;
     (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ;
 
 
-  node->pinBase         = pinBase ;
-  node->pinMax          = pinBase + numPins - 1 ;
-  node->pinMode         = pinModeDummy ;
-  node->pullUpDnControl = pullUpDnControlDummy ;
-  node->digitalRead     = digitalReadDummy ;
-  node->digitalWrite    = digitalWriteDummy ;
-  node->pwmWrite        = pwmWriteDummy ;
-  node->analogRead      = analogReadDummy ;
-  node->analogWrite     = analogWriteDummy ;
-  node->next            = wiringPiNodes ;
-  wiringPiNodes         = node ;
+  node->pinBase          = pinBase ;
+  node->pinMax           = pinBase + numPins - 1 ;
+  node->pinMode          = pinModeDummy ;
+  node->pullUpDnControl  = pullUpDnControlDummy ;
+  node->digitalRead      = digitalReadDummy ;
+//node->digitalRead8     = digitalRead8Dummy ;
+  node->digitalWrite     = digitalWriteDummy ;
+//node->digitalWrite8    = digitalWrite8Dummy ;
+  node->pwmWrite         = pwmWriteDummy ;
+  node->analogRead       = analogReadDummy ;
+  node->analogWrite      = analogWriteDummy ;
+  node->next             = wiringPiNodes ;
+  wiringPiNodes          = node ;
 
 
   return node ;
   return node ;
 }
 }
@@ -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:
  * digitalWrite:
  *	Set an output bit
  *	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:
  * pwmWrite:
  *	Set an output PWM value
  *	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
 // C doesn't have true/false by default and I can never remember which
 //	way round they are, so ...
 //	way round they are, so ...
+//	(and yes, I know about stdbool.h but I like capitals for these and I'm old)
 
 
 #ifndef	TRUE
 #ifndef	TRUE
 #  define	TRUE	(1==1)
 #  define	TRUE	(1==1)
@@ -36,6 +37,11 @@
 
 
 #define	UNU	__attribute__((unused))
 #define	UNU	__attribute__((unused))
 
 
+// Mask for the bottom 64 pins which belong to the Raspberry Pi
+//	The others are available for the other devices
+
+#define	PI_GPIO_MASK	(0xFFFFFFC0)
+
 // Handy defines
 // Handy defines
 
 
 // wiringPi modes
 // wiringPi modes
@@ -140,13 +146,15 @@ struct wiringPiNodeStruct
   unsigned int data2 ;	//  ditto
   unsigned int data2 ;	//  ditto
   unsigned int data3 ;	//  ditto
   unsigned int data3 ;	//  ditto
 
 
-  void   (*pinMode)         (struct wiringPiNodeStruct *node, int pin, int mode) ;
-  void   (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ;
-  int    (*digitalRead)     (struct wiringPiNodeStruct *node, int pin) ;
-  void   (*digitalWrite)    (struct wiringPiNodeStruct *node, int pin, int value) ;
-  void   (*pwmWrite)        (struct wiringPiNodeStruct *node, int pin, int value) ;
-  int    (*analogRead)      (struct wiringPiNodeStruct *node, int pin) ;
-  void   (*analogWrite)     (struct wiringPiNodeStruct *node, int pin, int value) ;
+           void   (*pinMode)          (struct wiringPiNodeStruct *node, int pin, int mode) ;
+           void   (*pullUpDnControl)  (struct wiringPiNodeStruct *node, int pin, int mode) ;
+           int    (*digitalRead)      (struct wiringPiNodeStruct *node, int pin) ;
+//unsigned int    (*digitalRead8)     (struct wiringPiNodeStruct *node, int pin) ;
+           void   (*digitalWrite)     (struct wiringPiNodeStruct *node, int pin, int value) ;
+//         void   (*digitalWrite8)    (struct wiringPiNodeStruct *node, int pin, int value) ;
+           void   (*pwmWrite)         (struct wiringPiNodeStruct *node, int pin, int value) ;
+           int    (*analogRead)       (struct wiringPiNodeStruct *node, int pin) ;
+           void   (*analogWrite)      (struct wiringPiNodeStruct *node, int pin, int value) ;
 
 
   struct wiringPiNodeStruct *next ;
   struct wiringPiNodeStruct *next ;
 } ;
 } ;
@@ -179,14 +187,16 @@ extern int  wiringPiSetupSys    (void) ;
 extern int  wiringPiSetupGpio   (void) ;
 extern int  wiringPiSetupGpio   (void) ;
 extern int  wiringPiSetupPhys   (void) ;
 extern int  wiringPiSetupPhys   (void) ;
 
 
-extern void pinModeAlt          (int pin, int mode) ;
-extern void pinMode             (int pin, int mode) ;
-extern void pullUpDnControl     (int pin, int pud) ;
-extern int  digitalRead         (int pin) ;
-extern void digitalWrite        (int pin, int value) ;
-extern void pwmWrite            (int pin, int value) ;
-extern int  analogRead          (int pin) ;
-extern void analogWrite         (int pin, int value) ;
+extern          void pinModeAlt          (int pin, int mode) ;
+extern          void pinMode             (int pin, int mode) ;
+extern          void pullUpDnControl     (int pin, int pud) ;
+extern          int  digitalRead         (int pin) ;
+extern          void digitalWrite        (int pin, int value) ;
+extern unsigned int  digitalRead8        (int pin) ;
+extern          void digitalWrite8       (int pin, int value) ;
+extern          void pwmWrite            (int pin, int value) ;
+extern          int  analogRead          (int pin) ;
+extern          void analogWrite         (int pin, int value) ;
 
 
 // PiFace specifics 
 // PiFace specifics 
 //	(Deprecated)
 //	(Deprecated)
@@ -204,12 +214,14 @@ extern          int  physPinToGpio       (int physPin) ;
 extern          void setPadDrive         (int group, int value) ;
 extern          void setPadDrive         (int group, int value) ;
 extern          int  getAlt              (int pin) ;
 extern          int  getAlt              (int pin) ;
 extern          void pwmToneWrite        (int pin, int freq) ;
 extern          void pwmToneWrite        (int pin, int freq) ;
-extern          void digitalWriteByte    (int value) ;
-extern unsigned int  digitalReadByte     (void) ;
 extern          void pwmSetMode          (int mode) ;
 extern          void pwmSetMode          (int mode) ;
 extern          void pwmSetRange         (unsigned int range) ;
 extern          void pwmSetRange         (unsigned int range) ;
 extern          void pwmSetClock         (int divisor) ;
 extern          void pwmSetClock         (int divisor) ;
 extern          void gpioClockSet        (int pin, int freq) ;
 extern          void gpioClockSet        (int pin, int freq) ;
+extern unsigned int  digitalReadByte     (void) ;
+extern unsigned int  digitalReadByte2    (void) ;
+extern          void digitalWriteByte    (int value) ;
+extern          void digitalWriteByte2   (int value) ;
 
 
 // Interrupts
 // Interrupts
 //	(Also Pi hardware specific)
 //	(Also Pi hardware specific)

+ 104 - 7
wiringPi/wpiExtensions.c

@@ -55,10 +55,13 @@
 #include "ads1115.h"
 #include "ads1115.h"
 #include "sn3218.h"
 #include "sn3218.h"
 #include "drcSerial.h"
 #include "drcSerial.h"
+#include "drcNet.h"
+#include "../wiringPiD/drcNetCmd.h"
 #include "pseudoPins.h"
 #include "pseudoPins.h"
 #include "bmp180.h"
 #include "bmp180.h"
 #include "htu21d.h"
 #include "htu21d.h"
 #include "ds18b20.h"
 #include "ds18b20.h"
+#include "rht03.h"
 
 
 #include "wpiExtensions.h"
 #include "wpiExtensions.h"
 
 
@@ -134,12 +137,16 @@ static char *extractInt (char *progName, char *p, int *num)
 /*
 /*
  * extractStr:
  * extractStr:
  *	Check & return a string at the given location (prefixed by a :)
  *	Check & return a string at the given location (prefixed by a :)
+ *	Note: The string can be enclosed in []'s to escape colons. This is
+ *	so we can handle IPv6 addresses which contain colons and the []'s is
+ *	a common way to prepresent them.
  *********************************************************************************
  *********************************************************************************
  */
  */
 
 
 static char *extractStr (char *progName, char *p, char **str)
 static char *extractStr (char *progName, char *p, char **str)
 {
 {
   char *q, *r ;
   char *q, *r ;
+  int quoted = FALSE ;
 
 
   if (*p != ':')
   if (*p != ':')
   {
   {
@@ -149,21 +156,38 @@ static char *extractStr (char *progName, char *p, char **str)
 
 
   ++p ;
   ++p ;
 
 
-  if (!isprint (*p))
+  if (*p == '[')
+  {
+    quoted = TRUE ;
+    ++p ;
+  }
+
+  if (!isprint (*p))	// Is this needed?
   {
   {
     verbError ("%s: character expected", progName) ;
     verbError ("%s: character expected", progName) ;
     return NULL ;
     return NULL ;
   }
   }
 
 
   q = p ;
   q = p ;
-  while ((*q != 0) && (*q != ':'))
-    ++q ;
+  if (quoted)
+  {
+    while ((*q != 0) && (*q != ']'))
+      ++q ;
+  }
+  else
+  {
+    while ((*q != 0) && (*q != ':'))
+      ++q ;
+  }
 
 
   *str = r = calloc (q - p + 2, 1) ;	// Zeros it
   *str = r = calloc (q - p + 2, 1) ;	// Zeros it
 
 
   while (p != q)
   while (p != q)
     *r++ = *p++ ;
     *r++ = *p++ ;
-    
+
+  if (quoted)				// Skip over the ] to the :
+    ++p ;
+
   return p ;
   return p ;
 }
 }
 
 
@@ -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:
  * doExtensionMax31855:
  *	Analog IO
  *	Analog IO
@@ -698,9 +740,9 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params)
   if ((params = extractInt (progName, params, &pins)) == NULL)
   if ((params = extractInt (progName, params, &pins)) == NULL)
     return FALSE ;
     return FALSE ;
 
 
-  if ((pins < 1) || (pins > 100))
+  if ((pins < 1) || (pins > 1000))
   {
   {
-    verbError ("%s: pins (%d) out of range (2-100)", progName, pins) ;
+    verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ;
     return FALSE ;
     return FALSE ;
   }
   }
   
   
@@ -728,6 +770,59 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params)
 }
 }
 
 
 
 
+/*
+ * doExtensionDrcNet:
+ *	Interface to a DRC Network system
+ *	drcn:base:pins:ipAddress:port:password
+ *********************************************************************************
+ */
+
+static int doExtensionDrcNet (char *progName, int pinBase, char *params)
+{
+  int pins ;
+  char *ipAddress, *port, *password ;
+  char pPort [1024] ;
+
+  if ((params = extractInt (progName, params, &pins)) == NULL)
+    return FALSE ;
+
+  if ((pins < 1) || (pins > 1000))
+  {
+    verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ;
+    return FALSE ;
+  }
+  
+  if ((params = extractStr (progName, params, &ipAddress)) == NULL)
+    return FALSE ;
+
+  if (strlen (ipAddress) == 0)
+  {
+    verbError ("%s: ipAddress required", progName) ;
+    return FALSE ;
+  }
+
+  if ((params = extractStr (progName, params, &port)) == NULL)
+    return FALSE ;
+
+  if (strlen (port) == 0)
+  {
+    sprintf (pPort, "%d", DEFAULT_SERVER_PORT) ;
+    port = pPort ;
+  }
+
+  if ((params = extractStr (progName, params, &password)) == NULL)
+    return FALSE ;
+
+  if (strlen (password) == 0)
+  {
+    verbError ("%s: password required", progName) ;
+    return FALSE ;
+  }
+
+  return drcSetupNet (pinBase, pins, ipAddress, port, password) ;
+}
+
+
 
 
 /*
 /*
  * Function list
  * Function list
@@ -748,6 +843,7 @@ static struct extensionFunctionStruct extensionFunctions [] =
   { "pseudoPins",	&doExtensionPseudoPins	},
   { "pseudoPins",	&doExtensionPseudoPins	},
   { "htu21d",		&doExtensionHtu21d	},
   { "htu21d",		&doExtensionHtu21d	},
   { "ds18b20",		&doExtensionDs18b20	},
   { "ds18b20",		&doExtensionDs18b20	},
+  { "rht03",		&doExtensionRht03	},
   { "mcp3002",		&doExtensionMcp3002	},
   { "mcp3002",		&doExtensionMcp3002	},
   { "mcp3004",		&doExtensionMcp3004	},
   { "mcp3004",		&doExtensionMcp3004	},
   { "mcp4802",		&doExtensionMcp4802	},
   { "mcp4802",		&doExtensionMcp4802	},
@@ -757,6 +853,7 @@ static struct extensionFunctionStruct extensionFunctions [] =
   { "max5322",		&doExtensionMax5322	},
   { "max5322",		&doExtensionMax5322	},
   { "sn3218",		&doExtensionSn3218	},
   { "sn3218",		&doExtensionSn3218	},
   { "drcs",		&doExtensionDrcS	},
   { "drcs",		&doExtensionDrcS	},
+  { "drcn",		&doExtensionDrcNet	},
   { NULL,		NULL		 	},
   { NULL,		NULL		 	},
 } ;
 } ;
 
 
@@ -826,6 +923,6 @@ int loadWPiExtension (char *progName, char *extensionData, int printErrors)
       return extensionFn->function (progName, pinBase, p) ;
       return extensionFn->function (progName, pinBase, p) ;
   }
   }
 
 
-  verbError ("%s: extension %s not found", progName, extension) ;
+  fprintf (stderr, "%s: extension %s not found", progName, extension) ;
   return FALSE ;
   return FALSE ;
 }
 }

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

二进制
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 ;
+}