From f32c7fc8b845660fd187d4f08f1f4a16a0a8d447 Mon Sep 17 00:00:00 2001 From: "S. Seegel" Date: Thu, 9 Jan 2020 19:58:26 +0000 Subject: [PATCH] add CUL emulator simplify some routines --- culemu.py | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ rfm69.py | 22 +++--- 2 files changed, 206 insertions(+), 11 deletions(-) create mode 100755 culemu.py diff --git a/culemu.py b/culemu.py new file mode 100755 index 0000000..89684d4 --- /dev/null +++ b/culemu.py @@ -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) diff --git a/rfm69.py b/rfm69.py index 025c5d2..aea3cab 100644 --- a/rfm69.py +++ b/rfm69.py @@ -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()