Add TCP Proxy to permit babyware and other paradox clients

parent 9ee8c278
......@@ -2,6 +2,9 @@
port: /dev/ttyUSB0
baudrate: 9600
enableTCPProxy: no
tcpport: 10001
tcpaddr: 127.0.0.1
[panel]
autodetect: yes
......
......@@ -25,7 +25,7 @@ import os, sys
import imodules, plugins
from nexlibs.utils.genutils import ConvenienceCaller
from nexlibs.utils import genutils
from ConfigParser import NoSectionError
log = logging.getLogger('Plugins')
......@@ -86,7 +86,7 @@ class Loader(object):
p = getPlugin(name, core)
self.plugreg[name] = p
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")
......
......@@ -25,8 +25,10 @@ from zope.interface import implements
from twisted.plugin import IPlugin
from twisted.internet.serialport import SerialPort
from twisted.internet.protocol import BaseProtocol
from twisted.internet import reactor
from twisted.internet.protocol import BaseProtocol, Protocol, Factory
from twisted.internet import reactor, tcp
from nexlibs.utils import genutils
import serial
import time
......@@ -45,6 +47,7 @@ class ParadoxProtocol(BaseProtocol):
sendqueue=[]
replyqueue=[]
packettimeout = 0
proxy = False
def __init__(self, logger, core, cfg):
self.log = logger
......@@ -69,16 +72,31 @@ class ParadoxProtocol(BaseProtocol):
elif len(self.packet) > 0:
self.packettimeout = time.time()
def _queueSendData(self, data, callback=False):
self.sendqueue+=[{'msg': data, 'cb': callback, 'try': 3}]
def _queueSendData(self, data, callback=False, expected_reply=None):
self.sendqueue+=[{'msg': data, 'cb': callback, 'try': 3, 'expected_reply': expected_reply}]
reactor.callLater(0, self._processSendQueue)
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 p37b.checkCmd(ord(self.queue[0][0]), p37b.CMD_EVENT):
reactor.callLater(0, self._processEvent, self.queue[0])
else:
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?
# in theory we don't need it as we will not send anything
# until the reply is received, but it would be more error
......@@ -86,6 +104,13 @@ class ParadoxProtocol(BaseProtocol):
if self.replyqueue[0]['cb'] and callable(self.replyqueue[0]['cb']):
reactor.callLater(0, self.replyqueue[0]['cb'], self.queue[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]
def _processSendQueue(self, addToReplyQueue=True):
......@@ -114,6 +139,8 @@ class ParadoxProtocol(BaseProtocol):
def dataReceived(self, data):
if self.proxy:
self.proxy.serialInData(data)
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.packet = []
......@@ -134,13 +161,13 @@ class ParadoxProtocol(BaseProtocol):
self.log.debug("Connection lost for "+str(reason))
def connect(self):
self.write(p37b.MSG_CONNECT)
self.write(p37b.MSG_GETSTATUS)
self.write(p37b.MSG_SYNC, self._replySync)
self.write(p37b.MSG_CONNECT, expected_reply=p37b.REPLY_CONNECT)
self.write(p37b.MSG_GETSTATUS, expected_reply=p37b.REPLY_GETSTATUS)
self.write(p37b.MSG_SYNC, self._replySync, expected_reply=p37b.REPLY_SYNC)
def write(self, message, reply_callback=False):
self._queueSendData(p37b.format37ByteMessage(message), reply_callback)
def write(self, message, reply_callback=False, expected_reply=False):
self._queueSendData(p37b.format37ByteMessage(message), reply_callback, expected_reply)
def _replySync(self, reply):
......@@ -161,8 +188,47 @@ class ParadoxProtocol(BaseProtocol):
def _processEvent(self, event):
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):
implements(IPlugin, imodules.IModules)
serproto = False
def _openSerial(self, port=SERIAL_PORT, retry=3):
try:
......@@ -176,7 +242,8 @@ class Paradox(object):
if retry > 0:
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:
self.log.info("Serial Port ERROR: "+str(err))
reactor.callLater(1, self._openSerial, port, retry-1)
......@@ -191,6 +258,13 @@ class Paradox(object):
self.cfg = self.core.readPluginConfig('paradox')
logger.info("Initialize Serial Connection...")
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")
......
......@@ -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_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):
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