add CUL emulator

simplify some routines
This commit is contained in:
S. Seegel 2020-01-09 19:58:26 +00:00
parent 3f5e577ca1
commit f32c7fc8b8
2 changed files with 206 additions and 11 deletions

195
culemu.py Executable file
View file

@ -0,0 +1,195 @@
#!/usr/bin/env python2.7
import socket
import time
import rfm69
from rfm69 import Rfm69
import xx2262
import it32
import threading
PORT = 5052
rfm = Rfm69(1, 24)
rfm.SetParams(
Freq = 868.300, #MHz center frequency
ModulationType = rfm69.FSK, #modulation
Datarate = 9.992, #kbit/s baudrate
Deviation = 19.042, #kHz frequency deviation -> OBW = 48 kHz, h = 3.81
SyncPattern = [0xc6, 0x26, 0xc6, 0x26], #syncword
Bandwidth = 100, #kHz bandwidth (101.5)
RssiThresh = -100, #-100 dB RSSI threshold
Preamble = 1700
)
connections = []
def maxPrint(frame):
x = {}
x['cnt'] = frame[1]
x['flag'] = hex(frame[2])
x['type'] = hex(frame[3])
x['src'] = hex(frame[4] << 16 | frame[5] << 8 | frame[6])
x['dst'] = hex(frame[7] << 16 | frame[8] << 8 | frame[9])
x['grp'] = frame[10]
x['pay'] = []
for i in range(frame[0] - 10):
x['pay'].append(frame[i + 11])
info = ""
if x['type'] == '0x42':
info = str(x['pay'][0] / 2.0) + ' / ' + str(x['pay'][1] / 10.0)
print(x['src'] + "->" + x['dst'] + " type " + x['type'] + ':', x['pay'], info)
class Connection(threading.Thread):
def __init__(self, sock, rfm):
self._socket = sock
self._rfm = rfm
self.__housecode = "0000"
self.__rxflags = 0
threading.Thread.__init__(self)
def sendHost(self, line):
#print("TO FHEM: " + line)
self._socket.send(line + "\n")
def sendRF(self, symbolTime, data):
self._rfm.SetParams(Datarate = 1E3/symbolTime)
self._rfm.SendPacket(data)
def run(self):
while True:
data = self._socket.recv(1024)
if not data:
break
lines = str.splitlines(data)
for line in lines:
#print("FROM FHEM: " + line)
if line == 'V':
self.sendHost("V 1.0 CULEMU")
elif line[:1] == "X":
line = line[1:]
if len(line) > 0:
self.__rxflags = int(line, 16)
else:
self.sendHost("X" + format(self.__rxflags, "02X") + format(900, "05d"))
pass
elif line[:2] == "is":
self.sendHost(line)
line = line[2:]
if len(line) == 12:
frame = xx2262.MakeFrame(line, 5)
self.sendRF(375, frame)
elif len(line) == 32:
frame = it32.MakeFrame(line, 5)
self.sendRF(275, frame)
elif line[:3] == "T01":
if len(line) > 3:
self.__housecode = line[3:]
else:
self.sendHost(self.__housecode)
elif line[:2] == "Zr":
pass
elif line[:2] == "Zs":
line = line[2:]
frame = bytearray.fromhex(line)
#maxPrint(frame)
rfm.WhitenTI(frame)
self._rfm.SendPacket(frame)
print("TX!")
else:
self.sendHost("? (? is unknown) Use one of C F R T V W X e f l t x Z")
print "destroy connection"
connections.remove(self)
del self
class CulEmu(threading.Thread):
def __init__(self, rfm, port):
self._rfm = rfm
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._sock.bind(('', port))
self._sock.listen(4)
threading.Thread.__init__(self)
def run(self):
while True:
conn, addr = self._sock.accept()
print "New connection from", addr
c = Connection(conn, self._rfm)
c.start()
connections.append(c)
def sendHost(self, s):
for c in connections:
c.sendHost(s)
rxevent = threading.Event()
rxmutex = threading.Lock()
rxbuf = []
cul = CulEmu(rfm, PORT)
cul.daemon = True
cul.start()
class RxThread(threading.Thread):
def __init__(self, rfm):
self.__rfm = rfm
rfm.SetParams(
CallbackSync = self.__callback
)
threading.Thread.__init__(self)
def __callback(self):
lfsr = 0x1ff
frame = rfm.ReadFifoWait(1)
len = frame[0] ^ 0xFF #invert due to whitening
frame += rfm.ReadFifoWait(len)
rxmutex.acquire()
rxbuf.append(frame)
rxmutex.release()
rxevent.set()
return
def run(self):
while True:
rxevent.wait()
left = True
while left:
rxmutex.acquire()
rxevent.clear()
frame = rxbuf.pop(0)
left = len(rxbuf) > 0
rxmutex.release()
rfm.WhitenTI(frame)
s = "Z"
for b in frame:
s += format(b, "02X")
s += "20"
cul.sendHost(s)
#maxPrint(frame)
if not left:
break
rxthread = RxThread(rfm)
rxthread.daemon = True
rxthread.start()
while True:
data = rfm.ReceivePacket(0)

View file

@ -374,7 +374,9 @@ class Rfm69(threading.Thread):
def __WaitInt(self):
self.__event.clear()
while not self.__event.wait(0.3):
if GPIO.input(self.__gpio_int):
return
while not self.__event.wait(0.1):
if GPIO.input(self.__gpio_int):
print("GPIO high!")
break
@ -428,11 +430,14 @@ class Rfm69(threading.Thread):
self.__rxmode = False
self.__mutex.release()
def ReadFifoWait(self):
while True:
def ReadFifoWait(self, length):
ret = []
while length > 0:
flags = self.ReadReg(RegIrqFlags2)
if (flags & (1<<6)) != 0: #FIFO not empty?
return self.ReadReg(RegFifo)
ret.append(self.ReadReg(RegFifo))
length -= 1
return ret
def GetNoiseFloor(self):
self.__mutex.acquire()
@ -472,7 +477,7 @@ class Rfm69(threading.Thread):
self.__SetDioMapping(0, 2) #DIO0 -> SyncAddress
else:
self.__SetDioMapping(0, 3) #DIO0 -> RSSI
print("goto rx")
self.__SetMode(MODE_RX)
self.__rxmode = True
self.__mutex.release()
@ -481,7 +486,6 @@ class Rfm69(threading.Thread):
if self.__rxmode == True:
break;
result = []
rssi = -self.ReadReg(RegRssiValue) / 2
afc = self.ReadReg(RegAfcMsb) << 8
afc = afc | self.ReadReg(RegAfcLsb)
@ -494,11 +498,7 @@ class Rfm69(threading.Thread):
self.__mutex.release()
return
while True:
result.append(self.ReadFifoWait())
length -= 1
if length == 0:
break;
result = self.ReadFifoWait(length)
self.ModeStandBy()
self.__mutex.release()