4 releases
| 0.0.3 | Jan 20, 2026 |
|---|---|
| 0.0.2 | Dec 29, 2025 |
| 0.0.1 | Oct 29, 2025 |
| 0.0.0 | May 23, 2025 |
#471 in Configuration
Used in 2 crates
(via zencan-macro)
215KB
4.5K
SLoC
zencan-build
Library crate to generate object dictionary rust code from an input device configuration file. Used to generate static objects for use with zencan-node crate.
Dev Notes
Better errors
When the generated code is not syntactically correct rust code, prettyplease generates errors which are less than helpful for determining the cause of the error. In this case, rustfmt provides a much better output, so:
cargo run --example build_od -- CONFIG_FILE.toml > temp.rs, and then
rustfmt temp.rs
lib.rs:
Tools for generating a zencan node
Device Config File
A "device config" is a TOML file, which defines the behavior of a node. It has some general
configuration options, like how many RPDOs/TPDOs the device should support, and it creates the
set of application specific objects that will be accessible in the node's object dictionary. It
is the input used by zencan-build to generate code for the node.
The file is read using DeviceConfig.
Generating code using build.rs
The expected way to use this crate is in your project's build.rs file. The
[build_node_from_device_config()] function can be used there to generate the code from a
device config file, and store it under a provided label. Then, in your code, the
include_modules! macro from the zencan-node create can be used to include the code wherever
you want.
Example
In build.rs:
if let Err(e) =
zencan_build::build_node_from_device_config("EXAMPLE", "example_device_config.toml")
{
eprintln!("Error building node from example_device_config.toml: {}", e);
std::process::exit(1);
}
Then, in main.rs:
mod zencan {
zencan_node::include_modules!(EXAMPLE);
}
The generated code
The generated code looks something like this:
pub static OBJECT1000: Object1000 = Object1000::default();
pub static OBJECT1001: Object1001 = Object1001::default();
pub static OBJECT1008: Object1008 = Object1008::default();
pub static NODE_STATE: NodeState<4usize, 4usize> = NodeState::new();
pub static NODE_MBOX: NodeMbox = NodeMbox::new(NODE_STATE.rpdos());
pub static OD_TABLE: [ODEntry; 31usize] = [
ODEntry {
index: 0x1000,
data: ObjectData::Storage(&OBJECT1000),
},
ODEntry {
index: 0x1001,
data: ObjectData::Storage(&OBJECT1001),
},
ODEntry {
index: 0x1008,
data: ObjectData::Storage(&OBJECT1008),
},
];
For each object defined in the object dictionary, a type is created -- e.g. Object1000 for
object 0x1000 -- as well as an instance. All objects are put into a 'static table, called
OD_TABLE. Additionally, a NODE_STATE and a NODE_MBOX are created, and these must be provided
when instantiating node.
Dependencies
~4–6MB
~107K SLoC