From aef9733f2e5780fd0291f3eece87edff837640c7 Mon Sep 17 00:00:00 2001 From: Stefan Seegel Date: Mon, 27 Jan 2020 02:11:10 +0100 Subject: [PATCH] refactoring, cleanup, testing --- apps/connair.py | 13 +- apps/fs20.py | 178 +++++++++++++++ apps/rcpulse.py | 137 ++++++++++-- connair.py | 72 ------ fs20tx.py | 26 +-- maxrx.py | 1 + raspyrfm/rfm69.py | 2 +- rfm69.py | 559 ---------------------------------------------- 8 files changed, 321 insertions(+), 667 deletions(-) create mode 100644 apps/fs20.py delete mode 100755 connair.py delete mode 100644 rfm69.py diff --git a/apps/connair.py b/apps/connair.py index 67e70c7..e6bdbc6 100755 --- a/apps/connair.py +++ b/apps/connair.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2.7 import socket -import RaspyRFM +from raspyrfm import * import sys UDP_IP = "0.0.0.0" @@ -12,10 +12,10 @@ sock = socket.socket(socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP sock.bind((UDP_IP, UDP_PORT)) -rfm = RaspyRFM.RaspyRFM() -rfm.SetParams( +rfm = RaspyRFM(1, RFM69) +rfm.set_params( Freq = 433.92, - TXPower = 13, + TxPower = 13, ModulationType = rfm69.OOK, SyncPattern = [], ) @@ -24,7 +24,6 @@ print("Listening...") while True: data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes print("received message from " + addr[0] + ': ' + str(data)) - print(sock) msg = str(data).split(":") if msg[0] == "SEARCH HCGW": @@ -59,5 +58,5 @@ while True: for i in range(bitleft): bindata[len(bindata) - 1] <<= 1 - rfm.SetParams(Datarate = 1000.0 / steplen) - rfm.SendPacket(bindata * rep) + rfm.set_params(Datarate = 1000.0 / steplen) + rfm.send_packet(bindata * rep) diff --git a/apps/fs20.py b/apps/fs20.py new file mode 100644 index 0000000..cea4453 --- /dev/null +++ b/apps/fs20.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python2.7 + +import re + +PROTOCOL = "FS20" + +def __parse_byte(bits): + i = int(bits, 2) + cnt = 0 + tmp = i + while tmp > 0: + cnt += 1 + tmp &= tmp - 1 + if (cnt & 1) == 0: + return i>>1 + else: + return -1 + +def Decode(pulses): + if len(pulses) != 118: + print(len(pulses), pulses) + return + + sym = "" + s = 0 + for p in pulses: + if (p >= 300) and (p <= 500): + sym += 's' + s += p + elif (p > 500) and (p <= 750): + sym += 'l' + s += p + else: + sym += '?' + + bits = "" + for i in range(59): + if sym[:2] == 'ss': + bits += "0" + elif sym[:2] == "ll": + bits += "1" + else: + bits +="?" + sym = sym[2:] + + print(bits) + #check for sync sequence + if bits[:13] != "0000000000001": + return + bits = bits[13:] #strip off sync sequence + + by = [] + while len(bits) >= 9: + by.append(__parse_byte(bits[:9])) + bits = bits[9:] + + #check checksum + cs = 6 + for i in range(len(by) - 1): + cs += by[i] + cs = by[-1:][0] - (cs & 0xff) + if (cs > 2) or (cs < 0): + return + + ret = { + "protocol": PROTOCOL, + "housecode": "{:04X}".format((by[0] << 8) | by[1]), + "address": "{:02X}".format(by[2]), + "command": "{:02X}".format(by[3]) if len(by) == 5 else "{:04X}".format(by[3] << 8 | by[4]) + } + print(ret) + + return + return ("fs20", bits, int(round(100 / (12.0 * 8 + 1)))) + +def Encode(args): + da = [] + bp = [0] + bv = [0] + def add_pulse(val, length): + for i in range(length): + bp[0] += 1 + bv[0] <<= 1 + bv[0] |= val + if bp[0] == 8: + da.append(bv[0]) + bv[0] = 0 + bp[0] = 0 + + def add_bit(b): + if b == 0: + add_pulse(1, 2) + add_pulse(0, 2) + else: + add_pulse(1, 3) + add_pulse(0, 3) + + def add_byte(by): + par = 0 + mask = 0x80 + while (mask): + add_bit(by & mask) + par >>= 1 + par ^= (by & mask) + mask >>= 1 + add_bit(par) + + #add sync pattern + for i in range(12): + add_bit(0) + add_bit(1) + + hc = int(args[0], 16) + adr = int(args[1], 16) + cmd = int(args[2], 16) + #calculate checksum + q = (6 + (hc >> 8) + (hc & 0xFF) + adr + (cmd >> 8) + (cmd & 0xFF)) & 0xff + #add housecode + add_byte(hc >> 8) + add_byte(hc & 0xFF) + #add address + add_byte(adr) + #add command + add_byte(cmd) + #add checksum + add_byte(q) + #add EOT + add_bit(0) + add_pulse(0, 33) + if bp[0] > 0: + add_pulse(0, 8-bp[0]) + return (da, 3, 200) + + code = ' '.join(args) + if re.match("^[01Ff]{12}$", code): + data = [] + for c in code: + if c == '0': + data.append(0x88) + elif c == '1': + data.append(0xEE) + elif c in ['F', 'f']: + data.append(0x8E) + data += [0x80, 0x00, 0x00, 0x00] #sync + + return (data, 5, 360) + + elif re.match('^[A-P] [1-4] [1-4] (on|off)$', code): + g = re.match('^([A-P]) ([1-4]) ([1-4]) (on|off)$', code).groups() + tristate = "" + tristate += encodeBits(ord(g[0]) - ord('A'), 4) #housecode + tristate += encodeBits(ord(g[2]) - 1, 2) #channel + tristate += encodeBits(ord(g[1]) - 1, 2) #group + tristate += "0F" + tristate += 'FF' if g[3] == 'on' else 'F0' + return Encode([tristate]) + + elif re.match('^([01]{5}) ([1-4]) (on|off)$', code): #Brennenstuhl + g = re.match('^([01]{5}) ([1-4]) (on|off)$', code).groups() + tristate = "" + for c in g[0]: + tristate += '0' if c == '1' else 'F' + for i in range(4): + tristate += '0' if int(g[1]) - 1 == i else 'F' + tristate += 'F' + tristate += '0F' if g[2] == 'on' else 'F0' + return Encode([tristate]) + + elif re.match('^[1-4] [1-4] (on|off)$', code): + g = re.match('^([1-4]) ([1-4]) (on|off)$', code).groups() + tristate = "" + for i in range(4): + tristate += "0" if int(g[0]) - 1 == i else "F" + for i in range(4): + tristate += "0" if int(g[1]) - 1 == i else "F" + tristate += "FFF" + tristate += 'F' if g[2] == 'on' else '0' + return Encode([tristate]) \ No newline at end of file diff --git a/apps/rcpulse.py b/apps/rcpulse.py index e051fe0..23a1223 100755 --- a/apps/rcpulse.py +++ b/apps/rcpulse.py @@ -1,16 +1,21 @@ #!/usr/bin/env python2.7 -import RaspyRFM +from raspyrfm import * import sys import time import it32 import tristate import bistate24 +import fs20 from argparse import ArgumentParser +import wave, struct parser = ArgumentParser() parser.add_argument("-t", "--timebase", type=int, help=u"timebase in \u03bcs") parser.add_argument("-r", "--repeats", type=int, help=u"number of repetitions") +parser.add_argument("-m", "--module", type=int, metavar="1-4", help=u"RaspyRFM module 1-4", default=1) +parser.add_argument("-f", "--frequency", type=float, help=u"frequency in MHz", default=433.92) +parser.add_argument("-w", "--write", help=u"write wavefile") parser.add_argument("code", nargs='*', help="code, e. g. '000000000FFF', 'A 1 2 on' or '10111100011101011111111110001110'") args = parser.parse_args() @@ -18,6 +23,7 @@ protos = [ it32, tristate, bistate24, + fs20, ] txdata = None @@ -28,51 +34,154 @@ if len(args.code) > 0: if data: txdata = data break - + if txdata is None: print("invalid code!") exit() -rfm = RaspyRFM.RaspyRFM() -rfm.SetParams( - Freq = 433.92, #MHz +rfm = RaspyRFM(args.module, RFM69) +rfm.set_params( + Freq = args.frequency, #MHz Datarate = 20.0, #kbit/s Bandwidth = 200, #kHz SyncPattern = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F], RssiThresh = -105, #dBm - ModulationType = RaspyRFM.OOK, + ModulationType = rfm69.OOK, OokThreshType = 1, #peak thresh OokPeakThreshDec = 3, + Preamble = 0, + TxPower = 13 ) +wf = wave.open("out.wav", "wb") +def rxcb(): + while True: + d = rfm.read_fifo_wait(64) + ba = bytearray() + for s in d: + mask = 0x80 + while mask > 0: + if (s & mask) > 0: + ba.append(255) + else: + ba.append(0) + mask >>= 1 + wf.writeframesraw(ba) + +if args.write: + wf.setnchannels(1) + wf.setsampwidth(1) + wf.setframerate(20000) + + rfm.set_params( + SyncPattern = [], + OokThreshType = 0, #fix thresh + OokFixedThresh = 85, + ) + rfm.start_rx(rxcb) + + wf.writeframes('') + wf.close() + print("WRITE!") + exit() + +rfm.set_params( + SyncPattern = [], + Datarate = 1.63, +) +i=[ + "01010011110011111110000111111111", + "01011101110011111110000111111111", + "01100011110011111110000111111111", + "01101101110011111110000111111111", +] +do=[] +b=0 +db=0 +def addpulse(h, l): + global do, b, db + for i in range(h): + db <<= 1 + db |= 1 + b += 1 + + if b == 8: + do.append(db) + db = 0 + b = 0 + + for i in range(l): + db <<= 1 + b += 1 + + if b == 8: + do.append(db) + db = 0 + b = 0 + +for c in i[args.timebase]: + if c == '0': + addpulse(2, 1) + else: + addpulse(1, 2) +addpulse(1, 17) +#print(do, b) +rfm.send_packet(do * 3) +exit() + +rfm.set_params( + Datarate = 20.0, #kbit/s + SyncPattern = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F], +) + if txdata: - rfm.SetParams( + rfm.set_params( SyncPattern = [], Datarate = 1000.0 / (args.timebase if args.timebase else txdata[2]) ) rep = (args.repeats if args.repeats else txdata[1]) - rfm.SendPacket(txdata[0] * rep) + rfm.send_packet(txdata[0] * rep) print("Code sent!") exit() - + def Decode(pulses): for i in range(len(pulses)): pulses[i] *= 50 - + dec = None for proto in protos: dec = proto.Decode(pulses) if dec: print(dec) - if not dec: - print("Len " + str(len(pulses)) + ": " + str(pulses)) + s = "" + if len(pulses) == 66: + for p in pulses: + if (p>900): + s += "l" + else: + s += "s" + b = "" + while len(s) > 0: + if s[:2] == "sl": + b += "1" + elif s[:2] == "ls": + b += "0" + else: + b += "?" + s = s[2:] + #print(b) + + #print(len(pulses), pulses) + + #if not dec: + # print("Len " + str(len(pulses)) + ": " + str(pulses)) while True: - data = rfm.ReceivePacket(260) + data = rfm.receive_packet(260) s = "" - pulsecount = 7 + pulsecount = 4 glitchcount = 0 bit = True pulses = [] diff --git a/connair.py b/connair.py deleted file mode 100755 index fe53a24..0000000 --- a/connair.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python2.7 - -import socket -import rfm69 -import sys - -UDP_IP = "0.0.0.0" -UDP_PORT = 49880 -HELLO_MESSAGE = "HCGW:VC:Seegel Systeme;MC:RaspyRFM;FW:1.00;IP:192.168.2.124;;" - -sock = socket.socket(socket.AF_INET, # Internet - socket.SOCK_DGRAM) # UDP -sock.bind((UDP_IP, UDP_PORT)) - -#sock.sendto("TXP:0,0,10,20000,350,25,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,1,3,1,3,3,1,1,17;", ("192.168.178.51", 49880)) -#sys.exit(0) - -rfm = rfm69.Rfm69() -rfm.SetParams( - Freq = 433.92, - TXPower = 13, - ModulationType = rfm69.OOK, - SyncPattern = [], - RssiThresh = -72 - ) - -while True: - data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes - #data = "TXP:0,0,6,5950,350,25,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,3,1,1,3,1,3,1,3,3,1,1,17;" - #addr = ("123", 5) - print "received message:", data, "from ", addr - - msg = str(data).split(":") - - if msg[0] == "SEARCH HCGW": - sock.sendto(HELLO_MESSAGE, addr) - print "Hello message" - - if msg[0] == "TXP": - msg[1] = msg[1].replace(";", "") - cmd = msg[1].split(",") - rep = int(cmd[2]) - pauselen = int(cmd[3]) - steplen = int(cmd[4]) - numpulse = int(cmd[5]) - pulsedata = cmd[6:] - pulsedata[numpulse * 2 - 1] = int(pulsedata[numpulse * 2 - 1]) + pauselen / steplen - - bindata = [] - bit = True - numbit = 0 - bitleft = 0 - for i in range(numpulse * 2): - for bits in range(int(pulsedata[i])): - if bitleft == 0: - bitleft = 8 - bindata.append(0x00) - - bindata[len(bindata) - 1] <<= 1 - if bit: - bindata[len(bindata) - 1] |= 0x01 - bitleft -= 1 - bit = not bit - for i in range(bitleft): - bindata[len(bindata) - 1] <<= 1 - print "bitleft: ", bitleft - - print "reps: ", rep - print "Pulse data", pulsedata - print "bin:", bindata - rfm.SetParams(Datarate = 1000.0 / steplen) - rfm.SendPacket(bindata * rep) diff --git a/fs20tx.py b/fs20tx.py index 3cfe710..884deda 100755 --- a/fs20tx.py +++ b/fs20tx.py @@ -1,23 +1,20 @@ #!/usr/bin/env python2.7 -from rfm69 import Rfm69 -import rfm69 -import sensors +from raspyrfm import * import sys import time -if Rfm69.Test(1): - rfm = Rfm69(1, 24) #when using the RaspyRFM twin -elif Rfm69.Test(0): - rfm = Rfm69() #when using a single single 868 MHz RaspyRFM -else: - print "No RFM69 module found!" - exit() +rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin +#elif Rfm69.Test(0): +# rfm = Rfm69() #when using a single single 868 MHz RaspyRFM +#else: +# print "No RFM69 module found!" +# exit() -rfm.SetParams( +rfm.set_params( Freq = 868.350, Datarate = 5.0, - TXPower = -10, + TxPower = -10, ModulationType = rfm69.OOK, SyncPattern = [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x38], Preamble = 0 @@ -27,7 +24,7 @@ data = [] bitcnt = 0 def AddBit(bit): - global data + global data global bitcnt if bit: if ((len(data) * 8) - bitcnt) < 6: @@ -81,5 +78,6 @@ def MakeFS20Frame(hc, adr, cmd): data = [] bitcnt = 0 MakeFS20Frame(int(sys.argv[1], 0), int(sys.argv[2], 0), int(sys.argv[3], 0)) +print(data) for x in range(3): - rfm.SendPacket(data) + rfm.send_packet(data) diff --git a/maxrx.py b/maxrx.py index 507f9a3..8139de1 100755 --- a/maxrx.py +++ b/maxrx.py @@ -65,6 +65,7 @@ rxThread.daemon = True rxThread.start() def Decode(frame): + print(frame) #decode MAX! frame cnt = frame[1] flag = hex(frame[2]) diff --git a/raspyrfm/rfm69.py b/raspyrfm/rfm69.py index 5cbf62b..dca47ac 100644 --- a/raspyrfm/rfm69.py +++ b/raspyrfm/rfm69.py @@ -402,7 +402,7 @@ class Rfm69(threading.Thread): self.__set_reg(RegOokPeak, 3<<6, value<<6) elif key == "OokFixedThresh": - self.___write_reg(RegOokFix, value) + self.__write_reg(RegOokFix, value) elif key == "OokPeakThreshDec": self.__set_reg(RegOokPeak, 7<<0, value) diff --git a/rfm69.py b/rfm69.py deleted file mode 100644 index 9b74880..0000000 --- a/rfm69.py +++ /dev/null @@ -1,559 +0,0 @@ -import RPi.GPIO as GPIO -import spidev -import threading -import time - -FXOSC = 32E6 -FSTEP = FXOSC / (1<<19) - -#------ Raspberry RFM Module connection ----- -# RaspyRFM single module -# Connect to pins 17-26 on raspberry pi -#-------------------------------------------------# -# Raspi | Raspi | Raspi | RFM69 | RFM12 | PCB con # -# Name | GPIO | Pin | Name | Name | Pin # -#-------------------------------------------------# -# 3V3 | - | 17 | 3.3V | VDD | 1 # -# - | 24 | 18 | DIO1 | FFIT | 2 # only when PCB jumper closed -# MOSI | 10 | 19 | MOSI | SDI | 3 # -# GND | - | 20 | GND | GND | 4 # -# MISO | 9 | 21 | MISO | SDO | 5 # -# - | 25 | 22 | DIO0 | nIRQ | 6 # -# SCKL | 11 | 23 | SCK | SCK | 7 # -# CE0 | 8 | 24 | NSS | nSEL | 8 # -# CE1 | 7 | 26 | DIO2 | nFFS | 10 # only when PCB jumper closed -#-------------------------------------------------# - -# RaspyRFM twin module with 10-pin connector -# Connect to pins 17-26 on raspberry pi -#-------------------------------------------------# -# Raspi | Raspi | Raspi | RFM69 | RFM12 | PCB con # -# Name | GPIO | Pin | Name | Name | Pin # -#-------------------------------------------------# -# 3V3 | - | 17 | 3.3V | VDD | 1 # -# - | 24 | 18 | DIO0_2| FFIT | 2 # -# MOSI | 10 | 19 | MOSI | SDI | 3 # -# GND | - | 20 | GND | GND | 4 # -# MISO | 9 | 21 | MISO | SDO | 5 # -# - | 25 | 22 | DIO0_1| nIRQ | 6 # -# SCKL | 11 | 23 | SCK | SCK | 7 # -# CE0 | 8 | 24 | NSS1 | nSEL | 8 # -# CE1 | 7 | 26 | NSS2 | nFFS | 10 # -#-------------------------------------------------# - -# RaspyRFM twin module with 12-pin connector -# Connect to pins 15-26 on raspberry pi -#-------------------------------------------------# -# Raspi | Raspi | Raspi | RFM69 | RFM12 | PCB con # -# Name | GPIO | Pin | Name | Name | Pin # -#-------------------------------------------------# -# - | 22 | 15 | DIO2_2| | 1 # -# - | 23 | 16 | DIO2_1| | 2 # -# 3V3 | - | 17 | 3.3V | VDD | 3 # -# - | 24 | 18 | DIO0_2| FFIT | 4 # -# MOSI | 10 | 19 | MOSI | SDI | 5 # -# GND | - | 20 | GND | GND | 6 # -# MISO | 9 | 21 | MISO | SDO | 7 # -# - | 25 | 22 | DIO0_1| nIRQ | 8 # -# SCKL | 11 | 23 | SCK | SCK | 9 # -# CE0 | 8 | 24 | NSS1 | nSEL | 10 # -# CE1 | 7 | 26 | NSS2 | nFFS | 12 # -#-------------------------------------------------# - -#RFM69 registers -#common registers -RegFifo = 0x00 -RegOpMode = 0x01 -RegDataModul = 0x02 -RegBitrateMsb = 0x03 -RegBitrateLsb = 0x04 -RegFdevMsb = 0x05 -RegFdevLsb = 0x06 -RegFrfMsb = 0x07 -RegFrfMid = 0x08 -RegFrfLsb = 0x09 -RegOsc1 = 0x0A -RegAfcCtrl = 0x0B -RegListen1 = 0x0D -RegListen2 = 0x0E -RegListen3 = 0x0F -RegVersion = 0x10 -#TX registers -RegPaLevel = 0x11 -RegPaRamp = 0x12 -RegOcp = 0x13 -#RX registers -RegLna = 0x18 -RegRxBw = 0x19 -RegAfcBw = 0x1A -RegOokPeak = 0x1B -RegOokAvg = 0x1C -RegOokFix = 0x1D -RegAfcFei = 0x1E -RegAfcMsb = 0x1F -RegAfcLsb = 0x20 -RegFeiMsb = 0x21 -RegFeiLsb = 0x22 -RegRssiConfig = 0x23 -RegRssiValue = 0x24 -#IRQ & pin mapping registers -RegDioMapping1 = 0x25 -RegDioMapping2 = 0x26 -RegIrqFlags1 = 0x27 -RegIrqFlags2 = 0x28 -RegRssiThresh = 0x29 -RegRxTimeout1 = 0x2A -RegRxTimeout2 = 0x2B -#packet engine registers -RegPreambleMsb = 0x2C -RegPreambleLsb = 0x2D -RegSyncConfig = 0x2E -RegSyncValue1 = 0x2F -RegPacketConfig1 = 0x37 -RegPayloadLength = 0x38 -RegNodeAdrs = 0x39 -RegBroadcastAdrs = 0x3A -RegAutoModes = 0x3B -RegFifoThresh = 0x3C -RegPacketConfig2 = 0x3D -RegTemp1 = 0x4E -RegTemp2 = 0x4F -RegTestLna = 0x58 -RegTestDagc = 0x6F -RegTestAfc = 0x71 - -InterPacketRxDelay = 4 #Bitposition -RestartRx = 2 -AutoRxRestartOn = 1 -AesOn = 0 - -#Modulation type -OOK = 1 -FSK = 0 - -#DcFree -DcFree_None = 0 -DcFree_Manchester = 1 -DcFree_Whitening = 2 - -#RFM69 modes -MODE_SLEEP = 0 -MODE_STDBY = 1 -MODE_FS = 2 -MODE_TX = 3 -MODE_RX = 4 - -#DIO packet mode -DIO0_PM_CRC = 0 -DIO0_PM_PAYLOAD = 1 -DIO0_PM_SYNC = 2 -DIO0_PM_RSSI = 3 -DIO0_PM_SENT = 0 -DIO0_PM_TXDONE = 1 -DIO0_PM_PLLLOCK = 3 - - -class Rfm69(threading.Thread): - @staticmethod - def Test(cs): - spi = spidev.SpiDev() - spi.open(0, cs) - spi.max_speed_hz = 5000 - #Testing presence of module - err = False - for i in range(0, 8): - spi.xfer2([(RegSyncValue1 + i) | 0x80, 0x55]) - test = spi.xfer2([(RegSyncValue1 + i), 0x00])[1] - if test != 0x55: - err = True - break - temp = spi.xfer2([(RegSyncValue1 + i) | 0x80, 0xAA]) - test = spi.xfer2([(RegSyncValue1 + i), 0x00])[1] - if test != 0xAA: - err = True - break - spi.close() - return not err - - - def __init__(self, cs = 0, gpio_int = 25): - if not Rfm69.Test(cs): - print "ERROR! RFM69 not found" - return - - self.__event = threading.Event() - self.__spi = spidev.SpiDev() - self.__spi.open(0, cs) - self.__spi.max_speed_hz=int(5E6) - self.__gpio_int = gpio_int - self.__mutex = threading.Lock() - self.__syncsize = 4 - self.__fifothresh = 32 - - print("RFM69 found on CS " + str(cs)) - GPIO.setmode(GPIO.BCM) - GPIO.setup(gpio_int, GPIO.IN) - GPIO.add_event_detect(gpio_int, GPIO.RISING, callback=self.__RfmIrq) - - self.__SetMode(MODE_STDBY) - config = {} - - #SET DEFAULTS - config[RegOpMode] = 0x04 - config[RegDataModul] = 0x00 - config[RegBitrateMsb] = 0x1A - config[RegBitrateMsb + 1] = 0x0B - config[RegFdevMsb] = 0x00 - config[RegFdevMsb + 1] = 0x52 - config[RegFrfMsb] = 0xE4 - config[RegFrfMsb + 1] = 0xC0 - config[RegFrfMsb + 2] = 0x00 - config[RegOsc1] = 0x41 - config[RegAfcCtrl] = 0x00 - config[0x0C] = 0x02 # reserved - config[RegListen1] = 0x92 - config[RegListen2] = 0xF5 - config[RegListen3] = 0x20 - config[RegVersion] = 0x24 - config[RegPaLevel] = 0x9F - config[RegPaRamp] = 0x09 - config[RegOcp] = 0x1A - config[0x17] = 0x9B # reserved - config[RegLna] = 0x88 - config[RegRxBw] = 0x55 - config[RegAfcBw] = 0x8B - config[RegOokPeak] = 0x40 - config[RegOokAvg] = 0x80 - config[RegOokFix] = 0x06 - config[RegAfcFei] = 0x00 - config[RegAfcMsb] = 0x00 - config[RegAfcLsb] = 0x00 - config[RegFeiMsb] = 0x00 - config[RegFeiLsb] = 0x00 - config[RegRssiConfig] = 0x02 - config[RegDioMapping1] = 0x00 - config[RegDioMapping2] = 0x05 - config[RegIrqFlags1] = 0x80 - config[RegIrqFlags2] = 0x10 - config[RegRssiThresh] = 0xE4 - config[RegRxTimeout1] = 0x00 - config[RegRxTimeout2] = 0x00 - config[RegPreambleMsb] = 0x00 - config[RegPreambleLsb] = 0x00 - config[RegSyncConfig] = 0x98 - config[RegPacketConfig1] = 0x10 - config[RegPayloadLength] = 0x40 - config[RegNodeAdrs] = 0x00 - config[RegBroadcastAdrs] = 0x00 - config[RegAutoModes] = 0 - config[RegFifoThresh] = 0x8F - config[RegPacketConfig2] = 0x02 - config[RegTemp1] = 0x01 - config[RegTemp2] = 0x00 - config[RegTestLna] = 0x1B - config[RegTestDagc] = 0x30 #low beta 0 - config[RegTestAfc] = 0x00 - - config[RegPacketConfig1] = 0x00 #Fixed length, CRC off, no adr - - for key in config: - self.__WriteReg(key, config[key]) - - self.ModeStandBy() - threading.Thread.__init__(self) - print("Init complete.") - - def run(self): - while True: - time.sleep(0.5) - - def __RfmIrq(self, ch): - self.__event.set() - - def __WriteReg(self, reg, val): - temp = self.__spi.xfer2([(reg & 0x7F) | 0x80, val & 0xFF]) - - def __WriteRegWord(self, reg, val): - self.__WriteReg(reg, (val >> 8) & 0xFF) - self.__WriteReg(reg + 1, val & 0xFF) - - def __SetReg(self, reg, mask, val): - temp = self.ReadReg(reg) & (~mask) - temp |= val & mask - self.__WriteReg(reg, temp) - - def __SetDioMapping(self, dio, mapping): - if ((dio >= 0) and (dio <=3)): - self.__SetReg(RegDioMapping1, 0xC0 >> (dio * 2), mapping << (6 - dio * 2)) - elif (dio == 5): - self.__SetReg(RegDioMapping2, 0x03 << 4, mapping << 4) - - def __SetMode(self, mode): - self.__WriteReg(RegOpMode, mode << 2) - self.__mode = mode - while ((self.ReadReg(RegIrqFlags1) & (1<<7)) == 0): - pass - - def ReadReg(self, reg): - temp = self.__spi.xfer2([reg & 0x7F, 0x00]) - return temp[1] - - def ReadFifoBurst(self, len): - temp = self.__spi.xfer2([0x00] + [0x00] * len) - return temp[1:] - - def WriteFifoBurst(self, data): - self.__spi.xfer2([0x80] + list(data)) - - def ReadRegWord(self, reg): - temp = self.__spi.xfer2([reg & 0x7F, 0x00, 0x00]) - return (temp[1] << 8) | (temp[2]) - - def ReadRssiValue(self): - return self.ReadReg(RegRssiValue) - - def ModeStandBy(self): - self.__SetMode(MODE_STDBY) - - def SetParams(self, **params): - self.__mutex.acquire() - self.__event.set() - for key in params: - value = params[key] - if key == "Freq": - fword = int(round(value * 1E6 / FSTEP)) - self.__WriteReg(RegFrfMsb, fword >> 16) - self.__WriteReg(RegFrfMid, fword >> 8) - self.__WriteReg(RegFrfLsb, fword) - - elif key == "TXPower": - pwr = int(value + 18) - self.__WriteReg(RegPaLevel, 0x80 | (pwr & 0x1F)) - - elif key == "Datarate": - rate = int(round(FXOSC / (value * 1000))) - self.__WriteRegWord(RegBitrateMsb, rate) - - elif key == "Deviation": - dev = int(round(value * 1000 / FSTEP)) - self.__WriteRegWord(RegFdevMsb, dev) - - elif key == "ModulationType": - self.__SetReg(RegDataModul, 0x18, value << 3) - - elif key == "ModulationsShaping": - self.__SetReg(RegDataModul, 0x03, value) - - elif key == "SyncPattern": - conf = 0 - self.__syncsize = len(value) - if (len(value)) > 0: - conf = ((len(value) - 1) & 0x07) << 3 - conf |= 1<<7 - else: - conf = 1<<6 - self.__WriteReg(RegSyncConfig, conf) - for i, d in enumerate(value): - self.__WriteReg(RegSyncValue1 + i, d) - - elif key == "Bandwidth": - RxBw = FXOSC / value / 1000 / 4 - e = 0 - while (RxBw > 32) and (e < 7): - e += 1 - RxBw /= 2 - RxBw = RxBw / 4 - 4 - RxBw = max(RxBw, 0) - m = int(RxBw) - self.__SetReg(RegRxBw, 0x1F, m<<3 | e) - - elif key == "AfcBandwidth": - RxBw = FXOSC / value / 1000 / 4 - e = 0 - while (RxBw > 32) and (e < 7): - e += 1 - RxBw /= 2 - RxBw = RxBw / 4 - 4 - RxBw = max(RxBw, 0) - m = int(RxBw) - self.__SetReg(RegAfcBw, 0x1F, m<<3 | e) - - elif key == "Preamble": - self.__WriteRegWord(RegPreambleMsb, value) - - elif key == "LnaGain": - self.__SetReg(RegLna, 0x07, value) - - elif key == "RssiThresh": - th = -(value * 2) - self.__WriteReg(RegRssiThresh, th) - - elif key == "Dagc": - self.__WriteReg(RegDagc, value) - - elif key == "AfcFei": - self.__WriteReg(RegAfcFei, value) - - elif key == "Callback": - self.__Callback = value - - elif key == "DcFree": - self.__SetReg(RegPacketConfig1, 3<<5, value<<5) - - elif key == "OokThreshType": - self.__SetReg(RegOokPeak, 3<<6, value<<6) - - elif key == "OokFixedThresh": - self.__WriteReg(RegOokFix, value) - - elif key == "OokPeakThreshDec": - self.__SetReg(RegOokPeak, 7<<0, value) - - else: - print("Unrecognized option >>" + key + "<<") - - self.ModeStandBy(); - self.__mutex.release() - - def __WaitInt(self): - self.__event.clear() - if GPIO.input(self.__gpio_int): - return - while not self.__event.wait(0.5): - if GPIO.input(self.__gpio_int): - break - - def WhitenHope(self, data): - lfsr = 0x3fe - for i, d in enumerate(data): - data[i] = data[i] ^ ((lfsr >> 2) & 0xFF) - #roll LFSR - for j in range(8): - if ((lfsr >> 5) ^ lfsr) & 0x10 != 0: - lfsr |= 1<<0 - lfsr <<= 1 - lfsr &= 0x3ff - - def WhitenTI(self, data): - lfsr = 0x1ff - for i, d in enumerate(data): - data[i] = data[i] ^ (lfsr & 0xFF) - for i in range(8): - if ((lfsr >> 5) ^ lfsr) & 0x01 != 0: - lfsr |= 1<<9 - lfsr >>= 1 - - def SendPacket(self, data): - self.__mutex.acquire() - self.__event.set() - self.ModeStandBy() - - #flush FIFO - status = self.ReadReg(RegIrqFlags2) - while (status & 0x40 == 0x40): - self.ReadReg(RegFifo) - status = self.ReadReg(RegIrqFlags2) - - self.__WriteReg(RegPayloadLength, 0) #unlimited length - self.__WriteReg(RegFifoThresh, 0x80 | self.__fifothresh) #start TX with 1st byte in FIFO - self.__SetDioMapping(0, DIO0_PM_SENT) #DIO0 -> PacketSent - self.__SetMode(MODE_TX) - - l = min(len(data), 64) - while True: - self.WriteFifoBurst(data[:l]) - data = data[l:] - if len(data) == 0: - break - while True: - status = self.ReadReg(RegIrqFlags2) - if (status & (1<<5)) == 0: #below fifothresh - l = min(len(data), self.__fifothresh) - break - if (status & (1<<7)) == 0: #space for at least 1 bytearray - l = 1 - break - - self.__WaitInt() - self.ModeStandBy() - self.__mutex.release() - - def ReadFifoWait(self, length): - ret = [] - while length > 0: - flags = self.ReadReg(RegIrqFlags2) - if ((flags & (1<<5)) != 0) and (length >= 32): #FIFO level? - ret += self.ReadFifoBurst(self.__fifothresh) - length -= self.__fifothresh - if (flags & (1<<6)) != 0: #FIFO not empty? - ret.append(self.ReadReg(RegFifo)) - length -= 1 - return ret - - def GetNoiseFloor(self): - self.__mutex.acquire() - #save values - rssithresh = self.ReadReg(RegRssiThresh) - ookthresh = self.ReadReg(RegOokFix) - sync = self.ReadReg(RegSyncConfig) - - self.__WriteReg(RegRssiThresh, 240) - self.__WriteReg(RegSyncConfig, 1<<6) #no sync, always fill FIFO - self.__WriteReg(RegPayloadLength, 0) #unlimited length - self.__SetMode(MODE_RX) - thresh = 40 - while True: - self.__WriteReg(RegOokFix, thresh) - for i in range(150): - b = self.ReadFifoWait() - if b <> 0: - thresh += 1 - break; - if i == 149: - break; - - #restore registers - self.__WriteReg(RegRssiThresh, rssithresh) - self.__WriteReg(RegOokFix, ookthresh) - self.__WriteReg(RegSyncConfig, sync) - self.ModeStandBy() - self.__mutex.release() - return thresh - - def __StartRx(self): - self.__SetDioMapping(2, 1) #DIO2 -> DATA - self.__mutex.acquire() - while True: - self.__WriteReg(RegPayloadLength, 0) #unlimited length - self.__WriteReg(RegFifoThresh, self.__fifothresh) - if self.__syncsize > 0: - self.__SetDioMapping(0, DIO0_PM_SYNC) #DIO0 -> SyncAddress - else: - self.__SetDioMapping(0, DIO0_PM_RSSI) #DIO0 -> RSSI - self.__SetMode(MODE_RX) - self.__mutex.release() - self.__WaitInt() - self.__mutex.acquire() - if self.__mode == MODE_RX: - break; - - def StartRx(self, cb): - self.__StartRx() - cb() - self.ModeStandBy() - self.__mutex.release() - - def ReceivePacket(self, length): - self.__StartRx() - result = self.ReadFifoWait(length) - - rssi = -self.ReadReg(RegRssiValue) / 2 - afc = self.ReadReg(RegAfcMsb) << 8 - afc = afc | self.ReadReg(RegAfcLsb) - - if afc >= 0x8000: - afc = afc - 0x10000 - - self.ModeStandBy() - self.__mutex.release() - return (result, rssi, afc)