Skip to content

rasprover: add ROS 2 CDR golden-bytes tests, fix BatteryState health enum - #73

Merged
rosterloh merged 2 commits into
mainfrom
test/rasprover-ros-cdr
Aug 14, 2026
Merged

rasprover: add ROS 2 CDR golden-bytes tests, fix BatteryState health enum#73
rosterloh merged 2 commits into
mainfrom
test/rasprover-ros-cdr

Conversation

@rosterloh

Copy link
Copy Markdown
Owner

Two commits. The second one is a real bug fix and is the reason this PR matters.

SHA Subject
790c59a rasprover: add Ztest suite for ROS 2 CDR encoding
5061147 rasprover: fix BatteryState health enum (was OVERHEAT, not GOOD)

The bug

app_ros_encode_battery_state() wrote 2 for power_supply_health under a /* POWER_SUPPLY_HEALTH_GOOD */ comment. In sensor_msgs/BatteryState the constants are POWER_SUPPLY_HEALTH_UNKNOWN = 0, GOOD = 1, OVERHEAT = 2 (mirroring the Linux power_supply enum).

Every battery message the rover published claimed the pack was overheating. Nothing in firmware reads the value back, so it was only ever visible to a ROS 2 subscriber — exactly the class of defect that is invisible from the firmware side and that golden-bytes tests exist to catch. It was found while deriving expected wire bytes from the message IDL, not by running the code.

power_supply_status = 2 (DISCHARGING) and power_supply_technology = 0 (UNKNOWN) are both correct. The neighbouring writes now spell out their numeric values too — a bare 2 sitting next to a constant name is what let this through.

app_zenoh.c:298 is the only caller and just publishes the buffer. Message length unchanged at 73 bytes.

The suite

10 tests over app_ros_cdr.c, which is pure (writes into a caller-supplied buffer, no kernel/net/fs) and was previously uncovered for BatteryState.

  • Golden byte arrays for BatteryState (73 B) and a one-joint JointState (72 B), derived from the message IDL and the CDR spec with the derivation shown in comments — not generated by running the code under test, which would assert nothing.
  • Alignment/padding transitions, which is where hand-rolled CDR actually breaks: the 3-byte pad for the f32 after an empty frame_id, the absence of a pad for the u32 after four u8 flags (rel 48 already aligned), the 4-byte pad for the f64 after the velocity count. Alignment measured from the post-encapsulation origin, as FastCDR expects.
  • Buffer-bounds behaviour at the trust boundary.
  • The existing byte layout is otherwise correct — field order and alignment both match the IDL.

Platform: qemu_cortex_m3

unit_testing would be the natural choice for pure code, but it does not build on macOS: ztest registers suites via STRUCT_SECTION_ITERABLE__attribute__((section(...))), which Mach-O rejects (mach-o section specifier requires a segment and section separated by a comma). native_sim is Linux-only. qemu_cortex_m3 ships with the Zephyr SDK and runs on any host; native_sim stays in platform_allow for Linux CI.

Verification

1 of 1 executed test configurations passed (100.00%), 0 failed, 0 errored
10 of 10 executed test cases passed (100.00%)
  • mise run agent-build rasprover --sysbuildsucceeds.
  • Pre-existing tests/rasprover/test_ros_cdr.py3 passed, unaffected (JointState only; it never covered BatteryState, which is why this gap existed).

Deliberately out of scope

  • tests/rasprover/test_ros_cdr.py left in place despite some JointState overlap — consolidating test infrastructure is not this PR's job.
  • No repo-wide twister task added: west twister -T applications currently fails on motor_controller (error: 'usb_dc_detach' is deprecated [-Werror=deprecated-declarations], 4 configs), so such a task would be red on arrival. That failure is pre-existing and worth its own look.

🤖 Generated with Claude Code

rosterloh and others added 2 commits August 14, 2026 09:31
app_ros_cdr.c hand-rolls the CDR byte layout for sensor_msgs/BatteryState
and sensor_msgs/JointState. A wrong pad byte does not fail the build, it
makes a ROS 2 subscriber silently misparse, so the layout needs pinning.

Ten tests over golden byte arrays derived by hand from the message IDL plus
the CDR alignment rule (working shown in comments), not from running the
code under test. They cover the encapsulation header, every alignment
transition that padding depends on (float32 after a string, uint32 after a
run of uint8, float64 after a uint32), the NaN "unmeasured" sentinels, the
buffer-too-small contract, and an encode/decode round trip.

Platform is qemu_cortex_m3. The code under test is pure and would suit
`unit_testing`, but ztest registers cases through ELF iterable sections and
Mach-O rejects the section attribute, so unit_testing does not build on
macOS; native_sim is Linux-only. qemu_cortex_m3 ships with the Zephyr SDK
and runs everywhere. native_sim stays in platform_allow for Linux CI.

test_battery_state_power_supply_enums documents a defect rather than hiding
it: the encoder writes 2 for power_supply_health and comments it
POWER_SUPPLY_HEALTH_GOOD, but in sensor_msgs/BatteryState GOOD is 1 and 2 is
OVERHEAT. The test asserts current behaviour so the suite stays green, with
a BUG note above it. No behaviour change here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
app_ros_encode_battery_state() wrote 2 for power_supply_health under a
/* POWER_SUPPLY_HEALTH_GOOD */ comment. In sensor_msgs/BatteryState the
constants are POWER_SUPPLY_HEALTH_UNKNOWN = 0, GOOD = 1, OVERHEAT = 2
(mirroring the Linux power_supply enum), so every battery message the rover
published claimed the pack was overheating. Nothing in firmware reads the
value back, so this was only ever visible to a ROS 2 subscriber.

Caught by the golden-bytes suite added in the previous commit, while
deriving the expected wire bytes from the message IDL.

The neighbouring status and technology writes now spell out their numeric
values too. A bare 2 sitting next to a constant name is what let this
through; naming the number makes the comment self-checking.

Message length is unchanged at 73 bytes, and app_zenoh.c is the only caller.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rosterloh
rosterloh merged commit fba23a8 into main Aug 14, 2026
8 checks passed
@rosterloh
rosterloh deleted the test/rasprover-ros-cdr branch August 14, 2026 08:43
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