PMPacket.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. '''
  2. Created on 13-04-2013
  3. @author: citan
  4. '''
  5. import array
  6. import binascii
  7. import collections
  8. class PMPacket(object):
  9. '''
  10. classdocs
  11. '''
  12. # 0x80
  13. # destination byte
  14. # source byte
  15. # data size byte
  16. # ...
  17. # checksum byte sum of every byte in packet (incl. header)
  18. _header_byte = 0x80
  19. _valid_bytes = [0xFF, 0xA8, 0xE8]
  20. def __init__(self, dst, src, data):
  21. self._dst = dst
  22. self._src = src
  23. self._data = data
  24. @classmethod
  25. def from_array(cls, data):
  26. validate = PMPacket.is_valid(data)
  27. if (not validate[0]):
  28. raise Exception('packet', validate[1])
  29. dst = data[1]
  30. src = data[2]
  31. data = data[4:-1]
  32. return cls(dst, src, data)
  33. @classmethod
  34. def is_valid(cls, data):
  35. # TODO: check E8
  36. valid = True
  37. msg = ""
  38. valid = valid and (len(data) > 5)
  39. msg += "invalid length (too short), " if (not valid) else ""
  40. valid = valid and (data[0] == PMPacket._header_byte)
  41. msg += "invalid header, " if (not valid) else ""
  42. #valid = data[4] in PMPacket._valid_bytes
  43. #msg += "invalid header, expected one of " + ', '.join(hex(s) for s in PMPacket._valid_bytes) +", got: " + hex(data[4]) + ", " if (not valid) else ""
  44. #valid = valid and ((data[1] == 0x10) or (data[1] == 0xf0))
  45. #valid = valid and ((data[2] == 0x10) or (data[2] == 0xf0))
  46. #valid = valid and (data[1] != data[2])
  47. #msg += "invalid source/target, " if (not valid) else ""
  48. current_len = len(data)
  49. expected_len = 5 + data[3]
  50. valid = valid and (current_len == expected_len)
  51. msg += "invalid length (is: " + str(current_len) + ", expected: " + str(expected_len) + "), " if (not valid) else ""
  52. checksum = 0
  53. for i in range(0, len(data) - 1):
  54. checksum = (checksum + data[i]) & 0xFF
  55. valid = valid and (checksum == data[-1])
  56. msg += "invalid checksum (is " + str(checksum) + ", expected: " + str(data[-1]) + "), " if (not valid) else ""
  57. return valid, msg
  58. def is_equal(self, packet):
  59. return self.to_bytes() == packet.to_bytes()
  60. def to_bytes(self):
  61. length = len(self._data)
  62. packet = [self._header_byte, self._dst, self._src, length]
  63. packet.extend(self._data)
  64. checksum = 0
  65. for b in packet:
  66. checksum = (checksum + b) & 0xFF
  67. packet.append(checksum)
  68. return packet
  69. def to_string(self):
  70. return array.array('B', self.to_bytes()).tostring()
  71. def dump(self):
  72. return "["+ ', '.join(("0x%0.2X" % s) for s in self.to_bytes()) + "], dst: " + hex(self._dst) + ", src: " + hex(self._src) + ", len: " + str(len(self._data))
  73. def get_data(self):
  74. return self._data
  75. def get_destination(self):
  76. return self._dst
  77. def get_source(self):
  78. return self._src
  79. def get_romid(self):
  80. if self._data[0] != 0xFF:
  81. raise Exception('packet', "not valid init response")
  82. if len(self._data) < 9:
  83. raise Exception('packet', "not valid init response")
  84. rom_id = ((self._data[4] << 32) | (self._data[5] << 24) | (self._data[6] << 16) | (self._data[7] << 8) | (self._data[8])) & 0xFFFFFFFFFF
  85. return hex(rom_id).lstrip("0x").upper()
  86. @classmethod
  87. def dump_header(cls, data):
  88. print("header ["+ ', '.join(hex(s) for s in data) +"], len: " + str(len(data)))