Преглед изворни кода

Merged from git.drogon.net, SPI driver helpers, C++ wrappers, softPwm, piNes, gertboard, SPI

Gordon Henderson пре 11 година
родитељ
комит
ae40bdaf6a

+ 21 - 4
examples/Makefile

@@ -35,11 +35,11 @@ LIBS    = -lwiringPi
 # Should not alter anything below this line
 ###############################################################################
 
-SRC	=	test1.c test2.c speed.c lcd.c wfi.c piface.c
+SRC	=	test1.c test2.c speed.c lcd.c wfi.c piface.c gertboard.c nes.c delayTest.c softPwm.c
 
-OBJ	=	test1.o test2.o speed.o lcd.o wfi.o piface.o
+OBJ	=	test1.o test2.o speed.o lcd.o wfi.o piface.o gertboard.o nes.o delayTest.o softPwm.o
 
-all:		test1 test2 speed lcd wfi piface
+all:		test1 test2 speed lcd wfi piface gertboard nes softPwm
 
 test1:	test1.o
 	@echo [link]
@@ -65,13 +65,30 @@ piface:	piface.o
 	@echo [link]
 	$(CC) -o $@ piface.o $(LDFLAGS) $(LIBS) -lpthread
 
+gertboard:	gertboard.o
+	@echo [link]
+	$(CC) -o $@ gertboard.o $(LDFLAGS) $(LIBS) -lm
+
+nes:	nes.o
+	@echo [link]
+	$(CC) -o $@ nes.o $(LDFLAGS) $(LIBS) -lm
+
+softPwm:	softPwm.o
+	@echo [link]
+	$(CC) -o $@ softPwm.o $(LDFLAGS) $(LIBS) -lm -lpthread
+
+
+delayTest:	delayTest.o
+	@echo [link]
+	$(CC) -o $@ delayTest.o $(LDFLAGS) $(LIBS)
+
 
 .c.o:
 	@echo [CC] $<
 	@$(CC) -c $(CFLAGS) $< -o $@
 
 clean:
-	rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface
+	rm -f $(OBJ) *~ core tags test1 test2 speed lcd wfi piface gertboard nes delayTest softPwm
 
 tags:	$(SRC)
 	@echo [ctags]

+ 68 - 0
examples/delayTest.c

@@ -0,0 +1,68 @@
+
+#include <stdio.h>
+#include <unistd.h>
+#include <wiringPi.h>
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#define	CYCLES	1000
+#define	DELAY	99
+
+int main()
+{
+  int x ;
+  struct timeval t1, t2 ;
+  long long    t ;
+  unsigned int max, min ;
+
+  unsigned int values [CYCLES] ;
+
+  max = 0 ;
+  min = 1000000 ;
+
+  if (wiringPiSetup () == -1)
+    return 1 ;
+
+  piHiPri (10) ;
+  sleep (1) ;
+
+// Baseline test
+
+  gettimeofday (&t1, NULL) ;
+  gettimeofday (&t2, NULL) ;
+
+  t = t2.tv_usec - t1.tv_usec ;
+  printf ("Baseline test: %lld\n", t);
+
+  for (x = 0 ; x < CYCLES ; ++x)
+  {
+    gettimeofday (&t1, NULL) ;
+    delayMicroseconds (DELAY) ;
+    gettimeofday (&t2, NULL) ;
+      
+    t = t2.tv_usec - t1.tv_usec ;
+    if (t > max) max = t ;
+    if (t < min) min = t ;
+    values [x] = t ;
+  }
+
+  printf ("Done: Max: %d, min: %d\n", max, min) ;
+
+  for (x = 0 ; x < CYCLES ; ++x)
+  {
+    printf ("%4d", values [x]) ;
+    if (values [x] > DELAY)
+      printf (".") ;
+    else if (values [x] < DELAY)
+      printf ("-") ;
+    else
+      printf (" ") ;
+    if (((x + 1) % 20) == 0)
+      printf ("\n") ;
+  }
+  printf ("\n") ;
+
+  return 0 ;
+}

+ 77 - 0
examples/gertboard.c

