code style cleanup
This commit is contained in:
parent
1b8297b809
commit
af23f5fe6f
40 changed files with 1214 additions and 1785 deletions
234
fwupd.py
234
fwupd.py
|
@ -14,137 +14,161 @@ from py9b.command.update import *
|
|||
|
||||
PING_RETRIES = 20
|
||||
|
||||
|
||||
def checksum(s, data):
|
||||
for c in data:
|
||||
s += ord(c)
|
||||
return (s & 0xFFFFFFFF)
|
||||
for c in data:
|
||||
s += ord(c)
|
||||
return s & 0xFFFFFFFF
|
||||
|
||||
|
||||
def UpdateFirmware(link, tran, dev, fwfile):
|
||||
fwfile.seek(0, os.SEEK_END)
|
||||
fw_size = fwfile.tell()
|
||||
fwfile.seek(0)
|
||||
fw_page_size = 0x80
|
||||
fwfile.seek(0, os.SEEK_END)
|
||||
fw_size = fwfile.tell()
|
||||
fwfile.seek(0)
|
||||
fw_page_size = 0x80
|
||||
|
||||
print('Pinging...', end='')
|
||||
for retry in range(PING_RETRIES):
|
||||
print('.', end='')
|
||||
try:
|
||||
if dev==BT.BLE:
|
||||
tran.execute(ReadRegs(dev, 0, '13s'))
|
||||
else:
|
||||
tran.execute(ReadRegs(dev, 0x10, '14s'))
|
||||
except LinkTimeoutException:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
print('Timed out !')
|
||||
return False
|
||||
print('OK')
|
||||
print("Pinging...", end="")
|
||||
for retry in range(PING_RETRIES):
|
||||
print(".", end="")
|
||||
try:
|
||||
if dev == BT.BLE:
|
||||
tran.execute(ReadRegs(dev, 0, "13s"))
|
||||
else:
|
||||
tran.execute(ReadRegs(dev, 0x10, "14s"))
|
||||
except LinkTimeoutException:
|
||||
continue
|
||||
break
|
||||
else:
|
||||
print("Timed out !")
|
||||
return False
|
||||
print("OK")
|
||||
|
||||
if args.interface!='blefleet':
|
||||
print('Locking...')
|
||||
tran.execute(WriteRegs(BT.ESC, 0x70, '<H', 0x0001))
|
||||
else:
|
||||
print('Not Locking...')
|
||||
if args.interface != "blefleet":
|
||||
print("Locking...")
|
||||
tran.execute(WriteRegs(BT.ESC, 0x70, "<H", 0x0001))
|
||||
else:
|
||||
print("Not Locking...")
|
||||
|
||||
print('Starting...')
|
||||
tran.execute(StartUpdate(dev, fw_size))
|
||||
print("Starting...")
|
||||
tran.execute(StartUpdate(dev, fw_size))
|
||||
|
||||
print('Writing...')
|
||||
pb = ProgressBar(maxval=fw_size//fw_page_size+1).start()
|
||||
page = 0
|
||||
chk = 0
|
||||
while fw_size:
|
||||
pb.update(page)
|
||||
chunk_sz = min(fw_size, fw_page_size)
|
||||
data = fwfile.read(chunk_sz)
|
||||
chk = checksum(chk, data)
|
||||
#tran.execute(WriteUpdate(dev, page, data))
|
||||
tran.execute(WriteUpdate(dev, page, data+b'\x00'*(fw_page_size-chunk_sz))) # TODO: Ninebot wants this padding. Will it work on M365 too?
|
||||
page += 1
|
||||
fw_size -= chunk_sz
|
||||
pb.finish()
|
||||
print("Writing...")
|
||||
pb = ProgressBar(maxval=fw_size // fw_page_size + 1).start()
|
||||
page = 0
|
||||
chk = 0
|
||||
while fw_size:
|
||||
pb.update(page)
|
||||
chunk_sz = min(fw_size, fw_page_size)
|
||||
data = fwfile.read(chunk_sz)
|
||||
chk = checksum(chk, data)
|
||||
# tran.execute(WriteUpdate(dev, page, data))
|
||||
tran.execute(
|
||||
WriteUpdate(dev, page, data + b"\x00" * (fw_page_size - chunk_sz))
|
||||
) # TODO: Ninebot wants this padding. Will it work on M365 too?
|
||||
page += 1
|
||||
fw_size -= chunk_sz
|
||||
pb.finish()
|
||||
|
||||
print('Finalizing...')
|
||||
tran.execute(FinishUpdate(dev, chk ^ 0xFFFFFFFF))
|
||||
print("Finalizing...")
|
||||
tran.execute(FinishUpdate(dev, chk ^ 0xFFFFFFFF))
|
||||
|
||||
print("Reboot")
|
||||
tran.execute(RebootUpdate(dev))
|
||||
print("Done")
|
||||
return True
|
||||
|
||||
print('Reboot')
|
||||
tran.execute(RebootUpdate(dev))
|
||||
print('Done')
|
||||
return True
|
||||
|
||||
##########################################################################################
|
||||
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description='Xiaomi/Ninebot firmware flasher',
|
||||
epilog='Example 1: %(prog)s ble ble_patched.bin - flash ble_patched.bin to BLE using default communication parameters'
|
||||
'\nExample 2: %(prog)s -i tcp -a 127.0.1.10:6000 bms bms115.bin - flash bms115.bin to BMS over TCP-BLE bridge at 127.0.1.10:6000'
|
||||
'\nExample 3: %(prog)s -i serial -a COM2 esc CFW.bin - flash CFW.bin to ESC via COM2'
|
||||
'\nExample 4: %(prog)s -i ble -a 12:34:56:78:9A:BC -p ninebot extbms bms107.bin - flash bms107.bin to Ninebot\'s external BMS via BLE, use specified BLE address')
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="Xiaomi/Ninebot firmware flasher",
|
||||
epilog="Example 1: %(prog)s ble ble_patched.bin - flash ble_patched.bin to BLE using default communication parameters"
|
||||
"\nExample 2: %(prog)s -i tcp -a 127.0.1.10:6000 bms bms115.bin - flash bms115.bin to BMS over TCP-BLE bridge at 127.0.1.10:6000"
|
||||
"\nExample 3: %(prog)s -i serial -a COM2 esc CFW.bin - flash CFW.bin to ESC via COM2"
|
||||
"\nExample 4: %(prog)s -i ble -a 12:34:56:78:9A:BC -p ninebot extbms bms107.bin - flash bms107.bin to Ninebot's external BMS via BLE, use specified BLE address",
|
||||
)
|
||||
|
||||
devices = {'ble' : BT.BLE, 'esc' : BT.ESC, 'bms' : BT.BMS, 'extbms' : BT.EXTBMS }
|
||||
parser.add_argument('device', help='target device', type=str.lower, choices=devices)
|
||||
devices = {"ble": BT.BLE, "esc": BT.ESC, "bms": BT.BMS, "extbms": BT.EXTBMS}
|
||||
parser.add_argument("device", help="target device", type=str.lower, choices=devices)
|
||||
|
||||
parser.add_argument('file', type=argparse.FileType('rb'), help='firmware file')
|
||||
parser.add_argument("file", type=argparse.FileType("rb"), help="firmware file")
|
||||
|
||||
parser.add_argument('-i', '--interface', help='communication interface, default: %(default)s', type=str.lower,
|
||||
choices=('ble', 'serial', 'tcp', 'blefleet'), default='ble')
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--interface",
|
||||
help="communication interface, default: %(default)s",
|
||||
type=str.lower,
|
||||
choices=("ble", "serial", "tcp", "blefleet"),
|
||||
default="ble",
|
||||
)
|
||||
|
||||
parser.add_argument('-a', '--address', help='communication address (ble: BDADDR, serial: port, tcp: host:port), default: first available')
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--address",
|
||||
help="communication address (ble: BDADDR, serial: port, tcp: host:port), default: first available",
|
||||
)
|
||||
|
||||
protocols = {'xiaomi' : XiaomiTransport, 'ninebot' : NinebotTransport }
|
||||
parser.add_argument('-p', '--protocol', help='communication protocol, default: %(default)s', type=str.lower,
|
||||
choices=protocols, default='xiaomi')
|
||||
protocols = {"xiaomi": XiaomiTransport, "ninebot": NinebotTransport}
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--protocol",
|
||||
help="communication protocol, default: %(default)s",
|
||||
type=str.lower,
|
||||
choices=protocols,
|
||||
default="xiaomi",
|
||||
)
|
||||
|
||||
if len(argv)==1:
|
||||
parser.print_usage()
|
||||
exit()
|
||||
if len(argv) == 1:
|
||||
parser.print_usage()
|
||||
exit()
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.device=='extbms' and args.protocol!='ninebot':
|
||||
exit('Only Ninebot supports External BMS !')
|
||||
if args.device == "extbms" and args.protocol != "ninebot":
|
||||
exit("Only Ninebot supports External BMS !")
|
||||
|
||||
dev = devices.get(args.device)
|
||||
|
||||
if args.interface=='ble':
|
||||
try:
|
||||
from py9b.link.ble import BLELink
|
||||
except:
|
||||
exit('BLE is not supported on your system !')
|
||||
link = BLELink()
|
||||
elif args.interface=='tcp':
|
||||
from py9b.link.tcp import TCPLink
|
||||
link = TCPLink()
|
||||
elif args.interface=='serial':
|
||||
from py9b.link.serial import SerialLink
|
||||
link = SerialLink()
|
||||
elif args.interface=='blefleet':
|
||||
try:
|
||||
from py9b.link.blefleet import BLELink
|
||||
except:
|
||||
exit('BLE is not supported on your system !')
|
||||
link = BLELink()
|
||||
if args.interface == "ble":
|
||||
try:
|
||||
from py9b.link.ble import BLELink
|
||||
except:
|
||||
exit("BLE is not supported on your system !")
|
||||
link = BLELink()
|
||||
elif args.interface == "tcp":
|
||||
from py9b.link.tcp import TCPLink
|
||||
|
||||
link = TCPLink()
|
||||
elif args.interface == "serial":
|
||||
from py9b.link.serial import SerialLink
|
||||
|
||||
link = SerialLink()
|
||||
elif args.interface == "blefleet":
|
||||
try:
|
||||
from py9b.link.blefleet import BLELink
|
||||
except:
|
||||
exit("BLE is not supported on your system !")
|
||||
link = BLELink()
|
||||
else:
|
||||
exit('!!! BUG !!! Unknown interface selected: '+args.interface)
|
||||
exit("!!! BUG !!! Unknown interface selected: " + args.interface)
|
||||
|
||||
with link:
|
||||
tran = protocols.get(args.protocol)(link)
|
||||
tran = protocols.get(args.protocol)(link)
|
||||
|
||||
if args.address:
|
||||
addr = args.address
|
||||
else:
|
||||
print('Scanning...')
|
||||
ports = link.scan()
|
||||
if not ports:
|
||||
exit("No interfaces found !")
|
||||
print('Connecting to', ports[0][0])
|
||||
addr = ports[0][1]
|
||||
if args.address:
|
||||
addr = args.address
|
||||
else:
|
||||
print("Scanning...")
|
||||
ports = link.scan()
|
||||
if not ports:
|
||||
exit("No interfaces found !")
|
||||
print("Connecting to", ports[0][0])
|
||||
addr = ports[0][1]
|
||||
|
||||
link.open(addr)
|
||||
print('Connected')
|
||||
try:
|
||||
UpdateFirmware(link, tran, dev, args.file)
|
||||
except Exception as e:
|
||||
print('Error:', e)
|
||||
raise
|
||||
link.open(addr)
|
||||
print("Connected")
|
||||
try:
|
||||
UpdateFirmware(link, tran, dev, args.file)
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
raise
|
||||
|
|
32
lock.py
32
lock.py
|
@ -1,31 +1,33 @@
|
|||
#!python2-32
|
||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||
from py9b.link.tcp import TCPLink
|
||||
#from py9b.link.ble import BLELink
|
||||
|
||||
# from py9b.link.ble import BLELink
|
||||
from py9b.link.serial import SerialLink
|
||||
from py9b.transport.base import BaseTransport as BT
|
||||
from py9b.transport.packet import BasePacket as PKT
|
||||
#from py9b.transport.xiaomi import XiaomiTransport
|
||||
|
||||
# from py9b.transport.xiaomi import XiaomiTransport
|
||||
from py9b.transport.ninebot import NinebotTransport
|
||||
from py9b.command.regio import ReadRegs, WriteRegs
|
||||
|
||||
#link = SerialLink(dump=True)
|
||||
# link = SerialLink(dump=True)
|
||||
link = TCPLink()
|
||||
#link = BLELink()
|
||||
# link = BLELink()
|
||||
|
||||
with link:
|
||||
print "Scanning..."
|
||||
ports = link.scan()
|
||||
print ports
|
||||
print("Scanning...")
|
||||
ports = link.scan()
|
||||
print(ports)
|
||||
|
||||
#tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
# tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print "Connected"
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print("Connected")
|
||||
|
||||
print('Locking...')
|
||||
tran.execute(WriteRegs(BT.ESC, 0x70, '<H', 0x0001))
|
||||
print("Locking...")
|
||||
tran.execute(WriteRegs(BT.ESC, 0x70, "<H", 0x0001))
|
||||
|
||||
link.close()
|
||||
link.close()
|
||||
|
|
17
m365_hax.py
17
m365_hax.py
|
@ -18,27 +18,28 @@ with link:
|
|||
link.open(devs[0])
|
||||
|
||||
data = tran.execute(ReadRegs(BT.ESC, 0x68, "<H"))[0]
|
||||
print('BLE version: %04x' % data)
|
||||
print("BLE version: %04x" % data)
|
||||
|
||||
if data >= 0x81:
|
||||
print('Connected, fetching keys...')
|
||||
print("Connected, fetching keys...")
|
||||
keys = link.fetch_keys()
|
||||
tran.keys = keys
|
||||
print('keys:', keys)
|
||||
print("keys:", keys)
|
||||
|
||||
# Recover longer keystream
|
||||
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0x50, data=bytearray([0x20]))
|
||||
tran.send(req)
|
||||
resp = tran.recv()
|
||||
tran.keys += resp.data[9:]
|
||||
print('Got %d bytes of keystream' % (len(tran.keys),))
|
||||
print("Got %d bytes of keystream" % (len(tran.keys),))
|
||||
|
||||
data = tran.execute(ReadRegs(BT.ESC, 0x68, "<H"))
|
||||
print('Version reported after encryption: %04x' % data)
|
||||
print("Version reported after encryption: %04x" % data)
|
||||
|
||||
data = tran.execute(ReadRegs(BT.ESC, 0x1A, "<H"))[0]
|
||||
print('ESC version: %04x' % data)
|
||||
print("ESC version: %04x" % data)
|
||||
data = tran.execute(ReadRegs(BT.BMS, 0x17, "<H"))[0]
|
||||
print('BMS version: %04x' % data)
|
||||
print("BMS version: %04x" % data)
|
||||
|
||||
print('Serial:', tran.execute(ReadRegs(BT.ESC, 0x10, "12s"))[0].decode())
|
||||
print("ESC Serial:", tran.execute(ReadRegs(BT.ESC, 0x10, "12s"))[0].decode())
|
||||
print("BMS Serial:", tran.execute(ReadRegs(BT.BMS, 0x10, "12s"))[0].decode())
|
||||
|
|
34
passwd.py
34
passwd.py
|
@ -1,32 +1,34 @@
|
|||
#!python2-32
|
||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||
from py9b.link.tcp import TCPLink
|
||||
#from py9b.link.ble import BLELink
|
||||
|
||||
# from py9b.link.ble import BLELink
|
||||
from py9b.link.serial import SerialLink
|
||||
from py9b.transport.base import BaseTransport as BT
|
||||
from py9b.transport.packet import BasePacket as PKT
|
||||
#from py9b.transport.xiaomi import XiaomiTransport
|
||||
|
||||
# from py9b.transport.xiaomi import XiaomiTransport
|
||||
from py9b.transport.ninebot import NinebotTransport
|
||||
from py9b.command.regio import ReadRegs, WriteRegs
|
||||
|
||||
#link = SerialLink(dump=True)
|
||||
# link = SerialLink(dump=True)
|
||||
link = TCPLink()
|
||||
#link = BLELink()
|
||||
# link = BLELink()
|
||||
|
||||
with link:
|
||||
print "Scanning..."
|
||||
ports = link.scan()
|
||||
print ports
|
||||
print("Scanning...")
|
||||
ports = link.scan()
|
||||
print(ports)
|
||||
|
||||
#tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
# tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print "Connected"
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print("Connected")
|
||||
|
||||
print 'Reading passwd...'
|
||||
pwd = tran.execute(ReadRegs(BT.ESC, 0x17, "6s"))
|
||||
print "Passwd:", pwd
|
||||
print("Reading passwd...")
|
||||
pwd = tran.execute(ReadRegs(BT.ESC, 0x17, "6s"))
|
||||
print("Passwd:", pwd)
|
||||
|
||||
link.close()
|
||||
link.close()
|
||||
|
|
32
powerdown.py
32
powerdown.py
|
@ -1,31 +1,33 @@
|
|||
#!python2-32
|
||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||
from py9b.link.tcp import TCPLink
|
||||
#from py9b.link.ble import BLELink
|
||||
|
||||
# from py9b.link.ble import BLELink
|
||||
from py9b.link.serial import SerialLink
|
||||
from py9b.transport.base import BaseTransport as BT
|
||||
from py9b.transport.packet import BasePacket as PKT
|
||||
#from py9b.transport.xiaomi import XiaomiTransport
|
||||
|
||||
# from py9b.transport.xiaomi import XiaomiTransport
|
||||
from py9b.transport.ninebot import NinebotTransport
|
||||
from py9b.command.regio import ReadRegs, WriteRegs
|
||||
|
||||
#link = SerialLink(dump=True)
|
||||
# link = SerialLink(dump=True)
|
||||
link = TCPLink()
|
||||
#link = BLELink()
|
||||
# link = BLELink()
|
||||
|
||||
with link:
|
||||
print "Scanning..."
|
||||
ports = link.scan()
|
||||
print ports
|
||||
print("Scanning...")
|
||||
ports = link.scan()
|
||||
print(ports)
|
||||
|
||||
#tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
# tran = XiaomiTransport(link)
|
||||
tran = NinebotTransport(link)
|
||||
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print "Connected"
|
||||
link.open(("127.0.0.20:6000"))
|
||||
# link.open(ports[0][1])
|
||||
print("Connected")
|
||||
|
||||
print('Power off...')
|
||||
tran.execute(WriteRegs(BT.ESC, 0x79, '<H', 0x0001))
|
||||
print("Power off...")
|
||||
tran.execute(WriteRegs(BT.ESC, 0x79, "<H", 0x0001))
|
||||
|
||||
link.close()
|
||||
link.close()
|
||||
|
|
|
@ -3,17 +3,16 @@ from ..transport.base import BaseTransport as BT
|
|||
|
||||
|
||||
class InvalidResponse(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class BaseCommand(object):
|
||||
def __init__(self, src=BT.HOST, dst=0, cmd=0, arg=0, data="", has_response=True):
|
||||
self.has_response = has_response
|
||||
self.request = PKT(src, dst, cmd, arg, data)
|
||||
def __init__(self, src=BT.HOST, dst=0, cmd=0, arg=0, data="", has_response=True):
|
||||
self.has_response = has_response
|
||||
self.request = PKT(src, dst, cmd, arg, data)
|
||||
|
||||
|
||||
def handle_response(self, response):
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
return True
|
||||
|
||||
|
||||
__all__ = ["BaseCommand", "InvalidResponse"]
|
||||
|
|
|
@ -3,15 +3,21 @@ from .base import BaseCommand, InvalidResponse
|
|||
|
||||
|
||||
class ReadMem(BaseCommand):
|
||||
def __init__(self, dev, addr, format):
|
||||
super(ReadMem, self).__init__(dst=dev, cmd=0x80, arg=calcsize(format), data=pack("<H", addr), has_response=True)
|
||||
self.dev = dev
|
||||
self.format = format
|
||||
def __init__(self, dev, addr, format):
|
||||
super(ReadMem, self).__init__(
|
||||
dst=dev,
|
||||
cmd=0x80,
|
||||
arg=calcsize(format),
|
||||
data=pack("<H", addr),
|
||||
has_response=True,
|
||||
)
|
||||
self.dev = dev
|
||||
self.format = format
|
||||
|
||||
def handle_response(self, response):
|
||||
if len(response.data)!=calcsize(self.format):
|
||||
raise InvalidResponse("ReadMem {0:X}".format(self.dev))
|
||||
return unpack(self.format, response.data)
|
||||
def handle_response(self, response):
|
||||
if len(response.data) != calcsize(self.format):
|
||||
raise InvalidResponse("ReadMem {0:X}".format(self.dev))
|
||||
return unpack(self.format, response.data)
|
||||
|
||||
|
||||
__all__=["ReadMem"]
|
||||
__all__ = ["ReadMem"]
|
||||
|
|
|
@ -5,20 +5,22 @@ from .base import BaseCommand, InvalidResponse
|
|||
|
||||
|
||||
class AuthError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class WriteSN(BaseCommand):
|
||||
def __init__(self, dev, sn, auth):
|
||||
super(WriteSN, self).__init__(dst=dev, cmd=0x18, arg=0x10, data=pack("<14sL", sn, auth), has_response=True)
|
||||
self.dev = dev
|
||||
def __init__(self, dev, sn, auth):
|
||||
super(WriteSN, self).__init__(
|
||||
dst=dev, cmd=0x18, arg=0x10, data=pack("<14sL", sn, auth), has_response=True
|
||||
)
|
||||
self.dev = dev
|
||||
|
||||
def handle_response(self, response):
|
||||
if len(response.data)!=0:
|
||||
raise InvalidResponse("WriteSN {0:X}".format(self.dev))
|
||||
if response.arg!=1:
|
||||
raise AuthError("WriteSN {0:X}".format(self.dev))
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
if len(response.data) != 0:
|
||||
raise InvalidResponse("WriteSN {0:X}".format(self.dev))
|
||||
if response.arg != 1:
|
||||
raise AuthError("WriteSN {0:X}".format(self.dev))
|
||||
return True
|
||||
|
||||
|
||||
__all__=["AuthError", "WriteSN"]
|
||||
__all__ = ["AuthError", "WriteSN"]
|
||||
|
|
|
@ -5,42 +5,62 @@ from .base import BaseCommand, InvalidResponse
|
|||
|
||||
|
||||
class ReadRegs(BaseCommand):
|
||||
def __init__(self, dev, reg, format):
|
||||
super(ReadRegs, self).__init__(dst=dev, cmd=0x01, arg=reg, data=pack("<B", calcsize(format)), has_response=True)
|
||||
self.dev = dev
|
||||
self.reg = reg
|
||||
self.format = format
|
||||
def __init__(self, dev, reg, format):
|
||||
super(ReadRegs, self).__init__(
|
||||
dst=dev,
|
||||
cmd=0x01,
|
||||
arg=reg,
|
||||
data=pack("<B", calcsize(format)),
|
||||
has_response=True,
|
||||
)
|
||||
self.dev = dev
|
||||
self.reg = reg
|
||||
self.format = format
|
||||
|
||||
def handle_response(self, response):
|
||||
if response.arg!=self.reg or len(response.data)!=calcsize(self.format):
|
||||
raise InvalidResponse("ReadRegs {0:X}:{1:X}: @{2:X} [{3:X}]".format(self.dev, self.reg, response.arg, len(response.data)))
|
||||
return unpack(self.format, response.data)
|
||||
def handle_response(self, response):
|
||||
if response.arg != self.reg or len(response.data) != calcsize(self.format):
|
||||
raise InvalidResponse(
|
||||
"ReadRegs {0:X}:{1:X}: @{2:X} [{3:X}]".format(
|
||||
self.dev, self.reg, response.arg, len(response.data)
|
||||
)
|
||||
)
|
||||
return unpack(self.format, response.data)
|
||||
|
||||
|
||||
class WriteProtectError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class WriteRegs(BaseCommand):
|
||||
def __init__(self, dev, reg, format, *args):
|
||||
super(WriteRegs, self).__init__(dst=dev, cmd=0x02, arg=reg, data=pack(format, *args), has_response=True)
|
||||
self.dev = dev
|
||||
self.reg = reg
|
||||
def __init__(self, dev, reg, format, *args):
|
||||
super(WriteRegs, self).__init__(
|
||||
dst=dev, cmd=0x02, arg=reg, data=pack(format, *args), has_response=True
|
||||
)
|
||||
self.dev = dev
|
||||
self.reg = reg
|
||||
|
||||
def handle_response(self, response):
|
||||
if response.cmd==0x02: # xiaomi style
|
||||
if response.arg!=self.reg or len(response.data)!=1:
|
||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
if unpack("<B", response.data)[0]!=1:
|
||||
raise WriteProtectError("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
elif response.cmd==0x05: # ninebot style
|
||||
if len(response.data)!=0:
|
||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
if response.arg!=0:
|
||||
raise WriteProtectError("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
else:
|
||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
if response.cmd == 0x02: # xiaomi style
|
||||
if response.arg != self.reg or len(response.data) != 1:
|
||||
raise InvalidResponse(
|
||||
"WriteRegs {0:X}:{1:X}".format(self.dev, self.reg)
|
||||
)
|
||||
if unpack("<B", response.data)[0] != 1:
|
||||
raise WriteProtectError(
|
||||
"WriteRegs {0:X}:{1:X}".format(self.dev, self.reg)
|
||||
)
|
||||
elif response.cmd == 0x05: # ninebot style
|
||||
if len(response.data) != 0:
|
||||
raise InvalidResponse(
|
||||
"WriteRegs {0:X}:{1:X}".format(self.dev, self.reg)
|
||||
)
|
||||
if response.arg != 0:
|
||||
raise WriteProtectError(
|
||||
"WriteRegs {0:X}:{1:X}".format(self.dev, self.reg)
|
||||
)
|
||||
else:
|
||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
||||
return True
|
||||
|
||||
|
||||
__all__=["ReadRegs", "WriteRegs", "WriteProtectError"]
|
||||
__all__ = ["ReadRegs", "WriteRegs", "WriteProtectError"]
|
||||
|
|
|
@ -5,68 +5,98 @@ from .base import BaseCommand, InvalidResponse
|
|||
|
||||
|
||||
# error codes:
|
||||
# 1 - invalid parameter
|
||||
# 2 - erase error
|
||||
# 3 - flash error
|
||||
# 4 - not locked
|
||||
# 5 - address error
|
||||
# 6 - command in progress
|
||||
# 7 - invalid cmd/len
|
||||
UpdateErrorCodes = { 0: 'OK', 1: 'Out of bounds', 2: 'Erase error', 3: 'Write error',
|
||||
4: 'Not locked', 5: 'Invalid address', 6: 'Command in progress', 7: 'Invalid payload len'}
|
||||
# 1 - invalid parameter
|
||||
# 2 - erase error
|
||||
# 3 - flash error
|
||||
# 4 - not locked
|
||||
# 5 - address error
|
||||
# 6 - command in progress
|
||||
# 7 - invalid cmd/len
|
||||
UpdateErrorCodes = {
|
||||
0: "OK",
|
||||
1: "Out of bounds",
|
||||
2: "Erase error",
|
||||
3: "Write error",
|
||||
4: "Not locked",
|
||||
5: "Invalid address",
|
||||
6: "Command in progress",
|
||||
7: "Invalid payload len",
|
||||
}
|
||||
|
||||
|
||||
class UpdateError(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class StartUpdate(BaseCommand):
|
||||
def __init__(self, dev, size):
|
||||
super(StartUpdate, self).__init__(dst=dev, cmd=0x07, data=pack("<L", size), has_response=True)
|
||||
self.dev = dev
|
||||
def __init__(self, dev, size):
|
||||
super(StartUpdate, self).__init__(
|
||||
dst=dev, cmd=0x07, data=pack("<L", size), has_response=True
|
||||
)
|
||||
self.dev = dev
|
||||
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse("StartUpdate {0:X}".format(self.dev))
|
||||
if response.arg!=0:
|
||||
raise UpdateError("StartUpdate {0:X}: {1:s}".format(self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse("StartUpdate {0:X}".format(self.dev))
|
||||
if response.arg != 0:
|
||||
raise UpdateError(
|
||||
"StartUpdate {0:X}: {1:s}".format(
|
||||
self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class WriteUpdate(BaseCommand):
|
||||
def __init__(self, dev, page, data):
|
||||
super(WriteUpdate, self).__init__(dst=dev, cmd=0x08, arg=page & 0xFF, data=data, has_response=True)
|
||||
self.dev = dev
|
||||
self.page = page
|
||||
def __init__(self, dev, page, data):
|
||||
super(WriteUpdate, self).__init__(
|
||||
dst=dev, cmd=0x08, arg=page & 0xFF, data=data, has_response=True
|
||||
)
|
||||
self.dev = dev
|
||||
self.page = page
|
||||
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse("WriteUpdate {0:X} @{1:X}".format(self.dev, self.page))
|
||||
if response.arg!=0:
|
||||
raise UpdateError("WriteUpdate {0:X} @{1:X}: {2:s}".format(self.dev, self.page, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse(
|
||||
"WriteUpdate {0:X} @{1:X}".format(self.dev, self.page)
|
||||
)
|
||||
if response.arg != 0:
|
||||
raise UpdateError(
|
||||
"WriteUpdate {0:X} @{1:X}: {2:s}".format(
|
||||
self.dev,
|
||||
self.page,
|
||||
UpdateErrorCodes.get(response.arg, str(response.arg)),
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class FinishUpdate(BaseCommand):
|
||||
def __init__(self, dev, checksum):
|
||||
super(FinishUpdate, self).__init__(dst=dev, cmd=0x09, data=pack("<L", checksum), has_response=True)
|
||||
self.dev = dev
|
||||
def __init__(self, dev, checksum):
|
||||
super(FinishUpdate, self).__init__(
|
||||
dst=dev, cmd=0x09, data=pack("<L", checksum), has_response=True
|
||||
)
|
||||
self.dev = dev
|
||||
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse("FinishUpdate {0:X}".format(self.dev))
|
||||
if response.arg!=0:
|
||||
raise UpdateError("FinishUpdate {0:X}: {1:s}".format(self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
if not len(response.data) in (0, 1):
|
||||
raise InvalidResponse("FinishUpdate {0:X}".format(self.dev))
|
||||
if response.arg != 0:
|
||||
raise UpdateError(
|
||||
"FinishUpdate {0:X}: {1:s}".format(
|
||||
self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
class RebootUpdate(BaseCommand):
|
||||
def __init__(self, dev):
|
||||
super(RebootUpdate, self).__init__(dst=dev, cmd=0x0A, has_response=False)
|
||||
self.dev = dev
|
||||
def __init__(self, dev):
|
||||
super(RebootUpdate, self).__init__(dst=dev, cmd=0x0A, has_response=False)
|
||||
self.dev = dev
|
||||
|
||||
def handle_response(self, response):
|
||||
return True
|
||||
def handle_response(self, response):
|
||||
return True
|
||||
|
||||
|
||||
__all__ = ["UpdateError", "StartUpdate", "WriteUpdate", "FinishUpdate", "RebootUpdate"]
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
"""BLE link using BlueGiga adapter via PyGatt/BGAPI"""
|
||||
|
||||
|
||||
import pygatt
|
||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||
from binascii import hexlify
|
||||
|
||||
SCAN_TIMEOUT = 3
|
||||
|
||||
|
||||
try:
|
||||
import queue
|
||||
except ImportError:
|
||||
import queue as 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 range(size):
|
||||
res += chr(self.q.get(True, timeout))
|
||||
return res
|
||||
|
||||
|
||||
#_cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
||||
_rx_char_uuid = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
|
||||
_tx_char_uuid = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'
|
||||
|
||||
_write_chunk_size = 20 # as in android dumps
|
||||
|
||||
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()
|
||||
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)
|
||||
for dev in devices:
|
||||
if dev['name'].startswith(('MISc', 'NBSc')):
|
||||
res.append((dev['name'], dev['address']))
|
||||
return res
|
||||
|
||||
|
||||
def open(self, port):
|
||||
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
|
||||
if self._adapter:
|
||||
self._adapter.stop()
|
||||
|
||||
|
||||
def read(self, 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
|
||||
|
||||
|
||||
def write(self, data):
|
||||
if self.dump:
|
||||
print('>', hexlify(data).upper())
|
||||
size = len(data)
|
||||
ofs = 0
|
||||
while size:
|
||||
chunk_sz = min(size, _write_chunk_size)
|
||||
self._dev.char_write_handle(self._wr_handle, bytearray(data[ofs:ofs+chunk_sz]))
|
||||
ofs += chunk_sz
|
||||
size -= chunk_sz
|
||||
|
||||
|
||||
__all__ = ['BLELink']
|
|
@ -1,109 +0,0 @@
|
|||
"""BLE link using BlueGiga adapter via PyGatt/BGAPI"""
|
||||
|
||||
|
||||
import pygatt
|
||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||
from binascii import hexlify
|
||||
|
||||
SCAN_TIMEOUT = 3
|
||||
|
||||
|
||||
try:
|
||||
import queue
|
||||
except ImportError:
|
||||
import queue as 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 range(size):
|
||||
res += chr(self.q.get(True, timeout))
|
||||
return res
|
||||
|
||||
|
||||
#_cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
||||
_rx_char_uuid = eval(input('RX UUID?'))
|
||||
_tx_char_uuid = eval(input('TX UUID?'))
|
||||
_write_chunk_size = 20 # as in android dumps
|
||||
|
||||
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()
|
||||
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)
|
||||
for dev in devices:
|
||||
if dev['name'].startswith(('MISc', 'NBSc')):
|
||||
res.append((dev['name'], dev['address']))
|
||||
return res
|
||||
|
||||
|
||||
def open(self, port):
|
||||
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
|
||||
if self._adapter:
|
||||
self._adapter.stop()
|
||||
|
||||
|
||||
def read(self, 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
|
||||
|
||||
|
||||
def write(self, data):
|
||||
if self.dump:
|
||||
print('>', hexlify(data).upper())
|
||||
size = len(data)
|
||||
ofs = 0
|
||||
while size:
|
||||
chunk_sz = min(size, _write_chunk_size)
|
||||
self._dev.char_write_handle(self._wr_handle, bytearray(data[ofs:ofs+chunk_sz]))
|
||||
ofs += chunk_sz
|
||||
size -= chunk_sz
|
||||
|
||||
|
||||
__all__ = ['BLELink']
|
|
@ -1,243 +0,0 @@
|
|||
"""BLE link using ABLE"""
|
||||
|
||||
|
||||
try:
|
||||
from able import GATT_SUCCESS, Advertisement, BluetoothDispatcher
|
||||
except ImportError:
|
||||
exit('error importing able')
|
||||
try:
|
||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||
except ImportError:
|
||||
exit('error importing .base')
|
||||
from binascii import hexlify
|
||||
from kivy.logger import Logger
|
||||
from kivy.properties import StringProperty
|
||||
|
||||
try:
|
||||
import queue
|
||||
except ImportError:
|
||||
import queue as queue
|
||||
|
||||
SCAN_TIMEOUT = 3
|
||||
|
||||
_write_chunk_size = 20
|
||||
|
||||
identity = bytearray([
|
||||
0x4e, 0x42, 0x21, 0x00, 0x00, 0x00, 0x00, 0xDE, # Ninebot Bluetooth ID 4E422100000000DE
|
||||
0x4e, 0x42, 0x21, 0x00, 0x00, 0x00, 0x00, 0xDF # Xiaomi Bluetooth ID 4E422100000000DF
|
||||
])
|
||||
|
||||
service_ids = {
|
||||
'retail': '6e400001-b5a3-f393-e0a9-e50e24dcca9e' #service UUID
|
||||
}
|
||||
|
||||
receive_ids = {
|
||||
'retail': '6e400002-b5a3-f393-e0a9-e50e24dcca9e' #receive characteristic UUID
|
||||
}
|
||||
|
||||
transmit_ids = {
|
||||
'retail': '6e400003-b5a3-f393-e0a9-e50e24dcca9e' #transmit characteristic UUID
|
||||
}
|
||||
|
||||
scoot_found = False
|
||||
|
||||
|
||||
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 range(size):
|
||||
res += chr(self.q.get(True, timeout))
|
||||
return res
|
||||
|
||||
|
||||
class ScootBT(BluetoothDispatcher):
|
||||
def __init__(self):
|
||||
super(ScootBT, self).__init__()
|
||||
self.rx_fifo = Fifo()
|
||||
self.ble_device = None
|
||||
self.state = StringProperty()
|
||||
self.dump = True
|
||||
self.tx_characteristic = None
|
||||
self.rx_characteristic = None
|
||||
self.timeout = SCAN_TIMEOUT
|
||||
self.set_queue_timeout(self.timeout)
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def discover(self):
|
||||
self.start_scan()
|
||||
self.state = 'scan'
|
||||
print((self.state))
|
||||
|
||||
|
||||
def on_device(self, device, rssi, advertisement):
|
||||
global scoot_found
|
||||
if self.state != 'scan':
|
||||
return
|
||||
Logger.debug("on_device event {}".format(list(advertisement)))
|
||||
self.addr = device.getAddress()
|
||||
if self.addr and address.startswith(self.addr):
|
||||
print((self.addr))
|
||||
self.ble_device = device
|
||||
self.scoot_found = True
|
||||
self.stop_scan()
|
||||
else:
|
||||
for ad in advertisement:
|
||||
print(ad)
|
||||
if ad.ad_type == Advertisement.ad_types.manufacturer_specific_data:
|
||||
if ad.data.startswith(self.identity):
|
||||
scoot_found = True
|
||||
else:
|
||||
break
|
||||
elif ad.ad_type == Advertisement.ad_types.complete_local_name:
|
||||
name = str(ad.data)
|
||||
if scoot_found:
|
||||
self.state = 'found'
|
||||
print((self.state))
|
||||
self.ble_device = device
|
||||
Logger.debug("Scooter detected: {}".format(name))
|
||||
self.stop_scan()
|
||||
|
||||
|
||||
def on_scan_completed(self):
|
||||
if self.ble_device:
|
||||
self.connect_gatt(self.ble_device)
|
||||
self.state = 'connected'
|
||||
print((self.state))
|
||||
else:
|
||||
self.start_scan()
|
||||
|
||||
|
||||
def on_connection_state_change(self, status, state):
|
||||
if status == GATT_SUCCESS and state:
|
||||
self.discover_services()
|
||||
self.state = 'discover'
|
||||
print((self.state))
|
||||
else:
|
||||
self.close_gatt()
|
||||
self.rx_characteristic = None
|
||||
self.tx_characteristic = None
|
||||
self.services = None
|
||||
|
||||
|
||||
def on_services(self, status, services):
|
||||
self.services = services
|
||||
for uuid in list(receive_ids.values()):
|
||||
self.rx_characteristic = self.services.search(uuid)
|
||||
print(('RX: '+uuid))
|
||||
for uuid in list(transmit_ids.values()):
|
||||
self.tx_characteristic = self.services.search(uuid)
|
||||
print(('TX: '+uuid))
|
||||
self.enable_notifications(self.tx_characteristic)
|
||||
|
||||
|
||||
def on_characteristic_changed(self, characteristic):
|
||||
if characteristic == self.tx_characteristic:
|
||||
data = characteristic.getValue()
|
||||
self.rx_fifo.write(data)
|
||||
|
||||
|
||||
def open(self, port):
|
||||
self.addr = port
|
||||
if self.ble_device == None:
|
||||
self.discover()
|
||||
if self.state!='connected':
|
||||
self.connect_gatt(self.ble_device)
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def close(self):
|
||||
if self.ble_device != None:
|
||||
self.close_gatt()
|
||||
self.services = None
|
||||
print('close')
|
||||
|
||||
|
||||
def read(self, size):
|
||||
print('read')
|
||||
if self.ble_device:
|
||||
try:
|
||||
data = self.rx_fifo.read(size, timeout=self.timeout)
|
||||
except queue.Empty:
|
||||
raise LinkTimeoutException
|
||||
if self.dump:
|
||||
print('<', hexlify(data).upper())
|
||||
return data
|
||||
else:
|
||||
print('BLE not connected')
|
||||
self.discover()
|
||||
|
||||
|
||||
def write(self, data):
|
||||
print('write')
|
||||
if self.ble_device:
|
||||
if self.dump:
|
||||
print('>', hexlify(data).upper())
|
||||
size = len(data)
|
||||
ofs = 0
|
||||
while size:
|
||||
chunk_sz = min(size, _write_chunk_size)
|
||||
self.write_characteristic(self.rx_characteristic, bytearray(data[ofs:ofs+chunk_sz]))
|
||||
ofs += chunk_sz
|
||||
size -= chunk_sz
|
||||
else:
|
||||
print('BLE not connected')
|
||||
self.discover()
|
||||
|
||||
|
||||
def scan(self):
|
||||
self.discover()
|
||||
|
||||
|
||||
class BLELink(BaseLink):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BLELink, self).__init__(*args, **kwargs)
|
||||
self._adapter = None
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
self._adapter = ScootBT()
|
||||
self._adapter.discover()
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def scan(self):
|
||||
devices = self._adapter.scan()
|
||||
|
||||
|
||||
def open(self, port):
|
||||
self._adapter.open(port)
|
||||
|
||||
|
||||
def close(self):
|
||||
self._adapter.close()
|
||||
|
||||
|
||||
def read(self, size):
|
||||
self._adapter.read(size)
|
||||
|
||||
|
||||
def write(self, data):
|
||||
self._adapter.write(data)
|
||||
|
||||
|
||||
__all__ = ['BLELink']
|
|
@ -1,61 +0,0 @@
|
|||
"""Direct serial link"""
|
||||
|
||||
|
||||
import serial
|
||||
import serial.tools.list_ports as lp
|
||||
from binascii import hexlify
|
||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||
|
||||
|
||||
class SerialLink(BaseLink):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SerialLink, self).__init__(*args, **kwargs)
|
||||
self.com = None
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def scan(self):
|
||||
ports = lp.comports()
|
||||
res = [("%s %04X:%04X" % (port.device, port.vid, port.pid), port.device) for port in ports]
|
||||
return res
|
||||
|
||||
|
||||
def open(self, port):
|
||||
try:
|
||||
self.com = serial.Serial(port, 115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=self.timeout)
|
||||
except serial.SerialException:
|
||||
raise LinkOpenException
|
||||
|
||||
|
||||
def close(self):
|
||||
if self.com:
|
||||
self.com.close()
|
||||
self.com = None
|
||||
|
||||
|
||||
def read(self, size):
|
||||
try:
|
||||
data = self.com.read(size)
|
||||
except serial.SerialTimeoutException:
|
||||
raise LinkTimeoutException
|
||||
if len(data)<size:
|
||||
raise LinkTimeoutException
|
||||
if self.dump:
|
||||
print("<", hexlify(data).upper())
|
||||
return data
|
||||
|
||||
|
||||
def write(self, data):
|
||||
if self.dump:
|
||||
print(">", hexlify(data).upper())
|
||||
self.com.write(data)
|
||||
|
||||
|
||||
__all__ = ["SerialLink"]
|
|
@ -1,80 +0,0 @@
|
|||
"""TCP-BLE bridge link"""
|
||||
|
||||
import socket
|
||||
from binascii import hexlify
|
||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||
|
||||
HOST, PORT = "127.0.0.1", 6000
|
||||
|
||||
_write_chunk_size = 20 # 20 as in android dumps
|
||||
|
||||
def recvall(sock, size):
|
||||
data = ""
|
||||
while len(data)<size:
|
||||
try:
|
||||
pkt = sock.recv(size-len(data))
|
||||
except socket.timeout:
|
||||
raise LinkTimeoutException()
|
||||
data+=pkt
|
||||
return data
|
||||
|
||||
|
||||
class TCPLink(BaseLink):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TCPLink, self).__init__(*args, **kwargs)
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.settimeout(self.timeout)
|
||||
self.connected = False
|
||||
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
|
||||
def scan(self):
|
||||
res = [("Android UART Bridge", HOST+':'+str(PORT))]
|
||||
return res
|
||||
|
||||
|
||||
def open(self, port):
|
||||
p = port.partition(':')
|
||||
host = p[0]
|
||||
port = int(p[2], 10)
|
||||
print(host, port)
|
||||
try:
|
||||
self.sock.connect((host, port))
|
||||
except socket.timeout:
|
||||
raise LinkOpenException
|
||||
self.connected = True
|
||||
|
||||
|
||||
def close(self):
|
||||
if self.connected:
|
||||
self.sock.close()
|
||||
self.connected = False
|
||||
|
||||