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, is_used_system_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 ElementName::LinEventTriggeredFrame => Ok(Self::Lin(LinEventTriggeredFrame::try_from(element)?.into())),
132 ElementName::LinSporadicFrame => Ok(Self::Lin(LinSporadicFrame::try_from(element)?.into())),
133 ElementName::LinUnconditionalFrame => Ok(Self::Lin(LinUnconditionalFrame::try_from(element)?.into())),
134 _ => Err(AutosarAbstractionError::ConversionError {
135 element,
136 dest: "Frame".to_string(),
137 }),
138 }
139 }
140}
141
142impl Frame {
143 fn map_pdu_internal(
144 &self,
145 pdu: &Pdu,
146 start_position: u32,
147 byte_order: ByteOrder,
148 update_bit: Option<u32>,
149 ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
150 let pdu_name = pdu
151 .name()
152 .ok_or(AutosarAbstractionError::InvalidParameter("invalid PDU".to_string()))?;
153 for mapping in self.mapped_pdus() {
154 if let Some(mapped_byte_order) = mapping.byte_order()
156 && mapped_byte_order != byte_order
157 {
158 return Err(AutosarAbstractionError::InvalidParameter(
159 "All mapped PDUs must use the same byte order".to_string(),
160 ));
161 }
162
163 }
165
166 for ft in self.frame_triggerings() {
168 let pt = ft.add_pdu_triggering(pdu)?;
169 for frame_port in ft.frame_ports() {
170 if let (Ok(ecu), Some(direction)) = (frame_port.ecu(), frame_port.communication_direction()) {
171 pt.create_pdu_port(&ecu, direction)?;
172 }
173 }
174 }
175
176 let model = self.element().model()?;
178 let base_path = self.element().path()?;
179 let name = make_unique_name(&model, &base_path, &pdu_name);
180
181 let mappings = self
182 .element()
183 .get_or_create_sub_element(ElementName::PduToFrameMappings)?;
184
185 if let Pdu::MultiplexedIPdu(mpdu) = pdu {
187 if let Some(static_ipdu) = mpdu.static_part() {
188 mpdu.update_pdu_triggerings(None, &static_ipdu)?;
189 }
190 for dynamic_part in mpdu.dynamic_part_alternatives() {
191 if let Some(dynamic_ipdu) = dynamic_part.ipdu() {
192 mpdu.update_pdu_triggerings(None, &dynamic_ipdu)?;
193 }
194 }
195 }
196
197 PduToFrameMapping::new(&name, &mappings, pdu, start_position, byte_order, update_bit)
198 }
199}
200
201pub trait AbstractFrameTriggering: AbstractionElement {
205 type FrameType: AbstractFrame;
207
208 #[must_use]
210 fn frame(&self) -> Option<Self::FrameType> {
211 Self::FrameType::try_from(
212 self.element()
213 .get_sub_element(ElementName::FrameRef)?
214 .get_reference_target()
215 .ok()?,
216 )
217 .ok()
218 }
219
220 fn frame_ports(&self) -> impl Iterator<Item = FramePort> + Send + use<Self> {
247 self.element()
248 .get_sub_element(ElementName::FramePortRefs)
249 .into_iter()
250 .flat_map(|elem| elem.sub_elements())
251 .filter_map(|fpref| {
252 fpref
253 .get_reference_target()
254 .ok()
255 .and_then(|fp| FramePort::try_from(fp).ok())
256 })
257 }
258
259 fn pdu_triggerings(&self) -> impl Iterator<Item = PduTriggering> + Send + use<Self> {
261 self.element()
262 .get_sub_element(ElementName::PduTriggerings)
263 .into_iter()
264 .flat_map(|elem| elem.sub_elements())
265 .filter_map(|element| {
266 element
267 .get_sub_element(ElementName::PduTriggeringRef)
268 .and_then(|ptr| ptr.get_reference_target().ok())
269 .and_then(|ptelem| PduTriggering::try_from(ptelem).ok())
270 })
271 }
272
273 fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
275 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
276 PhysicalChannel::try_from(channel_elem)
277 }
278}
279
280#[derive(Debug, Clone, PartialEq, Eq)]
284#[non_exhaustive]
285pub enum FrameTriggering {
286 Can(CanFrameTriggering),
288 Flexray(FlexrayFrameTriggering),
290 Lin(LinFrameTriggering),
292}
293
294impl AbstractionElement for FrameTriggering {
295 fn element(&self) -> &autosar_data::Element {
296 match self {
297 Self::Can(cft) => cft.element(),
298 Self::Flexray(fft) => fft.element(),
299 Self::Lin(lft) => lft.element(),
300 }
301 }
302}
303
304impl IdentifiableAbstractionElement for FrameTriggering {}
305
306impl AbstractFrameTriggering for FrameTriggering {
307 type FrameType = Frame;
308}
309
310impl TryFrom<Element> for FrameTriggering {
311 type Error = AutosarAbstractionError;
312
313 fn try_from(element: Element) -> Result<Self, Self::Error> {
314 match element.element_name() {
315 ElementName::CanFrameTriggering => Ok(CanFrameTriggering::try_from(element)?.into()),
316 ElementName::FlexrayFrameTriggering => Ok(FlexrayFrameTriggering::try_from(element)?.into()),
317 ElementName::LinFrameTriggering => Ok(LinFrameTriggering::try_from(element)?.into()),
318 _ => Err(AutosarAbstractionError::ConversionError {
319 element,
320 dest: "FrameTriggering".to_string(),
321 }),
322 }
323 }
324}
325
326impl FrameTriggering {
327 pub fn connect_to_ecu(
331 &self,
332 ecu: &EcuInstance,
333 direction: CommunicationDirection,
334 ) -> Result<FramePort, AutosarAbstractionError> {
335 for frame_port in self.frame_ports() {
336 if let (Ok(existing_ecu), Some(existing_direction)) =
337 (frame_port.ecu(), frame_port.communication_direction())
338 && existing_ecu == *ecu
339 && existing_direction == direction
340 {
341 return Ok(frame_port);
342 }
343 }
344
345 let channel = self.physical_channel()?;
346 let connector = channel
347 .ecu_connector(ecu)
348 .ok_or(AutosarAbstractionError::InvalidParameter(
349 "The ECU is not connected to the channel".to_string(),
350 ))?;
351
352 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
353 let suffix = match direction {
354 CommunicationDirection::In => "Rx",
355 CommunicationDirection::Out => "Tx",
356 };
357 let port_name = format!("{name}_{suffix}",);
358 let fp_elem = connector
359 .element()
360 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
361 .create_named_sub_element(ElementName::FramePort, &port_name)?;
362 fp_elem
363 .create_sub_element(ElementName::CommunicationDirection)?
364 .set_character_data::<EnumItem>(direction.into())?;
365
366 self.element()
367 .get_or_create_sub_element(ElementName::FramePortRefs)?
368 .create_sub_element(ElementName::FramePortRef)?
369 .set_reference_target(&fp_elem)?;
370
371 for pt in self.pdu_triggerings() {
372 pt.create_pdu_port(ecu, direction)?;
373 }
374
375 Ok(FramePort(fp_elem))
376 }
377
378 fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
379 let channel = self.physical_channel()?;
380 let pt = PduTriggering::new(pdu, &channel)?;
381 let triggerings = self.element().get_or_create_sub_element(ElementName::PduTriggerings)?;
382 triggerings
383 .create_sub_element(ElementName::PduTriggeringRefConditional)?
384 .create_sub_element(ElementName::PduTriggeringRef)?
385 .set_reference_target(pt.element())?;
386
387 for frame_port in self.frame_ports() {
388 if let (Ok(ecu), Some(direction)) = (frame_port.ecu(), frame_port.communication_direction()) {
389 pt.create_pdu_port(&ecu, direction)?;
390 }
391 }
392
393 Ok(pt)
394 }
395
396 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
398 match self {
399 Self::Can(cft) => cft.remove(deep),
400 Self::Flexray(fft) => fft.remove(deep),
401 Self::Lin(lft) => lft.remove(deep),
402 }
403 }
404}
405
406#[derive(Debug, Clone, PartialEq, Eq, Hash)]
410pub struct PduToFrameMapping(Element);
411abstraction_element!(PduToFrameMapping, PduToFrameMapping);
412impl IdentifiableAbstractionElement for PduToFrameMapping {}
413
414impl PduToFrameMapping {
415 fn new(
416 name: &str,
417 mappings: &Element,
418 pdu: &Pdu,
419 start_position: u32,
420 byte_order: ByteOrder,
421 update_bit: Option<u32>,
422 ) -> Result<Self, AutosarAbstractionError> {
423 let pdumapping_elem = mappings.create_named_sub_element(ElementName::PduToFrameMapping, name)?;
424 pdumapping_elem
425 .create_sub_element(ElementName::PduRef)?
426 .set_reference_target(pdu.element())?;
427
428 let pdumapping = Self(pdumapping_elem);
429
430 pdumapping.set_byte_order(byte_order)?;
431 pdumapping.set_start_position(start_position)?;
432 pdumapping.set_update_bit(update_bit)?;
433
434 Ok(pdumapping)
435 }
436
437 pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
439 let opt_pdu = self.pdu();
440
441 AbstractionElement::remove(self, deep)?;
442
443 if deep && let Some(pdu) = opt_pdu {
444 if !is_used_system_element(pdu.element()) {
446 pdu.remove(deep)?;
447 }
448 }
449
450 Ok(())
451 }
452
453 #[must_use]
455 pub fn pdu(&self) -> Option<Pdu> {
456 self.element()
457 .get_sub_element(ElementName::PduRef)
458 .and_then(|pduref| pduref.get_reference_target().ok())
459 .and_then(|pdu_elem| Pdu::try_from(pdu_elem).ok())
460 }
461
462 pub fn set_byte_order(&self, byte_order: ByteOrder) -> Result<(), AutosarAbstractionError> {
469 if byte_order == ByteOrder::Opaque {
470 return Err(AutosarAbstractionError::InvalidParameter(
471 "Byte order: opaque is not allowed for PDUs".to_string(),
472 ));
473 }
474 self.element()
475 .get_or_create_sub_element(ElementName::PackingByteOrder)?
476 .set_character_data::<EnumItem>(byte_order.into())?;
477 Ok(())
478 }
479
480 #[must_use]
485 pub fn byte_order(&self) -> Option<ByteOrder> {
486 self.element()
487 .get_sub_element(ElementName::PackingByteOrder)
488 .and_then(|pbo| pbo.character_data())
489 .and_then(|cdata| cdata.enum_value())
490 .and_then(|enumval| enumval.try_into().ok())
491 }
492
493 pub fn set_start_position(&self, start_position: u32) -> Result<(), AutosarAbstractionError> {
502 if (self.byte_order() == Some(ByteOrder::MostSignificantByteFirst) && (start_position % 8 != 7))
503 || (self.byte_order() == Some(ByteOrder::MostSignificantByteLast) && !start_position.is_multiple_of(8))
504 {
505 return Err(AutosarAbstractionError::InvalidParameter(
506 "PDUs must be byte-aligned".to_string(),
507 ));
508 }
509 self.element()
510 .get_or_create_sub_element(ElementName::StartPosition)?
511 .set_character_data(u64::from(start_position))?;
512 Ok(())
513 }
514
515 #[must_use]
521 pub fn start_position(&self) -> Option<u32> {
522 self.element()
523 .get_sub_element(ElementName::StartPosition)
524 .and_then(|pbo| pbo.character_data())
525 .and_then(|cdata| cdata.parse_integer())
526 }
527
528 pub fn set_update_bit(&self, update_bit: Option<u32>) -> Result<(), AutosarAbstractionError> {
530 if let Some(update_bit) = update_bit {
531 self.element()
532 .get_or_create_sub_element(ElementName::UpdateIndicationBitPosition)?
533 .set_character_data(u64::from(update_bit))?;
534 } else {
535 let _ = self
536 .element()
537 .remove_sub_element_kind(ElementName::UpdateIndicationBitPosition);
538 }
539 Ok(())
540 }
541
542 #[must_use]
544 pub fn update_bit(&self) -> Option<u32> {
545 self.element()
546 .get_sub_element(ElementName::UpdateIndicationBitPosition)
547 .and_then(|pbo| pbo.character_data())
548 .and_then(|cdata| cdata.parse_integer())
549 }
550}
551
552#[derive(Debug, Clone, PartialEq, Eq, Hash)]
556pub struct FramePort(Element);
557abstraction_element!(FramePort, FramePort);
558impl IdentifiableAbstractionElement for FramePort {}
559
560impl FramePort {
561 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
563 let comm_connector_elem = self.element().named_parent()?.unwrap();
564 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
565 EcuInstance::try_from(ecu_elem)
566 }
567
568 pub fn set_communication_direction(
570 &self,
571 direction: CommunicationDirection,
572 ) -> Result<(), AutosarAbstractionError> {
573 self.element()
574 .get_or_create_sub_element(ElementName::CommunicationDirection)?
575 .set_character_data::<EnumItem>(direction.into())?;
576 Ok(())
577 }
578
579 #[must_use]
581 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
582 self.element()
583 .get_sub_element(ElementName::CommunicationDirection)?
584 .character_data()?
585 .enum_value()?
586 .try_into()
587 .ok()
588 }
589}
590
591#[cfg(test)]
594mod test {
595 use super::*;
596 use crate::{AutosarModelAbstraction, SystemCategory};
597
598 #[test]
599 fn frame() {
600 let model = AutosarModelAbstraction::create("filename", autosar_data::AutosarVersion::LATEST);
601 let package = model.get_or_create_package("/package").unwrap();
602 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
603
604 let can_frame = system.create_can_frame("CanFrame", &package, 8).unwrap();
605 let flexray_frame = system.create_flexray_frame("FlexrayFrame", &package, 32).unwrap();
606
607 let frame_1 = Frame::try_from(can_frame.element().clone()).unwrap();
608 assert_eq!(frame_1.element().element_name(), autosar_data::ElementName::CanFrame);
609 let frame_2 = Frame::try_from(flexray_frame.element().clone()).unwrap();
610 assert_eq!(
611 frame_2.element().element_name(),
612 autosar_data::ElementName::FlexrayFrame
613 );
614
615 let err = Frame::try_from(model.root_element().clone());
616 assert!(err.is_err());
617 }
618}