#[repr(C)]pub struct ViolationRecord<const N: usize> {
pub magic: AtomicU32,
pub version: AtomicU32,
pub capacity: AtomicU32,
pub slot_words: AtomicU32,
pub total: AtomicU32,
pub head: AtomicU32,
pub dropped: AtomicU32,
pub suppressed_before_arm: AtomicU32,
pub armed: AtomicU32,
pub reserved: AtomicU32,
pub slots: [ViolationSlot; N],
}Expand description
phase-474 I1 – the image-wide violation record a debugger reads by NAME, for a board whose console reaches nobody.
The executor’s ring is carved out of executor storage (no symbol, and a
drain empties it), so on the Autoware Safety Island it could only be found
by scanning RAM for rule-id string pointers, and it held the FIRST eight
verdicts since boot. This record is the black box beside it: a #[repr(C)]
static, every word a u32, never drained, keeping the LATEST
MAX_VIOLATIONS stored violations of every executor in the image, with
the running total.
Layout (version RECORD_VERSION, little-endian u32 words):
| word | field | meaning |
|---|---|---|
| 0 | magic | RECORD_MAGIC ("NRVR") |
| 1 | version | RECORD_VERSION |
| 2 | capacity | slots (NROS_EXECUTOR_MAX_VIOLATIONS) |
| 3 | slot_words | RECORD_SLOT_WORDS |
| 4 | total | violations stored since boot (the last seq) |
| 5 | head | slot the NEXT violation takes (total % capacity) |
| 6 | dropped | entries overwritten (total - capacity, saturating) |
| 7 | suppressed_before_arm | verdicts before the monitors armed, all executors (phase-474 I2) |
| 8 | armed | executors whose monitors armed (counted as each arms; at its first spin by default) (phase-474 I2) |
| 9 | reserved | 0 |
| 10.. | slots | capacity x ViolationSlot |
The newest entry is in slot (head + capacity - 1) % capacity; reading
capacity slots backwards from there gives newest to oldest, and a slot
whose seq is 0 was never written.
Present only when the image asked for the boot report
(NROS_BOOT_REPORT=1, Zephyr CONFIG_NROS_BOOT_REPORT=y) – the same
opt-in as the SWD boot record it sits beside, so an image that does not
opt in is unchanged. Read it with scripts/read-violation-record.py.
Fields§
§magic: AtomicU32§version: AtomicU32§capacity: AtomicU32§slot_words: AtomicU32§total: AtomicU32§head: AtomicU32§dropped: AtomicU32§suppressed_before_arm: AtomicU32§armed: AtomicU32§reserved: AtomicU32§slots: [ViolationSlot; N]Implementations§
Source§impl<const N: usize> ViolationRecord<N>
impl<const N: usize> ViolationRecord<N>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
A valid, empty record: the header is written at compile time, so a
record with total == 0 reads as “no violation since boot” rather than
as uninitialised RAM.
Sourcepub fn store(&self, v: &Violation) -> u32
pub fn store(&self, v: &Violation) -> u32
Store one violation, overwriting the oldest when full. Returns its 1-based sequence number.
Lock-free and callable from any executor thread: the slot is claimed by
a fetch_add on total, so two executors never write one slot unless
N more violations land during one write.