Myxa with Ardupilot

I can’t remember the date exactly, but I’d hazard a guess around 2019.

This is my program, am I doing something wrong? update_auth.py (14.6 KB). When I run it, the program does this:

2024-12-02 14:04:48 INFO  __main__: Loaded bootloader image of 42112 bytes from 'https://files.zubax.com/products/com.zubax.telega/bootloader/com.zubax.telega.bootloader.bin'

Until I Ctrl+C it:

Traceback (most recent call last):
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1823, in _run_once
    event_list = self._selector.select(timeout)
  File "/usr/lib/python3.8/selectors.py", line 468, in select
    fd_event_list = self._selector.poll(timeout, max_ev)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "update_auth_bit.py", line 326, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.8/asyncio/runners.py", line 47, in run
    _cancel_all_tasks(loop)
  File "/usr/lib/python3.8/asyncio/runners.py", line 60, in _cancel_all_tasks
    task.cancel()
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  [Previous line repeated 495 more times]
RecursionError: maximum recursion depth exceeded

Just using the low-level IO service will not work because you need to follow a special procedure for ROM modification. This is implemented in the function called update_bootloader; you just need to feed it the signature instead of the bootloader image, along with the new write address. Perhaps you could just ask ChatGPT to edit the code for you.

Dealing with a lot of errors from both my code and ChatGPT’s code so far. Would it be possible if you could have a glance over it.

_logger.info("Rewriting the auth on node %d, this will take a while...", node_id)
    agent = STM32F4(rio)
    await agent.write_rom(0x0000BF00, 6e8cc6a6f2baa4b5907356c954c6457b7a0649a25ae6776dd9f8bafb75a72b02a3bc7f5c761fbb6782bba02352ddf95bed96668466223ad87821d222132d94f709799e932062fae39467c651cb40a0788c06b3fcecda0860fc1a3b65ffc9c52d4359c20083c45168d2d8804602a57898a0cb9472371af20e4735784409883cc4e8d7f978892ee2eae88731f73785e9fe86761e89ed8a8e414c201fe54ffafd5624e1d063cb4f2c224b7c5103ff53db1a3049bd14f5a8495796ee38b3b8991fbac1dced6c3ca9dbe3222f87a2f5e64b08c6c895aba2f015ce9ed59f86801d)
    _logger.info("Auth bit written")

Python doesn’t seem to like the length of the signature.
I’m not very good at embedded programming, so I apologise in advance if my mistake is rudimentary.

    _logger.info("Rewriting the auth on node %d, this will take a while...", node_id)
    agent = STM32F4(rio)
    s = '6e8cc6a6f2baa4b5907356c954c6457b7a0649a25ae6776dd9f8bafb75a72b02a3bc7f5c761fbb6782bba02352ddf95bed96668466223ad87821d222132d94f709799e932062fae39467c651cb40a0788c06b3fcecda0860fc1a3b65ffc9c52d4359c20083c45168d2d8804602a57898a0cb9472371af20e4735784409883cc4e8d7f978892ee2eae88731f73785e9fe86761e89ed8a8e414c201fe54ffafd5624e1d063cb4f2c224b7c5103ff53db1a3049bd14f5a8495796ee38b3b8991fbac1dced6c3ca9dbe3222f87a2f5e64b08c6c895aba2f015ce9ed59f86801d'
    await agent.write_rom(0x0000BF00, bytes.fromhex(s))
    _logger.info("Auth bit written")

Annoyingly, the program hangs here for (still here for the last 10 min) showing this:

2024-12-03 04:45:02 INFO  __main__: Loaded bootloader image of 42112 bytes from 'https://files.zubax.com/products/com.zubax.telega/bootloader/com.zubax.telega.bootloader.bin'

2024-12-03 04:45:02 INFO  __main__: Matching node found: 125 Entry(heartbeat=uavcan.node.Heartbeat.1.0(uptime=66, health=uavcan.node.Health.1.0(value=0), mode=uavcan.node.Mode.1.0(value=0), vendor_specific_status_code=0), info=uavcan.node.GetInfo.Response.1.0(protocol_version=uavcan.node.Version.1.0(major=1, minor=0), hardware_version=uavcan.node.Version.1.0(major=1, minor=3), software_version=uavcan.node.Version.1.0(major=1, minor=0), software_vcs_revision_id=2187630895419027378, unique_id=[48, 0,67, 0,10,81,54,49,48,54,56,56, 0, 0, 0, 0], name='com.zubax.telega', software_image_crc=[7652891267415001969], certificate_of_authenticity=''))

2024-12-03 04:45:02 INFO  __main__: Node 125 is configured and ready for the bootloader check/update; the low-level IO service-ID is 81

2024-12-03 04:45:02 INFO  __main__: Rewriting the auth on node 125, this will take a while...

Taking much longer than a “while”, no?

Consider increasing the log level by exporting the environment variable VERBOSE=1. Add extra logging statements if needed. That will get you an idea of what is happening.

I managed to get more info leading to this error (I think?):

^C2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module cStringIO as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module six.moves as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module six.moves.http_client as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module brotli as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module winreg as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module six.moves.urllib as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module six.moves.urllib.parse as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module brotli as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module socks as DSDL

2024-12-03 05:42:32 DEBUG pycyphal.dsdl._import_hook: Attempting to load module cPickle as DSDL

