summaryrefslogtreecommitdiff
path: root/heap/ebus/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'heap/ebus/__init__.py')
-rw-r--r--heap/ebus/__init__.py172
1 files changed, 172 insertions, 0 deletions
diff --git a/heap/ebus/__init__.py b/heap/ebus/__init__.py
new file mode 100644
index 0000000..8d4e6ac
--- /dev/null
+++ b/heap/ebus/__init__.py
@@ -0,0 +1,172 @@
+# -*- coding: utf-8 -*-
+import asynchat
+import asyncore
+import socket
+import sys
+import logging
+
+import os
+from lxml import objectify
+from lxml import etree
+
+logger = logging.getLogger("ebus.core")
+logger.setLevel(logging.INFO)
+
+class UnknownPacketException(Exception):
+ pass
+
+class EbusPacket(object):
+ EBUS_SPECIFICATION = os.path.join(os.path.dirname(__file__), "ebus_specification.xml")
+ ebus_xml = objectify.parse(open(EBUS_SPECIFICATION))
+
+ @staticmethod
+ def address_to_type(address):
+ d=[dev.get("type") for dev in EbusPacket.ebus_xml.xpath("/ebus/devices/device[@address=$address]",
+ address="#x%.2x"%address)]
+ return len(d)>0 and d[0] or None
+
+ def __init__(self, source, destination, primary_command, secondary_command):
+ self.source = source
+ self.destination = destination
+ self.primary_command = primary_command
+ self.secondary_command = secondary_command
+
+ def __str__(self):
+ #XXX self.length only in subclasses
+ return "<%-18s name=\"%s\" source=\"0x%.2x\" destination=\"0x%.2x\" primary=0x%x secondary=0x%x length=0x%x>" % \
+ (self.__class__.__name__, self.name(), self.source, self.destination, \
+ self.primary_command, self.secondary_command, self.length)
+
+ def get_packet_description(self):
+ p=EbusPacket.ebus_xml.xpath("/ebus/packets/packet[@primary=$primary and @secondary=$secondary]",
+ primary="#x%.2x"%self.primary_command,
+ secondary="#x%.2x"%self.secondary_command)
+ if len(p)>0 and p[0] is not None:
+ return p[0]
+ else:
+ raise UnknownPacketException("Unknown Packet, primary_command=#x%.2x secondary_command=#x%.2x" % (
+ self.primary_command,
+ self.secondary_command))
+
+ def get_source_name(self):
+ s=EbusPacket.ebus_xml.xpath("/ebus/devices/device[@address=$address]",
+ address="#x%.2x"%self.source)
+ return len(s)>0 and s[0].get("name") or None
+
+ def get_destination_name(self):
+ d=EbusPacket.ebus_xml.xpath("/ebus/devices/device[@address=$address]",
+ address="#x%.2x"%self.destination)
+ return len(d)>0 and d[0].get("name") or None
+
+ def name(self):
+ return self.get_packet_description().get("name")
+
+ def description(self):
+ return self.get_packet_description().get("description")
+
+
+class EbusMasterMaster(EbusPacket):
+ def __init__(self, source, destination, primary_command, secondary_command, data):
+ EbusPacket.__init__(self, source, destination, primary_command, secondary_command)
+ self.length = len(data)
+ self.data = data
+
+class EbusMasterSlave(EbusPacket):
+ def __init__(self, source, destination, primary_command, secondary_command, request, response):
+ EbusPacket.__init__(self, source, destination, primary_command, secondary_command)
+ self.length = len(request)
+ self.request = request
+ self.response = response
+
+ self.data = self.request #XXX
+
+class EbusBroadcast(EbusPacket):
+ def __init__(self, source, destination, primary_command, secondary_command, data):
+ EbusPacket.__init__(self, source, destination, primary_command, secondary_command)
+ self.length = len(data)
+ self.data = data
+
+
+class EbusReader(asynchat.async_chat):
+ def __init__(self):
+ asynchat.async_chat.__init__(self)
+ self.set_terminator("")
+ self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.connect(("10.2.2.200", 7970))
+
+ self.packetIndex = 0
+ self.buf = ""
+ self.debug = False
+
+ def collect_incoming_data(self,data):
+ for it in range(len(data)):
+ if data[it] == "\xaa":
+ if it+1 < len(data) and data[it+1] != "\xaa":
+ self._parse(self.buf)
+ self.buf = ""
+ self.packetIndex = 0
+ else:
+ self.buf += data[it]
+ self.packetIndex = self.packetIndex + 1
+ #print "%.2x [%d]" % (ord(data[it]),self.packetIndex)
+
+ def _parse(self,dataRaw):
+ #0xaa bug
+ i = 0
+ data = ""
+ while (i+1) < len(dataRaw):
+ if ord(dataRaw[i]) == 0xa9 and ord(dataRaw[i+1]) == 0x01:
+ data += "\xaa"
+ i = i + 1
+ elif ord(dataRaw[i]) == 0xa9 and ord(dataRaw[i+1]) == 0x00:
+ data += "\xa9"
+ i = i + 1
+ else:
+ data += dataRaw[i]
+ i = i + 1
+
+ if len(data) < 2:
+ logger.critical("Daten Gaga")
+ return
+ source = ord(data[0])
+ sourceType = EbusPacket.address_to_type(source)
+ destination = ord(data[1])
+ destinationType = EbusPacket.address_to_type(destination)
+
+ if len(data) < 9:
+ logger.critical("Unvollständige Daten")
+ return
+
+ primaryCommand = ord(data[2])
+ secondaryCommand = ord(data[3])
+ payloadLength = ord(data[4])
+ payload = data[5:5+payloadLength]
+
+ if self.debug:
+ print "\033[1;31m%.2x %.2x\033[1;m \033[1;33m%.2x %.2x\033[1;m \033[1;30m%.2x\033[1;m \033[1;45m%s\033[1;m" % (
+ source,
+ destination,
+ primaryCommand,
+ secondaryCommand,
+ payloadLength,
+ " ".join(map(lambda byte: "%.2x"%ord(byte), payload)))
+
+
+ try:
+ if sourceType == 'master' and destinationType == 'master':
+ p = EbusMasterMaster(source, destination, primaryCommand, secondaryCommand, payload)
+ self.handle_ebus(p)
+ elif sourceType == 'master' and destinationType == 'slave':
+ p = EbusMasterSlave(source, destination, primaryCommand, secondaryCommand, payload, None) #FIXME
+ logger.info("SKIP MASTER-SLAVE")
+ elif sourceType == 'master' and destinationType == 'broadcast':
+ p = EbusBroadcast(source, destination, primaryCommand, secondaryCommand, payload)
+ self.handle_ebus(p)
+ else:
+ logger.warning("SKIP source=%s sourceType=%s destination=%s destType=%s" % \
+ (source, sourceType, destination, destinationType))
+ except UnknownPacketException,e:
+ print e
+
+ def handle_ebus(self,ebus_packet):
+ logger.critical("unhandled ebus_packet")