This commit is contained in:
joan 2014-11-25 14:27:33 +00:00
parent a723db6efc
commit 4cbcce81ac
20 changed files with 1091 additions and 0 deletions

View File

@ -0,0 +1,2 @@
Program to show status changes for a Hall effect sensor.

View File

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

View File

@ -0,0 +1,4 @@
A program to passively sniff I2C transactions (100kHz bus maximum) and display the results.
This C program uses pigpio notifications.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
A program to display readings from the (I2C) PCF8591.

View File

@ -0,0 +1,3 @@
Function to time capacitor charging (through a resistance).
The time can be used to estimate the resistance.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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