@@ -0,0 +1,77 @@
+
+/*
+ * gertboard.c:
+ *	Simple test for the SPI bus on the Gertboard
+ *
+ *	Hardware setup:
+ *		D/A port 0 jumpered to A/D port 0.
+ *
+ *	We output a sine wave on D/A port 0 and sample A/D port 0. We then
+ *	copy this value to D/A port 1 and use a 'scope on both D/A ports
+ *	to check all's well.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <math.h>
+
+#define	B_SIZE	200
+#undef	DO_TIMING
+
+#include <wiringPi.h>
+#include <gertboard.h>
+
+int main (void)
+{
+  double angle ;
+  int i ;
+  uint32_t x1 ;
+  int  buffer [B_SIZE] ;
+
+#ifdef	DO_TIMING
+  unsigned int now, then ;
+#endif
+
+  printf ("Raspberry Pi Gertboard SPI test program\n") ;
+
+  if (wiringPiSetupSys () < 0)
+    return -1 ;
+
+  if (gertboardSPISetup () < 0)
+    return 1 ;
+
+// Generate a Sine Wave
+
+  for (i = 0 ; i < B_SIZE ; ++i)
+  {
+    angle = ((double)i / (double)B_SIZE) * M_PI * 2.0 ;
+    buffer [i] = (int)rint ((sin (angle)) * 127.0 + 128.0) ;
+  }
+
+
+  for (;;)
+  {
+#ifdef	DO_TIMING
+    then = millis () ;
+#endif
+
+    for (i = 0 ; i < B_SIZE ; ++i)
+    {
+      gertboardAnalogWrite (0, buffer [i]) ;
+
+#ifndef	DO_TIMING
+      x1 = gertboardAnalogRead (0) ;
+      gertboardAnalogWrite (1, x1 >> 2) ;	// 10-bit A/D, 8-bit D/A
+#endif
+    }
+
+#ifdef	DO_TIMING
+    now = millis () ;
+    printf ("%4d mS, %9.7f S/sample", now - then, ((double)(now - then) / 1000.0) / (double)B_SIZE) ;
+    printf (" -> %9.4f samples/sec \n", 1 / (((double)(now - then) / 1000.0) / (double)B_SIZE)) ;
+#endif
+  }
+
+  return 0 ;
+}

BIN
examples/gertboard.png


+ 44 - 0
examples/nes.c

@@ -0,0 +1,44 @@
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <wiringPi.h>
+#include <piNes.h>
+
+#define	BLANK	"|      "
+
+int main ()
+{
+  int joystick ;
+  unsigned int buttons ;
+
+  if (wiringPiSetup () == -1)
+  {
+    fprintf (stdout, "oops: %s\n", strerror (errno)) ;
+    return 1 ;
+  }
+
+  if ((joystick = setupNesJoystick (2, 1, 0)) == -1)
+  {
+    fprintf (stdout, "Unable to setup joystick\n") ;
+    return 1 ;
+  }
+
+  for (;;)
+  {
+    buttons = readNesJoystick (joystick) ;
+
+    if ((buttons & NES_UP)     != 0) printf ("|  UP  " ) ; else printf (BLANK) ;
+    if ((buttons & NES_DOWN)   != 0) printf ("| DOWN " ) ; else printf (BLANK) ;
+    if ((buttons & NES_LEFT)   != 0) printf ("| LEFT " ) ; else printf (BLANK) ;
+    if ((buttons & NES_RIGHT)  != 0) printf ("|RIGHT " ) ; else printf (BLANK) ;
+    if ((buttons & NES_SELECT) != 0) printf ("|SELECT" ) ; else printf (BLANK) ;
+    if ((buttons & NES_START)  != 0) printf ("|START " ) ; else printf (BLANK) ;
+    if ((buttons & NES_A)      != 0) printf ("|  A   " ) ; else printf (BLANK) ;
+    if ((buttons & NES_B)      != 0) printf ("|  B   " ) ; else printf (BLANK) ;
+    printf ("|\n") ;
+  }
+
+  return 0 ;
+}

+ 69 - 0
examples/softPwm.c

@@ -0,0 +1,69 @@
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <wiringPi.h>
+#include <softPwm.h>
+
+#define RANGE		100
+#define	NUM_LEDS	 12
+
+int ledMap [NUM_LEDS] = { 0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13 } ;
+
+int values [NUM_LEDS] = { 0, 17, 32, 50, 67, 85, 100, 85, 67, 50, 32, 17 } ;
+
+int main ()
+{
+  int i, j ;
+  char buf [80] ;
+
+  if (wiringPiSetup () == -1)
+  {
+    fprintf (stdout, "oops: %s\n", strerror (errno)) ;
+    return 1 ;
+  }
+
+  for (i = 0 ; i < NUM_LEDS ; ++i)
+  {
+    softPwmCreate (ledMap [i], 0, RANGE) ;
+    printf ("%3d, %3d, %3d\n", i, ledMap [i], values [i]) ;
+  }
+
+  fgets (buf, 80, stdin) ;
+
+// Bring all up one by one:
+
+  for (i = 0 ; i < NUM_LEDS ; ++i)
+    for (j = 0 ; j <= 100 ; ++j)
+    {
+      softPwmWrite (ledMap [i], j) ;
+      delay (10) ;
+    }
+
+  fgets (buf, 80, stdin) ;
+
+// Down fast
+
+  for (i = 100 ; i > 0 ; --i)
+  {
+    for (j = 0 ; j < NUM_LEDS ; ++j)
+      softPwmWrite (ledMap [j], i) ;
+    delay (10) ;
+  }
+
+  fgets (buf, 80, stdin) ;
+
+  for (;;)
+  {
+    for (i = 0 ; i < NUM_LEDS ; ++i)
+      softPwmWrite (ledMap [i], values [i]) ;
+
+    delay (50) ;
+
+    i = values [0] ;
+    for (j = 0 ; j < NUM_LEDS - 1 ; ++j)
+      values [j] = values [j + 1] ;
+    values [NUM_LEDS - 1] = i ;
+  }
+}

+ 1 - 1
gpio/Makefile

@@ -41,7 +41,7 @@ OBJ	=	gpio.o
 
 all:		gpio
 
-gpio:	gpio.o
+gpio:	gpio.o /usr/local/lib/libwiringPi.a
 	@echo [LD]
 	@$(CC) -o $@ gpio.o $(LDFLAGS) $(LIBS)
 	

+ 83 - 19
gpio/gpio.1

@@ -4,28 +4,55 @@
 gpio \- Command-line access to Raspberry Pi and PiFace GPIO
 
 .SH SYNOPSIS
-.TP
 .B gpio
-.RB [ \-v ]
-.TP
+.B \-v
+.PP
 .B gpio
-.RB [ \-g ]
-.RB < read/write/pwm/mode ...>
-.TP
+.B [ \-g ]
+.B read/write/pwm/mode ...
+.PP
 .B gpio
-.RB [ \-p ]
-.RB < read/write/mode ...>
-.TP
+.B [ \-p ]
+.B read/write/mode
+.B ...
+.PP
+.B gpio
+.B unexportall/exports
+.PP
+.B gpio
+.B export/edge/unexport
+.B ...
+.PP
 .B gpio
-.RB < export/edge/unexport/unexportall/exports ...>
+.B drive
+group value
+.PP
+.B gpio
+.B pwm-bal/pwm-ms
+.PP
+.B gpio
+.B pwmr
+range
+.PP
+.B gpio
+.B load \ i2c/spi
+.PP
+.B gpio
+.B gbr
+channel
+.PP
+.B gpio
+.B gbw
+channel value
 
 .SH DESCRIPTION
 
 .B GPIO
-is a command line tool to allow the user easy access to the GPIO pins
-on the Raspberry Pi. It's designed for simple testing and diagnostic
-purposes, but can be used in shell scripts for general if somewhat slow
-control of the GPIO pins.
+is a swiss army knofe of a command line tool to allow the user easy
+access to the GPIO pins on the Raspberry Pi and the SPI A/D and D/A
+convertors on the Gertboard. It's designed for simple testing and
+diagnostic purposes, but can be used in shell scripts for general if
+somewhat slow control of the GPIO pins.
 
 Additionally, it can be used to set the exports in the \fI/sys/class/gpio\fR
 system directory to allow subsequent programs to use the \fR/sys/class/gpio\fR
@@ -64,6 +91,14 @@ Set a pin into \fIinput\fR, \fIoutput\fR or \fIpwm\fR mode. Can also
 use the literals \fIup\fR, \fIdown\fR or \fItri\fR to set the internal
 pull-up, pull-down or tristate (off) controls.
 
+.TP
+.B unexportall
+Un-Export all the GPIO pins in the /sys/class/gpio directory.
+
+.TP
+.B exports
+Print a list (if any) of all the exported GPIO pins and their current values.
+
 .TP
 .B export
 Export a GPIO pin in the \fI/sys/class/gpio\fR directory. Use like the
@@ -96,12 +131,41 @@ requiring root/sudo.
 Un-Export a GPIO pin in the /sys/class/gpio directory.
 
 .TP
-.B unexportall
-Un-Export all the GPIO pins in the /sys/class/gpio directory.
+.B drive
+group value
+
+Change the pad driver value for the given pad group to the supplied drive
+value. Group is 0, 1 or 2 and value is 0-7. Do not use unless you are
+absolutely sure you know what you're doing.
 
 .TP
-.B exports
-Print a list (if any) of all the exported GPIO pins and their current values.
+.B pwm-bal/pwm-ms 
+Change the PWM mode to balanced (the default) or mark:space ratio (traditional)
+
+.TP
+.B pwmr
+Change the PWM range register. The default is 1024.
+
+.TP
+.B load i2c/spi
+This loads the i2c or the spi drivers into the system and changes the permissions on
+the associated /dev/ entries so that the current user has access to them.
+
+.TP
+.B gbr
+channel
+
+This reads the analog to digital convertor on the Gertboard on the given
+channel. The board jumpers need to be in-place to do this operation.
+
+.TP
+.B gbw
+channel value
+
+This writes the supplied value to the output channel on the Gertboards
+SPI digital to analogue convertor.
+The board jumpers need to be in-place to do this operation.
+
 
 .SH "WiringPi vs. GPIO Pin numbering"
 
@@ -170,7 +234,7 @@ Gordon Henderson
 
 .SH "REPORTING BUGS"
 
-Report bugs to <gordon@drogon.net>
+Report bugs to <projects@drogon.net>
 
 .SH COPYRIGHT
 

+ 360 - 90
gpio/gpio.c

@@ -1,6 +1,7 @@
 /*
  * gpio.c:
- *	Set-UID command-line interface to the Raspberry Pi's GPIO
+ *	Swiss-Army-Knife, Set-UID command-line interface to the Raspberry
+ *	Pi's GPIO.
  *	Copyright (c) 2012 Gordon Henderson
  ***********************************************************************
  * This file is part of wiringPi:
@@ -21,7 +22,6 @@
  ***********************************************************************
  */
 
-#include <wiringPi.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -32,15 +32,144 @@
 #include <sys/types.h>
 #include <fcntl.h>
 
+#include <wiringPi.h>
+#include <gertboard.h>
+
+#ifndef TRUE
+#  define	TRUE	(1==1)
+#  define	FALSE	(1==2)
+#endif
 
-#define	VERSION	"1.0"
+#define	VERSION	"1.2"
 
 static int wpMode ;
 
 char *usage = "Usage: gpio -v\n"
+              "       gpio -h\n"
               "       gpio [-g] <read/write/pwm/mode> ...\n"
               "       gpio [-p] <read/write/mode> ...\n"
-	      "       gpio <export/edge/unexport/unexportall/exports> ..." ;
+	      "       gpio export/edge/unexport/unexportall/exports ...\n"
+	      "       gpio drive <group> <value>\n"
+	      "       gpio pwm-bal/pwm-ms \n"
+	      "       gpio pwmr <range> \n"
+	      "       gpio load spi/i2c\n"
+	      "       gpio gbr <channel>\n"
+	      "       gpio gbw <channel> <value>\n" ;
+
+
+/*
+ * changeOwner:
+ *	Change the ownership of the file to the real userId of the calling
+ *	program so we can access it.
+ *********************************************************************************
+ */
+
+static void changeOwner (char *cmd, char *file)
+{
+  uid_t uid = getuid () ;
+  uid_t gid = getgid () ;
+
+  if (chown (file, uid, gid) != 0)
+  {
+    if (errno == ENOENT)	// Warn that it's not there
+      fprintf (stderr, "%s: Warning: File not present: %s\n", cmd, file) ;
+    else
+    {
+      fprintf (stderr, "%s: Unable to change ownership of %s: %s\n", cmd, file, strerror (errno)) ;
+      exit (1) ;
+    }
+  }
+}
+
+
+/*
+ * moduleLoaded:
+ *	Return true/false if the supplied module is loaded
+ *********************************************************************************
+ */
+
+static int moduleLoaded (char *modName)
+{
+  int len   = strlen (modName) ;
+  int found = FALSE ;
+  FILE *fd = fopen ("/proc/modules", "r") ;
+  char line [80] ;
+
+  if (fd == NULL)
+  {
+    fprintf (stderr, "gpio: Unable to check modules: %s\n", strerror (errno)) ;
+    exit (1) ;
+  }
+
+  while (fgets (line, 80, fd) != NULL)
+  {
+    if (strncmp (line, modName, len) != 0)
+      continue ;
+
+    found = TRUE ;
+    break ;
+  }
+
+  fclose (fd) ;
+
+  return found ;
+}
+
+
+/*
+ * doLoad:
+ *	Load either the spi or i2c modules and change device ownerships, etc.
+ *********************************************************************************
+ */
+
+static void _doLoadUsage (char *argv [])
+{
+  fprintf (stderr, "Usage: %s load <spi/i2c>\n", argv [0]) ;
+  exit (1) ;
+}
+
+static void doLoad (int argc, char *argv [])
+{
+  char *module ;
+  char cmd [80] ;
+  char *file1, *file2 ;
+
+  if (argc != 3)
+    _doLoadUsage (argv) ;
+
+  /**/ if (strcasecmp (argv [2], "spi") == 0)
+  {
+    module = "spi_bcm2708" ;
+    file1  = "/dev/spidev0.0" ;
+    file2  = "/dev/spidev0.1" ;
+  }
+  else if (strcasecmp (argv [2], "i2c") == 0)
+  {
+    module = "i2c_bcm2708" ;
+    file1  = "/dev/i2c-0" ;
+    file2  = "/dev/i2c-1" ;
+  }
+  else
+    _doLoadUsage (argv) ;
+
+  if (!moduleLoaded (module))
+  {
+    sprintf (cmd, "modprobe %s", module) ;
+    system (cmd) ;
+  }
+
+  if (!moduleLoaded (module))
+  {
+    fprintf (stderr, "%s: Unable to load %s\n", argv [0], module) ;
+    exit (1) ;
+  }
+
+  sleep (1) ;	// To let things get settled
+
+  changeOwner (argv [0], file1) ;
+  changeOwner (argv [0], file2) ;
+}
+
 
 
 /*
@@ -49,7 +178,7 @@ char *usage = "Usage: gpio -v\n"
  *********************************************************************************
  */
 
