From 05e2f67e7f43d83195fff108bcd952e7afe917ce Mon Sep 17 00:00:00 2001
From: Gordon Henderson <projects@drogon.net>
Date: Tue, 20 May 2014 11:43:07 +0100
Subject: [PATCH] changed to pin mode to support softPwm.
 bugfix in blink.sh - wring pin
 improving the maxdetect routing - a little.
 gpio pins

---
 examples/blink.sh     |    2 +-
 examples/blink6drcs.c |  115 +++++++++++++++++++++++++++++++++++++++++++++++++
 examples/rht03.c      |    5 ++
 gpio/Makefile         |   12 +++---
 gpio/gpio.1           |   27 +++++++++++-
 gpio/gpio.c           |    9 +++-
 gpio/pins.c           |   70 ++++++++++++++++++++++++++++++
 wiringPi/softPwm.c    |   49 +++++++++++++++++---
 wiringPi/softPwm.h    |    1 +
 wiringPi/wiringPi.c   |   11 ++++-
 wiringPi/wiringPi.h   |    1 +
 11 files changed, 281 insertions(+), 21 deletions(-)
 create mode 100644 examples/blink6drcs.c
 create mode 100644 gpio/pins.c

diff --git a/examples/blink.sh b/examples/blink.sh
index 2aa378a..7755383 100644
--- a/examples/blink.sh
+++ b/examples/blink.sh
@@ -25,7 +25,7 @@
 
 # LED Pin - wiringPi pin 0 is BCM_GPIO 17.
 
-LED=0
+PIN=0
 
 gpio mode $PIN out
 
