1use crate::communication::{
2 AbstractPhysicalChannel, CommunicationDirection, ISignal, ISignalGroup, ISignalTriggering, PhysicalChannel,
3};
4use crate::{
5 AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, IdentifiableAbstractionElement,
6 abstraction_element, make_unique_name,
7};
8use autosar_data::{AutosarDataError, Element, ElementName, EnumItem};
9use std::str::FromStr;
10
11mod container_ipdu;
12mod isignal_ipdu;
13mod secured_ipdu;
14
15pub use container_ipdu::*;
16pub use isignal_ipdu::*;
17pub use secured_ipdu::*;
18
19pub trait AbstractPdu: AbstractionElement + Into<Pdu> {
23 fn set_length(&self, length: u32) -> Result<(), AutosarAbstractionError> {
25 self.element()
26 .get_or_create_sub_element(ElementName::Length)?
27 .set_character_data(length as u64)?;
28 Ok(())
29 }
30
31 fn length(&self) -> Option<u32> {
33 self.element()
34 .get_sub_element(ElementName::Length)?
35 .character_data()?
36 .parse_integer()
37 }
38
39 fn pdu_triggerings(&self) -> Vec<PduTriggering> {
41 let model_result = self.element().model();
42 let path_result = self.element().path();
43 if let (Ok(model), Ok(path)) = (model_result, path_result) {
44 model
45 .get_references_to(&path)
46 .iter()
47 .filter_map(|e| {
48 e.upgrade()
49 .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
50 .and_then(|elem| PduTriggering::try_from(elem).ok())
51 })
52 .collect()
53 } else {
54 vec![]
55 }
56 }
57}
58
59pub trait AbstractIpdu: AbstractPdu + Into<IPdu> {
63 fn set_contained_ipdu_props(&self, props: Option<&ContainedIPduProps>) -> Result<(), AutosarAbstractionError> {
67 ContainedIPduProps::set_props(self.element(), props)
68 }
69
70 #[must_use]
72 fn contained_ipdu_props(&self) -> Option<ContainedIPduProps> {
73 ContainedIPduProps::get_props(self.element())
74 }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Hash)]
81pub struct NmPdu(Element);
82abstraction_element!(NmPdu, NmPdu);
83impl IdentifiableAbstractionElement for NmPdu {}
84
85impl NmPdu {
86 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
87 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
88 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::NmPdu, name)?;
89 elem_pdu
90 .create_sub_element(ElementName::Length)?
91 .set_character_data(length.to_string())?;
92
93 Ok(Self(elem_pdu))
94 }
95}
96
97impl AbstractPdu for NmPdu {}
98
99impl From<NmPdu> for Pdu {
100 fn from(value: NmPdu) -> Self {
101 Pdu::NmPdu(value)
102 }
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
109pub struct NPdu(Element);
110abstraction_element!(NPdu, NPdu);
111impl IdentifiableAbstractionElement for NPdu {}
112
113impl NPdu {
114 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
115 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
116 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::NPdu, name)?;
117 elem_pdu
118 .create_sub_element(ElementName::Length)?
119 .set_character_data(length.to_string())?;
120
121 Ok(Self(elem_pdu))
122 }
123}
124
125impl AbstractPdu for NPdu {}
126
127impl AbstractIpdu for NPdu {}
128
129impl From<NPdu> for Pdu {
130 fn from(value: NPdu) -> Self {
131 Pdu::NPdu(value)
132 }
133}
134
135impl From<NPdu> for IPdu {
136 fn from(value: NPdu) -> Self {
137 IPdu::NPdu(value)
138 }
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145pub struct DcmIPdu(Element);
146abstraction_element!(DcmIPdu, DcmIPdu);
147impl IdentifiableAbstractionElement for DcmIPdu {}
148
149impl DcmIPdu {
150 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
151 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
152 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::DcmIPdu, name)?;
153 elem_pdu
154 .create_sub_element(ElementName::Length)?
155 .set_character_data(length.to_string())?;
156
157 Ok(Self(elem_pdu))
158 }
159}
160
161impl AbstractPdu for DcmIPdu {}
162
163impl AbstractIpdu for DcmIPdu {}
164
165impl From<DcmIPdu> for Pdu {
166 fn from(value: DcmIPdu) -> Self {
167 Pdu::DcmIPdu(value)
168 }
169}
170
171impl From<DcmIPdu> for IPdu {
172 fn from(value: DcmIPdu) -> Self {
173 IPdu::DcmIPdu(value)
174 }
175}
176
177#[derive(Debug, Clone, PartialEq, Eq, Hash)]
181pub struct GeneralPurposePdu(Element);
182abstraction_element!(GeneralPurposePdu, GeneralPurposePdu);
183impl IdentifiableAbstractionElement for GeneralPurposePdu {}
184
185impl GeneralPurposePdu {
186 pub(crate) fn new(
187 name: &str,
188 package: &ArPackage,
189 length: u32,
190 category: GeneralPurposePduCategory,
191 ) -> Result<Self, AutosarAbstractionError> {
192 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
193 let pdu_elem = pkg_elements.create_named_sub_element(ElementName::GeneralPurposePdu, name)?;
194 let pdu = Self(pdu_elem);
195
196 pdu.set_length(length)?;
197 pdu.set_category(category)?;
198
199 Ok(pdu)
200 }
201
202 pub fn set_category(&self, category: GeneralPurposePduCategory) -> Result<(), AutosarAbstractionError> {
204 self.element()
205 .get_or_create_sub_element(ElementName::Category)?
206 .set_character_data(category.to_string())?;
207 Ok(())
208 }
209
210 #[must_use]
212 pub fn category(&self) -> Option<GeneralPurposePduCategory> {
213 let category_string = self
214 .element()
215 .get_sub_element(ElementName::Category)?
216 .character_data()?
217 .string_value()?;
218 GeneralPurposePduCategory::from_str(&category_string).ok()
219 }
220}
221
222impl AbstractPdu for GeneralPurposePdu {}
223
224impl From<GeneralPurposePdu> for Pdu {
225 fn from(value: GeneralPurposePdu) -> Self {
226 Pdu::GeneralPurposePdu(value)
227 }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
239pub enum GeneralPurposePduCategory {
240 Sd,
242 GlobalTime,
244 DoIp,
246}
247
248impl std::fmt::Display for GeneralPurposePduCategory {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 match self {
251 GeneralPurposePduCategory::Sd => write!(f, "SD"),
252 GeneralPurposePduCategory::GlobalTime => write!(f, "GLOBAL_TIME"),
253 GeneralPurposePduCategory::DoIp => write!(f, "DOIP"),
254 }
255 }
256}
257
258impl std::str::FromStr for GeneralPurposePduCategory {
259 type Err = AutosarAbstractionError;
260
261 fn from_str(s: &str) -> Result<Self, Self::Err> {
262 match s {
263 "SD" => Ok(GeneralPurposePduCategory::Sd),
264 "GLOBAL_TIME" => Ok(GeneralPurposePduCategory::GlobalTime),
265 "DOIP" => Ok(GeneralPurposePduCategory::DoIp),
266 _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
267 }
268 }
269}
270
271#[derive(Debug, Clone, PartialEq, Eq, Hash)]
275pub struct GeneralPurposeIPdu(Element);
276abstraction_element!(GeneralPurposeIPdu, GeneralPurposeIPdu);
277impl IdentifiableAbstractionElement for GeneralPurposeIPdu {}
278
279impl GeneralPurposeIPdu {
280 pub(crate) fn new(
281 name: &str,
282 package: &ArPackage,
283 length: u32,
284 category: GeneralPurposeIPduCategory,
285 ) -> Result<Self, AutosarAbstractionError> {
286 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
287 let pdu_elem = pkg_elements.create_named_sub_element(ElementName::GeneralPurposeIPdu, name)?;
288 let pdu = Self(pdu_elem);
289
290 pdu.set_length(length)?;
291 pdu.set_category(category)?;
292
293 Ok(pdu)
294 }
295
296 pub fn set_category(&self, category: GeneralPurposeIPduCategory) -> Result<(), AutosarAbstractionError> {
298 self.element()
299 .get_or_create_sub_element(ElementName::Category)?
300 .set_character_data(category.to_string())?;
301 Ok(())
302 }
303
304 #[must_use]
306 pub fn category(&self) -> Option<GeneralPurposeIPduCategory> {
307 let category_string = self
308 .element()
309 .get_sub_element(ElementName::Category)?
310 .character_data()?
311 .string_value()?;
312 GeneralPurposeIPduCategory::from_str(&category_string).ok()
313 }
314}
315
316impl AbstractPdu for GeneralPurposeIPdu {}
317
318impl AbstractIpdu for GeneralPurposeIPdu {}
319
320impl From<GeneralPurposeIPdu> for Pdu {
321 fn from(value: GeneralPurposeIPdu) -> Self {
322 Pdu::GeneralPurposeIPdu(value)
323 }
324}
325
326impl From<GeneralPurposeIPdu> for IPdu {
327 fn from(value: GeneralPurposeIPdu) -> Self {
328 IPdu::GeneralPurposeIPdu(value)
329 }
330}
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
341pub enum GeneralPurposeIPduCategory {
342 Xcp,
344 SomeipSegmentedIpdu,
346 Dlt,
348}
349
350impl std::fmt::Display for GeneralPurposeIPduCategory {
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 match self {
353 GeneralPurposeIPduCategory::Xcp => write!(f, "XCP"),
354 GeneralPurposeIPduCategory::SomeipSegmentedIpdu => write!(f, "SOMEIP_SEGMENTED_IPDU"),
355 GeneralPurposeIPduCategory::Dlt => write!(f, "DLT"),
356 }
357 }
358}
359
360impl std::str::FromStr for GeneralPurposeIPduCategory {
361 type Err = AutosarAbstractionError;
362
363 fn from_str(s: &str) -> Result<Self, Self::Err> {
364 match s {
365 "XCP" => Ok(GeneralPurposeIPduCategory::Xcp),
366 "SOMEIP_SEGMENTED_IPDU" => Ok(GeneralPurposeIPduCategory::SomeipSegmentedIpdu),
367 "DLT" => Ok(GeneralPurposeIPduCategory::Dlt),
368 _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
369 }
370 }
371}
372
373#[derive(Debug, Clone, PartialEq, Eq, Hash)]
377pub struct MultiplexedIPdu(Element);
378abstraction_element!(MultiplexedIPdu, MultiplexedIPdu);
379impl IdentifiableAbstractionElement for MultiplexedIPdu {}
380
381impl MultiplexedIPdu {
382 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
383 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
384 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::MultiplexedIPdu, name)?;
385 elem_pdu
386 .create_sub_element(ElementName::Length)?
387 .set_character_data(length.to_string())?;
388
389 Ok(Self(elem_pdu))
390 }
391}
392
393impl AbstractPdu for MultiplexedIPdu {}
394
395impl AbstractIpdu for MultiplexedIPdu {}
396
397impl From<MultiplexedIPdu> for Pdu {
398 fn from(value: MultiplexedIPdu) -> Self {
399 Pdu::MultiplexedIPdu(value)
400 }
401}
402
403impl From<MultiplexedIPdu> for IPdu {
404 fn from(value: MultiplexedIPdu) -> Self {
405 IPdu::MultiplexedIPdu(value)
406 }
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, Hash)]
413pub enum Pdu {
414 ISignalIPdu(ISignalIPdu),
416 NmPdu(NmPdu),
418 NPdu(NPdu),
420 DcmIPdu(DcmIPdu),
422 GeneralPurposePdu(GeneralPurposePdu),
424 GeneralPurposeIPdu(GeneralPurposeIPdu),
426 ContainerIPdu(ContainerIPdu),
428 SecuredIPdu(SecuredIPdu),
430 MultiplexedIPdu(MultiplexedIPdu),
432}
433
434impl AbstractionElement for Pdu {
435 fn element(&self) -> &Element {
436 match self {
437 Pdu::ISignalIPdu(pdu) => pdu.element(),
438 Pdu::NmPdu(pdu) => pdu.element(),
439 Pdu::NPdu(pdu) => pdu.element(),
440 Pdu::DcmIPdu(pdu) => pdu.element(),
441 Pdu::GeneralPurposePdu(pdu) => pdu.element(),
442 Pdu::GeneralPurposeIPdu(pdu) => pdu.element(),
443 Pdu::ContainerIPdu(pdu) => pdu.element(),
444 Pdu::SecuredIPdu(pdu) => pdu.element(),
445 Pdu::MultiplexedIPdu(pdu) => pdu.element(),
446 }
447 }
448}
449
450impl TryFrom<Element> for Pdu {
451 type Error = AutosarAbstractionError;
452
453 fn try_from(element: Element) -> Result<Self, Self::Error> {
454 match element.element_name() {
455 ElementName::ISignalIPdu => Ok(ISignalIPdu::try_from(element)?.into()),
456 ElementName::NmPdu => Ok(NmPdu::try_from(element)?.into()),
457 ElementName::NPdu => Ok(NPdu::try_from(element)?.into()),
458 ElementName::DcmIPdu => Ok(DcmIPdu::try_from(element)?.into()),
459 ElementName::GeneralPurposePdu => Ok(GeneralPurposePdu::try_from(element)?.into()),
460 ElementName::GeneralPurposeIPdu => Ok(GeneralPurposeIPdu::try_from(element)?.into()),
461 ElementName::ContainerIPdu => Ok(ContainerIPdu::try_from(element)?.into()),
462 ElementName::SecuredIPdu => Ok(SecuredIPdu::try_from(element)?.into()),
463 ElementName::MultiplexedIPdu => Ok(MultiplexedIPdu::try_from(element)?.into()),
464 _ => Err(AutosarAbstractionError::ConversionError {
465 element,
466 dest: "Pdu".to_string(),
467 }),
468 }
469 }
470}
471
472impl IdentifiableAbstractionElement for Pdu {}
473impl AbstractPdu for Pdu {}
474
475#[derive(Debug, Clone, PartialEq, Eq, Hash)]
479pub enum IPdu {
480 ISignalIPdu(ISignalIPdu),
482 NPdu(NPdu),
484 DcmIPdu(DcmIPdu),
486 GeneralPurposeIPdu(GeneralPurposeIPdu),
488 ContainerIPdu(ContainerIPdu),
490 SecuredIPdu(SecuredIPdu),
492 MultiplexedIPdu(MultiplexedIPdu),
494}
495
496impl AbstractionElement for IPdu {
497 fn element(&self) -> &Element {
498 match self {
499 IPdu::ISignalIPdu(pdu) => pdu.element(),
500 IPdu::NPdu(pdu) => pdu.element(),
501 IPdu::DcmIPdu(pdu) => pdu.element(),
502 IPdu::GeneralPurposeIPdu(pdu) => pdu.element(),
503 IPdu::ContainerIPdu(pdu) => pdu.element(),
504 IPdu::SecuredIPdu(pdu) => pdu.element(),
505 IPdu::MultiplexedIPdu(pdu) => pdu.element(),
506 }
507 }
508}
509
510impl TryFrom<Element> for IPdu {
511 type Error = AutosarAbstractionError;
512
513 fn try_from(element: Element) -> Result<Self, Self::Error> {
514 match element.element_name() {
515 ElementName::ISignalIPdu => Ok(IPdu::ISignalIPdu(ISignalIPdu::try_from(element)?)),
516 ElementName::NPdu => Ok(IPdu::NPdu(NPdu::try_from(element)?)),
517 ElementName::DcmIPdu => Ok(IPdu::DcmIPdu(DcmIPdu::try_from(element)?)),
518 ElementName::GeneralPurposeIPdu => Ok(IPdu::GeneralPurposeIPdu(GeneralPurposeIPdu::try_from(element)?)),
519 ElementName::ContainerIPdu => Ok(IPdu::ContainerIPdu(ContainerIPdu::try_from(element)?)),
520 ElementName::SecuredIPdu => Ok(IPdu::SecuredIPdu(SecuredIPdu::try_from(element)?)),
521 ElementName::MultiplexedIPdu => Ok(IPdu::MultiplexedIPdu(MultiplexedIPdu::try_from(element)?)),
522 _ => Err(AutosarAbstractionError::ConversionError {
523 element,
524 dest: "IPdu".to_string(),
525 }),
526 }
527 }
528}
529
530impl From<IPdu> for Pdu {
531 fn from(value: IPdu) -> Self {
532 match value {
533 IPdu::ISignalIPdu(pdu) => Pdu::ISignalIPdu(pdu),
534 IPdu::NPdu(pdu) => Pdu::NPdu(pdu),
535 IPdu::DcmIPdu(pdu) => Pdu::DcmIPdu(pdu),
536 IPdu::GeneralPurposeIPdu(pdu) => Pdu::GeneralPurposeIPdu(pdu),
537 IPdu::ContainerIPdu(pdu) => Pdu::ContainerIPdu(pdu),
538 IPdu::SecuredIPdu(pdu) => Pdu::SecuredIPdu(pdu),
539 IPdu::MultiplexedIPdu(pdu) => Pdu::MultiplexedIPdu(pdu),
540 }
541 }
542}
543
544impl IdentifiableAbstractionElement for IPdu {}
545impl AbstractPdu for IPdu {}
546impl AbstractIpdu for IPdu {}
547
548#[derive(Debug, Clone, PartialEq, Eq, Hash)]
552pub struct PduTriggering(Element);
553abstraction_element!(PduTriggering, PduTriggering);
554impl IdentifiableAbstractionElement for PduTriggering {}
555
556impl PduTriggering {
557 pub(crate) fn new(pdu: &Pdu, channel: &PhysicalChannel) -> Result<Self, AutosarAbstractionError> {
558 let model = channel.element().model()?;
559 let base_path = channel.element().path()?;
560 let pdu_name = pdu
561 .name()
562 .ok_or(AutosarAbstractionError::InvalidParameter("invalid pdu".to_string()))?;
563 let pt_name = format!("PT_{pdu_name}");
564 let pt_name = make_unique_name(&model, &base_path, &pt_name);
565
566 let triggerings = channel
567 .element()
568 .get_or_create_sub_element(ElementName::PduTriggerings)?;
569 let pt_elem = triggerings.create_named_sub_element(ElementName::PduTriggering, &pt_name)?;
570 pt_elem
571 .create_sub_element(ElementName::IPduRef)?
572 .set_reference_target(pdu.element())?;
573
574 let pt = Self(pt_elem);
575
576 if let Pdu::ISignalIPdu(isignal_ipdu) = pdu {
577 for signal_mapping in isignal_ipdu.mapped_signals() {
578 if let Some(signal) = signal_mapping.signal() {
579 pt.create_signal_triggering(&signal)?;
580 } else if let Some(signal_group) = signal_mapping.signal_group() {
581 pt.create_signal_group_triggering(&signal_group)?;
582 }
583 }
584 }
585
586 Ok(pt)
587 }
588
589 #[must_use]
591 pub fn pdu(&self) -> Option<Pdu> {
592 let pdu_elem = self
593 .element()
594 .get_sub_element(ElementName::IPduRef)?
595 .get_reference_target()
596 .ok()?;
597 Pdu::try_from(pdu_elem).ok()
598 }
599
600 pub fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
602 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
603 PhysicalChannel::try_from(channel_elem)
604 }
605
606 pub fn create_pdu_port(
608 &self,
609 ecu: &EcuInstance,
610 direction: CommunicationDirection,
611 ) -> Result<IPduPort, AutosarAbstractionError> {
612 for pdu_port in self.pdu_ports() {
613 if let (Ok(existing_ecu), Some(existing_direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
614 if existing_ecu == *ecu && existing_direction == direction {
615 return Ok(pdu_port);
616 }
617 }
618 }
619
620 let channel = self.physical_channel()?;
621 let connector = channel
622 .ecu_connector(ecu)
623 .ok_or(AutosarAbstractionError::InvalidParameter(
624 "The ECU is not connected to the channel".to_string(),
625 ))?;
626
627 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
628 let suffix = match direction {
629 CommunicationDirection::In => "Rx",
630 CommunicationDirection::Out => "Tx",
631 };
632 let port_name = format!("{name}_{suffix}",);
633 let pp_elem = connector
634 .element()
635 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
636 .create_named_sub_element(ElementName::IPduPort, &port_name)?;
637 pp_elem
638 .create_sub_element(ElementName::CommunicationDirection)?
639 .set_character_data::<EnumItem>(direction.into())?;
640
641 self.element()
642 .get_or_create_sub_element(ElementName::IPduPortRefs)?
643 .create_sub_element(ElementName::IPduPortRef)?
644 .set_reference_target(&pp_elem)?;
645
646 for st in self.signal_triggerings() {
647 st.connect_to_ecu(ecu, direction)?;
648 }
649
650 Ok(IPduPort(pp_elem))
651 }
652
653 pub fn pdu_ports(&self) -> impl Iterator<Item = IPduPort> + Send + use<> {
655 self.element()
656 .get_sub_element(ElementName::IPduPortRefs)
657 .into_iter()
658 .flat_map(|ipprefs| ipprefs.sub_elements())
659 .filter_map(|ippref| {
660 ippref
661 .get_reference_target()
662 .ok()
663 .and_then(|elem| IPduPort::try_from(elem).ok())
664 })
665 }
666
667 pub fn signal_triggerings(&self) -> impl Iterator<Item = ISignalTriggering> + Send + use<> {
669 self.element()
670 .get_sub_element(ElementName::ISignalTriggerings)
671 .into_iter()
672 .flat_map(|ists| ists.sub_elements())
673 .filter_map(|ist| {
674 ist.get_sub_element(ElementName::ISignalTriggeringRef)
675 .and_then(|str| str.get_reference_target().ok())
676 .and_then(|elem| ISignalTriggering::try_from(elem).ok())
677 })
678 }
679
680 pub(crate) fn create_signal_triggering(
682 &self,
683 signal: &ISignal,
684 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
685 let channel = self.physical_channel()?;
686 let st = ISignalTriggering::new(signal, &channel)?;
687 let triggerings = self
688 .element()
689 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
690 triggerings
691 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
692 .create_sub_element(ElementName::ISignalTriggeringRef)?
693 .set_reference_target(st.element())?;
694
695 for pdu_port in self.pdu_ports() {
696 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
697 st.connect_to_ecu(&ecu, direction)?;
698 }
699 }
700
701 Ok(st)
702 }
703
704 pub(crate) fn create_signal_group_triggering(
706 &self,
707 signal_group: &ISignalGroup,
708 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
709 let channel = self.physical_channel()?;
710 let st = ISignalTriggering::new_group(signal_group, &channel)?;
711 let triggerings = self
712 .element()
713 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
714 triggerings
715 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
716 .create_sub_element(ElementName::ISignalTriggeringRef)?
717 .set_reference_target(st.element())?;
718
719 for pdu_port in self.pdu_ports() {
720 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
721 st.connect_to_ecu(&ecu, direction)?;
722 }
723 }
724
725 Ok(st)
726 }
727}
728
729#[derive(Debug, Clone, PartialEq, Eq, Hash)]
733pub struct IPduPort(Element);
734abstraction_element!(IPduPort, IPduPort);
735impl IdentifiableAbstractionElement for IPduPort {}
736
737impl IPduPort {
738 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
740 let comm_connector_elem = self.element().named_parent()?.unwrap();
741 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
742 EcuInstance::try_from(ecu_elem)
743 }
744
745 pub fn set_communication_direction(
747 &self,
748 direction: CommunicationDirection,
749 ) -> Result<(), AutosarAbstractionError> {
750 self.element()
751 .get_or_create_sub_element(ElementName::CommunicationDirection)?
752 .set_character_data::<EnumItem>(direction.into())?;
753 Ok(())
754 }
755
756 #[must_use]
758 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
759 self.element()
760 .get_sub_element(ElementName::CommunicationDirection)?
761 .character_data()?
762 .enum_value()?
763 .try_into()
764 .ok()
765 }
766}
767
768#[derive(Debug, Clone, Copy, PartialEq, Eq)]
773pub enum PduCollectionTrigger {
774 Always,
776 Never,
778}
779
780impl From<PduCollectionTrigger> for EnumItem {
781 fn from(value: PduCollectionTrigger) -> Self {
782 match value {
783 PduCollectionTrigger::Always => EnumItem::Always,
784 PduCollectionTrigger::Never => EnumItem::Never,
785 }
786 }
787}
788
789impl TryFrom<EnumItem> for PduCollectionTrigger {
790 type Error = AutosarAbstractionError;
791
792 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
793 match value {
794 EnumItem::Always => Ok(PduCollectionTrigger::Always),
795 EnumItem::Never => Ok(PduCollectionTrigger::Never),
796 _ => Err(AutosarAbstractionError::ValueConversionError {
797 value: value.to_string(),
798 dest: "PduCollectionTrigger".to_string(),
799 }),
800 }
801 }
802}
803
804#[cfg(test)]
807mod test {
808 use super::*;
809 use crate::{
810 AutosarModelAbstraction, ByteOrder, SystemCategory,
811 communication::{AbstractFrame, AbstractFrameTriggering, CanAddressingMode, CanFrameType, TransferProperty},
812 };
813 use autosar_data::AutosarVersion;
814
815 #[test]
816 fn test_pdus() {
817 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
818 let package = model.get_or_create_package("/pkg").unwrap();
819 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
820
821 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
822 let nm_pdu = system.create_nm_pdu("nm_pdu", &package, 1).unwrap();
823 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
824 let dcm_ipdu = system.create_dcm_ipdu("dcm_ipdu", &package, 1).unwrap();
825 let gp_pdu = system
826 .create_general_purpose_pdu("gp_pdu", &package, 1, GeneralPurposePduCategory::Sd)
827 .unwrap();
828 let gp_ipdu = system
829 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
830 .unwrap();
831 let container_ipdu = system
832 .create_container_ipdu(
833 "container_ipdu",
834 &package,
835 1,
836 ContainerIPduHeaderType::ShortHeader,
837 RxAcceptContainedIPdu::AcceptAll,
838 )
839 .unwrap();
840 let secured_ipdu = system
841 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
842 .unwrap();
843 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
844
845 assert_eq!(isignal_ipdu.length().unwrap(), 1);
846 assert_eq!(nm_pdu.length().unwrap(), 1);
847 assert_eq!(n_pdu.length().unwrap(), 1);
848 assert_eq!(dcm_ipdu.length().unwrap(), 1);
849 assert_eq!(gp_pdu.length().unwrap(), 1);
850 assert_eq!(gp_ipdu.length().unwrap(), 1);
851 assert_eq!(container_ipdu.length().unwrap(), 1);
852 assert_eq!(secured_ipdu.length().unwrap(), 1);
853 assert_eq!(multiplexed_ipdu.length().unwrap(), 1);
854
855 isignal_ipdu.set_length(2).unwrap();
856 assert_eq!(isignal_ipdu.length().unwrap(), 2);
857
858 let frame = system.create_flexray_frame("frame1", &package, 64).unwrap();
859 frame
860 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
861 .unwrap();
862 frame
863 .map_pdu(&nm_pdu, 8, ByteOrder::MostSignificantByteLast, None)
864 .unwrap();
865 frame
866 .map_pdu(&n_pdu, 16, ByteOrder::MostSignificantByteLast, None)
867 .unwrap();
868 frame
869 .map_pdu(&dcm_ipdu, 24, ByteOrder::MostSignificantByteLast, None)
870 .unwrap();
871 frame
872 .map_pdu(&gp_pdu, 32, ByteOrder::MostSignificantByteLast, None)
873 .unwrap();
874 frame
875 .map_pdu(&gp_ipdu, 40, ByteOrder::MostSignificantByteLast, None)
876 .unwrap();
877 frame
878 .map_pdu(&container_ipdu, 48, ByteOrder::MostSignificantByteLast, None)
879 .unwrap();
880 frame
881 .map_pdu(&secured_ipdu, 56, ByteOrder::MostSignificantByteLast, None)
882 .unwrap();
883 frame
884 .map_pdu(&multiplexed_ipdu, 64, ByteOrder::MostSignificantByteLast, None)
885 .unwrap();
886
887 let mut pdus_iter = frame.mapped_pdus();
888 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "isignal_ipdu");
889 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "nm_pdu");
890 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "n_pdu");
891 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "dcm_ipdu");
892 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_pdu");
893 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_ipdu");
894 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "container_ipdu");
895 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "secured_ipdu");
896 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "multiplexed_ipdu");
897 assert!(pdus_iter.next().is_none());
898 }
899
900 #[test]
901 fn test_pdu_triggering() {
902 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
903 let package = model.get_or_create_package("/pkg").unwrap();
904 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
905
906 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
908 let syssignal = package.create_system_signal("syssignal").unwrap();
909 let isignal = system.create_isignal("isignal", &package, 1, &syssignal, None).unwrap();
910 isignal_ipdu
911 .map_signal(
912 &isignal,
913 0,
914 ByteOrder::MostSignificantByteLast,
915 None,
916 TransferProperty::Triggered,
917 )
918 .unwrap();
919 let syssignal_group = package.create_system_signal_group("syssignal_group").unwrap();
921 let isignal_group = system
922 .create_isignal_group("isignal_group", &package, &syssignal_group)
923 .unwrap();
924 let syssignal2 = package.create_system_signal("syssignal2").unwrap();
925 let isignal2 = system
926 .create_isignal("isignal2", &package, 1, &syssignal2, None)
927 .unwrap();
928 isignal_ipdu.map_signal_group(&isignal_group).unwrap();
929 isignal_ipdu
930 .map_signal(
931 &isignal2,
932 1,
933 ByteOrder::MostSignificantByteLast,
934 None,
935 TransferProperty::Triggered,
936 )
937 .unwrap();
938
939 let can_cluster = system.create_can_cluster("Cluster", &package, None).unwrap();
941 let channel = can_cluster.create_physical_channel("Channel").unwrap();
942 let frame = system.create_can_frame("frame", &package, 8).unwrap();
943 let frame_triggering = channel
944 .trigger_frame(&frame, 0x123, CanAddressingMode::Standard, CanFrameType::Can20)
945 .unwrap();
946 let _mapping = frame
947 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
948 .unwrap();
949
950 let ecu = system.create_ecu_instance("ecu", &package).unwrap();
952 let controller = ecu.create_can_communication_controller("controller").unwrap();
953 controller.connect_physical_channel("connection", &channel).unwrap();
954 frame_triggering
955 .connect_to_ecu(&ecu, CommunicationDirection::In)
956 .unwrap();
957
958 let pdu_triggering = frame_triggering.pdu_triggerings().next().unwrap();
959 assert_eq!(pdu_triggering.pdu_ports().count(), 1);
960 assert_eq!(pdu_triggering.signal_triggerings().count(), 3); let pdu_port = pdu_triggering.pdu_ports().next().unwrap();
963 assert_eq!(pdu_port.ecu().unwrap().name().unwrap(), "ecu");
964 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::In);
965 pdu_port
966 .set_communication_direction(CommunicationDirection::Out)
967 .unwrap();
968 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::Out);
969 pdu_port.set_name("new_name").unwrap();
970 assert_eq!(pdu_port.name().unwrap(), "new_name");
971 }
972
973 #[test]
974 fn general_purpose_pdu() {
975 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
976 let package = model.get_or_create_package("/pkg").unwrap();
977 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
978
979 let gp_pdu1 = system
980 .create_general_purpose_pdu("gp_pdu1", &package, 1, GeneralPurposePduCategory::Sd)
981 .unwrap();
982 assert_eq!(gp_pdu1.category().unwrap(), GeneralPurposePduCategory::Sd);
983
984 let gp_pdu2 = system
985 .create_general_purpose_pdu("gp_pdu2", &package, 1, GeneralPurposePduCategory::GlobalTime)
986 .unwrap();
987 assert_eq!(gp_pdu2.category().unwrap(), GeneralPurposePduCategory::GlobalTime);
988
989 let gp_pdu3 = system
990 .create_general_purpose_pdu("gp_pdu3", &package, 1, GeneralPurposePduCategory::DoIp)
991 .unwrap();
992 assert_eq!(gp_pdu3.category().unwrap(), GeneralPurposePduCategory::DoIp);
993
994 assert_eq!(
996 GeneralPurposePduCategory::from_str("SD").unwrap(),
997 GeneralPurposePduCategory::Sd
998 );
999 assert_eq!(
1000 GeneralPurposePduCategory::from_str("GLOBAL_TIME").unwrap(),
1001 GeneralPurposePduCategory::GlobalTime
1002 );
1003 assert_eq!(
1004 GeneralPurposePduCategory::from_str("DOIP").unwrap(),
1005 GeneralPurposePduCategory::DoIp
1006 );
1007 assert!(GeneralPurposePduCategory::from_str("invalid").is_err());
1008 }
1009
1010 #[test]
1011 fn create_general_purpose_ipdu() {
1012 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1013 let package = model.get_or_create_package("/pkg").unwrap();
1014 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1015
1016 let gp_ipdu1 = system
1017 .create_general_purpose_ipdu("gp_ipdu1", &package, 1, GeneralPurposeIPduCategory::Xcp)
1018 .unwrap();
1019 assert_eq!(gp_ipdu1.category().unwrap(), GeneralPurposeIPduCategory::Xcp);
1020
1021 let gp_ipdu2 = system
1022 .create_general_purpose_ipdu("gp_ipdu2", &package, 1, GeneralPurposeIPduCategory::SomeipSegmentedIpdu)
1023 .unwrap();
1024 assert_eq!(
1025 gp_ipdu2.category().unwrap(),
1026 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1027 );
1028
1029 let gp_ipdu3 = system
1030 .create_general_purpose_ipdu("gp_ipdu3", &package, 1, GeneralPurposeIPduCategory::Dlt)
1031 .unwrap();
1032 assert_eq!(gp_ipdu3.category().unwrap(), GeneralPurposeIPduCategory::Dlt);
1033
1034 assert_eq!(
1036 GeneralPurposeIPduCategory::from_str("XCP").unwrap(),
1037 GeneralPurposeIPduCategory::Xcp
1038 );
1039 assert_eq!(
1040 GeneralPurposeIPduCategory::from_str("SOMEIP_SEGMENTED_IPDU").unwrap(),
1041 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1042 );
1043 assert_eq!(
1044 GeneralPurposeIPduCategory::from_str("DLT").unwrap(),
1045 GeneralPurposeIPduCategory::Dlt
1046 );
1047 assert!(GeneralPurposeIPduCategory::from_str("invalid").is_err());
1048 }
1049
1050 #[test]
1051 fn ipdu() {
1052 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1053 let package = model.get_or_create_package("/pkg").unwrap();
1054 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1055
1056 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1057 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
1058 let dcm_ipdu = system.create_dcm_ipdu("dcm_ipdu", &package, 1).unwrap();
1059 let gp_ipdu = system
1060 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
1061 .unwrap();
1062 let container_ipdu = system
1063 .create_container_ipdu(
1064 "container_ipdu",
1065 &package,
1066 1,
1067 ContainerIPduHeaderType::LongHeader,
1068 RxAcceptContainedIPdu::AcceptConfigured,
1069 )
1070 .unwrap();
1071 let secured_ipdu = system
1072 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
1073 .unwrap();
1074 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1075
1076 let ipdu: IPdu = isignal_ipdu.clone().into();
1077 assert_eq!(ipdu.element(), isignal_ipdu.element());
1078 assert!(matches!(ipdu, IPdu::ISignalIPdu(_)));
1079
1080 let ipdu: IPdu = n_pdu.clone().into();
1083 assert_eq!(ipdu.element(), n_pdu.element());
1084 assert!(matches!(ipdu, IPdu::NPdu(_)));
1085
1086 let ipdu: IPdu = dcm_ipdu.clone().into();
1087 assert_eq!(ipdu.element(), dcm_ipdu.element());
1088 assert!(matches!(ipdu, IPdu::DcmIPdu(_)));
1089
1090 let ipdu: IPdu = n_pdu.clone().into();
1091 assert_eq!(ipdu.element(), n_pdu.element());
1092 assert!(matches!(ipdu, IPdu::NPdu(_)));
1093
1094 let ipdu: IPdu = gp_ipdu.clone().into();
1097 assert_eq!(ipdu.element(), gp_ipdu.element());
1098 assert!(matches!(ipdu, IPdu::GeneralPurposeIPdu(_)));
1099
1100 let ipdu: IPdu = container_ipdu.clone().into();
1101 assert_eq!(ipdu.element(), container_ipdu.element());
1102 assert!(matches!(ipdu, IPdu::ContainerIPdu(_)));
1103
1104 let ipdu: IPdu = secured_ipdu.clone().into();
1105 assert_eq!(ipdu.element(), secured_ipdu.element());
1106 assert!(matches!(ipdu, IPdu::SecuredIPdu(_)));
1107
1108 let ipdu: IPdu = multiplexed_ipdu.clone().into();
1109 assert_eq!(ipdu.element(), multiplexed_ipdu.element());
1110 assert!(matches!(ipdu, IPdu::MultiplexedIPdu(_)));
1111
1112 let pdu: Pdu = ipdu.clone().into();
1114 assert_eq!(pdu.element(), ipdu.element());
1115 }
1116}