mirror of https://github.com/joan2937/pigpio
V23
This commit is contained in:
parent
a723db6efc
commit
4cbcce81ac
|
@ -0,0 +1,2 @@
|
|||
Program to show status changes for a Hall effect sensor.
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
A program to passively sniff I2C transactions (100kHz bus maximum) and display the results.
|
||||
|
||||
This C program uses pigpio notifications.
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
A program to display readings from the (I2C) PCF8591.
|
|
@ -0,0 +1,3 @@
|
|||
Function to time capacitor charging (through a resistance).
|
||||
|
||||
The time can be used to estimate the resistance.
|
|
@ -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();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Function to decode a mechanical rotary encoder.
|
||||
|
||||
Follow the instructions in the test file to build and run.
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Function to decode a Wiegand code.
|
||||
|
||||
Follow the instructions in the test file to build and run.
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue