Skip to content

Add HPO support in SygnalInterfaceSocketcan via parse-ordering arbitration - #26

Merged
eric-polymath merged 3 commits into
mainfrom
eric/sygnal_can_interface_hpo_handling_tactical_norefactor
May 20, 2026
Merged

Add HPO support in SygnalInterfaceSocketcan via parse-ordering arbitration#26
eric-polymath merged 3 commits into
mainfrom
eric/sygnal_can_interface_hpo_handling_tactical_norefactor

Conversation

@eric-polymath

@eric-polymath eric-polymath commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary
Wires SygnalHpoInterface (landed in the prior PR) into SygnalInterfaceSocketcan and the ROS 2 node so HPO boards can be commanded and observed end-to-end. Tactical fix for now, proper per-board refactor + multi-protocol PRD deferred.

Detailed change log

Lib:
New HpoId struct + SendHpoCommandResult; constructor extended with optional hpo_ids (defaults to {}, zero behavior change for existing callers).
sendHpoControlEnable / sendHpoControlCommand + get_hpo_interface_states / get_hpo_overall_interface_state accessors.
parse() rewired: HPO parsers run before the existing MCM control-response parser, with a DO NOT REORDER comment block explaining why.
Constructor throws std::invalid_argument if any HPO and MCM share a bus address.
HPO_NUM_INTERFACES corrected from 7 → 5 to match real hardware (DBC defines 7, only 5 are wired). Matches MCM precedent.
ROS 2:

New hpo_endpoints:

int_array parameter (default []).
parse_hpo_id helper + hpo_ids_ member; passes vector through to the socketcan ctor.

Tests:
New always-on sygnal_interface_socketcan_routing_tests (6 cases / 29 assertions): disjoint-address ctor check, HPO/MCM heartbeat routing, HPO control-response non-disturbance of MCM queues.
Existing HPO interface tests updated for the 5-interface array length (17 cases / 74 assertions, green).
Why this works (CAN-ID arbitration mitigation)
Sygnal overloads CAN IDs across device types — 0x161 ControlCommandResponse carries different byte layouts depending on whether MCM or HPO produced it. The only field with stable semantics across layouts is the 7-bit BusAddress. We exploit two invariants:

Routing order :

parse() tries HPO parsers (which filter by bus_address) before SygnalControlInterface::parseCommandResponseFrame (which doesn't filter). Anything addressed to an HPO is claimed first; what reaches the MCM parser by elimination is MCM.
Disjoint bus addresses — enforced at construction time so the routing-by-elimination is sound.
What's deferred
Proper per-board refactor (move MCM control parse/pack into SygnalMcmInterface, delete SygnalControlInterface).
IO board, relay refactor, error-frame surfacing.
Multi-protocol/multi-version PRD (Emerson's thread).
Count8 rolling counter — still hard-coded to 0.
Breaking changes
None — existing two-arg constructor still works; mcm_endpoints param unchanged; legacy MCM behavior untouched.

Test plan
colcon test --packages-select sygnal_can_interface_lib green
colcon build --packages-up-to sygnal_can_interface_ros2 clean
On LEV05: send HPO ControlEnable + ControlCommand, observe heartbeat reflecting the command
Confirm misconfigured hpo_endpoints overlapping an MCM throws at node configure

@eric-polymath
eric-polymath merged commit 8b80c90 into main May 20, 2026
4 of 5 checks passed
@eric-polymath
eric-polymath deleted the eric/sygnal_can_interface_hpo_handling_tactical_norefactor branch May 20, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant