SocketCAN API on a RTOS

@lorenz.meier said today that the work on the media layer adapter bridging SocketCAN with libuavcan/libcanard is about to be underway (if not already), so I would like to provide some hands-on guidance here. I invite @scottdixon to verify this and expand my recommendations as necessary. CC @TSC21 FYI.

Generally, I think the solid work @PetervdPerk has done covers most if not all of the specifics of real-time communication, so the media layer implementations for our libraries will amount to a few hundred lines of trivial glue logic. It makes sense to consult with the v0 platform-specific components, keeping in mind that in v1 the media layer has been extended to support CAN FD and in some sense simplified.

Libuavcan v1

Libuavcan has a layered architecture where it bridges the underlying transport network and the application:

+---------------+
|  Application  |
+-------+-------+
        |
+-------+-------+
|   Libuavcan   |
+-------+-------+
        |  <---------- you are here
+-------+-------+
|  Media layer  |  <-- e.g., SocketCAN
+-------+-------+
        |
+-------+-------+
|    Hardware   |
+---------------+

So there are two interfaces: the front-end and the back-end. The library is not yet implemented but the back-end interface is already defined under /libuavcan/include/libuavcan/media. The interface may end up being slightly altered after the support for other transports is built into the design, but such changes are not expected to have any major impact on existing implementations so it is safe to proceed.

The media layer adapter is just the implementation of the interfaces defined under libuavcan::media; @noxuz has done it for his baremetal S32K driver. An important difference compared to v0 is that the TX queue and transmission deadline tracking will now be managed by SocketCAN itself (in v0 it used to be managed by Libuavcan). This design choice has certain implications for Linux.

Seeing as the Linux version of SocketCAN does not support transmission deadline tracking, that option should be simply omitted when compiling for Linux. In v0 we run a sophisticated queue monitoring trying to enforce deadlines and prevent priority inversion, but in reality, neither of the objectives are attained fully and there are serious issues with certain types of CAN hardware (discussed on this forum and on GitHub/Libuavcan) so that logic should not be recreated. This feature can be re-enabled later if someone managed to upstream Peter’s real-time extensions into mainline Linux SocketCAN.

The adapter should be designed to support any flavor of SocketCAN on any POSIX-like system. Judging by Peter’s experiment with Libuavcan v0, I don’t expect such OS-agnosticism to be hard to ensure, but it does mean that we will have to let go of certain facilities to accommodate the requirements of real-time systems: heap, exception handling, etc. will have to go.

I think that despite this being a concrete driver, it might make sense to make it header-only to simplify integration.

None of the apps and utilities shipped with the original v0 SocketCAN driver are needed anymore.

This component should be located under /socketcan/libuavcan in the platform-specific component repository.

Libcanard v1

Libcanard v1 is not layered. The library provides data handling services for the application; it is the responsibility of the latter to organize the flow of data between the library, the hardware, and the business logic:

+---------------------------------+
|           Application           |
+-------+-----------------+-------+
        |                 | <----------- you are here
+-------+-------+ +-------+-------+
|   Libcanard   | |  Media layer  |  <-- e.g., SocketCAN
+---------------+ +-------+-------+
                          |
                  +-------+-------+
                  |    Hardware   |
                  +---------------+

It follows that the definition of the interface between the application and the media layer is entirely up to its designer. I imagine in our case here it would amount to a simple wrapper that hides the somewhat clumsy Berkeley socket API behind a libcanard-oriented wrapper; perhaps it might look like this:

typedef int fd_t;
fd_t socketcanOpen(const char* const can_iface_name, const bool can_fd);
int16_t socketcanTransmit(const fd_t fd, const struct canfd_frame* const frame, const uint64_t deadline_usec);
int16_t socketcanReceive(const fd_t fd, struct canfd_frame* const out_frame, uint64_t* const out_timestamp_usec);
int16_t socketcanConfigureFilter(const fd_t fd, const size_t num_filters, const struct can_filter* filters);

Reliance on Libcanard itself is entirely optional.

We should strive to follow the rules of MISRA C, although there is no intention to enforce full documentation compliance.

This component should be located under /socketcan/libcanard in the platform-specific component repository.

You may use the old v0 driver as an inspiration but note that its API is a bit overcomplicated.

UPDATE: keep in mind that multiple SocketCAN sockets may be used on the same node side-by-side in configurations with redundant transports.

Quality assurance

The v1 codebase adheres to a higher quality standard. We enforce a consistent coding style following the Zubax C/C++ Conventions, use static analysis extensively, and strive to provide full test coverage. We recognize that it may sometimes be impractical to hold the platform-specific components (which we are discussing here) to the same stringent QA requirements because our resources are limited. Still, we would appreciate contributions leveraging the following methods:

  • Clang-Tidy and Clang-Format. A recommended configuration can be found in the Libcanard v1 repo.
  • A cloud static analysis tool supporting a decent subset of MISRA and CERT rules. Our C/C++ libraries currently leverage SonarQube, but we are entirely open to new options (they are actually preferable for the sake of exploration). The tool should be configured adequately, relevant rules should be enabled.
  • Configured CI/CD pipeline, preferably with HITL.

Also see the contribution guideline for Libuavcan and Libcanard.