From fdf94da4955040dc568a08ce8e32a2be4398355c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergiusz=20=27q3k=27=20Baza=C5=84ski?= Date: Fri, 20 Sep 2013 11:23:48 +0200 Subject: [PATCH] Basic watch communication working. --- main.py | 8 ++++ metawatch/protocol.py | 94 +++++++++++++++++++++++++++++++++++++++++-- metawatch/watch.py | 28 +++++++++++++ tests/test_packets.py | 9 ++++- 4 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 main.py create mode 100644 metawatch/watch.py 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('