1use crate::communication::{
2 AbstractPhysicalChannel, CommunicationDirection, ISignal, ISignalGroup, ISignalTriggering, PhysicalChannel,
3 TransferProperty,
4};
5use crate::{
6 AbstractionElement, ArPackage, AutosarAbstractionError, ByteOrder, EcuInstance, IdentifiableAbstractionElement,
7 abstraction_element, make_unique_name,
8};
9use autosar_data::{AutosarDataError, Element, ElementName, EnumItem};
10use std::str::FromStr;
11
12mod container_ipdu;
13mod isignal_ipdu;
14mod secured_ipdu;
15
16pub use container_ipdu::*;
17pub use isignal_ipdu::*;
18pub use secured_ipdu::*;
19
20pub trait AbstractPdu: AbstractionElement + Into<Pdu> {
24 fn set_length(&self, length: u32) -> Result<(), AutosarAbstractionError> {
26 self.element()
27 .get_or_create_sub_element(ElementName::Length)?
28 .set_character_data(length as u64)?;
29 Ok(())
30 }
31
32 fn length(&self) -> Option<u32> {
34 self.element()
35 .get_sub_element(ElementName::Length)?
36 .character_data()?
37 .parse_integer()
38 }
39
40 fn pdu_triggerings(&self) -> Vec<PduTriggering> {
42 let model_result = self.element().model();
43 let path_result = self.element().path();
44 if let (Ok(model), Ok(path)) = (model_result, path_result) {
45 model
46 .get_references_to(&path)
47 .iter()
48 .filter_map(|e| {
49 e.upgrade()
50 .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
51 .and_then(|elem| PduTriggering::try_from(elem).ok())
52 })
53 .collect()
54 } else {
55 vec![]
56 }
57 }
58}
59
60pub trait AbstractIpdu: AbstractPdu + Into<IPdu> {
64 fn set_contained_ipdu_props(&self, props: Option<&ContainedIPduProps>) -> Result<(), AutosarAbstractionError> {
68 ContainedIPduProps::set_props(self.element(), props)
69 }
70
71 #[must_use]
73 fn contained_ipdu_props(&self) -> Option<ContainedIPduProps> {
74 ContainedIPduProps::get_props(self.element())
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Hash)]
82pub struct NmPdu(Element);
83abstraction_element!(NmPdu, NmPdu);
84impl IdentifiableAbstractionElement for NmPdu {}
85
86impl NmPdu {
87 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
88 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
89 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::NmPdu, name)?;
90 elem_pdu
91 .create_sub_element(ElementName::Length)?
92 .set_character_data(length.to_string())?;
93
94 Ok(Self(elem_pdu))
95 }
96
97 pub fn set_unused_bit_pattern(&self, pattern: u8) -> Result<(), AutosarAbstractionError> {
99 self.element()
100 .get_or_create_sub_element(ElementName::UnusedBitPattern)?
101 .set_character_data(pattern.to_string())?;
102 Ok(())
103 }
104
105 #[must_use]
107 pub fn unused_bit_pattern(&self) -> Option<u8> {
108 self.element()
109 .get_sub_element(ElementName::UnusedBitPattern)?
110 .character_data()?
111 .parse_integer()
112 }
113
114 pub fn map_signal(
118 &self,
119 signal: &ISignal,
120 start_position: u32,
121 byte_order: ByteOrder,
122 update_bit: Option<u32>,
123 transfer_property: TransferProperty,
124 ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
125 let signal_name = signal
126 .name()
127 .ok_or(AutosarAbstractionError::InvalidParameter("invalid signal".to_string()))?;
128
129 verify_signal_mapping(self, signal, start_position, byte_order, update_bit, &signal_name)?;
130
131 for pt in self.pdu_triggerings() {
133 let st = pt.create_signal_triggering(signal)?;
134 for pdu_port in pt.pdu_ports() {
135 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
136 st.connect_to_ecu(&ecu, direction)?;
137 }
138 }
139 }
140
141 let model = self.element().model()?;
143 let base_path = self.element().path()?;
144 let name = make_unique_name(&model, &base_path, &signal_name);
145
146 let mappings = self
149 .element()
150 .get_or_create_sub_element(ElementName::ISignalToIPduMappings)?;
151
152 ISignalToIPduMapping::new_with_signal(
153 &name,
154 &mappings,
155 signal,
156 start_position,
157 byte_order,
158 update_bit,
159 transfer_property,
160 )
161 }
162
163 pub fn map_signal_group(
165 &self,
166 signal_group: &ISignalGroup,
167 ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
168 let signal_group_name = signal_group.name().ok_or(AutosarAbstractionError::InvalidParameter(
169 "invalid signal group".to_string(),
170 ))?;
171
172 for pt in self.pdu_triggerings() {
174 let st = pt.create_signal_group_triggering(signal_group)?;
175 for pdu_port in pt.pdu_ports() {
176 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
177 st.connect_to_ecu(&ecu, direction)?;
178 }
179 }
180 }
181
182 let model = self.element().model()?;
184 let base_path = self.element().path()?;
185 let name = make_unique_name(&model, &base_path, &signal_group_name);
186
187 let mappings = self
190 .element()
191 .get_or_create_sub_element(ElementName::ISignalToIPduMappings)?;
192
193 ISignalToIPduMapping::new_with_group(&name, &mappings, signal_group)
194 }
195}
196
197impl AbstractPdu for NmPdu {}
198impl SignalPdu for NmPdu {
199 fn map_signal(
200 &self,
201 signal: &ISignal,
202 start_position: u32,
203 byte_order: ByteOrder,
204 update_bit: Option<u32>,
205 transfer_property: TransferProperty,
206 ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
207 NmPdu::map_signal(self, signal, start_position, byte_order, update_bit, transfer_property)
208 }
209
210 fn map_signal_group(&self, signal_group: &ISignalGroup) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
211 NmPdu::map_signal_group(self, signal_group)
212 }
213}
214
215impl From<NmPdu> for Pdu {
216 fn from(value: NmPdu) -> Self {
217 Pdu::NmPdu(value)
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub struct NPdu(Element);
226abstraction_element!(NPdu, NPdu);
227impl IdentifiableAbstractionElement for NPdu {}
228
229impl NPdu {
230 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
231 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
232 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::NPdu, name)?;
233 elem_pdu
234 .create_sub_element(ElementName::Length)?
235 .set_character_data(length.to_string())?;
236
237 Ok(Self(elem_pdu))
238 }
239}
240
241impl AbstractPdu for NPdu {}
242
243impl AbstractIpdu for NPdu {}
244
245impl From<NPdu> for Pdu {
246 fn from(value: NPdu) -> Self {
247 Pdu::NPdu(value)
248 }
249}
250
251impl From<NPdu> for IPdu {
252 fn from(value: NPdu) -> Self {
253 IPdu::NPdu(value)
254 }
255}
256
257#[derive(Debug, Clone, PartialEq, Eq, Hash)]
261pub struct DcmIPdu(Element);
262abstraction_element!(DcmIPdu, DcmIPdu);
263impl IdentifiableAbstractionElement for DcmIPdu {}
264
265impl DcmIPdu {
266 pub(crate) fn new(
267 name: &str,
268 package: &ArPackage,
269 length: u32,
270 diag_pdu_type: DiagPduType,
271 ) -> Result<Self, AutosarAbstractionError> {
272 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
273 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::DcmIPdu, name)?;
274 elem_pdu
275 .create_sub_element(ElementName::Length)?
276 .set_character_data(length.to_string())?;
277 let dcm_ipdu = Self(elem_pdu);
278 dcm_ipdu.set_diag_pdu_type(diag_pdu_type)?;
279
280 Ok(dcm_ipdu)
281 }
282
283 pub fn set_diag_pdu_type(&self, pdu_type: DiagPduType) -> Result<(), AutosarAbstractionError> {
285 self.element()
286 .get_or_create_sub_element(ElementName::DiagPduType)?
287 .set_character_data::<EnumItem>(pdu_type.into())?;
288 Ok(())
289 }
290
291 #[must_use]
293 pub fn diag_pdu_type(&self) -> Option<DiagPduType> {
294 let enum_item = self
295 .element()
296 .get_sub_element(ElementName::DiagPduType)?
297 .character_data()?
298 .enum_value()?;
299 DiagPduType::try_from(enum_item).ok()
300 }
301}
302
303impl AbstractPdu for DcmIPdu {}
304
305impl AbstractIpdu for DcmIPdu {}
306
307impl From<DcmIPdu> for Pdu {
308 fn from(value: DcmIPdu) -> Self {
309 Pdu::DcmIPdu(value)
310 }
311}
312
313impl From<DcmIPdu> for IPdu {
314 fn from(value: DcmIPdu) -> Self {
315 IPdu::DcmIPdu(value)
316 }
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323pub enum DiagPduType {
324 DiagRequest,
326 DiagResponse,
328}
329
330impl TryFrom<EnumItem> for DiagPduType {
331 type Error = AutosarAbstractionError;
332
333 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
334 match value {
335 EnumItem::DiagRequest => Ok(DiagPduType::DiagRequest),
336 EnumItem::DiagResponse => Ok(DiagPduType::DiagResponse),
337 _ => Err(AutosarAbstractionError::ValueConversionError {
338 value: value.to_string(),
339 dest: "DiagPduType".to_string(),
340 }),
341 }
342 }
343}
344
345impl From<DiagPduType> for EnumItem {
346 fn from(value: DiagPduType) -> Self {
347 match value {
348 DiagPduType::DiagRequest => EnumItem::DiagRequest,
349 DiagPduType::DiagResponse => EnumItem::DiagResponse,
350 }
351 }
352}
353
354#[derive(Debug, Clone, PartialEq, Eq, Hash)]
358pub struct GeneralPurposePdu(Element);
359abstraction_element!(GeneralPurposePdu, GeneralPurposePdu);
360impl IdentifiableAbstractionElement for GeneralPurposePdu {}
361
362impl GeneralPurposePdu {
363 pub(crate) fn new(
364 name: &str,
365 package: &ArPackage,
366 length: u32,
367 category: GeneralPurposePduCategory,
368 ) -> Result<Self, AutosarAbstractionError> {
369 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
370 let pdu_elem = pkg_elements.create_named_sub_element(ElementName::GeneralPurposePdu, name)?;
371 let pdu = Self(pdu_elem);
372
373 pdu.set_length(length)?;
374 pdu.set_category(category)?;
375
376 Ok(pdu)
377 }
378
379 pub fn set_category(&self, category: GeneralPurposePduCategory) -> Result<(), AutosarAbstractionError> {
381 self.element()
382 .get_or_create_sub_element(ElementName::Category)?
383 .set_character_data(category.to_string())?;
384 Ok(())
385 }
386
387 #[must_use]
389 pub fn category(&self) -> Option<GeneralPurposePduCategory> {
390 let category_string = self
391 .element()
392 .get_sub_element(ElementName::Category)?
393 .character_data()?
394 .string_value()?;
395 GeneralPurposePduCategory::from_str(&category_string).ok()
396 }
397}
398
399impl AbstractPdu for GeneralPurposePdu {}
400
401impl From<GeneralPurposePdu> for Pdu {
402 fn from(value: GeneralPurposePdu) -> Self {
403 Pdu::GeneralPurposePdu(value)
404 }
405}
406
407#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
416pub enum GeneralPurposePduCategory {
417 Sd,
419 GlobalTime,
421 DoIp,
423}
424
425impl std::fmt::Display for GeneralPurposePduCategory {
426 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427 match self {
428 GeneralPurposePduCategory::Sd => write!(f, "SD"),
429 GeneralPurposePduCategory::GlobalTime => write!(f, "GLOBAL_TIME"),
430 GeneralPurposePduCategory::DoIp => write!(f, "DOIP"),
431 }
432 }
433}
434
435impl std::str::FromStr for GeneralPurposePduCategory {
436 type Err = AutosarAbstractionError;
437
438 fn from_str(s: &str) -> Result<Self, Self::Err> {
439 match s {
440 "SD" => Ok(GeneralPurposePduCategory::Sd),
441 "GLOBAL_TIME" => Ok(GeneralPurposePduCategory::GlobalTime),
442 "DOIP" => Ok(GeneralPurposePduCategory::DoIp),
443 _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
444 }
445 }
446}
447
448#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452pub struct GeneralPurposeIPdu(Element);
453abstraction_element!(GeneralPurposeIPdu, GeneralPurposeIPdu);
454impl IdentifiableAbstractionElement for GeneralPurposeIPdu {}
455
456impl GeneralPurposeIPdu {
457 pub(crate) fn new(
458 name: &str,
459 package: &ArPackage,
460 length: u32,
461 category: GeneralPurposeIPduCategory,
462 ) -> Result<Self, AutosarAbstractionError> {
463 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
464 let pdu_elem = pkg_elements.create_named_sub_element(ElementName::GeneralPurposeIPdu, name)?;
465 let pdu = Self(pdu_elem);
466
467 pdu.set_length(length)?;
468 pdu.set_category(category)?;
469
470 Ok(pdu)
471 }
472
473 pub fn set_category(&self, category: GeneralPurposeIPduCategory) -> Result<(), AutosarAbstractionError> {
475 self.element()
476 .get_or_create_sub_element(ElementName::Category)?
477 .set_character_data(category.to_string())?;
478 Ok(())
479 }
480
481 #[must_use]
483 pub fn category(&self) -> Option<GeneralPurposeIPduCategory> {
484 let category_string = self
485 .element()
486 .get_sub_element(ElementName::Category)?
487 .character_data()?
488 .string_value()?;
489 GeneralPurposeIPduCategory::from_str(&category_string).ok()
490 }
491}
492
493impl AbstractPdu for GeneralPurposeIPdu {}
494
495impl AbstractIpdu for GeneralPurposeIPdu {}
496
497impl From<GeneralPurposeIPdu> for Pdu {
498 fn from(value: GeneralPurposeIPdu) -> Self {
499 Pdu::GeneralPurposeIPdu(value)
500 }
501}
502
503impl From<GeneralPurposeIPdu> for IPdu {
504 fn from(value: GeneralPurposeIPdu) -> Self {
505 IPdu::GeneralPurposeIPdu(value)
506 }
507}
508
509#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
518pub enum GeneralPurposeIPduCategory {
519 Xcp,
521 SomeipSegmentedIpdu,
523 Dlt,
525}
526
527impl std::fmt::Display for GeneralPurposeIPduCategory {
528 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
529 match self {
530 GeneralPurposeIPduCategory::Xcp => write!(f, "XCP"),
531 GeneralPurposeIPduCategory::SomeipSegmentedIpdu => write!(f, "SOMEIP_SEGMENTED_IPDU"),
532 GeneralPurposeIPduCategory::Dlt => write!(f, "DLT"),
533 }
534 }
535}
536
537impl std::str::FromStr for GeneralPurposeIPduCategory {
538 type Err = AutosarAbstractionError;
539
540 fn from_str(s: &str) -> Result<Self, Self::Err> {
541 match s {
542 "XCP" => Ok(GeneralPurposeIPduCategory::Xcp),
543 "SOMEIP_SEGMENTED_IPDU" => Ok(GeneralPurposeIPduCategory::SomeipSegmentedIpdu),
544 "DLT" => Ok(GeneralPurposeIPduCategory::Dlt),
545 _ => Err(AutosarAbstractionError::InvalidParameter(s.to_string())),
546 }
547 }
548}
549
550#[derive(Debug, Clone, PartialEq, Eq, Hash)]
554pub struct MultiplexedIPdu(Element);
555abstraction_element!(MultiplexedIPdu, MultiplexedIPdu);
556impl IdentifiableAbstractionElement for MultiplexedIPdu {}
557
558impl MultiplexedIPdu {
559 pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
560 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
561 let elem_pdu = pkg_elements.create_named_sub_element(ElementName::MultiplexedIPdu, name)?;
562 elem_pdu
563 .create_sub_element(ElementName::Length)?
564 .set_character_data(length.to_string())?;
565
566 Ok(Self(elem_pdu))
567 }
568}
569
570impl AbstractPdu for MultiplexedIPdu {}
571
572impl AbstractIpdu for MultiplexedIPdu {}
573
574impl From<MultiplexedIPdu> for Pdu {
575 fn from(value: MultiplexedIPdu) -> Self {
576 Pdu::MultiplexedIPdu(value)
577 }
578}
579
580impl From<MultiplexedIPdu> for IPdu {
581 fn from(value: MultiplexedIPdu) -> Self {
582 IPdu::MultiplexedIPdu(value)
583 }
584}
585
586#[derive(Debug, Clone, PartialEq, Eq, Hash)]
590pub enum Pdu {
591 ISignalIPdu(ISignalIPdu),
593 NmPdu(NmPdu),
595 NPdu(NPdu),
597 DcmIPdu(DcmIPdu),
599 GeneralPurposePdu(GeneralPurposePdu),
601 GeneralPurposeIPdu(GeneralPurposeIPdu),
603 ContainerIPdu(ContainerIPdu),
605 SecuredIPdu(SecuredIPdu),
607 MultiplexedIPdu(MultiplexedIPdu),
609}
610
611impl AbstractionElement for Pdu {
612 fn element(&self) -> &Element {
613 match self {
614 Pdu::ISignalIPdu(pdu) => pdu.element(),
615 Pdu::NmPdu(pdu) => pdu.element(),
616 Pdu::NPdu(pdu) => pdu.element(),
617 Pdu::DcmIPdu(pdu) => pdu.element(),
618 Pdu::GeneralPurposePdu(pdu) => pdu.element(),
619 Pdu::GeneralPurposeIPdu(pdu) => pdu.element(),
620 Pdu::ContainerIPdu(pdu) => pdu.element(),
621 Pdu::SecuredIPdu(pdu) => pdu.element(),
622 Pdu::MultiplexedIPdu(pdu) => pdu.element(),
623 }
624 }
625}
626
627impl TryFrom<Element> for Pdu {
628 type Error = AutosarAbstractionError;
629
630 fn try_from(element: Element) -> Result<Self, Self::Error> {
631 match element.element_name() {
632 ElementName::ISignalIPdu => Ok(ISignalIPdu::try_from(element)?.into()),
633 ElementName::NmPdu => Ok(NmPdu::try_from(element)?.into()),
634 ElementName::NPdu => Ok(NPdu::try_from(element)?.into()),
635 ElementName::DcmIPdu => Ok(DcmIPdu::try_from(element)?.into()),
636 ElementName::GeneralPurposePdu => Ok(GeneralPurposePdu::try_from(element)?.into()),
637 ElementName::GeneralPurposeIPdu => Ok(GeneralPurposeIPdu::try_from(element)?.into()),
638 ElementName::ContainerIPdu => Ok(ContainerIPdu::try_from(element)?.into()),
639 ElementName::SecuredIPdu => Ok(SecuredIPdu::try_from(element)?.into()),
640 ElementName::MultiplexedIPdu => Ok(MultiplexedIPdu::try_from(element)?.into()),
641 _ => Err(AutosarAbstractionError::ConversionError {
642 element,
643 dest: "Pdu".to_string(),
644 }),
645 }
646 }
647}
648
649impl IdentifiableAbstractionElement for Pdu {}
650impl AbstractPdu for Pdu {}
651
652#[derive(Debug, Clone, PartialEq, Eq, Hash)]
656pub enum IPdu {
657 ISignalIPdu(ISignalIPdu),
659 NPdu(NPdu),
661 DcmIPdu(DcmIPdu),
663 GeneralPurposeIPdu(GeneralPurposeIPdu),
665 ContainerIPdu(ContainerIPdu),
667 SecuredIPdu(SecuredIPdu),
669 MultiplexedIPdu(MultiplexedIPdu),
671}
672
673impl AbstractionElement for IPdu {
674 fn element(&self) -> &Element {
675 match self {
676 IPdu::ISignalIPdu(pdu) => pdu.element(),
677 IPdu::NPdu(pdu) => pdu.element(),
678 IPdu::DcmIPdu(pdu) => pdu.element(),
679 IPdu::GeneralPurposeIPdu(pdu) => pdu.element(),
680 IPdu::ContainerIPdu(pdu) => pdu.element(),
681 IPdu::SecuredIPdu(pdu) => pdu.element(),
682 IPdu::MultiplexedIPdu(pdu) => pdu.element(),
683 }
684 }
685}
686
687impl TryFrom<Element> for IPdu {
688 type Error = AutosarAbstractionError;
689
690 fn try_from(element: Element) -> Result<Self, Self::Error> {
691 match element.element_name() {
692 ElementName::ISignalIPdu => Ok(IPdu::ISignalIPdu(ISignalIPdu::try_from(element)?)),
693 ElementName::NPdu => Ok(IPdu::NPdu(NPdu::try_from(element)?)),
694 ElementName::DcmIPdu => Ok(IPdu::DcmIPdu(DcmIPdu::try_from(element)?)),
695 ElementName::GeneralPurposeIPdu => Ok(IPdu::GeneralPurposeIPdu(GeneralPurposeIPdu::try_from(element)?)),
696 ElementName::ContainerIPdu => Ok(IPdu::ContainerIPdu(ContainerIPdu::try_from(element)?)),
697 ElementName::SecuredIPdu => Ok(IPdu::SecuredIPdu(SecuredIPdu::try_from(element)?)),
698 ElementName::MultiplexedIPdu => Ok(IPdu::MultiplexedIPdu(MultiplexedIPdu::try_from(element)?)),
699 _ => Err(AutosarAbstractionError::ConversionError {
700 element,
701 dest: "IPdu".to_string(),
702 }),
703 }
704 }
705}
706
707impl From<IPdu> for Pdu {
708 fn from(value: IPdu) -> Self {
709 match value {
710 IPdu::ISignalIPdu(pdu) => Pdu::ISignalIPdu(pdu),
711 IPdu::NPdu(pdu) => Pdu::NPdu(pdu),
712 IPdu::DcmIPdu(pdu) => Pdu::DcmIPdu(pdu),
713 IPdu::GeneralPurposeIPdu(pdu) => Pdu::GeneralPurposeIPdu(pdu),
714 IPdu::ContainerIPdu(pdu) => Pdu::ContainerIPdu(pdu),
715 IPdu::SecuredIPdu(pdu) => Pdu::SecuredIPdu(pdu),
716 IPdu::MultiplexedIPdu(pdu) => Pdu::MultiplexedIPdu(pdu),
717 }
718 }
719}
720
721impl IdentifiableAbstractionElement for IPdu {}
722impl AbstractPdu for IPdu {}
723impl AbstractIpdu for IPdu {}
724
725#[derive(Debug, Clone, PartialEq, Eq, Hash)]
729pub struct PduTriggering(Element);
730abstraction_element!(PduTriggering, PduTriggering);
731impl IdentifiableAbstractionElement for PduTriggering {}
732
733impl PduTriggering {
734 pub(crate) fn new(pdu: &Pdu, channel: &PhysicalChannel) -> Result<Self, AutosarAbstractionError> {
735 let model = channel.element().model()?;
736 let base_path = channel.element().path()?;
737 let pdu_name = pdu
738 .name()
739 .ok_or(AutosarAbstractionError::InvalidParameter("invalid pdu".to_string()))?;
740 let pt_name = format!("PT_{pdu_name}");
741 let pt_name = make_unique_name(&model, &base_path, &pt_name);
742
743 let triggerings = channel
744 .element()
745 .get_or_create_sub_element(ElementName::PduTriggerings)?;
746 let pt_elem = triggerings.create_named_sub_element(ElementName::PduTriggering, &pt_name)?;
747 pt_elem
748 .create_sub_element(ElementName::IPduRef)?
749 .set_reference_target(pdu.element())?;
750
751 let pt = Self(pt_elem);
752
753 if let Pdu::ISignalIPdu(isignal_ipdu) = pdu {
754 for signal_mapping in isignal_ipdu.mapped_signals() {
755 if let Some(signal) = signal_mapping.signal() {
756 pt.create_signal_triggering(&signal)?;
757 } else if let Some(signal_group) = signal_mapping.signal_group() {
758 pt.create_signal_group_triggering(&signal_group)?;
759 }
760 }
761 }
762
763 Ok(pt)
764 }
765
766 #[must_use]
768 pub fn pdu(&self) -> Option<Pdu> {
769 let pdu_elem = self
770 .element()
771 .get_sub_element(ElementName::IPduRef)?
772 .get_reference_target()
773 .ok()?;
774 Pdu::try_from(pdu_elem).ok()
775 }
776
777 pub fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
779 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
780 PhysicalChannel::try_from(channel_elem)
781 }
782
783 pub fn create_pdu_port(
785 &self,
786 ecu: &EcuInstance,
787 direction: CommunicationDirection,
788 ) -> Result<IPduPort, AutosarAbstractionError> {
789 for pdu_port in self.pdu_ports() {
790 if let (Ok(existing_ecu), Some(existing_direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
791 if existing_ecu == *ecu && existing_direction == direction {
792 return Ok(pdu_port);
793 }
794 }
795 }
796
797 let channel = self.physical_channel()?;
798 let connector = channel
799 .ecu_connector(ecu)
800 .ok_or(AutosarAbstractionError::InvalidParameter(
801 "The ECU is not connected to the channel".to_string(),
802 ))?;
803
804 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
805 let suffix = match direction {
806 CommunicationDirection::In => "Rx",
807 CommunicationDirection::Out => "Tx",
808 };
809 let port_name = format!("{name}_{suffix}",);
810 let pp_elem = connector
811 .element()
812 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
813 .create_named_sub_element(ElementName::IPduPort, &port_name)?;
814 pp_elem
815 .create_sub_element(ElementName::CommunicationDirection)?
816 .set_character_data::<EnumItem>(direction.into())?;
817
818 self.element()
819 .get_or_create_sub_element(ElementName::IPduPortRefs)?
820 .create_sub_element(ElementName::IPduPortRef)?
821 .set_reference_target(&pp_elem)?;
822
823 for st in self.signal_triggerings() {
824 st.connect_to_ecu(ecu, direction)?;
825 }
826
827 Ok(IPduPort(pp_elem))
828 }
829
830 pub fn pdu_ports(&self) -> impl Iterator<Item = IPduPort> + Send + use<> {
832 self.element()
833 .get_sub_element(ElementName::IPduPortRefs)
834 .into_iter()
835 .flat_map(|ipprefs| ipprefs.sub_elements())
836 .filter_map(|ippref| {
837 ippref
838 .get_reference_target()
839 .ok()
840 .and_then(|elem| IPduPort::try_from(elem).ok())
841 })
842 }
843
844 pub fn signal_triggerings(&self) -> impl Iterator<Item = ISignalTriggering> + Send + use<> {
846 self.element()
847 .get_sub_element(ElementName::ISignalTriggerings)
848 .into_iter()
849 .flat_map(|ists| ists.sub_elements())
850 .filter_map(|ist| {
851 ist.get_sub_element(ElementName::ISignalTriggeringRef)
852 .and_then(|str| str.get_reference_target().ok())
853 .and_then(|elem| ISignalTriggering::try_from(elem).ok())
854 })
855 }
856
857 pub(crate) fn create_signal_triggering(
859 &self,
860 signal: &ISignal,
861 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
862 let channel = self.physical_channel()?;
863 let st = ISignalTriggering::new(signal, &channel)?;
864 let triggerings = self
865 .element()
866 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
867 triggerings
868 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
869 .create_sub_element(ElementName::ISignalTriggeringRef)?
870 .set_reference_target(st.element())?;
871
872 for pdu_port in self.pdu_ports() {
873 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
874 st.connect_to_ecu(&ecu, direction)?;
875 }
876 }
877
878 Ok(st)
879 }
880
881 pub(crate) fn create_signal_group_triggering(
883 &self,
884 signal_group: &ISignalGroup,
885 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
886 let channel = self.physical_channel()?;
887 let st = ISignalTriggering::new_group(signal_group, &channel)?;
888 let triggerings = self
889 .element()
890 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
891 triggerings
892 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
893 .create_sub_element(ElementName::ISignalTriggeringRef)?
894 .set_reference_target(st.element())?;
895
896 for pdu_port in self.pdu_ports() {
897 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
898 st.connect_to_ecu(&ecu, direction)?;
899 }
900 }
901
902 Ok(st)
903 }
904}
905
906#[derive(Debug, Clone, PartialEq, Eq, Hash)]
910pub struct IPduPort(Element);
911abstraction_element!(IPduPort, IPduPort);
912impl IdentifiableAbstractionElement for IPduPort {}
913
914impl IPduPort {
915 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
917 let comm_connector_elem = self.element().named_parent()?.unwrap();
918 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
919 EcuInstance::try_from(ecu_elem)
920 }
921
922 pub fn set_communication_direction(
924 &self,
925 direction: CommunicationDirection,
926 ) -> Result<(), AutosarAbstractionError> {
927 self.element()
928 .get_or_create_sub_element(ElementName::CommunicationDirection)?
929 .set_character_data::<EnumItem>(direction.into())?;
930 Ok(())
931 }
932
933 #[must_use]
935 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
936 self.element()
937 .get_sub_element(ElementName::CommunicationDirection)?
938 .character_data()?
939 .enum_value()?
940 .try_into()
941 .ok()
942 }
943}
944
945#[derive(Debug, Clone, Copy, PartialEq, Eq)]
950pub enum PduCollectionTrigger {
951 Always,
953 Never,
955}
956
957impl From<PduCollectionTrigger> for EnumItem {
958 fn from(value: PduCollectionTrigger) -> Self {
959 match value {
960 PduCollectionTrigger::Always => EnumItem::Always,
961 PduCollectionTrigger::Never => EnumItem::Never,
962 }
963 }
964}
965
966impl TryFrom<EnumItem> for PduCollectionTrigger {
967 type Error = AutosarAbstractionError;
968
969 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
970 match value {
971 EnumItem::Always => Ok(PduCollectionTrigger::Always),
972 EnumItem::Never => Ok(PduCollectionTrigger::Never),
973 _ => Err(AutosarAbstractionError::ValueConversionError {
974 value: value.to_string(),
975 dest: "PduCollectionTrigger".to_string(),
976 }),
977 }
978 }
979}
980
981#[cfg(test)]
984mod test {
985 use super::*;
986 use crate::{
987 AutosarModelAbstraction, ByteOrder, SystemCategory,
988 communication::{AbstractFrame, AbstractFrameTriggering, CanAddressingMode, CanFrameType, TransferProperty},
989 };
990 use autosar_data::AutosarVersion;
991
992 #[test]
993 fn test_pdus() {
994 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
995 let package = model.get_or_create_package("/pkg").unwrap();
996 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
997
998 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
999 let nm_pdu = system.create_nm_pdu("nm_pdu", &package, 1).unwrap();
1000 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
1001 let dcm_ipdu = system
1002 .create_dcm_ipdu("dcm_ipdu", &package, 1, DiagPduType::DiagRequest)
1003 .unwrap();
1004 let gp_pdu = system
1005 .create_general_purpose_pdu("gp_pdu", &package, 1, GeneralPurposePduCategory::Sd)
1006 .unwrap();
1007 let gp_ipdu = system
1008 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
1009 .unwrap();
1010 let container_ipdu = system
1011 .create_container_ipdu(
1012 "container_ipdu",
1013 &package,
1014 1,
1015 ContainerIPduHeaderType::ShortHeader,
1016 RxAcceptContainedIPdu::AcceptAll,
1017 )
1018 .unwrap();
1019 let secured_ipdu = system
1020 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
1021 .unwrap();
1022 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1023
1024 assert_eq!(isignal_ipdu.length().unwrap(), 1);
1025 assert_eq!(nm_pdu.length().unwrap(), 1);
1026 assert_eq!(n_pdu.length().unwrap(), 1);
1027 assert_eq!(dcm_ipdu.length().unwrap(), 1);
1028 assert_eq!(gp_pdu.length().unwrap(), 1);
1029 assert_eq!(gp_ipdu.length().unwrap(), 1);
1030 assert_eq!(container_ipdu.length().unwrap(), 1);
1031 assert_eq!(secured_ipdu.length().unwrap(), 1);
1032 assert_eq!(multiplexed_ipdu.length().unwrap(), 1);
1033
1034 isignal_ipdu.set_length(2).unwrap();
1035 assert_eq!(isignal_ipdu.length().unwrap(), 2);
1036
1037 let frame = system.create_flexray_frame("frame1", &package, 64).unwrap();
1038 frame
1039 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
1040 .unwrap();
1041 frame
1042 .map_pdu(&nm_pdu, 8, ByteOrder::MostSignificantByteLast, None)
1043 .unwrap();
1044 frame
1045 .map_pdu(&n_pdu, 16, ByteOrder::MostSignificantByteLast, None)
1046 .unwrap();
1047 frame
1048 .map_pdu(&dcm_ipdu, 24, ByteOrder::MostSignificantByteLast, None)
1049 .unwrap();
1050 frame
1051 .map_pdu(&gp_pdu, 32, ByteOrder::MostSignificantByteLast, None)
1052 .unwrap();
1053 frame
1054 .map_pdu(&gp_ipdu, 40, ByteOrder::MostSignificantByteLast, None)
1055 .unwrap();
1056 frame
1057 .map_pdu(&container_ipdu, 48, ByteOrder::MostSignificantByteLast, None)
1058 .unwrap();
1059 frame
1060 .map_pdu(&secured_ipdu, 56, ByteOrder::MostSignificantByteLast, None)
1061 .unwrap();
1062 frame
1063 .map_pdu(&multiplexed_ipdu, 64, ByteOrder::MostSignificantByteLast, None)
1064 .unwrap();
1065
1066 let mut pdus_iter = frame.mapped_pdus();
1067 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "isignal_ipdu");
1068 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "nm_pdu");
1069 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "n_pdu");
1070 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "dcm_ipdu");
1071 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_pdu");
1072 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_ipdu");
1073 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "container_ipdu");
1074 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "secured_ipdu");
1075 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "multiplexed_ipdu");
1076 assert!(pdus_iter.next().is_none());
1077 }
1078
1079 #[test]
1080 fn test_pdu_triggering() {
1081 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1082 let package = model.get_or_create_package("/pkg").unwrap();
1083 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1084
1085 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1087 let syssignal = package.create_system_signal("syssignal").unwrap();
1088 let isignal = system.create_isignal("isignal", &package, 1, &syssignal, None).unwrap();
1089 isignal_ipdu
1090 .map_signal(
1091 &isignal,
1092 0,
1093 ByteOrder::MostSignificantByteLast,
1094 None,
1095 TransferProperty::Triggered,
1096 )
1097 .unwrap();
1098 let syssignal_group = package.create_system_signal_group("syssignal_group").unwrap();
1100 let isignal_group = system
1101 .create_isignal_group("isignal_group", &package, &syssignal_group)
1102 .unwrap();
1103 let syssignal2 = package.create_system_signal("syssignal2").unwrap();
1104 let isignal2 = system
1105 .create_isignal("isignal2", &package, 1, &syssignal2, None)
1106 .unwrap();
1107 isignal_ipdu.map_signal_group(&isignal_group).unwrap();
1108 isignal_ipdu
1109 .map_signal(
1110 &isignal2,
1111 1,
1112 ByteOrder::MostSignificantByteLast,
1113 None,
1114 TransferProperty::Triggered,
1115 )
1116 .unwrap();
1117
1118 let can_cluster = system.create_can_cluster("Cluster", &package, None).unwrap();
1120 let channel = can_cluster.create_physical_channel("Channel").unwrap();
1121 let frame = system.create_can_frame("frame", &package, 8).unwrap();
1122 let frame_triggering = channel
1123 .trigger_frame(&frame, 0x123, CanAddressingMode::Standard, CanFrameType::Can20)
1124 .unwrap();
1125 let _mapping = frame
1126 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
1127 .unwrap();
1128
1129 let ecu = system.create_ecu_instance("ecu", &package).unwrap();
1131 let controller = ecu.create_can_communication_controller("controller").unwrap();
1132 controller.connect_physical_channel("connection", &channel).unwrap();
1133 frame_triggering
1134 .connect_to_ecu(&ecu, CommunicationDirection::In)
1135 .unwrap();
1136
1137 let pdu_triggering = frame_triggering.pdu_triggerings().next().unwrap();
1138 assert_eq!(pdu_triggering.pdu_ports().count(), 1);
1139 assert_eq!(pdu_triggering.signal_triggerings().count(), 3); let pdu_port = pdu_triggering.pdu_ports().next().unwrap();
1142 assert_eq!(pdu_port.ecu().unwrap().name().unwrap(), "ecu");
1143 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::In);
1144 pdu_port
1145 .set_communication_direction(CommunicationDirection::Out)
1146 .unwrap();
1147 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::Out);
1148 pdu_port.set_name("new_name").unwrap();
1149 assert_eq!(pdu_port.name().unwrap(), "new_name");
1150 }
1151
1152 #[test]
1153 fn nm_pdu() {
1154 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00052);
1155 let package = model.get_or_create_package("/pkg").unwrap();
1156 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1157
1158 let nm_pdu = system.create_nm_pdu("nm_pdu", &package, 1).unwrap();
1159 assert_eq!(nm_pdu.length().unwrap(), 1);
1160
1161 nm_pdu.set_length(8).unwrap();
1162 assert_eq!(nm_pdu.length().unwrap(), 8);
1163
1164 nm_pdu.set_unused_bit_pattern(0xff).unwrap();
1165 assert_eq!(nm_pdu.unused_bit_pattern().unwrap(), 0xff);
1166
1167 let syssignal = package.create_system_signal("sys_userdata").unwrap();
1169 let isignal = system
1170 .create_isignal("userdata", &package, 16, &syssignal, None)
1171 .unwrap();
1172 let mapping = nm_pdu
1173 .map_signal(
1174 &isignal,
1175 0,
1176 ByteOrder::MostSignificantByteFirst,
1177 Some(16),
1178 TransferProperty::Triggered,
1179 )
1180 .unwrap();
1181 assert_eq!(mapping.signal().unwrap(), isignal);
1182 }
1183
1184 #[test]
1185 fn general_purpose_pdu() {
1186 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1187 let package = model.get_or_create_package("/pkg").unwrap();
1188 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1189
1190 let gp_pdu1 = system
1191 .create_general_purpose_pdu("gp_pdu1", &package, 1, GeneralPurposePduCategory::Sd)
1192 .unwrap();
1193 assert_eq!(gp_pdu1.category().unwrap(), GeneralPurposePduCategory::Sd);
1194
1195 let gp_pdu2 = system
1196 .create_general_purpose_pdu("gp_pdu2", &package, 1, GeneralPurposePduCategory::GlobalTime)
1197 .unwrap();
1198 assert_eq!(gp_pdu2.category().unwrap(), GeneralPurposePduCategory::GlobalTime);
1199
1200 let gp_pdu3 = system
1201 .create_general_purpose_pdu("gp_pdu3", &package, 1, GeneralPurposePduCategory::DoIp)
1202 .unwrap();
1203 assert_eq!(gp_pdu3.category().unwrap(), GeneralPurposePduCategory::DoIp);
1204
1205 assert_eq!(
1207 GeneralPurposePduCategory::from_str("SD").unwrap(),
1208 GeneralPurposePduCategory::Sd
1209 );
1210 assert_eq!(
1211 GeneralPurposePduCategory::from_str("GLOBAL_TIME").unwrap(),
1212 GeneralPurposePduCategory::GlobalTime
1213 );
1214 assert_eq!(
1215 GeneralPurposePduCategory::from_str("DOIP").unwrap(),
1216 GeneralPurposePduCategory::DoIp
1217 );
1218 assert!(GeneralPurposePduCategory::from_str("invalid").is_err());
1219 }
1220
1221 #[test]
1222 fn create_general_purpose_ipdu() {
1223 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1224 let package = model.get_or_create_package("/pkg").unwrap();
1225 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1226
1227 let gp_ipdu1 = system
1228 .create_general_purpose_ipdu("gp_ipdu1", &package, 1, GeneralPurposeIPduCategory::Xcp)
1229 .unwrap();
1230 assert_eq!(gp_ipdu1.category().unwrap(), GeneralPurposeIPduCategory::Xcp);
1231
1232 let gp_ipdu2 = system
1233 .create_general_purpose_ipdu("gp_ipdu2", &package, 1, GeneralPurposeIPduCategory::SomeipSegmentedIpdu)
1234 .unwrap();
1235 assert_eq!(
1236 gp_ipdu2.category().unwrap(),
1237 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1238 );
1239
1240 let gp_ipdu3 = system
1241 .create_general_purpose_ipdu("gp_ipdu3", &package, 1, GeneralPurposeIPduCategory::Dlt)
1242 .unwrap();
1243 assert_eq!(gp_ipdu3.category().unwrap(), GeneralPurposeIPduCategory::Dlt);
1244
1245 assert_eq!(
1247 GeneralPurposeIPduCategory::from_str("XCP").unwrap(),
1248 GeneralPurposeIPduCategory::Xcp
1249 );
1250 assert_eq!(
1251 GeneralPurposeIPduCategory::from_str("SOMEIP_SEGMENTED_IPDU").unwrap(),
1252 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1253 );
1254 assert_eq!(
1255 GeneralPurposeIPduCategory::from_str("DLT").unwrap(),
1256 GeneralPurposeIPduCategory::Dlt
1257 );
1258 assert!(GeneralPurposeIPduCategory::from_str("invalid").is_err());
1259 }
1260
1261 #[test]
1262 fn ipdu() {
1263 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1264 let package = model.get_or_create_package("/pkg").unwrap();
1265 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1266
1267 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1268 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
1269 let dcm_ipdu = system
1270 .create_dcm_ipdu("dcm_ipdu", &package, 1, DiagPduType::DiagResponse)
1271 .unwrap();
1272 let gp_ipdu = system
1273 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
1274 .unwrap();
1275 let container_ipdu = system
1276 .create_container_ipdu(
1277 "container_ipdu",
1278 &package,
1279 1,
1280 ContainerIPduHeaderType::LongHeader,
1281 RxAcceptContainedIPdu::AcceptConfigured,
1282 )
1283 .unwrap();
1284 let secured_ipdu = system
1285 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
1286 .unwrap();
1287 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1288
1289 let ipdu: IPdu = isignal_ipdu.clone().into();
1290 assert_eq!(ipdu.element(), isignal_ipdu.element());
1291 assert!(matches!(ipdu, IPdu::ISignalIPdu(_)));
1292
1293 let ipdu: IPdu = n_pdu.clone().into();
1296 assert_eq!(ipdu.element(), n_pdu.element());
1297 assert!(matches!(ipdu, IPdu::NPdu(_)));
1298
1299 let ipdu: IPdu = dcm_ipdu.clone().into();
1300 assert_eq!(ipdu.element(), dcm_ipdu.element());
1301 assert!(matches!(ipdu, IPdu::DcmIPdu(_)));
1302
1303 let ipdu: IPdu = n_pdu.clone().into();
1304 assert_eq!(ipdu.element(), n_pdu.element());
1305 assert!(matches!(ipdu, IPdu::NPdu(_)));
1306
1307 let ipdu: IPdu = gp_ipdu.clone().into();
1310 assert_eq!(ipdu.element(), gp_ipdu.element());
1311 assert!(matches!(ipdu, IPdu::GeneralPurposeIPdu(_)));
1312
1313 let ipdu: IPdu = container_ipdu.clone().into();
1314 assert_eq!(ipdu.element(), container_ipdu.element());
1315 assert!(matches!(ipdu, IPdu::ContainerIPdu(_)));
1316
1317 let ipdu: IPdu = secured_ipdu.clone().into();
1318 assert_eq!(ipdu.element(), secured_ipdu.element());
1319 assert!(matches!(ipdu, IPdu::SecuredIPdu(_)));
1320
1321 let ipdu: IPdu = multiplexed_ipdu.clone().into();
1322 assert_eq!(ipdu.element(), multiplexed_ipdu.element());
1323 assert!(matches!(ipdu, IPdu::MultiplexedIPdu(_)));
1324
1325 let pdu: Pdu = ipdu.clone().into();
1327 assert_eq!(pdu.element(), ipdu.element());
1328 }
1329}