Added slow flashing mode upto ten times slower that can help if the regular faster flashing is failing every time

This commit is contained in:
Adam Boardman 2020-12-19 16:01:29 +00:00
parent 5ef2d5c294
commit 5cc5cae2a9
2 changed files with 106 additions and 62 deletions

View file

@ -77,8 +77,6 @@ def check_new_fota_versions_available():
print("Newest Server Version:", newest_version)
if cf.get_codi_version() is not None and cf.get_resources_version() is not None:
print(LooseVersion(newest_version) > LooseVersion(cf.get_codi_version().replace('V', '')),
LooseVersion(newest_version) > LooseVersion(cf.get_resources_version().replace('R', '')))
return LooseVersion(newest_version) > LooseVersion(cf.get_codi_version().replace('V', '')) or \
LooseVersion(newest_version) > LooseVersion(cf.get_resources_version().replace('R', ''))
else:
@ -118,7 +116,7 @@ def callback(total_packets, success_count, error_count, total):
print_progress_bar(total_packets, error_count, total)
def send_file(file):
def send_file(file, slow_mode):
global ser
time.sleep(1) # Wait for listening thread to get started
@ -134,17 +132,17 @@ def send_file(file):
stm32_into_download_mode(False)
print("Send Command 1")
SerialPortManager.sendCommand(writeString("1"))
time.sleep(1)
time.sleep(2)
ser = SerialPortManager.get_socket()
modem = YMODEM(ser)
print("Sending", file)
print("Sending:", file)
print("Expect a few errors at 0% as the CoDi is erasing the flash, ~3 fw, ~15 res")
file_sent = False
try:
file_sent = modem.send(file, callback=callback)
file_sent = modem.send(file, slow_mode, callback=callback)
print("\r\nSend completed:", file_sent)
except Exception as e:
log.error(e)
@ -157,6 +155,9 @@ parser = optparse.OptionParser(usage='%prog [filename]')
parser.add_option("-d", "--debug",
action="store_true", dest="debug",
help="output debug logging to ymodem.log")
parser.add_option("-s", "--slow",
action="store_true", dest="slow_mode",
help="use slow mode for serial communications, this can help with stuck flashing")
options, args = parser.parse_args()
@ -170,7 +171,7 @@ lock_file.lock(lock)
SerialPortManager.init()
fileSent = False
if len(args) > 0:
fileSent = send_file(args[0])
fileSent = send_file(args[0], options.slow_mode)
else:
print("")
versionAvailable = check_new_fota_versions_available()

View file

