From 52700f95a28e6ba4bb7fb3eb3412cb84aec1275a Mon Sep 17 00:00:00 2001 From: Andrew Oaks - StarIC Date: Mon, 22 Dec 2025 16:16:43 -0500 Subject: [PATCH 1/2] Improve BOND Teensy update and fresh programming - Store pogo_hdr_definition._json location with driver so it can be reloaded on re-initialization of driver - Include logging of stderr for subprocess.run commands - Add teardown tests to end of sequences - Debug & Fix fresh program scripts --- public/prism/drivers/A4401_BOND/A4401_BOND.py | 59 +++++++++---------- .../drivers/A4401_BOND/A4401_BOND_cli.py | 12 ++-- .../drivers/A4401_BOND/hwdrv_A4401_BOND.py | 8 ++- .../A4401_BOND/hwdrv_A4401_BOND_prog.py | 2 +- .../scripts/example/BOND_v0/bond_P00xx.py | 49 +++++++-------- .../example/BOND_v0/bond_progfresh_0.scr | 6 +- .../scripts/example/BOND_v0/bond_update_0.scr | 1 + 7 files changed, 65 insertions(+), 72 deletions(-) diff --git a/public/prism/drivers/A4401_BOND/A4401_BOND.py b/public/prism/drivers/A4401_BOND/A4401_BOND.py index e0e34c9..49677ec 100644 --- a/public/prism/drivers/A4401_BOND/A4401_BOND.py +++ b/public/prism/drivers/A4401_BOND/A4401_BOND.py @@ -62,14 +62,15 @@ class A4401_BOND: # if that FW is not running, there is probably a problem! See method init(). _version_file = os.path.join(os.path.dirname(__file__), "server/teensy4_server/version.h") - def __init__(self, port, loggerIn=None): - self.lock = threading.Lock() + def __init__(self, port, loggerIn=None, header_def_filename=None): if loggerIn: self.logger = loggerIn else: self.logger = StubLogger() + self._header_def_filename = header_def_filename + self._lock = threading.Lock() self.port = port self.rpc = None @@ -82,14 +83,14 @@ def __init__(self, port, loggerIn=None): def set_port(self, port): self.port = port - def init(self, header_def_filename=None): + def init(self, skip_max11311=False): """ Init Teensy SimpleRPC connection - :param skip_init: True/False, skips MAX11311 setup, assume thats already done + :param skip_max11311: True/False, skips MAX11311 setup. Allow access other functions :return: whether Teensy SimpleRPC connection was created """ - self.logger.info(f"installing BOND on port {self.port} using {header_def_filename}") - if header_def_filename is None: + self.logger.info(f"installing BOND on port {self.port} using {self._header_def_filename}") + if not skip_max11311 and self._header_def_filename is None: self.logger.error("MAX11311 port definition file must be specified") return False @@ -107,9 +108,9 @@ def init(self, header_def_filename=None): return False if self.my_version != version_response["result"]["version"]: - self.logger.error("version does not match, Python: {} Arduino: {}".format(self.my_version, - version_response["result"][ - "version"])) + self.logger.error("version does not match, " + f"Python: {self.my_version} " + f"Arduino: {version_response["result"]["version"]}") return False status_response = self.status() @@ -123,30 +124,28 @@ def init(self, header_def_filename=None): # check if jig close has valid GPIOs self._jig_close_check() - if header_def_filename is None: - self.logger.error(f"Header pin definition filename not supplied") - return False - - if not os.path.exists(header_def_filename): - self.logger.error(f"Header pin definition filename {header_def_filename} does not exist") - return False + if not skip_max11311: + if not os.path.exists(self._header_def_filename): + self.logger.error(f"Header pin definition filename {self._header_def_filename} " + "does not exist") + return False - # init MAX11311 pins per the JSON defintion - # also calibrates the battery emulator if needed - success = self._init_maxs(header_def_filename) - if not success: - self.logger.error(f"Failed to init MAX11311 pins") - return False + # init MAX11311 pins per the JSON defintion + # also calibrates the battery emulator if needed + success = self._init_maxs(self._header_def_filename) + if not success: + self.logger.error("Failed to init MAX11311 pins") + return False - status_response = self.iox_vbat_con(False) - if not status_response["success"]: - self.logger.error(f"iox_vbat_con {status_response}") - return False + status_response = self.iox_vbat_con(False) + if not status_response["success"]: + self.logger.error(f"iox_vbat_con {status_response}") + return False - status_response = self.iox_selftest(False) - if not status_response["success"]: - self.logger.error(f"iox_vbat_con {status_response}") - return False + status_response = self.iox_selftest(False) + if not status_response["success"]: + self.logger.error(f"iox_vbat_con {status_response}") + return False # check bist voltages for _v in self.BIST_VOLTAGES: diff --git a/public/prism/drivers/A4401_BOND/A4401_BOND_cli.py b/public/prism/drivers/A4401_BOND/A4401_BOND_cli.py index 753ce86..9517aec 100644 --- a/public/prism/drivers/A4401_BOND/A4401_BOND_cli.py +++ b/public/prism/drivers/A4401_BOND/A4401_BOND_cli.py @@ -28,18 +28,18 @@ def parse_args(): python A4401_BOND_cli.py --port /dev/ttyACM0 led --on Port: Teensy4 when plugged into USB on Linux will show up as a ttyACM# device in /dev. - Use 'ls -al /dev/ttyACM*' to find the port. - + Use 'ls -al /dev/ttyACM*' to find the port. + Getting Help for a command: $ python3 A4401_BOND_cli.py --port /dev/ttyACM0 write_gpio --help usage: A4401_BOND_cli.py write_gpio [-h] --pin-number _PIN_NUMBER --state {True,False} - + options: -h, --help show this help message and exit --pin-number _PIN_NUMBER GPIO number (0-41) --state {True,False} True|False - + Examples: (venv) martin@martin-ThinkPad-L13:~/git/scripts/public/prism/drivers/A4401_BOND$ python A4401_BOND_cli.py -p /dev/ttyACM0 version (venv) martin@martin-ThinkPad-L13:~/git/scripts/public/prism/drivers/A4401_BOND$ python A4401_BOND_cli.py -p /dev/ttyACM0 -n iox_led_green --enable @@ -507,9 +507,9 @@ def sequence(args): else: logging.basicConfig(level=logging.DEBUG, format='%(filename)20s %(levelname)6s %(lineno)4s %(message)s') - teensy = A4401_BOND(args.port, loggerIn=logging) + teensy = A4401_BOND(args.port, loggerIn=logging, header_def_filename="pogo_hdr_definition._json") - success = teensy.init(header_def_filename="pogo_hdr_definition._json") + success = teensy.init() if not success: logging.error("Failed to create teensy instance") exit(1) diff --git a/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND.py b/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND.py index 81776fb..671dc51 100644 --- a/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND.py +++ b/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND.py @@ -36,7 +36,7 @@ def __init__(self): self._num_chan = 0 self.teensys = [] # holds a list of all objects found - def discover_channels(self, scriptArgs): + def discover_channels(self, scriptArgs=None): """ determine the number of channels, and populate hw drivers into shared state [ {"id": i, # ~slot number of the channel (see Note 1) @@ -98,8 +98,10 @@ def discover_channels(self, scriptArgs): #https: // stackoverflow.com / questions / 21050671 / how - to - check - if -device - is -connected - pyserial / 49450813 # test if this COM port is really a Teensy # create an instance of Teensy() - _teensy['hwdrv'] = A4401_BOND(port, loggerIn=logging.getLogger("teensy.try")) - success = _teensy['hwdrv'].init(scriptArgs) + _teensy['hwdrv'] = A4401_BOND(port, + loggerIn=logging.getLogger("teensy.try"), + header_def_filename=scriptArgs) + success = _teensy['hwdrv'].init() if not success: self.logger.error("failed on {}...".format(port)) continue diff --git a/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND_prog.py b/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND_prog.py index 685caf0..950e300 100644 --- a/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND_prog.py +++ b/public/prism/drivers/A4401_BOND/hwdrv_A4401_BOND_prog.py @@ -46,7 +46,7 @@ def __init__(self): self._num_chan = 0 self.teensys = [] - def discover_channels(self): + def discover_channels(self, scriptArgs=None): """ determine the number of channels, and populate hw drivers into shared state [ {"id": i, # ~slot number of the channel (see Note 1) diff --git a/public/prism/scripts/example/BOND_v0/bond_P00xx.py b/public/prism/scripts/example/BOND_v0/bond_P00xx.py index 6916d6d..21daf9f 100644 --- a/public/prism/scripts/example/BOND_v0/bond_P00xx.py +++ b/public/prism/scripts/example/BOND_v0/bond_P00xx.py @@ -141,7 +141,10 @@ def P200_Program(self): '-v', '-s', file_path], - stdout=subprocess.PIPE).stdout.decode('utf-8') + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True) + self.logger.info(result) self.shared_lock(DRIVER_TYPE_PROG).release() @@ -154,13 +157,13 @@ def P200_Program(self): # Booting # check for some key words to confirm success - if not result.count('Programming'): - self.log_bullet(f"Unexpected Programming") + if not result.stdout.count('Programming'): + self.log_bullet(f"'Programming' did not occur") self.item_end(ResultAPI.RECORD_RESULT_INTERNAL_ERROR) return - if not result.count('Booting'): - self.log_bullet(f"Unexpected Booting") + if not result.stdout.count('Booting'): + self.log_bullet(f"'Booting' did not occur") self.item_end(ResultAPI.RECORD_RESULT_INTERNAL_ERROR) return @@ -190,19 +193,20 @@ def P300_Reconnect(self): self.logger.info("Trying teensy at {}...".format(port)) # create an instance of Teensy() + # Bare minimum init -- does not require 'pogo_hdr_definition._json' _teensy = A4401_BOND(port, loggerIn=logging.getLogger("teensy.try")) - success = _teensy.init() + success = _teensy.init(skip_max11311=True) if not success: - self.log_bullet(f"Failed init") + self.log_bullet("Failed init") self.logger.error("failed on {}...".format(port)) else: - self.log_bullet(f"Found teensy") + self.log_bullet("Found teensy") found_teensy = True break if not found_teensy: - self.log_bullet(f"Teensy not found") + self.log_bullet("Teensy not found") self.item_end(ResultAPI.RECORD_RESULT_INTERNAL_ERROR) return @@ -310,7 +314,9 @@ def P600_Update(self): '-w', '-v', file_path], - stdout=subprocess.PIPE).stdout.decode('utf-8') + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True) self.logger.info(result) # expected output looks like, @@ -324,7 +330,7 @@ def P600_Update(self): # Booting # check for some keywords to confirm success - if result.count('Programming') and result.count('Booting'): + if result.stdout.count('Programming') and result.stdout.count('Booting'): success = True break @@ -412,24 +418,9 @@ def P700_Verify(self): self.logger.info("Trying teensy at {}...".format(port)) - # (re)create an instance of Teensy() - self.teensy = A4401_BOND(port, loggerIn=logging.getLogger("teensy.try")) - - # get the header_def_filename from script drivers section - header_def_filename = None - for i in ctx.config.drivers: - if "hwdrv_A4401_BOND" in i[0]: - header_def_filename = i[1] - break - if header_def_filename is None: - self.logger.error(f"header_def_filename: {header_def_filename}") - self.log_bullet(f"Failed header_def_filename") - self.shared_lock(DRIVER_TYPE).release() - self.item_end(ResultAPI.RECORD_RESULT_INTERNAL_ERROR) - return - self.logger.info(f"header_def_filename: {header_def_filename}") - - success = self.teensy.init(header_def_filename) + # re-connect to teensy at new port + self.teensy.set_port(port) + success = self.teensy.init() if not success: self.log_bullet(f"Failed init") self.logger.error("failed on {}...".format(self._teensy_port)) diff --git a/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr b/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr index 4f74696..9d4aebf 100644 --- a/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr +++ b/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr @@ -16,8 +16,7 @@ }, "config": { "fail_fast": true, - "drivers": [["public.prism.drivers.A4401_BOND.hwdrv_A4401_BOND", - "public/prism/scripts/example/BOND_v0/assets/pogo_hdr_definition._json"]] + "drivers": ["public.prism.drivers.A4401_BOND.hwdrv_A4401_BOND_prog"] }, "tests": [ { @@ -28,7 +27,8 @@ {"id": "P000_SETUP", "enable": true }, {"id": "P100_Check", "enable": true }, {"id": "P200_Program", "enable": true, "file": "teensy4_server.ino.hex" }, - {"id": "P300_Verify", "enable": true, "delay": 10 }, + {"id": "P300_Reconnect", "enable": true, "timeout": 40, "delay": 30 }, + {"id": "P900_TEARDOWN", "enable": true} ] } ] diff --git a/public/prism/scripts/example/BOND_v0/bond_update_0.scr b/public/prism/scripts/example/BOND_v0/bond_update_0.scr index bec91fe..73426ec 100644 --- a/public/prism/scripts/example/BOND_v0/bond_update_0.scr +++ b/public/prism/scripts/example/BOND_v0/bond_update_0.scr @@ -31,6 +31,7 @@ {"id": "P500_SETUP", "enable": true, "timeout": 30 }, {"id": "P600_Update", "enable": true, "file": "teensy4_server.ino.hex" }, {"id": "P700_Verify", "enable": true, "delay": 24, "timeout": 30 }, + {"id": "P900_TEARDOWN", "enable": true} ] } ] From 9bb7db14da8b36f0f2344e4a98154defadea427f Mon Sep 17 00:00:00 2001 From: Andrew Oaks - StarIC Date: Mon, 22 Dec 2025 16:29:03 -0500 Subject: [PATCH 2/2] Update bond_progfresh_0 reconnect delay/timeout - Match bond_update_0 --- public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr b/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr index 9d4aebf..671d8e4 100644 --- a/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr +++ b/public/prism/scripts/example/BOND_v0/bond_progfresh_0.scr @@ -27,7 +27,7 @@ {"id": "P000_SETUP", "enable": true }, {"id": "P100_Check", "enable": true }, {"id": "P200_Program", "enable": true, "file": "teensy4_server.ino.hex" }, - {"id": "P300_Reconnect", "enable": true, "timeout": 40, "delay": 30 }, + {"id": "P300_Reconnect", "enable": true, "timeout": 30, "delay": 24 }, {"id": "P900_TEARDOWN", "enable": true} ] }