-void doExports (void)
+static void doExports (int argc, char *argv [])
 {
   int fd ;
   int i, l, first ;
@@ -140,8 +269,6 @@ void doExport (int argc, char *argv [])
   int pin ;
   char *mode ;
   char fName [128] ;
-  uid_t uid ;
-  gid_t gid ;
 
   if (argc != 4)
   {
@@ -183,27 +310,11 @@ void doExport (int argc, char *argv [])
 
 // Change ownership so the current user can actually use it!
 
-  uid = getuid () ;
-  gid = getgid () ;
-
   sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
-  if (chown (fName, uid, gid) != 0)
-  {
-    fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
-    exit (1) ;
-  }
-
-// Also change ownership of the edge file - if it exists
+  changeOwner (argv [0], fName) ;
 
   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
-  if (chown (fName, uid, gid) != 0)
-  {
-    if (errno != ENOENT)	// Silently ignore File not found - older kernel
-    {
-      fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
-      exit (1) ;
-    }
-  }
+  changeOwner (argv [0], fName) ;
 
 }
 
@@ -222,8 +333,6 @@ void doEdge (int argc, char *argv [])
   int pin ;
   char *mode ;
   char fName [128] ;
-  uid_t uid ;
-  gid_t gid ;
 
   if (argc != 4)
   {
@@ -231,8 +340,7 @@ void doEdge (int argc, char *argv [])
     exit (1) ;
   }
 
-  pin = atoi (argv [2]) ;
-
+  pin  = atoi (argv [2]) ;
   mode = argv [3] ;
 
 // Export the pin and set direction to input
@@ -263,40 +371,23 @@ void doEdge (int argc, char *argv [])
     exit (1) ;
   }
 
-  /**/ if (strcasecmp (mode, "none")    == 0)
-    fprintf (fd, "none\n") ;
-  else if (strcasecmp (mode, "rising")  == 0)
-    fprintf (fd, "rising\n") ;
-  else if (strcasecmp (mode, "falling") == 0)
-    fprintf (fd, "falling\n") ;
-  else if (strcasecmp (mode, "both")    == 0)
-    fprintf (fd, "both\n") ;
+  /**/ if (strcasecmp (mode, "none")    == 0) fprintf (fd, "none\n") ;
+  else if (strcasecmp (mode, "rising")  == 0) fprintf (fd, "rising\n") ;
+  else if (strcasecmp (mode, "falling") == 0) fprintf (fd, "falling\n") ;
+  else if (strcasecmp (mode, "both")    == 0) fprintf (fd, "both\n") ;
   else
   {
     fprintf (stderr, "%s: Invalid mode: %s. Should be none, rising, falling or both\n", argv [1], mode) ;
     exit (1) ;
   }
 
-// Change ownership so the current user can actually use it!
-
-  uid = getuid () ;
-  gid = getgid () ;
+// Change ownership of the value and edge files, so the current user can actually use it!
 
   sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
-  if (chown (fName, uid, gid) != 0)
-  {
-    fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
-    exit (1) ;
-  }
-
-// Also change ownership of the edge file
+  changeOwner (argv [0], fName) ;
 
   sprintf (fName, "/sys/class/gpio/gpio%d/edge", pin) ;
-  if (chown (fName, uid, gid) != 0)
-  {
-    fprintf (stderr, "%s: Unable to change ownership of the value file: %s\n", argv [1], strerror (errno)) ;
-    exit (1) ;
-  }
+  changeOwner (argv [0], fName) ;
 
   fclose (fd) ;
 }
@@ -383,18 +474,12 @@ void doMode (int argc, char *argv [])
 
   mode = argv [3] ;
 
-  /**/ if (strcasecmp (mode, "in")   == 0)
-    pinMode (pin, INPUT) ;
-  else if (strcasecmp (mode, "out")  == 0)
-    pinMode (pin, OUTPUT) ;
-  else if (strcasecmp (mode, "pwm")  == 0)
-    pinMode (pin, PWM_OUTPUT) ;
-  else if (strcasecmp (mode, "up")   == 0)
-    pullUpDnControl (pin, PUD_UP) ;
-  else if (strcasecmp (mode, "down") == 0)
-    pullUpDnControl (pin, PUD_DOWN) ;
-  else if (strcasecmp (mode, "tri") == 0)
-    pullUpDnControl (pin, PUD_OFF) ;
+  /**/ if (strcasecmp (mode, "in")   == 0) pinMode         (pin, INPUT) ;
+  else if (strcasecmp (mode, "out")  == 0) pinMode         (pin, OUTPUT) ;
+  else if (strcasecmp (mode, "pwm")  == 0) pinMode         (pin, PWM_OUTPUT) ;
+  else if (strcasecmp (mode, "up")   == 0) pullUpDnControl (pin, PUD_UP) ;
+  else if (strcasecmp (mode, "down") == 0) pullUpDnControl (pin, PUD_DOWN) ;
+  else if (strcasecmp (mode, "tri")  == 0) pullUpDnControl (pin, PUD_OFF) ;
   else
   {
     fprintf (stderr, "%s: Invalid mode: %s. Should be in/out/pwm/up/down/tri\n", argv [1], mode) ;
@@ -402,13 +487,125 @@ void doMode (int argc, char *argv [])
   }
 }
 
