blob: 8124f7e6fc39689d1cc3ca5e006c36d22812f2ea [file] [view] [edit]
# Port Hubris `ast1060-mctp-i2c-echo` to OpenPRoT (Pigweed)
## Context
**Source:** `hubris/app/ast1060-mctp-i2c-echo/`
A Hubris RTOS application running MCTP-over-I2C echo on an AST1060 RoT.
| Task | Crate | Role |
|------|-------|------|
| `jefe` | `task-jefe` | Supervisor / fault manager |
| `idle` | `task-idle` | Idle task |
| `mctp_echo` | `mctp-echo` | Listens for MCTP type-1 requests, echoes payload back |
| `mctp_server` | `mctp-server` | MCTP transport layer (features: `serial_log`, `transport_i2c`) |
| `uart_driver` | `drv-ast1060-uart` | UART peripheral driver |
| `i2c_driver` | `drv-mock-i2c` | Mock I2C driver (feature: `mock-only`) |
**Target:** `openprot/`
Cargo workspace + Bazel, targeting the **Pigweed kernel** (pw_kernel). Existing services follow `api/` + `server/` + `backend-*/` pattern (see `services/i2c/`). Platform integration is Pigweed-only the MCTP server will run as a **userspace process** under pw_kernel, not a Hubris task or Linux process.
## Porting Principle
**Preserve as much of the original Hubris code as possible.** Only change what is OS-dependent. The MCTP protocol logic, packet handling, server state management, transport encoding/decoding, and application logic (echo) should be carried over as-is. The only parts that change are:
- **IPC mechanism**: Hubris `idol` / `sys_reply` / `Leased` Pigweed `pw_kernel` IPC/channels
- **Task/process model**: Hubris `task_slot!` / `sys_recv_open` / notifications Pigweed userspace process event loop
- **Driver APIs**: Hubris `drv-i2c-api` / `ast1060-uart-api` OpenPRoT `services/i2c/` userspace driver
- **Build system**: Hubris `app.toml` + `build.rs` code generation Bazel BUILD files + `system.json5`
Everything else the `Server` struct, `Router` integration, `Sender` implementations, handle management, timeout logic, MCTP type definitions should remain structurally identical to the Hubris originals.
---
## Phase 1: MCTP Service API (`services/mctp/api`) — COMPLETE
Create the platform-independent MCTP types and traits crate.
- [x] Create `services/mctp/api/` directory structure
- [x] `Cargo.toml` `openprot-mctp-api` crate
- [x] `src/lib.rs` `Handle`, `RecvMetadata` types
- [x] `src/error.rs` `ResponseCode`, `MctpError` (ported from hubris `mctp-api` `ServerError`)
- [x] `src/traits.rs` `MctpClient`, `MctpListener`, `MctpReqChannel`, `MctpRespChannel`
- [x] Add to workspace `Cargo.toml`
- [x] Verify `cargo check` passes
## Phase 2: MCTP Server Core (`services/mctp/server`) — COMPLETE
Create the platform-independent server logic crate.
- [x] Create `services/mctp/server/` directory structure
- [x] `Cargo.toml` `openprot-mctp-server` crate
- [x] `src/lib.rs` + `src/server.rs` `Server` struct with EID mgmt, pending recv tracking, timeouts
- [x] Add to workspace `Cargo.toml`
- [x] Verify `cargo check` passes
- [x] Integrate `mctp-stack` (`mctp-lib`) `Router` as the packet processing engine
- [x] Re-export `mctp_stack::Sender` trait for transport bindings
- [x] Wire up inbound packet Router pending recv fulfillment via `Server::inbound()` + `Server::update()`
## Phase 3: I2C Transport Binding (`services/mctp/transport-i2c`) — COMPLETE
Port the I2C transport from hubris `mctp-server/src/i2c.rs`, using the I2C userspace driver at `services/i2c/` as the underlying transport.
- [x] Create `services/mctp/transport-i2c/` crate
- [x] Implement `Sender` for I2C using the `services/i2c/` userspace driver (client API + IPC to I2C server)
- [x] Implement inbound I2C MCTP packet decoding (using `mctp-stack::i2c::MctpI2cHandler`)
- [x] Use `I2cTargetClient` from `services/i2c/api` for slave/target mode receive
- [x] Echo integration test with client/server partition (`DirectClient` implementing `MctpClient`, 2 tests passing)
## Phase 4: Serial Transport Binding (`services/mctp/transport-serial`) — NOT STARTED
Port the serial transport from hubris `mctp-server/src/serial.rs`. (Lower priority than I2C.)
- [ ] Create `services/mctp/transport-serial/` crate
- [ ] Implement `Sender` for serial (using `embedded-io::Write`, not hubris `ast1060-uart-api`)
- [ ] Implement inbound serial MCTP packet decoding (using `mctp-stack::serial::MctpSerialHandler`)
## Phase 5: MCTP Echo Application — IN PROGRESS
Port the echo task from hubris `task/mctp-echo/`.
- [x] IPC wire protocol (`services/mctp/api/src/wire.rs`) request/response encoding for all MCTP operations
- [x] IPC client (`services/mctp/client/`) `IpcMctpClient` implementing `MctpClient` via wire protocol + IPC
- [x] Server-side IPC dispatch (`services/mctp/server/src/dispatch.rs`) decodes wire requests, calls `Server`
- [x] Wire-protocol dispatch integration test (`tests/dispatch.rs`) full round-trip through wire encoding
- [x] Echo binary as Pigweed userspace process (`target/ast1060-evb/mctp/mctp_echo.rs`)
- [ ] Wire up with server + I2C transport for an end-to-end demo (needs real I2C sender in server `main.rs`)
## Phase 6: Pigweed Platform Integration — MOSTLY DONE
Wire up the MCTP server as a Pigweed userspace process on the AST1060-EVB (`target/ast1060-evb/`).
- [x] MCTP server `main.rs`: event loop driven by pw_kernel IPC/channels
- Replaces hubris `sys_recv_open` / notifications / `idol` IPC dispatch
- Uses `dispatch_mctp_op` for IPC request handling
- Follows the pattern established by `services/i2c/server/`
- Uses NoopSender for initial bring-up; real I2cSender wiring is TODO
- [x] Connect `IpcMctpClient::send_recv` to `syscall::channel_transact` (gated behind `pigweed` feature)
- [x] Bazel BUILD files for each new crate (following `services/i2c/` pattern)
- [x] `system.json5` entry for MCTP server + echo processes (`target/ast1060-evb/mctp/`)
- [x] Integration with `target/ast1060-evb/` platform definition (`target.rs`, `BUILD.bazel`)
## Phase 7: Testing & Documentation — PARTIALLY DONE
- [x] Wire protocol unit tests (7 tests in `api/src/wire.rs`)
- [x] Echo integration tests with client/server partition (2 tests in `server/tests/echo.rs`)
- [x] Wire-protocol dispatch integration tests (2 tests in `server/tests/dispatch.rs`)
- [x] README for each MCTP crate (`api/`, `server/`, `client/`, `transport-i2c/`)
- [ ] QEMU-based end-to-end test (following `services/i2c/` test pattern)
- [ ] Update `docs/src/specification/middleware/mctp.md` with implementation status
---
## Current Status
**Phases 13, 5, and 6 mostly complete.** All library code, IPC dispatch, Bazel BUILD files, system configuration, and echo binary are written. 11 tests pass. Remaining work: wire up real I2cSender in server main.rs (replace NoopSender), QEMU e2e test, and docs update.
## Key Dependencies
| Crate | Source | Role |
|-------|--------|------|
| `mctp` | workspace (types crate) | `Eid`, `MsgType`, `Tag`, `Error` etc. |
| `mctp-stack` / `mctp-lib` | `github.com/9elements/mctp-lib` branch `buildup` | `Router`, `Sender`, fragmentation, serial/I2C handlers |
| `services/i2c/` | I2C userspace driver | I2C client/target/server MCTP transport-i2c uses this as its underlying I2C transport |
| `heapless` | workspace | `no_std` collections |
| `zerocopy` | workspace | Zero-copy serialization |
| Pigweed (`pw_kernel`) | Bazel via `MODULE.bazel` | Userspace processes, IPC channels, system image |