diff --git a/examples/blink6drcs.c b/examples/blink6drcs.c
new file mode 100644
index 0000000..32f4921
--- /dev/null
+++ b/examples/blink6drcs.c
@@ -0,0 +1,115 @@
+/*
+ * blink6drcs.c:
+ *	Simple sequence over 6 pins on a remote DRC board.
+ *	Aimed at the Gertduino, but it's fairly generic.
+ *	This version uses DRC to talk to the ATmega on the Gertduino
+ *
+ * Copyright (c) 2012-2014 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 <drcSerial.h>
+
+#define	GERT_BASE	100
+
+static int pinMap [] =
+{
+  GERT_BASE + 6, GERT_BASE + 5, GERT_BASE + 3, GERT_BASE + 10, GERT_BASE + 9, GERT_BASE + 13,
+} ;
+
+// Simple sequencer data
+//	Triplets of LED, On/Off and delay
+
+
+int data [] =
+{
+               0, 1, 1,
+               1, 1, 1,
+   0, 0, 0,    2, 1, 1,
+   1, 0, 0,    3, 1, 1,
+   2, 0, 0,    4, 1, 1,
+   3, 0, 0,    5, 1, 1,
+   4, 0, 1,
+   5, 0, 1,
+
+   0, 0, 1,	// Extra delay
+
+// Back again
+
+               5, 1, 1,
+               4, 1, 1,
+   5, 0, 0,    3, 1, 1,
+   4, 0, 0,    2, 1, 1,
+   3, 0, 0,    1, 1, 1,
+   2, 0, 0,    0, 1, 1,
+   1, 0, 1,
+   0, 0, 1,
+
+   0, 0, 1,	// Extra delay
+
+   0, 9, 0,	// End marker
+
+} ;
+
+
+int main (void)
+{
+  int pin ;
+  int dataPtr ;
+  int l, s, d ;
+
+  printf ("Raspberry Pi - 6-LED Sequence\n") ;
+  printf ("=============================\n") ;
+  printf ("\n") ;
+  printf ("  Use the 2 buttons to temporarily speed up the sequence\n") ;
+
+  wiringPiSetupSys  () ;	// Not using the Pi's GPIO here
+  drcSetupSerial (GERT_BASE, 20, "/dev/ttyAMA0", 115200) ;
+
+  for (pin = 0 ; pin < 6 ; ++pin)
+    pinMode (pinMap [pin], OUTPUT) ;
+
+  pinMode (GERT_BASE + 16, INPUT) ;	// Buttons
+  pinMode (GERT_BASE + 17, INPUT) ;
+
+  pullUpDnControl (GERT_BASE + 16, PUD_UP) ;
+  pullUpDnControl (GERT_BASE + 17, PUD_UP) ;
+
+  dataPtr = 0 ;
+
+  for (;;)
+  {
+    l = data [dataPtr++] ;	// LED
+    s = data [dataPtr++] ;	// State
+    d = data [dataPtr++] ;	// Duration (10ths)
+
+    if (s == 9)			// 9 -> End Marker
+    {
+      dataPtr = 0 ;
+      continue ;
+    }
+
+    digitalWrite (pinMap [l], s) ;
+    delay        (d * digitalRead (GERT_BASE + 16) * 15 + digitalRead (GERT_BASE + 17) * 20) ;
+  }
+
+  return 0 ;
+}
diff --git a/examples/rht03.c b/examples/rht03.c
index e0cc116..566e954 100644
--- a/examples/rht03.c
+++ b/examples/rht03.c
@@ -56,6 +56,11 @@ int main (void)
     {
       temp = newTemp ;
       rh   = newRh ;
+      if ((temp & 0x8000) != 0)	// Negative
+      {
+	temp &= 0x7FFF ;
+	temp = -temp ;
+      }
       printf ("Temp: %5.1f, RH: %5.1f%%\n", temp / 10.0, rh / 10.0) ;
     }
   }
diff --git a/gpio/Makefile b/gpio/Makefile
index 8fa12d5..37b4887 100644
--- a/gpio/Makefile
+++ b/gpio/Makefile
@@ -38,7 +38,7 @@ LIBS    = -lwiringPi -lwiringPiDev -lpthread -lm
 # May not need to  alter anything below this line
 ###############################################################################
 
-SRC	=	gpio.c extensions.c readall.c
+SRC	=	gpio.c extensions.c readall.c pins.c
 
 OBJ	=	$(SRC:.c=.o)
 
@@ -52,17 +52,17 @@ gpio:	$(OBJ)
 	@echo [Compile] $<
 	@$(CC) -c $(CFLAGS) $< -o $@
 
-.PHONEY:	clean
+.PHONY:	clean
 clean:
 	@echo "[Clean]"
 	@rm -f $(OBJ) gpio *~ core tags *.bak
 
-.PHONEY:	tags
+.PHONY:	tags
 tags:	$(SRC)
 	@echo [ctags]
 	@ctags $(SRC)
 
-.PHONEY:	install
+.PHONY:	install
 install:
 	@echo "[Install]"
 	@cp gpio		$(DESTDIR)$(PREFIX)/bin
@@ -71,13 +71,13 @@ install:
 	@mkdir -p		$(DESTDIR)$(PREFIX)/man/man1
 	@cp gpio.1		$(DESTDIR)$(PREFIX)/man/man1
 
-.PHONEY:	uninstall
+.PHONY:	uninstall
 uninstall:
 	@echo "[UnInstall]"
 	@rm -f $(DESTDIR)$(PREFIX)/bin/gpio
 	@rm -f $(DESTDIR)$(PREFIX)/man/man1/gpio.1
 
-.PHONEY:	depend
+.PHONY:	depend
 depend:
 	makedepend -Y $(SRC)
 
diff --git a/gpio/gpio.1 b/gpio/gpio.1
index e1cba32..7300466 100644
--- a/gpio/gpio.1
+++ b/gpio/gpio.1
@@ -115,6 +115,28 @@ Write the given value (0 or 1) to the pin. You need to set the pin
 to output mode first.
 
 .TP
+.B aread <pin>
+Read the analog value of the given pin. This needs to be uses in
+conjunction with a -x flag to add in an extension that handles analog
+inputs.  respective logic levels.
+
+e.g. gpio -x mcp3002:200:0 aread 200
+
+will read the first analog input on an mcp3002 SPI ADC chip.
+
+.TP
+.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.
+
+e.g. gpio -x mcp4802:200:0 awrite 200 128
+
+will write the value 128 to the first DAC port on an mcp4802 chip on
+the Pi's SPI bus 0.
+
+
+.TP
 .B wb <value>
 Write the given byte to the 8 main GPIO pins. You can prefix it with 0x
 to specify a hexadecimal number. You need to set pins to output mode
@@ -132,8 +154,9 @@ digital and analog read on each pin in-turn.
 
 .TP
 .B reset
-Resets the GPIO - As much as it's possible to do. All pins are set to input
-mode and all the internal pull-up/down resistors are disconnected (tristate mode).
+Resets the GPIO - As much as it's possible to do. All pins are set to
+input mode and all the internal pull-up/down resistors are disconnected
+(tristate mode).
 
 The reset command is usable with an extension module (via the -x parameter),
 but it's limited to turning the pin into input mode (if applicable) and
diff --git a/gpio/gpio.c b/gpio/gpio.c
index b65af0e..d941db5 100644
--- a/gpio/gpio.c
+++ b/gpio/gpio.c
@@ -43,15 +43,19 @@
 
 extern int wiringPiDebug ;
 
+// External functions I can't be bothered creating a separate .h file for:
+
 extern void doReadall    (void) ;
 extern void doReadallOld (void) ;
 
+extern void doPins       (void) ;
+
 #ifndef TRUE
 #  define	TRUE	(1==1)
 #  define	FALSE	(1==2)
 #endif
 
-#define	VERSION		"2.13"
+#define	VERSION		"2.14"
 #define	I2CDETECT	"/usr/sbin/i2cdetect"
 
 int wpMode ;
@@ -1078,7 +1082,7 @@ int main (int argc, char *argv [])
   if (strcmp (argv [1], "-v") == 0)
   {
     printf ("gpio version: %s\n", VERSION) ;
-    printf ("Copyright (c) 2012-2013 Gordon Henderson\n") ;
+    printf ("Copyright (c) 2012-2014 Gordon Henderson\n") ;
     printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
     printf ("For details type: %s -warranty\n", argv [0]) ;
     printf ("\n") ;
@@ -1220,6 +1224,7 @@ int main (int argc, char *argv [])
   else if (strcasecmp (argv [1], "drive"    ) == 0) doPadDrive   (argc, argv) ;
   else if (strcasecmp (argv [1], "readall"  ) == 0) doReadallOld () ;
   else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall    () ;
+  else if (strcasecmp (argv [1], "pins"     ) == 0) doPins       () ;
   else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect  (argc, argv) ;
   else if (strcasecmp (argv [1], "i2cd"     ) == 0) doI2Cdetect  (argc, argv) ;
   else if (strcasecmp (argv [1], "reset"    ) == 0) doReset      (argv [0]) ;
diff --git a/gpio/pins.c b/gpio/pins.c
new file mode 100644
index 0000000..6df3cb2
--- /dev/null
+++ b/gpio/pins.c
@@ -0,0 +1,70 @@
+/*
+ * pins.c:
+ *	Just display a handy Pi pinnout diagram.
+ *	Copyright (c) 2012-2013 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 <stdlib.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <wiringPi.h>
+
+extern int wpMode ;
+
+void doPins (void)
+{
+  printf ("This Raspberry Pi is a revision %d board.\n", piBoardRev ()) ;
+
+  printf (
+" +-----+--------+------------+--------+-----+\n"
+" | Pin |   Name ||  P1 Pin  ||  Name  | Pin |\n"
+" +-----+--------+------------+--------+-----+\n"
+" |     |  3.3v  ||  1 oo 2  ||     5v |     |\n"
+" |   8 |   SDA  ||  3 oo 4  ||     5v |     |\n"
+" |   9 |    SCL ||  5 oo 6  ||    Gnd |     |\n"
+" |   7 | GPIO 7 ||  7 oo 8  ||    TxD |  15 |\n"
+" |     |    GND ||  9 oo 10 ||    RxD |  16 |\n"
+" |   0 | GPIO 0 || 11 oo 12 || GPIO 1 |   1 |\n"
+" |   2 | GPIO 2 || 13 oo 14 ||    Gnd |     |\n"
+" |   3 | GPIO 3 || 15 oo 16 || GPIO 4 |   4 |\n"
+" |     |   3.3v || 17 oo 18 || GPIO 5 |   5 |\n"
+" |  12 |   MOSI || 19 oo 20 ||    Gnd |     |\n"
+" |  13 |   MISO || 21 oo 22 || GPIO 6 |   6 |\n"
+" |  14 |   SCLK || 23 oo 24 ||   CE 0 |  10 |\n"
+" |     |    Gnd || 25 oo 26 ||   CE 1 |  11 |\n"
+" +-----+--------+------------+--------+-----+\n") ;
+
+/***
+ +---
+ |  5v|  5v| Gnd | TxD | RxD | G1  | Gnd |  G4  |  G5  | G
+ |  2 |  4 |  6 |  8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 |\n"
+ |  1 |  3 |  5 |  7 |  9 | 11 | 13 | 15 | 17 | 19 | 21 | 23 | 25 |\n"
+***/
+
+}
diff --git a/wiringPi/softPwm.c b/wiringPi/softPwm.c
index a4f0fc4..0bde180 100644
--- a/wiringPi/softPwm.c
+++ b/wiringPi/softPwm.c
@@ -1,7 +1,7 @@
 /*
  * softPwm.c:
  *	Provide 2 channels of software driven PWM.
- *	Copyright (c) 2012 Gordon Henderson
+ *	Copyright (c) 2012-2014 Gordon Henderson
  ***********************************************************************
  * This file is part of wiringPi:
  *	https://projects.drogon.net/raspberry-pi/wiringpi/
@@ -28,17 +28,22 @@
 #include "wiringPi.h"
 #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...
+
 #define	MAX_PINS	1024
 
 // The PWM Frequency is derived from the "pulse time" below. Essentially,
 //	the frequency is a function of the range and this pulse time.
-//	The total period will be range * pulse time in uS, so a pulse time
-//	of 100 and a range of 100 gives a period of 100 * 100 = 10,000 uS
+//	The total period will be range * pulse time in ÂµS, so a pulse time
+//	of 100 and a range of 100 gives a period of 100 * 100 = 10,000 ÂµS
 //	which is a frequency of 100Hz.
 //
 //	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 100uS - 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.
 //
 //	Another way to increase the frequency is to reduce the range - however
@@ -46,8 +51,9 @@
 
 #define	PULSE_TIME	100
 
-static int marks [MAX_PINS] ;
-static int range [MAX_PINS] ;
+static int marks         [MAX_PINS] ;
+static int range         [MAX_PINS] ;
+static pthread_t threads [MAX_PINS] ;
 
 int newPin = -1 ;
 
@@ -106,13 +112,20 @@ void softPwmWrite (int pin, int value)
 
 /*
  * softPwmCreate:
- *	Create a new PWM thread.
+ *	Create a new softPWM thread.
  *********************************************************************************
  */
 
 int softPwmCreate (int pin, int initialValue, int pwmRange)
 {
   int res ;
+  pthread_t myThread ;
+
+  if (range [pin] != 0)	// Already running on this pin
+    return -1 ;
+
+  if (range <= 0)
+    return -1 ;
 
   pinMode      (pin, OUTPUT) ;
   digitalWrite (pin, LOW) ;
@@ -121,10 +134,30 @@ int softPwmCreate (int pin, int initialValue, int pwmRange)
   range [pin] = pwmRange ;
 
   newPin = pin ;
-  res = piThreadCreate (softPwmThread) ;
+  res    = pthread_create (&myThread, NULL, softPwmThread, NULL) ;
 
   while (newPin != -1)
     delay (1) ;
 
+  threads [pin] = myThread ;
+
   return res ;
 }