+
+/*
+ * doPadDrive:
+ *	gpio drive group value
+ *********************************************************************************
+ */
+
+static void doPadDrive (int argc, char *argv [])
+{
+  int group, val ;
+
+  if (argc != 4)
+  {
+    fprintf (stderr, "Usage: %s drive group value\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  group = atoi (argv [2]) ;
+  val   = atoi (argv [3]) ;
+
+  if ((group < 0) || (group > 2))
+  {
+    fprintf (stderr, "%s: drive group not 0, 1 or 2: %d\n", argv [0], group) ;
+    exit (1) ;
+  }
+
+  if ((val < 0) || (val > 7))
+  {
+    fprintf (stderr, "%s: drive value not 0-7: %d\n", argv [0], val) ;
+    exit (1) ;
+  }
+
+  setPadDrive (group, val) ;
+}
+
+
+/*
+ * doGbw:
+ *	gpio gbw channel value
+ *********************************************************************************
+ */
+
+static void doGbw (int argc, char *argv [])
+{
+  int channel, value ;
+
+  if (argc != 4)
+  {
+    fprintf (stderr, "Usage: %s gbr <channel> <value>\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  channel = atoi (argv [2]) ;
+  value   = atoi (argv [3]) ;
+
+  if ((channel < 0) || (channel > 1))
+  {
+    fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  if ((value < 0) || (value > 1023))
+  {
+    fprintf (stderr, "%s: value must be from 0 to 255\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  if (gertboardSPISetup () == -1)
+  {
+    fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ;
+    exit (1) ;
+  }
+
+  gertboardAnalogWrite (channel, value) ;
+}
+
+
+/*
+ * doGbr:
+ *	gpio gbr channel
+ *********************************************************************************
+ */
+
+static void doGbr (int argc, char *argv [])
+{
+  int channel ;
+
+  if (argc != 3)
+  {
+    fprintf (stderr, "Usage: %s gbr <channel>\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  channel = atoi (argv [2]) ;
+
+  if ((channel < 0) || (channel > 1))
+  {
+    fprintf (stderr, "%s: channel must be 0 or 1\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  if (gertboardSPISetup () == -1)
+  {
+    fprintf (stderr, "Unable to initialise the Gertboard SPI interface: %s\n", strerror (errno)) ;
+    exit (1) ;
+  }
+
+  printf ("%d\n",gertboardAnalogRead (channel)) ;
+}
+
+
+
 /*
  * doWrite:
  *	gpio write pin value
  *********************************************************************************
  */
 
-void doWrite (int argc, char *argv [])
+static void doWrite (int argc, char *argv [])
 {
   int pin, val ;
 
@@ -489,6 +686,39 @@ void doPwm (int argc, char *argv [])
 }
 
 
+/*
+ * doPwmMode: doPwmRange:
+ *	Change the PWM mode and Range values
+ *********************************************************************************
+ */
+
+static void doPwmMode (int mode)
+{
+  pwmSetMode (mode) ;
+}
+
+static void doPwmRange (int argc, char *argv [])
+{
+  unsigned int range ;
+
+  if (argc != 3)
+  {
+    fprintf (stderr, "Usage: %s pwmr <range>\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  range = (unsigned int)strtoul (argv [2], NULL, 10) ;
+
+  if (range == 0)
+  {
+    fprintf (stderr, "%s: range must be > 0\n", argv [0]) ;
+    exit (1) ;
+  }
+
+  pwmSetRange (range) ;
+}
+
+
 /*
  * main:
  *	Start here
@@ -505,10 +735,10 @@ int main (int argc, char *argv [])
     return 1 ;
   }
 
-  if (geteuid () != 0)
+  if (strcasecmp (argv [1], "-h") == 0)
   {
-    fprintf (stderr, "%s: Must be root to run\n", argv [0]) ;
-    return 1 ;
+    printf ("%s: %s\n", argv [0], usage) ;
+    return 0 ;
   }
 
   if (strcasecmp (argv [1], "-v") == 0)
@@ -516,21 +746,54 @@ int main (int argc, char *argv [])
     printf ("gpio version: %s\n", VERSION) ;
     printf ("Copyright (c) 2012 Gordon Henderson\n") ;
     printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ;
+    printf ("For details type: %s -warranty\n", argv [0]) ;
     return 0 ;
   }
 
+  if (strcasecmp (argv [1], "-warranty") == 0)
+  {
+    printf ("gpio version: %s\n", VERSION) ;
+    printf ("Copyright (c) 2012 Gordon Henderson\n") ;
+    printf ("\n") ;
+    printf ("    This program is free software; you can redistribute it and/or modify\n") ;
+    printf ("    it under the terms of the GNU Leser General Public License as published\n") ;
+    printf ("    by the Free Software Foundation, either version 3 of the License, or\n") ;
+    printf ("    (at your option) any later version.\n") ;
+    printf ("\n") ;
+    printf ("    This program is distributed in the hope that it will be useful,\n") ;
+    printf ("    but WITHOUT ANY WARRANTY; without even the implied warranty of\n") ;
+    printf ("    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n") ;
+    printf ("    GNU Lesser General Public License for more details.\n") ;
+    printf ("\n") ;
+    printf ("    You should have received a copy of the GNU Lesser General Public License\n") ;
+    printf ("    along with this program. If not, see <http://www.gnu.org/licenses/>.\n") ;
+    printf ("\n") ;
+    return 0 ;
+  }
+
+  if (geteuid () != 0)
+  {
+    fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ;
+    return 1 ;
+  }
+
 // Initial test for /sys/class/gpio operations:
 
-  /**/ if (strcasecmp (argv [1], "exports" ) == 0)
-    { doExports () ;			return 0 ; }
-  else if (strcasecmp (argv [1], "export"  ) == 0)
-    { doExport (argc, argv) ;		return 0 ; }
-  else if (strcasecmp (argv [1], "edge"    ) == 0)
-    { doEdge (argc, argv) ;		return 0 ; }
-  else if (strcasecmp (argv [1], "unexportall") == 0)
-    { doUnexportall (argc, argv) ;	return 0 ; }
-  else if (strcasecmp (argv [1], "unexport") == 0)
-    { doUnexport (argc, argv) ;		return 0 ; }
+  /**/ if (strcasecmp (argv [1], "exports"    ) == 0)	{ doExports     (argc, argv) ;	return 0 ; }
+  else if (strcasecmp (argv [1], "export"     ) == 0)	{ doExport      (argc, argv) ;	return 0 ; }
+  else if (strcasecmp (argv [1], "edge"       ) == 0)	{ doEdge        (argc, argv) ;	return 0 ; }
+  else if (strcasecmp (argv [1], "unexportall") == 0)	{ doUnexportall (argc, argv) ;	return 0 ; }
+  else if (strcasecmp (argv [1], "unexport"   ) == 0)	{ doUnexport    (argc, argv) ;	return 0 ; }
+
+// Check for drive or load commands:
+
+  if (strcasecmp (argv [1], "drive") == 0)	{ doPadDrive (argc, argv) ; return 0 ; }
+  if (strcasecmp (argv [1], "load" ) == 0)	{ doLoad     (argc, argv) ; return 0 ; }
+
+// Gertboard commands
+
+  if (strcasecmp (argv [1], "gbr" ) == 0)	{ doGbr (argc, argv) ; return 0 ; }
+  if (strcasecmp (argv [1], "gbw" ) == 0)	{ doGbw (argc, argv) ; return 0 ; }
 
 // Check for -g argument
 
@@ -538,7 +801,7 @@ int main (int argc, char *argv [])
   {
     if (wiringPiSetupGpio () == -1)
     {
-      fprintf (stderr, "%s: Unable to initialise GPIO in GPIO mode.\n", argv [0]) ;
+      fprintf (stderr, "%s: Unable to initialise GPIO mode.\n", argv [0]) ;
       exit (1) ;
     }
 
@@ -570,23 +833,30 @@ int main (int argc, char *argv [])
   {
     if (wiringPiSetup () == -1)
     {
-      fprintf (stderr, "%s: Unable to initialise GPIO in wiringPi mode\n", argv [0]) ;
+      fprintf (stderr, "%s: Unable to initialise wiringPi mode\n", argv [0]) ;
       exit (1) ;
     }
     wpMode = WPI_MODE_PINS ;
   }
 
-  /**/ if (strcasecmp (argv [1], "write"   ) == 0)
-    doWrite  (argc, argv) ;
-  else if (strcasecmp (argv [1], "read"    ) == 0)
-    doRead   (argc, argv) ;
-  else if (strcasecmp (argv [1], "mode"    ) == 0)
-    doMode   (argc, argv) ;
-  else if (strcasecmp (argv [1], "pwm"     ) == 0)
-    doPwm    (argc, argv) ;
+// Check for PWM operations
+
+  if (wpMode != WPI_MODE_PIFACE)
+  {
+    if (strcasecmp (argv [1], "pwm-bal") == 0)	{ doPwmMode  (PWM_MODE_BAL) ; return 0 ; }
+    if (strcasecmp (argv [1], "pwm-ms")  == 0)	{ doPwmMode  (PWM_MODE_MS) ;  return 0 ; }
+    if (strcasecmp (argv [1], "pwmr")    == 0)	{ doPwmRange (argc, argv) ;   return 0 ; }
+  }
+
+// Check for wiring commands
+
+  /**/ if (strcasecmp (argv [1], "read" ) == 0) doRead     (argc, argv) ;
+  else if (strcasecmp (argv [1], "write") == 0) doWrite    (argc, argv) ;
+  else if (strcasecmp (argv [1], "pwm"  ) == 0) doPwm      (argc, argv) ;
+  else if (strcasecmp (argv [1], "mode" ) == 0) doMode     (argc, argv) ;
   else
   {
-    fprintf (stderr, "%s: Unknown command: %s. (read/write/pwm/mode expected)\n", argv [0], argv [1]) ;
+    fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ;
     exit (1) ;
   }
   return 0 ;

+ 122 - 0
wiringPi/gertboard.c

@@ -0,0 +1,122 @@
+/*
+ * gertboard.c:
+ *	Access routines for the SPI devices on the Gertboard
+ *	Copyright (c) 2012 Gordon Henderson
+ *
+ *	The Gertboard has:
+ *
+ *		An MCP3002 dual-channel A to D convertor connected
+ *		to the SPI bus, selected by chip-select A, and:
+ *
+ *		An MCP4802 dual-channel D to A convertor connected
+ *		to the SPI bus, selected via chip-select B.
+ *
+ ***********************************************************************
+ * 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 <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "wiringPiSPI.h"
+
+#include "gertboard.h"
+
+// The A-D convertor won't run at more than 1MHz @ 3.3v
+
+#define	SPI_ADC_SPEED	 1000000
+#define	SPI_DAC_SPEED	 1000000
+#define	SPI_A2D		0
+#define	SPI_D2A		1
+
+
+/*
+ * gertboardAnalogWrite:
+ *	Write an 8-bit data value to the MCP4802 Analog to digital
+ *	convertor on the Gertboard.
+ *********************************************************************************
+ */
+
+void gertboardAnalogWrite (int chan, int value)
+{
+  uint8_t spiData [2] ;
+  uint8_t chanBits, dataBits ;
+
+  if (chan == 0)
+    chanBits = 0x30 ;
+  else
+    chanBits = 0xB0 ;
+
+  chanBits |= ((value >> 4) & 0x0F) ;
+  dataBits  = ((value << 4) & 0xF0) ;
+
+  spiData [0] = chanBits ;
+  spiData [1] = dataBits ;
+
+  wiringPiSPIDataRW (SPI_D2A, spiData, 2) ;
+}
+
+
+/*
+ * gertboardAnalogRead:
+ *	Return the analog value of the given channel (0/1).
+ *	The A/D is a 10-bit device
+ *********************************************************************************
+ */
+
+int gertboardAnalogRead (int chan)
+{
+  uint8_t spiData [2] ;
+
+  uint8_t chanBits ;
+
+  if (chan == 0)
+    chanBits = 0b11010000 ;
+  else
+    chanBits = 0b11110000 ;
+
+  spiData [0] = chanBits ;
+  spiData [1] = 0 ;
+
+  wiringPiSPIDataRW (SPI_A2D, spiData, 2) ;
+
+  return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ;
+}
+
+
+/*
+ * gertboardSPISetup:
+ *	Initialise the SPI bus, etc.
+ *********************************************************************************
+ */
+
+int gertboardSPISetup (void)
+{
+  if (wiringPiSPISetup (SPI_A2D, SPI_ADC_SPEED) < 0)
+    return -1 ;
+
+  if (wiringPiSPISetup (SPI_D2A, SPI_DAC_SPEED) < 0)
+    return -1 ;
+
+  return 0 ;
+}

+ 39 - 0
wiringPi/gertboard.h

@@ -0,0 +1,39 @@
+/*
+ * gertboard.h:
+ *	Access routines for the SPI devices on the Gertboard
+ *	Copyright (c) 2012 Gordon Henderson
+ *
+ *	The Gertboard has an MCP4802 dual-channel D to A convertor
+ *	connected to the SPI bus, selected via chip-select B.
+ *
+ ***********************************************************************
+ * 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/>.
+ ***********************************************************************
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void gertboardAnalogWrite (int chan, int value) ;
+extern int  gertboardAnalogRead  (int chan) ;
+extern int  gertboardSPISetup    (void) ;
+
+#ifdef __cplusplus
+}
+#endif

+ 8 - 0
wiringPi/lcd.h

@@ -33,5 +33,13 @@ extern void lcdPutchar  (int fd, uint8_t data) ;
 extern void lcdPuts     (int fd, char *string) ;
 extern void lcdPrintf   (int fd, char *message, ...) ;
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern int  lcdInit (int rows, int cols, int bits, int rs, int strb,
 	int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) ;
+
+#ifdef __cplusplus
+}
+#endif

+ 113 - 0
wiringPi/piNes.c

@@ -0,0 +1,113 @@
+/*
+ * piNes.c:
+ *	Driver for the NES Joystick controller on the Raspberry Pi
+ *	Copyright (c) 2012 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 <wiringPi.h>
+
+#include "piNes.h"
+
+#define	MAX_NES_JOYSTICKS	8
+
+#define	NES_RIGHT	0x01
+#define	NES_LEFT	0x02
+#define	NES_DOWN	0x04
+#define	NES_UP		0x08
+#define	NES_START	0x10
+#define	NES_SELECT	0x20
+#define	NES_B		0x40
+#define	NES_A		0x80
+
+
+#define	PULSE_TIME	25
+
+// Data to store the pins for each controller
+
+struct nesPinsStruct
+{
+  unsigned int cPin, dPin, lPin ;
+} ;
+
+static struct nesPinsStruct nesPins [MAX_NES_JOYSTICKS] ;
+
+static int joysticks = 0 ;
+
+
+/*
+ * setupNesJoystick:
+ *	Create a new NES joystick interface, program the pins, etc.
+ *********************************************************************************
+ */
+
+int setupNesJoystick (int dPin, int cPin, int lPin)
+{
+  if (joysticks == MAX_NES_JOYSTICKS)
+    return -1 ;
+
+  nesPins [joysticks].dPin = dPin ;
+  nesPins [joysticks].cPin = cPin ;
+  nesPins [joysticks].lPin = lPin ;
+
+  digitalWrite (lPin, LOW) ;
+  digitalWrite (cPin, LOW) ;
+
+  pinMode (lPin, OUTPUT) ;
+  pinMode (cPin, OUTPUT) ;
+  pinMode (dPin, INPUT) ;
+
+  return joysticks++ ;
+}
+
+
+/*
+ * readNesJoystick:
+ *	Do a single scan of the NES Joystick.
+ *********************************************************************************
+ */
+
+unsigned int readNesJoystick (int joystick)
+{
+  unsigned int value = 0 ;
+  int  i ;
+
+  struct nesPinsStruct *pins = &nesPins [joystick] ;
+ 
+// Toggle Latch - which presents the first bit
+
+  digitalWrite (pins->lPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
+  digitalWrite (pins->lPin, LOW)  ; delayMicroseconds (PULSE_TIME) ;
+
+// Read first bit
+
+  value = digitalRead (pins->dPin) ;
+
+// Now get the next 7 bits with the clock
+
+  for (i = 0 ; i < 7 ; ++i)
+  {
+    digitalWrite (pins->cPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
+    digitalWrite (pins->cPin, LOW)  ; delayMicroseconds (PULSE_TIME) ;
+    value = (value << 1) | digitalRead (pins->dPin) ;
+  }
+
+  return value ^ 0xFF ;
+}

+ 45 - 0
wiringPi/piNes.h

@@ -0,0 +1,45 @@
+/*
+ * piNes.h:
+ *	Driver for the NES Joystick controller on the Raspberry Pi
+ *	Copyright (c) 2012 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	MAX_NES_JOYSTICKS	8
+
+#define	NES_RIGHT	0x01
+#define	NES_LEFT	0x02
+#define	NES_DOWN	0x04
+#define	NES_UP		0x08
+#define	NES_START	0x10
+#define	NES_SELECT	0x20
+#define	NES_B		0x40
+#define	NES_A		0x80
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int          setupNesJoystick (int dPin, int cPin, int lPin) ;
+extern unsigned int  readNesJoystick (int joystick) ;
+
+#ifdef __cplusplus
+}
+#endif

+ 130 - 0
wiringPi/softPwm.c

@@ -0,0 +1,130 @@
+/*
+ * softPwm.c:
+ *	Provide 2 channels of software driven PWM.
+ *	Copyright (c) 2012 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 <pthread.h>
+
+#include "wiringPi.h"
+#include "softPwm.h"
+
+#define	MAX_PINS	64
+
+// The PWM Frequency is derived from the "pulse time" below. Essentially,
+//	the frequency is a function of the range and this pulse time.
+//	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
+//	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
+//	accurate at all, and have an overhead.
+//
+//	Another way to increase the frequency is to reduce the range - however
+//	that reduces the overall output accuracy...
+
+#define	PULSE_TIME	100
+
+static int marks [MAX_PINS] ;
+static int range [MAX_PINS] ;
+
+int newPin = -1 ;
+
+
+/*
+ * softPwmThread:
+ *	Thread to do the actual PWM output
+ *********************************************************************************
+ */
+
+static PI_THREAD (softPwmThread)
+{
+  int pin, mark, space ;
+
+  pin    = newPin ;
+  newPin = -1 ;
+
+  piHiPri (50) ;
+
+  for (;;)
+  {
+    mark  = marks [pin] ;
+    space = range [pin] - mark ;
+
+    if (mark != 0)
+      digitalWrite (pin, HIGH) ;
+    delayMicroseconds (mark * 100) ;
+
+    if (space != 0)
+      digitalWrite (pin, LOW) ;
+    delayMicroseconds (space * 100) ;
+  }
+
+  return NULL ;
+}
+
+
+/*
+ * softPwmWrite:
+ *	Write a PWM value to the given pin
+ *********************************************************************************
+ */
+
+void softPwmWrite (int pin, int value)
+{
+  pin &= 63 ;
+
+  /**/ if (value < 0)
+    value = 0 ;
+  else if (value > range [pin])
+    value = range [pin] ;
+
+  marks [pin] = value ;
+}
+
+
+/*
+ * softPwmCreate:
+ *	Create a new PWM thread.
+ *********************************************************************************
+ */
+
+int softPwmCreate (int pin, int initialValue, int pwmRange)
+{
+  int res ;
+
+  pinMode      (pin, OUTPUT) ;
+  digitalWrite (pin, LOW) ;
+
+  marks [pin] = initialValue ;
+  range [pin] = pwmRange ;
+
+  newPin = pin ;
+  res = piThreadCreate (softPwmThread) ;
+
+  while (newPin != -1)
+    delay (1) ;
+
+  return res ;
+}

+ 34 - 0
wiringPi/softPwm.h

@@ -0,0 +1,34 @@
+/*
+ * softPwm.h:
+ *	Provide 2 channels of software driven PWM.
+ *	Copyright (c) 2012 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/>.
+ ***********************************************************************
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int  softPwmCreate (int pin, int value, int range) ;
+extern void softPwmWrite  (int pin, int value) ;
+
+#ifdef __cplusplus
+}
+#endif

+ 296 - 135
wiringPi/wiringPi.c

@@ -71,12 +71,16 @@
 
 // Function stubs
 
-void (*pinMode)          (int pin, int mode) ;
-void (*pullUpDnControl)  (int pin, int pud) ;
-void (*digitalWrite)     (int pin, int value) ;
-void (*pwmWrite)         (int pin, int value) ;
-int  (*digitalRead)      (int pin) ;
-int  (*waitForInterrupt) (int pin, int mS) ;
+void (*pinMode)           (int pin, int mode) ;
+void (*pullUpDnControl)   (int pin, int pud) ;
+void (*digitalWrite)      (int pin, int value) ;
+void (*pwmWrite)          (int pin, int value) ;
+void (*setPadDrive)       (int group, int value) ;
+int  (*digitalRead)       (int pin) ;
+int  (*waitForInterrupt)  (int pin, int mS) ;
+void (*delayMicroseconds) (unsigned int howLong) ;
+void (*pwmSetMode)        (int mode) ;
+void (*pwmSetRange)       (unsigned int range) ;
 
 
 #ifndef	TRUE
@@ -84,6 +88,11 @@ int  (*waitForInterrupt) (int pin, int mS) ;
 #define	FALSE	(1==2)
 #endif
 
+// BCM Magic
+
+#define	BCM_PASSWORD		0x5A000000
+
+
 // Port function select bits
 
 #define	FSEL_INPT		0b000
@@ -100,10 +109,11 @@ int  (*waitForInterrupt) (int pin, int mS) ;
 //	Take from Gert/Doms code. Some of this is not in the manual
 //	that I can find )-:
 
-#define BCM2708_PERI_BASE	0x20000000
+#define BCM2708_PERI_BASE	                   0x20000000
 #define GPIO_PADS		(BCM2708_PERI_BASE + 0x100000)
 #define CLOCK_BASE		(BCM2708_PERI_BASE + 0x101000)
 #define GPIO_BASE		(BCM2708_PERI_BASE + 0x200000)
+#define GPIO_TIMER		(BCM2708_PERI_BASE + 0x00B000)
 #define GPIO_PWM		(BCM2708_PERI_BASE + 0x20C000)
 
 #define	PAGE_SIZE		(4*1024)
@@ -137,12 +147,27 @@ int  (*waitForInterrupt) (int pin, int mS) ;
 #define	PWM0_SERIAL     0x0002  // Run in serial mode
 #define	PWM0_ENABLE     0x0001  // Channel Enable
 
+// Timer
+
+#define	TIMER_LOAD	(0x400 >> 2)
+#define	TIMER_VALUE	(0x404 >> 2)
+#define	TIMER_CONTROL	(0x408 >> 2)
+#define	TIMER_IRQ_CLR	(0x40C >> 2)
+#define	TIMER_IRQ_RAW	(0x410 >> 2)
+#define	TIMER_IRQ_MASK	(0x414 >> 2)
+#define	TIMER_RELOAD	(0x418 >> 2)
+#define	TIMER_PRE_DIV	(0x41C >> 2)
+#define	TIMER_COUNTER	(0x420 >> 2)
 
 // Locals to hold pointers to the hardware
 
 static volatile uint32_t *gpio ;
 static volatile uint32_t *pwm ;
 static volatile uint32_t *clk ;
+static volatile uint32_t *pads ;
+static volatile uint32_t *timer ;
+
+static volatile uint32_t *timerIrqRaw ;
 
 // The BCM2835 has 54 GPIO pins.
 //	BCM2835 data sheet, Page 90 onwards.
@@ -273,6 +298,8 @@ static uint8_t gpioToFEN [] =
 // gpioToPUDCLK
 //	(Word) offset to the Pull Up Down Clock regsiter
 
+#define	GPPUD	37
+
 static uint8_t gpioToPUDCLK [] =
 {
   38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,
@@ -352,30 +379,42 @@ void pinModeGpio (int pin, int mode)
     if (!pwmRunning)
     {
 
-//	Gert/Doms Values
-      *(clk + PWMCLK_DIV)  = 0x5A000000 | (32<<12) ;	// set pwm div to 32 (19.2/3 = 600KHz)
-      *(clk + PWMCLK_CNTL) = 0x5A000011 ;		// Source=osc and enable
-      digitalWrite (pin, LOW) ;
-      *(pwm + PWM_CONTROL) = 0 ;			// Disable PWM
+      *(pwm + PWM_CONTROL) = 0 ;			// Stop PWM
       delayMicroseconds (10) ;
-      *(pwm + PWM0_RANGE) = 0x400 ;
-      delayMicroseconds (10) ;
-      *(pwm + PWM1_RANGE) = 0x400 ;
+	
+//	Gert/Doms Values
+      *(clk + PWMCLK_DIV)  = BCM_PASSWORD | (32<<12) ;	// set pwm div to 32 (19.2/32 = 600KHz)
+      *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ;	// Source=osc and enable
+
       delayMicroseconds (10) ;
 
+      *(pwm + PWM0_RANGE) = 0x400 ; delayMicroseconds (10) ;
+      *(pwm + PWM1_RANGE) = 0x400 ; delayMicroseconds (10) ;
+
 // Enable PWMs
 
       *(pwm + PWM0_DATA) = 512 ;
       *(pwm + PWM1_DATA) = 512 ;
 
+// Balanced mode (default)
+
       *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
+
+      pwmRunning = TRUE ;
     }
 
   }
 
 // When we change mode of any pin, we remove the pull up/downs
+//	Or we used to... Hm. Commented out now because for some wieird reason,
+//	it seems to block subsequent attempts to set the pull up/downs and I've
+//	not quite gotten to the bottom of why this happens
+//	The down-side is that the pull up/downs are rememberd in the SoC between
+//	power cycles, so it's going to be a good idea to explicitly set them in
+//	any new code.
+//
+//  pullUpDnControl (pin, PUD_OFF) ;
 
-  pullUpDnControl (pin, PUD_OFF) ;
 }
 
 void pinModeWPi (int pin, int mode)
@@ -389,6 +428,38 @@ void pinModeSys (int pin, int mode)
 }
 
 
+/*
+ * pwmControl:
+ *	Allow the user to control some of the PWM functions
+ *********************************************************************************
+ */
+
+void pwmSetModeWPi (int mode)
+{
+  if (mode == PWM_MODE_MS)
+    *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ;
+  else
+    *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
+}
+
+void pwmSetModeSys (int mode)
+{
+  return ;
+}
+
+
+void pwmSetRangeWPi (unsigned int range)
+{
+  *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ;
+  *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ;
+}
+
+void pwmSetRangeSys (unsigned int range)
+{
+  return ;
+}
+
+
 #ifdef notYetReady
 /*
  * pinED01:
@@ -414,12 +485,12 @@ void pinEnableED01Pi (int pin)
 
 void digitalWriteWPi (int pin, int value)
 {
-  int gpioPin = pinToGpio [pin & 63] ;
+  pin = pinToGpio [pin & 63] ;
 
   if (value == LOW)
-    *(gpio + gpioToGPCLR [gpioPin]) = 1 << gpioPin ;
+    *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ;
   else
-    *(gpio + gpioToGPSET [gpioPin]) = 1 << gpioPin ;
+    *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ;
 }
 
 void digitalWriteGpio (int pin, int value)
@@ -427,9 +498,9 @@ void digitalWriteGpio (int pin, int value)
   pin &= 63 ;
 
   if (value == LOW)
-    *(gpio + gpioToGPCLR [pin]) = 1 << pin ;
+    *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ;
   else
-    *(gpio + gpioToGPSET [pin]) = 1 << pin ;
+    *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ;
 }
 
 void digitalWriteSys (int pin, int value)
@@ -452,28 +523,55 @@ void digitalWriteSys (int pin, int value)
  *********************************************************************************
  */
 
-void pwmWriteWPi (int pin, int value)
+void pwmWriteGpio (int pin, int value)
 {
-  int port, gpioPin ;
+  int port ;
 
-  gpioPin = pinToGpio [pin & 63] ;
-  port    = gpioToPwmPort [gpioPin] ;
+  pin  = pin & 63 ;
+  port = gpioToPwmPort [pin] ;
 
-  *(pwm + port) = value & 0x3FF ;
+  *(pwm + port) = value ;
 }
 
-void pwmWriteGpio (int pin, int value)
+void pwmWriteWPi (int pin, int value)
+{
+  pwmWriteGpio (pinToGpio [pin & 63], value) ;
+}
+
+void pwmWriteSys (int pin, int value)
+{
+  return ;
+}
+
+
+/*
+ * setPadDrive:
+ *	Set the PAD driver value
+ *********************************************************************************
+ */
+
+void setPadDriveWPi (int group, int value)
 {
-  int port, gpioPin ;
+  uint32_t wrVal ;
 
-  gpioPin = pin & 63 ;
-  port    = gpioToPwmPort [gpioPin] ;
+  if ((group < 0) || (group > 2))
+    return ;
 
-  *(pwm + port) = value & 0x3FF ;
+  wrVal = BCM_PASSWORD | 0x18 | (value & 7) ;
+  *(pads + group + 11) = wrVal ;
+
+#ifdef	DEBUG_PADS
+  printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ;
+  printf ("Read : %08X\n", *(pads + group + 11)) ;
+#endif
 }
 
+void setPadDriveGpio (int group, int value)
+{
+  setPadDriveWPi (group, value) ;
+}
 
-void pwmWriteSys (int pin, int value)
+void setPadDriveSys (int group, int value)
 {
   return ;
 }
@@ -487,13 +585,9 @@ void pwmWriteSys (int pin, int value)
 
 int digitalReadWPi (int pin)
 {
-  int gpioPin ;
-
-  pin &= 63 ;
-
-  gpioPin = pinToGpio [pin] ;
+  pin = pinToGpio [pin & 63] ;
 
-  if ((*(gpio + gpioToGPLEV [gpioPin]) & (1 << gpioPin)) != 0)
+  if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0)
     return HIGH ;
   else
     return LOW ;
@@ -503,7 +597,7 @@ int digitalReadGpio (int pin)
 {
   pin &= 63 ;
 
-  if ((*(gpio + gpioToGPLEV [pin]) & (1 << pin)) != 0)
+  if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0)
     return HIGH ;
   else
     return LOW ;
@@ -533,30 +627,21 @@ int digitalReadSys (int pin)
  *********************************************************************************
  */
 
-void pullUpDnControlWPi (int pin, int pud)
+void pullUpDnControlGpio (int pin, int pud)
 {
-  pin = pinToGpio [pin & 63] ;
+  pin &= 63 ;
+  pud &=  3 ;
 
-  *(gpio + 37) = pud ;
-  delayMicroseconds (10) ;
-  *(gpio + gpioToPUDCLK [pin]) = 1 << pin ;
-  delayMicroseconds (10) ;
+  *(gpio + GPPUD)              = pud ;			delayMicroseconds (5) ;
+  *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ;	delayMicroseconds (5) ;
   
-  *(gpio + 37) = 0 ;
-  *(gpio + gpioToPUDCLK [pin]) = 0 ;
+  *(gpio + GPPUD)              = 0 ;			delayMicroseconds (5) ;
+  *(gpio + gpioToPUDCLK [pin]) = 0 ;			delayMicroseconds (5) ;
 }
 
-void pullUpDnControlGpio (int pin, int pud)
+void pullUpDnControlWPi (int pin, int pud)
 {
-  pin &= 63 ;
-
-  *(gpio + 37) = pud ;
-  delayMicroseconds (10) ;
-  *(gpio + gpioToPUDCLK [pin]) = 1 << pin ;
-  delayMicroseconds (10) ;
-  
-  *(gpio + 37) = 0 ;
-  *(gpio + gpioToPUDCLK [pin]) = 0 ;
+  pullUpDnControlGpio (pinToGpio [pin & 63], pud) ;
 }
 
 void pullUpDnControlSys (int pin, int pud)
@@ -615,6 +700,94 @@ int waitForInterruptGpio (int pin, int mS)
 
 
 
+
+/*
+ * delay:
+ *	Wait for some number of milli seconds
+ *********************************************************************************
+ */
+
+void delay (unsigned int howLong)
+{
+  struct timespec sleeper, dummy ;
+
+  sleeper.tv_sec  = (time_t)(howLong / 1000) ;
+  sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
+
+  nanosleep (&sleeper, &dummy) ;
+}
+
+
+/*
+ * delayMicroseconds:
+ *	This is somewhat intersting. It seems that on the Pi, a single call
+ *	to nanosleep takes some 80 to 130 microseconds anyway, so while
+ *	obeying the standards (may take longer), it's not always what we
+ *	want!
+ *
+ *	So what I'll do now is if the delay is less than 100uS we'll do it
+ *	in a hard loop, watching a built-in counter on the ARM chip. This is
+ *	somewhat sub-optimal in that it uses 100% CPU, something not an issue
+ *	in a microcontroller, but under a multi-tasking, multi-user OS, it's
+ *	wastefull, however we've no real choice )-:
+ *********************************************************************************
+ */
+
+void delayMicrosecondsSys (unsigned int howLong)
+{
+  struct timespec sleeper, dummy ;
+
+  sleeper.tv_sec  = 0 ;
+  sleeper.tv_nsec = (long)(howLong * 1000) ;
+
+  nanosleep (&sleeper, &dummy) ;
+}
+
+void delayMicrosecondsHard (unsigned int howLong)
+{
+  *(timer + TIMER_LOAD)    = howLong ;
+  *(timer + TIMER_IRQ_CLR) = 0 ;
+
+  while (*timerIrqRaw == 0)
+    ;
+}
+
+void delayMicrosecondsWPi (unsigned int howLong)
+{
+  struct timespec sleeper, dummy ;
+
+  /**/ if (howLong ==   0)
+    return ;
+  else if (howLong  < 100)
+    delayMicrosecondsHard (howLong) ;
+  else
+  {
+    sleeper.tv_sec  = 0 ;
+    sleeper.tv_nsec = (long)(howLong * 1000) ;
+    nanosleep (&sleeper, &dummy) ;
+  }
+}
+
+
+/*
+ * millis:
+ *	Return a number of milliseconds as an unsigned int.
+ *********************************************************************************
+ */
+
+unsigned int millis (void)
+{
+  struct timeval tv ;
+  unsigned long long t1 ;
+
+  gettimeofday (&tv, NULL) ;
+
+  t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
+
+  return (uint32_t)(t1 - epoch) ;
+}
+
+
 /*
  * wiringPiSetup:
  *	Must be called once at the start of your program execution.
@@ -627,20 +800,19 @@ int waitForInterruptGpio (int pin, int mS)
 int wiringPiSetup (void)
 {
   int      fd ;
-  uint8_t *gpioMem, *pwmMem, *clkMem ;
+  uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ;
   struct timeval tv ;
 
-#ifdef	DEBUG_PADS
-  uint8_t *gpioMem, *padsMem, *pwmMem, *clkMem ;
-  uint32_t *pads ;
-#endif
-
-           pinMode =          pinModeWPi ;
-   pullUpDnControl =  pullUpDnControlWPi ;
-      digitalWrite =     digitalWriteWPi ;
-          pwmWrite =         pwmWriteWPi ;
-       digitalRead =      digitalReadWPi ;
-  waitForInterrupt = waitForInterruptWPi ;
+            pinMode =           pinModeWPi ;
+    pullUpDnControl =   pullUpDnControlWPi ;
+       digitalWrite =      digitalWriteWPi ;
+           pwmWrite =          pwmWriteWPi ;
+        setPadDrive =       setPadDriveWPi ;
+        digitalRead =       digitalReadWPi ;
+   waitForInterrupt =  waitForInterruptWPi ;
+  delayMicroseconds = delayMicrosecondsWPi ;
+         pwmSetMode =        pwmSetModeWPi ;
+        pwmSetRange =       pwmSetRangeWPi ;
   
 // Open the master /dev/memory device
 
@@ -711,7 +883,8 @@ int wiringPiSetup (void)
     return -1 ;
   }
  
-#ifdef	DEBUG_PADS
+// The drive pads
+
   if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
   {
     fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ;
@@ -728,14 +901,41 @@ int wiringPiSetup (void)
     fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ;
     return -1 ;
   }
- 
-  printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
 
-  printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
-//  *(pads + 11) = 0x1F ;
-  printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
+#ifdef	DEBUG_PADS
+  printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
+  printf (" -> %08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
 #endif
 
+// The system timer
+
+  if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
+  {
+    fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ;
+    return -1 ;
+  }
+
+  if (((uint32_t)timerMem % PAGE_SIZE) != 0)
+    timerMem += PAGE_SIZE - ((uint32_t)timerMem % PAGE_SIZE) ;
+
+  timer = (uint32_t *)mmap(timerMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_TIMER) ;
+
+  if ((int32_t)timer < 0)
+  {
+    fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ;
+    return -1 ;
+  }
+
+// Set the timer to free-running, 1MHz.
+//	0xF9 is 249, the timer divide is base clock / (divide+1)
+//	so base clock is 250MHz / 250 = 1MHz.
+
+  *(timer + TIMER_CONTROL) = 0x0000280 ;
+  *(timer + TIMER_PRE_DIV) = 0x00000F9 ;
+  timerIrqRaw = timer + TIMER_IRQ_RAW ;
+
+// Initialise our epoch for millis()
+
   gettimeofday (&tv, NULL) ;
   epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
 
@@ -759,12 +959,16 @@ int wiringPiSetupGpio (void)
   if (x != 0)
     return x ;
 
-           pinMode =          pinModeGpio ;
-   pullUpDnControl =  pullUpDnControlGpio ;
-      digitalWrite =     digitalWriteGpio ;
-          pwmWrite =         pwmWriteGpio ;
-       digitalRead =      digitalReadGpio ;
-  waitForInterrupt = waitForInterruptGpio ;
+            pinMode =           pinModeGpio ;
+    pullUpDnControl =   pullUpDnControlGpio ;
+       digitalWrite =      digitalWriteGpio ;
+           pwmWrite =          pwmWriteGpio ;
+        setPadDrive =       setPadDriveGpio ;
+        digitalRead =       digitalReadGpio ;
+   waitForInterrupt =  waitForInterruptGpio ;
+  delayMicroseconds = delayMicrosecondsWPi ;	// Same
+         pwmSetMode =        pwmSetModeWPi ;
+        pwmSetRange =       pwmSetRangeWPi ;
 
   return 0 ;
 }
@@ -785,12 +989,17 @@ int wiringPiSetupSys (void)
   struct timeval tv ;
   char fName [128] ;
 
-           pinMode =          pinModeSys ;
-   pullUpDnControl =  pullUpDnControlSys ;
-      digitalWrite =     digitalWriteSys ;
-          pwmWrite =         pwmWriteSys ;
-       digitalRead =      digitalReadSys ;
-  waitForInterrupt = waitForInterruptSys ;
+            pinMode =           pinModeSys ;
+    pullUpDnControl =   pullUpDnControlSys ;
+       digitalWrite =      digitalWriteSys ;
+           pwmWrite =          pwmWriteSys ;
+        setPadDrive =       setPadDriveSys ;
+        digitalRead =       digitalReadSys ;
+   waitForInterrupt =  waitForInterruptSys ;
+  delayMicroseconds = delayMicrosecondsSys ;
+         pwmSetMode =        pwmSetModeSys ;
+        pwmSetRange =       pwmSetRangeSys ;
+
 
 // Open and scan the directory, looking for exported GPIOs, and pre-open
 //	the 'value' interface to speed things up for later
@@ -808,51 +1017,3 @@ int wiringPiSetupSys (void)
 
   return 0 ;
 }
-
-
-
-
-
-/*
- * delay: delayMicroseconds
- *	Wait for some number of milli/micro seconds
- *********************************************************************************
- */
-
-void delay (unsigned int howLong)
-{
-  struct timespec sleeper, dummy ;
-
-  sleeper.tv_sec  = (time_t)(howLong / 1000) ;
-  sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
-
-  nanosleep (&sleeper, &dummy) ;
-}
-
-void delayMicroseconds (unsigned int howLong)
-{
-  struct timespec sleeper, dummy ;
-
-  sleeper.tv_sec  = 0 ;
-  sleeper.tv_nsec = (long)(howLong * 1000) ;
-
-  nanosleep (&sleeper, &dummy) ;
-}
-
-/*
- * millis:
- *	Return a number of milliseconds as an unsigned int.
- *********************************************************************************
- */
-
-unsigned int millis (void)
-{
-  struct timeval tv ;
-  unsigned long long t1 ;
-
-  gettimeofday (&tv, NULL) ;
-
-  t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
-
-  return (uint32_t)(t1 - epoch) ;
-}

+ 15 - 6
wiringPi/wiringPi.h

@@ -41,6 +41,12 @@
 #define	PUD_DOWN	 1
 #define	PUD_UP		 2
 
+// PWM
+
+#define	PWM_MODE_MS	0
+#define	PWM_MODE_BAL	1
+
+
 // Function prototypes
 //	c++ wrappers thanks to a commend by Nick Lott
 //	(and others on the Raspberry Pi forums)
@@ -58,11 +64,15 @@ extern int  wiringPiSetupPiFace (void) ;
 
 extern int  wiringPiSetupPiFaceForGpioProg (void) ;	// Don't use this - for gpio program only
 
-extern void (*pinMode)          (int pin, int mode) ;
-extern void (*pullUpDnControl)  (int pin, int pud) ;
-extern void (*digitalWrite)     (int pin, int value) ;
-extern void (*pwmWrite)         (int pin, int value) ;
-extern int  (*digitalRead)      (int pin) ;
+extern void (*pinMode)           (int pin, int mode) ;
+extern void (*pullUpDnControl)   (int pin, int pud) ;
+extern void (*digitalWrite)      (int pin, int value) ;
+extern void (*pwmWrite)          (int pin, int value) ;
+extern void (*setPadDrive)       (int group, int value) ;
+extern int  (*digitalRead)       (int pin) ;
+extern void (*delayMicroseconds) (unsigned int howLong) ;
+extern void (*pwmSetMode)        (int mode) ;
+extern void (*pwmSetRange)       (unsigned int range) ;
 
 // Interrupts
 
@@ -84,7 +94,6 @@ extern int piHiPri (int pri) ;
 // Extras from arduino land
 
 extern void         delay             (unsigned int howLong) ;
-extern void         delayMicroseconds (unsigned int howLong) ;
 extern unsigned int millis            (void) ;
 
 #ifdef __cplusplus

+ 117 - 0
wiringPi/wiringPiSPI.c

@@ -0,0 +1,117 @@
+/*
+ * wiringPiSPI.c:
+ *	Simplified SPI access routines
+ *	Copyright (c) 2012 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 <stdint.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "wiringPiSPI.h"
+
+
+// The SPI bus parameters
+//	Variables as they need to be passed as pointers later on
+
+static char       *spiDev0 = "/dev/spidev0.0" ;
+static char       *spiDev1 = "/dev/spidev0.1" ;
+static uint8_t     spiMode   = 0 ;
+static uint8_t     spiBPW    = 8 ;
+static uint16_t    spiDelay  = 0;
+
+static uint32_t    spiSpeeds [2] ;
+static int         spiFds [2] ;
+
+
+/*
+ * wiringPiSPIGetFd:
+ *	Return the file-descriptor for the given channel
+ *********************************************************************************
+ */
+
+int wiringPiSPIGetFd (int channel)
+{
+  return spiFds [channel &1] ;
+}
+
+
+/*
+ * wiringPiSPIDataRW:
+ *	Write and Read a block of data over the SPI bus.
+ *	Note the data ia being read into the transmit buffer, so will
+ *	overwrite it!
+ *	This is also a full-duplex operation.
+ *********************************************************************************
+ */
+
+int wiringPiSPIDataRW (int channel, unsigned char *data, int len)
+{
+  struct spi_ioc_transfer spi ;
+
+  channel &= 1 ;
+
+  spi.tx_buf        = (unsigned long)data ;
+  spi.rx_buf        = (unsigned long)data ;
+  spi.len           = len ;
+  spi.delay_usecs   = spiDelay ;
+  spi.speed_hz      = spiSpeeds [channel] ;
+  spi.bits_per_word = spiBPW ;
+
+  return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ;
+}
+
+
+/*
+ * wiringPiSPISetup:
+ *	Open the SPI device, and set it up, etc.
+ *********************************************************************************
+ */
+
+int wiringPiSPISetup (int channel, int speed)
+{
+  int fd ;
+
+  channel &= 1 ;
+
+  if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0)
+    return -1 ;
+
+  spiSpeeds [channel] = speed ;
+  spiFds    [channel] = fd ;
+
+// Set SPI parameters.
+//	Why are we reading it afterwriting it? I've no idea, but for now I'm blindly
+//	copying example code I've seen online...
+
+  if (ioctl (fd, SPI_IOC_WR_MODE, &spiMode)         < 0) return -1 ;
+  if (ioctl (fd, SPI_IOC_RD_MODE, &spiMode)         < 0) return -1 ;
+
+  if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) return -1 ;
+  if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0) return -1 ;
+
+  if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed)   < 0) return -1 ;
+  if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed)   < 0) return -1 ;
+
+  return fd ;
+}

+ 35 - 0
wiringPi/wiringPiSPI.h

@@ -0,0 +1,35 @@
+/*
+ * wiringPiSPI.h:
+ *	Simplified SPI access routines
+ *	Copyright (c) 2012 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/>.
+ ***********************************************************************
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int wiringPiSPIGetFd  (int channel) ;
+int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ;
+int wiringPiSPISetup  (int channel, int speed) ;
+
+#ifdef __cplusplus
+}
+#endif

+ 25 - 19
wiringPi/wiringSerial.c

@@ -20,8 +20,6 @@
  ***********************************************************************
  */
 
-#undef	DEBUG
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -49,10 +47,6 @@ int serialOpen (char *device, int baud)
   speed_t myBaud ;
   int     status, fd ;
 
-#ifdef	DEBUG
-  printf ("openSerialPort: <%s> baud: $d\n", device, baud) ;
-#endif
-
   switch (baud)
   {
     case     50:	myBaud =     B50 ; break ;
@@ -86,22 +80,22 @@ int serialOpen (char *device, int baud)
 
   tcgetattr (fd, &options) ;
 
-  cfmakeraw   (&options) ;
-  cfsetispeed (&options, myBaud) ;
-  cfsetospeed (&options, myBaud) ;
+    cfmakeraw   (&options) ;
+    cfsetispeed (&options, myBaud) ;
+    cfsetospeed (&options, myBaud) ;
 
-  options.c_cflag |= (CLOCAL | CREAD) ;
-  options.c_cflag &= ~PARENB ;
-  options.c_cflag &= ~CSTOPB ;
-  options.c_cflag &= ~CSIZE ;
-  options.c_cflag |= CS8 ;
-  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
-  options.c_oflag &= ~OPOST ;
+    options.c_cflag |= (CLOCAL | CREAD) ;
+    options.c_cflag &= ~PARENB ;
+    options.c_cflag &= ~CSTOPB ;
+    options.c_cflag &= ~CSIZE ;
+    options.c_cflag |= CS8 ;
+    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
+    options.c_oflag &= ~OPOST ;
 
-  options.c_cc [VMIN]  =   0 ;
-  options.c_cc [VTIME] = 100 ;	// Ten seconds (100 deciseconds)
+    options.c_cc [VMIN]  =   0 ;
+    options.c_cc [VTIME] = 100 ;	// Ten seconds (100 deciseconds)
 
-  tcsetattr (fd, TCSANOW, &options) ;
+  tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ;
 
   ioctl (fd, TIOCMGET, &status);
 
@@ -116,6 +110,18 @@ int serialOpen (char *device, int baud)
 }
 
 
+/*
+ * serialFlush:
+ *	Flush the serial buffers (both tx & rx)
+ *********************************************************************************
+ */
+
+void serialFlush (int fd)
+{
+  tcflush (fd, TCIOFLUSH) ;
+}
+
+
 /*
  * serialClose:
  *	Release the serial port

+ 1 - 0
wiringPi/wiringSerial.h

@@ -26,6 +26,7 @@ extern "C" {
 
 extern int   serialOpen      (char *device, int baud) ;
 extern void  serialClose     (int fd) ;
+extern void  serialFlush     (int fd) ;
 extern void  serialPutchar   (int fd, unsigned char c) ;
 extern void  serialPuts      (int fd, char *s) ;
 extern void  serialPrintf    (int fd, char *message, ...) ;