Skip to content

Add SMBus PEC byte to ec-test-lib serial transport#92

Merged
dymk merged 1 commit into
OpenDevicePartnership:mainfrom
dymk:dymk/ec-test-cli-smbus-pec
May 20, 2026
Merged

Add SMBus PEC byte to ec-test-lib serial transport#92
dymk merged 1 commit into
OpenDevicePartnership:mainfrom
dymk:dymk/ec-test-cli-smbus-pec

Conversation

@dymk
Copy link
Copy Markdown
Contributor

@dymk dymk commented May 20, 2026

Summary

Adds SMBus PEC (Packet Error Code) byte computation on TX and verification on RX to ec-test-lib's serial transport, bringing it in line with the SMBus spec.

Motivation

embedded-services PR OpenDevicePartnership/embedded-services#852 makes uart-service's SmbusEspiMedium strictly spec-compliant: it now emits a PEC byte on every TX frame and requires one on every RX frame. Without a matching host-side change, ec-test-cli --source serial against any post-#852 uart-service consumer hangs — the EC waits for a PEC byte the host never sends, and the host waits for a PEC byte the EC includes but the host doesn't expect.

Changes

  • ec/test-lib/Cargo.toml: add smbus-pec = "1.0.1" direct dependency
  • ec/test-lib/src/serial.rs:
    • TX: append smbus_pec::pec() byte after the existing frame write
    • RX: read one extra byte after each response packet + verify against smbus_pec::pec() over the received frame; return Error::Protocol on mismatch

Validation

Test procedure

The goal was to validate that ec-test-cli --source serial works correctly against a dev-qemu EC firmware built with the post-#852 embedded-services (which emits and requires PEC bytes).

Environment: odp-platform-qemu-sbsa devcontainer (provides qemu-system-riscv32 v10.0.0).

Step 1 — Build dev-qemu with post-#852 embedded-services:

