CANopenNode icon indicating copy to clipboard operation
CANopenNode copied to clipboard

Refactor CANopenNode into Rust for Enhanced Safety and Modernization

Open DonavanMartin opened this issue 7 months ago • 3 comments

Description

The goal of this issue is to initiate a project to refactor the CANopenNode library, currently implemented in C (with C++ compatibility), into Rust. CANopenNode provides a robust implementation of the CANopen protocol (a higher-layer protocol over CAN) for industrial and automotive applications. Refactoring it in Rust will leverage Rust’s memory safety, concurrency features, and modern ecosystem to improve reliability, maintainability, and developer experience while preserving the library’s functionality for embedded systems.

Motivation

  • No Rust Equivalent: As of June 2025, there is no mature Rust library for CANopen, despite growing Rust adoption in industrial automation (e.g., Modbus, OPC UA).
  • Safety: Rust’s compile-time checks eliminate common C issues like buffer overflows, null pointer dereferences, and memory leaks, critical for safety-critical systems using CANopen.
  • Performance: Rust offers comparable performance to C, suitable for real-time industrial applications.
  • Ecosystem: Integration with Rust’s ecosystem (e.g., socketcan for CAN, tokio for async) can enhance CANopenNode’s capabilities for modern IoT and embedded systems
  • Community Demand: Rust’s popularity in embedded systems (e.g., automotive, robotics) suggests a Rust-native CANopen library would be valuable.

Goals

  • Create a Rust-native implementation of CANopenNode that replicates its core functionality (e.g., PDO, SDO, NMT, LSS, heartbeat).
  • Ensure compatibility with embedded systems, avoiding dynamic memory allocation where possible.
  • Maintain cross-platform support (Linux, Windows, RTOS).
  • Provide safe, idiomatic Rust APIs for developers.
  • Optionally, integrate with Rust’s socketcan crate for CAN bus communication.

Non-Goals

  • Immediate replacement of the C implementation (the Rust version can coexist as an alternative).
  • Adding new CANopen features beyond the current C implementation (future enhancements can be separate issues).

Proposed Approach

Project Setup:

  • Create a new repository (e.g., CANopenNode-rs) or a Rust submodule in the existing CANopenNode repo.
  • Use cargo for build management and no_std for embedded compatibility.
  • License: Apache License 2.0 (to match the original CANopenNode).

Architecture:

  • Port core CANopen components (e.g., object dictionary, PDO/SDO processing, state machine) to Rust using safe abstractions.
  • Use Rust enums for CANopen states and error handling (e.g., Result for protocol errors).
  • Implement CAN bus interaction via socketcan (Linux) and provide abstractions for other platforms (e.g., Windows, RTOS).

Implementation Phases:

  • Phase 1: Port core CANopen stack (NMT, object dictionary, basic SDO).
  • Phase 2: Add PDO, heartbeat, and emergency message support.
  • Phase 3: Implement advanced features (LSS, SYNC, time) and optimize for no_std.
  • Phase 4: Add tests, examples, and documentation.

Testing:

  • Unit tests using cargo test for protocol logic.
  • Integration tests with CAN hardware or simulators (e.g., CANoe, vcan0 on Linux).
  • Benchmark performance against the C implementation to ensure no regression.

Documentation:

Provide Rustdoc comments and a user guide.

DonavanMartin avatar Jun 02 '25 20:06 DonavanMartin

That sounds great. I'm ready to cooperate, but personally I'm not skilled with Rust and don't have much time to take on this project.

Probably we will then have two parallel projects, C is still the only option in most microcontrollers. But this should not be the problem.

We will have to add new exporter into CANopenEditor, similar to https://github.com/CANopenNode/CANopenEditor/blob/main/libEDSsharp/CanOpenNodeExporter_V4.cs. It currently generates OD.h and OD.c files. But of course, first we could just manually translate those two files into Rust.

Then make a good foundation in Rust from mainline, driver.h/c, CANopen.h/c.

If we decide to start, I can create new repository here and specify developers...

CANopenNode avatar Jun 03 '25 10:06 CANopenNode

I'm currently putting together a canopen implementation in rust. I am just targeting CIA 301 for now, but I should have something together in the next couple weeks to make public

Its just a state machine in the "sans io" style where the user is required to pass received frames in, periodically call a tick function, send frames that are emitted and handle events.

The idea is I think similar to CANOpenNode with an event thread, receive thread and a tick thread, but the event thread also transmits frames. This part is obviously platform dependent, and in rust, async/blocking dependent.

I have a blocking socketcan based library that performs the event/tick/rx part and plan to implement an embassy based one as well.

Drop me a message if anyone is interested, I shall post it here when it's released

domw95 avatar Jun 10 '25 17:06 domw95

There is this project https://github.com/mcbridejc/zencan looks like mainly one contributor at the moment though.

nathanaelg avatar Oct 29 '25 04:10 nathanaelg