155 lines
4.6 KiB
Python
155 lines
4.6 KiB
Python
|
'''
|
||
|
Created on 11.06.2015
|
||
|
|
||
|
@author: wn
|
||
|
'''
|
||
|
|
||
|
import MeterbusTypeConversion
|
||
|
|
||
|
class MeterbusLibException(Exception):
|
||
|
pass
|
||
|
|
||
|
class InvalidFrameCodeException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidFrameException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidChecksumException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidStopCharException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidStartCharException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidLengthException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class InvalidSecondLengthException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class PayloadTooShortException(MeterbusLibException):
|
||
|
pass
|
||
|
|
||
|
class Frame(object):
|
||
|
def __init__(self, startCharacter, frameLength, firstPayload, telegram):
|
||
|
self.telegram = telegram
|
||
|
self.frameName = self.__class__.__name__
|
||
|
self.frameLength = frameLength
|
||
|
self.payloadLength = self.frameLength - 6
|
||
|
self.frameStartCharacter = startCharacter
|
||
|
self.firstPayload = firstPayload
|
||
|
|
||
|
def parse(self):
|
||
|
if self.telegram[0] != self.frameStartCharacter:
|
||
|
raise InvalidStartCharException()
|
||
|
if len(self.telegram) != self.frameLength:
|
||
|
raise InvalidLengthException()
|
||
|
self.verifyChecksumAndEnd()
|
||
|
self.parse2()
|
||
|
|
||
|
def verifyChecksumAndEnd(self):
|
||
|
if (self.firstPayload != 0):
|
||
|
checksum = sum(self.telegram[self.firstPayload:-2]) & 0xff
|
||
|
if checksum != self.telegram[-2]:
|
||
|
raise InvalidChecksumException()
|
||
|
if self.telegram[-1] != 0x16:
|
||
|
raise InvalidStopCharException()
|
||
|
|
||
|
def parse2(self):
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def getJSON(self):
|
||
|
raise NotImplementedError
|
||
|
|
||
|
|
||
|
class SingleCharacter(Frame):
|
||
|
def __init__(self, telegram):
|
||
|
super(SingleCharacter, self).__init__(0xe5, 1, 0, telegram)
|
||
|
|
||
|
def parse2(self):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class ShortFrame(Frame):
|
||
|
def __init__(self, telegram):
|
||
|
super(ShortFrame, self).__init__(0x10, 5, 1, telegram)
|
||
|
|
||
|
def parse2(self):
|
||
|
self.cField = self.telegram[1]
|
||
|
self.address = self.telegram[2]
|
||
|
|
||
|
|
||
|
class ControlFrame(Frame):
|
||
|
def __init__(self, telegram):
|
||
|
super(ControlFrame, self).__init__(0x68, (telegram[1] + 6), 4, telegram)
|
||
|
|
||
|
def parse2(self):
|
||
|
if self.telegram[2] != self.payloadLength:
|
||
|
raise InvalidSecondLengthException
|
||
|
if self.payloadLength < 3:
|
||
|
raise PayloadTooShortException("too short for c, a, ci fields")
|
||
|
self.cField = self.telegram[4]
|
||
|
self.address = self.telegram[5]
|
||
|
self.ciField = self.telegram[6]
|
||
|
|
||
|
|
||
|
class LongFrame(ControlFrame):
|
||
|
class FixedDataHeader(object):
|
||
|
def __init__(self, data):
|
||
|
self.data = data
|
||
|
print("Fixed header length: %d" % len(self.data))
|
||
|
|
||
|
def parse(self):
|
||
|
self.identNr = MeterbusTypeConversion.bcd(self.data[:4])
|
||
|
self.manufacturer = self.data[4:6]
|
||
|
self.version = self.data[6]
|
||
|
self.medium = self.data[7]
|
||
|
self.accessNo = self.data[8]
|
||
|
self.status = self.data[9]
|
||
|
self.signature = self.data[10:]
|
||
|
|
||
|
def parse2(self):
|
||
|
super(LongFrame, self).parse2()
|
||
|
if self.payloadLength < 3 + 12:
|
||
|
raise PayloadTooShortException("too short for fixed data header")
|
||
|
self.fixedDataHeader = LongFrame.FixedDataHeader(self.telegram[7:19])
|
||
|
self.fixedDataHeader.parse()
|
||
|
|
||
|
|
||
|
class Telegram(object):
|
||
|
def __init__(self):
|
||
|
pass
|
||
|
|
||
|
def fromHexString(self, hexString):
|
||
|
self.hexString = hexString
|
||
|
octetList = [int(o, 16) for o in self.hexString.split(' ')]
|
||
|
self.telegram = bytearray(octetList)
|
||
|
|
||
|
for i in self.telegram:
|
||
|
print(int(i))
|
||
|
|
||
|
def toHexString(self):
|
||
|
return str([hex(b) for b in self.telegram])
|
||
|
|
||
|
def parse(self):
|
||
|
if self.telegram[0] == 0x68 and self.telegram[1] == 0x03:
|
||
|
self.frame = ControlFrame(self.telegram)
|
||
|
elif self.telegram[0] == 0x68:
|
||
|
self.frame = LongFrame(self.telegram)
|
||
|
elif self.telegram[0] == 0x10:
|
||
|
self.frame = ShortFrame(self.telegram)
|
||
|
elif self.telegram[0] == 0xe5:
|
||
|
self.frame = SingleCharacter(self.telegram)
|
||
|
else:
|
||
|
raise InvalidStartCharException()
|
||
|
|
||
|
self.frame.parse()
|
||
|
|
||
|
print("Frame is %s" % self.frame)
|
||
|
|
||
|
|
||
|
|