Skip to content

The state file ​

An NMEA 2000 device negotiates its address at every power-up, so in principle it could land somewhere different each time. Chartplotters notice: a gateway that appears at a new address after every start looks like a new device, and some displays accumulate a list of ghosts.

muxen-nmea2000 avoids that by remembering the addresses it claimed last time and asking for the same ones again. That memory is a single small binary file.

Nothing in this chapter needs attention on a working boat. The file manages itself, and if it is ever wrong the daemon deletes it and carries on. It is documented because --show-state is a useful diagnostic when a device's address is in question.

Where it lives ​

Path
/var/lib/muxen-nmea2000/statethe primary daemon
/var/lib/muxen-nmea2000-<instance>/statea templated instance
<state-dir>/state.tmpthe temporary file used while writing

--state-dir DIR overrides the directory. Under systemd it comes from StateDirectory=, which is why an instance's state lands beside its own runtime directory rather than in the primary's.

The directory is created with mode 0750 if it does not exist; the file is written with mode 0600.

What it stores ​

The four addresses claimed by the four virtual devices, each with the NAME it claimed them under.

Storing the NAME alongside the address is what makes the file safe. If the daemon is restarted with a different NAME — a different boat, a changed identity, a templated instance sharing a directory by mistake — the saved addresses do not match and are simply not used. A stale file can never make the daemon claim an address that belongs to somebody else's identity.

Format ​

Version 3, little-endian, fixed layout.

Header:

FieldTypeValue
magicuint320x4A313933, ASCII J193
versionuint323
timestampuint64Unix seconds when written
checksumuint32CRC-32 over header and payload, with the checksum field zeroed
reserveduint32

Payload:

FieldType
vdev_countuint8number of entries in use, at most 8
reserveduint8[7]
vdevs8 entriesfixed-size array

Each entry:

FieldType
nameuint64the J1939 NAME this virtual device claimed under
addressuint8the address it claimed
vdev_iduint80 navigation, 1 engine, 2 AIS, 3 electrical
function_codeuint8the J1939 function code
reserveduint8[5]

The array is 8 entries although only 4 are used, so the format does not have to change if more virtual devices are added.

Earlier versions ​

VersionNotes
1original format, no checksum. Not read
2added the CRC-32, one device only. Read once and migrated
3current: multiple virtual devices

A version 2 file is migrated automatically on first read:

State file: Migrating v2 format to v3...
State file: Migrated v2 NAME=0x…

A migration that fails deletes the file, as any other corruption does.

Writing ​

Writes are atomic. The daemon writes state.tmp, flushes it, fsyncs it, renames it over state and then sets the mode to 0600. A power cut mid-write leaves either the old file or the new one, never a half-written one.

Validation, and what happens when it fails ​

Every field is checked on load, and a file that fails any check is deleted rather than partially trusted:

CheckFailure message
magic is 0x4A313933Invalid magic number 0x… (expected 0x4A313933)
version is 3 (or 2, to migrate)Unexpected version N (expected 3)
CRC-32 matchesChecksum mismatch (got 0x…, expected 0x…)
entry count ≤ 8Invalid vdev count N (max 8)
NAME is neither 0 nor all-onesInvalid NAME 0x… for vdev N
address is 0–253, or 254 (null)Invalid address 0x… for vdev N
the file is long enoughIncomplete read

followed by:

State file: Validation failed, deleting corrupted file

Deleting is the right response because the file is a cache of something the daemon can rediscover in two seconds. Keeping a suspect one risks claiming an address that belongs to another device.

A NAME mismatch is not corruption. The file is valid, it just belongs to a different identity, so it is ignored and left in place — reverting the identity should bring the addresses back.

A missing file is the normal first run:

State file: No saved state found (first run)

None of these prevent startup. The daemon falls back to its preferred address and claims normally.

Inspecting and clearing it ​

Both commands act and exit; neither starts the daemon, and both are safe to run while it is running.

sh
$ muxen-nmea2000 --show-state
State: File path: /var/lib/muxen-nmea2000/state
State: --------------------------------------------------
State: Status: Valid state file (4 virtual devices)
State: --------------------------------------------------
State: VDEV[0]:
State:   J1939 NAME:    0x11223344FF467788
State:   Address:       0x80 (128)
State:   Function Code: 130
State: NAME breakdown:
State:   …

The NAME breakdown decodes every field — identity number, manufacturer code and name, function code and name, industry group, arbitrary-address-capable — which makes --show-state the quickest way to check that a configured NAME is what you think it is.

With no valid file:

State: Status: No valid state file found
State: Possible reasons:
State:   - File does not exist (first run)
State:   - File is corrupted (invalid magic, checksum, etc.)
State:   - File has invalid data (NAME or address out of range)

To forget the saved addresses:

sh
$ muxen-nmea2000 --clear-state
State: Clearing file: /var/lib/muxen-nmea2000/state
State: File deleted successfully

--clear-state exits non-zero if the file could not be deleted.

Add --state-dir to either command to work on an instance's file:

sh
muxen-nmea2000 --show-state --state-dir /var/lib/muxen-nmea2000-can0

When clearing it is the right move ​

Rarely, and always for one of these reasons:

  • The gateway keeps claiming an address you have reassigned to another device. Clearing makes it renegotiate from its preferred address.
  • The boat's NAME has been changed deliberately and you want a clean start rather than a mismatch that is ignored.
  • You are moving a Brain between boats.

It is never a fix for "no data on the screens". The state file has no influence on anything except which address is asked for first.

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