refactoring, cleanup, testing

This commit is contained in:
Stefan Seegel 2020-01-27 02:11:10 +01:00
parent dcbdbeec0b
commit aef9733f2e
8 changed files with 321 additions and 667 deletions

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python2.7
import socket import socket
import RaspyRFM from raspyrfm import *
import sys import sys
UDP_IP = "0.0.0.0" UDP_IP = "0.0.0.0"
@ -12,10 +12,10 @@ sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT)) sock.bind((UDP_IP, UDP_PORT))
rfm = RaspyRFM.RaspyRFM() rfm = RaspyRFM(1, RFM69)
rfm.SetParams( rfm.set_params(
Freq = 433.92, Freq = 433.92,
TXPower = 13, TxPower = 13,
ModulationType = rfm69.OOK, ModulationType = rfm69.OOK,
SyncPattern = [], SyncPattern = [],
) )
@ -24,7 +24,6 @@ print("Listening...")
while True: while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print("received message from " + addr[0] + ': ' + str(data)) print("received message from " + addr[0] + ': ' + str(data))
print(sock)
msg = str(data).split(":") msg = str(data).split(":")
if msg[0] == "SEARCH HCGW": if msg[0] == "SEARCH HCGW":
@ -59,5 +58,5 @@ while True:
for i in range(bitleft): for i in range(bitleft):
bindata[len(bindata) - 1] <<= 1 bindata[len(bindata) - 1] <<= 1
rfm.SetParams(Datarate = 1000.0 / steplen) rfm.set_params(Datarate = 1000.0 / steplen)
rfm.SendPacket(bindata * rep) rfm.send_packet(bindata * rep)

178
apps/fs20.py Normal file
View file

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

View file

@ -1,16 +1,21 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python2.7
import RaspyRFM from raspyrfm import *
import sys import sys
import time import time
import it32 import it32
import tristate import tristate
import bistate24 import bistate24
import fs20
from argparse import ArgumentParser from argparse import ArgumentParser
import wave, struct
parser = ArgumentParser() parser = ArgumentParser()
parser.add_argument("-t", "--timebase", type=int, help=u"timebase in \u03bcs") 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("-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'") parser.add_argument("code", nargs='*', help="code, e. g. '000000000FFF', 'A 1 2 on' or '10111100011101011111111110001110'")
args = parser.parse_args() args = parser.parse_args()
@ -18,6 +23,7 @@ protos = [
it32, it32,
tristate, tristate,
bistate24, bistate24,
fs20,
] ]
txdata = None txdata = None
@ -33,25 +39,108 @@ if len(args.code) > 0:
print("invalid code!") print("invalid code!")
exit() exit()
rfm = RaspyRFM.RaspyRFM() rfm = RaspyRFM(args.module, RFM69)
rfm.SetParams( rfm.set_params(
Freq = 433.92, #MHz Freq = args.frequency, #MHz
Datarate = 20.0, #kbit/s Datarate = 20.0, #kbit/s
Bandwidth = 200, #kHz Bandwidth = 200, #kHz
SyncPattern = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F], SyncPattern = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F],
RssiThresh = -105, #dBm RssiThresh = -105, #dBm
ModulationType = RaspyRFM.OOK, ModulationType = rfm69.OOK,
OokThreshType = 1, #peak thresh OokThreshType = 1, #peak thresh
OokPeakThreshDec = 3, 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: if txdata:
rfm.SetParams( rfm.set_params(
SyncPattern = [], SyncPattern = [],
Datarate = 1000.0 / (args.timebase if args.timebase else txdata[2]) Datarate = 1000.0 / (args.timebase if args.timebase else txdata[2])
) )
rep = (args.repeats if args.repeats else txdata[1]) rep = (args.repeats if args.repeats else txdata[1])
rfm.SendPacket(txdata[0] * rep) rfm.send_packet(txdata[0] * rep)
print("Code sent!") print("Code sent!")
exit() exit()
@ -65,14 +154,34 @@ def Decode(pulses):
if dec: if dec:
print(dec) print(dec)
if not dec: s = ""
print("Len " + str(len(pulses)) + ": " + str(pulses)) 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: while True:
data = rfm.ReceivePacket(260) data = rfm.receive_packet(260)
s = "" s = ""
pulsecount = 7 pulsecount = 4
glitchcount = 0 glitchcount = 0
bit = True bit = True
pulses = [] pulses = []

View file

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

View file

@ -1,23 +1,20 @@
#!/usr/bin/env python2.7 #!/usr/bin/env python2.7
from rfm69 import Rfm69 from raspyrfm import *
import rfm69
import sensors
import sys import sys
import time import time
if Rfm69.Test(1): rfm = RaspyRFM(2, RFM69) #when using the RaspyRFM twin
rfm = Rfm69(1, 24) #when using the RaspyRFM twin #elif Rfm69.Test(0):
elif Rfm69.Test(0): # rfm = Rfm69() #when using a single single 868 MHz RaspyRFM
rfm = Rfm69() #when using a single single 868 MHz RaspyRFM #else:
else: # print "No RFM69 module found!"
print "No RFM69 module found!" # exit()
exit()
rfm.SetParams( rfm.set_params(
Freq = 868.350, Freq = 868.350,
Datarate = 5.0, Datarate = 5.0,
TXPower = -10, TxPower = -10,
ModulationType = rfm69.OOK, ModulationType = rfm69.OOK,
SyncPattern = [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x38], SyncPattern = [0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x38],
Preamble = 0 Preamble = 0
@ -81,5 +78,6 @@ def MakeFS20Frame(hc, adr, cmd):
data = [] data = []
bitcnt = 0 bitcnt = 0
MakeFS20Frame(int(sys.argv[1], 0), int(sys.argv[2], 0), int(sys.argv[3], 0)) MakeFS20Frame(int(sys.argv[1], 0), int(sys.argv[2], 0), int(sys.argv[3], 0))
print(data)
for x in range(3): for x in range(3):
rfm.SendPacket(data) rfm.send_packet(data)

View file

@ -65,6 +65,7 @@ rxThread.daemon = True
rxThread.start() rxThread.start()
def Decode(frame): def Decode(frame):
print(frame)
#decode MAX! frame #decode MAX! frame
cnt = frame[1] cnt = frame[1]
flag = hex(frame[2]) flag = hex(frame[2])

View file

@ -402,7 +402,7 @@ class Rfm69(threading.Thread):
self.__set_reg(RegOokPeak, 3<<6, value<<6) self.__set_reg(RegOokPeak, 3<<6, value<<6)
elif key == "OokFixedThresh": elif key == "OokFixedThresh":
self.___write_reg(RegOokFix, value) self.__write_reg(RegOokFix, value)
elif key == "OokPeakThreshDec": elif key == "OokPeakThreshDec":
self.__set_reg(RegOokPeak, 7<<0, value) self.__set_reg(RegOokPeak, 7<<0, value)

559
rfm69.py
View file

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