|
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. Written in python for ease of maintainence and development.
build.py: Main entry point for CANpiler. Coordinates the top-level data flow.
templates/: Directory containing Jinja2 templates for all generated build artifacts. Decouples the output formatting from the generation logic.
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, bxcan_filter.c.jinja, can_router.h.jinja, can_types.h.jinja, fault_data.c.jinja, fault_data.h.jinja, fdcan_filter.c.jinja, node_header.h.jinja.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.
is_<msg>_stale() plus <MSG>_STALE_TIMEOUT_MS derived from 2.5x the message period so consumers can flag frames that have not arrived within that window.