$ show CANopenNode/CANopenNode
This repository contains CANopenNode, a full-featured, portable ANSI C implementation of the CANopen protocol stack compliant with EN 50325-4 (CiA 301) and related standards (CiA 302, 303, 304, 305, 309). It is designed for embedded microcontrollers and real-time industrial automation systems. The stack implements Network Management (NMT) with heartbeat and node guarding, SDO server/client with expedited/segmented/block transfer, PDO with dynamic mapping, Emergency messages, SYNC, Time-stamp, LSS, Safety-Related Data Objects (SRDO), and an ASCII gateway for remote management (CiA 309-3). The architecture is modular, with each protocol in its own directory (301/, 303/, 304/, 305/, 309/). Central orchestration is provided by `CANopen.c` with a main processing loop `CO_process()` that should be called cyclically. The stack is configuration-driven via compile-time macros in `CO_config.h`, allowing feature enable/disable to reduce footprint. A hardware abstraction layer (`CO_driver.h`) separates CAN bus specifics, and example blank drivers (`CO_driver_blank.c`, `CO_storageBlank.c`) facilitate porting to new platforms. Key design patterns include a generic Object Dictionary interface with extension callbacks, a reusable circular FIFO buffer with protocol parsing, storage abstraction with CRC integrity, and non-blocking state machines. The codebase adheres to MISRA C:2012 (with documented exceptions) and includes Doxygen documentation. While primarily a library, the repository contains an example application skeleton and a generated device profile XML. Technical debt includes the FIFO and gateway modules being excluded from static analysis, certain static variables limiting reentrancy, and the trace feature being non-functional. The project is actively maintained with a large user base and multiple derivative repositories for specific platforms (Linux, STM32, PIC, etc.).
The LLM identified 4 files worth highlighting for reuse:
Self-contained circular byte FIFO with token scanning, multiple data type conversions (u8-u64, float, hex, visible string), base64 encode/decode, and an alternate read pointer for retransmission without data consumption. Demonstrates careful non-blocking design and is used by SDO client and ASCII gateway, but requires no internal stack dependencies and can be extracted for any embedded serial protocol.
Generic interface to the CANopen Object Dictionary, providing find, read, write, and sub-entry access. The OD_extension_t pattern allows inserting custom read/write callbacks on any OD entry without modifying auto-generated code. This decouples application logic from the OD layout and is a reusable abstraction for any dictionary-based embedded system.
Base class for persistence of Object Dictionary parameters. Provides a generic interface with store/restore functions, CRC16-CCITT integrity checks, and support for multiple storage backends (e.g., EEPROM). The pattern separates data format (CANopen variables) from storage media, making it adaptable to any non-volatile memory type.
Standalone CRC16-CCITT implementation (polynomial 0x1021) with init, update, and finalize functions. Used across multiple stack modules (SDO block transfer, SRDO, storage). Can be extracted as a utility for any protocol requiring CRC-16/CCITT.