python-validity/validitysensor/usb.py
2020-08-03 19:34:20 +02:00

129 lines
3.5 KiB
Python

import logging
import errno
import usb.core as ucore
from binascii import *
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()