diff --git a/py9b/link/ble.py b/py9b/link/ble.py index 2dca97e..06c8ec8 100644 --- a/py9b/link/ble.py +++ b/py9b/link/ble.py @@ -2,29 +2,61 @@ from __future__ import absolute_import import pygatt +from .base import BaseLink, LinkTimeoutException, LinkOpenException from binascii import hexlify + +SCAN_TIMEOUT = 3 + + +import queue + +class Fifo(): + def __init__(self): + self.q = queue.Queue() + + def write(self, data): # put bytes + for b in data: + self.q.put(b) + + def read(self, size=1, timeout=None): # but read string + res = "" + for i in xrange(size): + res += chr(self.q.get(True, timeout)) + return res + -SCAN_TIMEOUT = 3 +#_cccd_uuid = "00002902-0000-1000-8000-00805f9b34fb" +_rx_char_uuid = "6e400002-b5a3-f393-e0a9-e50e24dcca9e" +_tx_char_uuid = "6e400003-b5a3-f393-e0a9-e50e24dcca9e" -class BLELink(): - def __init__(self, dump=False): - self.dev = None - self.dump = dump +class BLELink(BaseLink): + def __init__(self, *args, **kwargs): + super(BLELink, self).__init__(*args, **kwargs) + self._adapter = None + self._dev = None + self._wr_handle = None + self._rx_fifo = Fifo() def __enter__(self): - self.adapter = pygatt.BGAPIBackend() - self.adapter.start() + self._adapter = pygatt.BGAPIBackend() + self._adapter.start() return self def __exit__(self, exc_type, exc_value, traceback): self.close() + + def _make_rx_cb(self): # this is a closure :) + def rx_cb(handle, value): + self._rx_fifo.write(value) + return rx_cb + def scan(self): res = [] - devices = self.adapter.scan(timeout=SCAN_TIMEOUT) + devices = self._adapter.scan(timeout=SCAN_TIMEOUT) for dev in devices: if dev["name"].startswith(u"MISc"): res.append((dev["name"], dev["address"])) @@ -32,18 +64,27 @@ class BLELink(): def open(self, port): - self.dev = self.adapter.connect(port, address_type=pygatt.BLEAddressType.random) - + try: + self._dev = self._adapter.connect(port, address_type=pygatt.BLEAddressType.random) + self._dev.subscribe(_tx_char_uuid, callback=self._make_rx_cb()) + self._wr_handle = self._dev.get_handle(_rx_char_uuid) + except pygatt.exceptions.NotConnectedError: + raise LinkOpenException + def close(self): - if self.dev: - self.dev.disconnect() - self.dev = None - self.adapter.stop() + if self._dev: + self._dev.disconnect() + self._dev = None + if self._adapter: + self._adapter.stop() def read(self, size): - data = self.dev.read(size) + try: + data = self._rx_fifo.read(size, timeout=self.timeout) + except queue.Empty: + raise LinkTimeoutException if self.dump: print "<", hexlify(data).upper() return data @@ -52,7 +93,7 @@ class BLELink(): def write(self, data): if self.dump: print ">", hexlify(data).upper() - return self.dev.write(data) + self._dev.char_write_handle(self._wr_handle, bytearray(data)) __all__ = ["BLELink"] diff --git a/py9b/link/serial.py b/py9b/link/serial.py index 3de0552..21a1548 100644 --- a/py9b/link/serial.py +++ b/py9b/link/serial.py @@ -7,7 +7,7 @@ from binascii import hexlify from .base import BaseLink, LinkTimeoutException, LinkOpenException -class SerialLink(): +class SerialLink(BaseLink): def __init__(self, *args, **kwargs): super(SerialLink, self).__init__(*args, **kwargs) self.com = None diff --git a/py9b/transport/xiaomi.py b/py9b/transport/xiaomi.py index ae8f106..1896929 100644 --- a/py9b/transport/xiaomi.py +++ b/py9b/transport/xiaomi.py @@ -5,28 +5,34 @@ from .packet import BasePacket class XiaomiTransport(BT): - HEAD2ESC = 0x20 - ESC2HEAD = 0x23 - HEAD2BMS = 0x22 - BMS2HEAD = 0x25 - DEV01 = 0x01 + MASTER2ESC = 0x20 + ESC2MASTER = 0x23 - _SaDa2Addr = { BT.HOST : { BT.DEV01 : DEV01, BT.ESC : HEAD2ESC, BT.BMS : HEAD2BMS }, - BT.ESC : { BT.HOST : ESC2HEAD, BT.BMS : HEAD2BMS, BT.DEV01 : DEV01 }, - BT.BMS : { BT.HOST : BMS2HEAD, BT.ESC : BMS2HEAD, BT.DEV01 : DEV01 }, + MASTER2BLE = 0x21 + BLE2MASTER = 0x24 + + MASTER2BMS = 0x22 + BMS2MASTER = 0x25 + + DEV01 = 0x01 + DEVFF = 0xFF + + _SaDa2Addr = { BT.HOST : { BT.DEV01 : DEV01, BT.ESC : MASTER2ESC, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS }, + BT.ESC : { BT.HOST : ESC2MASTER, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS, BT.DEV01 : DEV01 }, + BT.BMS : { BT.HOST : BMS2MASTER, BT.ESC : BMS2MASTER, BT.DEV01 : DEV01 }, BT.DEV01 : {BT.HOST : DEV01, BT.ESC : DEV01, BT.BMS : DEV01 } } # TBC - _BleAddr2SaDa = { HEAD2ESC : (BT.HOST, BT.ESC), - ESC2HEAD : (BT.ESC, BT.HOST), - HEAD2BMS : (BT.HOST, BT.BMS), - BMS2HEAD : (BT.BMS, BT.HOST), + _BleAddr2SaDa = { MASTER2ESC : (BT.HOST, BT.ESC), + ESC2MASTER : (BT.ESC, BT.HOST), + MASTER2BMS : (BT.HOST, BT.BMS), + BMS2MASTER : (BT.BMS, BT.HOST), DEV01 : (BT.DEV01, BT.HOST) } - _BmsAddr2SaDa = { HEAD2ESC : (BT.BMS, BT.ESC), - ESC2HEAD : (BT.ESC, BT.BMS), - HEAD2BMS : (BT.ESC, BT.BMS), - BMS2HEAD : (BT.BMS, BT.ESC), + _BmsAddr2SaDa = { MASTER2ESC : (BT.BMS, BT.ESC), + ESC2MASTER : (BT.ESC, BT.BMS), + MASTER2BMS : (BT.ESC, BT.BMS), + BMS2MASTER : (BT.BMS, BT.ESC), DEV01 : (BT.DEV01, BT.BMS) } diff --git a/read_esc.py b/read_esc.py new file mode 100644 index 0000000..2c0f96a --- /dev/null +++ b/read_esc.py @@ -0,0 +1,41 @@ +from py9b.link.base import LinkOpenException, LinkTimeoutException +from py9b.link.tcp import TCPLink +from py9b.link.ble import BLELink +from py9b.transport.base import BaseTransport as BT +from py9b.transport.packet import BasePacket as PKT +from py9b.transport.xiaomi import XiaomiTransport + +READ_CHUNK_SIZE = 0x40 + +#link = SerialLink() +#link = TCPLink() +link = BLELink() + +with link: + print "Scanning..." + ports = link.scan() + print ports + + tran = XiaomiTransport(link) + + #link.open(("192.168.1.45", 6000)) + link.open(ports[0][1]) + print "Connected" + + req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x01, reg=0, data=chr(READ_CHUNK_SIZE)) + + hfo = open("EscRegs.bin", "wb") + for i in xrange(0, 0x200, READ_CHUNK_SIZE): + print ".", + req.reg = i>>1 + for retry in xrange(3): + tran.send(req) + try: + rsp = tran.recv() + except LinkTimeoutException: + continue + break + hfo.write(rsp.data) + + hfo.close() + link.close()