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 && mapped_byte_order != byte_order
154 {
155 return Err(AutosarAbstractionError::InvalidParameter(
156 "All mapped PDUs must use the same byte order".to_string(),
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 if let Pdu::MultiplexedIPdu(mpdu) = pdu {
184 if let Some(static_ipdu) = mpdu.static_part() {
185 mpdu.update_pdu_triggerings(None, &static_ipdu)?;
186 }
187 for dynamic_part in mpdu.dynamic_part_alternatives() {
188 if let Some(dynamic_ipdu) = dynamic_part.ipdu() {
189 mpdu.update_pdu_triggerings(None, &dynamic_ipdu)?;
190 }
191 }
192 }
193
194 PduToFrameMapping::new(&name, &mappings, pdu, start_position, byte_order, update_bit)
195 }
196}
197
198pub trait AbstractFrameTriggering: AbstractionElement {
202 type FrameType: AbstractFrame;
204
205 #[must_use]
207 fn frame(&self) -> Option<Self::FrameType> {
208 Self::FrameType::try_from(
209 self.element()
210 .get_sub_element(ElementName::FrameRef)?
211 .get_reference_target()
212 .ok()?,
213 )
214 .ok()
215 }
216
217 fn frame_ports(&self) -> impl Iterator<Item = FramePort> + Send + use<Self> {
244 self.element()
245 .get_sub_element(ElementName::FramePortRefs)
246 .into_iter()
247 .flat_map(|elem| elem.sub_elements())
248 .filter_map(|fpref| {
249 fpref
250 .get_reference_target()
251 .ok()
252 .and_then(|fp| FramePort::try_from(fp).ok())
253 })
254 }
255
256 fn pdu_triggerings(&self) -> impl Iterator<Item = PduTriggering> + Send + use<Self> {
258 self.element()
259 .get_sub_element(ElementName::PduTriggerings)
260 .into_iter()
261 .flat_map(|elem| elem.sub_elements())
262 .filter_map(|element| {
263 element
264 .get_sub_element(ElementName::PduTriggeringRef)
265 .and_then(|ptr| ptr.get_reference_target().ok())
266 .and_then(|ptelem| PduTriggering::try_from(ptelem).ok())
267 })
268 }
269
270 fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
272 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
273 PhysicalChannel::try_from(channel_elem)
274 }
275}
276
277#[derive(Debug, Clone, PartialEq, Eq)]
281#[non_exhaustive]
282pub enum FrameTriggering {
283 Can(CanFrameTriggering),
285 Flexray(FlexrayFrameTriggering),
287 Lin(LinFrameTriggering),
289}
290
291impl AbstractionElement for FrameTriggering {
292 fn element(&self) -> &autosar_data::Element {
293 match self {
294 Self::Can(cft) => cft.element(),
295 Self::Flexray(fft) => fft.element(),
296 Self::Lin(lft) => lft.element(),
297 }
298 }
299}
300
301impl IdentifiableAbstractionElement for FrameTriggering {}
302
303impl AbstractFrameTriggering for FrameTriggering {
304 type FrameType = Frame;
305}
306
307impl TryFrom<Element> for FrameTriggering {
308 type Error = AutosarAbstractionError;
309
310 fn try_from(element: Element) -> Result<Self, Self::Error> {
311 match element.element_name() {
312 ElementName::CanFrameTriggering => Ok(CanFrameTriggering::try_from(element)?.into()),
313 ElementName::FlexrayFrameTriggering => Ok(FlexrayFrameTriggering::try_from(element)?.into()),
314 ElementName::LinFrameTriggering => Ok(LinFrameTriggering::try_from(element)?.into()),
315 _ => Err(AutosarAbstractionError::ConversionError {
316 element,
317 dest: "FrameTriggering".to_string(),
318 }),
319 }
320 }
321}
322
323impl FrameTriggering {
324 pub fn connect_to_ecu(
328 &self,
329 ecu: &EcuInstance,
330 direction: CommunicationDirection,
331 ) -> Result<FramePort, AutosarAbstractionError> {
332 for frame_port in self.frame_ports() {
333 if let (Ok(existing_ecu), Some(existing_direction)) =
334 (frame_port.ecu(), frame_port.communication_direction())
335 && existing_ecu == *ecu
336 && existing_direction == direction
337 {
338 return Ok(frame_port);
339 }
340 }
341
342 let channel = self.physical_channel()?;
343 let connector = channel
344 .ecu_connector(ecu)
345 .ok_or(AutosarAbstractionError::InvalidParameter(
346 "The ECU is not connected to the channel".to_string(),
347 ))?;
348
349 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
350 let suffix = match direction {
351 CommunicationDirection::In => "Rx",
352 CommunicationDirection::Out => "Tx",
353 };
354 let port_name = format!("{name}_{suffix}",);
355 let fp_elem = connector
356 .element()
357 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
358 .create_named_sub_element(ElementName::FramePort, &port_name)?;
359 fp_elem
360 .create_sub_element(ElementName::CommunicationDirection)?
361 .set_character_data::<EnumItem>(direction.into())?;
362
363 self.element()
364 .get_or_create_sub_element(ElementName::FramePortRefs)?
365 .create_sub_element(ElementName::FramePortRef)?
366 .set_reference_target(&fp_elem)?;
367
368 for pt in self.pdu_triggerings() {
369 pt.create_pdu_port(ecu, direction)?;
370 }
371
372 Ok(FramePort(fp_elem))
373 }
374
375 fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
376 let channel = self.physical_channel()?;
377 let pt = PduTriggering::new(pdu, &channel)?;
378 let triggerings = self.element().get_or_create_sub_element(ElementName::PduTriggerings)?;
379 triggerings
380 .create_sub_element(ElementName::PduTriggeringRefConditional)?
381 .create_sub_element(ElementName::PduTriggeringRef)?
382 .set_reference_target(pt.element())?;
383
384 for frame_port in self.frame_ports() {
385 if let (Ok(ecu), Some(direction)) = (frame_port.ecu(), frame_port.communication_direction()) {
386 pt.create_pdu_port(&ecu, direction)?;
387 }
388 }
389
390 Ok(pt)
391 }
392}
393
394#[derive(Debug, Clone, PartialEq, Eq, Hash)]
398pub struct PduToFrameMapping(Element);
399abstraction_element!(PduToFrameMapping, PduToFrameMapping);
400impl IdentifiableAbstractionElement for PduToFrameMapping {}
401
402impl PduToFrameMapping {
403 fn new(
404 name: &str,
405 mappings: &Element,
406 pdu: &Pdu,
407 start_position: u32,
408 byte_order: ByteOrder,
409 update_bit: Option<u32>,
410 ) -> Result<Self, AutosarAbstractionError> {
411 let pdumapping_elem = mappings.create_named_sub_element(ElementName::PduToFrameMapping, name)?;
412 pdumapping_elem
413 .create_sub_element(ElementName::PduRef)?
414 .set_reference_target(pdu.element())?;
415
416 let pdumapping = Self(pdumapping_elem);
417
418 pdumapping.set_byte_order(byte_order)?;
419 pdumapping.set_start_position(start_position)?;
420 pdumapping.set_update_bit(update_bit)?;
421
422 Ok(pdumapping)
423 }
424
425 #[must_use]
427 pub fn pdu(&self) -> Option<Pdu> {
428 self.element()
429 .get_sub_element(ElementName::PduRef)
430 .and_then(|pduref| pduref.get_reference_target().ok())
431 .and_then(|pdu_elem| Pdu::try_from(pdu_elem).ok())
432 }
433
434 pub fn set_byte_order(&self, byte_order: ByteOrder) -> Result<(), AutosarAbstractionError> {
441 if byte_order == ByteOrder::Opaque {
442 return Err(AutosarAbstractionError::InvalidParameter(
443 "Byte order: opaque is not allowed for PDUs".to_string(),
444 ));
445 }
446 self.element()
447 .get_or_create_sub_element(ElementName::PackingByteOrder)?
448 .set_character_data::<EnumItem>(byte_order.into())?;
449 Ok(())
450 }
451
452 #[must_use]
457 pub fn byte_order(&self) -> Option<ByteOrder> {
458 self.element()
459 .get_sub_element(ElementName::PackingByteOrder)
460 .and_then(|pbo| pbo.character_data())
461 .and_then(|cdata| cdata.enum_value())
462 .and_then(|enumval| enumval.try_into().ok())
463 }
464
465 pub fn set_start_position(&self, start_position: u32) -> Result<(), AutosarAbstractionError> {
474 if (self.byte_order() == Some(ByteOrder::MostSignificantByteFirst) && (start_position % 8 != 7))
475 || (self.byte_order() == Some(ByteOrder::MostSignificantByteLast) && !start_position.is_multiple_of(8))
476 {
477 return Err(AutosarAbstractionError::InvalidParameter(
478 "PDUs must be byte-aligned".to_string(),
479 ));
480 }
481 self.element()
482 .get_or_create_sub_element(ElementName::StartPosition)?
483 .set_character_data(u64::from(start_position))?;
484 Ok(())
485 }
486
487 #[must_use]
493 pub fn start_position(&self) -> Option<u32> {
494 self.element()
495 .get_sub_element(ElementName::StartPosition)
496 .and_then(|pbo| pbo.character_data())
497 .and_then(|cdata| cdata.parse_integer())
498 }
499
500 pub fn set_update_bit(&self, update_bit: Option<u32>) -> Result<(), AutosarAbstractionError> {
502 if let Some(update_bit) = update_bit {
503 self.element()
504 .get_or_create_sub_element(ElementName::UpdateIndicationBitPosition)?
505 .set_character_data(u64::from(update_bit))?;
506 } else {
507 let _ = self
508 .element()
509 .remove_sub_element_kind(ElementName::UpdateIndicationBitPosition);
510 }
511 Ok(())
512 }
513
514 #[must_use]
516 pub fn update_bit(&self) -> Option<u32> {
517 self.element()
518 .get_sub_element(ElementName::UpdateIndicationBitPosition)
519 .and_then(|pbo| pbo.character_data())
520 .and_then(|cdata| cdata.parse_integer())
521 }
522}
523
524#[derive(Debug, Clone, PartialEq, Eq, Hash)]
528pub struct FramePort(Element);
529abstraction_element!(FramePort, FramePort);
530impl IdentifiableAbstractionElement for FramePort {}
531
532impl FramePort {
533 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
535 let comm_connector_elem = self.element().named_parent()?.unwrap();
536 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
537 EcuInstance::try_from(ecu_elem)
538 }
539
540 pub fn set_communication_direction(
542 &self,
543 direction: CommunicationDirection,
544 ) -> Result<(), AutosarAbstractionError> {
545 self.element()
546 .get_or_create_sub_element(ElementName::CommunicationDirection)?
547 .set_character_data::<EnumItem>(direction.into())?;
548 Ok(())
549 }
550
551 #[must_use]
553 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
554 self.element()
555 .get_sub_element(ElementName::CommunicationDirection)?
556 .character_data()?
557 .enum_value()?
558 .try_into()
559 .ok()
560 }
561}
562
563#[cfg(test)]
566mod test {
567 use super::*;
568 use crate::{AutosarModelAbstraction, SystemCategory};
569
570 #[test]
571 fn frame() {
572 let model = AutosarModelAbstraction::create("filename", autosar_data::AutosarVersion::LATEST);
573 let package = model.get_or_create_package("/package").unwrap();
574 let system = package.create_system("System", SystemCategory::SystemExtract).unwrap();
575
576 let can_frame = system.create_can_frame("CanFrame", &package, 8).unwrap();
577 let flexray_frame = system.create_flexray_frame("FlexrayFrame", &package, 32).unwrap();
578
579 let frame_1 = Frame::try_from(can_frame.element().clone()).unwrap();
580 assert_eq!(frame_1.element().element_name(), autosar_data::ElementName::CanFrame);
581 let frame_2 = Frame::try_from(flexray_frame.element().clone()).unwrap();
582 assert_eq!(
583 frame_2.element().element_name(),
584 autosar_data::ElementName::FlexrayFrame
585 );
586
587 let err = Frame::try_from(model.root_element().clone());
588 assert!(err.is_err());
589 }
590}