Generic Media Access Layer

Several of the libraries in the project now are beginning to have somewhat duplicated code in the framing layer above the media itself. The same or similar algorithm exists in libcanard / libupdard / libserard / lib*ard for reorganizing frames into cohesive serialized messages w/ meta-data. I think it’s time we separated out those generic algorithms into something slightly more abstract so that the media access itself is not a dependency. This will allow anyone to implement cyphal over more media types and could leverage more usecases than just CAN/UDP/UART.

This would start as a garage project and move into being a first class library after it can be show to functionally match lib*ard.


Cyphal transport layers belong to either category: those with cyclic (i.e., modular, overflowing) transfer-ID and those with monotonic (i.e., sufficiently wide to be non-overflowing) transfer-ID counters. They have little in common, and I don’t think there is a meaningful way to unify their implementations.

Currently, there is only one transport definition that relies on the cyclic transfer-ID, which is Cyphal/CAN. It is preferable to avoid introduction of new transports with cyclic transfer-ID; see this for context: pycyphal.transport.redundant package — PyCyphal 1.10.6 documentation

Cyphal/UDP and Cyphal/Serial rely on the monotonic transfer-ID. Their commonalities are exploited in PyCyphal with the help of this small internal module (not well-documented because it is not part of the public API):

We could define something like this for libudpard/libserard but I wouldn’t call it a first-order objective because the entire framing/deframing logic can be described in just a couple hundred lines of C, so the benefits are probably insignificant.