0
0
Fork 0

WIP rx: Add basic CAM and DENM evaluation

This commit is contained in:
Jannik Beyerstedt 2026-08-03 11:17:51 +02:00
commit 97412982bd
2 changed files with 111 additions and 0 deletions

65
src/rx/cam.rs Normal file
View file

@ -0,0 +1,65 @@
//! C-ITS CAM Evaluation
use c_its_parser::standards::cam_1_4_1::cam_pdu_descriptions::{self, HighFrequencyContainer};
/// Prints a CAM as one line
pub fn pretty_print(etsi: &cam_pdu_descriptions::CAM) -> Option<alloc::string::String> {
match &etsi.cam.cam_parameters.high_frequency_container {
HighFrequencyContainer::basicVehicleContainerHighFrequency(obu) => {
let station_id = etsi.header.station_id.0;
let lat_deg = etsi
.cam
.cam_parameters
.basic_container
.reference_position
.latitude
.as_deg();
let lon_deg = etsi
.cam
.cam_parameters
.basic_container
.reference_position
.longitude
.as_deg();
let result = if obu.speed.speed_value.is_unavailable() {
alloc::format!(
"Got CAM from {station_id} at {lat_deg:.3}°N, {lon_deg:.3}°E, speed unavailable",
)
} else {
alloc::format!(
"Got CAM from {station_id} at {lat_deg:.3}°N, {lon_deg:.3}°E, speed {:.2} km/h",
obu.speed.speed_value.as_kmh()
)
};
Some(result)
}
HighFrequencyContainer::rsuContainerHighFrequency(rsu) => Some(alloc::format!(
"Got RSU from {} at {:.3}°N, {:.3}°E, {} protected zones",
etsi.header.station_id.0,
etsi.cam
.cam_parameters
.basic_container
.reference_position
.latitude
.as_deg(),
etsi.cam
.cam_parameters
.basic_container
.reference_position
.longitude
.as_deg(),
rsu.protected_communication_zones_rsu
.as_ref()
.map(|d| d.0.len())
.unwrap_or_default()
)),
_ => {
// enum is non-exhaustive, so we need a default case
// but this should never be reached in practical applications
None
}
}
}

46
src/rx/denm.rs Normal file
View file

@ -0,0 +1,46 @@
//! C-ITS DENM Evaluation
use c_its_parser::standards::denm_2_2_1::denm_pdu_description;
/// Prints a DENM as one line (unless it's a termination)
pub fn pretty_print(etsi: &denm_pdu_description::DENM) -> Option<alloc::string::String> {
let mgmt = &etsi.denm.management;
if mgmt.termination.is_some() {
return None;
}
let result = if let (Some(sit), Some(loc)) = (&etsi.denm.situation, &etsi.denm.location) {
// let timestamp: chrono::DateTime<chrono::Utc> = mgmt.reference_time.clone().into();
let end_time = chrono::DateTime::<chrono::Utc>::from(mgmt.reference_time.clone())
+ chrono::Duration::seconds(mgmt.validity_duration.0.into());
let station_id = &mgmt.action_id.originating_station_id.0;
let seq_num = mgmt.action_id.sequence_number.0;
let lat_deg = mgmt.event_position.latitude.as_deg();
let lon_deg = mgmt.event_position.longitude.as_deg();
let heading = loc
.event_position_heading
.as_ref()
.map(|v| v.value.as_deg());
// let direction = mgmt.traffic_direction;
let (cc, scc) = sit.event_type.cc_and_scc.to_u8_tuple();
if let Some(hdg) = heading {
alloc::format!(
"DENN: {station_id}/{seq_num} CC {cc}/{scc} at {lat_deg:.3}°N, {lon_deg:.3}°E, hdg {hdg:.1}° until {end_time:?}"
)
} else {
alloc::format!(
"DENN: {station_id}/{seq_num} CC {cc}/{scc} at {lat_deg:.3}°N, {lon_deg:.3}°E until {end_time:?}"
)
}
} else {
alloc::format!("DENM: One of situation or location container not available")
};
Some(result)
}