px_uploader.py: clean up various tidbits

Includes:
- Remove some of the outdated Python2 checks and compatibility.
- Try not catch all exceptions but only the expected ones. Otherwise,
  this makes it really hard to debug if anything unexpected actually
  goes wrong.
- Make use of fstrings.
- Make output slightly prettier.

Signed-off-by: Julian Oes <julian@oes.ch>
This commit is contained in:
Julian Oes
2024-05-22 18:18:55 +12:00
parent 7c4507b6d6
commit 8fe8f2fcb3
+40 -46
View File
@@ -50,9 +50,6 @@
# Currently only used for informational purposes. # Currently only used for informational purposes.
# #
# for python2.7 compatibility
from __future__ import print_function
import sys import sys
import argparse import argparse
import binascii import binascii
@@ -70,35 +67,32 @@ from sys import platform as _platform
try: try:
import serial import serial
except ImportError as e: except ImportError as e:
print("Failed to import serial: " + str(e)) print(f"Failed to import serial: {e}")
print("") print("")
print("You may need to install it using:") print("You may need to install it using:")
print(" pip3 install --user pyserial") print(" python -m pip install pyserial")
print("") print("")
sys.exit(1) sys.exit(1)
# Define time to use time.time() by default
def _time():
return time.time()
# Detect python version # Detect python version
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
runningPython3 = False raise RuntimeError("Python 2 is not supported. Please try again using Python 3.")
else: sys.exit(1)
runningPython3 = True
if sys.version_info[1] >=3:
# redefine to use monotonic time when available # Use monotonic time where available
def _time(): def _time():
try: try:
return time.monotonic() return time.monotonic()
except Exception: except Exception:
return time.time() return time.time()
class FirmwareNotSuitableException(Exception): class FirmwareNotSuitableException(Exception):
def __init__(self, message): def __init__(self, message):
super(FirmwareNotSuitableException, self).__init__(message) super(FirmwareNotSuitableException, self).__init__(message)
class firmware(object): class firmware(object):
'''Loads a firmware file''' '''Loads a firmware file'''
@@ -163,13 +157,13 @@ class firmware(object):
def crc(self, padlen): def crc(self, padlen):
state = self.__crc32(self.image, int(0)) state = self.__crc32(self.image, int(0))
for i in range(len(self.image), (padlen - 1), 4): for _ in range(len(self.image), (padlen - 1), 4):
state = self.__crc32(self.crcpad, state) state = self.__crc32(self.crcpad, state)
return state return state
class uploader(object): class uploader:
'''Uploads a firmware file to the PX FMU bootloader''' '''Uploads a firmware file to the PX4 bootloader'''
# protocol bytes # protocol bytes
INSYNC = b'\x12' INSYNC = b'\x12'
@@ -361,19 +355,22 @@ class uploader(object):
self.port.baudrate = self.baudrate_bootloader * 2.33 self.port.baudrate = self.baudrate_bootloader * 2.33
except NotImplementedError as e: except NotImplementedError as e:
# This error can occur because pySerial on Windows does not support odd baudrates # This error can occur because pySerial on Windows does not support odd baudrates
print(str(e) + " -> could not check for FTDI device, assuming USB connection") print(f"{e} -> could not check for FTDI device, assuming USB connection")
return return
self.__send(uploader.GET_SYNC + self.__send(uploader.GET_SYNC +
uploader.EOC) uploader.EOC)
try: try:
self.__getSync(False) self.__getSync(False)
except: except RuntimeError:
# if it fails we are on a real serial port - only leave this enabled on Windows # if it fails we are on a real serial port - only leave this enabled on Windows
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
self.ackWindowedMode = True self.ackWindowedMode = True
finally: finally:
self.port.baudrate = self.baudrate_bootloader try:
self.port.baudrate = self.baudrate_bootloader
except Exception:
pass
# send the GET_DEVICE command and wait for an info parameter # send the GET_DEVICE command and wait for an info parameter
def __getInfo(self, param): def __getInfo(self, param):
@@ -423,8 +420,7 @@ class uploader(object):
except RuntimeError: except RuntimeError:
# Bootloader doesn't support version call # Bootloader doesn't support version call
return "unknown" return "unknown"
pieces = value.split(b".") return value.decode()
return pieces
def __drawProgressBar(self, label, progress, maxVal): def __drawProgressBar(self, label, progress, maxVal):
if maxVal < progress: if maxVal < progress:
@@ -437,7 +433,7 @@ class uploader(object):
# send the CHIP_ERASE command and wait for the bootloader to become ready # send the CHIP_ERASE command and wait for the bootloader to become ready
def __erase(self, label): def __erase(self, label):
print("Windowed mode: %s" % self.ackWindowedMode) print(f"Windowed mode: {self.ackWindowedMode}")
print("\n", end='') print("\n", end='')
if self.force_erase: if self.force_erase:
@@ -672,14 +668,14 @@ class uploader(object):
self.otp_coa = self.otp[32:160] self.otp_coa = self.otp[32:160]
# show user: # show user:
try: try:
print("sn: ", end='') print("Sn: ", end='')
for byte in range(0, 12, 4): for byte in range(0, 12, 4):
x = self.__getSN(byte) x = self.__getSN(byte)
x = x[::-1] # reverse the bytes x = x[::-1] # reverse the bytes
self.sn = self.sn + x self.sn = self.sn + x
print(binascii.hexlify(x).decode('Latin-1'), end='') # show user print(binascii.hexlify(x).decode('Latin-1'), end='') # show user
print('') print('')
print("chip: %08x" % self.__getCHIP()) print("Chip: %08x" % self.__getCHIP())
otp_id = self.otp_id.decode('Latin-1') otp_id = self.otp_id.decode('Latin-1')
if ("PX4" in otp_id): if ("PX4" in otp_id):
@@ -689,17 +685,19 @@ class uploader(object):
print("OTP pid: " + binascii.hexlify(self.otp_pid).decode('Latin-1')) print("OTP pid: " + binascii.hexlify(self.otp_pid).decode('Latin-1'))
print("OTP coa: " + binascii.b2a_base64(self.otp_coa).decode('Latin-1')) print("OTP coa: " + binascii.b2a_base64(self.otp_coa).decode('Latin-1'))
except Exception: except Exception as e:
# ignore bad character encodings # ignore bad character encodings
print(f"Exception ignored: {e}")
pass pass
# Silicon errata check was added in v5 # Silicon errata check was added in v5
if (self.bl_rev >= 5): if (self.bl_rev >= 5):
des = self.__getCHIPDes() des = self.__getCHIPDes()
if (len(des) == 2): if (len(des) == 2):
print("family: %s" % des[0]) family, revision = des
print("revision: %s" % des[1]) print(f"Family: {family.decode()}")
print("flash: %d bytes" % self.fw_maxsize) print(f"Revision: {revision.decode()}")
print(f"Flash: {self.fw_maxsize} bytes")
# Prevent uploads where the maximum image size of the board config is smaller than the flash # Prevent uploads where the maximum image size of the board config is smaller than the flash
# of the board. This is a hint the user chose the wrong config and will lack features # of the board. This is a hint the user chose the wrong config and will lack features
@@ -710,8 +708,7 @@ class uploader(object):
# https://github.com/PX4/Firmware/blob/master/src/drivers/boards/common/stm32/board_mcu_version.c#L125-L144 # https://github.com/PX4/Firmware/blob/master/src/drivers/boards/common/stm32/board_mcu_version.c#L125-L144
if self.fw_maxsize > fw.property('image_maxsize') and not force: if self.fw_maxsize > fw.property('image_maxsize') and not force:
raise RuntimeError("Board can accept larger flash images (%u bytes) than board config (%u bytes). Please use the correct board configuration to avoid lacking critical functionality." raise RuntimeError(f"Board can accept larger flash images ({self.fw_maxsize} bytes) than board config ({fw.property('image_maxsize')} bytes). Please use the correct board configuration to avoid lacking critical functionality.")
% (self.fw_maxsize, fw.property('image_maxsize')))
else: else:
# If we're still on bootloader v4 on a Pixhawk, we don't know if we # If we're still on bootloader v4 on a Pixhawk, we don't know if we
# have the silicon errata and therefore need to flash px4_fmu-v2 # have the silicon errata and therefore need to flash px4_fmu-v2
@@ -812,10 +809,6 @@ class uploader(object):
def main(): def main():
# Python2 is EOL
if not runningPython3:
raise RuntimeError("Python 2 is not supported. Please try again using Python 3.")
# Parse commandline arguments # Parse commandline arguments
parser = argparse.ArgumentParser(description="Firmware uploader for the PX autopilot system.") parser = argparse.ArgumentParser(description="Firmware uploader for the PX autopilot system.")
parser.add_argument('--port', action="store", required=True, help="Comma-separated list of serial port(s) to which the FMU may be attached") parser.add_argument('--port', action="store", required=True, help="Comma-separated list of serial port(s) to which the FMU may be attached")
@@ -900,9 +893,10 @@ def main():
# Windows, don't open POSIX ports # Windows, don't open POSIX ports
if "/" not in port: if "/" not in port:
up = uploader(port, args.baud_bootloader, baud_flightstack) up = uploader(port, args.baud_bootloader, baud_flightstack)
except Exception: except Exception as e:
# open failed, rate-limit our attempts # open failed, rate-limit our attempts
time.sleep(0.05) time.sleep(0.05)
print(f"Exception ignored: {e}")
# and loop to the next port # and loop to the next port
continue continue
@@ -917,10 +911,10 @@ def main():
up.identify() up.identify()
found_bootloader = True found_bootloader = True
print() print()
print("Found board id: %s,%s bootloader version: %s on %s" % (up.board_type, up.board_rev, up.bl_rev, port)) print(f"Found board id: {up.board_type},{up.board_rev} bootloader protocol revision {up.bl_rev} on {port}")
break break
except Exception: except RuntimeError or serial.SerialException:
if not up.send_reboot(args.use_protocol_splitter_format): if not up.send_reboot(args.use_protocol_splitter_format):
break break
@@ -945,9 +939,9 @@ def main():
# if we made this far without raising exceptions, the upload was successful # if we made this far without raising exceptions, the upload was successful
successful = True successful = True
except RuntimeError as ex: except RuntimeError as e:
# print the error # print the error
print("\nERROR: %s" % ex.args) print(f"\n\nError: {e}")
except FirmwareNotSuitableException: except FirmwareNotSuitableException:
unsuitable_board = True unsuitable_board = True
@@ -986,4 +980,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4