+
+
+/*
+ * softPwmStop:
+ *	Stop an existing softPWM thread
+ *********************************************************************************
+ */
+
+void softPwmStop (int pin)
+{
+  if (range [pin] != 0)
+  {
+    pthread_cancel (threads [pin]) ;
+    pthread_join   (threads [pin], NULL) ;
+    range [pin] = 0 ;
+    digitalWrite (pin, LOW) ;
+}
+}
diff --git a/wiringPi/softPwm.h b/wiringPi/softPwm.h
index 28ad299..0351da5 100644
--- a/wiringPi/softPwm.h
+++ b/wiringPi/softPwm.h
@@ -28,6 +28,7 @@ extern "C" {
 
 extern int  softPwmCreate (int pin, int value, int range) ;
 extern void softPwmWrite  (int pin, int value) ;
+extern void softPwmStop   (int pin) ;
 
 #ifdef __cplusplus
 }
diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c
index b54ad29..4660a67 100644
--- a/wiringPi/wiringPi.c
+++ b/wiringPi/wiringPi.c
@@ -70,6 +70,8 @@
 #include <sys/wait.h>
 #include <sys/ioctl.h>
 
+#include "softPwm.h"
+
 #include "wiringPi.h"
 
 #ifndef	TRUE
@@ -961,6 +963,7 @@ void pinMode (int pin, int mode)
 {
   int    fSel, shift, alt ;
   struct wiringPiNodeStruct *node = wiringPiNodes ;
+  int origPin = pin ;
 
   if ((pin & PI_GPIO_MASK) == 0)		// On-board pin
   {
@@ -971,6 +974,8 @@ void pinMode (int pin, int mode)
     else if (wiringPiMode != WPI_MODE_GPIO)
       return ;
 
+    softPwmStop (origPin) ;
+
     fSel    = gpioToGPFSEL [pin] ;
     shift   = gpioToShift  [pin] ;
 
@@ -978,9 +983,11 @@ void pinMode (int pin, int mode)
       *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input
     else if (mode == OUTPUT)
       *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ;
+    else if (mode == SOFT_PWM_OUTPUT)
+      softPwmCreate (origPin, 0, 100) ;
     else if (mode == PWM_OUTPUT)
     {
-      if ((alt = gpioToPwmALT [pin]) == 0)	// Not a PWM pin
+      if ((alt = gpioToPwmALT [pin]) == 0)	// Not a hardware capable PWM pin
 	return ;
 
 // Set pin to PWM mode
@@ -990,7 +997,7 @@ void pinMode (int pin, int mode)
 
       pwmSetMode  (PWM_MODE_BAL) ;	// Pi default mode
       pwmSetRange (1024) ;		// Default range of 1024
-      pwmSetClock (32) ;			// 19.2 / 32 = 600KHz - Also starts the PWM
+      pwmSetClock (32) ;		// 19.2 / 32 = 600KHz - Also starts the PWM
     }
     else if (mode == GPIO_CLOCK)
     {
diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h
index ce4680a..4eea3e5 100644
--- a/wiringPi/wiringPi.h
+++ b/wiringPi/wiringPi.h
@@ -42,6 +42,7 @@
 #define	OUTPUT			 1
 #define	PWM_OUTPUT		 2
 #define	GPIO_CLOCK		 3
+#define	SOFT_PWM_OUTPUT		 4
 
 #define	LOW			 0
 #define	HIGH			 1
-- 
1.7.2.5

