-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Changing the Header #51
Comments
What all is the seqno used for? A system might have a small number of message types, but send them frequently. A use case we currently have is sending led commands, which are sometimes animations sent at 30hz and run for hours. That's on an i2c transport. If the seqno is only used to disambiguate in-flight requests, then that application would only need a u8 (probably only a single bit, actually). It also suggests that it might be fine to always have a u8 seqno? Or perhaps each side could keep an internal seqno of usize but only send a u8 on the wire, handling rollovers so it appears as a usize to the user. |
Yes, sequence number is used to disambiguate in-flight requests. It is possible that you have multiple in flight requests at once. I would agree it is not very likely that you have >256 in flight. |
This is a major change to postcard-rpc. This is a **very breaking wire change!** In particular, this PR changes the following: ## Server Rework Signifcantly reworks how "servers" are implemented, removing the previous embassy-usb-specific one in favor of more reusable parts, that allow for implementing a server generically over different transports. This new version still has an implementation for embassy-usb 0.3, but ALSO provides a channel-based implementation for testing, and I am likely to port a TCP-based one I have in `poststation` as well. This unlocks the ability to reuse the bulk of the existing code for supporting other transports, like UART, SPI, I2C, Ethernet, or even over radio. ## `define_dispatch` macro rework As part of the Server Rework, I also mostly rewrote the `define_dispatch!` macro, which now can be used with ANY transport, not just embassy-usb. This change also now allows servers to define topic handlers, so incoming published messages can be dispatched similar to endpoint dispatching. CC #15 ## Automatic Key Shrinking Previously, we would always send the full 8-byte "hash of the path and schema" ID in every message, as well as checking at compile time whether there is a collision or not. This PR takes that up a notch, now calculating the *smallest* hash key we can use (1, 2, 4, or 8 bytes) automatically at compile time, and uses that as our "native" mapping. This is similar to the concept of "Perfect Hash Functions". ## Variable Sequence Number size Additionally, the client can now send sequence numbers of 1, 2, or 4 bytes. Previously, sequence numbers were a `varint(u32)`. Servers will always respond back with the same sequence number they received when replying to requests. ## Completely redo message headers As we now have variable sized keys and sequence numbers, headers can now scale dynamically to the necessary size. CC #51 Before, we had 8 byte keys (fixed) and 1-5 bytes (`varint(u32)`), meaning headers were between **9-13 bytes**. Now, we use one byte as a discriminant, containing the key and seqno len, as well as a 4-bit version field, as well as the variable key and variable sequence number. This now means that headers are **3-13 bytes** (1B discriminant + 1/2/4/8B key + 1/2/4B sequence number), and will be **3 bytes in many common cases** where it is not necessary to disambiguate more than 256 in-flight messages (via sequence numbers) or 256 endpoints (though the liklihood of having a collision at 8 bits is higher than that due to the birthday problem). When a Client first connects to a Server, it will always start by sending an 8B key. If the Server replies with a shorter key, the Client will then switch to using keys of that size. It is not necessary to ever hardcode what size keys are necessary, as this is calculated when the Server is compiled, and is automatically detected by the Client. In general: * The CLIENT (usually the PC) is in charge of picking the size of the sequence number * The SERVER (usually the MCU) is in charge of picking the size of the message keys
Merged in #53 |
Currently, the defined header in postcard-rpc is:
[u8; 8]
representing theKey
of the request/response/publishvarint(u32)
representing the sequence number of the request/response/publishThis is generally fine for USB, as the header takes up 9-13 bytes, still often allowing a whole message to fit in a 64 byte frame. However, this amount of overhead is less desirable on low-bandwidth transports, like over a radio, where less is more.
I have been unsure about shortening the key, as it is procedurally generated, and the goal is to practically never require users to think about the chance of a collision. However for many users with a small number of endpoints/topics, one or two bytes is likely enough to be unique. Ideally we'd be able to have devices choose which size they'd like to use at compile time, however we should not feature-gate this, as a host may speak via multiple transports with different settings (e.g. "full fat" USB and "lite" I2C on the same machine).
Additionally for devices with low throughput, a smaller sequence number range is also likely acceptable.
I'd propose the following new format for postcard-rpc headers:
The settings byte would act as the following bitfield values:
0b00
: 1B Key, 1B SN (3 bytes total)0b01
: 2B Key, 2B SN (5 bytes total)0b10
: 4B Key, 4B SN (9 bytes total)0b11
: 8B Key, 4B SN (13 bytes total)Alternative uses for the 6b other that protocol version:
How it works
Right now, I have the following thoughts:
ABCDEFGH
sentABCD ^ EFGH
sentAB ^ CD ^ EF ^ GH
sentA ^ B ^ C ^ D ^ E ^ F ^ G ^ H
sent% 65536
% 256
This would make keys still natively eight bytes, but the end-devices could choose which key to use as part of their
define_dispatch!
invocation, e.g.:This will configure the Dispatcher and Sender to use the appropriate types, particularly for the const-time check for collisions (here).
The dispatch machinery will still require accepting messages with a longer-than-preferred key/seq, by shrinking as defined above. Perhaps we also carry the config of requests and use the same size as response?
Needs definition
The text was updated successfully, but these errors were encountered: