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 pub fn set_static_part(&self, static_ipdu: &ISignalIPdu) -> Result<(), AutosarAbstractionError> {
571 let prev_static_part = self.static_part();
572
573 self.element()
574 .get_or_create_sub_element(ElementName::StaticParts)?
575 .get_or_create_sub_element(ElementName::StaticPart)?
576 .get_or_create_sub_element(ElementName::IPduRef)?
577 .set_reference_target(static_ipdu.element())?;
578
579 self.update_pdu_triggerings(prev_static_part.as_ref(), static_ipdu)?;
580
581 Ok(())
582 }
583
584 #[must_use]
586 pub fn static_part(&self) -> Option<ISignalIPdu> {
587 let ipdu_elem = self
588 .element()
589 .get_sub_element(ElementName::StaticParts)?
590 .get_sub_element(ElementName::StaticPart)?
591 .get_sub_element(ElementName::IPduRef)?
592 .get_reference_target()
593 .ok()?;
594 ISignalIPdu::try_from(ipdu_elem).ok()
595 }
596
597 pub fn add_dynamic_part(
603 &self,
604 dynamic_ipdu: &ISignalIPdu,
605 selector_code: u16,
606 initial_dynamic_part: bool,
607 ) -> Result<DynamicPartAlternative, AutosarAbstractionError> {
608 let dp_alternatives = self
609 .element()
610 .get_or_create_sub_element(ElementName::DynamicParts)?
611 .get_or_create_sub_element(ElementName::DynamicPart)?
612 .get_or_create_sub_element(ElementName::DynamicPartAlternatives)?;
613
614 DynamicPartAlternative::new(&dp_alternatives, dynamic_ipdu, selector_code, initial_dynamic_part)
615 }
616
617 pub fn dynamic_part_alternatives(&self) -> impl Iterator<Item = DynamicPartAlternative> {
619 let dp_alternatives_elem = self
620 .element()
621 .get_sub_element(ElementName::DynamicParts)
622 .and_then(|e| e.get_sub_element(ElementName::DynamicPart))
623 .and_then(|e| e.get_sub_element(ElementName::DynamicPartAlternatives));
624
625 dp_alternatives_elem
626 .into_iter()
627 .flat_map(|e| e.sub_elements())
628 .filter_map(|elem| DynamicPartAlternative::try_from(elem).ok())
629 }
630
631 pub fn set_selector_field(
635 &self,
636 length: u8,
637 start_position: u32,
638 byte_order: ByteOrder,
639 ) -> Result<(), AutosarAbstractionError> {
640 if length == 0 || length > 16 {
641 return Err(AutosarAbstractionError::InvalidParameter(
642 "selector field length must be between 1 and 16".to_string(),
643 ));
644 }
645 self.element()
646 .get_or_create_sub_element(ElementName::SelectorFieldLength)?
647 .set_character_data(length as u64)?;
648 self.element()
649 .get_or_create_sub_element(ElementName::SelectorFieldStartPosition)?
650 .set_character_data(start_position as u64)?;
651 self.element()
652 .get_or_create_sub_element(ElementName::SelectorFieldByteOrder)?
653 .set_character_data::<EnumItem>(byte_order.into())?;
654 Ok(())
655 }
656
657 pub fn selector_field(&self) -> Option<(u8, u32, ByteOrder)> {
659 let length = self
660 .element()
661 .get_sub_element(ElementName::SelectorFieldLength)?
662 .character_data()?
663 .parse_integer()?;
664 let start_position = self
665 .element()
666 .get_sub_element(ElementName::SelectorFieldStartPosition)?
667 .character_data()?
668 .parse_integer()?;
669 let byte_order_enum = self
670 .element()
671 .get_sub_element(ElementName::SelectorFieldByteOrder)?
672 .character_data()?
673 .enum_value()?;
674 let byte_order = ByteOrder::try_from(byte_order_enum).ok()?;
675 Some((length, start_position, byte_order))
676 }
677
678 pub(crate) fn update_pdu_triggerings(
681 &self,
682 old_ipdu: Option<&ISignalIPdu>,
683 new_ipdu: &ISignalIPdu,
684 ) -> Result<(), AutosarAbstractionError> {
685 if let Some(old_ipdu) = old_ipdu {
688 for pt in old_ipdu.pdu_triggerings() {
689 if let Ok(Some(pt_parent)) = pt.element().parent() {
691 let _ = pt_parent.remove_sub_element(pt.element().clone());
692 }
693 }
694 }
695
696 for multiplex_pt in self.pdu_triggerings() {
698 if let Ok(channel) = multiplex_pt.physical_channel() {
699 let new_pt = PduTriggering::new(&Pdu::ISignalIPdu(new_ipdu.clone()), &channel)?;
700 for pp in multiplex_pt.pdu_ports() {
701 if let (Ok(ecu), Some(direction)) = (pp.ecu(), pp.communication_direction()) {
702 let _ = new_pt.create_pdu_port(&ecu, direction);
703 }
704 }
705 }
706 }
707
708 Ok(())
709 }
710}
711
712impl AbstractPdu for MultiplexedIPdu {}
713
714impl AbstractIpdu for MultiplexedIPdu {}
715
716impl From<MultiplexedIPdu> for Pdu {
717 fn from(value: MultiplexedIPdu) -> Self {
718 Pdu::MultiplexedIPdu(value)
719 }
720}
721
722impl From<MultiplexedIPdu> for IPdu {
723 fn from(value: MultiplexedIPdu) -> Self {
724 IPdu::MultiplexedIPdu(value)
725 }
726}
727
728#[derive(Debug, Clone, PartialEq, Eq, Hash)]
732pub struct DynamicPartAlternative(Element);
733abstraction_element!(DynamicPartAlternative, DynamicPartAlternative);
734
735impl DynamicPartAlternative {
736 fn new(
737 parent: &Element,
738 dynamic_ipdu: &ISignalIPdu,
739 selector_code: u16,
740 initial_dynamic_part: bool,
741 ) -> Result<Self, AutosarAbstractionError> {
742 let dp_alt_elem = parent.create_sub_element(ElementName::DynamicPartAlternative)?;
743 let dp_alt = Self(dp_alt_elem);
744 dp_alt.set_ipdu(dynamic_ipdu)?;
745 dp_alt.set_selector_field_code(selector_code)?;
746 dp_alt.set_initial_dynamic_part(initial_dynamic_part)?;
747
748 Ok(dp_alt)
749 }
750
751 pub fn set_ipdu(&self, ipdu: &ISignalIPdu) -> Result<(), AutosarAbstractionError> {
753 let old_ipdu = self.ipdu();
754 self.element()
755 .get_or_create_sub_element(ElementName::IPduRef)?
756 .set_reference_target(ipdu.element())?;
757
758 self.multiplexed_ipdu()?
759 .update_pdu_triggerings(old_ipdu.as_ref(), ipdu)?;
760
761 Ok(())
762 }
763
764 #[must_use]
766 pub fn ipdu(&self) -> Option<ISignalIPdu> {
767 let ipdu_elem = self
768 .element()
769 .get_sub_element(ElementName::IPduRef)?
770 .get_reference_target()
771 .ok()?;
772 ISignalIPdu::try_from(ipdu_elem).ok()
773 }
774
775 pub fn set_selector_field_code(&self, code: u16) -> Result<(), AutosarAbstractionError> {
777 self.element()
778 .get_or_create_sub_element(ElementName::SelectorFieldCode)?
779 .set_character_data(code as u64)?;
780 Ok(())
781 }
782
783 #[must_use]
785 pub fn selector_field_code(&self) -> Option<u16> {
786 self.element()
787 .get_sub_element(ElementName::SelectorFieldCode)?
788 .character_data()?
789 .parse_integer()
790 }
791
792 pub fn set_initial_dynamic_part(&self, initial: bool) -> Result<(), AutosarAbstractionError> {
794 self.element()
795 .get_or_create_sub_element(ElementName::InitialDynamicPart)?
796 .set_character_data(initial)?;
797 Ok(())
798 }
799
800 #[must_use]
802 pub fn is_initial_dynamic_part(&self) -> Option<bool> {
803 self.element()
804 .get_sub_element(ElementName::InitialDynamicPart)?
805 .character_data()?
806 .parse_bool()
807 }
808
809 pub fn multiplexed_ipdu(&self) -> Result<MultiplexedIPdu, AutosarAbstractionError> {
811 let parent_elem = self.element().named_parent()?;
812 let parent_elem = parent_elem.unwrap(); MultiplexedIPdu::try_from(parent_elem)
814 }
815}
816
817#[derive(Debug, Clone, PartialEq, Eq, Hash)]
821pub enum Pdu {
822 ISignalIPdu(ISignalIPdu),
824 NmPdu(NmPdu),
826 NPdu(NPdu),
828 DcmIPdu(DcmIPdu),
830 GeneralPurposePdu(GeneralPurposePdu),
832 GeneralPurposeIPdu(GeneralPurposeIPdu),
834 ContainerIPdu(ContainerIPdu),
836 SecuredIPdu(SecuredIPdu),
838 MultiplexedIPdu(MultiplexedIPdu),
840}
841
842impl AbstractionElement for Pdu {
843 fn element(&self) -> &Element {
844 match self {
845 Pdu::ISignalIPdu(pdu) => pdu.element(),
846 Pdu::NmPdu(pdu) => pdu.element(),
847 Pdu::NPdu(pdu) => pdu.element(),
848 Pdu::DcmIPdu(pdu) => pdu.element(),
849 Pdu::GeneralPurposePdu(pdu) => pdu.element(),
850 Pdu::GeneralPurposeIPdu(pdu) => pdu.element(),
851 Pdu::ContainerIPdu(pdu) => pdu.element(),
852 Pdu::SecuredIPdu(pdu) => pdu.element(),
853 Pdu::MultiplexedIPdu(pdu) => pdu.element(),
854 }
855 }
856}
857
858impl TryFrom<Element> for Pdu {
859 type Error = AutosarAbstractionError;
860
861 fn try_from(element: Element) -> Result<Self, Self::Error> {
862 match element.element_name() {
863 ElementName::ISignalIPdu => Ok(ISignalIPdu::try_from(element)?.into()),
864 ElementName::NmPdu => Ok(NmPdu::try_from(element)?.into()),
865 ElementName::NPdu => Ok(NPdu::try_from(element)?.into()),
866 ElementName::DcmIPdu => Ok(DcmIPdu::try_from(element)?.into()),
867 ElementName::GeneralPurposePdu => Ok(GeneralPurposePdu::try_from(element)?.into()),
868 ElementName::GeneralPurposeIPdu => Ok(GeneralPurposeIPdu::try_from(element)?.into()),
869 ElementName::ContainerIPdu => Ok(ContainerIPdu::try_from(element)?.into()),
870 ElementName::SecuredIPdu => Ok(SecuredIPdu::try_from(element)?.into()),
871 ElementName::MultiplexedIPdu => Ok(MultiplexedIPdu::try_from(element)?.into()),
872 _ => Err(AutosarAbstractionError::ConversionError {
873 element,
874 dest: "Pdu".to_string(),
875 }),
876 }
877 }
878}
879
880impl IdentifiableAbstractionElement for Pdu {}
881impl AbstractPdu for Pdu {}
882
883#[derive(Debug, Clone, PartialEq, Eq, Hash)]
887pub enum IPdu {
888 ISignalIPdu(ISignalIPdu),
890 NPdu(NPdu),
892 DcmIPdu(DcmIPdu),
894 GeneralPurposeIPdu(GeneralPurposeIPdu),
896 ContainerIPdu(ContainerIPdu),
898 SecuredIPdu(SecuredIPdu),
900 MultiplexedIPdu(MultiplexedIPdu),
902}
903
904impl AbstractionElement for IPdu {
905 fn element(&self) -> &Element {
906 match self {
907 IPdu::ISignalIPdu(pdu) => pdu.element(),
908 IPdu::NPdu(pdu) => pdu.element(),
909 IPdu::DcmIPdu(pdu) => pdu.element(),
910 IPdu::GeneralPurposeIPdu(pdu) => pdu.element(),
911 IPdu::ContainerIPdu(pdu) => pdu.element(),
912 IPdu::SecuredIPdu(pdu) => pdu.element(),
913 IPdu::MultiplexedIPdu(pdu) => pdu.element(),
914 }
915 }
916}
917
918impl TryFrom<Element> for IPdu {
919 type Error = AutosarAbstractionError;
920
921 fn try_from(element: Element) -> Result<Self, Self::Error> {
922 match element.element_name() {
923 ElementName::ISignalIPdu => Ok(IPdu::ISignalIPdu(ISignalIPdu::try_from(element)?)),
924 ElementName::NPdu => Ok(IPdu::NPdu(NPdu::try_from(element)?)),
925 ElementName::DcmIPdu => Ok(IPdu::DcmIPdu(DcmIPdu::try_from(element)?)),
926 ElementName::GeneralPurposeIPdu => Ok(IPdu::GeneralPurposeIPdu(GeneralPurposeIPdu::try_from(element)?)),
927 ElementName::ContainerIPdu => Ok(IPdu::ContainerIPdu(ContainerIPdu::try_from(element)?)),
928 ElementName::SecuredIPdu => Ok(IPdu::SecuredIPdu(SecuredIPdu::try_from(element)?)),
929 ElementName::MultiplexedIPdu => Ok(IPdu::MultiplexedIPdu(MultiplexedIPdu::try_from(element)?)),
930 _ => Err(AutosarAbstractionError::ConversionError {
931 element,
932 dest: "IPdu".to_string(),
933 }),
934 }
935 }
936}
937
938impl From<IPdu> for Pdu {
939 fn from(value: IPdu) -> Self {
940 match value {
941 IPdu::ISignalIPdu(pdu) => Pdu::ISignalIPdu(pdu),
942 IPdu::NPdu(pdu) => Pdu::NPdu(pdu),
943 IPdu::DcmIPdu(pdu) => Pdu::DcmIPdu(pdu),
944 IPdu::GeneralPurposeIPdu(pdu) => Pdu::GeneralPurposeIPdu(pdu),
945 IPdu::ContainerIPdu(pdu) => Pdu::ContainerIPdu(pdu),
946 IPdu::SecuredIPdu(pdu) => Pdu::SecuredIPdu(pdu),
947 IPdu::MultiplexedIPdu(pdu) => Pdu::MultiplexedIPdu(pdu),
948 }
949 }
950}
951
952impl IdentifiableAbstractionElement for IPdu {}
953impl AbstractPdu for IPdu {}
954impl AbstractIpdu for IPdu {}
955
956#[derive(Debug, Clone, PartialEq, Eq, Hash)]
960pub struct PduTriggering(Element);
961abstraction_element!(PduTriggering, PduTriggering);
962impl IdentifiableAbstractionElement for PduTriggering {}
963
964impl PduTriggering {
965 pub(crate) fn new(pdu: &Pdu, channel: &PhysicalChannel) -> Result<Self, AutosarAbstractionError> {
966 let model = channel.element().model()?;
967 let base_path = channel.element().path()?;
968 let pdu_name = pdu
969 .name()
970 .ok_or(AutosarAbstractionError::InvalidParameter("invalid pdu".to_string()))?;
971 let pt_name = format!("PT_{pdu_name}");
972 let pt_name = make_unique_name(&model, &base_path, &pt_name);
973
974 let triggerings = channel
975 .element()
976 .get_or_create_sub_element(ElementName::PduTriggerings)?;
977 let pt_elem = triggerings.create_named_sub_element(ElementName::PduTriggering, &pt_name)?;
978 pt_elem
979 .create_sub_element(ElementName::IPduRef)?
980 .set_reference_target(pdu.element())?;
981
982 let pt = Self(pt_elem);
983
984 if let Pdu::ISignalIPdu(isignal_ipdu) = pdu {
985 for signal_mapping in isignal_ipdu.mapped_signals() {
986 if let Some(signal) = signal_mapping.signal() {
987 pt.create_signal_triggering(&signal)?;
988 } else if let Some(signal_group) = signal_mapping.signal_group() {
989 pt.create_signal_group_triggering(&signal_group)?;
990 }
991 }
992 }
993
994 Ok(pt)
995 }
996
997 #[must_use]
999 pub fn pdu(&self) -> Option<Pdu> {
1000 let pdu_elem = self
1001 .element()
1002 .get_sub_element(ElementName::IPduRef)?
1003 .get_reference_target()
1004 .ok()?;
1005 Pdu::try_from(pdu_elem).ok()
1006 }
1007
1008 pub fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
1010 let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
1011 PhysicalChannel::try_from(channel_elem)
1012 }
1013
1014 pub fn create_pdu_port(
1016 &self,
1017 ecu: &EcuInstance,
1018 direction: CommunicationDirection,
1019 ) -> Result<IPduPort, AutosarAbstractionError> {
1020 for pdu_port in self.pdu_ports() {
1021 if let (Ok(existing_ecu), Some(existing_direction)) = (pdu_port.ecu(), pdu_port.communication_direction())
1022 && existing_ecu == *ecu
1023 && existing_direction == direction
1024 {
1025 return Ok(pdu_port);
1026 }
1027 }
1028
1029 let channel = self.physical_channel()?;
1030 let connector = channel
1031 .ecu_connector(ecu)
1032 .ok_or(AutosarAbstractionError::InvalidParameter(
1033 "The ECU is not connected to the channel".to_string(),
1034 ))?;
1035
1036 let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
1037 let suffix = match direction {
1038 CommunicationDirection::In => "Rx",
1039 CommunicationDirection::Out => "Tx",
1040 };
1041 let port_name = format!("{name}_{suffix}",);
1042 let pp_elem = connector
1043 .element()
1044 .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
1045 .create_named_sub_element(ElementName::IPduPort, &port_name)?;
1046 pp_elem
1047 .create_sub_element(ElementName::CommunicationDirection)?
1048 .set_character_data::<EnumItem>(direction.into())?;
1049
1050 self.element()
1051 .get_or_create_sub_element(ElementName::IPduPortRefs)?
1052 .create_sub_element(ElementName::IPduPortRef)?
1053 .set_reference_target(&pp_elem)?;
1054
1055 for st in self.signal_triggerings() {
1056 st.connect_to_ecu(ecu, direction)?;
1057 }
1058
1059 Ok(IPduPort(pp_elem))
1060 }
1061
1062 pub fn pdu_ports(&self) -> impl Iterator<Item = IPduPort> + Send + use<> {
1064 self.element()
1065 .get_sub_element(ElementName::IPduPortRefs)
1066 .into_iter()
1067 .flat_map(|ipprefs| ipprefs.sub_elements())
1068 .filter_map(|ippref| {
1069 ippref
1070 .get_reference_target()
1071 .ok()
1072 .and_then(|elem| IPduPort::try_from(elem).ok())
1073 })
1074 }
1075
1076 pub fn signal_triggerings(&self) -> impl Iterator<Item = ISignalTriggering> + Send + use<> {
1078 self.element()
1079 .get_sub_element(ElementName::ISignalTriggerings)
1080 .into_iter()
1081 .flat_map(|ists| ists.sub_elements())
1082 .filter_map(|ist| {
1083 ist.get_sub_element(ElementName::ISignalTriggeringRef)
1084 .and_then(|str| str.get_reference_target().ok())
1085 .and_then(|elem| ISignalTriggering::try_from(elem).ok())
1086 })
1087 }
1088
1089 pub(crate) fn create_signal_triggering(
1091 &self,
1092 signal: &ISignal,
1093 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
1094 let channel = self.physical_channel()?;
1095 let st = ISignalTriggering::new(signal, &channel)?;
1096 let triggerings = self
1097 .element()
1098 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
1099 triggerings
1100 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
1101 .create_sub_element(ElementName::ISignalTriggeringRef)?
1102 .set_reference_target(st.element())?;
1103
1104 for pdu_port in self.pdu_ports() {
1105 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
1106 st.connect_to_ecu(&ecu, direction)?;
1107 }
1108 }
1109
1110 Ok(st)
1111 }
1112
1113 pub(crate) fn create_signal_group_triggering(
1115 &self,
1116 signal_group: &ISignalGroup,
1117 ) -> Result<ISignalTriggering, AutosarAbstractionError> {
1118 let channel = self.physical_channel()?;
1119 let st = ISignalTriggering::new_group(signal_group, &channel)?;
1120 let triggerings = self
1121 .element()
1122 .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
1123 triggerings
1124 .create_sub_element(ElementName::ISignalTriggeringRefConditional)?
1125 .create_sub_element(ElementName::ISignalTriggeringRef)?
1126 .set_reference_target(st.element())?;
1127
1128 for pdu_port in self.pdu_ports() {
1129 if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
1130 st.connect_to_ecu(&ecu, direction)?;
1131 }
1132 }
1133
1134 Ok(st)
1135 }
1136}
1137
1138#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1142pub struct IPduPort(Element);
1143abstraction_element!(IPduPort, IPduPort);
1144impl IdentifiableAbstractionElement for IPduPort {}
1145
1146impl IPduPort {
1147 pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
1149 let comm_connector_elem = self.element().named_parent()?.unwrap();
1150 let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
1151 EcuInstance::try_from(ecu_elem)
1152 }
1153
1154 pub fn set_communication_direction(
1156 &self,
1157 direction: CommunicationDirection,
1158 ) -> Result<(), AutosarAbstractionError> {
1159 self.element()
1160 .get_or_create_sub_element(ElementName::CommunicationDirection)?
1161 .set_character_data::<EnumItem>(direction.into())?;
1162 Ok(())
1163 }
1164
1165 #[must_use]
1167 pub fn communication_direction(&self) -> Option<CommunicationDirection> {
1168 self.element()
1169 .get_sub_element(ElementName::CommunicationDirection)?
1170 .character_data()?
1171 .enum_value()?
1172 .try_into()
1173 .ok()
1174 }
1175}
1176
1177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1182pub enum PduCollectionTrigger {
1183 Always,
1185 Never,
1187}
1188
1189impl From<PduCollectionTrigger> for EnumItem {
1190 fn from(value: PduCollectionTrigger) -> Self {
1191 match value {
1192 PduCollectionTrigger::Always => EnumItem::Always,
1193 PduCollectionTrigger::Never => EnumItem::Never,
1194 }
1195 }
1196}
1197
1198impl TryFrom<EnumItem> for PduCollectionTrigger {
1199 type Error = AutosarAbstractionError;
1200
1201 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
1202 match value {
1203 EnumItem::Always => Ok(PduCollectionTrigger::Always),
1204 EnumItem::Never => Ok(PduCollectionTrigger::Never),
1205 _ => Err(AutosarAbstractionError::ValueConversionError {
1206 value: value.to_string(),
1207 dest: "PduCollectionTrigger".to_string(),
1208 }),
1209 }
1210 }
1211}
1212
1213#[cfg(test)]
1216mod test {
1217 use super::*;
1218 use crate::{
1219 AutosarModelAbstraction, ByteOrder, SystemCategory,
1220 communication::{AbstractFrame, AbstractFrameTriggering, CanAddressingMode, CanFrameType, TransferProperty},
1221 };
1222 use autosar_data::AutosarVersion;
1223
1224 #[test]
1225 fn test_pdus() {
1226 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1227 let package = model.get_or_create_package("/pkg").unwrap();
1228 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1229
1230 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1231 let nm_pdu = system.create_nm_pdu("nm_pdu", &package, 1).unwrap();
1232 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
1233 let dcm_ipdu = system
1234 .create_dcm_ipdu("dcm_ipdu", &package, 1, DiagPduType::DiagRequest)
1235 .unwrap();
1236 let gp_pdu = system
1237 .create_general_purpose_pdu("gp_pdu", &package, 1, GeneralPurposePduCategory::Sd)
1238 .unwrap();
1239 let gp_ipdu = system
1240 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
1241 .unwrap();
1242 let container_ipdu = system
1243 .create_container_ipdu(
1244 "container_ipdu",
1245 &package,
1246 1,
1247 ContainerIPduHeaderType::ShortHeader,
1248 RxAcceptContainedIPdu::AcceptAll,
1249 )
1250 .unwrap();
1251 let secured_ipdu = system
1252 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
1253 .unwrap();
1254 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1255
1256 assert_eq!(isignal_ipdu.length().unwrap(), 1);
1257 assert_eq!(nm_pdu.length().unwrap(), 1);
1258 assert_eq!(n_pdu.length().unwrap(), 1);
1259 assert_eq!(dcm_ipdu.length().unwrap(), 1);
1260 assert_eq!(gp_pdu.length().unwrap(), 1);
1261 assert_eq!(gp_ipdu.length().unwrap(), 1);
1262 assert_eq!(container_ipdu.length().unwrap(), 1);
1263 assert_eq!(secured_ipdu.length().unwrap(), 1);
1264 assert_eq!(multiplexed_ipdu.length().unwrap(), 1);
1265
1266 isignal_ipdu.set_length(2).unwrap();
1267 assert_eq!(isignal_ipdu.length().unwrap(), 2);
1268
1269 let frame = system.create_flexray_frame("frame1", &package, 64).unwrap();
1270 frame
1271 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
1272 .unwrap();
1273 frame
1274 .map_pdu(&nm_pdu, 8, ByteOrder::MostSignificantByteLast, None)
1275 .unwrap();
1276 frame
1277 .map_pdu(&n_pdu, 16, ByteOrder::MostSignificantByteLast, None)
1278 .unwrap();
1279 frame
1280 .map_pdu(&dcm_ipdu, 24, ByteOrder::MostSignificantByteLast, None)
1281 .unwrap();
1282 frame
1283 .map_pdu(&gp_pdu, 32, ByteOrder::MostSignificantByteLast, None)
1284 .unwrap();
1285 frame
1286 .map_pdu(&gp_ipdu, 40, ByteOrder::MostSignificantByteLast, None)
1287 .unwrap();
1288 frame
1289 .map_pdu(&container_ipdu, 48, ByteOrder::MostSignificantByteLast, None)
1290 .unwrap();
1291 frame
1292 .map_pdu(&secured_ipdu, 56, ByteOrder::MostSignificantByteLast, None)
1293 .unwrap();
1294 frame
1295 .map_pdu(&multiplexed_ipdu, 64, ByteOrder::MostSignificantByteLast, None)
1296 .unwrap();
1297
1298 let mut pdus_iter = frame.mapped_pdus();
1299 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "isignal_ipdu");
1300 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "nm_pdu");
1301 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "n_pdu");
1302 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "dcm_ipdu");
1303 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_pdu");
1304 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "gp_ipdu");
1305 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "container_ipdu");
1306 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "secured_ipdu");
1307 assert_eq!(pdus_iter.next().unwrap().name().unwrap(), "multiplexed_ipdu");
1308 assert!(pdus_iter.next().is_none());
1309 }
1310
1311 #[test]
1312 fn test_pdu_triggering() {
1313 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1314 let package = model.get_or_create_package("/pkg").unwrap();
1315 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1316
1317 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1319 let syssignal = package.create_system_signal("syssignal").unwrap();
1320 let isignal = system.create_isignal("isignal", &package, 1, &syssignal, None).unwrap();
1321 isignal_ipdu
1322 .map_signal(
1323 &isignal,
1324 0,
1325 ByteOrder::MostSignificantByteLast,
1326 None,
1327 TransferProperty::Triggered,
1328 )
1329 .unwrap();
1330 let syssignal_group = package.create_system_signal_group("syssignal_group").unwrap();
1332 let isignal_group = system
1333 .create_isignal_group("isignal_group", &package, &syssignal_group)
1334 .unwrap();
1335 let syssignal2 = package.create_system_signal("syssignal2").unwrap();
1336 let isignal2 = system
1337 .create_isignal("isignal2", &package, 1, &syssignal2, None)
1338 .unwrap();
1339 isignal_ipdu.map_signal_group(&isignal_group).unwrap();
1340 isignal_ipdu
1341 .map_signal(
1342 &isignal2,
1343 1,
1344 ByteOrder::MostSignificantByteLast,
1345 None,
1346 TransferProperty::Triggered,
1347 )
1348 .unwrap();
1349
1350 let can_cluster = system.create_can_cluster("Cluster", &package, None).unwrap();
1352 let channel = can_cluster.create_physical_channel("Channel").unwrap();
1353 let frame = system.create_can_frame("frame", &package, 8).unwrap();
1354 let frame_triggering = channel
1355 .trigger_frame(&frame, 0x123, CanAddressingMode::Standard, CanFrameType::Can20)
1356 .unwrap();
1357 let _mapping = frame
1358 .map_pdu(&isignal_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
1359 .unwrap();
1360
1361 let ecu = system.create_ecu_instance("ecu", &package).unwrap();
1363 let controller = ecu.create_can_communication_controller("controller").unwrap();
1364 controller.connect_physical_channel("connection", &channel).unwrap();
1365 frame_triggering
1366 .connect_to_ecu(&ecu, CommunicationDirection::In)
1367 .unwrap();
1368
1369 let pdu_triggering = frame_triggering.pdu_triggerings().next().unwrap();
1370 assert_eq!(pdu_triggering.pdu_ports().count(), 1);
1371 assert_eq!(pdu_triggering.signal_triggerings().count(), 3); let pdu_port = pdu_triggering.pdu_ports().next().unwrap();
1374 assert_eq!(pdu_port.ecu().unwrap().name().unwrap(), "ecu");
1375 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::In);
1376 pdu_port
1377 .set_communication_direction(CommunicationDirection::Out)
1378 .unwrap();
1379 assert_eq!(pdu_port.communication_direction().unwrap(), CommunicationDirection::Out);
1380 pdu_port.set_name("new_name").unwrap();
1381 assert_eq!(pdu_port.name().unwrap(), "new_name");
1382 }
1383
1384 #[test]
1385 fn nm_pdu() {
1386 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00052);
1387 let package = model.get_or_create_package("/pkg").unwrap();
1388 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1389
1390 let nm_pdu = system.create_nm_pdu("nm_pdu", &package, 1).unwrap();
1391 assert_eq!(nm_pdu.length().unwrap(), 1);
1392
1393 nm_pdu.set_length(8).unwrap();
1394 assert_eq!(nm_pdu.length().unwrap(), 8);
1395
1396 nm_pdu.set_unused_bit_pattern(0xff).unwrap();
1397 assert_eq!(nm_pdu.unused_bit_pattern().unwrap(), 0xff);
1398
1399 let syssignal = package.create_system_signal("sys_userdata").unwrap();
1401 let isignal = system
1402 .create_isignal("userdata", &package, 16, &syssignal, None)
1403 .unwrap();
1404 let mapping = nm_pdu
1405 .map_signal(
1406 &isignal,
1407 0,
1408 ByteOrder::MostSignificantByteFirst,
1409 Some(16),
1410 TransferProperty::Triggered,
1411 )
1412 .unwrap();
1413 assert_eq!(mapping.signal().unwrap(), isignal);
1414 }
1415
1416 #[test]
1417 fn general_purpose_pdu() {
1418 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1419 let package = model.get_or_create_package("/pkg").unwrap();
1420 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1421
1422 let gp_pdu1 = system
1423 .create_general_purpose_pdu("gp_pdu1", &package, 1, GeneralPurposePduCategory::Sd)
1424 .unwrap();
1425 assert_eq!(gp_pdu1.category().unwrap(), GeneralPurposePduCategory::Sd);
1426
1427 let gp_pdu2 = system
1428 .create_general_purpose_pdu("gp_pdu2", &package, 1, GeneralPurposePduCategory::GlobalTime)
1429 .unwrap();
1430 assert_eq!(gp_pdu2.category().unwrap(), GeneralPurposePduCategory::GlobalTime);
1431
1432 let gp_pdu3 = system
1433 .create_general_purpose_pdu("gp_pdu3", &package, 1, GeneralPurposePduCategory::DoIp)
1434 .unwrap();
1435 assert_eq!(gp_pdu3.category().unwrap(), GeneralPurposePduCategory::DoIp);
1436
1437 assert_eq!(
1439 GeneralPurposePduCategory::from_str("SD").unwrap(),
1440 GeneralPurposePduCategory::Sd
1441 );
1442 assert_eq!(
1443 GeneralPurposePduCategory::from_str("GLOBAL_TIME").unwrap(),
1444 GeneralPurposePduCategory::GlobalTime
1445 );
1446 assert_eq!(
1447 GeneralPurposePduCategory::from_str("DOIP").unwrap(),
1448 GeneralPurposePduCategory::DoIp
1449 );
1450 assert!(GeneralPurposePduCategory::from_str("invalid").is_err());
1451 }
1452
1453 #[test]
1454 fn general_purpose_ipdu() {
1455 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1456 let package = model.get_or_create_package("/pkg").unwrap();
1457 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1458
1459 let gp_ipdu1 = system
1460 .create_general_purpose_ipdu("gp_ipdu1", &package, 1, GeneralPurposeIPduCategory::Xcp)
1461 .unwrap();
1462 assert_eq!(gp_ipdu1.category().unwrap(), GeneralPurposeIPduCategory::Xcp);
1463
1464 let gp_ipdu2 = system
1465 .create_general_purpose_ipdu("gp_ipdu2", &package, 1, GeneralPurposeIPduCategory::SomeipSegmentedIpdu)
1466 .unwrap();
1467 assert_eq!(
1468 gp_ipdu2.category().unwrap(),
1469 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1470 );
1471
1472 let gp_ipdu3 = system
1473 .create_general_purpose_ipdu("gp_ipdu3", &package, 1, GeneralPurposeIPduCategory::Dlt)
1474 .unwrap();
1475 assert_eq!(gp_ipdu3.category().unwrap(), GeneralPurposeIPduCategory::Dlt);
1476
1477 assert_eq!(
1479 GeneralPurposeIPduCategory::from_str("XCP").unwrap(),
1480 GeneralPurposeIPduCategory::Xcp
1481 );
1482 assert_eq!(
1483 GeneralPurposeIPduCategory::from_str("SOMEIP_SEGMENTED_IPDU").unwrap(),
1484 GeneralPurposeIPduCategory::SomeipSegmentedIpdu
1485 );
1486 assert_eq!(
1487 GeneralPurposeIPduCategory::from_str("DLT").unwrap(),
1488 GeneralPurposeIPduCategory::Dlt
1489 );
1490 assert!(GeneralPurposeIPduCategory::from_str("invalid").is_err());
1491 }
1492
1493 #[test]
1494 fn multiplexed_ipdu() {
1495 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1496 let package = model.get_or_create_package("/pkg").unwrap();
1497 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1498
1499 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1500 assert_eq!(multiplexed_ipdu.length().unwrap(), 1);
1501
1502 multiplexed_ipdu.set_length(16).unwrap();
1503 assert_eq!(multiplexed_ipdu.length().unwrap(), 16);
1504
1505 let static_ipdu = system.create_isignal_ipdu("static_ipdu", &package, 8).unwrap();
1506 multiplexed_ipdu.set_static_part(&static_ipdu).unwrap();
1507 assert_eq!(multiplexed_ipdu.static_part().unwrap(), static_ipdu);
1508
1509 let dynamic_ipdu = system.create_isignal_ipdu("dynamic_ipdu", &package, 8).unwrap();
1510 let dp_alt = multiplexed_ipdu.add_dynamic_part(&dynamic_ipdu, 0, true).unwrap();
1511 assert_eq!(dp_alt.ipdu().unwrap(), dynamic_ipdu);
1512 assert_eq!(dp_alt.selector_field_code().unwrap(), 0);
1513 assert_eq!(dp_alt.is_initial_dynamic_part().unwrap(), true);
1514 assert_eq!(dp_alt.multiplexed_ipdu().unwrap(), multiplexed_ipdu);
1515 assert_eq!(multiplexed_ipdu.dynamic_part_alternatives().count(), 1);
1516
1517 multiplexed_ipdu
1518 .set_selector_field(8, 16, ByteOrder::MostSignificantByteFirst)
1519 .unwrap();
1520 let (start_bit, length, byte_order) = multiplexed_ipdu.selector_field().unwrap();
1521 assert_eq!(start_bit, 8);
1522 assert_eq!(length, 16);
1523 assert_eq!(byte_order, ByteOrder::MostSignificantByteFirst);
1524
1525 let cluster = system.create_can_cluster("cluster", &package, None).unwrap();
1526 let channel = cluster.create_physical_channel("channel").unwrap();
1527 let frame = system.create_can_frame("frame", &package, 64).unwrap();
1528 channel
1529 .trigger_frame(&frame, 0x33, CanAddressingMode::Standard, CanFrameType::CanFd)
1530 .unwrap();
1531 let _mapping = frame
1532 .map_pdu(&multiplexed_ipdu, 0, ByteOrder::MostSignificantByteLast, None)
1533 .unwrap();
1534
1535 assert_eq!(channel.frame_triggerings().count(), 1);
1536 assert_eq!(channel.pdu_triggerings().count(), 3); }
1538
1539 #[test]
1540 fn ipdu() {
1541 let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
1542 let package = model.get_or_create_package("/pkg").unwrap();
1543 let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1544
1545 let isignal_ipdu = system.create_isignal_ipdu("isignal_ipdu", &package, 1).unwrap();
1546 let n_pdu = system.create_n_pdu("n_pdu", &package, 1).unwrap();
1547 let dcm_ipdu = system
1548 .create_dcm_ipdu("dcm_ipdu", &package, 1, DiagPduType::DiagResponse)
1549 .unwrap();
1550 let gp_ipdu = system
1551 .create_general_purpose_ipdu("gp_ipdu", &package, 1, GeneralPurposeIPduCategory::Xcp)
1552 .unwrap();
1553 let container_ipdu = system
1554 .create_container_ipdu(
1555 "container_ipdu",
1556 &package,
1557 1,
1558 ContainerIPduHeaderType::LongHeader,
1559 RxAcceptContainedIPdu::AcceptConfigured,
1560 )
1561 .unwrap();
1562 let secured_ipdu = system
1563 .create_secured_ipdu("secured_ipdu", &package, 1, &SecureCommunicationProps::default())
1564 .unwrap();
1565 let multiplexed_ipdu = system.create_multiplexed_ipdu("multiplexed_ipdu", &package, 1).unwrap();
1566
1567 let ipdu: IPdu = isignal_ipdu.clone().into();
1568 assert_eq!(ipdu.element(), isignal_ipdu.element());
1569 assert!(matches!(ipdu, IPdu::ISignalIPdu(_)));
1570
1571 let ipdu: IPdu = n_pdu.clone().into();
1574 assert_eq!(ipdu.element(), n_pdu.element());
1575 assert!(matches!(ipdu, IPdu::NPdu(_)));
1576
1577 let ipdu: IPdu = dcm_ipdu.clone().into();
1578 assert_eq!(ipdu.element(), dcm_ipdu.element());
1579 assert!(matches!(ipdu, IPdu::DcmIPdu(_)));
1580
1581 let ipdu: IPdu = n_pdu.clone().into();
1582 assert_eq!(ipdu.element(), n_pdu.element());
1583 assert!(matches!(ipdu, IPdu::NPdu(_)));
1584
1585 let ipdu: IPdu = gp_ipdu.clone().into();
1588 assert_eq!(ipdu.element(), gp_ipdu.element());
1589 assert!(matches!(ipdu, IPdu::GeneralPurposeIPdu(_)));
1590
1591 let ipdu: IPdu = container_ipdu.clone().into();
1592 assert_eq!(ipdu.element(), container_ipdu.element());
1593 assert!(matches!(ipdu, IPdu::ContainerIPdu(_)));
1594
1595 let ipdu: IPdu = secured_ipdu.clone().into();
1596 assert_eq!(ipdu.element(), secured_ipdu.element());
1597 assert!(matches!(ipdu, IPdu::SecuredIPdu(_)));
1598
1599 let ipdu: IPdu = multiplexed_ipdu.clone().into();
1600 assert_eq!(ipdu.element(), multiplexed_ipdu.element());
1601 assert!(matches!(ipdu, IPdu::MultiplexedIPdu(_)));
1602
1603 let pdu: Pdu = ipdu.clone().into();
1605 assert_eq!(pdu.element(), ipdu.element());
1606 }
1607}