autosar_data_abstraction/communication/frame/
mod.rs1use crate::communication::{
2 AbstractPdu, AbstractPhysicalChannel, CommunicationDirection, Pdu, PduTriggering, PhysicalChannel,
3};
4use crate::{
5 AbstractionElement, AutosarAbstractionError, ByteOrder, EcuInstance, IdentifiableAbstractionElement,
6 abstraction_element, make_unique_name,
7};
8
9mod can;
10mod flexray;
11use autosar_data::{AutosarDataError, Element, ElementName, EnumItem};
14pub use can::*;
15pub use flexray::*;
16
17pub trait AbstractFrame: AbstractionElement {
21 type FrameTriggeringType: AbstractFrameTriggering;
23
24 fn mapped_pdus(&self) -> impl Iterator<Item = PduToFrameMapping> + Send + use<Self> {
26 self.element()
27 .get_sub_element(ElementName::PduToFrameMappings)
28 .into_iter()
29 .flat_map(|elem| elem.sub_elements())
30 .filter_map(|elem| PduToFrameMapping::try_from(elem).ok())
31 }
32
33 fn frame_triggerings(&self) -> Vec<Self::FrameTriggeringType>;
35
36 fn map_pdu<T: AbstractPdu>(
38 &self,
39 gen_pdu: &T,
40 start_position: u32,
41 byte_order: ByteOrder,
42 update_bit: Option<u32>,
43 ) -> Result<PduToFrameMapping, AutosarAbstractionError>;
44
45 fn set_length(&self, length: u32) -> Result<(), AutosarAbstractionError> {
47 self.element()
48 .get_or_create_sub_element(ElementName::FrameLength)?
49 .set_character_data(u64::from(length))?;
50 Ok(())
51 }
52
53 fn length(&self) -> Option<u32> {
55 self.element()
56 .get_sub_element(ElementName::FrameLength)
57 .and_then(|elem| elem.character_data())
58 .and_then(|cdata| cdata.parse_integer())
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
66#[non_exhaustive]
67pub enum Frame {
68 Can(CanFrame),
70 Flexray(FlexrayFrame),
72}
73
74impl AbstractionElement for Frame {
75 fn element(&self) -> &autosar_data::Element {
76 match self {
77 Self::Can(cf) => cf.element(),
78 Self::Flexray(ff) => ff.element(),
79 }
80 }
81}
82
83impl IdentifiableAbstractionElement for Frame {}
84
85impl AbstractFrame for Frame {
86 type FrameTriggeringType = FrameTriggering;
87
88 fn frame_triggerings(&self) -> Vec<FrameTriggering> {
89 let model_result = self.element().model();
90 let path_result = self.element().path();
91 if let (Ok(model), Ok(path)) = (model_result, path_result) {
92 model
93 .get_references_to(&path)
94 .iter()
95 .filter_map(|e| {
96 e.upgrade()
97 .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
98 .and_then(|elem| FrameTriggering::try_from(elem).ok())
99 })
100 .collect()
101 } else {
102 vec![]
103 }
104 }
105
106 fn map_pdu<T: AbstractPdu>(
108 &self,
109 gen_pdu: &T,
110 start_position: u32,
111 byte_order: ByteOrder,
112 update_bit: Option<u32>,
113 ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
114 let pdu = gen_pdu.clone().into();
115 Self::map_pdu_internal(self, &pdu, start_position, byte_order, update_bit)
116 }
117}
118
119impl TryFrom<Element> for Frame {
120 type Error = AutosarAbstractionError;
121
122 fn try_from(element: Element) -> Result<Self, Self::Error> {
123 match element.element_name() {
124 ElementName::CanFrame => Ok(Self::Can(CanFrame::try_from(element)?)),
125 ElementName::FlexrayFrame => Ok(Self::Flexray(FlexrayFrame::try_from(element)?)),
126 _ => Err(AutosarAbstractionError::ConversionError {
127 element,
128 dest: "Frame".to_string(),
129 }),
130 }
131 }
132}
133
134impl Frame {
135 fn map_pdu_internal(
136 &self,
137 pdu: &Pdu,
138 start_position: u32,
139 byte_order: ByteOrder,
140 update_bit: Option<u32>,
141 ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
142 let pdu_name = pdu
143 .name()
144 .ok_or(AutosarAbstractionError::InvalidParameter("invalid PDU".to_string()))?;
145 for mapping in self.mapped_pdus() {
146 if let Some(mapped_byte_order) = mapping.byte_order() {
148 if mapped_byte_order != byte_order {
149 return Err(AutosarAbstractionError::InvalidParameter(
150 "All mapped PDUs must use the same byte order".to_string(),
151 ));
152 }
153 }
154
155 }
157
158 for ft in self.frame_triggerings() {
160 let pt = ft.add_pdu_triggering(pdu)?;
161 for frame_port in ft.frame_ports() {
162 if let (Ok(ecu), Some(direction)) = (frame_port.ecu(), frame_port.communication_direction()) {
163 pt.create_pdu_port(&ecu, direction)?;
164 }
165 }
166 }
167
168 let model = self.element().model()?;
170 let base_path = self.element().path()?;
171 let name = make_unique_name(&model, &base_path, &pdu_name);
172
173 let mappings = self
174 .element()
175 .get_or_create_sub_element(ElementName::PduToFrameMappings)?;
176
177 PduToFrameMapping::new(&name, &mappings, pdu, start_position, byte_order, update_bit)
178 }
179}
180
181pub trait AbstractFrameTriggering: AbstractionElement {
185 type FrameType: AbstractFrame;
187
188 #[must_use]
190 fn frame(&self) -> Option<Self::FrameType> {
191 Self::FrameType::try_from(
192 self.element()
193 .get_sub_element(ElementName::FrameRef)?
194 .get_reference_target()
195 .ok()?,
196 )
197 .ok()
198 }
199
200 fn frame_ports(&self) -> impl Iterator<Item = FramePort> + Send + use<Self> {
227 self.element()
228 .get_sub_element(ElementName::FramePortRefs)
229 .into_iter()
230 .flat_map(|elem| elem.sub_elements())
231 .filter_map(|fpref| {
232 fpref
233 .get_reference_target()
234 .ok()
235 .and_then(|fp| FramePort::try_from(fp).ok())
236 })
237 }
238
239 fn pdu_triggerings(&self) -> impl Iterator<Item = PduTriggering> + Send + use<Self> {
241 self.element()
242 .get_sub_element(ElementName::PduTriggerings)
243 .into_iter()
244 .flat_map(|elem| elem.sub_elements())
245 .filter_map(|element| {
246 element
247 .get_sub_element(ElementName::PduTriggeringRef)
248 .and_then(|ptr| ptr.get_reference_target().ok())
249 .and_then(|ptelem| PduTriggering::try_from(ptelem).ok())
250 })
251 }
252
253 fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
255 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
256 PhysicalChannel::try_from(channel_elem)
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq)]
264#[non_exhaustive]
265pub enum FrameTriggering {
266 Can(CanFrameTriggering),
268 Flexray(FlexrayFrameTriggering),
270}
271
272impl AbstractionElement for FrameTriggering {
273 fn element(&self) -> &autosar_data::Element {
274 match self {
275 Self::Can(cft) => cft.element(),
276 Self::Flexray(fft) => fft.element(),
277 }
278 }
279}
280
281impl IdentifiableAbstractionElement for FrameTriggering {}
282
283impl AbstractFrameTriggering for FrameTriggering {
284 type FrameType = Frame;
285}
286
287impl TryFrom<Element> for FrameTriggering {
288 type Error = AutosarAbstractionError;
289
290 fn try_from(element: Element) -> Result<Self, Self::Error> {
291 match element.element_name() {
292 ElementName::CanFrameTriggering => Ok(CanFrameTriggering::try_from(element)?.into()),
293 ElementName::FlexrayFrameTriggering => Ok(FlexrayFrameTriggering::try_from(element)?.into()),
294 _ => Err(AutosarAbstractionError::ConversionError {
295 element,
296 dest: "FrameTriggering".to_string(),
297 }),
298 }
299 }
300}
301
302impl FrameTriggering {
303 pub fn connect_to_ecu(
307 &self,
308 ecu: &EcuInstance,
309 direction: CommunicationDirection,
310 ) -> Result<FramePort, AutosarAbstractionError> {
311 for frame_port in self.frame_ports() {
312 if let (Ok(existing_ecu), Some(existing_direction)) =
313 (frame_port.ecu(), frame_port.communication_direction())
314 {
315 if existing_ecu == *ecu && existing_direction == direction {
316 return Ok(frame_port);
317 }
318 }
319 }
320
321 let channel = self.physical_channel()?;
322 let connector = channel
323 .ecu_connector(ecu)
324 .ok_or(AutosarAbstractionError::InvalidParameter(
325 "The ECU is not connected to the channel".to_string(),
326 ))?;
327
328 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
329 let suffix = match direction {
330 CommunicationDirection::In => "Rx",
331 CommunicationDirection::Out => "Tx",
332 };
333 let port_name = format!("{name}_{suffix}",);
334 let fp_elem = connector
335 .element()
336 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
337 .create_named_sub_element(ElementName::FramePort, &port_name)?;
338 fp_elem
339 .create_sub_element(ElementName::CommunicationDirection)?
340 .set_character_data::<EnumItem>(direction.into())?;
341
342 self.element()
343 .get_or_create_sub_element(ElementName::FramePortRefs)?
344 .create_sub_element(ElementName::FramePortRef)?
345 .set_reference_target(&fp_elem)?;
346
347 for pt in self.pdu_triggerings() {
348 pt.create_pdu_port(ecu, direction)?;
349 }
350
351 Ok(FramePort(fp_elem))
352 }
353
354 fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
355 let channel = self.physical_channel()?;
356 let pt = PduTriggering::new(pdu, &channel)?;
357 let triggerings = self.element().get_or_create_sub_element(ElementName::PduTriggerings)?;
358 triggerings
359 .create_sub_element(ElementName::PduTriggeringRefConditional)?
360 .create_sub_element(ElementName::PduTriggeringRef)?
361 .set_reference_target(pt.element())?;
362
363 for frame_port in self.frame_ports() {
364 if let (Ok(ecu), Some(direction)) = (frame_port.ecu(), frame_port.communication_direction()) {
365 pt.create_pdu_port(&ecu, direction)?;
366 }
367 }
368
369 Ok(pt)
370 }
371}
372
373#[derive(Debug, Clone, PartialEq, Eq, Hash)]
377pub struct PduToFrameMapping(Element);
378abstraction_element!(PduToFrameMapping, PduToFrameMapping);
379impl IdentifiableAbstractionElement for PduToFrameMapping {}
380
381impl PduToFrameMapping {
382 fn new(
383 name: &str,
384 mappings: &Element,
385 pdu: &Pdu,
386 start_position: u32,
387 byte_order: ByteOrder,
388 update_bit: Option<u32>,
389 ) -> Result<Self, AutosarAbstractionError> {
390 let pdumapping_elem = mappings.create_named_sub_element(ElementName::PduToFrameMapping, name)?;
391 pdumapping_elem
392 .create_sub_element(ElementName::PduRef)?
393 .set_reference_target(pdu.element())?;
394
395 let pdumapping = Self(pdumapping_elem);
396
397 pdumapping.set_byte_order(byte_order)?;
398 pdumapping.set_start_position(start_position)?;
399 pdumapping.set_update_bit(update_bit)?;
400
401 Ok(pdumapping)
402 }
403
404 #[must_use]
406 pub fn pdu(&self) -> Option<Pdu> {
407 self.element()
408 .get_sub_element(ElementName::PduRef)
409 .and_then(|pduref| pduref.get_reference_target().ok())
410 .and_then(|pdu_elem| Pdu::try_from(pdu_elem).ok())
411 }
412
413 pub fn set_byte_order(&self, byte_order: ByteOrder) -> Result<(), AutosarAbstractionError> {
420 if byte_order == ByteOrder::Opaque {
421 return Err(AutosarAbstractionError::InvalidParameter(
422 "Byte order: opaque is not allowed for PDUs".to_string(),
423 ));
424 }
425 self.element()
426 .get_or_create_sub_element(ElementName::PackingByteOrder)?
427 .set_character_data::<EnumItem>(byte_order.into())?;
428 Ok(())
429 }
430
431 #[must_use]
436 pub fn byte_order(&self) -> Option<ByteOrder> {
437 self.element()
438 .get_sub_element(ElementName::PackingByteOrder)
439 .and_then(|pbo| pbo.character_data())
440 .and_then(|cdata| cdata.enum_value())
441 .and_then(|enumval| enumval.try_into().ok())
442 }
443
444 pub fn set_start_position(&self, start_position: u32) -> Result<(), AutosarAbstractionError> {
453 if (self.byte_order() == Some(ByteOrder::MostSignificantByteFirst) && (start_position % 8 != 7))
454 || (self.byte_order() == Some(ByteOrder::MostSignificantByteLast) && (start_position % 8 != 0))
455 {
456 return Err(AutosarAbstractionError::InvalidParameter(
457 "PDUs must be byte-aligned".to_string(),
458 ));
459 }
460 self.element()
461 .get_or_create_sub_element(ElementName::StartPosition)?
462 .set_character_data(u64::from(start_position))?;
463 Ok(())
464 }
465
466 #[must_use]
472 pub fn start_position(&self) -> Option<u32> {
473 self.element()
474 .get_sub_element(ElementName::StartPosition)
475 .and_then(|pbo| pbo.character_data())
476 .and_then(|cdata| cdata.parse_integer())
477 }
478
479 pub fn set_update_bit(&self, update_bit: Option<u32>) -> Result<(), AutosarAbstractionError> {
481 if let Some(update_bit) = update_bit {
482 self.element()
483 .get_or_create_sub_element(ElementName::UpdateIndicationBitPosition)?
484 .set_character_data(u64::from(update_bit))?;
485 } else {
486 let _ = self
487 .element()
488 .remove_sub_element_kind(ElementName::UpdateIndicationBitPosition);
489 }
490 Ok(())
491 }
492
493 #[must_use]
495 pub fn update_bit(&self) -> Option<u32> {
496 self.element()
497 .get_sub_element(ElementName::UpdateIndicationBitPosition)
498 .and_then(|pbo| pbo.character_data())
499 .and_then(|cdata| cdata.parse_integer())
500 }
501}
502
503#[derive(Debug, Clone, PartialEq, Eq, Hash)]
507pub struct FramePort(Element);
508abstraction_element!(FramePort, FramePort);
509impl IdentifiableAbstractionElement for FramePort {}
510
511impl FramePort {
512 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
514 let comm_connector_elem = self.element().named_parent()?.unwrap();
515 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
516 EcuInstance::try_from(ecu_elem)
517 }
518
519 pub fn set_communication_direction(
521 &self,
522 direction: CommunicationDirection,
523 ) -> Result<(), AutosarAbstractionError> {
524 self.element()
525 .get_or_create_sub_element(ElementName::CommunicationDirection)?
526 .set_character_data::<EnumItem>(direction.into())?;
527 Ok(())
528 }
529
530 #[must_use]
532 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
533 self.element()
534 .get_sub_element(ElementName::CommunicationDirection)?
535 .character_data()?
536 .enum_value()?
537 .try_into()
538 .ok()
539 }
540}
541
542#[cfg(test)]
545mod test {
546 use crate::{AutosarModelAbstraction, SystemCategory};
547
548 use super::*;
549
550 #[test]
551 fn frame() {
552 let model = AutosarModelAbstraction::create("filename", autosar_data::AutosarVersion::LATEST);
553 let package = model.get_or_create_package("/package").unwrap();
554 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
555
556 let can_frame = system.create_can_frame("CanFrame", &package, 8).unwrap();
557 let flexray_frame = system.create_flexray_frame("FlexrayFrame", &package, 32).unwrap();
558
559 let frame_1 = Frame::try_from(can_frame.element().clone()).unwrap();
560 assert_eq!(frame_1.element().element_name(), autosar_data::ElementName::CanFrame);
561 let frame_2 = Frame::try_from(flexray_frame.element().clone()).unwrap();
562 assert_eq!(
563 frame_2.element().element_name(),
564 autosar_data::ElementName::FlexrayFrame
565 );
566
567 let err = Frame::try_from(model.root_element().clone());
568 assert!(err.is_err());
569 }
570}