22 releases (9 breaking)
0.10.7 | Nov 15, 2024 |
---|---|
0.10.1 | Oct 31, 2024 |
0.6.0 | Jul 29, 2024 |
0.4.0 | Feb 23, 2024 |
0.3.1 | Nov 26, 2023 |
#148 in Embedded development
2,790 downloads per month
Used in 4 crates
295KB
5.5K
SLoC
Postcard RPC
A host (PC) and client (MCU) library for handling RPC-style request-response types.
See overview.md for documentation.
See the postcard-rpc
book for a walk-through example.
You can also watch James' RustNL talk for a video explainer of what this crate does.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
lib.rs
:
The goal of postcard-rpc
is to make it easier for a
host PC to talk to a constrained device, like a microcontroller.
See the repo for examples
Architecture overview
┌──────────┐ ┌─────────┐ ┌───────────┐
│ Endpoint │ │ Publish │ │ Subscribe │
└──────────┘ └─────────┘ └───────────┘
│ ▲ message│ │ ▲
┌────────┐ rqst│ │resp │ subscribe│ │messages
┌─┤ CLIENT ├─────┼─────┼──────────────┼────────────────┼────────┼──┐
│ └────────┘ ▼ │ ▼ ▼ │ │
│ ┌─────────────────────────────────────────────────────┐ │ │
│ │ HostClient │ │ │
│ └─────────────────────────────────────────────────────┘ │ │
│ │ │ ▲ │ | │
│ │ │ │ │ │ │
│ │ │ │ ▼ │ │
│ │ │ ┌──────────────┬──────────────┐│
│ │ └─────▶│ Pending Resp │ Subscription ││
│ │ └──────────────┴──────────────┘│
│ │ ▲ ▲ │
│ │ └───────┬──────┘ │
│ ▼ │ │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ ││ Task: out_worker │ │ Task: in_worker ▲│ │
│ ├┼───────────────────┤ ├───────────────────┼┤ │
│ │▼ Trait: WireTx │ │ Trait: WireRx ││ │
└──────┴────────────────────┴────────────┴────────────────────┴────┘
│ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ▲
│ The Server + Client WireRx │
│ │ and WireTx traits can be │ │
│ impl'd for any wire │
│ │ transport like USB, TCP, │ │
│ I2C, UART, etc. │
▼ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │
┌─────┬────────────────────┬────────────┬────────────────────┬─────┐
│ ││ Trait: WireRx │ │ Trait: WireTx ▲│ │
│ ├┼───────────────────┤ ├───────────────────┼┤ │
│ ││ Server │ ┌───▶│ Sender ││ │
│ ├┼───────────────────┤ │ └────────────────────┘ │
│ │▼ Macro: Dispatch │ │ ▲ │
│ └────────────────────┘ │ │ │
│ ┌─────────┐ │ ┌──────────┐ │ ┌───────────┐ │ ┌───────────┐ │
│ │ Topic │ │ │ Endpoint │ │ │ Publisher │ │ │ Publisher │ │
│ │ fn │◀┼▶│ async fn │────┤ │ Task │─┼─│ Task │ │
│ │ Handler │ │ │ Handler │ │ └───────────┘ │ └───────────┘ │
│ └─────────┘ │ └──────────┘ │ │ │
│ ┌─────────┐ │ ┌──────────┐ │ ┌───────────┐ │ ┌───────────┐ │
│ │ Topic │ │ │ Endpoint │ │ │ Publisher │ │ │ Publisher │ │
│ │async fn │◀┴▶│ task │────┘ │ Task │─┴─│ Task │ │
│ │ Handler │ │ Handler │ └───────────┘ └───────────┘ │
│ └─────────┘ └──────────┘ │
│ ┌────────┐ │
└─┤ SERVER ├───────────────────────────────────────────────────────┘
└────────┘
Defining a schema
Typically, you will define your "wire types" in a shared schema crate. This crate essentially defines the protocol used between two or more devices.
A schema consists of a couple of necessary items:
Wire types
We will need to define all of the types that we will use within our protocol. We specify normal Rust types, which will need to implement or derive three important traits:
serde
'sSerialize
trait - which defines how we can convert a type into bytes on the wireserde
'sDeserialize
trait - which defines how we can convert bytes on the wire into a typepostcard_schema
'sSchema
trait - which generates a reflection-style schema value for a given type.
Endpoints
Now that we have some basic types that will be used on the wire, we need to start building our protocol. The first thing we can build are [Endpoint]s, which represent a bidirectional "Request"/"Response" relationship. One of our devices will act as a Client (who makes a request, and receives a response), and the other device will act as a Server (who receives a request, and sends a response). Every request should be followed (eventually) by exactly one response.
An endpoint consists of:
- The type of the Request
- The type of the Response
- A string "path", like an HTTP URI that uniquely identifies the endpoint.
Topics
Sometimes, you would just like to send data in a single direction, with no response. This could be for reasons like asynchronous logging, blindly sending sensor data periodically, or any other reason you can think of.
Topics have no "client" or "server" role, either device may decide to send a message on a given topic.
A topic consists of:
- The type of the Message
- A string "path", like an HTTP URI that uniquely identifies the topic.
Dependencies
~2–35MB
~547K SLoC