Fix writing on large files. Improve speed. Improve usb handling to match newer libusb. Bug fixing.

This commit is contained in:
Bjoern Kerler 2021-06-19 00:48:16 +02:00
parent 8d8eadb92f
commit 28868105f5
4 changed files with 99 additions and 96 deletions

View file

@ -201,9 +201,9 @@ class firehose(metaclass=LogBase):
def xmlsend(self, data, skipresponse=False):
if isinstance(data, bytes) or isinstance(data, bytearray):
self.cdc.write(data, self.cfg.MaxXMLSizeInBytes)
self.cdc.write(data[:self.cfg.MaxXMLSizeInBytes])
else:
self.cdc.write(bytes(data, 'utf-8'), self.cfg.MaxXMLSizeInBytes)
self.cdc.write(bytes(data, 'utf-8')[:self.cfg.MaxXMLSizeInBytes])
# time.sleep(0.01)
rdata = bytearray()
counter = 0
@ -416,13 +416,7 @@ class firehose(metaclass=LogBase):
if rsp[0]:
old = 0
while bytestowrite > 0:
# todo: Why on earth doesn't MaxPayloadSizeToTargetInBytes work here ?
# Forced to use self.cfg.SECTOR_SIZE_IN_BYTES ... thus slow as hell
"""
wlen = min(bytestowrite, self.cfg.MaxPayloadSizeToTargetInBytes // self.cfg.SECTOR_SIZE_IN_BYTES \
* self.cfg.SECTOR_SIZE_IN_BYTES)
"""
wlen = min(bytestowrite, self.cfg.SECTOR_SIZE_IN_BYTES)
wlen = min(bytestowrite, self.cfg.MaxPayloadSizeToTargetInBytes)
if sparseformat:
wdata = sparse.read(wlen)
@ -434,9 +428,8 @@ class firehose(metaclass=LogBase):
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + \
self.cfg.SECTOR_SIZE_IN_BYTES
wdata += b"\x00" * (filllen - wlen)
wlen = len(wdata)
self.cdc.write(wdata, wlen)
self.cdc.write(wdata)
prog = round(float(total - bytestowrite) / float(total) * float(100), 1)
if prog > old:
@ -447,7 +440,7 @@ class firehose(metaclass=LogBase):
bar_length=50)
old = prog
self.cdc.write(b'', self.cfg.MaxPayloadSizeToTargetInBytes)
self.cdc.write(b'')
# time.sleep(0.2)
wd = self.wait_for_data()
@ -467,10 +460,11 @@ class firehose(metaclass=LogBase):
return True
def cmd_program_buffer(self, physical_partition_number, start_sector, wfdata, display=True):
size = len(wfdata)
bytestowrite = len(wfdata)
total = bytestowrite
# Make sure we fill data up to the sector size
num_partition_sectors = size // self.cfg.SECTOR_SIZE_IN_BYTES
if (size % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
num_partition_sectors = bytestowrite // self.cfg.SECTOR_SIZE_IN_BYTES
if (bytestowrite % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
num_partition_sectors += 1
if display:
self.info(f"\nWriting to physical partition {str(physical_partition_number)}, " +
@ -481,66 +475,57 @@ class firehose(metaclass=LogBase):
f" num_partition_sectors=\"{num_partition_sectors}\"" + \
f" physical_partition_number=\"{physical_partition_number}\"" + \
f" start_sector=\"{start_sector}\" "
if self.modules is not None:
data += self.modules.addprogram()
data += f"/>\n</data>"
rsp = self.xmlsend(data)
pos = 0
rsp = self.xmlsend(data, self.skipresponse)
prog = 0
# time.sleep(0.01)
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
print_progress(prog, 100, prefix='Progress:', suffix='Complete (Sector %d)' % start_sector,
bar_length=50)
if rsp[0]:
bytesToWrite = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
total = self.cfg.SECTOR_SIZE_IN_BYTES * num_partition_sectors
old = 0
fpos = 0
fsize = len(wfdata)
while fsize > 0:
# todo: Why on earth doesn't MaxPayloadSizeToTargetInBytes work here ?
# Forced to use self.cfg.SECTOR_SIZE_IN_BYTES ... thus slow as hell
"""
wlen = self.cfg.MaxPayloadSizeToTargetInBytes // self.cfg.SECTOR_SIZE_IN_BYTES \
* self.cfg.SECTOR_SIZE_IN_BYTES
wlen = min(fsize, wlen)
"""
wlen = min(fsize, self.cfg.SECTOR_SIZE_IN_BYTES)
wdata = wfdata[fpos:fpos + wlen]
bytesToWrite -= wlen
fsize -= wlen
pos += wlen
fpos += wlen
if (wlen % self.cfg.SECTOR_SIZE_IN_BYTES) != 0:
pos = 0
while bytestowrite > 0:
wlen = min(bytestowrite, self.cfg.MaxPayloadSizeToTargetInBytes)
wdata = data[pos:pos+wlen]
pos+=wlen
bytestowrite -= wlen
if wlen % self.cfg.SECTOR_SIZE_IN_BYTES != 0:
filllen = (wlen // self.cfg.SECTOR_SIZE_IN_BYTES * self.cfg.SECTOR_SIZE_IN_BYTES) + \
self.cfg.SECTOR_SIZE_IN_BYTES
wdata += b"\x00" * (filllen - wlen)
wlen = len(wdata)
self.cdc.write(wdata, wlen)
prog = round(float(pos) / float(total) * float(100), 1)
self.cdc.write(wdata)
prog = round(float(total - bytestowrite) / float(total) * float(100), 1)
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Written (Sector %d)'
% (pos // self.cfg.SECTOR_SIZE_IN_BYTES),
print_progress(prog, 100, prefix='Progress:',
suffix='Complete (Sector %d)' % ((total - bytestowrite) //
self.cfg.SECTOR_SIZE_IN_BYTES),
bar_length=50)
if display and prog != 100:
print_progress(100, 100, prefix='Progress:', suffix='Done', bar_length=50)
self.cdc.write(b'', self.cfg.MaxPayloadSizeToTargetInBytes)
old = prog
self.cdc.write(b'')
# time.sleep(0.2)
wd = self.wait_for_data()
info = self.xml.getlog(wd)
log = self.xml.getlog(wd)
rsp = self.xml.getresponse(wd)
if "value" in rsp:
if rsp["value"] != "ACK":
self.error(f"Error:")
for line in info:
for line in log:
self.error(line)
return False
else:
self.error(f"Error:{rsp}")
return False
else:
self.error(f"Error:{rsp}")
return False
if display and prog != 100:
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
print_progress(100, 100, prefix='Progress:', suffix='Done', bar_length=50)
return True
def cmd_erase(self, physical_partition_number, start_sector, num_partition_sectors, display=True):
@ -576,7 +561,7 @@ class firehose(metaclass=LogBase):
wlen = bytesToWrite
"""
wlen = min(bytesToWrite, self.cfg.SECTOR_SIZE_IN_BYTES)
self.cdc.write(empty[0:wlen], self.cfg.MaxPayloadSizeToTargetInBytes)
self.cdc.write(empty[0:wlen])
prog = round(float(pos) / float(total) * float(100), 1)
if prog > old:
if display:
@ -587,7 +572,7 @@ class firehose(metaclass=LogBase):
pos += wlen
if display and prog != 100:
print_progress(100, 100, prefix='Progress:', suffix='Done', bar_length=50)
self.cdc.write(b'', self.cfg.MaxPayloadSizeToTargetInBytes)
self.cdc.write(b'')
# time.sleep(0.2)
res = self.wait_for_data()
info = self.xml.getlog(res)
@ -635,12 +620,13 @@ class firehose(metaclass=LogBase):
prog = 0
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
# todo: Why on earth doesn't MaxPayloadSizeToTargetInBytes work here ?
# Forced to use self.cfg.SECTOR_SIZE_IN_BYTES ... thus slow as hell
size = min(self.cfg.SECTOR_SIZE_IN_BYTES, 1048576)
while bytesToRead > 0:
size = min(size, bytesToRead)
tmp = self.cdc.read(size)
if bytesToRead > self.cfg.MaxPayloadSizeFromTargetInBytes:
tmp = b"".join([self.cdc.read(self.cdc.EP_IN.wMaxPacketSize)
for _ in range(self.cfg.MaxPayloadSizeFromTargetInBytes//self.cdc.EP_IN.wMaxPacketSize)])
else:
size = min(self.cdc.EP_IN.wMaxPacketSize, bytesToRead)
tmp = self.cdc.read(size)
bytesToRead -= len(tmp)
wr.write(tmp)
if display:
@ -699,13 +685,13 @@ class firehose(metaclass=LogBase):
prog = 0
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Complete', bar_length=50)
# todo: Why on earth doesn't MaxPayloadSizeToTargetInBytes work here ?
# Forced to use self.cfg.SECTOR_SIZE_IN_BYTES ... thus slow as hell
#size = min(self.cfg.SECTOR_SIZE_IN_BYTES, 1048576)
size = min(self.cfg.SECTOR_SIZE_IN_BYTES, 1048576)
while bytesToRead > 0:
size = min(size, bytesToRead)
tmp = self.cdc.read(size)
if bytesToRead > self.cfg.MaxPayloadSizeFromTargetInBytes:
tmp = b"".join([self.cdc.read(self.cdc.EP_IN.wMaxPacketSize) for _ in
range(self.cfg.MaxPayloadSizeFromTargetInBytes // self.cdc.EP_IN.wMaxPacketSize)])
else:
size = min(self.cdc.EP_IN.wMaxPacketSize, bytesToRead)
tmp = self.cdc.read(size)
bytesToRead -= len(tmp)
dataread += len(tmp)
resData += tmp
@ -713,9 +699,7 @@ class firehose(metaclass=LogBase):
if prog > old:
if display:
print_progress(prog, 100, prefix='Progress:', suffix='Read (Sector %d)'
% (
dataread // self.cfg.SECTOR_SIZE_IN_BYTES),
bar_length=50)
% (dataread // self.cfg.SECTOR_SIZE_IN_BYTES), bar_length=50)
old = prog
if display and prog != 100:
print_progress(100, 100, prefix='Progress:', suffix='Complete', bar_length=50)
@ -1151,7 +1135,7 @@ class firehose(metaclass=LogBase):
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" " + \
f"SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
try:
self.cdc.write(xdata, self.cfg.MaxXMLSizeInBytes)
self.cdc.write(xdata[:self.cfg.MaxXMLSizeInBytes])
except Exception as e: # pylint: disable=broad-except
self.debug(str(e))
pass
@ -1162,7 +1146,7 @@ class firehose(metaclass=LogBase):
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
xdata = f"<?xml version=\"1.0\" ?><data><poke address64=\"{str(address + pos)}\" " + \
f"SizeInBytes=\"{str(maxsize)}\" value64=\"{content}\" /></data>\n"
self.cdc.write(xdata, self.cfg.MaxXMLSizeInBytes)
self.cdc.write(xdata[:self.cfg.MaxXMLSizeInBytes])
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b'<response' in addrinfo and 'NAK' in addrinfo) or b"Invalid parameters" in addrinfo:
self.error(f"Error:{addrinfo}")
@ -1211,7 +1195,7 @@ class firehose(metaclass=LogBase):
0xFF 0xEA 0xFE 0xFF 0xFF 0xEA 0xFE 0xFF " /></data>
'''
try:
self.cdc.write(data, self.cfg.MaxXMLSizeInBytes)
self.cdc.write(data[:self.cfg.MaxXMLSizeInBytes])
except Exception as err: # pylint: disable=broad-except
self.debug(str(err))
pass
@ -1222,7 +1206,7 @@ class firehose(metaclass=LogBase):
tmp += self.cdc.read(self.cfg.MaxXMLSizeInBytes)
data = f"<?xml version=\"1.0\" ?><data><peek address64=\"{hex(address)}\" " + \
f"SizeInBytes=\"{hex(SizeInBytes)}\" /></data>"
self.cdc.write(data, self.cfg.MaxXMLSizeInBytes)
self.cdc.write(data[:self.cfg.MaxXMLSizeInBytes])
addrinfo = self.cdc.read(self.cfg.MaxXMLSizeInBytes)
if (b'<response' in addrinfo and 'NAK' in addrinfo) or b"Invalid parameters" in addrinfo:
self.error(f"Error:{addrinfo}")

View file

@ -205,7 +205,7 @@ class hdlc:
tmp.append(0x7E)
tmp.extend(outdata)
outdata = tmp
return self.cdc.write(outdata, MAX_PACKET_LEN)
return self.cdc.write(outdata[:MAX_PACKET_LEN])
# FlushFileBuffers(ser)
def send_cmd_base(self, outdata, prefixflag, nocrc=False):

View file

@ -386,12 +386,12 @@ class sahara(metaclass=LogBase):
return ["nandprg", None]
else:
data = b"<?xml version=\"1.0\" ?><data><nop /></data>"
self.cdc.write(data, 0x80)
self.cdc.write(data)
res = self.cdc.read()
if res == b"":
try:
data = b"\x7E\x06\x4E\x95\x7E" # Streaming nop
self.cdc.write(data, 0x80)
self.cdc.write(data)
res = self.cdc.read()
if b"\x7E\x0D\x16\x00\x00\x00\x00" in res or b"Invalid Command" in res:
return ["nandprg", None]
@ -407,7 +407,7 @@ class sahara(metaclass=LogBase):
return ["sahara", None]
else:
data = b"\x7E\x11\x00\x12\x00\xA0\xE3\x00\x00\xC1\xE5\x01\x40\xA0\xE3\x1E\xFF\x2F\xE1\x4B\xD9\x7E"
self.cdc.write(data, 0x80)
self.cdc.write(data)
res = self.cdc.read()
if len(res) > 0 and res[1] == 0x12:
return ["nandprg", None]
@ -793,7 +793,7 @@ class sahara(metaclass=LogBase):
while len(programmer) < data_offset + data_len:
programmer += b"\xFF"
data_to_send = programmer[data_offset:data_offset + data_len]
self.cdc.write(data_to_send, self.pktsize)
self.cdc.write(data_to_send)
datalen -= data_len
self.info("Loader uploaded.")
cmd, pkt = self.get_rsp()

View file

@ -76,6 +76,7 @@ class UsbClass(metaclass=LogBase):
self.__logger.addHandler(fh)
def verify_data(self, data, pre="RX:"):
self.debug("", stack_info=True)
if isinstance(data, bytes) or isinstance(data, bytearray):
if data[:5] == b"<?xml":
try:
@ -84,11 +85,13 @@ class UsbClass(metaclass=LogBase):
try:
self.debug(pre + line.decode('utf-8'))
rdata += line + b"\n"
except: # pylint: disable=broad-except
except Exception as e: # pylint: disable=broad-except
v = hexlify(line)
self.debug(str(e))
self.debug(pre + v.decode('utf-8'))
return rdata
except: # pylint: disable=broad-except
except Exception as e: # pylint: disable=broad-except
self.debug(str(e))
pass
if logging.DEBUG >= self.__logger.level:
self.debug(pre + hexlify(data).decode('utf-8'))
@ -105,7 +108,8 @@ class UsbClass(metaclass=LogBase):
return False
try:
self.device.set_configuration()
except:
except Exception as e:
self.debug(str(e))
pass
self.configuration = self.device.get_active_configuration()
self.debug(2, self.configuration)
@ -247,8 +251,8 @@ class UsbClass(metaclass=LogBase):
if self.device.is_kernel_driver_active(self.interface):
self.debug("Detaching kernel driver")
self.device.detach_kernel_driver(self.interface)
except:
pass
except Exception as e:
self.debug(str(e))
usb.util.claim_interface(self.device, self.interface)
if ep_out == -1:
@ -282,29 +286,44 @@ class UsbClass(metaclass=LogBase):
self.device.attach_kernel_driver(0)
if reset:
self.device.reset()
except: # pylint: disable=broad-except
except Exception as e: # pylint: disable=broad-except
self.debug(str(e))
pass
del self.device
def write(self, command, pktsize=64):
def write(self, command):
pktsize=self.EP_OUT.wMaxPacketSize
if isinstance(command, str):
command = bytes(command, 'utf-8')
pos = 0
if command == b'':
self.device.write(self.EP_OUT, b'')
try:
self.EP_OUT.write(b'')
except usb.core.USBError as e:
error = str(e.strerror)
if "timeout" in error:
time.sleep(0.01)
try:
self.EP_OUT.write(b'')
except Exception as e: # pylint: disable=broad-except
self.debug(str(e))
return False
return True
else:
i = 0
while pos < len(command):
try:
self.device.write(self.EP_OUT, command[pos:pos + pktsize])
pos += pktsize
except: # pylint: disable=broad-except
# print("Error while writing")
time.sleep(0.05)
try:
[self.EP_OUT.write(command[pos:pos+pktsize]) for pos in range(0,len(command),pktsize)]
except Exception as e: # pylint: disable=broad-except
# print("Error while writing")
if "timed out" in str(e):
self.debug(str(e))
time.sleep(0.01)
i += 1
if i == 5:
if i == 3:
return False
pass
else:
self.error(str(e))
return False
self.verify_data(bytearray(command), "TX:")
return True
@ -315,7 +334,7 @@ class UsbClass(metaclass=LogBase):
timeout = self.timeout
while bytearray(tmp) == b'':
try:
tmp = self.device.read(self.EP_IN, length, timeout)
tmp = self.EP_IN.read(length, timeout)
except usb.core.USBError as e:
error = str(e.strerror)
if "timed out" in error: