diff --git a/main.py b/main.py new file mode 100644 index 0000000..ed5faff --- /dev/null +++ b/main.py @@ -0,0 +1,8 @@ +import serial + +from metawatch.watch import Watch + +w = Watch(serial.Serial('/dev/rfcomm0')) +print(w.get_device_type()) +print(w.get_rtc()) + diff --git a/metawatch/protocol.py b/metawatch/protocol.py index 6da3003..c0b50bd 100644 --- a/metawatch/protocol.py +++ b/metawatch/protocol.py @@ -1,4 +1,5 @@ import struct +import datetime from functools import reduce # Adapted & Pythonized from pymetawatch by Travis Goodspeed @@ -53,10 +54,97 @@ class OutboundPacket: stream.write(self._data) stream.flush() + class GetDeviceType(OutboundPacket): def __init__(self): - self._generate(1, 0) + self._generate(0x01, 0) -class GetInformationString(OutboundPacket): +class GetRTC(OutboundPacket): def __init__(self): - self._generate(3, 0) + self._generate(0x27, 0) + +class PacketDecodeError(Exception): + pass + + +class TypedInboundPacket: + def __init__(self, inbound): + self._payload = inbound._payload + self._type = inbound._type + self._options = inbound._options + + def _assert_payload_length(self, l): + """Asserts that the received payload is at least `l` bytes long.""" + if len(self._payload) < l: + raise PacketDecodeError("Incorrect payload length! Is {} bytes long, should be at least {}.".format(len(self._payload), l)) + + def _assert_type(self, _type): + if self._type != _type: + raise PacketDecodeError("Incorrect message type! Expected {0:x}, got {1:x}.".format(_type, self._type)) + + +class GetDeviceTypeResponse(TypedInboundPacket): + def parse(self): + self._assert_type(0x02) + self._assert_payload_length(1) + self.device_type = self._payload[0] + + +class GetRTCResponse(TypedInboundPacket): + def parse(self): + self._assert_type(0x28) + self._assert_payload_length(8) + year = (self._payload[1] << 8) | self._payload[0] + month = self._payload[2] + day = self._payload[3] + h, m, s = self._payload[4:7] + dt = datetime.datetime(year=year, month=month, day=day, hour=h, minute=m, second=s) + self.datetime = dt + +class InboundPacket: + PACKET_TYPES = { + 0x02: GetDeviceTypeResponse, + 0x28: GetRTCResponse, + } + def __init__(self, stream): + self._s = stream + + def _start_crc(self): + self._crc_check = [] + + def _read(self, count): + """Gets bytes and saves them to an list for later CRC-Checking.""" + b = self._s.read(count) + self._crc_check += b + return b + + def _end_crc(self): + mspcrc = MSPCRC() + return mspcrc.checksum_bytes(bytes(self._crc_check)) + + def read(self): + self._start_crc() + start, = self._read(1) + if start != 1: + raise PacketDecodeError("Bad start byte (received 0x{0:x}).".format(start)) + length, = self._read(1) + if length > 32 or length < 6: + raise PacketDecodeError("Length not in spec (got {}).".format(length)) + + payload_length = length - 6 + self._type, = self._read(1) + self._options, = self._read(1) + self._payload = self._read(payload_length) + + received_crc, = struct.unpack('