|
PER Firmware
|
The CANpiler is the centralized code generation authority. It handles CAN message generation, fault library, and (soon) daq variable generation.
Modeled After the traditional compiler pipeline.
build.py: Main entry point for CANpiler. Coordinates the top-level data flow.
utils.py: Shared helpers (format_float, print_as_success, etc.) used across the pipeline.
validator.py: Catches syntax errors in the configuration files using the jsonschema library (Draft 2020-12 validator).
parser.py: Parses configurations into IR @dataclasses. "Logical" config errors are caught during this phase.
SystemContext is assembled by build.py after linking and mapping.faultgen.augment_system_with_faults: Walks each fault-library-enabled node and injects <node>_fault_event + <node>_fault_sync TX messages before linking. This ensures fault messages get IDs assigned alongside everything else.
linker.py: Transforms the IR into a linked IR with resolved message IDs using a two-pass "Water Level" algorithm.
msg_id_override values respect priority monotonicity (messages in priority $N$ cannot have IDs higher than messages in priority $N+1$).msg_name to ensure deterministic builds.msg_name on the same logical bus as the subscription. Bit-level layout (offsets, shifts, masks) for TX messages is computed earlier in parsing.(bus_name, msg_name) there must be exactly one transmitting node on that bus. Duplicate TX definitions (two nodes, or two entries in one node) fail the build.msg_name on that bus (hardware nodes are not configured to receive their own frames).mapper.py: Maps CAN IDs to physical hardware resources.
accept_all_messages is enabled.Produces the final build artifacts from the SystemContext using the Jinja2 templating engine.
static constexpr for type-safe constants and identifiers.../templates/): bus_header.h.jinja, can_router.h.jinja, can_types.h.jinja, fault_data.c.jinja, fault_data.h.jinja, filter/bxcan.c.jinja, filter/fdcan.c.jinja, node_header.h.jinja, plus shared node/ partials.codegen.py: Generates can_types.h, per-node headers (<NODE>.h), per-bus headers, and the central can_router.h from the Jinja templates. Packed bit-field structs, endianness-safe accessors, and hardened sign-extension for signed signals.dbcgen.py: Produces deterministic, versioned DBC files using the cantools library.faultgen.py: Injects FAULT_SYNC and FAULT_EVENT messages into node configurations and generates global fault tracking maps (fault_data.c / fault_data.h).load_calc.py: Performs post-generation capacity analysis for each bus in the system.