This commit is contained in:
joan 2014-11-25 16:36:44 +00:00
parent 4cbcce81ac
commit 6e8073871d
12 changed files with 553 additions and 0 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -0,0 +1,4 @@
Class to decode a mechanical rotary encoder.
Follow the instructions in the test file to build and run.

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -0,0 +1,3 @@
Class to decode a Wiegand code.
Follow the instructions in the test file to build and run.

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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