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