Crate postcard_rpc

Source
Expand description

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’s Serialize trait - which defines how we can convert a type into bytes on the wire
  • serde’s Deserialize trait - which defines how we can convert bytes on the wire into a type
  • postcard_schema’s Schema 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 Endpoints, 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.

Modules§

  • Accumulator tools
  • URI and Schema Hashing
  • Postcard-RPC Header Format
  • A postcard-rpc host client
  • Definitions of a postcard-rpc Server
  • These are items you can use for your error path and error key.
  • Test utilities for doctests and integration tests
  • Create unique type lists at compile time

Macros§

  • Define Dispatch Macro
  • Endpoint macro
  • Endpoints macro
  • merge_unique_types collects all unique, non-primitive types contained by the given comma separated types. It can be used with any types that implement the Schema trait, and returns a &'static [&'static NamedType].
  • Topic macro
  • Topics macro
  • unique_types collects all unique, non-primitive types contained by the given single type. It can be used with any type that implements the Schema trait, and returns a &'static [&'static NamedType].

Structs§

  • An overview of all topics (in and out) and endpoints
  • An overview of a list of endpoints
  • The Key uniquely identifies what “kind” of message this is.
  • A compacted 2-byte key
  • A compacted 2-byte key
  • A compacted 4-byte key
  • An overview of a list of topics

Traits§

  • A marker trait denoting a single endpoint
  • A marker trait denoting a single topic