V23
authorjoan <joan@abyz.me.uk>
Tue, 25 Nov 2014 14:27:33 +0000 (14:27 +0000)
committerjoan <joan@abyz.me.uk>
Tue, 25 Nov 2014 14:27:33 +0000 (14:27 +0000)
20 files changed:
EXAMPLES/C/HALL_EFFECT_SENSOR/README [new file with mode: 0644]
EXAMPLES/C/HALL_EFFECT_SENSOR/hall.c [new file with mode: 0644]
EXAMPLES/C/I2C_SNIFFER/README [new file with mode: 0644]
EXAMPLES/C/I2C_SNIFFER/pig2i2c.c [new file with mode: 0644]
EXAMPLES/C/IR_RECEIVER/README [new file with mode: 0644]
EXAMPLES/C/IR_RECEIVER/ir_hasher.c [new file with mode: 0644]
EXAMPLES/C/IR_RECEIVER/ir_hasher.h [new file with mode: 0644]
EXAMPLES/C/IR_RECEIVER/test_ir_hasher.c [new file with mode: 0644]
EXAMPLES/C/PCF8591_YL-40/PCF8591.c [new file with mode: 0644]
EXAMPLES/C/PCF8591_YL-40/README [new file with mode: 0644]
EXAMPLES/C/POT_CAP_RECHARGE/README [new file with mode: 0644]
EXAMPLES/C/POT_CAP_RECHARGE/pot_cap_charge.c [new file with mode: 0644]
EXAMPLES/C/ROTARY_ENCODER/README [new file with mode: 0644]
EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.c [new file with mode: 0644]
EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.h [new file with mode: 0644]
EXAMPLES/C/ROTARY_ENCODER/test_rotary_encoder.c [new file with mode: 0644]
EXAMPLES/C/WIEGAND_CODE/README [new file with mode: 0644]
EXAMPLES/C/WIEGAND_CODE/test_wiegand.c [new file with mode: 0644]
EXAMPLES/C/WIEGAND_CODE/wiegand.c [new file with mode: 0644]
EXAMPLES/C/WIEGAND_CODE/wiegand.h [new file with mode: 0644]

