V23
authorjoan <joan@abyz.me.uk>
Tue, 25 Nov 2014 16:36:44 +0000 (16:36 +0000)
committerjoan <joan@abyz.me.uk>
Tue, 25 Nov 2014 16:36:44 +0000 (16:36 +0000)
12 files changed:
EXAMPLES/CPP/IR_RECEIVER/README [new file with mode: 0644]
EXAMPLES/CPP/IR_RECEIVER/ir_hasher.cpp [new file with mode: 0644]
EXAMPLES/CPP/IR_RECEIVER/ir_hasher.hpp [new file with mode: 0644]
EXAMPLES/CPP/IR_RECEIVER/test_ir_hasher.cpp [new file with mode: 0644]
EXAMPLES/CPP/ROTARY_ENCODER/README [new file with mode: 0644]
EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.cpp [new file with mode: 0644]
EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.hpp [new file with mode: 0644]
EXAMPLES/CPP/ROTARY_ENCODER/test_rotary_encoder.cpp [new file with mode: 0644]
EXAMPLES/CPP/WIEGAND_CODE/README [new file with mode: 0644]
EXAMPLES/CPP/WIEGAND_CODE/test_wiegand.cpp [new file with mode: 0644]
EXAMPLES/CPP/WIEGAND_CODE/wiegand.cpp [new file with mode: 0644]
EXAMPLES/CPP/WIEGAND_CODE/wiegand.hpp [new file with mode: 0644]