Traceback (most recent call last):
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1859, in _run_once
    handle._run()
  File "/usr/lib/python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "update_auth_bit.py", line 287, in run
    await update_bootloader(node, node_id, bootloader_image)
  File "update_auth_bit.py", line 246, in update_bootloader
    await agent.write_rom(0x0000BF00, bytes.fromhex(s))
  File "update_auth_bit.py", line 120, in write_rom
    while len(data) % write_size:
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "update_auth_bit.py", line 306, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.8/asyncio/runners.py", line 47, in run
    _cancel_all_tasks(loop)
  File "/usr/lib/python3.8/asyncio/runners.py", line 60, in _cancel_all_tasks
    task.cancel()
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  File "/usr/lib/python3.8/asyncio/tasks.py", line 718, in cancel
    if child.cancel():
  [Previous line repeated 495 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
2024-12-03 05:42:32 ERROR asyncio: Task exception was never retrieved
future: <Task finished name='update_bootloader(125)' coro=<main.<locals>.run() done, defined at update_auth_bit.py:285> exception=KeyboardInterrupt()>
Traceback (most recent call last):
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1859, in _run_once
    handle._run()
  File "/usr/lib/python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "update_auth_bit.py", line 287, in run
    await update_bootloader(node, node_id, bootloader_image)
  File "update_auth_bit.py", line 246, in update_bootloader
    await agent.write_rom(0x0000BF00, bytes.fromhex(s))
  File "update_auth_bit.py", line 120, in write_rom
    while len(data) % write_size:
KeyboardInterrupt

Then another few stanzas of errors appear.

  1. Ensure that the device is running Telega v1.0. Otherwise, the script will not work.
  2. Add more logging calls throughout the code to see what’s happening. Right now there is no relevant output in the log.

Indeed, my Myxa is running Telega v1.0. I have to upload it every time I power it on through Yukon.

Lots of logging calls later, I found that this part of the script:

while len(data) % write_size:
            data = data.ljust(1, b"\xFF")

Continues running to infinity. I’m not too sure why, but that’s apparently what’s holding the actual upload up.

Ah indeed. Please do this instead:

while len(data) % write_size:
    data += b'\xFF'
1 Like

This is my current error actually:

--- Logging error ---
Traceback (most recent call last):
  File "/usr/lib/python3.8/logging/__init__.py", line 1085, in emit
    msg = self.format(record)
  File "/usr/lib/python3.8/logging/__init__.py", line 929, in format
    return fmt.format(record)
  File "/home/usr/.local/lib/python3.8/site-packages/coloredlogs/__init__.py", line 1140, in format
    return logging.Formatter.format(self, record)
  File "/usr/lib/python3.8/logging/__init__.py", line 668, in format
    record.message = record.getMessage()
  File "/usr/lib/python3.8/logging/__init__.py", line 373, in getMessage
    msg = msg % self.args
TypeError: not all arguments converted during string formatting
Call stack:
  File "update_auth_bit.py", line 308, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.8/asyncio/base_events.py", line 603, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 570, in run_forever
    self._run_once()
  File "/usr/lib/python3.8/asyncio/base_events.py", line 1859, in _run_once
    handle._run()
  File "/usr/lib/python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "update_auth_bit.py", line 289, in run
    await update_bootloader(node, node_id, bootloader_image)
  File "update_auth_bit.py", line 248, in update_bootloader
    await agent.write_rom(0x0000BF00, bytes.fromhex(s))
  File "update_auth_bit.py", line 131, in write_rom
    await self._flash_erase_sector(sec)
  File "update_auth_bit.py", line 154, in _flash_erase_sector
    _logger.debug("Sector Number",sector_number)
Message: 'Sector Number'
Arguments: (None,)
2024-12-05 04:09:20 CRITI __main__: Bootloader update on node 125 has failed: unsupported operand type(s) for <<: 'NoneType' and 'int'
Traceback (most recent call last):
  File "update_auth_bit.py", line 289, in run
    await update_bootloader(node, node_id, bootloader_image)
  File "update_auth_bit.py", line 248, in update_bootloader
    await agent.write_rom(0x0000BF00, bytes.fromhex(s))
  File "update_auth_bit.py", line 131, in write_rom
    await self._flash_erase_sector(sec)
  File "update_auth_bit.py", line 155, in _flash_erase_sector
    cr = 0x00000002 | (sector_number << 3)
TypeError: unsupported operand type(s) for <<: 'NoneType' and 'int'

I managed to fix the previous one quite similarly to yours. Thank you however.

It looks like there have been changes around the sector number calculation code. Let’s look at the latest edition of your script. Also, do add the flash offset to the write destination address: 0x0000BF00 → 0x0800BF00

Sure!
update_auth.py (13.9 KB)

The main difference between my script so far and the original one would be the log calls I’ve put in for debugging. I think the script is being held up at the moment by the previously reported error.
Hopefully this makes it all more clearer.

Your _map_address_to_flash_sector_number is broken – the code was modified, the new method does not return anything, which causes the None type error mentioned earlier. If you repair it, everything should work. Consider viewing the diff of your file against the original one and make sure there have been no unintended modifications:

diff update_auth.py original_file.py

I tried doing that to arrive at this program:
update_auth 2.py (14.1 KB)
After some positive looking comments on the console, the LED on the Myxa turned off, and is completely invisible to any method of probing - USB or CANBUS. I think it’s bricked.
I don’t have a SWD programmer, nor do I know how to use one.
What are my options?

You can get a $9 probe like this: STLINK-V3MODS STMicroelectronics | Development Boards, Kits, Programmers | DigiKey

Connect SWDIO, SWDCLK, GND, +3.3V to the board, then upload the bootloader, the signature, and the application. You can use the official ST-Link utility for this. The whole process takes about 10 minutes.