diff --git a/EXAMPLES/C/HALL_EFFECT_SENSOR/README b/EXAMPLES/C/HALL_EFFECT_SENSOR/README
new file mode 100644 (file)
index 0000000..57f9143
--- /dev/null
@@ -0,0 +1,2 @@
+Program to show status changes for a Hall effect sensor.
+
diff --git a/EXAMPLES/C/HALL_EFFECT_SENSOR/hall.c b/EXAMPLES/C/HALL_EFFECT_SENSOR/hall.c
new file mode 100644 (file)
index 0000000..5c2f103
--- /dev/null
@@ -0,0 +1,51 @@
+#include <stdio.h>
+
+#include <pigpio.h>
+
+/*
+OH3144E or equivalent Hall effect sensor
+
+Pin 1 - 5V
+Pin 2 - Ground
+Pin 3 - gpio (here P1-8, gpio 14, TXD is used)
+
+The internal gpio pull-up is enabled so that the sensor
+normally reads high.  It reads low when a magnet is close.
+
+gcc -o hall hall.c -lpigpio -lrt -lpthread
+sudo ./hall
+*/
+
+#define HALL 14
+
+void alert(int gpio, int level, uint32_t tick)
+{
+   static uint32_t lastTick=0;
+
+   if (lastTick) printf("%d %.2f\n", level, (float)(tick-lastTick)/1000000.0);
+   else          printf("%d 0.00\n", level);
+
+   lastTick = tick;
+}
+
+int main(int argc, char *argv[])
+{
+   int secs=60;
+
+   if (argc>1) secs = atoi(argv[1]); /* program run seconds */
+
+   if ((secs<1) || (secs>3600)) secs = 3600;
+
+   if (gpioInitialise()<0) return 1;
+
+   gpioSetMode(HALL, PI_INPUT);
+
+   gpioSetPullUpDown(HALL, PI_PUD_UP);
+
+   gpioSetAlertFunc(HALL, alert);
+
+   sleep(secs);
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/C/I2C_SNIFFER/README b/EXAMPLES/C/I2C_SNIFFER/README
new file mode 100644 (file)
index 0000000..23b5594
--- /dev/null
@@ -0,0 +1,4 @@
+A program to passively sniff I2C transactions (100kHz bus maximum) and display the results.
+
+This C program uses pigpio notifications.
+
diff --git a/EXAMPLES/C/I2C_SNIFFER/pig2i2c.c b/EXAMPLES/C/I2C_SNIFFER/pig2i2c.c
new file mode 100644 (file)
index 0000000..bf9102c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include "pigpio.h"
+
+/*
+This software reads pigpio notification reports monitoring the I2C signals.
+
+Notifications are pipe based so this software must be run on the Pi
+being monitored.
+
+It should be able to handle a 100kHz bus.  You are unlikely to get any
+usable results if the bus is running at 400kHz.
+
+gcc -o pig2i2c pig2i2c.c
+
+Do something like
+
+sudo pigpiod -s 2
+
+# get a notification handle, assume handle 0 was returned
+
+pigs no
+
+# start notifications for SCL/SDA
+
+e.g. pigs nb 0 0x3   # Rev. 1 select gpios 0/1
+e.g. pigs nb 0 0xC   # Rev. 2 select gpios 2/3
+e.g. pigs nb 0 0xA00 # select gpios 9/11 (1<<9|1<<11)
+
+# run the program, specifying SCL/SDA and notification pipe
+
+./pig2i2c SCL SDA </dev/pigpioN # specify gpios for SCL/SDA and pipe N
+
+e.g. ./pig2i2c 1  0 </dev/pigpio0 # Rev.1 I2C gpios
+e.g. ./pig2i2c 3  2 </dev/pigpio0 # Rev.2 I2C gpios
+e.g. ./pig2i2c 9 11 </dev/pigpio0 # monitor external bus 
+*/
+
+#define RS (sizeof(gpioReport_t))
+
+#define SCL_FALLING 0
+#define SCL_RISING  1
+#define SCL_STEADY  2
+
+#define SDA_FALLING 0
+#define SDA_RISING  4
+#define SDA_STEADY  8
+
+static char * timeStamp()
+{
+   static char buf[32];
+
+   struct timeval now;
+   struct tm tmp;
+
+   gettimeofday(&now, NULL);
+
+   localtime_r(&now.tv_sec, &tmp);
+   strftime(buf, sizeof(buf), "%F %T", &tmp);
+
+   return buf;
+}
+
+void parse_I2C(int SCL, int SDA)
+{
+   static int in_data=0, byte=0, bit=0;
+   static int oldSCL=1, oldSDA=1;
+
+   int xSCL, xSDA;
+
+   if (SCL != oldSCL)
+   {
+      oldSCL = SCL;
+      if (SCL) xSCL = SCL_RISING;
+      else     xSCL = SCL_FALLING;
+   }
+   else        xSCL = SCL_STEADY;
+
+   if (SDA != oldSDA)
+   {
+      oldSDA = SDA;
+      if (SDA) xSDA = SDA_RISING;
+      else     xSDA = SDA_FALLING;
+   }
+   else        xSDA = SDA_STEADY;
+
+   switch (xSCL+xSDA)
+   {
+      case SCL_RISING + SDA_RISING:
+      case SCL_RISING + SDA_FALLING:
+      case SCL_RISING + SDA_STEADY:
+         if (in_data)
+         {
+            if (bit++ < 8)
+            {
+               byte <<= 1;
+               byte |= SDA;
+            }
+            else
+            {
+               printf("%02X", byte);
+               if (SDA) printf("-"); else printf("+");
+               bit = 0;
+               byte = 0;
+            }
+         }
+         break;
+
+      case SCL_FALLING + SDA_RISING:
+         break;
+
+      case SCL_FALLING + SDA_FALLING:
+         break;
+
+      case SCL_FALLING + SDA_STEADY:
+         break;
+
+      case SCL_STEADY + SDA_RISING:
+         if (SCL)
+         {
+            in_data = 0;
+            byte = 0;
+            bit = 0;
+
+            printf("]\n"); // stop
+            fflush(NULL);
+         }
+         break;
+
+      case SCL_STEADY + SDA_FALLING:
+         if (SCL)
+         {
+            in_data = 1;
+            byte = 0;
+            bit = 0;
+
+            printf("["); // start
+         }
+         break;
+
+      case SCL_STEADY + SDA_STEADY:
+         break;
+
+   }
+}
+
+int main(int argc, char * argv[])
+{
+   int gSCL, gSDA, SCL, SDA, xSCL;
+   int r;
+   uint32_t level, changed, bI2C, bSCL, bSDA;
+
+   gpioReport_t report;
+
+   if (argc > 2)
+   {
+      gSCL = atoi(argv[1]);
+      gSDA = atoi(argv[2]);
+
+      bSCL = 1<<gSCL;
+      bSDA = 1<<gSDA;
+
+      bI2C = bSCL | bSDA;
+   }
+   else
+   {
+      exit(-1);
+   }
+
+   /* default to SCL/SDA high */
+
+   SCL = 1;
+   SDA = 1;
+   level = bI2C;
+
+   while ((r=read(STDIN_FILENO, &report, RS)) == RS)
+   {
+      report.level &= bI2C;
+
+      if (report.level != level)
+      {
+         changed = report.level ^ level;
+
+         level = report.level;
+
+         if (level & bSCL) SCL = 1; else SCL = 0;
+         if (level & bSDA) SDA = 1; else SDA = 0;
+
+         parse_I2C(SCL, SDA);
+      }
+   }
+   return 0;
+}
+
diff --git a/EXAMPLES/C/IR_RECEIVER/README b/EXAMPLES/C/IR_RECEIVER/README
new file mode 100644 (file)
index 0000000..6e995f9
--- /dev/null
@@ -0,0 +1,3 @@
+Function to hash a code from an IR receiver (reading an IR remote control). 
+
+Follow the instructions in the test file to build and run.
diff --git a/EXAMPLES/C/IR_RECEIVER/ir_hasher.c b/EXAMPLES/C/IR_RECEIVER/ir_hasher.c
new file mode 100644 (file)
index 0000000..ef154a1
--- /dev/null
@@ -0,0 +1,132 @@
+#include <stdlib.h>
+
+#include <pigpio.h>
+
+#include "ir_hasher.h"
+
+/*
+This code forms a hash over the IR pulses generated by an
+IR remote.
+
+The remote key press is not converted into a code in the manner of
+the lirc module.  No attempt is made to decode the type of protocol
+used by the remote.  The hash is likely to be unique for different
+keys and different remotes but this is not guaranteed.
+
+This hashing process works for some remotes/protocols but not for
+others.  The only way to find out if it works for one or more of
+your remotes is to try it and see.
+*/
+
+struct _Pi_Hasher_s
+{
+   int gpio;
+   Pi_Hasher_CB_t callback;
+   int timeout;
+   int in_code;
+   uint32_t hash_val;
+   int edges;
+   int t1;
+   int t2;
+   int t3;
+   int t4;
+};
+
+
+static uint32_t _hash(uint32_t hv, int old_val, int new_val)
+{
+   int val;
+
+   if      (new_val < (old_val * 0.60)) val = 13;
+   else if (old_val < (new_val * 0.60)) val = 23;
+   else                                 val = 2;
+
+   hv ^= val;
+   hv *= 16777619; /* FNV_PRIME_32 */
+
+   return hv;
+}
+
+static void _cb(int gpio, int level, uint32_t tick, void *user)
+{
+   Pi_Hasher_t * hasher;
+
+   hasher = user;
+
+   if (level != PI_TIMEOUT)
+   {
+      if (hasher->in_code == 0)
+      {
+         hasher->in_code = 1;
+
+         gpioSetWatchdog(gpio, hasher->timeout);
+
+         hasher->hash_val = 2166136261U; /* FNV_BASIS_32 */
+
+         hasher->edges = 1;
+
+         hasher->t1 = 0;
+         hasher->t2 = 0;
+         hasher->t3 = 0;
+         hasher->t4 = tick;
+      }
+      else
+      {
+         hasher->edges++;
+
+         hasher->t1 = hasher->t2;
+         hasher->t2 = hasher->t3;
+         hasher->t3 = hasher->t4;
+         hasher->t4 = tick;
+
+         if (hasher->edges > 3)
+         {
+            hasher->hash_val =
+               _hash(hasher->hash_val,
+                     (hasher->t2)-(hasher->t1),
+                     (hasher->t4)-(hasher->t3));
+         }
+      }
+   }
+   else
+   {
+      if (hasher->in_code)
+      {
+         hasher->in_code = 0;
+
+         gpioSetWatchdog(gpio, 0);
+
+         if (hasher->edges > 12) /* Anything less is probably noise. */
+         {
+            (hasher->callback)(hasher->hash_val);
+         }
+      }
+   }
+}
+
+Pi_Hasher_t *Pi_Hasher(int gpio, Pi_Hasher_CB_t callback, int timeout)
+{
+   Pi_Hasher_t *hasher;
+
+   hasher = malloc(sizeof(Pi_Hasher_t));
+
+   hasher->gpio     = gpio;
+   hasher->callback = callback;
+   hasher->timeout  = 5;
+
+   hasher->in_code = 0;
+
+   gpioSetMode(gpio, PI_INPUT);
+   gpioSetAlertFuncEx(gpio, _cb, hasher);
+}
+
+void Pi_Hasher_cancel(Pi_Hasher_t *hasher)
+{
+   if (hasher)
+   {
+      gpioSetAlertFunc(hasher->gpio, 0);
+
+      free(hasher);
+   }
+}
+
diff --git a/EXAMPLES/C/IR_RECEIVER/ir_hasher.h b/EXAMPLES/C/IR_RECEIVER/ir_hasher.h
new file mode 100644 (file)
index 0000000..ef2278f
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef IR_HASHER_H
+#define IR_HASHER_H
+
+#include <stdint.h>
+
+typedef void (*Pi_Hasher_CB_t)(uint32_t);
+
+struct _Pi_Hasher_s;
+
+typedef struct _Pi_Hasher_s Pi_Hasher_t;
+
+Pi_Hasher_t * Pi_Hasher(int gpio, Pi_Hasher_CB_t callback, int timeout);
+   /*
+      This function establishes an IR hasher on the gpio.
+
+      A gap of timeout milliseconds without a new bit indicates
+      the end of a code.
+
+      When code end is detected the callback function is called
+      with the code hash.
+
+      A pointer to a private data type is returned.  This should be passed
+      to Pi_Hasher_cancel if the hasher is to be cancelled.
+   */
+
+
+void Pi_Hasher_cancel(Pi_Hasher_t *hasher);
+   /*
+      This function releases the resources used by the hasher.
+   */
+
+
+#endif
diff --git a/EXAMPLES/C/IR_RECEIVER/test_ir_hasher.c b/EXAMPLES/C/IR_RECEIVER/test_ir_hasher.c
new file mode 100644 (file)
index 0000000..878bdb8
--- /dev/null
@@ -0,0 +1,47 @@
+#include <stdio.h>
+
+#include <pigpio.h>
+
+#include "ir_hasher.h"
+
+/*
+
+REQUIRES
+
+An IR receiver output pin connected to a Pi gpio.
+
+TO BUILD
+
+gcc -o ir_hash_c test_ir_hasher.c  ir_hasher.c -lpigpio -lrt
+
+TO RUN
+
+sudo ./ir_hash_c
+
+*/
+
+void callback(uint32_t hash)
+{
+   printf("hash=%u\n", hash);
+}
+
+int main(int argc, char *argv[])
+{
+   Pi_Hasher_t *hasher;
+
+   if (gpioInitialise() < 0) return 1;
+
+   /* 
+      This assumes the output pin of an IR receiver is
+      connected to gpio 7.
+   */
+
+   hasher = Pi_Hasher(7, callback, 5);
+
+   sleep(300);
+
+   Pi_Hasher_cancel(hasher);
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/C/PCF8591_YL-40/PCF8591.c b/EXAMPLES/C/PCF8591_YL-40/PCF8591.c
new file mode 100644 (file)
index 0000000..f2c0730
--- /dev/null
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+#include <ncurses.h> /* libncurses5-dev */
+
+/*
+2014-08-26 PCF8591.c
+
+sudo apt-get install libncurses5-dev
+
+gcc -o PCF8591 PCF8591.c -lcurses -lpigpio -lpthread
+
+sudo ./PCF8591
+*/
+
+/*
+Connect Pi 5V - VCC, Ground - Ground, SDA - SDA, SCL - SCL.
+*/
+
+#define PCF8591_I2C_ADDR 0x48
+
+/*
+    P4 The thermister voltage is provided at AIN 1.
+    P5 The photocell voltage is provided at AIN 0.
+    P6 The single turn 10K ohm trim pot voltage is provided at AIN 3.
+*/
+
+/*
+7 6 5 4 3 2 1 0
+0 X X X 0 X X X
+  | | |   | | |
+  A B B   C D D
+
+0 1 0 0 0 1 0 0
+
+A 0 D/A inactive
+  1 D/A active
+
+B 00 single ended inputs
+  01 differential inputs
+  10 single ended and differential
+  11 two differential inputs
+
+C 0 no auto inc
+  1 auto inc
+
+D 00 select channel 0
+  01 select channel 1
+  10 select channel 2
+  11 select channel 3
+
+*/
+
+int main(int argc, char *argv[])
+{
+   int i;
+   int r;
+   int handle;
+   char aout;
+   unsigned char command[2];
+   unsigned char value[4];
+   unsigned char str[8];
+
+   int j;
+   int key;
+
+   if (gpioInitialise() < 0) return 1;
+
+   initscr();
+   noecho();
+   cbreak();
+   nodelay(stdscr, true);
+   curs_set(0);
+
+   printw("PCF8591 + or - to change aout, any other key to quit.");
+
+   mvaddstr(10, 0, "Brightness");
+   mvaddstr(12, 0, "Temperature");
+   mvaddstr(14, 0, "?");
+   mvaddstr(16, 0, "Resistor");
+
+   refresh();
+
+   handle = i2cOpen(1, PCF8591_I2C_ADDR, 0);
+
+   command[1] = 0;
+   aout = 128;
+
+   while (1)
+   {
+      for (i=0; i<4; i++)
+      {
+         command[1] = aout;
+         command[0] = 0x40 | ((i + 1) & 0x03); // output enable | read input i
+
+         i2cWriteDevice(handle, &command, 2);
+
+         usleep(20000);
+
+         // the read is always one step behind the selected input
+         value[i] = i2cReadByte(handle);
+
+         sprintf(str, "%3d", value[i]);
+         mvaddstr(10+i+i, 12, str);
+         value[i] = value[i] / 4;
+         move(10 + i + i, 16);
+
+         for(j = 0; j < 64; j++)
+            if(j < value[i]) addch('*'); else addch(' ');
+      }
+
+      refresh();
+
+      key = getch();
+
+      if      ((key == '+') || (key == '=')) aout++;
+      else if ((key == '-') || (key == '_')) aout--;
+      else if  (key != -1)                   break;
+   }
+
+   endwin();
+   i2cClose(handle);
+
+   gpioTerminate();
+
+   return (0);
+}
+
diff --git a/EXAMPLES/C/PCF8591_YL-40/README b/EXAMPLES/C/PCF8591_YL-40/README
new file mode 100644 (file)
index 0000000..40428b1
--- /dev/null
@@ -0,0 +1 @@
+A program to display readings from the (I2C) PCF8591.
diff --git a/EXAMPLES/C/POT_CAP_RECHARGE/README b/EXAMPLES/C/POT_CAP_RECHARGE/README
new file mode 100644 (file)
index 0000000..530685c
--- /dev/null
@@ -0,0 +1,3 @@
+Function to time capacitor charging (through a resistance).
+
+The time can be used to estimate the resistance.
diff --git a/EXAMPLES/C/POT_CAP_RECHARGE/pot_cap_charge.c b/EXAMPLES/C/POT_CAP_RECHARGE/pot_cap_charge.c
new file mode 100644 (file)
index 0000000..811e3f7
--- /dev/null
@@ -0,0 +1,94 @@
+#include <stdio.h>
+
+#include <pigpio.h>
+
+/*
+   Measure how long a capacitor takes to charge through a resistance.
+
+   A potentimeter is used to vary the resistance.
+
+   The time taken will be proportional to the resistance.
+
+   3V3 ----- Potentiometer --+-- Capacitor ----- Ground
+                             |
+                             +-- gpio
+
+
+  gcc -o pot_cap_charge pot_cap_charge.c -lpigpio -lpthread -lrt
+  sudo ./pot_cap_charge
+
+*/
+
+#define GPIO 25
+
+#define MAX_READING 1000
+
+static uint32_t rechargeTick = 0;
+
+void callback(int gpio, int level, uint32_t tick)
+{
+   static uint32_t smooth = 0;
+   static int reading = 0;
+
+   uint32_t raw;
+
+   if (level == 1) /* measure recharge time */
+   {
+      ++reading;
+
+      if (rechargeTick)
+      {
+         raw = tick - rechargeTick; /* set in main */
+
+         if (raw < MAX_READING) /* ignore outliers */
+         {
+            /* smooth using 0.8 * smooth + 0.2 * raw */
+
+            smooth = (raw + (4 * smooth)) / 5;
+
+            printf("%d %d %d\n", reading, raw, smooth);
+         }
+         else
+         {
+            /* ignore outlier, set dot at fixed position */
+            printf("%d %d %d\n", reading, 40, smooth);
+         }
+      }
+      else
+      {
+         /* ignore reschedule, set dot at fixed position */
+         printf("%d %d %d\n", reading, 20, smooth);
+      }
+   }
+}
+
+int main (int argc, char *argv[])
+{
+   uint32_t t1, t2;
+   int tDiff;
+
+   if (gpioInitialise()<0) return 1;
+
+   gpioSetAlertFunc(GPIO, callback); /* callback when GPIO changes state */
+    
+   while (1)
+   {
+      gpioWrite(GPIO, PI_OFF); /* drain capacitor */
+
+      gpioDelay(200); /* microseconds */
+
+      t1 = gpioTick();
+
+      gpioSetMode(GPIO, PI_INPUT); /* start capacitor recharge */
+
+      t2 = gpioTick();
+
+      /* dump reading if rechargeTick not accurate to 3 micros */
+
+      if ((t2 - t1) < 3) rechargeTick = t1; else rechargeTick = 0;
+
+      gpioDelay(5000); /* microseconds, nominal 200 readings per second */
+   }
+
+   gpioTerminate();
+}
diff --git a/EXAMPLES/C/ROTARY_ENCODER/README b/EXAMPLES/C/ROTARY_ENCODER/README
new file mode 100644 (file)
index 0000000..d07037e
--- /dev/null
@@ -0,0 +1,4 @@
+Function to decode a mechanical rotary encoder.
+
+Follow the instructions in the test file to build and run.
+
diff --git a/EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.c b/EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.c
new file mode 100644 (file)
index 0000000..5bccba7
--- /dev/null
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <pigpio.h>
+
+#include "rotary_encoder.h"
+
+struct _Pi_Renc_s
+{
+   int gpioA;
+   int gpioB;
+   Pi_Renc_CB_t callback;
+   int levA;
+   int levB;
+   int lastGpio;
+};
+
+/*
+
+             +---------+         +---------+      0
+             |         |         |         |
+   A         |         |         |         |
+             |         |         |         |
+   +---------+         +---------+         +----- 1
+
+       +---------+         +---------+            0
+       |         |         |         |
+   B   |         |         |         |
+       |         |         |         |
+   ----+         +---------+         +---------+  1
+
+*/
+
+static void _cb(int gpio, int level, uint32_t tick, void *user)
+{
+   Pi_Renc_t *renc;
+
+   renc = user;
+
+   if (gpio == renc->gpioA) renc->levA = level; else renc->levB = level;
+
+   if (gpio != renc->lastGpio) /* debounce */
+   {
+      renc->lastGpio = gpio;
+
+      if ((gpio == renc->gpioA) && (level == 1))
+      {
+         if (renc->levB) (renc->callback)(1);
+      }
+      else if ((gpio == renc->gpioB) && (level == 1))
+      {
+         if (renc->levA) (renc->callback)(-1);
+      }
+   }
+}
+
+Pi_Renc_t * Pi_Renc(int gpioA, int gpioB, Pi_Renc_CB_t callback)
+{
+   Pi_Renc_t *renc;
+
+   renc = malloc(sizeof(Pi_Renc_t));
+
+   renc->gpioA = gpioA;
+   renc->gpioB = gpioB;
+   renc->callback = callback;
+   renc->levA=0;
+   renc->levB=0;
+   renc->lastGpio = -1;
+
+   gpioSetMode(gpioA, PI_INPUT);
+   gpioSetMode(gpioB, PI_INPUT);
+
+   /* pull up is needed as encoder common is grounded */
+
+   gpioSetPullUpDown(gpioA, PI_PUD_UP);
+   gpioSetPullUpDown(gpioB, PI_PUD_UP);
+
+   /* monitor encoder level changes */
+
+   gpioSetAlertFuncEx(gpioA, _cb, renc);
+   gpioSetAlertFuncEx(gpioB, _cb, renc);
+}
+
+void Pi_Renc_cancel(Pi_Renc_t *renc)
+{
+   if (renc)
+   {
+      gpioSetAlertFunc(renc->gpioA, 0);
+      gpioSetAlertFunc(renc->gpioB, 0);
+
+      free(renc);
+   }
+}
+
diff --git a/EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.h b/EXAMPLES/C/ROTARY_ENCODER/rotary_encoder.h
new file mode 100644 (file)
index 0000000..73f7454
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef ROTARY_ENCODER_H
+#define ROTARY_ENCODER_H
+
+typedef void (*Pi_Renc_CB_t)(int);
+
+struct _Pi_Renc_s;
+
+typedef struct _Pi_Renc_s Pi_Renc_t;
+
+Pi_Renc_t * Pi_Renc(int gpioA, int gpioB, Pi_Renc_CB_t callback);
+/*
+   This function establishes a rotary encoder on gpioA and gpioB.
+
+   When the encoder is turned the callback function is called.
+
+   A pointer to a private data type is returned.  This should be passed
+   to Pi_Renc_cancel if the rotary encoder is to be cancelled.
+*/
+
+void Pi_Renc_cancel(Pi_Renc_t *renc);
+/*
+   This function releases the resources used by the decoder.
+*/
+
+#endif
diff --git a/EXAMPLES/C/ROTARY_ENCODER/test_rotary_encoder.c b/EXAMPLES/C/ROTARY_ENCODER/test_rotary_encoder.c
new file mode 100644 (file)
index 0000000..9f512e0
--- /dev/null
@@ -0,0 +1,47 @@
+#include <stdio.h>
+
+#include <pigpio.h>
+
+#include "rotary_encoder.h"
+
+/*
+
+REQUIRES
+
+A rotary encoder contacts A and B connected to separate gpios and
+the common contact connected to Pi ground.
+
+TO BUILD
+
+gcc -o rot_enc_c test_rotary_encoder.c rotary_encoder.c -lpigpio -lrt
+
+TO RUN
+
+sudo ./rot_enc_c
+
+*/
+
+void callback(int way)
+{
+   static int pos = 0;
+
+   pos += way;
+
+   printf("pos=%d\n", pos);
+}
+
+int main(int argc, char *argv[])
+{
+   Pi_Renc_t * renc;
+
+   if (gpioInitialise() < 0) return 1;
+
+   renc = Pi_Renc(7, 8, callback);
+
+   sleep(300);
+
+   Pi_Renc_cancel(renc);
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/C/WIEGAND_CODE/README b/EXAMPLES/C/WIEGAND_CODE/README
new file mode 100644 (file)
index 0000000..38d5acb
--- /dev/null
@@ -0,0 +1,4 @@
+Function to decode a Wiegand code.
+
+Follow the instructions in the test file to build and run.
+
diff --git a/EXAMPLES/C/WIEGAND_CODE/test_wiegand.c b/EXAMPLES/C/WIEGAND_CODE/test_wiegand.c
new file mode 100644 (file)
index 0000000..8aef6d6
--- /dev/null
@@ -0,0 +1,42 @@
+#include <stdio.h>
+
+#include <pigpio.h>
+
+#include "wiegand.h"
+
+/*
+
+REQUIRES
+
+Wiegand contacts 0 and 1 connected to separate gpios.
+
+TO BUILD
+
+gcc -o wiegand_c test_wiegand.c wiegand.c -lpigpio -lrt
+
+TO RUN
+
+sudo ./wiegand_c
+
+*/
+
+void callback(int bits, uint32_t value)
+{
+   printf("bits=%d value=%u\n", bits, value);
+}
+
+int main(int argc, char *argv[])
+{
+   Pi_Wieg_t * w;
+
+   if (gpioInitialise() < 0) return 1;
+
+   w = Pi_Wieg(14, 15, callback, 5);
+
+   sleep(300);
+
+   Pi_Wieg_cancel(w);
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/C/WIEGAND_CODE/wiegand.c b/EXAMPLES/C/WIEGAND_CODE/wiegand.c
new file mode 100644 (file)
index 0000000..5bfecd7
--- /dev/null
@@ -0,0 +1,137 @@
+#include <stdlib.h>
+
+#include <pigpio.h>
+
+#include "wiegand.h"
+
+struct _Pi_Wieg_s
+{
+   int mygpio_0;
+   int mygpio_1;
+   int mytimeout;
+   int in_code;
+   int bits;
+   Pi_Wieg_CB_t mycallback;
+   uint32_t num;
+   uint32_t code_timeout;
+};
+
+void _cb(int gpio, int level, uint32_t tick, void *user)
+{
+   /*
+      Accumulate bits until both gpios 0 and 1 timeout.
+   */
+
+   Pi_Wieg_t *wieg;
+
+   wieg = user;
+
+   if (level == 0) /* a falling edge indicates a new bit */
+   {
+      if (!wieg->in_code)
+      {
+         wieg->bits = 1;
+         wieg->num = 0;
+
+         wieg->in_code = 1;
+         wieg->code_timeout = 0;
+
+         gpioSetWatchdog(wieg->mygpio_0, wieg->mytimeout);
+         gpioSetWatchdog(wieg->mygpio_1, wieg->mytimeout);
+      }
+      else
+      {
+         wieg->bits++;
+         wieg->num <<= 1;
+      }
+
+      if (gpio == wieg->mygpio_0)
+      {
+         wieg->code_timeout &= 2; /* clear gpio 0 timeout */
+      }
+      else
+      {
+         wieg->code_timeout &= 1; /* clear gpio 1 timeout */
+         wieg->num |= 1;
+      }
+   }
+   else if (level == PI_TIMEOUT)
+   {
+      if (wieg->in_code)
+      {
+         if (gpio == wieg->mygpio_0)
+         {
+            wieg->code_timeout |= 1; /* timeout gpio 0 */
+         }
+         else
+         {
+            wieg->code_timeout |= 2; /* timeout gpio 1 */
+         }
+
+         if (wieg->code_timeout == 3) /* both gpios timed out */
+         {
+            gpioSetWatchdog(wieg->mygpio_0, 0);
+            gpioSetWatchdog(wieg->mygpio_1, 0);
+
+            wieg->in_code = 0;
+
+            (wieg->mycallback)(wieg->bits, wieg->num);
+         }
+      }
+   }
+}
+
+Pi_Wieg_t * Pi_Wieg(
+   int gpio_0,
+   int gpio_1,
+   Pi_Wieg_CB_t callback,
+   int timeout)
+{
+   /*
+      Instantiate with the gpio for 0 (green wire), the gpio for 1
+      (white wire), the callback function, and the timeout in
+      milliseconds which indicates the end of a code.
+
+      The callback is passed the code length in bits and the value.
+   */
+
+   Pi_Wieg_t *wieg;
+
+   wieg = malloc(sizeof(Pi_Wieg_t));
+
+   wieg->mygpio_0 = gpio_0;
+   wieg->mygpio_1 = gpio_1;
+
+   wieg->mycallback = callback;
+
+   wieg->mytimeout = timeout;
+
+   wieg->in_code = 0;
+
+   gpioSetMode(gpio_0, PI_INPUT);
+   gpioSetMode(gpio_1, PI_INPUT);
+
+   gpioSetPullUpDown(gpio_0, PI_PUD_UP);
+   gpioSetPullUpDown(gpio_1, PI_PUD_UP);
+
+   gpioSetAlertFuncEx(gpio_0, _cb, wieg);
+   gpioSetAlertFuncEx(gpio_1, _cb, wieg);
+
+   return wieg;
+}
+
+void Pi_Wieg_cancel(Pi_Wieg_t *wieg)
+{
+   /*
+      Cancel the Wiegand decoder.
+   */
+
+   if (wieg)
+   {
+      gpioSetAlertFunc(wieg->mygpio_0, 0);
+      gpioSetAlertFunc(wieg->mygpio_1, 0);
+
+      free(wieg);
+   }
+}
+
diff --git a/EXAMPLES/C/WIEGAND_CODE/wiegand.h b/EXAMPLES/C/WIEGAND_CODE/wiegand.h
new file mode 100644 (file)
index 0000000..8deaa3a
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef WIEGAND_H
+#define WIEGAND_H
+
+#include <stdint.h>
+
+typedef void (*Pi_Wieg_CB_t)(int, uint32_t);
+
+struct _Pi_Wieg_s;
+
+typedef struct _Pi_Wieg_s Pi_Wieg_t;
+
+Pi_Wieg_t *Pi_Wieg(int gpio_0, int gpio_1, Pi_Wieg_CB_t callback, int timeout);
+   /*
+      This function establishes a Wiegand decoder on gpio_0 and gpio_1.
+
+      A gap of timeout milliseconds without a new bit indicates the
+      end of a code.
+
+      When the code is ended the callback function is called with the code
+      bit length and value.
+
+      A pointer to a private data type is returned.  This should be passed
+      to Pi_Wieg_cancel if the decoder is to be cancelled.
+   */
+
+void Pi_Wieg_cancel(Pi_Wieg_t *wieg);
+   /*
+      This function releases the resources used by the decoder.
+   */
+
+#endif
+