mirror of https://github.com/joan2937/pigpio
V23
This commit is contained in:
parent
6e8073871d
commit
e8a8ce1982
|
@ -1 +0,0 @@
|
|||
pigpio C++ examples
|
|
@ -0,0 +1,283 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# 2014-07-11 DHT22.py
|
||||
|
||||
import time
|
||||
import atexit
|
||||
|
||||
import pigpio
|
||||
|
||||
class sensor:
|
||||
"""
|
||||
A class to read relative humidity and temperature from the
|
||||
DHT22 sensor. The sensor is also known as the AM2302.
|
||||
|
||||
The sensor can be powered from the Pi 3V3 or the Pi 5V rail.
|
||||
|
||||
Powering from the 3V3 rail is simpler and safer. You may need
|
||||
to power from 5V if the sensor is connected via a long cable.
|
||||
|
||||
For 3V3 operation connect pin 1 to 3V3 and pin 4 to ground.
|
||||
|
||||
Connect pin 2 to a gpio.
|
||||
|
||||
For 5V operation connect pin 1 to 5V and pin 4 to ground.
|
||||
|
||||
The following pin 2 connection works for me. Use at YOUR OWN RISK.
|
||||
|
||||
5V--5K_resistor--+--10K_resistor--Ground
|
||||
|
|
||||
DHT22 pin 2 -----+
|
||||
|
|
||||
gpio ------------+
|
||||
"""
|
||||
|
||||
def __init__(self, pi, gpio, LED=None, power=None):
|
||||
"""
|
||||
Instantiate with the Pi and gpio to which the DHT22 output
|
||||
pin is connected.
|
||||
|
||||
Optionally a LED may be specified. This will be blinked for
|
||||
each successful reading.
|
||||
|
||||
Optionally a gpio used to power the sensor may be specified.
|
||||
This gpio will be set high to power the sensor. If the sensor
|
||||
locks it will be power cycled to restart the readings.
|
||||
|
||||
Taking readings more often than about once every two seconds will
|
||||
eventually cause the DHT22 to hang. A 3 second interval seems OK.
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gpio = gpio
|
||||
self.LED = LED
|
||||
self.power = power
|
||||
|
||||
if power is not None:
|
||||
pi.write(power, 1) # Switch sensor on.
|
||||
time.sleep(2)
|
||||
|
||||
self.powered = True
|
||||
|
||||
self.cb = None
|
||||
|
||||
atexit.register(self.cancel)
|
||||
|
||||
self.bad_CS = 0 # Bad checksum count.
|
||||
self.bad_SM = 0 # Short message count.
|
||||
self.bad_MM = 0 # Missing message count.
|
||||
self.bad_SR = 0 # Sensor reset count.
|
||||
|
||||
# Power cycle if timeout > MAX_TIMEOUTS.
|
||||
self.no_response = 0
|
||||
self.MAX_NO_RESPONSE = 2
|
||||
|
||||
self.rhum = -999
|
||||
self.temp = -999
|
||||
|
||||
self.tov = None
|
||||
|
||||
self.high_tick = 0
|
||||
self.bit = 40
|
||||
|
||||
pi.set_pull_up_down(gpio, pigpio.PUD_OFF)
|
||||
|
||||
pi.set_watchdog(gpio, 0) # Kill any watchdogs.
|
||||
|
||||
self.cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._cb)
|
||||
|
||||
def _cb(self, gpio, level, tick):
|
||||
"""
|
||||
Accumulate the 40 data bits. Format into 5 bytes, humidity high,
|
||||
humidity low, temperature high, temperature low, checksum.
|
||||
"""
|
||||
diff = pigpio.tickDiff(self.high_tick, tick)
|
||||
|
||||
if level == 0:
|
||||
|
||||
# Edge length determines if bit is 1 or 0.
|
||||
|
||||
if diff >= 50:
|
||||
val = 1
|
||||
if diff >= 200: # Bad bit?
|
||||
self.CS = 256 # Force bad checksum.
|
||||
else:
|
||||
val = 0
|
||||
|
||||
if self.bit >= 40: # Message complete.
|
||||
self.bit = 40
|
||||
|
||||
elif self.bit >= 32: # In checksum byte.
|
||||
self.CS = (self.CS<<1) + val
|
||||
|
||||
if self.bit == 39:
|
||||
|
||||
# 40th bit received.
|
||||
|
||||
self.pi.set_watchdog(self.gpio, 0)
|
||||
|
||||
self.no_response = 0
|
||||
|
||||
total = self.hH + self.hL + self.tH + self.tL
|
||||
|
||||
if (total & 255) == self.CS: # Is checksum ok?
|
||||
|
||||
self.rhum = ((self.hH<<8) + self.hL) * 0.1
|
||||
|
||||
if self.tH & 128: # Negative temperature.
|
||||
mult = -0.1
|
||||
self.tH = self.tH & 127
|
||||
else:
|
||||
mult = 0.1
|
||||
|
||||
self.temp = ((self.tH<<8) + self.tL) * mult
|
||||
|
||||
self.tov = time.time()
|
||||
|
||||
if self.LED is not None:
|
||||
self.pi.write(self.LED, 0)
|
||||
|
||||
else:
|
||||
|
||||
self.bad_CS += 1
|
||||
|
||||
elif self.bit >=24: # in temp low byte
|
||||
self.tL = (self.tL<<1) + val
|
||||
|
||||
elif self.bit >=16: # in temp high byte
|
||||
self.tH = (self.tH<<1) + val
|
||||
|
||||
elif self.bit >= 8: # in humidity low byte
|
||||
self.hL = (self.hL<<1) + val
|
||||
|
||||
elif self.bit >= 0: # in humidity high byte
|
||||
self.hH = (self.hH<<1) + val
|
||||
|
||||
else: # header bits
|
||||
pass
|
||||
|
||||
self.bit += 1
|
||||
|
||||
elif level == 1:
|
||||
self.high_tick = tick
|
||||
if diff > 250000:
|
||||
self.bit = -2
|
||||
self.hH = 0
|
||||
self.hL = 0
|
||||
self.tH = 0
|
||||
self.tL = 0
|
||||
self.CS = 0
|
||||
|
||||
else: # level == pigpio.TIMEOUT:
|
||||
self.pi.set_watchdog(self.gpio, 0)
|
||||
if self.bit < 8: # Too few data bits received.
|
||||
self.bad_MM += 1 # Bump missing message count.
|
||||
self.no_response += 1
|
||||
if self.no_response > self.MAX_NO_RESPONSE:
|
||||
self.no_response = 0
|
||||
self.bad_SR += 1 # Bump sensor reset count.
|
||||
if self.power is not None:
|
||||
self.powered = False
|
||||
self.pi.write(self.power, 0)
|
||||
time.sleep(2)
|
||||
self.pi.write(self.power, 1)
|
||||
time.sleep(2)
|
||||
self.powered = True
|
||||
elif self.bit < 39: # Short message receieved.
|
||||
self.bad_SM += 1 # Bump short message count.
|
||||
self.no_response = 0
|
||||
|
||||
else: # Full message received.
|
||||
self.no_response = 0
|
||||
|
||||
def temperature(self):
|
||||
"""Return current temperature."""
|
||||
return self.temp
|
||||
|
||||
def humidity(self):
|
||||
"""Return current relative humidity."""
|
||||
return self.rhum
|
||||
|
||||
def staleness(self):
|
||||
"""Return time since measurement made."""
|
||||
if self.tov is not None:
|
||||
return time.time() - self.tov
|
||||
else:
|
||||
return -999
|
||||
|
||||
def bad_checksum(self):
|
||||
"""Return count of messages received with bad checksums."""
|
||||
return self.bad_CS
|
||||
|
||||
def short_message(self):
|
||||
"""Return count of short messages."""
|
||||
return self.bad_SM
|
||||
|
||||
def missing_message(self):
|
||||
"""Return count of missing messages."""
|
||||
return self.bad_MM
|
||||
|
||||
def sensor_resets(self):
|
||||
"""Return count of power cycles because of sensor hangs."""
|
||||
return self.bad_SR
|
||||
|
||||
def trigger(self):
|
||||
"""Trigger a new relative humidity and temperature reading."""
|
||||
if self.powered:
|
||||
if self.LED is not None:
|
||||
self.pi.write(self.LED, 1)
|
||||
|
||||
self.pi.write(self.gpio, pigpio.LOW)
|
||||
time.sleep(0.017) # 17 ms
|
||||
self.pi.set_mode(self.gpio, pigpio.INPUT)
|
||||
self.pi.set_watchdog(self.gpio, 200)
|
||||
|
||||
def cancel(self):
|
||||
"""Cancel the DHT22 sensor."""
|
||||
|
||||
self.pi.set_watchdog(self.gpio, 0)
|
||||
|
||||
if self.cb != None:
|
||||
self.cb.cancel()
|
||||
self.cb = None
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import DHT22
|
||||
|
||||
# Intervals of about 2 seconds or less will eventually hang the DHT22.
|
||||
INTERVAL=3
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
s = DHT22.sensor(pi, 22, LED=16, power=8)
|
||||
|
||||
r = 0
|
||||
|
||||
next_reading = time.time()
|
||||
|
||||
while True:
|
||||
|
||||
r += 1
|
||||
|
||||
s.trigger()
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
print("{} {} {} {:3.2f} {} {} {} {}".format(
|
||||
r, s.humidity(), s.temperature(), s.staleness(),
|
||||
s.bad_checksum(), s.short_message(), s.missing_message(),
|
||||
s.sensor_resets()))
|
||||
|
||||
next_reading += INTERVAL
|
||||
|
||||
time.sleep(next_reading-time.time()) # Overall INTERVAL second polling.
|
||||
|
||||
s.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Class to read the relative humidity and temperature from a DHT22/AM2302 sensor.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Script to display the status of gpios 0-31.
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
import curses
|
||||
import atexit
|
||||
|
||||
import pigpio
|
||||
|
||||
GPIOS=32
|
||||
|
||||
MODES=["INPUT", "OUTPUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3"]
|
||||
|
||||
def cleanup():
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
pi.stop()
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
stdscr = curses.initscr()
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
|
||||
atexit.register(cleanup)
|
||||
|
||||
cb = []
|
||||
|
||||
for g in range(GPIOS):
|
||||
cb.append(pi.callback(g, pigpio.EITHER_EDGE))
|
||||
|
||||
# disable gpio 28 as the PCM clock is swamping the system
|
||||
|
||||
cb[28].cancel()
|
||||
|
||||
stdscr.nodelay(1)
|
||||
|
||||
stdscr.addstr(0, 23, "Status of gpios 0-31", curses.A_REVERSE)
|
||||
|
||||
while True:
|
||||
|
||||
for g in range(GPIOS):
|
||||
tally = cb[g].tally()
|
||||
mode = pi.get_mode(g)
|
||||
|
||||
col = (g / 11) * 25
|
||||
row = (g % 11) + 2
|
||||
|
||||
stdscr.addstr(row, col, "{:2}".format(g), curses.A_BOLD)
|
||||
|
||||
stdscr.addstr(
|
||||
"={} {:>6}: {:<10}".format(pi.read(g), MODES[mode], tally))
|
||||
|
||||
stdscr.refresh()
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
c = stdscr.getch()
|
||||
|
||||
if c != curses.ERR:
|
||||
break
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Program to show status changes for a Hall effect sensor.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
HALL=14
|
||||
|
||||
pi = pigpio.pi() # connect to local Pi
|
||||
|
||||
pi.set_mode(HALL, pigpio.INPUT)
|
||||
pi.set_pull_up_down(HALL, pigpio.PUD_UP)
|
||||
|
||||
start = time.time()
|
||||
|
||||
while (time.time() - start) < 60:
|
||||
print("Hall = {}".format(pi.read(HALL)))
|
||||
time.sleep(0.2)
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
class sniffer:
|
||||
"""
|
||||
A class to passively monitor activity on an I2C bus. This should
|
||||
work for an I2C bus running at 100kbps or less. You are unlikely
|
||||
to get any usable results for a bus running any faster.
|
||||
"""
|
||||
|
||||
def __init__(self, pi, SCL, SDA, set_as_inputs=True):
|
||||
"""
|
||||
Instantiate with the Pi and the gpios for the I2C clock
|
||||
and data lines.
|
||||
|
||||
If you are monitoring one of the Raspberry Pi buses you
|
||||
must set set_as_inputs to False so that they remain in
|
||||
I2C mode.
|
||||
|
||||
The pigpio daemon should have been started with a higher
|
||||
than default sample rate.
|
||||
|
||||
For an I2C bus rate of 100Kbps sudo pigpiod -s 2 should work.
|
||||
|
||||
A message is printed for each I2C transaction formatted with
|
||||
"[" for the START
|
||||
"XX" two hex characters for each data byte
|
||||
"+" if the data is ACKd, "-" if the data is NACKd
|
||||
"]" for the STOP
|
||||
|
||||
E.g. Reading the X, Y, Z values from an ADXL345 gives:
|
||||
|
||||
[A6+32+]
|
||||
[A7+01+FF+F2+FF+06+00-]
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gSCL = SCL
|
||||
self.gSDA = SDA
|
||||
|
||||
self.FALLING = 0
|
||||
self.RISING = 1
|
||||
self.STEADY = 2
|
||||
|
||||
self.in_data = False
|
||||
self.byte = 0
|
||||
self.bit = 0
|
||||
self.oldSCL = 1
|
||||
self.oldSDA = 1
|
||||
|
||||
self.transact = ""
|
||||
|
||||
if set_as_inputs:
|
||||
self.pi.set_mode(SCL, pigpio.INPUT)
|
||||
self.pi.set_mode(SDA, pigpio.INPUT)
|
||||
|
||||
self.cbA = self.pi.callback(SCL, pigpio.EITHER_EDGE, self._cb)
|
||||
self.cbB = self.pi.callback(SDA, pigpio.EITHER_EDGE, self._cb)
|
||||
|
||||
def _parse(self, SCL, SDA):
|
||||
"""
|
||||
Accumulate all the data between START and STOP conditions
|
||||
into a string and output when STOP is detected.
|
||||
"""
|
||||
|
||||
if SCL != self.oldSCL:
|
||||
self.oldSCL = SCL
|
||||
if SCL:
|
||||
xSCL = self.RISING
|
||||
else:
|
||||
xSCL = self.FALLING
|
||||
else:
|
||||
xSCL = self.STEADY
|
||||
|
||||
if SDA != self.oldSDA:
|
||||
self.oldSDA = SDA
|
||||
if SDA:
|
||||
xSDA = self.RISING
|
||||
else:
|
||||
xSDA = self.FALLING
|
||||
else:
|
||||
xSDA = self.STEADY
|
||||
|
||||
if xSCL == self.RISING:
|
||||
if self.in_data:
|
||||
if self.bit < 8:
|
||||
self.byte = (self.byte << 1) | SDA
|
||||
self.bit += 1
|
||||
else:
|
||||
self.transact += '{:02X}'.format(self.byte)
|
||||
if SDA:
|
||||
self.transact += '-'
|
||||
else:
|
||||
self.transact += '+'
|
||||
self.bit = 0
|
||||
self.byte = 0
|
||||
|
||||
elif xSCL == self.STEADY:
|
||||
|
||||
if xSDA == self.RISING:
|
||||
if SCL:
|
||||
self.in_data = False
|
||||
self.byte = 0
|
||||
self.bit = 0
|
||||
self.transact += ']' # STOP
|
||||
print (self.transact)
|
||||
self.transact = ""
|
||||
|
||||
if xSDA == self.FALLING:
|
||||
if SCL:
|
||||
self.in_data = True
|
||||
self.byte = 0
|
||||
self.bit = 0
|
||||
self.transact += '[' # START
|
||||
|
||||
def _cb(self, gpio, level, tick):
|
||||
"""
|
||||
Check which line has altered state (ignoring watchdogs) and
|
||||
call the parser with the new state.
|
||||
"""
|
||||
SCL = self.oldSCL
|
||||
SDA = self.oldSDA
|
||||
|
||||
if gpio == self.gSCL:
|
||||
if level == 0:
|
||||
SCL = 0
|
||||
elif level == 1:
|
||||
SCL = 1
|
||||
|
||||
if gpio == self.gSDA:
|
||||
if level == 0:
|
||||
SDA = 0
|
||||
elif level == 1:
|
||||
SDA = 1
|
||||
|
||||
self._parse(SCL, SDA)
|
||||
|
||||
def cancel(self):
|
||||
"""Cancel the I2C callbacks."""
|
||||
self.cbA.cancel()
|
||||
self.cbB.cancel()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import I2C_sniffer
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
s = I2C_sniffer.sniffer(pi, 1, 0, False) # leave gpios 1/0 in I2C mode
|
||||
|
||||
time.sleep(60000)
|
||||
|
||||
s.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
A program to passively sniff I2C transactions (100kHz bus maximum) and display the results.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Class to hash a code from an IR receiver (reading an IR remote control).
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pigpio
|
||||
|
||||
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.
|
||||
|
||||
EXAMPLE CODE
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
import pigpio
|
||||
import ir_hasher
|
||||
|
||||
def callback(hash):
|
||||
print("hash={}".format(hash));
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
ir = ir_hasher.hasher(pi, 7, callback, 5)
|
||||
|
||||
print("ctrl c to exit");
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
pi.stop()
|
||||
"""
|
||||
|
||||
def __init__(self, pi, gpio, callback, timeout=5):
|
||||
|
||||
"""
|
||||
Initialises an IR remote hasher on a pi's gpio. A gap of timeout
|
||||
milliseconds indicates the end of the remote key press.
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gpio = gpio
|
||||
self.code_timeout = timeout
|
||||
self.callback = callback
|
||||
|
||||
self.in_code = False
|
||||
|
||||
pi.set_mode(gpio, pigpio.INPUT)
|
||||
|
||||
self.cb = pi.callback(gpio, pigpio.EITHER_EDGE, self._cb)
|
||||
|
||||
def _hash(self, old_val, new_val):
|
||||
|
||||
if new_val < (old_val * 0.60):
|
||||
val = 13
|
||||
elif old_val < (new_val * 0.60):
|
||||
val = 23
|
||||
else:
|
||||
val = 2
|
||||
|
||||
self.hash_val = self.hash_val ^ val
|
||||
self.hash_val *= 16777619 # FNV_PRIME_32
|
||||
self.hash_val = self.hash_val & ((1<<32)-1)
|
||||
|
||||
def _cb(self, gpio, level, tick):
|
||||
|
||||
if level != pigpio.TIMEOUT:
|
||||
|
||||
if self.in_code == False:
|
||||
|
||||
self.in_code = True
|
||||
|
||||
self.pi.set_watchdog(self.gpio, self.code_timeout)
|
||||
|
||||
self.hash_val = 2166136261 # FNV_BASIS_32
|
||||
|
||||
self.edges = 1
|
||||
|
||||
self.t1 = None
|
||||
self.t2 = None
|
||||
self.t3 = None
|
||||
self.t4 = tick
|
||||
|
||||
else:
|
||||
|
||||
self.edges += 1
|
||||
|
||||
self.t1 = self.t2
|
||||
self.t2 = self.t3
|
||||
self.t3 = self.t4
|
||||
self.t4 = tick
|
||||
|
||||
if self.t1 is not None:
|
||||
|
||||
d1 = pigpio.tickDiff(self.t1,self.t2)
|
||||
d2 = pigpio.tickDiff(self.t3,self.t4)
|
||||
|
||||
self._hash(d1, d2)
|
||||
|
||||
else:
|
||||
|
||||
if self.in_code:
|
||||
|
||||
self.in_code = False
|
||||
|
||||
self.pi.set_watchdog(self.gpio, 0)
|
||||
|
||||
if self.edges > 12:
|
||||
|
||||
self.callback(self.hash_val)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
import pigpio
|
||||
import ir_hasher
|
||||
|
||||
hashes = {
|
||||
142650387: '2', 244341844: 'menu', 262513468: 'vol-',
|
||||
272048826: '5', 345069212: '6', 363685443: 'prev.ch',
|
||||
434191356: '1', 492745084: 'OK', 549497027: 'mute',
|
||||
603729091: 'text', 646476378: 'chan-', 832916949: 'home',
|
||||
923778138: 'power', 938165610: 'power', 953243510: 'forward',
|
||||
1009731980:'1', 1018231875:'TV', 1142888517:'c-up',
|
||||
1151589683:'chan+', 1344018636:'OK', 1348032067:'chan+',
|
||||
1367109971:'prev.ch', 1370712102:'c-left', 1438405361:'rewind',
|
||||
1452589043:'pause', 1518578730:'chan-', 1554432645:'8',
|
||||
1583569525:'0', 1629745313:'rewind', 1666513749:'record',
|
||||
1677653754:'c-down', 1825951717:'c-right', 1852412236:'6',
|
||||
1894279468:'9', 1904895749:'vol+', 1941947509:'ff',
|
||||
2076573637:'0', 2104823531:'back', 2141641957:'home',
|
||||
2160787557:'record', 2398525299:'7', 2468117013:'8',
|
||||
2476712746:'play', 2574308838:'forward', 2577952149:'4',
|
||||
2706654902:'stop', 2829002741:'c-up', 2956097083:'back',
|
||||
3112717386:'5', 3263244773:'ff', 3286088195:'pause',
|
||||
3363767978:'c-down', 3468076364:'vol-', 3491068358:'stop',
|
||||
3593710134:'c-left', 3708232515:'3', 3734134565:'back',
|
||||
3766109107:'TV', 3798010010:'play', 3869937700:'menu',
|
||||
3872715523:'7', 3885097091:'2', 3895301587:'text',
|
||||
3931058739:'mute', 3983900853:'c-right', 4032250885:'4',
|
||||
4041913909:'vol+', 4207017660:'9', 4227138677:'back',
|
||||
4294027955:'3'}
|
||||
|
||||
def callback(hash):
|
||||
if hash in hashes:
|
||||
print("key={} hash={}".format(hashes[hash], hash));
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
ir = ir_hasher.hasher(pi, 7, callback, 5)
|
||||
|
||||
print("ctrl c to exit");
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Script to transmit the morse code corresponding to a text string.
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pigpio
|
||||
|
||||
morse={
|
||||
'a':'.-' , 'b':'-...' , 'c':'-.-.' , 'd':'-..' , 'e':'.' ,
|
||||
'f':'..-.' , 'g':'--.' , 'h':'....' , 'i':'..' , 'j':'.---' ,
|
||||
'k':'-.-' , 'l':'.-..' , 'm':'--' , 'n':'-.' , 'o':'---' ,
|
||||
'p':'.--.' , 'q':'--.-' , 'r':'.-.' , 's':'...' , 't':'-' ,
|
||||
'u':'..-' , 'v':'...-' , 'w':'.--' , 'x':'-..-' , 'y':'-.--' ,
|
||||
'z':'--..' , '1':'.----', '2':'..---', '3':'...--', '4':'....-',
|
||||
'5':'.....', '6':'-....', '7':'--...', '8':'---..', '9':'----.',
|
||||
'0':'-----'}
|
||||
|
||||
GPIO=22
|
||||
|
||||
MICROS=100000
|
||||
|
||||
NONE=0
|
||||
|
||||
DASH=3
|
||||
DOT=1
|
||||
|
||||
GAP=1
|
||||
LETTER_GAP=3-GAP
|
||||
WORD_GAP=7-LETTER_GAP
|
||||
|
||||
def transmit_string(pi, gpio, str):
|
||||
|
||||
pi.wave_clear() # start a new waveform
|
||||
|
||||
wf=[]
|
||||
|
||||
for C in str:
|
||||
c=C.lower()
|
||||
print(c)
|
||||
if c in morse:
|
||||
k = morse[c]
|
||||
for x in k:
|
||||
|
||||
if x == '.':
|
||||
wf.append(pigpio.pulse(1<<gpio, NONE, DOT * MICROS))
|
||||
else:
|
||||
wf.append(pigpio.pulse(1<<gpio, NONE, DASH * MICROS))
|
||||
|
||||
wf.append(pigpio.pulse(NONE, 1<<gpio, GAP * MICROS))
|
||||
|
||||
wf.append(pigpio.pulse(NONE, 1<<gpio, LETTER_GAP * MICROS))
|
||||
|
||||
elif c == ' ':
|
||||
wf.append(pigpio.pulse(NONE, 1<<gpio, WORD_GAP * MICROS))
|
||||
|
||||
pi.wave_add_generic(wf)
|
||||
|
||||
pi.wave_tx_start()
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
pi.set_mode(GPIO, pigpio.OUTPUT)
|
||||
|
||||
transmit_string(pi, GPIO, "Now is the winter of our discontent")
|
||||
|
||||
while pi.wave_tx_busy():
|
||||
pass
|
||||
|
||||
transmit_string(pi, GPIO, "made glorious summer by this sun of York")
|
||||
|
||||
while pi.wave_tx_busy():
|
||||
pass
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# 2014-08-26 PCF8591.py
|
||||
|
||||
import time
|
||||
import curses
|
||||
|
||||
import pigpio
|
||||
|
||||
# sudo pigpiod
|
||||
# ./PCF8591.py
|
||||
|
||||
# Connect Pi 5V - VCC, Ground - Ground, SDA - SDA, SCL - SCL.
|
||||
|
||||
YL_40=0x48
|
||||
|
||||
pi = pigpio.pi() # Connect to local Pi.
|
||||
|
||||
handle = pi.i2c_open(1, YL_40, 0)
|
||||
|
||||
stdscr = curses.initscr()
|
||||
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
|
||||
aout = 0
|
||||
|
||||
stdscr.addstr(10, 0, "Brightness")
|
||||
stdscr.addstr(12, 0, "Temperature")
|
||||
stdscr.addstr(14, 0, "AOUT->AIN2")
|
||||
stdscr.addstr(16, 0, "Resistor")
|
||||
|
||||
stdscr.nodelay(1)
|
||||
|
||||
try:
|
||||
while True:
|
||||
|
||||
for a in range(0,4):
|
||||
aout = aout + 1
|
||||
pi.i2c_write_byte_data(handle, 0x40 | ((a+1) & 0x03), aout&0xFF)
|
||||
v = pi.i2c_read_byte(handle)
|
||||
hashes = v / 4
|
||||
spaces = 64 - hashes
|
||||
stdscr.addstr(10+a*2, 12, str(v) + ' ')
|
||||
stdscr.addstr(10+a*2, 16, '#' * hashes + ' ' * spaces )
|
||||
|
||||
stdscr.refresh()
|
||||
time.sleep(0.04)
|
||||
|
||||
c = stdscr.getch()
|
||||
|
||||
if c != curses.ERR:
|
||||
break
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
curses.nocbreak()
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
pi.i2c_close(handle)
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Script to display readings from the (I2C) PCF8591.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Script to benchmark the pigpio Python module's performance.
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# WARNING!
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Unless you know what you are doing don't run this script with anything #
|
||||
# connected to the gpios. You will CAUSE damage. #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
#
|
||||
# WARNING!
|
||||
#
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
delay = 30
|
||||
|
||||
class gpioTest:
|
||||
|
||||
def __init__(self, pi, gpio, edge, freq, duty):
|
||||
self.pi = pi
|
||||
self.gpio = gpio
|
||||
self.edge = edge
|
||||
self.freq = freq
|
||||
self.duty = duty
|
||||
self.calls = 0
|
||||
|
||||
def cb(self, g, t, l):
|
||||
self.calls = self.calls + 1
|
||||
# print g,t,l
|
||||
|
||||
def num(self):
|
||||
return self.calls
|
||||
|
||||
def start(self):
|
||||
self.pi.set_PWM_frequency(self.gpio, self.freq)
|
||||
self.pi.set_PWM_range(self.gpio, 25)
|
||||
self.pi.set_PWM_dutycycle(self.gpio, self.duty)
|
||||
self.n = self.pi.callback(self.gpio, self.edge, self.cb)
|
||||
|
||||
def stop(self):
|
||||
self.pi.set_PWM_dutycycle(self.gpio, 0)
|
||||
self.n.cancel()
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
t1 = gpioTest(pi, 4, pigpio.EITHER_EDGE, 4000, 1)
|
||||
t2 = gpioTest(pi, 7, pigpio.RISING_EDGE, 8000, 2)
|
||||
t3 = gpioTest(pi, 8, pigpio.FALLING_EDGE, 8000, 3)
|
||||
t4 = gpioTest(pi, 9, pigpio.EITHER_EDGE, 4000, 4)
|
||||
t5 = gpioTest(pi,10, pigpio.RISING_EDGE, 8000, 5)
|
||||
t6 = gpioTest(pi,11, pigpio.FALLING_EDGE, 8000, 6)
|
||||
t7 = gpioTest(pi,14, pigpio.EITHER_EDGE, 4000, 7)
|
||||
t8 = gpioTest(pi,15, pigpio.RISING_EDGE, 8000, 8)
|
||||
t9 = gpioTest(pi,17, pigpio.FALLING_EDGE, 8000, 9)
|
||||
t10 = gpioTest(pi,18, pigpio.EITHER_EDGE, 4000, 10)
|
||||
t11 = gpioTest(pi,22, pigpio.RISING_EDGE, 8000, 11)
|
||||
t12 = gpioTest(pi,23, pigpio.FALLING_EDGE, 8000, 12)
|
||||
t13 = gpioTest(pi,24, pigpio.EITHER_EDGE, 4000, 13)
|
||||
t14 = gpioTest(pi,25, pigpio.RISING_EDGE, 8000, 14)
|
||||
|
||||
# R1: 0 1 4 7 8 9 10 11 14 15 17 18 21 22 23 24 25
|
||||
# R2: 2 3 4 7 8 9 10 11 14 15 17 18 22 23 24 25 27 28 29 30 31
|
||||
|
||||
tests = [t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14]
|
||||
|
||||
for i in tests: i.start()
|
||||
|
||||
time.sleep(delay)
|
||||
|
||||
for i in tests: i.stop()
|
||||
|
||||
pi.stop()
|
||||
|
||||
tot = 0
|
||||
msg = ""
|
||||
|
||||
for i in tests:
|
||||
tot += i.num()
|
||||
msg += str(i.num()) + " "
|
||||
|
||||
print(msg)
|
||||
|
||||
print("eps={} ({}/{})".format(tot/delay, tot, delay))
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Class to decode a mechanical rotary encoder.
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pigpio
|
||||
|
||||
class decoder:
|
||||
|
||||
"""Class to decode mechanical rotary encoder pulses."""
|
||||
|
||||
def __init__(self, pi, gpioA, gpioB, callback):
|
||||
|
||||
"""
|
||||
Instantiate the class with the pi and gpios connected to
|
||||
rotary encoder contacts A and B. The common contact
|
||||
should be connected to ground. The callback is
|
||||
called when the rotary encoder is turned. It takes
|
||||
one parameter which is +1 for clockwise and -1 for
|
||||
counterclockwise.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
import time
|
||||
import pigpio
|
||||
|
||||
import rotary_encoder
|
||||
|
||||
pos = 0
|
||||
|
||||
def callback(way):
|
||||
|
||||
global pos
|
||||
|
||||
pos += way
|
||||
|
||||
print("pos={}".format(pos))
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
decoder = rotary_encoder.decoder(pi, 7, 8, callback)
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
decoder.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gpioA = gpioA
|
||||
self.gpioB = gpioB
|
||||
self.callback = callback
|
||||
|
||||
self.levA = 0
|
||||
self.levB = 0
|
||||
|
||||
self.lastGpio = None
|
||||
|
||||
self.pi.set_mode(gpioA, pigpio.INPUT)
|
||||
self.pi.set_mode(gpioB, pigpio.INPUT)
|
||||
|
||||
self.pi.set_pull_up_down(gpioA, pigpio.PUD_UP)
|
||||
self.pi.set_pull_up_down(gpioB, pigpio.PUD_UP)
|
||||
|
||||
self.cbA = self.pi.callback(gpioA, pigpio.EITHER_EDGE, self._pulse)
|
||||
self.cbB = self.pi.callback(gpioB, pigpio.EITHER_EDGE, self._pulse)
|
||||
|
||||
def _pulse(self, gpio, level, tick):
|
||||
|
||||
"""
|
||||
Decode the rotary encoder pulse.
|
||||
|
||||
+---------+ +---------+ 0
|
||||
| | | |
|
||||
A | | | |
|
||||
| | | |
|
||||
+---------+ +---------+ +----- 1
|
||||
|
||||
+---------+ +---------+ 0
|
||||
| | | |
|
||||
B | | | |
|
||||
| | | |
|
||||
----+ +---------+ +---------+ 1
|
||||
"""
|
||||
|
||||
if gpio == self.gpioA:
|
||||
self.levA = level
|
||||
else:
|
||||
self.levB = level;
|
||||
|
||||
if gpio != self.lastGpio: # debounce
|
||||
self.lastGpio = gpio
|
||||
|
||||
if gpio == self.gpioA and level == 1:
|
||||
if self.levB == 1:
|
||||
self.callback(1)
|
||||
elif gpio == self.gpioB and level == 1:
|
||||
if self.levA == 1:
|
||||
self.callback(-1)
|
||||
|
||||
def cancel(self):
|
||||
|
||||
"""
|
||||
Cancel the rotary encoder decoder.
|
||||
"""
|
||||
|
||||
self.cbA.cancel()
|
||||
self.cbB.cancel()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
import pigpio
|
||||
|
||||
import rotary_encoder
|
||||
|
||||
pos = 0
|
||||
|
||||
def callback(way):
|
||||
|
||||
global pos
|
||||
|
||||
pos += way
|
||||
|
||||
print("pos={}".format(pos))
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
decoder = rotary_encoder.decoder(pi, 7, 8, callback)
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
decoder.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -1 +0,0 @@
|
|||
pigpio Python examples
|
|
@ -0,0 +1,2 @@
|
|||
Class to read sonar rangers with separate trigger and echo pins.
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
class ranger:
|
||||
"""
|
||||
This class encapsulates a type of acoustic ranger. In particular
|
||||
the type of ranger with separate trigger and echo pins.
|
||||
|
||||
A pulse on the trigger initiates the sonar ping and shortly
|
||||
afterwards a sonar pulse is transmitted and the echo pin
|
||||
goes high. The echo pins stays high until a sonar echo is
|
||||
received (or the response times-out). The time between
|
||||
the high and low edges indicates the sonar round trip time.
|
||||
"""
|
||||
|
||||
def __init__(self, pi, trigger, echo):
|
||||
"""
|
||||
The class is instantiated with the Pi to use and the
|
||||
gpios connected to the trigger and echo pins.
|
||||
"""
|
||||
self.pi = pi
|
||||
self._trig = trigger
|
||||
self._echo = echo
|
||||
|
||||
self._ping = False
|
||||
self._high = None
|
||||
self._time = None
|
||||
|
||||
self._triggered = False
|
||||
|
||||
self._trig_mode = pi.get_mode(self._trig)
|
||||
self._echo_mode = pi.get_mode(self._echo)
|
||||
|
||||
pi.set_mode(self._trig, pigpio.OUTPUT)
|
||||
pi.set_mode(self._echo, pigpio.INPUT)
|
||||
|
||||
self._cb = pi.callback(self._trig, pigpio.EITHER_EDGE, self._cbf)
|
||||
self._cb = pi.callback(self._echo, pigpio.EITHER_EDGE, self._cbf)
|
||||
|
||||
self._inited = True
|
||||
|
||||
def _cbf(self, gpio, level, tick):
|
||||
if gpio == self._trig:
|
||||
if level == 0: # trigger sent
|
||||
self._triggered = True
|
||||
self._high = None
|
||||
else:
|
||||
if self._triggered:
|
||||
if level == 1:
|
||||
self._high = tick
|
||||
else:
|
||||
if self._high is not None:
|
||||
self._time = tick - self._high
|
||||
self._high = None
|
||||
self._ping = True
|
||||
|
||||
def read(self):
|
||||
"""
|
||||
Triggers a reading. The returned reading is the number
|
||||
of microseconds for the sonar round-trip.
|
||||
|
||||
round trip cms = round trip time / 1000000.0 * 34030
|
||||
"""
|
||||
if self._inited:
|
||||
self._ping = False
|
||||
self.pi.gpio_trigger(self._trig)
|
||||
start = time.time()
|
||||
while not self._ping:
|
||||
if (time.time()-start) > 5.0:
|
||||
return 20000
|
||||
time.sleep(0.001)
|
||||
return self._time
|
||||
else:
|
||||
return None
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Cancels the ranger and returns the gpios to their
|
||||
original mode.
|
||||
"""
|
||||
if self._inited:
|
||||
self._inited = False
|
||||
self._cb.cancel()
|
||||
self.pi.set_mode(self._trig, self._trig_mode)
|
||||
self.pi.set_mode(self._echo, self._echo_mode)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import sonar_trigger_echo
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
sonar = sonar_trigger_echo.ranger(pi, 23, 18)
|
||||
|
||||
end = time.time() + 600.0
|
||||
|
||||
r = 1
|
||||
while time.time() < end:
|
||||
|
||||
print("{} {}".format(r, sonar.read()))
|
||||
r += 1
|
||||
time.sleep(0.03)
|
||||
|
||||
sonar.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Class to send and receive radio messages compatible with the Virtual Wire library for Arduinos.
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
This module provides a 313MHz/434MHz radio interface compatible
|
||||
with the Virtual Wire library used on Arduinos.
|
||||
|
||||
It has been tested between a Pi, TI Launchpad, and Arduino Pro Mini.
|
||||
"""
|
||||
# 2014-08-14
|
||||
# vw.py
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
MAX_MESSAGE_BYTES=77
|
||||
|
||||
MIN_BPS=50
|
||||
MAX_BPS=10000
|
||||
|
||||
_HEADER=[0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x38, 0x2c]
|
||||
|
||||
_CTL=3
|
||||
|
||||
_SYMBOL=[
|
||||
0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
|
||||
0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x32, 0x34]
|
||||
|
||||
|
||||
def _sym2nibble(symbol):
|
||||
for nibble in range(16):
|
||||
if symbol == _SYMBOL[nibble]:
|
||||
return nibble
|
||||
return 0
|
||||
|
||||
def _crc_ccitt_update(crc, data):
|
||||
|
||||
data = data ^ (crc & 0xFF);
|
||||
|
||||
data = (data ^ (data << 4)) & 0xFF;
|
||||
|
||||
return (
|
||||
(((data << 8) & 0xFFFF) | (crc >> 8)) ^
|
||||
((data >> 4) & 0x00FF) ^ ((data << 3) & 0xFFFF)
|
||||
)
|
||||
|
||||
class tx():
|
||||
|
||||
def __init__(self, pi, txgpio, bps=2000):
|
||||
"""
|
||||
Instantiate a transmitter with the Pi, the transmit gpio,
|
||||
and the bits per second (bps). The bps defaults to 2000.
|
||||
The bps is constrained to be within MIN_BPS to MAX_BPS.
|
||||
"""
|
||||
self.pi = pi
|
||||
|
||||
self.txbit = (1<<txgpio)
|
||||
|
||||
if bps < MIN_BPS:
|
||||
bps = MIN_BPS
|
||||
elif bps > MAX_BPS:
|
||||
bps = MAX_BPS
|
||||
|
||||
self.mics = int(1000000 / bps)
|
||||
|
||||
self.wave_id = None
|
||||
|
||||
pi.wave_add_new()
|
||||
|
||||
pi.set_mode(txgpio, pigpio.OUTPUT)
|
||||
|
||||
|
||||
def _nibble(self, nibble):
|
||||
|
||||
for i in range(6):
|
||||
if nibble & (1<<i):
|
||||
self.wf.append(pigpio.pulse(self.txbit, 0, self.mics))
|
||||
else:
|
||||
self.wf.append(pigpio.pulse(0, self.txbit, self.mics))
|
||||
|
||||
def _byte(self, crc, byte):
|
||||
self._nibble(_SYMBOL[byte>>4])
|
||||
self._nibble(_SYMBOL[byte&0x0F])
|
||||
return _crc_ccitt_update(crc, byte)
|
||||
|
||||
def put(self, data):
|
||||
"""
|
||||
Transmit a message. If the message is more than
|
||||
MAX_MESSAGE_BYTES in size it is discarded. If a message
|
||||
is currently being transmitted it is aborted and replaced
|
||||
with the new message. True is returned if message
|
||||
transmission has successfully started. False indicates
|
||||
an error.
|
||||
"""
|
||||
if len(data) > MAX_MESSAGE_BYTES:
|
||||
return False
|
||||
|
||||
self.wf = []
|
||||
|
||||
self.cancel()
|
||||
|
||||
for i in _HEADER:
|
||||
self._nibble(i)
|
||||
|
||||
crc = self._byte(0xFFFF, len(data)+_CTL)
|
||||
|
||||
for i in data:
|
||||
|
||||
if type(i) == type(""):
|
||||
v = ord(i)
|
||||
else:
|
||||
v = i
|
||||
|
||||
crc = self._byte(crc, v)
|
||||
|
||||
crc = ~crc
|
||||
|
||||
self._byte(0, crc&0xFF)
|
||||
self._byte(0, crc>>8)
|
||||
|
||||
self.pi.wave_add_generic(self.wf)
|
||||
|
||||
self.wave_id = self.pi.wave_create()
|
||||
|
||||
if self.wave_id >= 0:
|
||||
self.pi.wave_send_once(self.wave_id)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def ready(self):
|
||||
"""
|
||||
Returns True if a new message may be transmitted.
|
||||
"""
|
||||
return not self.pi.wave_tx_busy()
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Cancels the wireless transmitter, aborting any message
|
||||
in progress.
|
||||
"""
|
||||
if self.wave_id is not None:
|
||||
self.pi.wave_tx_stop()
|
||||
self.pi.wave_delete(self.wave_id)
|
||||
self.pi.wave_add_new()
|
||||
|
||||
self.wave_id = None
|
||||
|
||||
class rx():
|
||||
|
||||
def __init__(self, pi, rxgpio, bps=2000):
|
||||
"""
|
||||
Instantiate a receiver with the Pi, the receive gpio, and
|
||||
the bits per second (bps). The bps defaults to 2000.
|
||||
The bps is constrained to be within MIN_BPS to MAX_BPS.
|
||||
"""
|
||||
self.pi = pi
|
||||
self.rxgpio = rxgpio
|
||||
|
||||
self.messages = []
|
||||
self.bad_CRC = 0
|
||||
|
||||
if bps < MIN_BPS:
|
||||
bps = MIN_BPS
|
||||
elif bps > MAX_BPS:
|
||||
bps = MAX_BPS
|
||||
|
||||
slack = 0.20
|
||||
self.mics = int(1000000 / bps)
|
||||
slack_mics = int(slack * self.mics)
|
||||
self.min_mics = self.mics - slack_mics # Shortest legal edge.
|
||||
self.max_mics = (self.mics + slack_mics) * 4 # Longest legal edge.
|
||||
|
||||
self.timeout = 8 * self.mics / 1000 # 8 bits time in ms.
|
||||
if self.timeout < 8:
|
||||
self.timeout = 8
|
||||
|
||||
self.last_tick = None
|
||||
self.good = 0
|
||||
self.bits = 0
|
||||
self.token = 0
|
||||
self.in_message = False
|
||||
self.message = [0]*(MAX_MESSAGE_BYTES+_CTL)
|
||||
self.message_len = 0
|
||||
self.byte = 0
|
||||
|
||||
pi.set_mode(rxgpio, pigpio.INPUT)
|
||||
|
||||
self.cb = pi.callback(rxgpio, pigpio.EITHER_EDGE, self._cb)
|
||||
|
||||
def _calc_crc(self):
|
||||
|
||||
crc = 0xFFFF
|
||||
for i in range(self.message_length):
|
||||
crc = _crc_ccitt_update(crc, self.message[i])
|
||||
return crc
|
||||
|
||||
def _insert(self, bits, level):
|
||||
|
||||
for i in range(bits):
|
||||
|
||||
self.token >>= 1
|
||||
|
||||
if level == 0:
|
||||
self.token |= 0x800
|
||||
|
||||
if self.in_message:
|
||||
|
||||
self.bits += 1
|
||||
|
||||
if self.bits >= 12: # Complete token.
|
||||
|
||||
byte = (
|
||||
_sym2nibble(self.token & 0x3f) << 4 |
|
||||
_sym2nibble(self.token >> 6))
|
||||
|
||||
if self.byte == 0:
|
||||
self.message_length = byte
|
||||
|
||||
if byte > (MAX_MESSAGE_BYTES+_CTL):
|
||||
self.in_message = False # Abort message.
|
||||
return
|
||||
|
||||
self.message[self.byte] = byte
|
||||
|
||||
self.byte += 1
|
||||
self.bits = 0
|
||||
|
||||
if self.byte >= self.message_length:
|
||||
self.in_message = False
|
||||
self.pi.set_watchdog(self.rxgpio, 0)
|
||||
|
||||
crc = self._calc_crc()
|
||||
|
||||
if crc == 0xF0B8: # Valid CRC.
|
||||
self.messages.append(
|
||||
self.message[1:self.message_length-2])
|
||||
else:
|
||||
self.bad_CRC += 1
|
||||
|
||||
else:
|
||||
if self.token == 0xB38: # Start message token.
|
||||
self.in_message = True
|
||||
self.pi.set_watchdog(self.rxgpio, self.timeout)
|
||||
self.bits = 0
|
||||
self.byte = 0
|
||||
|
||||
def _cb(self, gpio, level, tick):
|
||||
|
||||
if self.last_tick is not None:
|
||||
|
||||
if level == pigpio.TIMEOUT:
|
||||
|
||||
self.pi.set_watchdog(self.rxgpio, 0) # Switch watchdog off.
|
||||
|
||||
if self.in_message:
|
||||
self._insert(4, not self.last_level)
|
||||
|
||||
self.good = 0
|
||||
self.in_message = False
|
||||
|
||||
else:
|
||||
|
||||
edge = pigpio.tickDiff(self.last_tick, tick)
|
||||
|
||||
if edge < self.min_mics:
|
||||
|
||||
self.good = 0
|
||||
self.in_message = False
|
||||
|
||||
elif edge > self.max_mics:
|
||||
|
||||
if self.in_message:
|
||||
self._insert(4, level)
|
||||
|
||||
self.good = 0
|
||||
self.in_message = False
|
||||
|
||||
else:
|
||||
|
||||
self.good += 1
|
||||
|
||||
if self.good > 8:
|
||||
|
||||
bitlen = (100 * edge) / self.mics
|
||||
|
||||
if bitlen < 140:
|
||||
bits = 1
|
||||
elif bitlen < 240:
|
||||
bits = 2
|
||||
elif bitlen < 340:
|
||||
bits = 3
|
||||
else:
|
||||
bits = 4
|
||||
|
||||
self._insert(bits, level)
|
||||
|
||||
self.last_tick = tick
|
||||
self.last_level = level
|
||||
|
||||
def get(self):
|
||||
"""
|
||||
Returns the next unread message, or None if none is avaiable.
|
||||
"""
|
||||
if len(self.messages):
|
||||
return self.messages.pop(0)
|
||||
else:
|
||||
return None
|
||||
|
||||
def ready(self):
|
||||
"""
|
||||
Returns True if there is a message available to be read.
|
||||
"""
|
||||
return len(self.messages)
|
||||
|
||||
def cancel(self):
|
||||
"""
|
||||
Cancels the wireless receiver.
|
||||
"""
|
||||
if self.cb is not None:
|
||||
self.cb.cancel()
|
||||
self.pi.set_watchdog(self.rxgpio, 0)
|
||||
self.cb = None
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import vw
|
||||
|
||||
RX=11
|
||||
TX=25
|
||||
|
||||
BPS=2000
|
||||
|
||||
pi = pigpio.pi() # Connect to local Pi.
|
||||
|
||||
rx = vw.rx(pi, RX, BPS) # Specify Pi, rx gpio, and baud.
|
||||
tx = vw.tx(pi, TX, BPS) # Specify Pi, tx gpio, and baud.
|
||||
|
||||
msg = 0
|
||||
|
||||
start = time.time()
|
||||
|
||||
while (time.time()-start) < 300:
|
||||
|
||||
msg += 1
|
||||
|
||||
while not tx.ready():
|
||||
time.sleep(0.1)
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
tx.put([48, 49, 65, ((msg>>6)&0x3F)+32, (msg&0x3F)+32])
|
||||
|
||||
while not tx.ready():
|
||||
time.sleep(0.1)
|
||||
|
||||
time.sleep(0.2)
|
||||
|
||||
tx.put("Hello World #{}!".format(msg))
|
||||
|
||||
while rx.ready():
|
||||
print("".join(chr (c) for c in rx.get()))
|
||||
|
||||
rx.cancel()
|
||||
tx.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Class to decode a Wiegand code.
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import pigpio
|
||||
|
||||
class decoder:
|
||||
|
||||
"""
|
||||
A class to read Wiegand codes of an arbitrary length.
|
||||
|
||||
The code length and value are returned.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
#!/usr/bin/env python
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import wiegand
|
||||
|
||||
def callback(bits, code):
|
||||
print("bits={} code={}".format(bits, code))
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
w = wiegand.decoder(pi, 14, 15, callback)
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
w.cancel()
|
||||
|
||||
pi.stop()
|
||||
"""
|
||||
|
||||
def __init__(self, pi, gpio_0, gpio_1, callback, bit_timeout=5):
|
||||
|
||||
"""
|
||||
Instantiate with the pi, 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.
|
||||
"""
|
||||
|
||||
self.pi = pi
|
||||
self.gpio_0 = gpio_0
|
||||
self.gpio_1 = gpio_1
|
||||
|
||||
self.callback = callback
|
||||
|
||||
self.bit_timeout = bit_timeout
|
||||
|
||||
self.in_code = False
|
||||
|
||||
self.pi.set_mode(gpio_0, pigpio.INPUT)
|
||||
self.pi.set_mode(gpio_1, pigpio.INPUT)
|
||||
|
||||
self.pi.set_pull_up_down(gpio_0, pigpio.PUD_UP)
|
||||
self.pi.set_pull_up_down(gpio_1, pigpio.PUD_UP)
|
||||
|
||||
self.cb_0 = self.pi.callback(gpio_0, pigpio.FALLING_EDGE, self._cb)
|
||||
self.cb_1 = self.pi.callback(gpio_1, pigpio.FALLING_EDGE, self._cb)
|
||||
|
||||
def _cb(self, gpio, level, tick):
|
||||
|
||||
"""
|
||||
Accumulate bits until both gpios 0 and 1 timeout.
|
||||
"""
|
||||
|
||||
if level < pigpio.TIMEOUT:
|
||||
|
||||
if self.in_code == False:
|
||||
self.bits = 1
|
||||
self.num = 0
|
||||
|
||||
self.in_code = True
|
||||
self.code_timeout = 0
|
||||
self.pi.set_watchdog(self.gpio_0, self.bit_timeout)
|
||||
self.pi.set_watchdog(self.gpio_1, self.bit_timeout)
|
||||
else:
|
||||
self.bits += 1
|
||||
self.num = self.num << 1
|
||||
|
||||
if gpio == self.gpio_0:
|
||||
self.code_timeout = self.code_timeout & 2 # clear gpio 0 timeout
|
||||
else:
|
||||
self.code_timeout = self.code_timeout & 1 # clear gpio 1 timeout
|
||||
self.num = self.num | 1
|
||||
|
||||
else:
|
||||
|
||||
if self.in_code:
|
||||
|
||||
if gpio == self.gpio_0:
|
||||
self.code_timeout = self.code_timeout | 1 # timeout gpio 0
|
||||
else:
|
||||
self.code_timeout = self.code_timeout | 2 # timeout gpio 1
|
||||
|
||||
if self.code_timeout == 3: # both gpios timed out
|
||||
self.pi.set_watchdog(self.gpio_0, 0)
|
||||
self.pi.set_watchdog(self.gpio_1, 0)
|
||||
self.in_code = False
|
||||
self.callback(self.bits, self.num)
|
||||
|
||||
def cancel(self):
|
||||
|
||||
"""
|
||||
Cancel the Wiegand decoder.
|
||||
"""
|
||||
|
||||
self.cb_0.cancel()
|
||||
self.cb_1.cancel()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
import time
|
||||
|
||||
import pigpio
|
||||
|
||||
import wiegand
|
||||
|
||||
def callback(bits, value):
|
||||
print("bits={} value={}".format(bits, value))
|
||||
|
||||
pi = pigpio.pi()
|
||||
|
||||
w = wiegand.decoder(pi, 14, 15, callback)
|
||||
|
||||
time.sleep(300)
|
||||
|
||||
w.cancel()
|
||||
|
||||
pi.stop()
|
||||
|
Loading…
Reference in New Issue