Add TCP Proxy to permit babyware and other paradox clients

parent 9ee8c278
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
port: /dev/ttyUSB0 port: /dev/ttyUSB0
baudrate: 9600 baudrate: 9600
enableTCPProxy: no
tcpport: 10001
tcpaddr: 127.0.0.1
[panel] [panel]
autodetect: yes autodetect: yes
......
...@@ -25,7 +25,7 @@ import os, sys ...@@ -25,7 +25,7 @@ import os, sys
import imodules, plugins import imodules, plugins
from nexlibs.utils.genutils import ConvenienceCaller from nexlibs.utils.genutils import ConvenienceCaller
from nexlibs.utils import genutils from nexlibs.utils import genutils
from ConfigParser import NoSectionError
log = logging.getLogger('Plugins') log = logging.getLogger('Plugins')
...@@ -86,7 +86,7 @@ class Loader(object): ...@@ -86,7 +86,7 @@ class Loader(object):
p = getPlugin(name, core) p = getPlugin(name, core)
self.plugreg[name] = p self.plugreg[name] = p
p.initialize(ConvenienceCaller(lambda c: self._plugincback(name, c)), PluginLogger(name)) p.initialize(ConvenienceCaller(lambda c: self._plugincback(name, c)), PluginLogger(name))
except: except NoSectionError:
log.error("Trying to load "+name+" plugin but no value in config file plugins section") log.error("Trying to load "+name+" plugin but no value in config file plugins section")
......
...@@ -25,8 +25,10 @@ from zope.interface import implements ...@@ -25,8 +25,10 @@ from zope.interface import implements
from twisted.plugin import IPlugin from twisted.plugin import IPlugin
from twisted.internet.serialport import SerialPort from twisted.internet.serialport import SerialPort
from twisted.internet.protocol import BaseProtocol from twisted.internet.protocol import BaseProtocol, Protocol, Factory
from twisted.internet import reactor from twisted.internet import reactor, tcp
from nexlibs.utils import genutils
import serial import serial
import time import time
...@@ -45,6 +47,7 @@ class ParadoxProtocol(BaseProtocol): ...@@ -45,6 +47,7 @@ class ParadoxProtocol(BaseProtocol):
sendqueue=[] sendqueue=[]
replyqueue=[] replyqueue=[]
packettimeout = 0 packettimeout = 0
proxy = False
def __init__(self, logger, core, cfg): def __init__(self, logger, core, cfg):
self.log = logger self.log = logger
...@@ -69,16 +72,31 @@ class ParadoxProtocol(BaseProtocol): ...@@ -69,16 +72,31 @@ class ParadoxProtocol(BaseProtocol):
elif len(self.packet) > 0: elif len(self.packet) > 0:
self.packettimeout = time.time() self.packettimeout = time.time()
def _queueSendData(self, data, callback=False): def _queueSendData(self, data, callback=False, expected_reply=None):
self.sendqueue+=[{'msg': data, 'cb': callback, 'try': 3}] self.sendqueue+=[{'msg': data, 'cb': callback, 'try': 3, 'expected_reply': expected_reply}]
reactor.callLater(0, self._processSendQueue) reactor.callLater(0, self._processSendQueue)
def _processQueue(self): def _processQueue(self):
def _expected_reply(replystart, expected):
if expected:
if isinstance(expected, (list, tuple)):
for i in expected:
if p37b.checkCmd(replystart, i):
return True
else:
if p37b.checkCmd(replystart, expected):
return True
else:
return True
return False
if len(self.queue) > 0: if len(self.queue) > 0:
if p37b.checkCmd(ord(self.queue[0][0]), p37b.CMD_EVENT): if p37b.checkCmd(ord(self.queue[0][0]), p37b.CMD_EVENT):
reactor.callLater(0, self._processEvent, self.queue[0]) reactor.callLater(0, self._processEvent, self.queue[0])
else: else:
if len(self.replyqueue) > 0: if len(self.replyqueue) > 0:
if _expected_reply(ord(self.queue[0][0]), self.replyqueue[0]['expected_reply']):
# XXX Can we check in some way if is the *RIGHT* reply? # XXX Can we check in some way if is the *RIGHT* reply?
# in theory we don't need it as we will not send anything # in theory we don't need it as we will not send anything
# until the reply is received, but it would be more error # until the reply is received, but it would be more error
...@@ -86,6 +104,13 @@ class ParadoxProtocol(BaseProtocol): ...@@ -86,6 +104,13 @@ class ParadoxProtocol(BaseProtocol):
if self.replyqueue[0]['cb'] and callable(self.replyqueue[0]['cb']): if self.replyqueue[0]['cb'] and callable(self.replyqueue[0]['cb']):
reactor.callLater(0, self.replyqueue[0]['cb'], self.queue[0]) reactor.callLater(0, self.replyqueue[0]['cb'], self.queue[0])
del self.replyqueue[0] del self.replyqueue[0]
else:
if isinstance(self.replyqueue[0]['expected_reply'], (list, tuple)):
expected = "["+",".join(["\\x%02X" % (x) for x in self.replyqueue[0]['expected_reply']])+"]"
else:
print self.replyqueue[0]['expected_reply'] << 4
expected = "\\x%02X" % (self.replyqueue[0]['expected_reply'])
self.log.error("Wrong Expected Reply! (have "+"\\x%02X" % (ord(self.queue[0][0]) >> 4)+" expect "+expected+")")
del self.queue[0] del self.queue[0]
def _processSendQueue(self, addToReplyQueue=True): def _processSendQueue(self, addToReplyQueue=True):
...@@ -114,6 +139,8 @@ class ParadoxProtocol(BaseProtocol): ...@@ -114,6 +139,8 @@ class ParadoxProtocol(BaseProtocol):
def dataReceived(self, data): def dataReceived(self, data):
if self.proxy:
self.proxy.serialInData(data)
if len(self.packet) > 0 and (time.time()-self.packettimeout) > PKTTIMEOUT: if len(self.packet) > 0 and (time.time()-self.packettimeout) > PKTTIMEOUT:
self.log.debug("Serial Timeout: discard packet "+''.join( [ "\\x%02X" % ord( x ) for x in self.packet ] ).strip()) self.log.debug("Serial Timeout: discard packet "+''.join( [ "\\x%02X" % ord( x ) for x in self.packet ] ).strip())
self.packet = [] self.packet = []
...@@ -134,13 +161,13 @@ class ParadoxProtocol(BaseProtocol): ...@@ -134,13 +161,13 @@ class ParadoxProtocol(BaseProtocol):
self.log.debug("Connection lost for "+str(reason)) self.log.debug("Connection lost for "+str(reason))
def connect(self): def connect(self):
self.write(p37b.MSG_CONNECT) self.write(p37b.MSG_CONNECT, expected_reply=p37b.REPLY_CONNECT)
self.write(p37b.MSG_GETSTATUS) self.write(p37b.MSG_GETSTATUS, expected_reply=p37b.REPLY_GETSTATUS)
self.write(p37b.MSG_SYNC, self._replySync) self.write(p37b.MSG_SYNC, self._replySync, expected_reply=p37b.REPLY_SYNC)
def write(self, message, reply_callback=False): def write(self, message, reply_callback=False, expected_reply=False):
self._queueSendData(p37b.format37ByteMessage(message), reply_callback) self._queueSendData(p37b.format37ByteMessage(message), reply_callback, expected_reply)
def _replySync(self, reply): def _replySync(self, reply):
...@@ -161,8 +188,47 @@ class ParadoxProtocol(BaseProtocol): ...@@ -161,8 +188,47 @@ class ParadoxProtocol(BaseProtocol):
def _processEvent(self, event): def _processEvent(self, event):
pass pass
class ParadoxTCPProxy(Protocol):
cid = 0
def __init__(self, clients, factory):
self.clients = clients
self.factory = factory
def connectionMade(self):
cid = len(self.clients)
self.clients[cid] = self
self.cid = cid
def connectionLost(self, reason):
if self.cid in self.clients.keys():
del self.clients[self.cid]
def dataReceived(self, data):
self.factory.log.debug("Data FROM TCP Client "+str(self.cid)+": "+''.join( [ "\\x%02X" % ord( x ) for x in data ] ).strip())
self.factory.serproto.transport.write(data)
class ParadoxTCPFactory(Factory):
def __init__(self, core, serproto, logger):
self.clients = {}
self.serproto = serproto
self.serproto.proxy = self
self.log = logger
def serialInData(self, data):
for cid in self.clients.keys():
self.clients[cid].transport.write(data)
def buildProtocol(self, addr):
return ParadoxTCPProxy(self.clients, self)
class Paradox(object): class Paradox(object):
implements(IPlugin, imodules.IModules) implements(IPlugin, imodules.IModules)
serproto = False
def _openSerial(self, port=SERIAL_PORT, retry=3): def _openSerial(self, port=SERIAL_PORT, retry=3):
try: try:
...@@ -176,7 +242,8 @@ class Paradox(object): ...@@ -176,7 +242,8 @@ class Paradox(object):
if retry > 0: if retry > 0:
try: try:
self.port = SerialPort(ParadoxProtocol(self.log, self.core, self.cfg), dev, reactor, baudrate=brate) self.serproto = ParadoxProtocol(self.log, self.core, self.cfg)
self.port = SerialPort(self.serproto, dev, reactor, baudrate=brate)
except serial.SerialException as err: except serial.SerialException as err:
self.log.info("Serial Port ERROR: "+str(err)) self.log.info("Serial Port ERROR: "+str(err))
reactor.callLater(1, self._openSerial, port, retry-1) reactor.callLater(1, self._openSerial, port, retry-1)
...@@ -191,6 +258,13 @@ class Paradox(object): ...@@ -191,6 +258,13 @@ class Paradox(object):
self.cfg = self.core.readPluginConfig('paradox') self.cfg = self.core.readPluginConfig('paradox')
logger.info("Initialize Serial Connection...") logger.info("Initialize Serial Connection...")
self._openSerial() self._openSerial()
if genutils.isTrue(self.cfg.get("connection", "enableTCPProxy")) and self.serproto:
self.proxy = ParadoxTCPFactory(self.core, self.serproto, self.log)
tcpport = self.cfg.get("connection", "tcpport")
self.log.debug("TCP Port "+str(tcpport)+" OPEN")
port = tcp.Port(int(tcpport), self.proxy, 50, self.cfg.get("connection", "tcpaddr"), reactor)
port.startListening()
logger.info("Plugin initialized") logger.info("Plugin initialized")
......
...@@ -121,6 +121,11 @@ MSG_SYNC= '\x5F\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0 ...@@ -121,6 +121,11 @@ MSG_SYNC= '\x5F\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
MSG_UNKWNOWN_HS1= '\x50\x00\x1F\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4F' MSG_UNKWNOWN_HS1= '\x50\x00\x1F\xE0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x4F'
MSG_UNKWNOWN_HS2= '\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50' MSG_UNKWNOWN_HS2= '\x50\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x50'
# Expected replies command
REPLY_CONNECT=0x7
REPLY_GETSTATUS=[0x5, 0x7]
REPLY_SYNC=0x0
def checkSumCalc(message): def checkSumCalc(message):
checksum = 0 checksum = 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment