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

View file

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