python-validity/validitysensor/usb.py
Arvid Norlander 9a5b045378
Get rid of star imports.
These are dangerous as you will import not only the functions defined
in the other module but also all of it's imports! This makes automated
cleanups brittle.
2020-08-06 11:46:19 +02:00

132 lines
3.5 KiB
Python

import logging
import errno
import usb.core as ucore
from binascii import hexlify, unhexlify
from .util import assert_status
from struct import unpack
from usb.core import USBError
from .blobs import init_hardcoded, init_hardcoded_clean_slate
supported_devices = [
(0x138a, 0x0090),
(0x138a, 0x0097),
(0x06cb, 0x009a),
]
class CancelledException(Exception):
pass
class Usb():
def __init__(self):
self.interrupt_cb = None
self.trace_enabled = False
self.dev = None
self.cancel = False
def open(self, vendor=None, product=None):
if vendor is not None and product is not None:
dev = ucore.find(idVendor=vendor, idProduct=product)
else:
def match(d):
return (d.idVendor, d.idProduct) in supported_devices
dev = ucore.find(custom_match=match)
self.open_dev(dev)
def open_devpath(self, busnum, address):
def match(d):
return d.bus == busnum and d.address == address
dev = ucore.find(custom_match=match)
self.open_dev(dev)
def open_dev(self, dev):
if dev is None:
raise Exception('No matching devices found')
self.dev = dev
self.dev.default_timeout = 15000
def close(self):
if self.dev is not None:
try:
self.dev.reset()
self.dev = None
except:
pass
def usb_dev(self):
return self.dev
def send_init(self):
#self.dev.set_configuration()
# TODO analyse responses, detect hardware type
assert_status(self.cmd(unhexlify('01'))) # RomInfo.get()
assert_status(self.cmd(unhexlify('19')))
# 43 -- get partition header(?) (02 -- fwext partition)
# c28c745a in response is a FwextBuildtime = 0x5A748CC2
rsp = self.cmd(unhexlify('4302')) # get_fw_info()
assert_status(self.cmd(init_hardcoded))
(err, ), rsp = unpack('<H', rsp[:2]), rsp[2:]
if err != 0:
# fwext is not loaded
logging.info('Clean slate')
self.cmd(init_hardcoded_clean_slate)
def cmd(self, out):
if callable(out):
out = out()
if not out:
return 0
self.trace('>cmd> %s' % hexlify(out).decode())
self.dev.write(1, out)
resp = self.dev.read(129, 100 * 1024)
resp = bytes(resp)
self.trace('<cmd< %s' % hexlify(resp).decode())
return resp
def read_82(self):
try:
resp = self.dev.read(130, 1024 * 1024, timeout=10000)
resp = bytes(resp)
self.trace('<130< %s' % hexlify(resp).decode())
return resp
except Exception as e:
self.trace('<130< Error: %s' % repr(e))
return None
# FIXME There is a chance of a race condition here
def cancel(self):
self.cancel = True
def wait_int(self):
self.cancel = False
while True:
try:
resp = self.dev.read(131, 1024, timeout=100)
resp = bytes(resp)
self.trace('<int< %s' % hexlify(resp).decode())
return resp
except USBError as e:
if e.errno == errno.ETIMEDOUT:
if self.cancel:
raise CancelledException()
else:
raise e
def trace(self, s):
if self.trace_enabled:
logging.debug(s)
usb = Usb()