2 stable releases
Uses new Rust 2024
| new 1.2.1 | Feb 8, 2026 |
|---|---|
| 1.1.0 | Jun 15, 2025 |
| 1.0.0 |
|
#1260 in Embedded development
140KB
1.5K
SLoC
PK Command
[中文]
This repository contains the specification and an implementation of the PK Command, a communication protocol designed for embedded devices.
Library usage
This Rust library is universal on both host and device. The caller needs to construct a PkCommand instance on the host or device and keep calling the instance's poll method.
Variable and method management is provided by types that implement the PkVariableAccessor and PkMethodAccessor traits, where the non-blocking mechanism of methods is based on the Pollable trait. This library also provides predefined PkVHashmapWrapper (for variables), PkMHashmapWrapper (for methods), and PkPollable.
Example
See the test case.
The Protocol
lib.rs:
PK Command
A lightweight, reliable data transfer protocol designed for constrained channels (e.g., HID, Serial) between a Host and an Embedded Device.
Key Features
- Reliability: Built-in ACK/Retransmission mechanism.
- Efficiency: Fixed-length headers and data slicing for small MTUs.
- Flexibility: Supports variable access (GET/SET) and remote method invocation (INVOK).
- no_std Support: Core logic is compatible with embedded systems without an OS. Note that
allocis still used in no_std environments. - Wait Mechanism: Keep-alive
AWAITpackets for long-running operations.
Architecture
The protocol operates using Transaction Chains. A chain starts with a START
command and ends with ENDTR. Large payloads are automatically sliced into
SDATA packets.
Command Format
Every command follows the fixed layout:
[MSG ID][OPERATION NAME] [OBJECT] [DATA].
MSG ID: A base-94 encoded unsigned integer (using ASCII characters from '!' to '~') that uniquely identifies the command within a transaction.OPERATION NAME: A 5-character ASCII string representing the command type. All the operations defined in the specification are defined in this library. (Seetypes::Operationfor details.)OBJECT: An optional 5-character ASCII string that provides additional context for the operation (e.g., variable name, method name).DATA: An optional binary payload that carries parameters or return values. It can be of arbitrary length and may contain any byte values.
See Command for a structured representation of commands and utilities for parsing and serialization.
Note that:
OBJECTis either omitted, or exactly 5 ASCII characters.DATA(payload) is arbitrary binary data.- The total length of a command is limited by the transportation layer's MTU (e.g., 64 bytes for HID). (See
PkCommandConfig.) But the protocol handles slicing and reassembly of large payloads automatically, so you can work with large data without worrying about the underlying transport constraints.
Example
use pk_command::{PkCommand, PkCommandConfig, PkHashmapMethod, PkHashmapVariable};
// 1. Setup configuration and accessors
let config = PkCommandConfig::default(64);
let vars = PkHashmapVariable::new(vec![]);
let methods = PkHashmapMethod::new(vec![]);
// 2. Initialize the state machine
let pk = PkCommand::<_, _, std::time::Instant>::new(config, vars, methods);
// 3. Basic loop driving the protocol
loop {
// Handle received bytes from your transport (HID/Serial/etc.)
if let Some(bytes) = transport.recv() {
pk.incoming_command(bytes);
}
// Process and get commands to send back
if let Some(cmd) = pk.poll() {
transport.send(cmd.to_bytes());
}
if pk.is_complete() {
break;
}
}
Feature flags
std: Enables features that require the Rust standard library. (Mainly the convenient wrappers likePkPromise,PkHashmapVariable,PkHashmapMethod) Enabled by default.embassy: Enables integration with the Embassy async framework. Flags below are also enabled when this is active:embassy-time: Enables the support for embassy-time crate, which provides timekeeping utilities for embedded environments.embassy-runtime: Enables the support for embassy-executor crate, which provides integration between the main state machine and Embassy async tasks.
tokio-runtime: Enables integration with the Tokio async runtime. Providestokio_adapterfor running async operations within method implementations. Requiresstdfeature.smol-runtime: Enables integration with the Smol async executor. Providessmol_adapterfor running async operations within method implementations. Requiresstdfeature.
Dependencies
~0–16MB
~154K SLoC