Chapter 10 — CAN Transport State Machine

The CAN main state machine orchestrates the CAN transport layer: it handles duplicate alias resolution, outgoing CAN frame transmission, CAN login frame sequencing, and round-robin node enumeration. It is the CAN-layer counterpart of the OpenLCB main dispatcher.

Source files: src/drivers/canbus/can_main_statemachine.c, src/drivers/canbus/can_main_statemachine.h

10.1 Entry Point

CanMainStateMachine_run() is called from the main loop alongside the OpenLCB state machines. Each call performs one cooperative step and returns immediately. Before the priority chain runs, it calls OpenLcbBufferList_check_timeouts() to expire stale multi-frame assembly buffers.

10.2 Priority Dispatch Flowchart

flowchart TD A["CanMainStateMachine_run()"] --> T["check_timeouts()"] T --> B{"handle_duplicate\n_aliases()"} B -- "true" --> Z["return"] B -- "false" --> C{"handle_outgoing\n_can_message()"} C -- "true" --> Z C -- "false" --> D{"handle_login_outgoing\n_can_message()"} D -- "true" --> Z D -- "false" --> E{"handle_try_enumerate\n_first_node()"} E -- "true" --> Z E -- "false" --> F{"handle_try_enumerate\n_next_node()"} F --> Z style A fill:#4a90d9,color:#fff style Z fill:#888,color:#fff
PriorityFunctionPurpose
0 (always) check_timeouts() Expire stale multi-frame assembly buffers in the BufferList (3-second timeout).
1 (highest) handle_duplicate_aliases() Scan alias table for duplicates; unregister and reset affected nodes.
2 handle_outgoing_can_message() Pop one frame from the outgoing CAN FIFO and transmit. Retries on busy.
3 handle_login_outgoing_can_message() Transmit the pending login frame (CID/RID/AMD) from the static buffer.
4 handle_try_enumerate_first_node() Start node enumeration; run login state machine for nodes still in CAN login phase.
5 handle_try_enumerate_next_node() Advance to next node; continue CAN login processing if needed.

10.3 Duplicate Alias Handling

Duplicate aliases are detected by the CAN RX path (ISR context) and flagged in the alias mapping table. The main state machine resolves them in the main-loop context:

flowchart LR A["RX ISR detects\nduplicate alias"] --> B["Set is_duplicate\nflag on mapping entry"] B --> C["Set has_duplicate_alias\nglobal flag"] C --> D["Main loop:\nhandle_duplicate_aliases()"] D --> E["Unregister alias\nfrom mapping table"] E --> F["Reset node to\nRUNSTATE_GENERATE_SEED"] F --> G["Node re-logs in\nwith new alias"]

The _reset_node() function clears:

10.4 CAN Identifier Layout

OpenLCB CAN frames use 29-bit extended identifiers. The top bit (bit 28) distinguishes OpenLCB frames from CAN control frames:

BitsFieldDescription
28Frame Type1 = OpenLCB message, 0 = CAN control frame
27:24Frame SubtypeFor OpenLCB: message type (standard, datagram variants, stream). For control: sequence number or 0 for variable-field.
23:12Variable FieldMTI (for standard messages), Destination Alias (for datagrams/streams), or CID check value / control frame type.
11:0Source Alias12-bit alias of the sending node.

OpenLCB Frame Types (bits 27:24)

ValueFrame TypeVariable Field (bits 23:12)
0x1Standard (global/addressed)CAN MTI
0x2Datagram OnlyDestination Alias
0x3Datagram FirstDestination Alias
0x4Datagram MiddleDestination Alias
0x5Datagram FinalDestination Alias
0x6Reserved--
0x7StreamDestination Alias

CAN Control Frames (bit 28 = 0)

SequenceVariable FieldMeaning
00x0700RID (Reserve ID)
00x0701AMD (Alias Map Definition)
00x0702AME (Alias Map Enquiry)
00x0703AMR (Alias Map Reset)
00x0710-0x0713Error Information Report
7..1Check valueCID7 through CID1 (Check ID frames)

10.5 Node Enumeration for Login

The CAN state machine's enumerate-first / enumerate-next loop processes nodes whose run_state < RUNSTATE_LOAD_INITIALIZATION_COMPLETE. These nodes are still in the CAN login phase (alias reservation). The CAN login state machine is invoked via the login_statemachine_run() callback. Nodes that have passed this threshold are handled by the OpenLCB login state machine (Chapter 9) instead.