@ -63,9 +63,7 @@ __copyright__ = ['Copyright (c) 2010 Wijnand Modderman',
__license__ = 'MIT'
__version__ = '0.4.5'
import platform
import logging
import time
import sys
import os
@ -159,7 +157,7 @@ class YMODEM(object):
for _ in range(count):
self.ser.write(CAN)
def send(self, filename, retry=20, timeout=60, quiet=False, callback=None):
def send(self, filename, slow_mode=False, retry=20, timeout=60, callback=None):
'''
Send a stream via the YMODEM protocol.
@ -169,16 +167,17 @@ class YMODEM(object):
Returns ``True`` upon successful transmission or ``False`` in case of
failure.
:param stream: The stream object to send data from.
:type stream: stream (file, etc.)
:param filename: The filename to send data from.
:type filename: string
:param slow_mode: If True, send only imediately after being asked, this can
help with repeatedly failing flashing.
:type slow_mode: bool
:param retry: The maximum number of times to try to resend a failed
packet before failing.
:type retry: int
:param timeout: The number of seconds to wait for a response before
timing out.
:type timeout: int
:param quiet: If True, write transfer information to stderr.
:type quiet: bool
:param callback: Reference to a callback function that has the
following signature. This is useful for
getting status updates while a ymodem
@ -193,25 +192,19 @@ class YMODEM(object):
self.log.debug('Begin start sequence, packet_size=%d', packet_size)
error_count = 0
crc_mode = 0
cancel = 0
while True:
char = self.ser.read(1)
if char:
if char == NAK:
self.log.debug('standard checksum requested (NAK).')
crc_mode = 0
break
elif char == CRC:
if char == CRC:
self.log.debug('16-bit CRC requested (CRC).')
crc_mode = 1
break
elif char == CAN or char == CAN2:
if not quiet:
print('received CAN', file=sys.stderr)
self.log.debug('received CAN')
if cancel:
self.log.info('Transmission canceled: received 2xCAN '
'at start-sequence')
print("Remote side requested cancel, suggest trying again later")
return False
else:
self.log.debug('cancellation at start sequence.')
@ -227,65 +220,104 @@ class YMODEM(object):
self.abort(timeout=timeout)
return False
# send data
error_count = 0
nak_count = 0
success_count = 0
total_packets = 0
total = 0
header_sent = False
sequence = 0
stream = None
while True:
# build packet
if not header_sent:
# send packet sequence 0 containing:
# Filename Length [Modification-Date [Mode [Serial-Number]]]
stream = open(filename, 'rb')
stat = os.stat(filename)
data = os.path.basename(filename).encode() + NUL + str(stat.st_size).encode()
self.log.debug('ymodem sending : "%s" len:%d', filename, stat.st_size)
if len(data) <= 128:
header_size = 128
else:
header_size = 1024
# send packet sequence 0 containing:
# Filename Length [Modification-Date [Mode [Serial-Number]]]
stream = open(filename, 'rb')
stat = os.stat(filename)
data = os.path.basename(filename).encode() + NUL + str(stat.st_size).encode()
self.log.debug('ymodem sending : "%s" len:%d', filename, stat.st_size)
header = self._make_send_header(header_size, sequence)
data = data.ljust(header_size, NUL)
checksum = self._make_send_checksum(crc_mode, data)
header_sent = True
total = (stat.st_size / packet_size) + 1
else:
# normal data packet
data = stream.read(packet_size)
if not data:
# end of stream
self.log.debug('send: at EOF')
break
total_packets += 1
if len(data) <= 128:
header_size = 128
else:
header_size = 1024
header = self._make_send_header(packet_size, sequence)
data = data.ljust(packet_size, self.pad)
checksum = self._make_send_checksum(crc_mode, data)
header = self._make_send_header(header_size, sequence)
data = data.ljust(header_size, NUL)
checksum = self._make_send_checksum(1, data)
total = (stat.st_size / packet_size) + 1
header_sent = False
# emit packet & get ACK
while not header_sent:
self.log.debug('header send: block %d, pks: %d', sequence, header_size)
self.ser.write(header + data + checksum)
while True:
char = self.ser.read(1)
if char == CRC or char == CRC2 or char == CRC3:
if self.ser.in_waiting == 0:
self.log.debug('re-send: block %d, pks: %d', sequence, packet_size)
self.log.debug('header re-send: block %d, pks: %d', sequence, packet_size)
self.ser.write(header + data + checksum)
else:
elif self.ser.in_waiting > 1:
rubbish = self.ser.read(self.ser.in_waiting-1)
self.log.info('got NAK rubbish %r for block %d', rubbish, sequence)
self.log.info('header got rubbish %r for block %d', rubbish, sequence)
continue
if char == ACK or char == ACK2 or char == NAK:
if char == ACK or char == ACK2:
success_count += 1
if callable(callback):
callback(total_packets, success_count, error_count, total)
error_count = 0
header_sent = True
break
self.log.info('send error: expected CRC|ACK; got %r for block %d', char, sequence)
error_count += 1
if callable(callback):
callback(total_packets, success_count, error_count, total)
if error_count > retry:
# excessive amounts of retransmissions requested,
# abort transfer
self.log.info('header send error: Unexpected received %d times, '
'aborting.', error_count)
self.abort(timeout=timeout)
return False
# keep track of sequence
sequence = (sequence + 1) % 0x100
#send data
while True:
# build normal data packet
data = stream.read(packet_size)
if not data:
# end of stream
self.log.debug('send: at EOF')
break
total_packets += 1
header = self._make_send_header(packet_size, sequence)
data = data.ljust(packet_size, self.pad)
checksum = self._make_send_checksum(1, data)
# emit packet & get ACK
if not slow_mode:
self.log.debug('send: block %d, pks: %d', sequence, packet_size)
self.ser.write(header + data + checksum)
while True:
char = self.ser.read(1)
if char == CRC or char == CRC2 or char == CRC3:
if slow_mode:
self.log.debug('send: block %d, pks: %d', sequence, packet_size)
self.ser.write(header + data + checksum)
elif self.ser.in_waiting == 0:
self.log.debug('re-send: block %d, pks: %d', sequence, packet_size)
self.ser.write(header + data + checksum)
elif self.ser.in_waiting > 1:
rubbish = self.ser.read(self.ser.in_waiting-1)
self.log.info('got rubbish %r for block %d', rubbish, sequence)
continue
if char == ACK or char == ACK2 or (char == NAK and not slow_mode):
success_count += 1
if callable(callback):
callback(total_packets, success_count, error_count, total)
error_count = 0
nak_count = 0
if char == NAK:
rubbish = self.ser.read(1024)
self.log.info('got NAK rubbish %r for block %d', rubbish, sequence)
@ -296,9 +328,20 @@ class YMODEM(object):
rubbish = self.ser.read(1024)
self.log.info('got NAK rubbish %r for block %d', rubbish, sequence)
break
if slow_mode and char == NAK:
nak_count += 1
error_count += 1
self.log.error('send error: expected CRC|ACK; got NAK(%d) for block %d', nak_count, sequence)
if nak_count > 4:
nak_count = 0
self.log.debug('try sending next block: %d', sequence)
break
if char == ABT:
self.log.debug('got abort')
return False
if char == CAN or char == CAN2:
self.log.debug('got cancel')
return False
self.log.info('send error: expected CRC|ACK; got %r for block %d',
char, sequence)