diff --git a/EXAMPLES/CPP/IR_RECEIVER/README b/EXAMPLES/CPP/IR_RECEIVER/README
new file mode 100644 (file)
index 0000000..ccb0165
--- /dev/null
@@ -0,0 +1,4 @@
+Class 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/CPP/IR_RECEIVER/ir_hasher.cpp b/EXAMPLES/CPP/IR_RECEIVER/ir_hasher.cpp
new file mode 100644 (file)
index 0000000..d2d01fd
--- /dev/null
@@ -0,0 +1,91 @@
+#include <pigpio.h>
+
+#include "ir_hasher.hpp"
+
+void Hasher::_hash(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;
+
+   hash_val ^= val;
+   hash_val *= 16777619; /* FNV_PRIME_32 */
+}
+
+void Hasher::_callback(int gpio, int level, uint32_t tick)
+{
+   if (level != PI_TIMEOUT)
+   {
+      if (in_code == 0)
+      {
+         in_code = 1;
+
+         gpioSetWatchdog(mygpio, mytimeout);
+
+         hash_val = 2166136261U; /* FNV_BASIS_32 */
+
+         edges = 1;
+
+         t1 = 0;
+         t2 = 0;
+         t3 = 0;
+         t4 = tick;
+      }
+      else
+      {
+         edges++;
+
+         t1 = t2;
+         t2 = t3;
+         t3 = t4;
+         t4 = tick;
+
+         if (edges > 3) _hash(t2-t1, t4-t3);
+      }
+   }
+   else
+   {
+      if (in_code)
+      {
+         in_code = 0;
+
+         gpioSetWatchdog(mygpio, 0);
+
+         if (edges > 12) /* Anything less is probably noise. */
+         {
+            (mycallback)(hash_val);
+         }
+      }
+   }
+}
+
+void Hasher::_callbackExt(int gpio, int level, uint32_t tick, void *user)
+{
+   /*
+      Need a static callback to link with C.
+   */
+
+   Hasher *mySelf = (Hasher *) user;
+
+   mySelf->_callback(gpio, level, tick); /* Call the instance callback. */
+}
+
+Hasher::Hasher(int gpio, HasherCB_t callback, int timeout)
+{
+   /*
+      Initialises an IR remote hasher on a gpio.  A gap of timeout
+      milliseconds indicates the end of the remote key press.
+   */
+   mygpio     = gpio;
+   mycallback = callback;
+   mytimeout  = timeout;
+
+   in_code = 0;
+
+   gpioSetMode(gpio, PI_INPUT);
+
+   gpioSetAlertFuncEx(gpio, _callbackExt, (void *)this);
+}
+
diff --git a/EXAMPLES/CPP/IR_RECEIVER/ir_hasher.hpp b/EXAMPLES/CPP/IR_RECEIVER/ir_hasher.hpp
new file mode 100644 (file)
index 0000000..2e9322a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef IR_RX_HASHER_HPP
+#define IR_RX_HASHER_HPP
+
+#include <stdint.h>
+
+typedef void (*HasherCB_t)(uint32_t);
+
+class Hasher
+{
+
+   /*
+   This class 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.
+   */
+
+   int mygpio, mytimeout;
+   HasherCB_t mycallback;
+   int in_code;
+   uint32_t hash_val;
+   int edges;
+   uint32_t t1, t2, t3, t4;
+
+   void _hash(int old_val, int new_val);
+   void _callback(int gpio, int level, uint32_t tick);
+
+   /* Need a static callback to link with C. */
+   static void _callbackExt(int gpio, int level, uint32_t tick, void *user);
+
+   public:
+
+   Hasher(int gpio, HasherCB_t callback, int timeout=5);
+};
+
+#endif
+
diff --git a/EXAMPLES/CPP/IR_RECEIVER/test_ir_hasher.cpp b/EXAMPLES/CPP/IR_RECEIVER/test_ir_hasher.cpp
new file mode 100644 (file)
index 0000000..a852220
--- /dev/null
@@ -0,0 +1,44 @@
+#include <iostream>
+
+#include <pigpio.h>
+
+#include "ir_hasher.hpp"
+
+/*
+
+REQUIRES
+
+An IR receiver output pin connected to a Pi gpio.
+
+TO BUILD
+
+g++ -o ir_hash_cpp test_ir_hasher.cpp ir_hasher.cpp -lpigpio -lrt
+
+TO RUN
+
+sudo ./ir_hash_cpp
+
+*/
+
+void callback(uint32_t hash)
+{
+   std::cout << "hash=" << hash << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+   if (gpioInitialise() >= 0)
+   {
+      /* Can't instantiate a Hasher before pigpio is initialised. */
+
+      /* 
+         This assumes the output pin of an IR receiver is
+         connected to gpio 7.
+      */
+
+      Hasher ir(7, callback);
+
+      sleep(300);
+   }
+}
+
diff --git a/EXAMPLES/CPP/ROTARY_ENCODER/README b/EXAMPLES/CPP/ROTARY_ENCODER/README
new file mode 100644 (file)
index 0000000..f9e01cb
--- /dev/null
@@ -0,0 +1,4 @@
+Class to decode a mechanical rotary encoder.
+
+Follow the instructions in the test file to build and run.
+
diff --git a/EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.cpp b/EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.cpp
new file mode 100644 (file)
index 0000000..f0b6fb7
--- /dev/null
@@ -0,0 +1,84 @@
+#include <iostream>
+
+#include <pigpio.h>
+
+#include "rotary_encoder.hpp"
+
+/*
+
+             +---------+         +---------+      0
+             |         |         |         |
+   A         |         |         |         |
+             |         |         |         |
+   +---------+         +---------+         +----- 1
+
+       +---------+         +---------+            0
+       |         |         |         |
+   B   |         |         |         |
+       |         |         |         |
+   ----+         +---------+         +---------+  1
+
+*/
+
+void re_decoder::_pulse(int gpio, int level, uint32_t tick)
+{
+   if (gpio == mygpioA) levA = level; else levB = level;
+
+   if (gpio != lastGpio) /* debounce */
+   {
+      lastGpio = gpio;
+
+      if ((gpio == mygpioA) && (level == 1))
+      {
+         if (levB) (mycallback)(1);
+      }
+      else if ((gpio == mygpioB) && (level == 1))
+      {
+         if (levA) (mycallback)(-1);
+      }
+   }
+}
+
+void re_decoder::_pulseEx(int gpio, int level, uint32_t tick, void *user)
+{
+   /*
+      Need a static callback to link with C.
+   */
+
+   re_decoder *mySelf = (re_decoder *) user;
+
+   mySelf->_pulse(gpio, level, tick); /* Call the instance callback. */
+}
+
+re_decoder::re_decoder(int gpioA, int gpioB, re_decoderCB_t callback)
+{
+   mygpioA = gpioA;
+   mygpioB = gpioB;
+
+   mycallback = callback;
+
+   levA=0;
+   levB=0;
+
+   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, _pulseEx, this);
+   gpioSetAlertFuncEx(gpioB, _pulseEx, this);
+}
+
+void re_decoder::re_cancel(void)
+{
+   gpioSetAlertFuncEx(mygpioA, 0, this);
+   gpioSetAlertFuncEx(mygpioB, 0, this);
+}
+
diff --git a/EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.hpp b/EXAMPLES/CPP/ROTARY_ENCODER/rotary_encoder.hpp
new file mode 100644 (file)
index 0000000..e2ef8c0
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef ROTARY_ENCODER_HPP
+#define ROTARY_ENCODER_HPP
+
+#include <stdint.h>
+
+typedef void (*re_decoderCB_t)(int);
+
+class re_decoder
+{
+   int mygpioA, mygpioB, levA, levB, lastGpio;
+
+   re_decoderCB_t mycallback;
+
+   void _pulse(int gpio, int level, uint32_t tick);
+
+   /* Need a static callback to link with C. */
+   static void _pulseEx(int gpio, int level, uint32_t tick, void *user);
+
+
+   public:
+
+   re_decoder(int gpioA, int gpioB, re_decoderCB_t callback);
+   /*
+      This function establishes a rotary encoder on gpioA and gpioB.
+
+      When the encoder is turned the callback function is called.
+   */
+
+   void re_cancel(void);
+   /*
+      This function releases the resources used by the decoder.
+   */
+};
+
+#endif
diff --git a/EXAMPLES/CPP/ROTARY_ENCODER/test_rotary_encoder.cpp b/EXAMPLES/CPP/ROTARY_ENCODER/test_rotary_encoder.cpp
new file mode 100644 (file)
index 0000000..f1d6a59
--- /dev/null
@@ -0,0 +1,45 @@
+#include <iostream>
+
+#include <pigpio.h>
+
+#include "rotary_encoder.hpp"
+
+/*
+
+REQUIRES
+
+A rotary encoder contacts A and B connected to separate gpios and
+the common contact connected to Pi ground.
+
+TO BUILD
+
+g++ -o rot_enc_cpp test_rotary_encoder.cpp rotary_encoder.cpp -lpigpio -lrt
+
+TO RUN
+
+sudo ./rot_enc_cpp
+
+*/
+
+void callback(int way)
+{
+   static int pos = 0;
+
+   pos += way;
+
+   std::cout << "pos=" << pos << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+   if (gpioInitialise() < 0) return 1;
+
+   re_decoder dec(7, 8, callback);
+
+   sleep(3000);
+
+   dec.re_cancel();
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/CPP/WIEGAND_CODE/README b/EXAMPLES/CPP/WIEGAND_CODE/README
new file mode 100644 (file)
index 0000000..28079b4
--- /dev/null
@@ -0,0 +1,3 @@
+Class to decode a Wiegand code.
+
+Follow the instructions in the test file to build and run.
diff --git a/EXAMPLES/CPP/WIEGAND_CODE/test_wiegand.cpp b/EXAMPLES/CPP/WIEGAND_CODE/test_wiegand.cpp
new file mode 100644 (file)
index 0000000..ca225a4
--- /dev/null
@@ -0,0 +1,40 @@
+#include <iostream>
+
+#include <pigpio.h>
+
+#include "wiegand.hpp"
+
+/*
+
+REQUIRES
+
+Wiegand contacts 0 and 1 connected to separate gpios.
+
+TO BUILD
+
+g++ -o wiegand_cpp test_wiegand.cpp wiegand.cpp -lpigpio -lrt
+
+TO RUN
+
+sudo ./wiegand_cpp
+
+*/
+
+void callback(int bits, uint32_t value)
+{
+   std::cout << "bits=" << bits << " value=" << value << std::endl;
+}
+
+int main(int argc, char *argv[])
+{
+   if (gpioInitialise() < 0) return 1;
+
+   Wiegand dec(14, 15, callback);
+
+   sleep(300);
+
+   dec.cancel();
+
+   gpioTerminate();
+}
+
diff --git a/EXAMPLES/CPP/WIEGAND_CODE/wiegand.cpp b/EXAMPLES/CPP/WIEGAND_CODE/wiegand.cpp
new file mode 100644 (file)
index 0000000..598b76d
--- /dev/null
@@ -0,0 +1,116 @@
+#include <pigpio.h>
+
+#include "wiegand.hpp"
+
+Wiegand::Wiegand(int gpio_0, int gpio_1, WiegandCB_t callback, int timeout)
+{
+   /*
+      Instantiate with the gpio for 0 (green wire), the gpio for 1
+      (white wire), the callback function, and the bit timeout in
+      milliseconds which indicates the end of a code.
+
+      The callback is passed the code length in bits and the value.
+   */
+
+   mygpio_0 = gpio_0;
+   mygpio_1 = gpio_1;
+
+   mycallback = callback;
+
+   mytimeout = timeout;
+
+   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, _cbEx, this);
+   gpioSetAlertFuncEx(gpio_1, _cbEx, this);
+}
+
+void Wiegand::_cb(int gpio, int level, uint32_t tick)
+{
+   /*
+      Accumulate bits until both gpios 0 and 1 timeout.
+   */
+
+   if (level == 0) /* a falling edge indicates a new bit */
+   {
+      if (!in_code)
+      {
+         bits = 1;
+         num = 0;
+
+         in_code = 1;
+         code_timeout = 0;
+
+         gpioSetWatchdog(mygpio_0, mytimeout);
+         gpioSetWatchdog(mygpio_1, mytimeout);
+      }
+      else
+      {
+         bits++;
+         num <<= 1;
+      }
+
+      if (gpio == mygpio_0)
+      {
+         code_timeout &= 2; /* clear gpio 0 timeout */
+      }
+      else
+      {
+         code_timeout &= 1; /* clear gpio 1 timeout */
+         num |= 1;
+      }
+   }
+   else if (level == PI_TIMEOUT)
+   {
+      if (in_code)
+      {
+         if (gpio == mygpio_0)
+         {
+            code_timeout |= 1; /* timeout gpio 0 */
+         }
+         else
+         {
+            code_timeout |= 2; /* timeout gpio 1 */
+         }
+
+         if (code_timeout == 3) /* both gpios timed out */
+         {
+            gpioSetWatchdog(mygpio_0, 0);
+            gpioSetWatchdog(mygpio_1, 0);
+
+            in_code = 0;
+
+            (mycallback)(bits, num);
+         }
+      }
+   }
+}
+
+void Wiegand::_cbEx(int gpio, int level, uint32_t tick, void *user)
+{
+   /*
+      Need a static callback to link with C.
+   */
+
+   Wiegand *mySelf = (Wiegand *) user;
+
+   mySelf->_cb(gpio, level, tick); /* Call the instance callback. */
+}
+
+
+void Wiegand::cancel(void)
+{
+   /*
+      Cancel the Wiegand decoder.
+   */
+
+   gpioSetAlertFuncEx(mygpio_0, 0, this);
+   gpioSetAlertFuncEx(mygpio_1, 0, this);
+}
+
diff --git a/EXAMPLES/CPP/WIEGAND_CODE/wiegand.hpp b/EXAMPLES/CPP/WIEGAND_CODE/wiegand.hpp
new file mode 100644 (file)
index 0000000..4b5215c
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef WIEGAND_HPP
+#define WIEGAND_HPP
+
+#include <stdint.h>
+
+typedef void (*WiegandCB_t)(int, uint32_t);
+
+class Wiegand
+{
+   int mygpio_0, mygpio_1, mytimeout, in_code, bits;
+
+   WiegandCB_t mycallback;
+
+   uint32_t num;
+
+   uint32_t code_timeout;
+
+   void _cb(int gpio, int level, uint32_t tick);
+
+   /* Need a static callback to link with C. */
+   static void _cbEx(int gpio, int level, uint32_t tick, void *user);
+
+   public:
+
+   Wiegand(int gpio_0, int gpio_1, WiegandCB_t callback, int timeout=5);
+   /*
+      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.
+   */
+
+   void cancel(void);
+   /*
+      This function releases the resources used by the decoder.
+   */
+};
+
+#endif
+