In odp-embedded-controller, temporarily patched platform/dev-qemu/Cargo.toml to:

  • Pin uart-service to the dymk/phase-34-uart-service-generic branch of dymk/embedded-services (which contains PR #852's changes: generic Service<R, M>, spec-compliant SmbusEspiMedium with PEC emit/verify, frame_complete() requiring PEC byte)
  • Add a [patch] section redirecting all embedded-services crates to the same fork branch (required for trait coherence since platform-common also depends on embedded-services)
  • Locally swapped the medium from MctpSerialMedium (Phase 35's DSP0253 choice) to Service::default_smbusespi(relay) so the EC speaks the SmbusEspi wire format that ec-test-cli uses

Built inside the devcontainer:

cd platform/dev-qemu
cargo build --release --locked --config 'env.DEFMT_LOG="off"'

Step 2 — Build ec-test-cli with this PR's PEC changes:

In odp-platform-common/ec, applied this PR's changes to test-lib/Cargo.toml and test-lib/src/serial.rs, plus a temporary [patch] block in ec/Cargo.toml redirecting embedded-services to the same dymk fork branch (so the SerializableMessage trait + message types match between ec-test-cli and dev-qemu):

cd ec
cargo build --release -p ec-test-cli

The [patch] block is test-only — it is NOT part of this PR. In production, ec-test-cli's message struct shapes come from the upstream v0.2.0 branch which is wire-compatible.

Step 3 — Run the integration test:

Copied the built ec-test-cli binary into the devcontainer's PATH, then ran odp-embedded-controller's existing scripts/integration-test.sh (added by OpenDevicePartnership/odp-embedded-controller#14). This script:

  1. Builds dev-qemu with cargo run-headless (QEMU with -serial pty)
  2. Polls QEMU output for the allocated /dev/pts/N path
  3. Runs 18 sequential ec-test-cli --port /dev/pts/N <service> <command> invocations
dev-qemu serial port: /dev/pts/2
Running thermal tests...
thermal get-temperature       → 19.950000000000045
thermal get-rpm               → 0.0
thermal get-min-rpm           → 0.0
thermal get-max-rpm           → 6000.0
thermal get-threshold on      → 24.950000000000045
thermal get-threshold ramping → 29.950000000000045
thermal get-threshold max     → 34.950000000000045
thermal set-rpm 1000
Running battery tests...
battery get-bst → BstReturn { battery_state: 2, battery_present_rate: 500, ... }
battery get-bix → BixFixedStrings { revision: 1, power_unit: 1, ... }
battery set-btp 50
Running RTC tests...
rtc get-capabilities          → TimeAlarmDeviceCapabilities { ... }
rtc get-real-time             → AcpiTimestamp { ... 1970-01-01 00:00:13 ... }
rtc get-wake-status ac        → TimerStatus { ... }
rtc get-wake-status dc        → TimerStatus { ... }
rtc get-expired-timer-wake-policy ac → AlarmExpiredWakePolicy(4294967295)
rtc get-expired-timer-wake-policy dc → AlarmExpiredWakePolicy(4294967295)
rtc get-timer-value ac        → AlarmTimerSeconds(4294967295)
rtc get-timer-value dc        → AlarmTimerSeconds(0)
SUCCESS: Integration test passed!

All 18 commands returned valid, non-error responses.

Step 4 — Verified the FAILURE case without this PR's changes:

Also ran the same test with an UNPATCHED ec-test-cli (no PEC changes) against the same post-#852 dev-qemu. Result: immediate timeout on the first command (thermal get-temperature), confirming the PEC mismatch is the root cause:

thermal get-temperature
Error: Io("Custom { kind: TimedOut, error: \"Operation timed out\" }")

Step 5 — Cleanup:

All temporary patches ([patch] blocks, medium swap in dev-qemu/src/main.rs, ec-test-cli binary in devcontainer) were reverted. Both repos' working trees verified clean.

Coordination note

This PR and embedded-services#852 must land in tight sequence. After #852 merges and odp-embedded-controller bumps its embedded-services pin past it, EC_TEST_CLI_REV in .github/workflows/check.yml must be bumped past this commit at the same time — otherwise the integration-test: CI job will fail.

Follow-up

A structural refactor to use mctp-rs directly in ec-test-lib::serial (eliminating the remaining hand-rolled MCTP framing) is planned as a separate followup PR.

The serial transport in ec-test-lib currently sends MCTP frames without
the trailing SMBus PEC (Packet Error Code) byte that the SMBus protocol
specifies as the trailing byte of each frame. embedded-services'
uart-service historically compensated for this on the device side by
stripping the PEC byte on TX and skipping the PEC byte on RX.

embedded-services PR OpenDevicePartnership/embedded-services#852 makes
uart-service strictly spec-compliant: SmbusEspiMedium now emits a PEC
byte on every TX frame and requires a PEC byte on every RX frame.
Without a matching change on the host side, `ec-test-cli --source
serial` against any post-#852 uart-service consumer (dev-imxrt,
dev-mcxa, dev-npcx, dev-qemu) hangs waiting for a PEC byte the EC
never sends, and the extra PEC byte sent by ec-test-cli corrupts the
EC's next request.

This change adds PEC computation on TX (one byte appended after the
existing frame) and verification on RX (one byte read + compared
against `smbus_pec::pec()` over the received frame), using the
`smbus_pec` crate already in the transitive dependency graph.

Coordination note: this PR and embedded-services #852 must land in
tight sequence. After #852 merges and `odp-embedded-controller` bumps
its `embedded-services` pin past it, `EC_TEST_CLI_REV` in
`.github/workflows/check.yml` must be bumped past this commit at the
same time, otherwise the `integration-test:` CI job added by
OpenDevicePartnership/odp-embedded-controller#14 will fail.

Validated end-to-end against `odp-embedded-controller`'s
`scripts/integration-test.sh` running dev-qemu built against
embedded-services with PR #852 applied: all 18 commands (thermal x8,
battery x3, rtc x7) succeed.

Assisted-by: GitHub Copilot CLI:claude-opus-4.7-1m-internal
@dymk dymk closed this May 20, 2026
@dymk dymk reopened this May 20, 2026
@dymk dymk marked this pull request as ready for review May 20, 2026 16:50
@dymk dymk requested a review from a team as a code owner May 20, 2026 16:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates ec-test-lib’s serial transport to be SMBus-spec compliant by adding Packet Error Code (PEC) handling on both transmit (append) and receive (verify), aligning host behavior with updated uart-service expectations.

Changes:

  • Add the smbus-pec crate as a direct dependency for PEC calculation.
  • Append a computed PEC byte after each transmitted SMBus-framed request.
  • Read and validate the trailing PEC byte on each received response packet, returning a protocol error on mismatch.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.

File Description
ec/test-lib/src/serial.rs Compute and append PEC on TX; read and verify PEC on RX for each packet.
ec/test-lib/Cargo.toml Add smbus-pec = "1.0.1" dependency used by the serial transport.
ec/Cargo.lock Lockfile update to include smbus-pec in the resolved dependency graph.

Copy link
Copy Markdown
Member

@kurtjd kurtjd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks!

So should we wait for OpenDevicePartnership/embedded-services#852 to be merged, then odp-embedded-controller-updated, before we merge this?

@dymk dymk merged commit d705cd4 into OpenDevicePartnership:main May 20, 2026
48 checks passed
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.

7 participants