This commit is contained in:
2026-06-12 22:57:50 +02:00
parent d8057a47d2
commit 5e2cfeafb9
5 changed files with 414 additions and 118 deletions
+106 -57
View File
@@ -30,16 +30,11 @@ struct FrameOutput {
error_frames: Vec<ErrorFrame>,
}
fn frame_worker(
mmap: &[u8],
dbc: &Dbc,
) -> FrameOutput {
let mut channel_data = HashMap::<CanId, Vec<CanFrame>>::new();
let mut metadatas = HashMap::<CanId, MessageMetadata>::new();
let mut unknown_ids = HashSet::<CanId>::new();
let mut error_frames = Vec::<ErrorFrame>::new();
/// Build the LD metadata for a single CAN id from the DBC, applying the
/// project's `ld_*`/`Frequency` attribute defaults. Returns `None` when the
/// id is not described by the DBC (an "unknown" id). Shared by the ASC decode
/// path and the live-CAN path so both produce identical metadata.
pub fn build_message_metadata(dbc: &Dbc, id: CanId) -> Option<MessageMetadata> {
let get_default = |name: &str| match dbc
.attribute_defaults
.iter()
@@ -56,57 +51,66 @@ fn frame_worker(
let default_scale = get_default("ld_scale");
let default_decimal_places = get_default("ld_decimal_places");
let mut add_metadata = |id| {
let msg = match dbc.messages.iter().find(|x| x.id.raw() == id) {
Some(msg) => msg,
None => {
unknown_ids.insert(id);
return;
}
};
let signals = &msg.signals;
let mut signals_meta = Vec::<SignalMetadata>::new();
for signal in signals {
let decimal_places = dbc
.attribute_values_signal
.iter()
.find(|x| {
x.message_id.raw() == id
&& x.signal_name == signal.name
&& x.name == "ld_decimal_places"
})
.map_or(default_decimal_places, |x| match x.value {
can_dbc::AttributeValue::Uint(val) => val,
_ => panic!("Bad ld_decimal_places value type, expected Uint."),
});
signals_meta.push(SignalMetadata {
shift: default_shift as u16,
scale: default_scale as u16,
decimal_places: decimal_places as u16,
name: signal.name.clone(),
unit: signal.unit.clone(),
signal: signal.clone(),
});
}
let frequency = dbc
.attribute_values_message
let msg = dbc.messages.iter().find(|x| x.id.raw() == id)?;
let signals = &msg.signals;
let mut signals_meta = Vec::<SignalMetadata>::new();
for signal in signals {
let decimal_places = dbc
.attribute_values_signal
.iter()
.find(|x| x.message_id.raw() == id && x.name == "Frequency")
.map_or(default_freqency, |x| match x.value {
.find(|x| {
x.message_id.raw() == id
&& x.signal_name == signal.name
&& x.name == "ld_decimal_places"
})
.map_or(default_decimal_places, |x| match x.value {
can_dbc::AttributeValue::Uint(val) => val,
_ => panic!("Bad Frequency value type, expected Uint."),
_ => panic!("Bad ld_decimal_places value type, expected Uint."),
});
metadatas.insert(
id,
MessageMetadata {
id,
frequency: frequency as u16,
signals: signals_meta,
},
);
signals_meta.push(SignalMetadata {
shift: default_shift as u16,
scale: default_scale as u16,
decimal_places: decimal_places as u16,
name: signal.name.clone(),
unit: signal.unit.clone(),
signal: signal.clone(),
});
}
let frequency = dbc
.attribute_values_message
.iter()
.find(|x| x.message_id.raw() == id && x.name == "Frequency")
.map_or(default_freqency, |x| match x.value {
can_dbc::AttributeValue::Uint(val) => val,
_ => panic!("Bad Frequency value type, expected Uint."),
});
Some(MessageMetadata {
id,
frequency: frequency as u16,
signals: signals_meta,
})
}
fn frame_worker(
mmap: &[u8],
dbc: &Dbc,
) -> FrameOutput {
let mut channel_data = HashMap::<CanId, Vec<CanFrame>>::new();
let mut metadatas = HashMap::<CanId, MessageMetadata>::new();
let mut unknown_ids = HashSet::<CanId>::new();
let mut error_frames = Vec::<ErrorFrame>::new();
let mut add_metadata = |id| match build_message_metadata(dbc, id) {
Some(meta) => {
metadatas.insert(id, meta);
}
None => {
unknown_ids.insert(id);
}
};
// Caller has aligned the chunk to line boundaries, so we always start at
@@ -171,6 +175,51 @@ pub struct DecodeResult {
pub info: DecodeProcessInfo,
}
impl DecodeResult {
/// An empty result suitable for incrementally accumulating live CAN
/// frames via [`DecodeResult::push_live`]. The `info` fields that only
/// make sense for the file-based decode are zeroed.
pub fn empty() -> Self {
DecodeResult {
data: HashMap::new(),
metadata: HashMap::new(),
info: DecodeProcessInfo {
unknown_ids: HashSet::new(),
error_frames: Vec::new(),
date: chrono::DateTime::from_timestamp(0, 0).unwrap().naive_utc(),
thread_count: 0,
page_size: 0,
pages_per_chunk: 0,
chunk_size: 0,
},
}
}
/// Append a single live frame, lazily resolving its metadata from the DBC
/// the first time an id is seen. Frames are expected to arrive in
/// non-decreasing timestamp order (as they do off a live bus), so no
/// re-sorting is performed — `compute_signal` consumes them in order.
pub fn push_live(&mut self, dbc: &Dbc, frame: CanFrame) {
match self.data.get_mut(&frame.can_id) {
Some(vec) => vec.push(frame),
None => {
let id = frame.can_id;
self.data.insert(id, vec![frame]);
if !self.metadata.contains_key(&id) {
match build_message_metadata(dbc, id) {
Some(meta) => {
self.metadata.insert(id, meta);
}
None => {
self.info.unknown_ids.insert(id);
}
}
}
}
}
}
}
pub fn decode(dbc: &Dbc,
asc_path: &Path) -> DecodeResult {
let thread_count = std::thread::available_parallelism().unwrap().get();