code style cleanup
parent
1b8297b809
commit
af23f5fe6f
234
fwupd.py
234
fwupd.py
|
@ -14,137 +14,161 @@ from py9b.command.update import *
|
||||||
|
|
||||||
PING_RETRIES = 20
|
PING_RETRIES = 20
|
||||||
|
|
||||||
|
|
||||||
def checksum(s, data):
|
def checksum(s, data):
|
||||||
for c in data:
|
for c in data:
|
||||||
s += ord(c)
|
s += ord(c)
|
||||||
return (s & 0xFFFFFFFF)
|
return s & 0xFFFFFFFF
|
||||||
|
|
||||||
|
|
||||||
def UpdateFirmware(link, tran, dev, fwfile):
|
def UpdateFirmware(link, tran, dev, fwfile):
|
||||||
fwfile.seek(0, os.SEEK_END)
|
fwfile.seek(0, os.SEEK_END)
|
||||||
fw_size = fwfile.tell()
|
fw_size = fwfile.tell()
|
||||||
fwfile.seek(0)
|
fwfile.seek(0)
|
||||||
fw_page_size = 0x80
|
fw_page_size = 0x80
|
||||||
|
|
||||||
print('Pinging...', end='')
|
print("Pinging...", end="")
|
||||||
for retry in range(PING_RETRIES):
|
for retry in range(PING_RETRIES):
|
||||||
print('.', end='')
|
print(".", end="")
|
||||||
try:
|
try:
|
||||||
if dev==BT.BLE:
|
if dev == BT.BLE:
|
||||||
tran.execute(ReadRegs(dev, 0, '13s'))
|
tran.execute(ReadRegs(dev, 0, "13s"))
|
||||||
else:
|
else:
|
||||||
tran.execute(ReadRegs(dev, 0x10, '14s'))
|
tran.execute(ReadRegs(dev, 0x10, "14s"))
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print('Timed out !')
|
print("Timed out !")
|
||||||
return False
|
return False
|
||||||
print('OK')
|
print("OK")
|
||||||
|
|
||||||
if args.interface!='blefleet':
|
if args.interface != "blefleet":
|
||||||
print('Locking...')
|
print("Locking...")
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x70, '<H', 0x0001))
|
tran.execute(WriteRegs(BT.ESC, 0x70, "<H", 0x0001))
|
||||||
else:
|
else:
|
||||||
print('Not Locking...')
|
print("Not Locking...")
|
||||||
|
|
||||||
print('Starting...')
|
print("Starting...")
|
||||||
tran.execute(StartUpdate(dev, fw_size))
|
tran.execute(StartUpdate(dev, fw_size))
|
||||||
|
|
||||||
print('Writing...')
|
print("Writing...")
|
||||||
pb = ProgressBar(maxval=fw_size//fw_page_size+1).start()
|
pb = ProgressBar(maxval=fw_size // fw_page_size + 1).start()
|
||||||
page = 0
|
page = 0
|
||||||
chk = 0
|
chk = 0
|
||||||
while fw_size:
|
while fw_size:
|
||||||
pb.update(page)
|
pb.update(page)
|
||||||
chunk_sz = min(fw_size, fw_page_size)
|
chunk_sz = min(fw_size, fw_page_size)
|
||||||
data = fwfile.read(chunk_sz)
|
data = fwfile.read(chunk_sz)
|
||||||
chk = checksum(chk, data)
|
chk = checksum(chk, data)
|
||||||
#tran.execute(WriteUpdate(dev, page, 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?
|
tran.execute(
|
||||||
page += 1
|
WriteUpdate(dev, page, data + b"\x00" * (fw_page_size - chunk_sz))
|
||||||
fw_size -= chunk_sz
|
) # TODO: Ninebot wants this padding. Will it work on M365 too?
|
||||||
pb.finish()
|
page += 1
|
||||||
|
fw_size -= chunk_sz
|
||||||
|
pb.finish()
|
||||||
|
|
||||||
print('Finalizing...')
|
print("Finalizing...")
|
||||||
tran.execute(FinishUpdate(dev, chk ^ 0xFFFFFFFF))
|
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,
|
parser = argparse.ArgumentParser(
|
||||||
description='Xiaomi/Ninebot firmware flasher',
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
epilog='Example 1: %(prog)s ble ble_patched.bin - flash ble_patched.bin to BLE using default communication parameters'
|
description="Xiaomi/Ninebot firmware flasher",
|
||||||
'\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'
|
epilog="Example 1: %(prog)s ble ble_patched.bin - flash ble_patched.bin to BLE using default communication parameters"
|
||||||
'\nExample 3: %(prog)s -i serial -a COM2 esc CFW.bin - flash CFW.bin to ESC via COM2'
|
"\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 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')
|
"\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 }
|
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("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,
|
parser.add_argument(
|
||||||
choices=('ble', 'serial', 'tcp', 'blefleet'), default='ble')
|
"-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 }
|
protocols = {"xiaomi": XiaomiTransport, "ninebot": NinebotTransport}
|
||||||
parser.add_argument('-p', '--protocol', help='communication protocol, default: %(default)s', type=str.lower,
|
parser.add_argument(
|
||||||
choices=protocols, default='xiaomi')
|
"-p",
|
||||||
|
"--protocol",
|
||||||
|
help="communication protocol, default: %(default)s",
|
||||||
|
type=str.lower,
|
||||||
|
choices=protocols,
|
||||||
|
default="xiaomi",
|
||||||
|
)
|
||||||
|
|
||||||
if len(argv)==1:
|
if len(argv) == 1:
|
||||||
parser.print_usage()
|
parser.print_usage()
|
||||||
exit()
|
exit()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.device=='extbms' and args.protocol!='ninebot':
|
if args.device == "extbms" and args.protocol != "ninebot":
|
||||||
exit('Only Ninebot supports External BMS !')
|
exit("Only Ninebot supports External BMS !")
|
||||||
|
|
||||||
dev = devices.get(args.device)
|
dev = devices.get(args.device)
|
||||||
|
|
||||||
if args.interface=='ble':
|
if args.interface == "ble":
|
||||||
try:
|
try:
|
||||||
from py9b.link.ble import BLELink
|
from py9b.link.ble import BLELink
|
||||||
except:
|
except:
|
||||||
exit('BLE is not supported on your system !')
|
exit("BLE is not supported on your system !")
|
||||||
link = BLELink()
|
link = BLELink()
|
||||||
elif args.interface=='tcp':
|
elif args.interface == "tcp":
|
||||||
from py9b.link.tcp import TCPLink
|
from py9b.link.tcp import TCPLink
|
||||||
link = TCPLink()
|
|
||||||
elif args.interface=='serial':
|
link = TCPLink()
|
||||||
from py9b.link.serial import SerialLink
|
elif args.interface == "serial":
|
||||||
link = SerialLink()
|
from py9b.link.serial import SerialLink
|
||||||
elif args.interface=='blefleet':
|
|
||||||
try:
|
link = SerialLink()
|
||||||
from py9b.link.blefleet import BLELink
|
elif args.interface == "blefleet":
|
||||||
except:
|
try:
|
||||||
exit('BLE is not supported on your system !')
|
from py9b.link.blefleet import BLELink
|
||||||
link = BLELink()
|
except:
|
||||||
|
exit("BLE is not supported on your system !")
|
||||||
|
link = BLELink()
|
||||||
else:
|
else:
|
||||||
exit('!!! BUG !!! Unknown interface selected: '+args.interface)
|
exit("!!! BUG !!! Unknown interface selected: " + args.interface)
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
tran = protocols.get(args.protocol)(link)
|
tran = protocols.get(args.protocol)(link)
|
||||||
|
|
||||||
if args.address:
|
if args.address:
|
||||||
addr = args.address
|
addr = args.address
|
||||||
else:
|
else:
|
||||||
print('Scanning...')
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
if not ports:
|
if not ports:
|
||||||
exit("No interfaces found !")
|
exit("No interfaces found !")
|
||||||
print('Connecting to', ports[0][0])
|
print("Connecting to", ports[0][0])
|
||||||
addr = ports[0][1]
|
addr = ports[0][1]
|
||||||
|
|
||||||
link.open(addr)
|
link.open(addr)
|
||||||
print('Connected')
|
print("Connected")
|
||||||
try:
|
try:
|
||||||
UpdateFirmware(link, tran, dev, args.file)
|
UpdateFirmware(link, tran, dev, args.file)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Error:', e)
|
print("Error:", e)
|
||||||
raise
|
raise
|
||||||
|
|
32
lock.py
32
lock.py
|
@ -1,31 +1,33 @@
|
||||||
#!python2-32
|
#!python2-32
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
from py9b.link.tcp import TCPLink
|
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.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
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.transport.ninebot import NinebotTransport
|
||||||
from py9b.command.regio import ReadRegs, WriteRegs
|
from py9b.command.regio import ReadRegs, WriteRegs
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.20:6000"))
|
link.open(("127.0.0.20:6000"))
|
||||||
# link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
print('Locking...')
|
print("Locking...")
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x70, '<H', 0x0001))
|
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])
|
link.open(devs[0])
|
||||||
|
|
||||||
data = tran.execute(ReadRegs(BT.ESC, 0x68, "<H"))[0]
|
data = tran.execute(ReadRegs(BT.ESC, 0x68, "<H"))[0]
|
||||||
print('BLE version: %04x' % data)
|
print("BLE version: %04x" % data)
|
||||||
|
|
||||||
if data >= 0x81:
|
if data >= 0x81:
|
||||||
print('Connected, fetching keys...')
|
print("Connected, fetching keys...")
|
||||||
keys = link.fetch_keys()
|
keys = link.fetch_keys()
|
||||||
tran.keys = keys
|
tran.keys = keys
|
||||||
print('keys:', keys)
|
print("keys:", keys)
|
||||||
|
|
||||||
# Recover longer keystream
|
# Recover longer keystream
|
||||||
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0x50, data=bytearray([0x20]))
|
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0x50, data=bytearray([0x20]))
|
||||||
tran.send(req)
|
tran.send(req)
|
||||||
resp = tran.recv()
|
resp = tran.recv()
|
||||||
tran.keys += resp.data[9:]
|
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"))
|
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]
|
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]
|
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
|
#!python2-32
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
from py9b.link.tcp import TCPLink
|
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.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
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.transport.ninebot import NinebotTransport
|
||||||
from py9b.command.regio import ReadRegs, WriteRegs
|
from py9b.command.regio import ReadRegs, WriteRegs
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.20:6000"))
|
link.open(("127.0.0.20:6000"))
|
||||||
# link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
print 'Reading passwd...'
|
print("Reading passwd...")
|
||||||
pwd = tran.execute(ReadRegs(BT.ESC, 0x17, "6s"))
|
pwd = tran.execute(ReadRegs(BT.ESC, 0x17, "6s"))
|
||||||
print "Passwd:", pwd
|
print("Passwd:", pwd)
|
||||||
|
|
||||||
link.close()
|
link.close()
|
||||||
|
|
32
powerdown.py
32
powerdown.py
|
@ -1,31 +1,33 @@
|
||||||
#!python2-32
|
#!python2-32
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
from py9b.link.tcp import TCPLink
|
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.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
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.transport.ninebot import NinebotTransport
|
||||||
from py9b.command.regio import ReadRegs, WriteRegs
|
from py9b.command.regio import ReadRegs, WriteRegs
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.20:6000"))
|
link.open(("127.0.0.20:6000"))
|
||||||
# link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
print('Power off...')
|
print("Power off...")
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x79, '<H', 0x0001))
|
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):
|
class InvalidResponse(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BaseCommand(object):
|
class BaseCommand(object):
|
||||||
def __init__(self, src=BT.HOST, dst=0, cmd=0, arg=0, data="", has_response=True):
|
def __init__(self, src=BT.HOST, dst=0, cmd=0, arg=0, data="", has_response=True):
|
||||||
self.has_response = has_response
|
self.has_response = has_response
|
||||||
self.request = PKT(src, dst, cmd, arg, data)
|
self.request = PKT(src, dst, cmd, arg, data)
|
||||||
|
|
||||||
|
def handle_response(self, response):
|
||||||
def handle_response(self, response):
|
return True
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BaseCommand", "InvalidResponse"]
|
__all__ = ["BaseCommand", "InvalidResponse"]
|
||||||
|
|
|
@ -3,15 +3,21 @@ from .base import BaseCommand, InvalidResponse
|
||||||
|
|
||||||
|
|
||||||
class ReadMem(BaseCommand):
|
class ReadMem(BaseCommand):
|
||||||
def __init__(self, dev, addr, 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)
|
super(ReadMem, self).__init__(
|
||||||
self.dev = dev
|
dst=dev,
|
||||||
self.format = format
|
cmd=0x80,
|
||||||
|
arg=calcsize(format),
|
||||||
|
data=pack("<H", addr),
|
||||||
|
has_response=True,
|
||||||
|
)
|
||||||
|
self.dev = dev
|
||||||
|
self.format = format
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if len(response.data)!=calcsize(self.format):
|
if len(response.data) != calcsize(self.format):
|
||||||
raise InvalidResponse("ReadMem {0:X}".format(self.dev))
|
raise InvalidResponse("ReadMem {0:X}".format(self.dev))
|
||||||
return unpack(self.format, response.data)
|
return unpack(self.format, response.data)
|
||||||
|
|
||||||
|
|
||||||
__all__=["ReadMem"]
|
__all__ = ["ReadMem"]
|
||||||
|
|
|
@ -5,20 +5,22 @@ from .base import BaseCommand, InvalidResponse
|
||||||
|
|
||||||
|
|
||||||
class AuthError(Exception):
|
class AuthError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class WriteSN(BaseCommand):
|
class WriteSN(BaseCommand):
|
||||||
def __init__(self, dev, sn, auth):
|
def __init__(self, dev, sn, auth):
|
||||||
super(WriteSN, self).__init__(dst=dev, cmd=0x18, arg=0x10, data=pack("<14sL", sn, auth), has_response=True)
|
super(WriteSN, self).__init__(
|
||||||
self.dev = dev
|
dst=dev, cmd=0x18, arg=0x10, data=pack("<14sL", sn, auth), has_response=True
|
||||||
|
)
|
||||||
|
self.dev = dev
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if len(response.data)!=0:
|
if len(response.data) != 0:
|
||||||
raise InvalidResponse("WriteSN {0:X}".format(self.dev))
|
raise InvalidResponse("WriteSN {0:X}".format(self.dev))
|
||||||
if response.arg!=1:
|
if response.arg != 1:
|
||||||
raise AuthError("WriteSN {0:X}".format(self.dev))
|
raise AuthError("WriteSN {0:X}".format(self.dev))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
__all__=["AuthError", "WriteSN"]
|
__all__ = ["AuthError", "WriteSN"]
|
||||||
|
|
|
@ -5,42 +5,62 @@ from .base import BaseCommand, InvalidResponse
|
||||||
|
|
||||||
|
|
||||||
class ReadRegs(BaseCommand):
|
class ReadRegs(BaseCommand):
|
||||||
def __init__(self, dev, reg, 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)
|
super(ReadRegs, self).__init__(
|
||||||
self.dev = dev
|
dst=dev,
|
||||||
self.reg = reg
|
cmd=0x01,
|
||||||
self.format = format
|
arg=reg,
|
||||||
|
data=pack("<B", calcsize(format)),
|
||||||
|
has_response=True,
|
||||||
|
)
|
||||||
|
self.dev = dev
|
||||||
|
self.reg = reg
|
||||||
|
self.format = format
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if response.arg!=self.reg or len(response.data)!=calcsize(self.format):
|
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)))
|
raise InvalidResponse(
|
||||||
return unpack(self.format, response.data)
|
"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):
|
class WriteProtectError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class WriteRegs(BaseCommand):
|
class WriteRegs(BaseCommand):
|
||||||
def __init__(self, dev, reg, format, *args):
|
def __init__(self, dev, reg, format, *args):
|
||||||
super(WriteRegs, self).__init__(dst=dev, cmd=0x02, arg=reg, data=pack(format, *args), has_response=True)
|
super(WriteRegs, self).__init__(
|
||||||
self.dev = dev
|
dst=dev, cmd=0x02, arg=reg, data=pack(format, *args), has_response=True
|
||||||
self.reg = reg
|
)
|
||||||
|
self.dev = dev
|
||||||
|
self.reg = reg
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if response.cmd==0x02: # xiaomi style
|
if response.cmd == 0x02: # xiaomi style
|
||||||
if response.arg!=self.reg or len(response.data)!=1:
|
if response.arg != self.reg or len(response.data) != 1:
|
||||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
raise InvalidResponse(
|
||||||
if unpack("<B", response.data)[0]!=1:
|
"WriteRegs {0:X}:{1:X}".format(self.dev, self.reg)
|
||||||
raise WriteProtectError("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
)
|
||||||
elif response.cmd==0x05: # ninebot style
|
if unpack("<B", response.data)[0] != 1:
|
||||||
if len(response.data)!=0:
|
raise WriteProtectError(
|
||||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
"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))
|
elif response.cmd == 0x05: # ninebot style
|
||||||
else:
|
if len(response.data) != 0:
|
||||||
raise InvalidResponse("WriteRegs {0:X}:{1:X}".format(self.dev, self.reg))
|
raise InvalidResponse(
|
||||||
return True
|
"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:
|
# error codes:
|
||||||
# 1 - invalid parameter
|
# 1 - invalid parameter
|
||||||
# 2 - erase error
|
# 2 - erase error
|
||||||
# 3 - flash error
|
# 3 - flash error
|
||||||
# 4 - not locked
|
# 4 - not locked
|
||||||
# 5 - address error
|
# 5 - address error
|
||||||
# 6 - command in progress
|
# 6 - command in progress
|
||||||
# 7 - invalid cmd/len
|
# 7 - invalid cmd/len
|
||||||
UpdateErrorCodes = { 0: 'OK', 1: 'Out of bounds', 2: 'Erase error', 3: 'Write error',
|
UpdateErrorCodes = {
|
||||||
4: 'Not locked', 5: 'Invalid address', 6: 'Command in progress', 7: 'Invalid payload len'}
|
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):
|
class UpdateError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StartUpdate(BaseCommand):
|
class StartUpdate(BaseCommand):
|
||||||
def __init__(self, dev, size):
|
def __init__(self, dev, size):
|
||||||
super(StartUpdate, self).__init__(dst=dev, cmd=0x07, data=pack("<L", size), has_response=True)
|
super(StartUpdate, self).__init__(
|
||||||
self.dev = dev
|
dst=dev, cmd=0x07, data=pack("<L", size), has_response=True
|
||||||
|
)
|
||||||
|
self.dev = dev
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if not len(response.data) in (0, 1):
|
if not len(response.data) in (0, 1):
|
||||||
raise InvalidResponse("StartUpdate {0:X}".format(self.dev))
|
raise InvalidResponse("StartUpdate {0:X}".format(self.dev))
|
||||||
if response.arg!=0:
|
if response.arg != 0:
|
||||||
raise UpdateError("StartUpdate {0:X}: {1:s}".format(self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
raise UpdateError(
|
||||||
return True
|
"StartUpdate {0:X}: {1:s}".format(
|
||||||
|
self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class WriteUpdate(BaseCommand):
|
class WriteUpdate(BaseCommand):
|
||||||
def __init__(self, dev, page, data):
|
def __init__(self, dev, page, data):
|
||||||
super(WriteUpdate, self).__init__(dst=dev, cmd=0x08, arg=page & 0xFF, data=data, has_response=True)
|
super(WriteUpdate, self).__init__(
|
||||||
self.dev = dev
|
dst=dev, cmd=0x08, arg=page & 0xFF, data=data, has_response=True
|
||||||
self.page = page
|
)
|
||||||
|
self.dev = dev
|
||||||
|
self.page = page
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if not len(response.data) in (0, 1):
|
if not len(response.data) in (0, 1):
|
||||||
raise InvalidResponse("WriteUpdate {0:X} @{1:X}".format(self.dev, self.page))
|
raise InvalidResponse(
|
||||||
if response.arg!=0:
|
"WriteUpdate {0:X} @{1:X}".format(self.dev, self.page)
|
||||||
raise UpdateError("WriteUpdate {0:X} @{1:X}: {2:s}".format(self.dev, self.page, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
)
|
||||||
return True
|
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):
|
class FinishUpdate(BaseCommand):
|
||||||
def __init__(self, dev, checksum):
|
def __init__(self, dev, checksum):
|
||||||
super(FinishUpdate, self).__init__(dst=dev, cmd=0x09, data=pack("<L", checksum), has_response=True)
|
super(FinishUpdate, self).__init__(
|
||||||
self.dev = dev
|
dst=dev, cmd=0x09, data=pack("<L", checksum), has_response=True
|
||||||
|
)
|
||||||
|
self.dev = dev
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
if not len(response.data) in (0, 1):
|
if not len(response.data) in (0, 1):
|
||||||
raise InvalidResponse("FinishUpdate {0:X}".format(self.dev))
|
raise InvalidResponse("FinishUpdate {0:X}".format(self.dev))
|
||||||
if response.arg!=0:
|
if response.arg != 0:
|
||||||
raise UpdateError("FinishUpdate {0:X}: {1:s}".format(self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))))
|
raise UpdateError(
|
||||||
return True
|
"FinishUpdate {0:X}: {1:s}".format(
|
||||||
|
self.dev, UpdateErrorCodes.get(response.arg, str(response.arg))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class RebootUpdate(BaseCommand):
|
class RebootUpdate(BaseCommand):
|
||||||
def __init__(self, dev):
|
def __init__(self, dev):
|
||||||
super(RebootUpdate, self).__init__(dst=dev, cmd=0x0A, has_response=False)
|
super(RebootUpdate, self).__init__(dst=dev, cmd=0x0A, has_response=False)
|
||||||
self.dev = dev
|
self.dev = dev
|
||||||
|
|
||||||
def handle_response(self, response):
|
def handle_response(self, response):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["UpdateError", "StartUpdate", "WriteUpdate", "FinishUpdate", "RebootUpdate"]
|
__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
|
|
||||||
|
|
||||||
|
|
||||||
def read(self, size):
|
|
||||||
data = recvall(self.sock, size)
|
|
||||||
if data and 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.sock.sendall(data[ofs:ofs+chunk_sz])
|
|
||||||
ofs += chunk_sz
|
|
||||||
size -= chunk_sz
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["TCPLink"]
|
|
|
@ -1,34 +1,32 @@
|
||||||
class LinkTimeoutException(Exception):
|
class LinkTimeoutException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class LinkOpenException(Exception):
|
class LinkOpenException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BaseLink(object):
|
class BaseLink(object):
|
||||||
DEF_TIMEOUT = 1
|
DEF_TIMEOUT = 1
|
||||||
|
|
||||||
def __init__(self, timeout=DEF_TIMEOUT, dump=False):
|
def __init__(self, timeout=DEF_TIMEOUT, dump=False):
|
||||||
self.dump = dump
|
self.dump = dump
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def open(self, port):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def open(self, port):
|
def close(self):
|
||||||
raise NotImplementedError()
|
pass
|
||||||
|
|
||||||
|
def read(self, size):
|
||||||
def close(self):
|
raise NotImplementedError()
|
||||||
pass
|
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def read(self, size):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def write(self, data):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["LinkTimeoutException", "LinkOpenException", "BaseLink"]
|
__all__ = ["LinkTimeoutException", "LinkOpenException", "BaseLink"]
|
||||||
|
|
|
@ -13,26 +13,28 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import Queue as queue
|
import Queue as queue
|
||||||
|
|
||||||
class Fifo():
|
|
||||||
|
class Fifo:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.q = queue.Queue()
|
self.q = queue.Queue()
|
||||||
|
|
||||||
def write(self, data): # put bytes
|
def write(self, data): # put bytes
|
||||||
for b in data:
|
for b in data:
|
||||||
self.q.put(b)
|
self.q.put(b)
|
||||||
|
|
||||||
def read(self, size=1, timeout=None): # but read string
|
def read(self, size=1, timeout=None): # but read string
|
||||||
res = ''
|
res = ""
|
||||||
for i in xrange(size):
|
for i in xrange(size):
|
||||||
res += chr(self.q.get(True, timeout))
|
res += chr(self.q.get(True, timeout))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
#_cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
# _cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
||||||
_rx_char_uuid = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
|
_rx_char_uuid = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
|
||||||
_tx_char_uuid = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'
|
_tx_char_uuid = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
|
||||||
|
|
||||||
|
_write_chunk_size = 20 # as in android dumps
|
||||||
|
|
||||||
_write_chunk_size = 20 # as in android dumps
|
|
||||||
|
|
||||||
class BLELink(BaseLink):
|
class BLELink(BaseLink):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -42,42 +44,41 @@ class BLELink(BaseLink):
|
||||||
self._wr_handle = None
|
self._wr_handle = None
|
||||||
self._rx_fifo = Fifo()
|
self._rx_fifo = Fifo()
|
||||||
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._adapter = pygatt.GATTToolBackend()
|
self._adapter = pygatt.GATTToolBackend()
|
||||||
self._adapter.start()
|
self._adapter.start()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
def _make_rx_cb(self): # this is a closure :)
|
||||||
def _make_rx_cb(self): # this is a closure :)
|
|
||||||
def rx_cb(handle, value):
|
def rx_cb(handle, value):
|
||||||
self._rx_fifo.write(value)
|
self._rx_fifo.write(value)
|
||||||
return rx_cb
|
|
||||||
|
|
||||||
|
return rx_cb
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
res = []
|
res = []
|
||||||
self._adapter.reset()
|
self._adapter.reset()
|
||||||
devices = self._adapter.scan(timeout=SCAN_TIMEOUT)
|
devices = self._adapter.scan(timeout=SCAN_TIMEOUT)
|
||||||
for dev in devices:
|
for dev in devices:
|
||||||
if dev['name'] and dev['name'].startswith((u'MISc', u'NBSc', u'JP2', u'Seg')):
|
if dev["name"] and dev["name"].startswith(
|
||||||
res.append((dev['name'], dev['address']))
|
(u"MISc", u"NBSc", u"JP2", u"Seg")
|
||||||
|
):
|
||||||
|
res.append((dev["name"], dev["address"]))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def open(self, port):
|
def open(self, port):
|
||||||
try:
|
try:
|
||||||
self._dev = self._adapter.connect(port, address_type=pygatt.BLEAddressType.random)
|
self._dev = self._adapter.connect(
|
||||||
|
port, address_type=pygatt.BLEAddressType.random
|
||||||
|
)
|
||||||
self._dev.subscribe(_tx_char_uuid, callback=self._make_rx_cb())
|
self._dev.subscribe(_tx_char_uuid, callback=self._make_rx_cb())
|
||||||
self._wr_handle = self._dev.get_handle(_rx_char_uuid)
|
self._wr_handle = self._dev.get_handle(_rx_char_uuid)
|
||||||
except pygatt.exceptions.NotConnectedError:
|
except pygatt.exceptions.NotConnectedError:
|
||||||
raise LinkOpenException
|
raise LinkOpenException
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self._dev:
|
if self._dev:
|
||||||
self._dev.disconnect()
|
self._dev.disconnect()
|
||||||
|
@ -85,27 +86,27 @@ class BLELink(BaseLink):
|
||||||
if self._adapter:
|
if self._adapter:
|
||||||
self._adapter.stop()
|
self._adapter.stop()
|
||||||
|
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
try:
|
try:
|
||||||
data = self._rx_fifo.read(size, timeout=self.timeout)
|
data = self._rx_fifo.read(size, timeout=self.timeout)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
raise LinkTimeoutException
|
raise LinkTimeoutException
|
||||||
if self.dump:
|
if self.dump:
|
||||||
print('<', hexlify(data).upper())
|
print("<", hexlify(data).upper())
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
if self.dump:
|
if self.dump:
|
||||||
print('>', hexlify(data).upper())
|
print(">", hexlify(data).upper())
|
||||||
size = len(data)
|
size = len(data)
|
||||||
ofs = 0
|
ofs = 0
|
||||||
while size:
|
while size:
|
||||||
chunk_sz = min(size, _write_chunk_size)
|
chunk_sz = min(size, _write_chunk_size)
|
||||||
self._dev.char_write_handle(self._wr_handle, bytearray(data[ofs:ofs+chunk_sz]))
|
self._dev.char_write_handle(
|
||||||
|
self._wr_handle, bytearray(data[ofs : ofs + chunk_sz])
|
||||||
|
)
|
||||||
ofs += chunk_sz
|
ofs += chunk_sz
|
||||||
size -= chunk_sz
|
size -= chunk_sz
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['BLELink']
|
__all__ = ["BLELink"]
|
||||||
|
|
|
@ -4,24 +4,25 @@ from bleak import discover, BleakClient
|
||||||
from py9b.link.base import BaseLink
|
from py9b.link.base import BaseLink
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
_rx_char_uuid = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'
|
_rx_char_uuid = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
|
||||||
_tx_char_uuid = '6e400003-b5a3-f393-e0a9-e50e24dcca9e'
|
_tx_char_uuid = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
|
||||||
_keys_char_uuid = '00000014-0000-1000-8000-00805f9b34fb'
|
_keys_char_uuid = "00000014-0000-1000-8000-00805f9b34fb"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import queue
|
import queue
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import Queue as queue
|
import Queue as queue
|
||||||
|
|
||||||
class Fifo():
|
|
||||||
|
class Fifo:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.q = queue.Queue()
|
self.q = queue.Queue()
|
||||||
|
|
||||||
def write(self, data): # put bytes
|
def write(self, data): # put bytes
|
||||||
for b in data:
|
for b in data:
|
||||||
self.q.put(b)
|
self.q.put(b)
|
||||||
|
|
||||||
def read(self, size=1, timeout=None): # but read string
|
def read(self, size=1, timeout=None): # but read string
|
||||||
res = bytearray()
|
res = bytearray()
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
res.append(self.q.get(True, timeout))
|
res.append(self.q.get(True, timeout))
|
||||||
|
@ -29,12 +30,13 @@ class Fifo():
|
||||||
|
|
||||||
|
|
||||||
def run_worker(loop):
|
def run_worker(loop):
|
||||||
print('Starting event loop', loop)
|
print("Starting event loop", loop)
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
loop.run_forever()
|
loop.run_forever()
|
||||||
|
|
||||||
|
|
||||||
class BleakLink(BaseLink):
|
class BleakLink(BaseLink):
|
||||||
def __init__(self, device='hci0', loop=None, *args, **kwargs):
|
def __init__(self, device="hci0", loop=None, *args, **kwargs):
|
||||||
self.device = device
|
self.device = device
|
||||||
self.timeout = 5
|
self.timeout = 5
|
||||||
self.loop = loop or asyncio.get_event_loop()
|
self.loop = loop or asyncio.get_event_loop()
|
||||||
|
@ -59,11 +61,19 @@ class BleakLink(BaseLink):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
asyncio.run_coroutine_threadsafe(self._client.disconnect(), self.loop).result(10)
|
asyncio.run_coroutine_threadsafe(self._client.disconnect(), self.loop).result(
|
||||||
|
10
|
||||||
|
)
|
||||||
|
|
||||||
def scan(self, timeout=1):
|
def scan(self, timeout=1):
|
||||||
future = asyncio.run_coroutine_threadsafe(discover(timeout=timeout, device=self.device), self.loop)
|
future = asyncio.run_coroutine_threadsafe(
|
||||||
return [(dev.name, dev.address) for dev in future.result(timeout*2) if dev.name.startswith(('MISc', 'NBSc'))]
|
discover(timeout=timeout, device=self.device), self.loop
|
||||||
|
)
|
||||||
|
return [
|
||||||
|
(dev.name, dev.address)
|
||||||
|
for dev in future.result(timeout * 2)
|
||||||
|
if dev.name.startswith(("MISc", "NBSc"))
|
||||||
|
]
|
||||||
|
|
||||||
def open(self, port):
|
def open(self, port):
|
||||||
fut = asyncio.run_coroutine_threadsafe(self._connect(port), self.loop)
|
fut = asyncio.run_coroutine_threadsafe(self._connect(port), self.loop)
|
||||||
|
@ -72,17 +82,20 @@ class BleakLink(BaseLink):
|
||||||
async def _connect(self, port):
|
async def _connect(self, port):
|
||||||
self._client = BleakClient(port[1], device=self.device)
|
self._client = BleakClient(port[1], device=self.device)
|
||||||
await self._client.connect()
|
await self._client.connect()
|
||||||
print('connected')
|
print("connected")
|
||||||
await self._client.start_notify(_tx_char_uuid, self._data_received)
|
await self._client.start_notify(_tx_char_uuid, self._data_received)
|
||||||
print('services:', list(await self._client.get_services()))
|
print("services:", list(await self._client.get_services()))
|
||||||
|
|
||||||
def _data_received(self, sender, data):
|
def _data_received(self, sender, data):
|
||||||
print('<<', ' '.join(map(lambda b: '%02x' % b, data)))
|
print("<<", " ".join(map(lambda b: "%02x" % b, data)))
|
||||||
self._rx_fifo.write(data)
|
self._rx_fifo.write(data)
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
print('>>', ' '.join(map(lambda b: '%02x' % b, data)))
|
print(">>", " ".join(map(lambda b: "%02x" % b, data)))
|
||||||
fut = asyncio.run_coroutine_threadsafe(self._client.write_gatt_char(_rx_char_uuid, bytearray(data), False), self.loop)
|
fut = asyncio.run_coroutine_threadsafe(
|
||||||
|
self._client.write_gatt_char(_rx_char_uuid, bytearray(data), False),
|
||||||
|
self.loop,
|
||||||
|
)
|
||||||
return fut.result(3)
|
return fut.result(3)
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
|
@ -93,4 +106,6 @@ class BleakLink(BaseLink):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def fetch_keys(self):
|
def fetch_keys(self):
|
||||||
return asyncio.run_coroutine_threadsafe(self._client.read_gatt_char(_keys_char_uuid), self.loop).result(5)
|
return asyncio.run_coroutine_threadsafe(
|
||||||
|
self._client.read_gatt_char(_keys_char_uuid), self.loop
|
||||||
|
).result(5)
|
||||||
|
|
|
@ -9,101 +9,100 @@ SCAN_TIMEOUT = 3
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import queue
|
import queue
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import Queue as queue
|
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 xrange(size):
|
|
||||||
res += chr(self.q.get(True, timeout))
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
#_cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
class Fifo:
|
||||||
_rx_char_uuid = input('RX UUID?')
|
def __init__(self):
|
||||||
_tx_char_uuid = input('TX UUID?')
|
self.q = queue.Queue()
|
||||||
_write_chunk_size = 20 # as in android dumps
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# _cccd_uuid = '00002902-0000-1000-8000-00805f9b34fb'
|
||||||
|
_rx_char_uuid = input("RX UUID?")
|
||||||
|
_tx_char_uuid = input("TX UUID?")
|
||||||
|
_write_chunk_size = 20 # as in android dumps
|
||||||
|
|
||||||
|
|
||||||
class BLELink(BaseLink):
|
class BLELink(BaseLink):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(BLELink, self).__init__(*args, **kwargs)
|
super(BLELink, self).__init__(*args, **kwargs)
|
||||||
self._adapter = None
|
self._adapter = None
|
||||||
self._dev = None
|
self._dev = None
|
||||||
self._wr_handle = None
|
self._wr_handle = None
|
||||||
self._rx_fifo = Fifo()
|
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((u"MISc", u"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
|
||||||
|
|
||||||
|
|
||||||
def __enter__(self):
|
__all__ = ["BLELink"]
|
||||||
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((u'MISc', u'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,14 +1,15 @@
|
||||||
"""BLE link using ABLE"""
|
"""BLE link using ABLE"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from able import GATT_SUCCESS, Advertisement, BluetoothDispatcher
|
from able import GATT_SUCCESS, Advertisement, BluetoothDispatcher
|
||||||
except ImportError:
|
except ImportError:
|
||||||
exit('error importing able')
|
exit("error importing able")
|
||||||
try:
|
try:
|
||||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||||
except ImportError:
|
except ImportError:
|
||||||
exit('error importing .base')
|
exit("error importing .base")
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from kivy.logger import Logger
|
from kivy.logger import Logger
|
||||||
from kivy.properties import StringProperty
|
from kivy.properties import StringProperty
|
||||||
|
@ -22,36 +23,50 @@ SCAN_TIMEOUT = 3
|
||||||
|
|
||||||
_write_chunk_size = 20
|
_write_chunk_size = 20
|
||||||
|
|
||||||
identity = bytearray([
|
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
|
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 = {
|
service_ids = {"retail": "6e400001-b5a3-f393-e0a9-e50e24dcca9e"} # service UUID
|
||||||
'retail': '6e400001-b5a3-f393-e0a9-e50e24dcca9e' #service UUID
|
|
||||||
}
|
|
||||||
|
|
||||||
receive_ids = {
|
receive_ids = {
|
||||||
'retail': '6e400002-b5a3-f393-e0a9-e50e24dcca9e' #receive characteristic UUID
|
"retail": "6e400002-b5a3-f393-e0a9-e50e24dcca9e" # receive characteristic UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
transmit_ids = {
|
transmit_ids = {
|
||||||
'retail': '6e400003-b5a3-f393-e0a9-e50e24dcca9e' #transmit characteristic UUID
|
"retail": "6e400003-b5a3-f393-e0a9-e50e24dcca9e" # transmit characteristic UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
scoot_found = False
|
scoot_found = False
|
||||||
|
|
||||||
|
|
||||||
class Fifo():
|
class Fifo:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.q = queue.Queue()
|
self.q = queue.Queue()
|
||||||
|
|
||||||
def write(self, data): # put bytes
|
def write(self, data): # put bytes
|
||||||
for b in data:
|
for b in data:
|
||||||
self.q.put(b)
|
self.q.put(b)
|
||||||
|
|
||||||
def read(self, size=1, timeout=None): # but read string
|
def read(self, size=1, timeout=None): # but read string
|
||||||
res = ''
|
res = ""
|
||||||
for i in xrange(size):
|
for i in xrange(size):
|
||||||
res += chr(self.q.get(True, timeout))
|
res += chr(self.q.get(True, timeout))
|
||||||
return res
|
return res
|
||||||
|
@ -69,24 +84,20 @@ class ScootBT(BluetoothDispatcher):
|
||||||
self.timeout = SCAN_TIMEOUT
|
self.timeout = SCAN_TIMEOUT
|
||||||
self.set_queue_timeout(self.timeout)
|
self.set_queue_timeout(self.timeout)
|
||||||
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
def discover(self):
|
def discover(self):
|
||||||
self.start_scan()
|
self.start_scan()
|
||||||
self.state = 'scan'
|
self.state = "scan"
|
||||||
print(self.state)
|
print(self.state)
|
||||||
|
|
||||||
|
|
||||||
def on_device(self, device, rssi, advertisement):
|
def on_device(self, device, rssi, advertisement):
|
||||||
global scoot_found
|
global scoot_found
|
||||||
if self.state != 'scan':
|
if self.state != "scan":
|
||||||
return
|
return
|
||||||
Logger.debug("on_device event {}".format(list(advertisement)))
|
Logger.debug("on_device event {}".format(list(advertisement)))
|
||||||
self.addr = device.getAddress()
|
self.addr = device.getAddress()
|
||||||
|
@ -106,26 +117,24 @@ class ScootBT(BluetoothDispatcher):
|
||||||
elif ad.ad_type == Advertisement.ad_types.complete_local_name:
|
elif ad.ad_type == Advertisement.ad_types.complete_local_name:
|
||||||
name = str(ad.data)
|
name = str(ad.data)
|
||||||
if scoot_found:
|
if scoot_found:
|
||||||
self.state = 'found'
|
self.state = "found"
|
||||||
print(self.state)
|
print(self.state)
|
||||||
self.ble_device = device
|
self.ble_device = device
|
||||||
Logger.debug("Scooter detected: {}".format(name))
|
Logger.debug("Scooter detected: {}".format(name))
|
||||||
self.stop_scan()
|
self.stop_scan()
|
||||||
|
|
||||||
|
|
||||||
def on_scan_completed(self):
|
def on_scan_completed(self):
|
||||||
if self.ble_device:
|
if self.ble_device:
|
||||||
self.connect_gatt(self.ble_device)
|
self.connect_gatt(self.ble_device)
|
||||||
self.state = 'connected'
|
self.state = "connected"
|
||||||
print(self.state)
|
print(self.state)
|
||||||
else:
|
else:
|
||||||
self.start_scan()
|
self.start_scan()
|
||||||
|
|
||||||
|
|
||||||
def on_connection_state_change(self, status, state):
|
def on_connection_state_change(self, status, state):
|
||||||
if status == GATT_SUCCESS and state:
|
if status == GATT_SUCCESS and state:
|
||||||
self.discover_services()
|
self.discover_services()
|
||||||
self.state = 'discover'
|
self.state = "discover"
|
||||||
print(self.state)
|
print(self.state)
|
||||||
else:
|
else:
|
||||||
self.close_gatt()
|
self.close_gatt()
|
||||||
|
@ -133,73 +142,68 @@ class ScootBT(BluetoothDispatcher):
|
||||||
self.tx_characteristic = None
|
self.tx_characteristic = None
|
||||||
self.services = None
|
self.services = None
|
||||||
|
|
||||||
|
|
||||||
def on_services(self, status, services):
|
def on_services(self, status, services):
|
||||||
self.services = services
|
self.services = services
|
||||||
for uuid in receive_ids.values():
|
for uuid in receive_ids.values():
|
||||||
self.rx_characteristic = self.services.search(uuid)
|
self.rx_characteristic = self.services.search(uuid)
|
||||||
print('RX: '+uuid)
|
print("RX: " + uuid)
|
||||||
for uuid in transmit_ids.values():
|
for uuid in transmit_ids.values():
|
||||||
self.tx_characteristic = self.services.search(uuid)
|
self.tx_characteristic = self.services.search(uuid)
|
||||||
print('TX: '+uuid)
|
print("TX: " + uuid)
|
||||||
self.enable_notifications(self.tx_characteristic)
|
self.enable_notifications(self.tx_characteristic)
|
||||||
|
|
||||||
|
|
||||||
def on_characteristic_changed(self, characteristic):
|
def on_characteristic_changed(self, characteristic):
|
||||||
if characteristic == self.tx_characteristic:
|
if characteristic == self.tx_characteristic:
|
||||||
data = characteristic.getValue()
|
data = characteristic.getValue()
|
||||||
self.rx_fifo.write(data)
|
self.rx_fifo.write(data)
|
||||||
|
|
||||||
|
|
||||||
def open(self, port):
|
def open(self, port):
|
||||||
self.addr = port
|
self.addr = port
|
||||||
if self.ble_device == None:
|
if self.ble_device == None:
|
||||||
self.discover()
|
self.discover()
|
||||||
if self.state!='connected':
|
if self.state != "connected":
|
||||||
self.connect_gatt(self.ble_device)
|
self.connect_gatt(self.ble_device)
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.ble_device != None:
|
if self.ble_device != None:
|
||||||
self.close_gatt()
|
self.close_gatt()
|
||||||
self.services = None
|
self.services = None
|
||||||
print('close')
|
print("close")
|
||||||
|
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
print('read')
|
print("read")
|
||||||
if self.ble_device:
|
if self.ble_device:
|
||||||
try:
|
try:
|
||||||
data = self.rx_fifo.read(size, timeout=self.timeout)
|
data = self.rx_fifo.read(size, timeout=self.timeout)
|
||||||
except queue.Empty:
|
except queue.Empty:
|
||||||
raise LinkTimeoutException
|
raise LinkTimeoutException
|
||||||
if self.dump:
|
if self.dump:
|
||||||
print '<', hexlify(data).upper()
|
print("<", hexlify(data).upper())
|
||||||
return data
|
return data
|
||||||
else:
|
else:
|
||||||
print('BLE not connected')
|
print("BLE not connected")
|
||||||
self.discover()
|
self.discover()
|
||||||
|
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
print('write')
|
print("write")
|
||||||
if self.ble_device:
|
if self.ble_device:
|
||||||
if self.dump:
|
if self.dump:
|
||||||
print '>', hexlify(data).upper()
|
print(">", hexlify(data).upper())
|
||||||
size = len(data)
|
size = len(data)
|
||||||
ofs = 0
|
ofs = 0
|
||||||
while size:
|
while size:
|
||||||
chunk_sz = min(size, _write_chunk_size)
|
chunk_sz = min(size, _write_chunk_size)
|
||||||
self.write_characteristic(self.rx_characteristic, bytearray(data[ofs:ofs+chunk_sz]))
|
self.write_characteristic(
|
||||||
|
self.rx_characteristic, bytearray(data[ofs : ofs + chunk_sz])
|
||||||
|
)
|
||||||
ofs += chunk_sz
|
ofs += chunk_sz
|
||||||
size -= chunk_sz
|
size -= chunk_sz
|
||||||
else:
|
else:
|
||||||
print('BLE not connected')
|
print("BLE not connected")
|
||||||
self.discover()
|
self.discover()
|
||||||
|
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
self.discover()
|
self.discover()
|
||||||
|
|
||||||
|
@ -209,35 +213,28 @@ class BLELink(BaseLink):
|
||||||
super(BLELink, self).__init__(*args, **kwargs)
|
super(BLELink, self).__init__(*args, **kwargs)
|
||||||
self._adapter = None
|
self._adapter = None
|
||||||
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._adapter = ScootBT()
|
self._adapter = ScootBT()
|
||||||
self._adapter.discover()
|
self._adapter.discover()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
devices = self._adapter.scan()
|
devices = self._adapter.scan()
|
||||||
|
|
||||||
|
|
||||||
def open(self, port):
|
def open(self, port):
|
||||||
self._adapter.open(port)
|
self._adapter.open(port)
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self._adapter.close()
|
self._adapter.close()
|
||||||
|
|
||||||
|
|
||||||
def read(self, size):
|
def read(self, size):
|
||||||
self._adapter.read(size)
|
self._adapter.read(size)
|
||||||
|
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
self._adapter.write(data)
|
self._adapter.write(data)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['BLELink']
|
__all__ = ["BLELink"]
|
||||||
|
|
|
@ -5,57 +5,59 @@ import serial
|
||||||
import serial.tools.list_ports as lp
|
import serial.tools.list_ports as lp
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||||
|
|
||||||
|
|
||||||
class SerialLink(BaseLink):
|
class SerialLink(BaseLink):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(SerialLink, self).__init__(*args, **kwargs)
|
super(SerialLink, self).__init__(*args, **kwargs)
|
||||||
self.com = None
|
self.com = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
def __enter__(self):
|
return self
|
||||||
return self
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.close()
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
|
||||||
self.close()
|
def scan(self):
|
||||||
|
ports = lp.comports()
|
||||||
|
res = [
|
||||||
def scan(self):
|
("%s %04X:%04X" % (port.device, port.vid, port.pid), port.device)
|
||||||
ports = lp.comports()
|
for port in ports
|
||||||
res = [("%s %04X:%04X" % (port.device, port.vid, port.pid), port.device) for port in ports]
|
]
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def open(self, port):
|
||||||
def open(self, port):
|
try:
|
||||||
try:
|
self.com = serial.Serial(
|
||||||
self.com = serial.Serial(port, 115200, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=self.timeout)
|
port,
|
||||||
except serial.SerialException:
|
115200,
|
||||||
raise LinkOpenException
|
parity=serial.PARITY_NONE,
|
||||||
|
stopbits=serial.STOPBITS_ONE,
|
||||||
|
timeout=self.timeout,
|
||||||
def close(self):
|
)
|
||||||
if self.com:
|
except serial.SerialException:
|
||||||
self.com.close()
|
raise LinkOpenException
|
||||||
self.com = None
|
|
||||||
|
def close(self):
|
||||||
|
if self.com:
|
||||||
def read(self, size):
|
self.com.close()
|
||||||
try:
|
self.com = None
|
||||||
data = self.com.read(size)
|
|
||||||
except serial.SerialTimeoutException:
|
def read(self, size):
|
||||||
raise LinkTimeoutException
|
try:
|
||||||
if len(data)<size:
|
data = self.com.read(size)
|
||||||
raise LinkTimeoutException
|
except serial.SerialTimeoutException:
|
||||||
if self.dump:
|
raise LinkTimeoutException
|
||||||
print("<", hexlify(data).upper())
|
if len(data) < size:
|
||||||
return data
|
raise LinkTimeoutException
|
||||||
|
if self.dump:
|
||||||
|
print("<", hexlify(data).upper())
|
||||||
def write(self, data):
|
return data
|
||||||
if self.dump:
|
|
||||||
print(">", hexlify(data).upper())
|
def write(self, data):
|
||||||
self.com.write(data)
|
if self.dump:
|
||||||
|
print(">", hexlify(data).upper())
|
||||||
|
self.com.write(data)
|
||||||
__all__ = ["SerialLink"]
|
|
||||||
|
|
||||||
|
__all__ = ["SerialLink"]
|
||||||
|
|
108
py9b/link/tcp.py
108
py9b/link/tcp.py
|
@ -6,75 +6,69 @@ from .base import BaseLink, LinkTimeoutException, LinkOpenException
|
||||||
|
|
||||||
HOST, PORT = "127.0.0.1", 6000
|
HOST, PORT = "127.0.0.1", 6000
|
||||||
|
|
||||||
_write_chunk_size = 20 # 20 as in android dumps
|
_write_chunk_size = 20 # 20 as in android dumps
|
||||||
|
|
||||||
|
|
||||||
def recvall(sock, size):
|
def recvall(sock, size):
|
||||||
data = ""
|
data = ""
|
||||||
while len(data)<size:
|
while len(data) < size:
|
||||||
try:
|
try:
|
||||||
pkt = sock.recv(size-len(data))
|
pkt = sock.recv(size - len(data))
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
raise LinkTimeoutException()
|
raise LinkTimeoutException()
|
||||||
data+=pkt
|
data += pkt
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
class TCPLink(BaseLink):
|
class TCPLink(BaseLink):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TCPLink, self).__init__(*args, **kwargs)
|
super(TCPLink, self).__init__(*args, **kwargs)
|
||||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.sock.settimeout(self.timeout)
|
self.sock.settimeout(self.timeout)
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
def __enter__(self):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
return self
|
self.close()
|
||||||
|
|
||||||
|
def scan(self):
|
||||||
|
res = [("Android UART Bridge", HOST + ":" + str(PORT))]
|
||||||
|
return res
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def open(self, port):
|
||||||
self.close()
|
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
|
||||||
|
|
||||||
def scan(self):
|
def read(self, size):
|
||||||
res = [("Android UART Bridge", HOST+':'+str(PORT))]
|
data = recvall(self.sock, size)
|
||||||
return res
|
if data and self.dump:
|
||||||
|
print("<", hexlify(data).upper())
|
||||||
|
return data
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
def open(self, port):
|
if self.dump:
|
||||||
p = port.partition(':')
|
print(">", hexlify(data).upper())
|
||||||
host = p[0]
|
size = len(data)
|
||||||
port = int(p[2], 10)
|
ofs = 0
|
||||||
print(host, port)
|
while size:
|
||||||
try:
|
chunk_sz = min(size, _write_chunk_size)
|
||||||
self.sock.connect((host, port))
|
self.sock.sendall(data[ofs : ofs + chunk_sz])
|
||||||
except socket.timeout:
|
ofs += chunk_sz
|
||||||
raise LinkOpenException
|
size -= chunk_sz
|
||||||
self.connected = True
|
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
if self.connected:
|
|
||||||
self.sock.close()
|
|
||||||
self.connected = False
|
|
||||||
|
|
||||||
|
|
||||||
def read(self, size):
|
|
||||||
data = recvall(self.sock, size)
|
|
||||||
if data and 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.sock.sendall(data[ofs:ofs+chunk_sz])
|
|
||||||
ofs += chunk_sz
|
|
||||||
size -= chunk_sz
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["TCPLink"]
|
__all__ = ["TCPLink"]
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
"""Ninebot packet transport"""
|
|
||||||
from struct import pack, unpack
|
|
||||||
from .base import checksum, BaseTransport as BT
|
|
||||||
from .packet import BasePacket
|
|
||||||
|
|
||||||
|
|
||||||
class NinebotTransport(BT):
|
|
||||||
def __init__(self, link, device=BT.HOST):
|
|
||||||
super(NinebotTransport, self).__init__(link)
|
|
||||||
self.device = device
|
|
||||||
|
|
||||||
|
|
||||||
def _wait_pre(self):
|
|
||||||
while True:
|
|
||||||
while True:
|
|
||||||
c = self.link.read(1)
|
|
||||||
if c=="\x5A":
|
|
||||||
break
|
|
||||||
while True:
|
|
||||||
c = self.link.read(1)
|
|
||||||
if c=="\xA5":
|
|
||||||
return True
|
|
||||||
if c!="\x5A":
|
|
||||||
break # start waiting 5A again, else - this is 5A, so wait for A5
|
|
||||||
|
|
||||||
|
|
||||||
def recv(self):
|
|
||||||
self._wait_pre()
|
|
||||||
pkt = self.link.read(1)
|
|
||||||
l = ord(pkt)+6
|
|
||||||
for i in range(l):
|
|
||||||
pkt += self.link.read(1)
|
|
||||||
ck_calc = checksum(pkt[0:-2])
|
|
||||||
ck_pkt = unpack("<H", pkt[-2:])[0]
|
|
||||||
if ck_pkt!=ck_calc:
|
|
||||||
print("Checksum mismatch !")
|
|
||||||
return None
|
|
||||||
return BasePacket(ord(pkt[1]), ord(pkt[2]), ord(pkt[3]), ord(pkt[4]), pkt[5:-2]) # sa, da, cmd, arg, data
|
|
||||||
|
|
||||||
|
|
||||||
def send(self, packet):
|
|
||||||
pkt = pack("<BBBBB", len(packet.data), packet.src, packet.dst, packet.cmd, packet.arg)+packet.data
|
|
||||||
pkt = "\x5A\xA5" + pkt + pack("<H", checksum(pkt))
|
|
||||||
self.link.write(pkt)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["NinebotTransport"]
|
|
|
@ -1,95 +0,0 @@
|
||||||
"""Xiaomi packet transport"""
|
|
||||||
from struct import pack, unpack
|
|
||||||
from .base import checksum, BaseTransport as BT
|
|
||||||
from .packet import BasePacket
|
|
||||||
|
|
||||||
|
|
||||||
class XiaomiTransport(BT):
|
|
||||||
MASTER2ESC = 0x20
|
|
||||||
ESC2MASTER = 0x23
|
|
||||||
|
|
||||||
MASTER2BLE = 0x21
|
|
||||||
BLE2MASTER = 0x24
|
|
||||||
|
|
||||||
MASTER2BMS = 0x22
|
|
||||||
BMS2MASTER = 0x25
|
|
||||||
|
|
||||||
MOTOR = 0x01
|
|
||||||
DEVFF = 0xFF
|
|
||||||
|
|
||||||
_SaDa2Addr = { BT.HOST : { BT.MOTOR : MOTOR, BT.ESC : MASTER2ESC, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS },
|
|
||||||
BT.ESC : { BT.HOST : ESC2MASTER, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS, BT.MOTOR : MOTOR },
|
|
||||||
BT.BMS : { BT.HOST : BMS2MASTER, BT.ESC : BMS2MASTER, BT.MOTOR : MOTOR },
|
|
||||||
BT.MOTOR : {BT.HOST : MOTOR, BT.ESC : MOTOR, BT.BMS : MOTOR } }
|
|
||||||
|
|
||||||
# TBC
|
|
||||||
_BleAddr2SaDa = { MASTER2ESC : (BT.HOST, BT.ESC),
|
|
||||||
ESC2MASTER : (BT.ESC, BT.HOST),
|
|
||||||
MASTER2BMS : (BT.HOST, BT.BMS),
|
|
||||||
BMS2MASTER : (BT.BMS, BT.HOST),
|
|
||||||
MASTER2BLE : (BT.HOST, BT.BLE),
|
|
||||||
BLE2MASTER : (BT.BLE, BT.HOST),
|
|
||||||
MOTOR : (BT.MOTOR, BT.HOST) }
|
|
||||||
|
|
||||||
_BmsAddr2SaDa = { MASTER2ESC : (BT.BMS, BT.ESC),
|
|
||||||
ESC2MASTER : (BT.ESC, BT.BMS),
|
|
||||||
MASTER2BMS : (BT.ESC, BT.BMS),
|
|
||||||
BMS2MASTER : (BT.BMS, BT.ESC),
|
|
||||||
MASTER2BLE : (BT.BMS, BT.BLE),
|
|
||||||
BLE2MASTER : (BT.BLE, BT.BMS),
|
|
||||||
MOTOR : (BT.MOTOR, BT.BMS) }
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, link, device=BT.HOST):
|
|
||||||
super(XiaomiTransport, self).__init__(link)
|
|
||||||
self.device = device
|
|
||||||
|
|
||||||
|
|
||||||
def _make_addr(self, src, dst):
|
|
||||||
return XiaomiTransport._SaDa2Addr[src][dst]
|
|
||||||
|
|
||||||
|
|
||||||
def _split_addr(self, addr):
|
|
||||||
if self.device==BT.BMS:
|
|
||||||
return XiaomiTransport._BmsAddr2SaDa[addr]
|
|
||||||
else:
|
|
||||||
return XiaomiTransport._BleAddr2SaDa[addr]
|
|
||||||
|
|
||||||
|
|
||||||
def _wait_pre(self):
|
|
||||||
while True:
|
|
||||||
while True:
|
|
||||||
c = self.link.read(1)
|
|
||||||
if c=="\x55":
|
|
||||||
break
|
|
||||||
while True:
|
|
||||||
c = self.link.read(1)
|
|
||||||
if c=="\xAA":
|
|
||||||
return True
|
|
||||||
if c!="\x55":
|
|
||||||
break # start waiting 55 again, else - this is 55, so wait for AA
|
|
||||||
|
|
||||||
|
|
||||||
def recv(self):
|
|
||||||
self._wait_pre()
|
|
||||||
pkt = self.link.read(1)
|
|
||||||
l = ord(pkt)+3
|
|
||||||
for i in range(l):
|
|
||||||
pkt += self.link.read(1)
|
|
||||||
ck_calc = checksum(pkt[0:-2])
|
|
||||||
ck_pkt = unpack("<H", pkt[-2:])[0]
|
|
||||||
if ck_pkt!=ck_calc:
|
|
||||||
print("Checksum mismatch !")
|
|
||||||
return None
|
|
||||||
sa, da = self._split_addr(ord(pkt[1]))
|
|
||||||
return BasePacket(sa, da, ord(pkt[2]), ord(pkt[3]), pkt[4:-2]) # sa, da, cmd, arg, data
|
|
||||||
|
|
||||||
|
|
||||||
def send(self, packet):
|
|
||||||
dev = self._make_addr(packet.src, packet.dst)
|
|
||||||
pkt = pack("<BBBB", len(packet.data)+2, dev, packet.cmd, packet.arg)+packet.data
|
|
||||||
pkt = "\x55\xAA" + pkt + pack("<H", checksum(pkt))
|
|
||||||
self.link.write(pkt)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["XiaomiTransport"]
|
|
|
@ -1,43 +1,58 @@
|
||||||
"""Transport abstract class"""
|
"""Transport abstract class"""
|
||||||
|
|
||||||
def checksum(data):
|
|
||||||
s = 0
|
|
||||||
for c in data:
|
|
||||||
s += c
|
|
||||||
return (s & 0xFFFF) ^ 0xFFFF
|
|
||||||
|
|
||||||
|
def checksum(data):
|
||||||
|
s = 0
|
||||||
|
for c in data:
|
||||||
|
s += c
|
||||||
|
return (s & 0xFFFF) ^ 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
class BaseTransport(object):
|
class BaseTransport(object):
|
||||||
MOTOR = 0x01
|
MOTOR = 0x01
|
||||||
ESC = 0x20
|
ESC = 0x20
|
||||||
BLE = 0x21
|
BLE = 0x21
|
||||||
BMS = 0x22
|
BMS = 0x22
|
||||||
EXTBMS = 0x23
|
EXTBMS = 0x23
|
||||||
HOST = 0x3E
|
HOST = 0x3E
|
||||||
|
|
||||||
DeviceNames = { MOTOR : "MOTOR", ESC : "ESC", BLE : "BLE", BMS : "BMS", EXTBMS : "EXTBMS", HOST : "HOST" }
|
|
||||||
|
|
||||||
def __init__(self, link):
|
DeviceNames = {
|
||||||
self.link = link
|
MOTOR: "MOTOR",
|
||||||
|
ESC: "ESC",
|
||||||
|
BLE: "BLE",
|
||||||
|
BMS: "BMS",
|
||||||
|
EXTBMS: "EXTBMS",
|
||||||
|
HOST: "HOST",
|
||||||
|
}
|
||||||
|
|
||||||
def recv(self):
|
def __init__(self, link):
|
||||||
raise NotImplementedError()
|
self.link = link
|
||||||
|
|
||||||
def send(self, src, dst, cmd, arg, data=""):
|
def recv(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def execute(self, command):
|
def send(self, src, dst, cmd, arg, data=""):
|
||||||
self.send(command.request)
|
raise NotImplementedError()
|
||||||
if not command.has_response:
|
|
||||||
return True
|
|
||||||
#TODO: retry ?
|
|
||||||
rsp = self.recv()
|
|
||||||
return command.handle_response(rsp)
|
|
||||||
|
|
||||||
@staticmethod
|
def execute(self, command):
|
||||||
def GetDeviceName(dev):
|
self.send(command.request)
|
||||||
return BaseTransport.DeviceNames.get(dev, "%02X" % (dev))
|
if not command.has_response:
|
||||||
|
return True
|
||||||
|
# TODO: retry ?
|
||||||
|
exc = None
|
||||||
|
for n in range(1):
|
||||||
|
try:
|
||||||
|
rsp = self.recv()
|
||||||
|
return command.handle_response(rsp)
|
||||||
|
except Exception as e:
|
||||||
|
print("retry")
|
||||||
|
exc = e
|
||||||
|
pass
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def GetDeviceName(dev):
|
||||||
|
return BaseTransport.DeviceNames.get(dev, "%02X" % (dev))
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["checksum", "BaseTransport"]
|
__all__ = ["checksum", "BaseTransport"]
|
||||||
|
|
|
@ -5,43 +5,52 @@ from .packet import BasePacket
|
||||||
|
|
||||||
|
|
||||||
class NinebotTransport(BT):
|
class NinebotTransport(BT):
|
||||||
def __init__(self, link, device=BT.HOST):
|
def __init__(self, link, device=BT.HOST):
|
||||||
super(NinebotTransport, self).__init__(link)
|
super(NinebotTransport, self).__init__(link)
|
||||||
self.device = device
|
self.device = device
|
||||||
|
|
||||||
|
def _wait_pre(self):
|
||||||
|
while True:
|
||||||
|
while True:
|
||||||
|
c = self.link.read(1)
|
||||||
|
if c == b"\x5A":
|
||||||
|
break
|
||||||
|
while True:
|
||||||
|
c = self.link.read(1)
|
||||||
|
if c == b"\xA5":
|
||||||
|
return True
|
||||||
|
if c != b"\x5A":
|
||||||
|
break # start waiting 5A again, else - this is 5A, so wait for A5
|
||||||
|
|
||||||
def _wait_pre(self):
|
def recv(self):
|
||||||
while True:
|
self._wait_pre()
|
||||||
while True:
|
pkt = self.link.read(1)
|
||||||
c = self.link.read(1)
|
l = ord(pkt) + 6
|
||||||
if c==b"\x5A":
|
for i in range(l):
|
||||||
break
|
pkt += self.link.read(1)
|
||||||
while True:
|
ck_calc = checksum(pkt[0:-2])
|
||||||
c = self.link.read(1)
|
ck_pkt = unpack("<H", pkt[-2:])[0]
|
||||||
if c==b"\xA5":
|
if ck_pkt != ck_calc:
|
||||||
return True
|
print("Checksum mismatch !")
|
||||||
if c!=b"\x5A":
|
return None
|
||||||
break # start waiting 5A again, else - this is 5A, so wait for A5
|
return BasePacket(
|
||||||
|
pkt[1], pkt[2], pkt[3], pkt[4], pkt[5:-2]
|
||||||
|
) # sa, da, cmd, arg, data
|
||||||
|
|
||||||
|
def send(self, packet):
|
||||||
def recv(self):
|
pkt = (
|
||||||
self._wait_pre()
|
pack(
|
||||||
pkt = self.link.read(1)
|
"<BBBBB",
|
||||||
l = ord(pkt)+6
|
len(packet.data),
|
||||||
for i in range(l):
|
packet.src,
|
||||||
pkt += self.link.read(1)
|
packet.dst,
|
||||||
ck_calc = checksum(pkt[0:-2])
|
packet.cmd,
|
||||||
ck_pkt = unpack("<H", pkt[-2:])[0]
|
packet.arg,
|
||||||
if ck_pkt!=ck_calc:
|
)
|
||||||
print("Checksum mismatch !")
|
+ packet.data
|
||||||
return None
|
)
|
||||||
return BasePacket(pkt[1], pkt[2], pkt[3], pkt[4], pkt[5:-2]) # sa, da, cmd, arg, data
|
pkt = b"\x5A\xA5" + pkt + pack("<H", checksum(pkt))
|
||||||
|
self.link.write(pkt)
|
||||||
|
|
||||||
def send(self, packet):
|
|
||||||
pkt = pack("<BBBBB", len(packet.data), packet.src, packet.dst, packet.cmd, packet.arg)+packet.data
|
|
||||||
pkt = b"\x5A\xA5" + pkt + pack("<H", checksum(pkt))
|
|
||||||
self.link.write(pkt)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["NinebotTransport"]
|
__all__ = ["NinebotTransport"]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
from .base import BaseTransport as BT
|
from .base import BaseTransport as BT
|
||||||
|
|
||||||
|
|
||||||
class BasePacket(object):
|
class BasePacket(object):
|
||||||
def __init__(self, src=0, dst=0, cmd=0, arg=0, data=""):
|
def __init__(self, src=0, dst=0, cmd=0, arg=0, data=""):
|
||||||
self.src = src
|
self.src = src
|
||||||
|
@ -10,7 +11,13 @@ class BasePacket(object):
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s->%s: %02X @%02X %s" % (BT.GetDeviceName(self.src), BT.GetDeviceName(self.dst), self.cmd, self.arg, hexlify(self.data).upper())
|
return "%s->%s: %02X @%02X %s" % (
|
||||||
|
BT.GetDeviceName(self.src),
|
||||||
|
BT.GetDeviceName(self.dst),
|
||||||
|
self.cmd,
|
||||||
|
self.arg,
|
||||||
|
hexlify(self.data).upper(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["BasePacket"]
|
__all__ = ["BasePacket"]
|
||||||
|
|
|
@ -14,93 +14,108 @@ class XiaomiTransport(BT):
|
||||||
MASTER2BMS = 0x22
|
MASTER2BMS = 0x22
|
||||||
BMS2MASTER = 0x25
|
BMS2MASTER = 0x25
|
||||||
|
|
||||||
MOTOR = 0x01
|
MOTOR = 0x01
|
||||||
DEVFF = 0xFF
|
DEVFF = 0xFF
|
||||||
|
|
||||||
_SaDa2Addr = { BT.HOST : { BT.MOTOR : MOTOR, BT.ESC : MASTER2ESC, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS },
|
_SaDa2Addr = {
|
||||||
BT.ESC : { BT.HOST : ESC2MASTER, BT.BLE : MASTER2BLE, BT.BMS : MASTER2BMS, BT.MOTOR : MOTOR },
|
BT.HOST: {
|
||||||
BT.BMS : { BT.HOST : BMS2MASTER, BT.ESC : BMS2MASTER, BT.MOTOR : MOTOR },
|
BT.MOTOR: MOTOR,
|
||||||
BT.MOTOR : {BT.HOST : MOTOR, BT.ESC : MOTOR, BT.BMS : MOTOR } }
|
BT.ESC: MASTER2ESC,
|
||||||
|
BT.BLE: MASTER2BLE,
|
||||||
|
BT.BMS: MASTER2BMS,
|
||||||
|
},
|
||||||
|
BT.ESC: {
|
||||||
|
BT.HOST: ESC2MASTER,
|
||||||
|
BT.BLE: MASTER2BLE,
|
||||||
|
BT.BMS: MASTER2BMS,
|
||||||
|
BT.MOTOR: MOTOR,
|
||||||
|
},
|
||||||
|
BT.BMS: {BT.HOST: BMS2MASTER, BT.ESC: BMS2MASTER, BT.MOTOR: MOTOR},
|
||||||
|
BT.MOTOR: {BT.HOST: MOTOR, BT.ESC: MOTOR, BT.BMS: MOTOR},
|
||||||
|
}
|
||||||
|
|
||||||
# TBC
|
# TBC
|
||||||
_BleAddr2SaDa = { MASTER2ESC : (BT.HOST, BT.ESC),
|
_BleAddr2SaDa = {
|
||||||
ESC2MASTER : (BT.ESC, BT.HOST),
|
MASTER2ESC: (BT.HOST, BT.ESC),
|
||||||
MASTER2BMS : (BT.HOST, BT.BMS),
|
ESC2MASTER: (BT.ESC, BT.HOST),
|
||||||
BMS2MASTER : (BT.BMS, BT.HOST),
|
MASTER2BMS: (BT.HOST, BT.BMS),
|
||||||
MASTER2BLE : (BT.HOST, BT.BLE),
|
BMS2MASTER: (BT.BMS, BT.HOST),
|
||||||
BLE2MASTER : (BT.BLE, BT.HOST),
|
MASTER2BLE: (BT.HOST, BT.BLE),
|
||||||
MOTOR : (BT.MOTOR, BT.HOST) }
|
BLE2MASTER: (BT.BLE, BT.HOST),
|
||||||
|
MOTOR: (BT.MOTOR, BT.HOST),
|
||||||
_BmsAddr2SaDa = { MASTER2ESC : (BT.BMS, BT.ESC),
|
}
|
||||||
ESC2MASTER : (BT.ESC, BT.BMS),
|
|
||||||
MASTER2BMS : (BT.ESC, BT.BMS),
|
|
||||||
BMS2MASTER : (BT.BMS, BT.ESC),
|
|
||||||
MASTER2BLE : (BT.BMS, BT.BLE),
|
|
||||||
BLE2MASTER : (BT.BLE, BT.BMS),
|
|
||||||
MOTOR : (BT.MOTOR, BT.BMS) }
|
|
||||||
|
|
||||||
|
_BmsAddr2SaDa = {
|
||||||
|
MASTER2ESC: (BT.BMS, BT.ESC),
|
||||||
|
ESC2MASTER: (BT.ESC, BT.BMS),
|
||||||
|
MASTER2BMS: (BT.ESC, BT.BMS),
|
||||||
|
BMS2MASTER: (BT.BMS, BT.ESC),
|
||||||
|
MASTER2BLE: (BT.BMS, BT.BLE),
|
||||||
|
BLE2MASTER: (BT.BLE, BT.BMS),
|
||||||
|
MOTOR: (BT.MOTOR, BT.BMS),
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, link, device=BT.HOST):
|
def __init__(self, link, device=BT.HOST):
|
||||||
super(XiaomiTransport, self).__init__(link)
|
super(XiaomiTransport, self).__init__(link)
|
||||||
self.device = device
|
self.device = device
|
||||||
self.keys = None
|
self.keys = None
|
||||||
|
|
||||||
|
|
||||||
def _make_addr(self, src, dst):
|
def _make_addr(self, src, dst):
|
||||||
return XiaomiTransport._SaDa2Addr[src][dst]
|
return XiaomiTransport._SaDa2Addr[src][dst]
|
||||||
|
|
||||||
|
|
||||||
def _split_addr(self, addr):
|
def _split_addr(self, addr):
|
||||||
if self.device==BT.BMS:
|
if self.device == BT.BMS:
|
||||||
return XiaomiTransport._BmsAddr2SaDa[addr]
|
return XiaomiTransport._BmsAddr2SaDa[addr]
|
||||||
else:
|
else:
|
||||||
return XiaomiTransport._BleAddr2SaDa[addr]
|
return XiaomiTransport._BleAddr2SaDa[addr]
|
||||||
|
|
||||||
|
|
||||||
def _wait_pre(self):
|
def _wait_pre(self):
|
||||||
while True:
|
while True:
|
||||||
while True:
|
while True:
|
||||||
c = self.link.read(1)
|
c = self.link.read(1)
|
||||||
if c == b'\x55':
|
if c == b"\x55":
|
||||||
break
|
break
|
||||||
while True:
|
while True:
|
||||||
c = self.link.read(1)
|
c = self.link.read(1)
|
||||||
if c == b'\xaa' or c == b'\xab':
|
if c == b"\xaa" or c == b"\xab":
|
||||||
return c
|
return c
|
||||||
if c != b'\x55':
|
if c != b"\x55":
|
||||||
break # start waiting 55 again, else - this is 55, so wait for AA
|
break # start waiting 55 again, else - this is 55, so wait for AA
|
||||||
|
|
||||||
|
|
||||||
def recv(self):
|
def recv(self):
|
||||||
ver = self._wait_pre()
|
ver = self._wait_pre()
|
||||||
pkt = self.link.read(1)
|
pkt = self.link.read(1)
|
||||||
l = ord(pkt) + 3 + (4 if ver == b'\xab' else 0)
|
l = ord(pkt) + 3 + (4 if ver == b"\xab" else 0)
|
||||||
for i in range(l):
|
for i in range(l):
|
||||||
pkt.extend(self.link.read(1))
|
pkt.extend(self.link.read(1))
|
||||||
ck_calc = checksum(pkt[0:-2])
|
ck_calc = checksum(pkt[0:-2])
|
||||||
ck_pkt = unpack("<H", pkt[-2:])[0]
|
ck_pkt = unpack("<H", pkt[-2:])[0]
|
||||||
if ck_pkt!=ck_calc:
|
if ck_pkt != ck_calc:
|
||||||
print("Checksum mismatch !")
|
print("Checksum mismatch !")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if ver == b'\xab':
|
if ver == b"\xab":
|
||||||
# Drops 2 bytes of garbage and 2 bytes of checksum, first 2 bytes
|
# Drops 2 bytes of garbage and 2 bytes of checksum, first 2 bytes
|
||||||
# of garbage are dropped below
|
# of garbage are dropped below
|
||||||
pkt[1:] = self.encrypt(pkt[1:])[:-4]
|
pkt[1:] = self.encrypt(pkt[1:])[:-4]
|
||||||
|
|
||||||
sa, da = self._split_addr(pkt[1])
|
sa, da = self._split_addr(pkt[1])
|
||||||
return BasePacket(sa, da, pkt[2], pkt[3], pkt[4:-2]) # sa, da, cmd, arg, data
|
return BasePacket(sa, da, pkt[2], pkt[3], pkt[4:-2]) # sa, da, cmd, arg, data
|
||||||
|
|
||||||
|
|
||||||
def send(self, packet):
|
def send(self, packet):
|
||||||
dev = self._make_addr(packet.src, packet.dst)
|
dev = self._make_addr(packet.src, packet.dst)
|
||||||
if self.keys:
|
if self.keys:
|
||||||
pkt = pack("<B", len(packet.data)+2)
|
pkt = pack("<B", len(packet.data) + 2)
|
||||||
pkt += self.encrypt(pack("<BBB", dev, packet.cmd, packet.arg)+packet.data + (b'\x00' * 4))
|
pkt += self.encrypt(
|
||||||
pkt = b'\x55\xab' + pkt + pack("<H", checksum(pkt))
|
pack("<BBB", dev, packet.cmd, packet.arg) + packet.data + (b"\x00" * 4)
|
||||||
|
)
|
||||||
|
pkt = b"\x55\xab" + pkt + pack("<H", checksum(pkt))
|
||||||
else:
|
else:
|
||||||
pkt = pack("<BBBB", len(packet.data)+2, dev, packet.cmd, packet.arg)+packet.data
|
pkt = (
|
||||||
pkt = b'\x55\xaa' + pkt + pack("<H", checksum(pkt))
|
pack("<BBBB", len(packet.data) + 2, dev, packet.cmd, packet.arg)
|
||||||
|
+ packet.data
|
||||||
|
)
|
||||||
|
pkt = b"\x55\xaa" + pkt + pack("<H", checksum(pkt))
|
||||||
self.link.write(pkt)
|
self.link.write(pkt)
|
||||||
|
|
||||||
def encrypt(self, data):
|
def encrypt(self, data):
|
||||||
|
|
50
read_bms.py
50
read_bms.py
|
@ -11,35 +11,35 @@ from py9b.command.regio import ReadRegs
|
||||||
|
|
||||||
READ_CHUNK_SIZE = 0x10
|
READ_CHUNK_SIZE = 0x10
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
link = BLELink()
|
link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
hfo = open("BmsRegs.bin", "wb")
|
hfo = open("BmsRegs.bin", "wb")
|
||||||
for i in xrange(0x0, 0x100, READ_CHUNK_SIZE):
|
for i in xrange(0x0, 0x100, READ_CHUNK_SIZE):
|
||||||
print ".",
|
print(".")
|
||||||
for retry in xrange(5):
|
for retry in xrange(5):
|
||||||
try:
|
try:
|
||||||
data = tran.execute(ReadRegs(BT.BMS, i>>1, "16s"))[0]
|
data = tran.execute(ReadRegs(BT.BMS, i >> 1, "16s"))[0]
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print "No response !"
|
print("No response !")
|
||||||
break
|
break
|
||||||
hfo.write(data)
|
hfo.write(data)
|
||||||
|
|
||||||
hfo.close()
|
hfo.close()
|
||||||
link.close()
|
link.close()
|
||||||
|
|
|
@ -10,37 +10,37 @@ from py9b.transport.xiaomi import XiaomiTransport
|
||||||
READ_CHUNK_SIZE = 0x10
|
READ_CHUNK_SIZE = 0x10
|
||||||
|
|
||||||
link = SerialLink(dump=True)
|
link = SerialLink(dump=True)
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
tran = XiaomiTransport(link)
|
tran = XiaomiTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0, data=chr(READ_CHUNK_SIZE))
|
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0, data=chr(READ_CHUNK_SIZE))
|
||||||
|
|
||||||
hfo = open("BmsRegs.bin", "wb")
|
hfo = open("BmsRegs.bin", "wb")
|
||||||
for i in xrange(0x0, 0x100, READ_CHUNK_SIZE):
|
for i in xrange(0x0, 0x100, READ_CHUNK_SIZE):
|
||||||
print ".",
|
print(".")
|
||||||
req.arg = i>>1
|
req.arg = i >> 1
|
||||||
for retry in xrange(5):
|
for retry in xrange(5):
|
||||||
tran.send(req)
|
tran.send(req)
|
||||||
try:
|
try:
|
||||||
rsp = tran.recv()
|
rsp = tran.recv()
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print "No response !"
|
print("No response !")
|
||||||
break
|
break
|
||||||
hfo.write(rsp.data)
|
hfo.write(rsp.data)
|
||||||
|
|
||||||
hfo.close()
|
hfo.close()
|
||||||
link.close()
|
link.close()
|
||||||
|
|
|
@ -13,33 +13,33 @@ SIZE = 0x800
|
||||||
READ_CHUNK_SIZE = 0x10
|
READ_CHUNK_SIZE = 0x10
|
||||||
|
|
||||||
link = SerialLink(dump=True)
|
link = SerialLink(dump=True)
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
tran = XiaomiTransport(link)
|
tran = XiaomiTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
hfo = open("BmsEep.bin", "wb")
|
hfo = open("BmsEep.bin", "wb")
|
||||||
for i in xrange(ADDR, ADDR+SIZE, READ_CHUNK_SIZE):
|
for i in xrange(ADDR, ADDR + SIZE, READ_CHUNK_SIZE):
|
||||||
print ".",
|
print(".")
|
||||||
for retry in xrange(5):
|
for retry in xrange(5):
|
||||||
try:
|
try:
|
||||||
data = tran.execute(ReadMem(BT.BMS, i, "16s"))[0]
|
data = tran.execute(ReadMem(BT.BMS, i, "16s"))[0]
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print "No response !"
|
print("No response !")
|
||||||
break
|
break
|
||||||
hfo.write(data)
|
hfo.write(data)
|
||||||
|
|
||||||
hfo.close()
|
hfo.close()
|
||||||
link.close()
|
link.close()
|
||||||
|
|
50
read_esc.py
50
read_esc.py
|
@ -12,34 +12,34 @@ from py9b.command.regio import ReadRegs
|
||||||
READ_CHUNK_SIZE = 0x10
|
READ_CHUNK_SIZE = 0x10
|
||||||
|
|
||||||
link = SerialLink()
|
link = SerialLink()
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
hfo = open("EscRegs.bin", "wb")
|
hfo = open("EscRegs.bin", "wb")
|
||||||
for i in xrange(0x0, 0x200, READ_CHUNK_SIZE):
|
for i in xrange(0x0, 0x200, READ_CHUNK_SIZE):
|
||||||
print ".",
|
print(".")
|
||||||
for retry in xrange(5):
|
for retry in xrange(5):
|
||||||
try:
|
try:
|
||||||
data = tran.execute(ReadRegs(BT.ESC, i>>1, "16s"))[0]
|
data = tran.execute(ReadRegs(BT.ESC, i >> 1, "16s"))[0]
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print "No response !"
|
print("No response !")
|
||||||
break
|
break
|
||||||
hfo.write(data)
|
hfo.write(data)
|
||||||
|
|
||||||
hfo.close()
|
hfo.close()
|
||||||
link.close()
|
link.close()
|
||||||
|
|
|
@ -9,35 +9,35 @@ from py9b.transport.xiaomi import XiaomiTransport
|
||||||
|
|
||||||
READ_CHUNK_SIZE = 0x40
|
READ_CHUNK_SIZE = 0x40
|
||||||
|
|
||||||
#link = SerialLink()
|
# link = SerialLink()
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
link = BLELink()
|
link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
tran = XiaomiTransport(link)
|
tran = XiaomiTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x01, arg=0, data=chr(READ_CHUNK_SIZE))
|
req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x01, arg=0, data=chr(READ_CHUNK_SIZE))
|
||||||
|
|
||||||
hfo = open("EscRegs.bin", "wb")
|
hfo = open("EscRegs.bin", "wb")
|
||||||
for i in xrange(0, 0x200, READ_CHUNK_SIZE):
|
for i in xrange(0, 0x200, READ_CHUNK_SIZE):
|
||||||
print ".",
|
print(".")
|
||||||
req.arg = i>>1
|
req.arg = i >> 1
|
||||||
for retry in xrange(3):
|
for retry in xrange(3):
|
||||||
tran.send(req)
|
tran.send(req)
|
||||||
try:
|
try:
|
||||||
rsp = tran.recv()
|
rsp = tran.recv()
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
hfo.write(rsp.data)
|
hfo.write(rsp.data)
|
||||||
|
|
||||||
hfo.close()
|
hfo.close()
|
||||||
link.close()
|
link.close()
|
||||||
|
|
163
readregs.py
163
readregs.py
|
@ -17,92 +17,115 @@ from py9b.command.regio import ReadRegs
|
||||||
|
|
||||||
READ_CHUNK_SIZE = 0x10
|
READ_CHUNK_SIZE = 0x10
|
||||||
|
|
||||||
|
|
||||||
def ReadAllRegs(link, tran, dev, hfo):
|
def ReadAllRegs(link, tran, dev, hfo):
|
||||||
size = 0x200 if dev==BT.ESC else 0x100
|
size = 0x200 if dev == BT.ESC else 0x100
|
||||||
pb = ProgressBar(maxval=size).start()
|
pb = ProgressBar(maxval=size).start()
|
||||||
for i in xrange(0x0, size, READ_CHUNK_SIZE):
|
for i in xrange(0x0, size, READ_CHUNK_SIZE):
|
||||||
pb.update(i)
|
pb.update(i)
|
||||||
for retry in xrange(5):
|
for retry in xrange(5):
|
||||||
try:
|
try:
|
||||||
data = tran.execute(ReadRegs(dev, i>>1, '16s'))[0]
|
data = tran.execute(ReadRegs(dev, i >> 1, "16s"))[0]
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print('No response !')
|
print("No response !")
|
||||||
return False
|
return False
|
||||||
hfo.write(data)
|
hfo.write(data)
|
||||||
pb.finish()
|
pb.finish()
|
||||||
print('OK')
|
print("OK")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
parser = argparse.ArgumentParser(
|
||||||
description='Xiaomi/Ninebot register reader',
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
epilog='Example 1: %(prog)s esc esc_regs.bin - read ESC regs to esc_regs.bin using default communication parameters'
|
description="Xiaomi/Ninebot register reader",
|
||||||
'\nExample 2: %(prog)s -i tcp -a 127.0.1.10:6000 bms bms_regs.bin - flash BMS regs over TCP-BLE bridge at 127.0.1.10:6000'
|
epilog="Example 1: %(prog)s esc esc_regs.bin - read ESC regs to esc_regs.bin using default communication parameters"
|
||||||
'\nExample 3: %(prog)s -i serial -a COM2 esc esc_regs.bin - read ESC regs via COM2'
|
"\nExample 2: %(prog)s -i tcp -a 127.0.1.10:6000 bms bms_regs.bin - flash BMS regs over TCP-BLE bridge at 127.0.1.10:6000"
|
||||||
'\nExample 4: %(prog)s -i ble -a 12:34:56:78:9A:BC esc esc_regs.bin - read ESC regs via BLE, use specified BLE address')
|
"\nExample 3: %(prog)s -i serial -a COM2 esc esc_regs.bin - read ESC regs via COM2"
|
||||||
|
"\nExample 4: %(prog)s -i ble -a 12:34:56:78:9A:BC esc esc_regs.bin - read ESC regs via BLE, use specified BLE address",
|
||||||
devices = {'esc' : BT.ESC, 'bms' : BT.BMS, 'extbms' : BT.EXTBMS }
|
)
|
||||||
parser.add_argument('device', help='device to read from', type=str.lower, choices=devices)
|
|
||||||
|
|
||||||
parser.add_argument('file', type=argparse.FileType('wb'), help='output file')
|
devices = {"esc": BT.ESC, "bms": BT.BMS, "extbms": BT.EXTBMS}
|
||||||
|
parser.add_argument(
|
||||||
|
"device", help="device to read from", type=str.lower, choices=devices
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument('-i', '--interface', help='communication interface, default: %(default)s', type=str.lower,
|
parser.add_argument("file", type=argparse.FileType("wb"), help="output file")
|
||||||
choices=('ble', 'serial', 'tcp'), default='ble')
|
|
||||||
|
|
||||||
parser.add_argument('-a', '--address', help='communication address (ble: BDADDR, serial: port, tcp: host:port), default: first available')
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--interface",
|
||||||
|
help="communication interface, default: %(default)s",
|
||||||
|
type=str.lower,
|
||||||
|
choices=("ble", "serial", "tcp"),
|
||||||
|
default="ble",
|
||||||
|
)
|
||||||
|
|
||||||
protocols = {'xiaomi' : XiaomiTransport, 'ninebot' : NinebotTransport }
|
parser.add_argument(
|
||||||
parser.add_argument('-p', '--protocol', help='communication protocol, default: %(default)s', type=str.lower,
|
"-a",
|
||||||
choices=protocols, default='xiaomi')
|
"--address",
|
||||||
|
help="communication address (ble: BDADDR, serial: port, tcp: host:port), default: first available",
|
||||||
|
)
|
||||||
|
|
||||||
if len(argv)==1:
|
protocols = {"xiaomi": XiaomiTransport, "ninebot": NinebotTransport}
|
||||||
parser.print_usage()
|
parser.add_argument(
|
||||||
exit()
|
"-p",
|
||||||
|
"--protocol",
|
||||||
|
help="communication protocol, default: %(default)s",
|
||||||
|
type=str.lower,
|
||||||
|
choices=protocols,
|
||||||
|
default="xiaomi",
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(argv) == 1:
|
||||||
|
parser.print_usage()
|
||||||
|
exit()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.device=='extbms' and args.protocol!='ninebot':
|
if args.device == "extbms" and args.protocol != "ninebot":
|
||||||
exit('Only Ninebot supports External BMS !')
|
exit("Only Ninebot supports External BMS !")
|
||||||
|
|
||||||
dev = devices.get(args.device)
|
dev = devices.get(args.device)
|
||||||
|
|
||||||
if args.interface=='ble':
|
if args.interface == "ble":
|
||||||
try:
|
try:
|
||||||
from py9b.link.ble import BLELink
|
from py9b.link.ble import BLELink
|
||||||
except:
|
except:
|
||||||
exit('BLE is not supported on your system !')
|
exit("BLE is not supported on your system !")
|
||||||
link = BLELink()
|
link = BLELink()
|
||||||
elif args.interface=='tcp':
|
elif args.interface == "tcp":
|
||||||
from py9b.link.tcp import TCPLink
|
from py9b.link.tcp import TCPLink
|
||||||
link = TCPLink()
|
|
||||||
elif args.interface=='serial':
|
link = TCPLink()
|
||||||
from py9b.link.serial import SerialLink
|
elif args.interface == "serial":
|
||||||
link = SerialLink()
|
from py9b.link.serial import SerialLink
|
||||||
|
|
||||||
|
link = SerialLink()
|
||||||
else:
|
else:
|
||||||
exit('!!! BUG !!! Unknown interface selected: '+args.interface)
|
exit("!!! BUG !!! Unknown interface selected: " + args.interface)
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
tran = protocols.get(args.protocol)(link)
|
tran = protocols.get(args.protocol)(link)
|
||||||
|
|
||||||
if args.address:
|
if args.address:
|
||||||
addr = args.address
|
addr = args.address
|
||||||
else:
|
else:
|
||||||
print('Scanning...')
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
if not ports:
|
if not ports:
|
||||||
exit('No interfaces found !')
|
exit("No interfaces found !")
|
||||||
print('Connecting to', ports[0][0])
|
print("Connecting to", ports[0][0])
|
||||||
addr = ports[0][1]
|
addr = ports[0][1]
|
||||||
|
|
||||||
link.open(addr)
|
link.open(addr)
|
||||||
print('Connected')
|
print("Connected")
|
||||||
try:
|
try:
|
||||||
ReadAllRegs(link, tran, dev, args.file)
|
ReadAllRegs(link, tran, dev, args.file)
|
||||||
args.file.close()
|
args.file.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('Error:', e)
|
print("Error:", e)
|
||||||
raise
|
raise
|
||||||
|
|
32
reboot.py
32
reboot.py
|
@ -1,31 +1,33 @@
|
||||||
#!python2-32
|
#!python2-32
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
from py9b.link.tcp import TCPLink
|
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.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
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.transport.ninebot import NinebotTransport
|
||||||
from py9b.command.regio import ReadRegs, WriteRegs
|
from py9b.command.regio import ReadRegs, WriteRegs
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.20:6000"))
|
link.open(("127.0.0.20:6000"))
|
||||||
# link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
print('Reboot...')
|
print("Reboot...")
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x78, '<H', 0x0001))
|
tran.execute(WriteRegs(BT.ESC, 0x78, "<H", 0x0001))
|
||||||
|
|
||||||
link.close()
|
link.close()
|
||||||
|
|
109
sniffer.py
109
sniffer.py
|
@ -1,8 +1,9 @@
|
||||||
#!python2-32
|
#!python2-32
|
||||||
from struct import unpack
|
from struct import unpack
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
#from py9b.link.tcp import TCPLink
|
|
||||||
#from py9b.link.ble import BLELink
|
# from py9b.link.tcp import TCPLink
|
||||||
|
# from py9b.link.ble import BLELink
|
||||||
from py9b.link.serial import SerialLink
|
from py9b.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
from py9b.transport.packet import BasePacket as PKT
|
||||||
|
@ -10,57 +11,63 @@ from py9b.transport.xiaomi import XiaomiTransport
|
||||||
from py9b.transport.ninebot import NinebotTransport
|
from py9b.transport.ninebot import NinebotTransport
|
||||||
|
|
||||||
link = SerialLink()
|
link = SerialLink()
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
# link.open(("127.0.0.1", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
last_esc_64 = ""
|
last_esc_64 = ""
|
||||||
last_esc_65 = ""
|
last_esc_65 = ""
|
||||||
last_ble_64 = ""
|
last_ble_64 = ""
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
rsp = tran.recv()
|
rsp = tran.recv()
|
||||||
if not rsp:
|
if not rsp:
|
||||||
continue
|
continue
|
||||||
if rsp.src==BT.HOST and rsp.dst==BT.ESC and rsp.cmd in (0x64, 0x65):
|
if rsp.src == BT.HOST and rsp.dst == BT.ESC and rsp.cmd in (0x64, 0x65):
|
||||||
if len(rsp.data)==5:
|
if len(rsp.data) == 5:
|
||||||
if rsp.data==last_esc_65:
|
if rsp.data == last_esc_65:
|
||||||
continue
|
continue
|
||||||
ll, throttle, brake, u2, u3 = unpack("<BBBBB", rsp.data)
|
ll, throttle, brake, u2, u3 = unpack("<BBBBB", rsp.data)
|
||||||
print "BLE->ESC: TH: %02X, BR: %02X, %02X %02X" % (throttle, brake, u2, u3)
|
print(
|
||||||
last_esc_65 = rsp.data
|
"BLE->ESC: TH: %02X, BR: %02X, %02X %02X"
|
||||||
continue
|
% (throttle, brake, u2, u3)
|
||||||
elif len(rsp.data)==7:
|
)
|
||||||
if rsp.data==last_esc_64:
|
last_esc_65 = rsp.data
|
||||||
continue
|
continue
|
||||||
ll, throttle, brake, u2, u3, ver = unpack("<BBBBBH", rsp.data)
|
elif len(rsp.data) == 7:
|
||||||
print "BLE->ESC: TH: %02X, BR: %02X, %02X %02X, VER: %04X" % (throttle, brake, u2, u3, ver)
|
if rsp.data == last_esc_64:
|
||||||
last_esc_64 = rsp.data
|
continue
|
||||||
continue
|
ll, throttle, brake, u2, u3, ver = unpack("<BBBBBH", rsp.data)
|
||||||
elif rsp.src==BT.HOST and rsp.dst==BT.BLE and rsp.cmd==0x64:
|
print(
|
||||||
if len(rsp.data)==4:
|
"BLE->ESC: TH: %02X, BR: %02X, %02X %02X, VER: %04X"
|
||||||
if rsp.data==last_ble_64:
|
% (throttle, brake, u2, u3, ver)
|
||||||
continue
|
)
|
||||||
u0, u1, u2, u3 = unpack("<BBBB", rsp.data)
|
last_esc_64 = rsp.data
|
||||||
print "ESC->BLE: %02X %02X %02X %02X" % (u0, u1, u2, u3)
|
continue
|
||||||
last_ble_64 = rsp.data
|
elif rsp.src == BT.HOST and rsp.dst == BT.BLE and rsp.cmd == 0x64:
|
||||||
continue
|
if len(rsp.data) == 4:
|
||||||
print rsp
|
if rsp.data == last_ble_64:
|
||||||
except LinkTimeoutException:
|
continue
|
||||||
pass
|
u0, u1, u2, u3 = unpack("<BBBB", rsp.data)
|
||||||
except KeyboardInterrupt:
|
print("ESC->BLE: %02X %02X %02X %02X" % (u0, u1, u2, u3))
|
||||||
pass
|
last_ble_64 = rsp.data
|
||||||
|
continue
|
||||||
link.close()
|
print(rsp)
|
||||||
|
except LinkTimeoutException:
|
||||||
|
pass
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
|
link.close()
|
||||||
|
|
36
tcp_test.py
36
tcp_test.py
|
@ -4,26 +4,26 @@ from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
from py9b.transport.packet import BasePacket as PKT
|
||||||
from py9b.transport.xiaomi import XiaomiTransport
|
from py9b.transport.xiaomi import XiaomiTransport
|
||||||
|
|
||||||
#link = SerialLink()
|
# link = SerialLink()
|
||||||
with TCPLink() as link:
|
with TCPLink() as link:
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
tran = XiaomiTransport(link)
|
|
||||||
|
|
||||||
#link.open(("127.0.0.1", 6000))
|
tran = XiaomiTransport(link)
|
||||||
link.open(ports[0][1])
|
|
||||||
|
|
||||||
#req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x01, arg=0x10, data="\x10")
|
# link.open(("127.0.0.1", 6000))
|
||||||
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0x10, data="\x10")
|
link.open(ports[0][1])
|
||||||
|
|
||||||
while raw_input("Press ENTER to send...")!="q":
|
# req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x01, arg=0x10, data="\x10")
|
||||||
tran.send(req)
|
req = PKT(src=BT.HOST, dst=BT.BMS, cmd=0x01, arg=0x10, data="\x10")
|
||||||
try:
|
|
||||||
rsp = tran.recv()
|
|
||||||
except LinkTimeoutException:
|
|
||||||
print "No response"
|
|
||||||
continue
|
|
||||||
print rsp
|
|
||||||
|
|
||||||
link.close()
|
while raw_input("Press ENTER to send...") != "q":
|
||||||
|
tran.send(req)
|
||||||
|
try:
|
||||||
|
rsp = tran.recv()
|
||||||
|
except LinkTimeoutException:
|
||||||
|
print("No response")
|
||||||
|
continue
|
||||||
|
print(rsp)
|
||||||
|
|
||||||
|
link.close()
|
||||||
|
|
32
unlock.py
32
unlock.py
|
@ -1,31 +1,33 @@
|
||||||
#!python2-32
|
#!python2-32
|
||||||
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
from py9b.link.base import LinkOpenException, LinkTimeoutException
|
||||||
from py9b.link.tcp import TCPLink
|
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.link.serial import SerialLink
|
||||||
from py9b.transport.base import BaseTransport as BT
|
from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
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.transport.ninebot import NinebotTransport
|
||||||
from py9b.command.regio import ReadRegs, WriteRegs
|
from py9b.command.regio import ReadRegs, WriteRegs
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.20:6000"))
|
link.open(("127.0.0.20:6000"))
|
||||||
# link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
print('Unlocking...')
|
print("Unlocking...")
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x71, '<H', 0x0001))
|
tran.execute(WriteRegs(BT.ESC, 0x71, "<H", 0x0001))
|
||||||
|
|
||||||
link.close()
|
link.close()
|
||||||
|
|
32
wr_esc.py
32
wr_esc.py
|
@ -6,27 +6,27 @@ from py9b.transport.base import BaseTransport as BT
|
||||||
from py9b.transport.packet import BasePacket as PKT
|
from py9b.transport.packet import BasePacket as PKT
|
||||||
from py9b.transport.xiaomi import XiaomiTransport
|
from py9b.transport.xiaomi import XiaomiTransport
|
||||||
|
|
||||||
#link = SerialLink()
|
# link = SerialLink()
|
||||||
link = TCPLink()
|
link = TCPLink()
|
||||||
#link = BLELink()
|
# link = BLELink()
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print "Scanning..."
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print ports
|
print(ports)
|
||||||
|
|
||||||
tran = XiaomiTransport(link)
|
tran = XiaomiTransport(link)
|
||||||
|
|
||||||
link.open(("127.0.0.1", 6000))
|
link.open(("127.0.0.1", 6000))
|
||||||
#link.open(ports[0][1])
|
# link.open(ports[0][1])
|
||||||
print "Connected"
|
print("Connected")
|
||||||
|
|
||||||
req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x02, arg=0x41, data="\xCE\xAB\x00\x00")
|
req = PKT(src=BT.HOST, dst=BT.ESC, cmd=0x02, arg=0x41, data="\xCE\xAB\x00\x00")
|
||||||
|
|
||||||
tran.send(req)
|
tran.send(req)
|
||||||
try:
|
try:
|
||||||
rsp = tran.recv()
|
rsp = tran.recv()
|
||||||
finally:
|
finally:
|
||||||
link.close()
|
link.close()
|
||||||
|
|
||||||
print rsp
|
print(rsp)
|
||||||
|
|
106
wr_esc_sn.py
106
wr_esc_sn.py
|
@ -14,75 +14,75 @@ from py9b.command.mfg import WriteSN
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
|
||||||
#new_sn = "16133/00101234"
|
# new_sn = "16133/00101234"
|
||||||
#new_sn = "N2GTR1826C1234"
|
# new_sn = "N2GTR1826C1234"
|
||||||
|
|
||||||
|
|
||||||
def CalcSnAuth(oldsn, newsn, uid3):
|
def CalcSnAuth(oldsn, newsn, uid3):
|
||||||
s = 0
|
s = 0
|
||||||
for i in xrange(0x0E):
|
for i in xrange(0x0E):
|
||||||
s += ord(oldsn[i])
|
s += ord(oldsn[i])
|
||||||
s *= ord(newsn[i])
|
s *= ord(newsn[i])
|
||||||
s += uid3+(uid3<<4)
|
s += uid3 + (uid3 << 4)
|
||||||
s &= 0xFFFFFFFF
|
s &= 0xFFFFFFFF
|
||||||
if (s & 0x80000000)!=0:
|
if (s & 0x80000000) != 0:
|
||||||
s = 0x100000000-s
|
s = 0x100000000 - s
|
||||||
|
|
||||||
return s % 1000000
|
return s % 1000000
|
||||||
|
|
||||||
|
|
||||||
#link = SerialLink(dump=True)
|
# link = SerialLink(dump=True)
|
||||||
#link = TCPLink()
|
# link = TCPLink()
|
||||||
link = BLELink(dump=True)
|
link = BLELink(dump=True)
|
||||||
|
|
||||||
with link:
|
with link:
|
||||||
print("Scanning...")
|
print("Scanning...")
|
||||||
ports = link.scan()
|
ports = link.scan()
|
||||||
print(ports)
|
print(ports)
|
||||||
|
|
||||||
#tran = XiaomiTransport(link)
|
# tran = XiaomiTransport(link)
|
||||||
tran = NinebotTransport(link)
|
tran = NinebotTransport(link)
|
||||||
|
|
||||||
#link.open(("192.168.1.45", 6000))
|
# link.open(("192.168.1.45", 6000))
|
||||||
link.open(ports[0][1])
|
link.open(ports[0][1])
|
||||||
print("Connected")
|
print("Connected")
|
||||||
|
|
||||||
print("Pinging...")
|
print("Pinging...")
|
||||||
for retry in xrange(20):
|
for retry in xrange(20):
|
||||||
print(".", end="")
|
print(".", end="")
|
||||||
try:
|
try:
|
||||||
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
exit("Timed out !")
|
exit("Timed out !")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
# lock
|
||||||
#lock
|
# tran.execute(WriteRegs(BT.ESC, 0x70, "<H", 0x01))
|
||||||
#tran.execute(WriteRegs(BT.ESC, 0x70, "<H", 0x01))
|
|
||||||
|
|
||||||
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
||||||
print("Old S/N:", old_sn)
|
print("Old S/N:", old_sn)
|
||||||
|
|
||||||
uid3 = tran.execute(ReadRegs(BT.ESC, 0xDE, "<L"))[0]
|
uid3 = tran.execute(ReadRegs(BT.ESC, 0xDE, "<L"))[0]
|
||||||
print("UID3: %08X" % (uid3))
|
print("UID3: %08X" % (uid3))
|
||||||
|
|
||||||
auth = CalcSnAuth(old_sn, new_sn, uid3)
|
auth = CalcSnAuth(old_sn, new_sn, uid3)
|
||||||
#auth = 0
|
# auth = 0
|
||||||
print("Auth: %08X" % (auth))
|
print("Auth: %08X" % (auth))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tran.execute(WriteSN(BT.ESC, new_sn, auth))
|
tran.execute(WriteSN(BT.ESC, new_sn, auth))
|
||||||
print("OK")
|
print("OK")
|
||||||
except LinkTimeoutException:
|
except LinkTimeoutException:
|
||||||
print("Timeout !")
|
print("Timeout !")
|
||||||
|
|
||||||
# save config and restart
|
# save config and restart
|
||||||
tran.execute(WriteRegs(BT.ESC, 0x78, "<H", 0x01))
|
tran.execute(WriteRegs(BT.ESC, 0x78, "<H", 0x01))
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
old_sn = tran.execute(ReadRegs(BT.ESC, 0x10, "14s"))[0]
|
||||||
print("Current S/N:", old_sn)
|
print("Current S/N:", old_sn)
|
||||||
|
|
||||||
link.close()
|
link.close()
|
||||||
|
|
Loading…
Reference in New Issue