refactor(cli_mode): Improve CLI mode workflow code

This commit is contained in:
Radim Karniš
2025-02-03 16:06:42 +01:00
parent 6e959ef595
commit 0671d350e4

View File

@@ -768,185 +768,213 @@ def main(argv=None, esp=None):
operation_func = globals()[args.operation] operation_func = globals()[args.operation]
operation_args = inspect.getfullargspec(operation_func).args operation_args = inspect.getfullargspec(operation_func).args
if ( # Commands that don't require an ESP object (image generation, etc.)
operation_args[0] == "esp" if operation_args[0] != "esp":
): # operation function takes an ESPLoader connection object operation_func(args)
if args.before != "no_reset_no_sync": return
initial_baud = min(
ESPLoader.ESP_ROM_BAUD, args.baud
) # don't sync faster than the default baud rate
else:
initial_baud = args.baud
if args.port is None: # Commands that require an ESP object (flash read/write, etc.)
ser_list = get_port_list( # 1) Get the ESP object
args.filterVids, args.filterPids, args.filterNames, args.filterSerials #######################
)
log.print(f"Found {len(ser_list)} serial ports") if args.before != "no_reset_no_sync":
else: initial_baud = min(
ser_list = [args.port] ESPLoader.ESP_ROM_BAUD, args.baud
open_port_attempts = os.environ.get( ) # don't sync faster than the default baud rate
"ESPTOOL_OPEN_PORT_ATTEMPTS", DEFAULT_OPEN_PORT_ATTEMPTS else:
initial_baud = args.baud
if args.port is None:
ser_list = get_port_list(
args.filterVids, args.filterPids, args.filterNames, args.filterSerials
) )
try: log.print(f"Found {len(ser_list)} serial ports")
open_port_attempts = int(open_port_attempts) else:
except ValueError: ser_list = [args.port]
raise SystemExit("Invalid value for ESPTOOL_OPEN_PORT_ATTEMPTS") open_port_attempts = os.environ.get(
if open_port_attempts != 1: "ESPTOOL_OPEN_PORT_ATTEMPTS", DEFAULT_OPEN_PORT_ATTEMPTS
if args.port is None or args.chip == "auto": )
log.warning( try:
"The ESPTOOL_OPEN_PORT_ATTEMPTS (open_port_attempts) option " open_port_attempts = int(open_port_attempts)
"can only be used with --port and --chip arguments." except ValueError:
) raise SystemExit("Invalid value for ESPTOOL_OPEN_PORT_ATTEMPTS")
else: if open_port_attempts != 1:
esp = esp or connect_loop( if args.port is None or args.chip == "auto":
args.port, log.warning(
initial_baud, "The ESPTOOL_OPEN_PORT_ATTEMPTS (open_port_attempts) option "
args.chip, "can only be used with --port and --chip arguments."
open_port_attempts, )
args.trace, else:
args.before, esp = esp or connect_loop(
) args.port,
esp = esp or get_default_connected_device( initial_baud,
ser_list, args.chip,
port=args.port, open_port_attempts,
connect_attempts=args.connect_attempts, args.trace,
initial_baud=initial_baud, args.before,
chip=args.chip, )
trace=args.trace, esp = esp or get_default_connected_device(
before=args.before, ser_list,
port=args.port,
connect_attempts=args.connect_attempts,
initial_baud=initial_baud,
chip=args.chip,
trace=args.trace,
before=args.before,
)
if esp is None:
raise FatalError(
"Could not connect to an Espressif device "
f"on any of the {len(ser_list)} available serial ports."
) )
if esp is None: # 2) Print the chip info
raise FatalError( ########################
"Could not connect to an Espressif device "
f"on any of the {len(ser_list)} available serial ports."
)
if esp.secure_download_mode:
log.print(f"Chip is {esp.CHIP_NAME} in Secure Download Mode")
else:
log.print(f"Chip is {esp.get_chip_description()}")
log.print(f"Features: {', '.join(esp.get_chip_features())}")
log.print(f"Crystal is {esp.get_crystal_freq()}MHz")
usb_mode = esp.get_usb_mode()
if usb_mode is not None:
log.print(f"USB mode: {usb_mode}")
read_mac(esp, args)
# 3) Upload the stub flasher
############################
if not args.no_stub:
if esp.secure_download_mode: if esp.secure_download_mode:
log.print(f"Chip is {esp.CHIP_NAME} in Secure Download Mode") log.warning(
else: "Stub loader is not supported in Secure Download Mode, "
log.print(f"Chip is {esp.get_chip_description()}") "setting --no-stub"
log.print(f"Features: {', '.join(esp.get_chip_features())}") )
log.print(f"Crystal is {esp.get_crystal_freq()}MHz") args.no_stub = True
usb_mode = esp.get_usb_mode() elif not esp.IS_STUB and esp.stub_is_disabled:
if usb_mode is not None: log.warning(
log.print(f"USB mode: {usb_mode}") "Stub loader has been disabled for compatibility, setting --no-stub"
read_mac(esp, args) )
args.no_stub = True
if not args.no_stub: elif esp.CHIP_NAME in [
if esp.secure_download_mode:
log.warning(
"Stub loader is not supported in Secure Download Mode, "
"setting --no-stub"
)
args.no_stub = True
elif not esp.IS_STUB and esp.stub_is_disabled:
log.warning(
"Stub loader has been disabled for compatibility, setting --no-stub"
)
args.no_stub = True
elif esp.CHIP_NAME in [
"ESP32-H21", "ESP32-H21",
"ESP32-H4", "ESP32-H4",
]: # TODO: [ESP32H21] IDF-11509 [ESP32H4] IDF-12271 ]: # TODO: [ESP32H21] IDF-11509 [ESP32H4] IDF-12271
log.warning( log.warning(
f"Stub loader is not yet supported on {esp.CHIP_NAME}, " f"Stub loader is not yet supported on {esp.CHIP_NAME}, "
"setting --no-stub" "setting --no-stub"
) )
args.no_stub = True args.no_stub = True
else: else:
try:
esp = esp.run_stub()
except Exception:
# The CH9102 bridge (PID: 0x55D4) can have issues on MacOS
if sys.platform == "darwin" and esp._get_pid() == 0x55D4:
log.print()
log.note(
"If issues persist, "
"try installing the WCH USB-to-Serial MacOS driver."
)
raise
if args.override_vddsdio:
esp.override_vddsdio(args.override_vddsdio)
if args.baud > initial_baud:
try: try:
esp.change_baud(args.baud) esp = esp.run_stub()
except NotImplementedInROMError: except Exception:
log.warning( # The CH9102 bridge (PID: 0x55D4) can have issues on MacOS
f"ROM doesn't support changing baud rate. " if sys.platform == "darwin" and esp._get_pid() == 0x55D4:
f"Keeping initial baud rate {initial_baud}" log.print()
) log.note(
"If issues persist, "
"try installing the WCH USB-to-Serial MacOS driver."
)
raise
flash_attach(esp, args.spi_connection if hasattr(args, "spi_connection") else None) # 4) Configure the baud rate and voltage regulator
if hasattr(args, "flash_size"): ##################################################
args.flash_size = flash_set_parameters(esp, args.flash_size)
# Detect flash size if "ALL" is specified if args.override_vddsdio:
if getattr(args, "size", "") == "all": esp.override_vddsdio(args.override_vddsdio)
if esp.secure_download_mode:
raise FatalError(
"Detecting flash size is not supported in secure download mode. "
"Set an exact size value."
)
size_str = detect_flash_size(esp)
if size_str is None:
raise FatalError(
"Detecting flash size failed. Set an exact size value."
)
log.print(f"Detected flash size: {size_str}")
args.size = flash_size_bytes(size_str)
# Check if we are writing past 16MB boundary
if esp.IS_STUB and args.operation != "dump_mem" and hasattr(args, "address") and hasattr(args, "size"):
if esp.CHIP_NAME != "ESP32-S3" and args.address + args.size > 0x1000000:
log.note(
"Flasher stub doesn't fully support flash size larger "
"than 16MB, in case of failure use --no-stub."
)
if args.baud > initial_baud:
try: try:
operation_func(esp, args) esp.change_baud(args.baud)
finally: except NotImplementedInROMError:
try: # Clean up AddrFilenamePairAction files log.warning(
for address, argfile in args.addr_filename: f"ROM doesn't support changing baud rate. "
argfile.close() f"Keeping initial baud rate {initial_baud}"
except AttributeError: )
pass
# Handle post-operation behaviour (reset or other) # 5) Attach the flash chip and set its parameters
if operation_func == load_ram: #################################################
# the ESP is now running the loaded image, so let it run
log.print("Exiting immediately.") flash_attach(esp, args.spi_connection if hasattr(args, "spi_connection") else None)
elif args.after == "hard_reset": if hasattr(args, "flash_size"):
args.flash_size = flash_set_parameters(esp, args.flash_size)
# 6) Perform argument processing and validation
###############################################
if getattr(args, "size", "") == "all":
if esp.secure_download_mode:
raise FatalError(
"Detecting flash size is not supported in secure download mode. "
"Set an exact size value."
)
size_str = detect_flash_size(esp)
if size_str is None:
raise FatalError("Detecting flash size failed. Set an exact size value.")
log.print(f"Detected flash size: {size_str}")
args.size = flash_size_bytes(size_str)
if ( # Check if we are writing/reading past 16MB boundary
esp.IS_STUB
and args.operation != "dump_mem"
and hasattr(args, "address")
and hasattr(args, "size")
):
if esp.CHIP_NAME != "ESP32-S3" and args.address + args.size > 0x1000000:
log.note(
"Flasher stub doesn't fully support flash size larger "
"than 16MB, in case of failure use --no-stub."
)
# 7) Run the selected operation
###############################
try:
operation_func(esp, args)
finally:
try: # Clean up AddrFilenamePairAction files
for address, argfile in args.addr_filename:
argfile.close()
except AttributeError:
pass
# 8) Reset the chip
###################
# Handle post-operation behaviour (reset or other)
if operation_func == load_ram:
# the ESP is now running the loaded image, so let it run
log.print("Exiting immediately.")
elif args.after == "hard_reset":
esp.hard_reset()
elif args.after == "soft_reset":
log.print("Soft resetting...")
# flash_finish will trigger a soft reset
esp.soft_reset(False)
elif args.after == "no_reset_stub":
log.print("Staying in flasher stub.")
elif args.after == "watchdog_reset":
if esp.secure_download_mode:
log.warning(
"Watchdog hard reset is not supported in Secure Download Mode, "
"attempting classic hard reset instead."
)
esp.hard_reset() esp.hard_reset()
elif args.after == "soft_reset": else:
log.print("Soft resetting...") esp.watchdog_reset()
# flash_finish will trigger a soft reset else: # args.after == 'no_reset'
esp.soft_reset(False) log.print("Staying in bootloader.")
elif args.after == "no_reset_stub": if esp.IS_STUB:
log.print("Staying in flasher stub.") esp.soft_reset(True) # exit stub back to ROM loader
elif args.after == "watchdog_reset":
if esp.secure_download_mode:
log.warning(
"Watchdog hard reset is not supported in Secure Download Mode, "
"attempting classic hard reset instead."
)
esp.hard_reset()
else:
esp.watchdog_reset()
else: # args.after == 'no_reset'
log.print("Staying in bootloader.")
if esp.IS_STUB:
esp.soft_reset(True) # exit stub back to ROM loader
if not external_esp: # 9) Finish and close the port
esp._port.close() ##############################
else: if not external_esp:
operation_func(args) esp._port.close()
def arg_auto_int(x): def arg_auto_int(x):