Skip to content

Firmware ​

Updating the firmware of a MUXEN box means sending it a new program over the CAN bus, one block at a time. While it runs, that box is out of service. It is a deliberate maintenance act, usually done at the yard, and it is never triggered by anything the crew does.

muxen-uds performs the upload. The images themselves come from the muxen-firmware package.

The firmware store ​

Everything lives under one directory:

/usr/lib/muxen/firmware/
├── products.json
├── 010010004/
│   ├── 010010004-v6.2-NMEA2000.srec
│   └── 010010004-v5.21-NMEA2000.srec
└── 010020007/
    └── 010020007-v6.0-8H-v1.5.srec

products.json is the catalog: an array of products, each with a code (the ProductId), a commercial name, and — when the catalog declares it — the hardwareId of the board an image targets and the softwareId of the application it implements. Images sit in a subdirectory named after the product code.

The directory is read directly; there is no registration step and no database. Installing or upgrading muxen-firmware is what puts images there, and no device is touched by that: an image only reaches a device during an explicit firmware command.

Listing what is available ​

sh
$ muxen-uds listfirmware
firmware: 010010004: 010010004-v6.2-NMEA2000.srec (hw: 990010061)
firmware: 010020007: 010020007-v6.0-8H-v1.5.srec (hw: unknown)

listfirmware needs no device and no CAN traffic — it reads the directory. hw is the board the image targets, or unknown when products.json carries no annotation for that file.

Over the WebSocket the same command returns name, code, filename, the absolute firmware path, hardwareId and softwareId, with the last two null rather than absent when the catalog does not declare them.

Choosing the right image ​

Getting this wrong is the one part of a firmware update that a tool cannot recover from on its own. Two rules:

Match the board, not the filename. A device reports ProductId, HardwareId and SoftwareId in its own parameter table. Compare those against the catalog's code, hardwareId and softwareId:

sh
muxen-uds -i can0 -d 0x280 readconfig --only-name ProductId \
                                      --only-name HardwareId \
                                      --only-name SoftwareVersion

When hardwareId is null the catalog does not declare the board for that image. Do not guess — pick the image by hand from the product documentation.

Do not cross a major version boundary blindly. A v5 and a v6 bootloader are signed with different keys, so a device refuses an image from the other major version. The refusal happens before any data is written, so nothing is damaged — but the update simply cannot succeed. Match the major version of the image to the device's current SoftwareVersion.

Uploading ​

sh
muxen-uds -i can0 -d 0x043 firmware --srec 010010004-v6.2-NMEA2000.srec
muxen-uds -i can0 -d 0x043 firmware --name 010010004-v6.2-NMEA2000.srec
OptionEffect
--srec <file>a path to an SREC file, resolved as given
--name <name>a file name looked up inside the firmware store

--name searches every product subdirectory of /usr/lib/muxen/firmware for a .srec file with exactly that name, so you can pass what listfirmware printed without knowing which product folder it sits in. --srec takes any readable path, which is what you want for an image that is not in the store.

Progress is printed in place:

step 3: 42 / 100%
step 3: 100 / 100%
cmd: firmware updated

Run it with -vv to see each stage announced (step 1: parse firmware, step 2: download request, step 3: transfer data, step 4: transfer exit).

What happens during an upload ​

  1. The SREC is parsed into memory in one pass. Only S3 records are used; the first one gives the start address, and their combined payload gives the total size. A malformed record is skipped with a message at -vv. Once parsed, the file is closed — the upload no longer depends on it.
  2. A Request Download announces the address and size to the device.
  3. The bus is quieted. A broadcast communication off frame is sent before the transfer and again every 10 blocks, so the device is not competing with normal traffic while it writes flash.
  4. Each S3 record is sent as one Transfer Data block, with a rolling block counter. A block is given 1.5 seconds to be acknowledged and up to 10 attempts; the very last block is given 5 seconds per attempt instead.
  5. A Transfer Exit closes the session.

Two of those numbers are not arbitrary, and knowing why saves a lot of guessing when an upload misbehaves:

  • 1.5 s per block, not longer. When the device's ISO-TP receiver overflows a block under load it answers nothing at all. The retry has to land before the device's own 5-second upload session times out; a slower retry arrives after it, and the device then answers that attempt and every later one with requestSequenceError — the transfer is dead with no way back except starting over.
  • 5 s for the last block. The final block carries the image trailer at the top of the flash slot, so the device first fills the gap from the end of the image, one flash write per byte, before acknowledging. It is legitimately slow, not lost — measured at about 3 seconds on the bench. Retrying it early is what fails, because by then the device's write pointer has moved past it and it answers requestSequenceError; waiting is what works.

Progress over the WebSocket ​

The firmware command streams { "percent": N } notifications before its final response, at most one every 500 ms. Each notification also re-arms the client's request timeout, which turns that timeout into an idle timeout: an upload is abandoned only when the daemon goes quiet, however long it takes overall. See Web clients — @muxen/uds.

After an upload ​

A firmware update is expected to reset the device's configuration, InstanceNum included. Plan to re-apply it:

sh
muxen-uds -i can0 -d 0x043 readconfig --save-as-json before.json   # first
muxen-uds -i can0 -d 0x043 firmware --name …
muxen-uds -i can0 -d 0x043 writeconfig --from-json before.json     # after

The restore matches by name and re-resolves identifiers against the new firmware, so a parameter that moved to another id is still written correctly — see Device configuration.

InstanceNum is part of that configuration. A device that comes back at instance 0 after an update, on a bus where another unit of the same function already sits at 0, produces an address collision. Check with uid --scan afterwards.

When an upload aborts ​

The transfer is retried aggressively precisely because an aborted upload wastes time. When it does abort, muxen-uds reports the failure and stops; it never leaves a transfer half-finished behind it, and it never retries on its own.

What the device does with a partial image is decided by the device's bootloader, not by muxen-uds. In practice a unit that has just refused an upload answers readconfig immediately afterwards, which is the first thing to check:

sh
muxen-uds -i can0 -d 0x043 readconfig --only-name SoftwareVersion

If it answers, the box is alive — diagnose at leisure and upload again. See Troubleshooting.

Integration of multiplexed solutions
MUXEN and the MUXEN logo are trademarks of MUXEN SAS.