feat: implement wire framing, RPC server/client, and CLI tool#1
Conversation
- Add framing layer (COBS/rzCOBS) to telepath-wire - Implement transport and RPC server in telepath-firmware - Implement host-side RPC client in telepath-host - Add RTT transport and update nRF52840-DK example - Add telepath-cli tool crate - Fix .gitignore to use **/target/ covering all subdirectories Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates ignore rules intended to prevent committed Rust build artifacts, but also introduces substantial new Telepath RTT/COBS protocol plumbing across host, firmware, examples, and a new CLI tool.
Changes:
- Update
.gitignoreto ignoretarget/directories recursively. - Add COBS framing utilities and integrate RTT-based transport + polling server on firmware, plus corresponding host framing in
TelepathClient. - Add
telepath-cliand update the nRF52840-DK example to use RTT transport and apingcommand.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Switches to **/target/ ignore pattern. |
Cargo.toml |
Excludes tools/telepath-cli from the workspace. |
tools/telepath-cli/Cargo.toml |
Adds a standalone host-side CLI crate with probe-rs/clap deps. |
tools/telepath-cli/src/main.rs |
Implements RTT ping command using probe-rs and COBS framing. |
crates/telepath-wire/src/lib.rs |
Exposes new framing module. |
crates/telepath-wire/src/framing.rs |
Adds COBS encode/decode helpers and a FrameAccumulator with tests. |
crates/telepath-wire/Cargo.toml |
Adds cobs dependency (no_std). |
crates/telepath-firmware/src/transport.rs |
Introduces non-blocking byte-stream Transport trait. |
crates/telepath-firmware/src/lib.rs |
Adds RTT/COBS frame accumulation, request dispatch, and response framing in poll(). |
crates/telepath-firmware/Cargo.toml |
Adds serde and postcard dependencies to support serialization in firmware crate. |
crates/telepath-host/src/lib.rs |
Implements COBS framing in TelepathClient::call_raw and adds tests. |
crates/telepath-host/Cargo.toml |
Adds cobs and a firmware dev-dependency for integration tests. |
examples/nrf52840-dk/Cargo.toml |
Switches RTT stack to rtt-target, adds postcard, changes panic impl. |
examples/nrf52840-dk/.cargo/config.toml |
Removes defmt linker script flag. |
examples/nrf52840-dk/src/rtt_transport.rs |
Adds RTT-backed Transport implementation for firmware server. |
examples/nrf52840-dk/src/main.rs |
Initializes RTT channels, registers ping command, and polls server in loop. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Import MAX_FRAME_SIZE in telepath-host; add FrameTooLarge guard in the receive loop so an unbounded stream cannot exhaust host memory. - Split PayloadTooLarge into RequestPayloadTooLarge (args too large before sending) and ResponsePayloadTooLarge (response payload exceeds limit). - Validate resp.kind == PacketType::Response after deserialization; a packet with the wrong kind field now returns HostError::FramingError. - Mirror the same MAX_FRAME_SIZE guard in telepath-cli cmd_ping. - Update call_raw_rejects_oversized_args test to match new variant name. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Reject frames whose deserialized kind != PacketType::Request; this prevents a mislabeled or replayed Response packet from being dispatched. - Reject requests whose args slice exceeds MAX_PAYLOAD_SIZE before dispatch, guarding handlers from unexpectedly large inputs. - Clamp dispatcher return values > MAX_PAYLOAD_SIZE to SystemError instead of silently truncating, so the host always receives a valid bounded frame. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Expand the cortex_m::asm::delay comment to explain why blocking the Embassy executor is acceptable in this single-task demo and point to the correct async alternative (embassy_time::Timer) for multi-task firmware. - Rename call_raw_ping_roundtrip → server_ping_roundtrip and update its doc comment to accurately reflect that it exercises server.poll() + manual encode/decode, not the call_raw() code path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add self-contained usage documentation to each crate introduced in PR #1: - crates/telepath-wire: protocol overview, key types, framing API, constants - crates/telepath-firmware: architecture diagram, Transport trait, CommandMetadata usage - crates/telepath-host: TelepathClient API, HostError variants, call_raw example - tools/telepath-cli: prerequisites, build, ping subcommand, RTT channel layout - examples/nrf52840-dk: prerequisites, build/flash steps, RTT channels, verify with CLI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document the SEGGER J-Link udev rule required for USB access on Linux, and add --allow-erase-all to the probe-rs runner command to handle the factory APPROTECT lock on nRF52840. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rtt_init! requires down channel indices to start at 0 and be contiguous.
The previous config used only index 1, causing rtt_init_channels! to
write to channels.down[1] in a 1-element array (out-of-bounds UB) and
advertising num_down_channels=1, so the host's down_channel(1) call
returned None and the CLI bailed with "RTT down channel 1 not found".
Fix: add a 1-byte placeholder at down channel 0 so indices {0,1} are
contiguous. Channel 1 remains the telepath RPC channel; update the
RttTransport::new() call to use channels.down.1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verification ChecklistBefore merging, please run through the following two tiers. Tier 1 — No hardware required (mirrors CI)All four steps pass in CI, but running them locally catches environment issues before merge. Tier 2 — Real nRF52840-DK (optional but recommended)Prerequisites
Steps Troubleshooting
Once Tier 1 passes (Tier 2 if hardware is available), this PR is ready for squash merge to preserve Conventional Commit history. |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TelepathClient and its transport were created but never called; the test drives the roundtrip by writing into the pipe directly and calling server.poll(). Drop both unused bindings to clear the unused_mut / unused_variables warnings in cargo test and clippy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
telepath-wire(framing.rs)telepath-firmwaretelepath-hosttelepath-clitool crate for host-side serial communicationnrf52840-dkexample with RTT transport integrationPayloadTooLargevariants.gitignoreto use**/target/covering all subdirectoriesKey Changes
telepath-wireframingmodule (COBS encode/decode, rzCOBS encode/decode,MAX_FRAME_SIZE)telepath-firmwarepoll-based dispatch),transportmodule, payload/kind validationtelepath-hostcall_raw), frame size guard, response kind validationtelepath-clipingcommandnrf52840-dkUsage
Prerequisites
cargo install probe-rs-tools)thumbv7em-none-eabitarget:rustup target add thumbv7em-none-eabi1. Flash the firmware
cargo runflashes the binary and opens an RTT session. The firmwarestarts immediately; LED 1 blinks to indicate liveness.
2. Run the CLI
In a second terminal (firmware must remain running):
Expected output:
To target a different chip:
3. Use
telepath-hostas a libraryTest plan
cargo test --workspacepassescargo clippy --workspace -- -D warningscleancd examples/nrf52840-dk && cargo build --releasesucceedscd tools/telepath-cli && cargo buildsucceeds🤖 Generated with Claude Code