autosar_data_abstraction/communication/signal/
mod.rs

1use crate::communication::{
2    AbstractPhysicalChannel, CommunicationDirection, DataTransformation, EndToEndTransformationISignalProps,
3    PhysicalChannel, SomeIpTransformationISignalProps, TransformationTechnology,
4};
5use crate::datatype::{CompuMethod, DataConstr, SwBaseType, Unit, ValueSpecification};
6use crate::{
7    AbstractionElement, ArPackage, AutosarAbstractionError, EcuInstance, abstraction_element,
8    communication::ISignalToIPduMapping, make_unique_name,
9};
10use crate::{
11    IdentifiableAbstractionElement, SenderReceiverToSignalMapping, get_reference_parents, is_used,
12    is_used_system_element,
13};
14use autosar_data::{AutosarDataError, Element, ElementName, EnumItem, WeakElement};
15
16use super::TransformationISignalProps;
17
18/// Signal of the Interaction Layer
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct ISignal(Element);
21abstraction_element!(ISignal, ISignal);
22impl IdentifiableAbstractionElement for ISignal {}
23
24impl ISignal {
25    pub(crate) fn new(
26        name: &str,
27        package: &ArPackage,
28        bit_length: u64,
29        syssignal: &SystemSignal,
30        datatype: Option<&SwBaseType>,
31    ) -> Result<Self, AutosarAbstractionError> {
32        if bit_length > u64::from(u32::MAX) * 8 {
33            // max bit_length is 2^32 bytes
34            return Err(AutosarAbstractionError::InvalidParameter(format!(
35                "isignal {name}: bit length {bit_length} is too big"
36            )));
37        }
38
39        let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
40        let elem_isignal = pkg_elements.create_named_sub_element(ElementName::ISignal, name)?;
41
42        elem_isignal
43            .create_sub_element(ElementName::DataTypePolicy)?
44            .set_character_data(EnumItem::Override)?;
45
46        let isignal = Self(elem_isignal);
47        isignal.set_length(bit_length)?;
48        isignal.set_system_signal(syssignal)?;
49
50        if let Some(datatype) = datatype {
51            isignal.set_datatype(datatype)?;
52        }
53
54        Ok(isignal)
55    }
56
57    /// remove this `ISignal` from the model
58    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
59        let signal_mappings = self.mappings();
60        let signal_triggerings = self.signal_triggerings();
61
62        for transformation_prop in self.transformation_isignal_props() {
63            transformation_prop.remove(deep)?;
64        }
65
66        let data_transformations: Vec<DataTransformation> = self.data_transformations().collect();
67
68        let opt_signal_group = self.signal_group();
69        let opt_system_signal = self.system_signal();
70        let opt_datatype = self.datatype();
71
72        AbstractionElement::remove(self, deep)?;
73
74        // remove all mappings of this signal
75        for signal_mapping in signal_mappings {
76            signal_mapping.remove(deep)?;
77        }
78        // remove all triggerings of this signal
79        for signal_triggering in signal_triggerings {
80            signal_triggering.remove(deep)?;
81        }
82
83        if deep {
84            if let Some(signal_group) = opt_signal_group
85                && signal_group.signals().count() == 0
86            {
87                // remove the signal group if it became empty
88                signal_group.remove(deep)?;
89            }
90
91            if let Some(datatype) = opt_datatype
92                && !is_used(datatype.element())
93            {
94                // remove the data type if it is no longer used
95                datatype.remove(deep)?;
96            }
97
98            if let Some(system_signal) = opt_system_signal
99                && !is_used(system_signal.element())
100            {
101                // remove the system signal if it is no longer used
102                system_signal.remove(deep)?;
103            }
104
105            for data_transformation in data_transformations {
106                if !is_used(data_transformation.element()) {
107                    // remove unused data transformations
108                    data_transformation.remove(deep)?;
109                }
110            }
111        }
112
113        Ok(())
114    }
115
116    /// set the data type for this signal
117    pub fn set_datatype(&self, datatype: &SwBaseType) -> Result<(), AutosarAbstractionError> {
118        self.element()
119            .get_or_create_sub_element(ElementName::NetworkRepresentationProps)?
120            .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
121            .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
122            .get_or_create_sub_element(ElementName::BaseTypeRef)?
123            .set_reference_target(datatype.element())?;
124        Ok(())
125    }
126
127    /// get the data type of this signal
128    #[must_use]
129    pub fn datatype(&self) -> Option<SwBaseType> {
130        self.element()
131            .get_sub_element(ElementName::NetworkRepresentationProps)?
132            .get_sub_element(ElementName::SwDataDefPropsVariants)?
133            .get_sub_element(ElementName::SwDataDefPropsConditional)?
134            .get_sub_element(ElementName::BaseTypeRef)?
135            .get_reference_target()
136            .ok()?
137            .try_into()
138            .ok()
139    }
140
141    /// set the length of this signal in bits
142    pub fn set_length(&self, bit_length: u64) -> Result<(), AutosarAbstractionError> {
143        self.element()
144            .get_or_create_sub_element(ElementName::Length)?
145            .set_character_data(bit_length)?;
146        Ok(())
147    }
148
149    /// get the length of this signal in bits
150    #[must_use]
151    pub fn length(&self) -> Option<u64> {
152        self.element()
153            .get_sub_element(ElementName::Length)?
154            .character_data()?
155            .parse_integer()
156    }
157
158    /// set the init value for this signal
159    ///
160    /// only `NumericalValueSpecification`, `TextValueSpecification` or `ArrayValueSpecification` are permitted here
161    pub fn set_init_value<T: Into<ValueSpecification>>(
162        &self,
163        value_spec: Option<T>,
164    ) -> Result<(), AutosarAbstractionError> {
165        if let Some(value_spec) = value_spec {
166            let value_spec: ValueSpecification = value_spec.into();
167            if !matches!(
168                value_spec,
169                ValueSpecification::Numerical(_) | ValueSpecification::Text(_) | ValueSpecification::Array(_)
170            ) {
171                return Err(AutosarAbstractionError::InvalidParameter(
172                "The init value must be a NumericalValueSpecification, TextValueSpecification or ArrayValueSpecification".to_string(),
173            ));
174            }
175            let init_value_elem = self.element().get_or_create_sub_element(ElementName::InitValue)?;
176            value_spec.store(&init_value_elem)?;
177        } else {
178            // remove the init value element if it exists
179            let _ = self.element().remove_sub_element_kind(ElementName::InitValue);
180        }
181        Ok(())
182    }
183
184    /// get the init value for this signal
185    #[must_use]
186    pub fn init_value(&self) -> Option<ValueSpecification> {
187        let init_value_elem = self
188            .element()
189            .get_sub_element(ElementName::InitValue)?
190            .get_sub_element_at(0)?;
191        ValueSpecification::load(&init_value_elem)
192    }
193
194    /// set the system signal that corresponds to this signal
195    pub fn set_system_signal(&self, syssignal: &SystemSignal) -> Result<(), AutosarAbstractionError> {
196        self.element()
197            .get_or_create_sub_element(ElementName::SystemSignalRef)?
198            .set_reference_target(syssignal.element())?;
199        Ok(())
200    }
201
202    /// get the system signal that corresponds to this isignal
203    #[must_use]
204    pub fn system_signal(&self) -> Option<SystemSignal> {
205        self.element()
206            .get_sub_element(ElementName::SystemSignalRef)?
207            .get_reference_target()
208            .ok()?
209            .try_into()
210            .ok()
211    }
212
213    /// an iterator over all `ISignalToIPduMapping` for this signal
214    ///
215    /// Usually a signal should only be mapped to a single PDU,
216    /// so this iterator is expected to return either zero or one item in ordinary cases.
217    #[must_use]
218    pub fn mappings(&self) -> Vec<ISignalToIPduMapping> {
219        let model_result = self.element().model();
220        let path_result = self.element().path();
221        if let (Ok(model), Ok(path)) = (model_result, path_result) {
222            model
223                .get_references_to(&path)
224                .iter()
225                .filter_map(|e| {
226                    e.upgrade()
227                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
228                        .and_then(|elem| ISignalToIPduMapping::try_from(elem).ok())
229                })
230                .collect()
231        } else {
232            vec![]
233        }
234    }
235
236    /// get the signal group that contains this signal, if any
237    #[must_use]
238    pub fn signal_group(&self) -> Option<ISignalGroup> {
239        let path = self.element().path().ok()?;
240        let referrers = self.element().model().ok()?.get_references_to(&path);
241
242        for elem in referrers
243            .iter()
244            .filter_map(|weak| weak.upgrade().and_then(|elem| elem.named_parent().ok().flatten()))
245        {
246            if let Ok(grp) = ISignalGroup::try_from(elem) {
247                return Some(grp);
248            }
249        }
250        None
251    }
252
253    /// list all `ISignalTriggering`s that trigger this signal
254    #[must_use]
255    pub fn signal_triggerings(&self) -> Vec<ISignalTriggering> {
256        let model_result = self.element().model();
257        let path_result = self.element().path();
258        if let (Ok(model), Ok(path)) = (model_result, path_result) {
259            model
260                .get_references_to(&path)
261                .iter()
262                .filter_map(|e| {
263                    e.upgrade()
264                        .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
265                        .and_then(|elem| ISignalTriggering::try_from(elem).ok())
266                })
267                .collect()
268        } else {
269            vec![]
270        }
271    }
272
273    /// add a data transformation to this signal
274    pub fn add_data_transformation(
275        &self,
276        data_transformation: &DataTransformation,
277    ) -> Result<(), AutosarAbstractionError> {
278        let transformations = self
279            .element()
280            .get_or_create_sub_element(ElementName::DataTransformations)?;
281        transformations
282            .create_sub_element(ElementName::DataTransformationRefConditional)?
283            .create_sub_element(ElementName::DataTransformationRef)?
284            .set_reference_target(data_transformation.element())?;
285
286        Ok(())
287    }
288
289    /// get all data transformations that are applied to this signal
290    pub fn data_transformations(&self) -> impl Iterator<Item = DataTransformation> + Send + use<> {
291        self.element()
292            .get_sub_element(ElementName::DataTransformations)
293            .into_iter()
294            .flat_map(|elem| elem.sub_elements())
295            .filter_map(|elem| elem.get_sub_element(ElementName::DataTransformationRef))
296            .filter_map(|elem| elem.get_reference_target().ok())
297            .filter_map(|elem| elem.try_into().ok())
298    }
299
300    /// create E2E transformation properties for this signal
301    pub fn create_e2e_transformation_isignal_props(
302        &self,
303        transformer: &TransformationTechnology,
304    ) -> Result<EndToEndTransformationISignalProps, AutosarAbstractionError> {
305        let tsp = self
306            .element()
307            .get_or_create_sub_element(ElementName::TransformationISignalPropss)?;
308        EndToEndTransformationISignalProps::new(tsp, transformer)
309    }
310
311    /// create SomeIp transformation properties for this signal
312    pub fn create_someip_transformation_isignal_props(
313        &self,
314        transformer: &TransformationTechnology,
315    ) -> Result<SomeIpTransformationISignalProps, AutosarAbstractionError> {
316        let tsp = self
317            .element()
318            .get_or_create_sub_element(ElementName::TransformationISignalPropss)?;
319        SomeIpTransformationISignalProps::new(tsp, transformer)
320    }
321
322    /// get all transformation properties that are applied to this signal
323    pub fn transformation_isignal_props(&self) -> impl Iterator<Item = TransformationISignalProps> + Send + use<> {
324        self.element()
325            .get_sub_element(ElementName::TransformationISignalPropss)
326            .into_iter()
327            .flat_map(|elem| elem.sub_elements())
328            .filter_map(|elem| TransformationISignalProps::try_from(elem).ok())
329    }
330}
331
332//##################################################################
333
334/// The system signal represents the communication system's view of data exchanged between SW components which reside on different ECUs
335///
336/// Use [`ArPackage::create_system_signal`] to create a new system signal
337#[derive(Debug, Clone, PartialEq, Eq, Hash)]
338pub struct SystemSignal(Element);
339abstraction_element!(SystemSignal, SystemSignal);
340impl IdentifiableAbstractionElement for SystemSignal {}
341
342impl SystemSignal {
343    /// Create a new system signal in the given package
344    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
345        let package_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
346        let elem_syssignal = package_elements.create_named_sub_element(ElementName::SystemSignal, name)?;
347
348        Ok(Self(elem_syssignal))
349    }
350
351    /// remove this `SystemSignal` from the model
352    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
353        // remove all references from ISignals to this system signal
354        let model = self.element().model()?;
355        let path = self.element().path()?;
356        let referrers = model.get_references_to(&path);
357        for elem in referrers
358            .iter()
359            .filter_map(WeakElement::upgrade)
360            .filter_map(|refelem| refelem.named_parent().ok().flatten())
361        {
362            if let Ok(isignal) = ISignal::try_from(elem) {
363                isignal.remove(deep)?;
364            }
365        }
366
367        let opt_unit = self.unit();
368        let opt_compu_method = self.compu_method();
369        let opt_data_constr = self.data_constr();
370
371        AbstractionElement::remove(self, deep)?;
372
373        if deep {
374            if let Some(unit) = opt_unit
375                && !is_used(unit.element())
376            {
377                // remove the unit if it became unused
378                unit.remove(deep)?;
379            }
380
381            if let Some(compu_method) = opt_compu_method
382                && !is_used(compu_method.element())
383            {
384                // remove the compu method if it became unused
385                compu_method.remove(deep)?;
386            }
387
388            if let Some(data_constr) = opt_data_constr
389                && !is_used(data_constr.element())
390            {
391                // remove the data constraint if it became unused
392                data_constr.remove(deep)?;
393            }
394        }
395
396        Ok(())
397    }
398
399    /// get the signal group that contains this signal
400    pub fn signal_group(&self) -> Option<SystemSignalGroup> {
401        let path = self.element().path().ok()?;
402        let referrers = self.element().model().ok()?.get_references_to(&path);
403        for elem in referrers
404            .iter()
405            .filter_map(WeakElement::upgrade)
406            .filter_map(|refelem| refelem.named_parent().ok().flatten())
407        {
408            if let Ok(grp) = SystemSignalGroup::try_from(elem) {
409                return Some(grp);
410            }
411        }
412        None
413    }
414
415    /// set the unit for this signal
416    pub fn set_unit(&self, unit: &Unit) -> Result<(), AutosarAbstractionError> {
417        self.element()
418            .get_or_create_sub_element(ElementName::PhysicalProps)?
419            .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
420            .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
421            .get_or_create_sub_element(ElementName::UnitRef)?
422            .set_reference_target(unit.element())?;
423        Ok(())
424    }
425
426    /// get the unit for this signal
427    #[must_use]
428    pub fn unit(&self) -> Option<Unit> {
429        self.element()
430            .get_sub_element(ElementName::PhysicalProps)?
431            .get_sub_element(ElementName::SwDataDefPropsVariants)?
432            .get_sub_element(ElementName::SwDataDefPropsConditional)?
433            .get_sub_element(ElementName::UnitRef)?
434            .get_reference_target()
435            .ok()?
436            .try_into()
437            .ok()
438    }
439
440    /// set the compu method for this signal
441    pub fn set_compu_method(&self, compu_method: &CompuMethod) -> Result<(), AutosarAbstractionError> {
442        self.element()
443            .get_or_create_sub_element(ElementName::PhysicalProps)?
444            .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
445            .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
446            .get_or_create_sub_element(ElementName::CompuMethodRef)?
447            .set_reference_target(compu_method.element())?;
448        Ok(())
449    }
450
451    /// get the compu method for this signal
452    #[must_use]
453    pub fn compu_method(&self) -> Option<CompuMethod> {
454        self.element()
455            .get_sub_element(ElementName::PhysicalProps)?
456            .get_sub_element(ElementName::SwDataDefPropsVariants)?
457            .get_sub_element(ElementName::SwDataDefPropsConditional)?
458            .get_sub_element(ElementName::CompuMethodRef)?
459            .get_reference_target()
460            .ok()?
461            .try_into()
462            .ok()
463    }
464
465    /// set the data constraint for this signal
466    pub fn set_data_constr(&self, data_constr: &DataConstr) -> Result<(), AutosarAbstractionError> {
467        self.element()
468            .get_or_create_sub_element(ElementName::PhysicalProps)?
469            .get_or_create_sub_element(ElementName::SwDataDefPropsVariants)?
470            .get_or_create_sub_element(ElementName::SwDataDefPropsConditional)?
471            .get_or_create_sub_element(ElementName::DataConstrRef)?
472            .set_reference_target(data_constr.element())?;
473        Ok(())
474    }
475
476    /// get the data constraint for this signal
477    #[must_use]
478    pub fn data_constr(&self) -> Option<DataConstr> {
479        self.element()
480            .get_sub_element(ElementName::PhysicalProps)?
481            .get_sub_element(ElementName::SwDataDefPropsVariants)?
482            .get_sub_element(ElementName::SwDataDefPropsConditional)?
483            .get_sub_element(ElementName::DataConstrRef)?
484            .get_reference_target()
485            .ok()?
486            .try_into()
487            .ok()
488    }
489}
490
491//##################################################################
492
493/// An `ISignalGroup` groups signals that should always be kept together
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495pub struct ISignalGroup(Element);
496abstraction_element!(ISignalGroup, ISignalGroup);
497impl IdentifiableAbstractionElement for ISignalGroup {}
498
499impl ISignalGroup {
500    pub(crate) fn new(
501        name: &str,
502        package: &ArPackage,
503        system_signal_group: &SystemSignalGroup,
504    ) -> Result<Self, AutosarAbstractionError> {
505        let sig_pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
506        let elem_isiggrp = sig_pkg_elements.create_named_sub_element(ElementName::ISignalGroup, name)?;
507
508        elem_isiggrp
509            .create_sub_element(ElementName::SystemSignalGroupRef)?
510            .set_reference_target(system_signal_group.element())?;
511
512        Ok(Self(elem_isiggrp))
513    }
514
515    /// remove this `ISignalGroup` from the model
516    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
517        let signals = if deep {
518            self.signals().collect::<Vec<_>>()
519        } else {
520            vec![]
521        };
522
523        let opt_system_signal_group = self.system_signal_group();
524
525        let ref_parents = get_reference_parents(self.element())?;
526
527        AbstractionElement::remove(self, deep)?;
528
529        for (_named_parent, parent) in ref_parents {
530            if parent.element_name() == ElementName::SenderReceiverToSignalMapping
531                && let Ok(sender_receiver_to_signal_mapping) = SenderReceiverToSignalMapping::try_from(parent)
532            {
533                sender_receiver_to_signal_mapping.remove(deep)?;
534            }
535        }
536
537        if deep {
538            // remove all signals that were part of this group
539            for signal in signals {
540                if !is_used_system_element(signal.element()) {
541                    // only remove unused signals
542                    signal.remove(deep)?;
543                }
544            }
545
546            // remove the system signal group if it became unused
547            if let Some(system_signal_group) = opt_system_signal_group
548                && !is_used(system_signal_group.element())
549            {
550                system_signal_group.remove(deep)?;
551            }
552        }
553
554        Ok(())
555    }
556
557    /// Add a signal to the signal group
558    pub fn add_signal(&self, signal: &ISignal) -> Result<(), AutosarAbstractionError> {
559        // make sure the relation of signal to signal group is maintained for the referenced system signal
560        let syssig_grp_of_signal = signal.system_signal().and_then(|ss| ss.signal_group());
561        let syssig_grp = self.system_signal_group();
562        if syssig_grp != syssig_grp_of_signal {
563            return Err(AutosarAbstractionError::InvalidParameter(
564                "The isignal and the system signal must both be part of corresponding signal groups".to_string(),
565            ));
566        }
567
568        let isrefs = self.element().get_or_create_sub_element(ElementName::ISignalRefs)?;
569
570        // check if the signal already exists in isrefs?
571
572        isrefs
573            .create_sub_element(ElementName::ISignalRef)?
574            .set_reference_target(signal.element())?;
575
576        Ok(())
577    }
578
579    /// get the system signal group that is associated with this signal group
580    #[must_use]
581    pub fn system_signal_group(&self) -> Option<SystemSignalGroup> {
582        self.element()
583            .get_sub_element(ElementName::SystemSignalGroupRef)?
584            .get_reference_target()
585            .ok()?
586            .try_into()
587            .ok()
588    }
589
590    /// Iterator over all [`ISignal`]s in this group
591    ///
592    /// # Example
593    pub fn signals(&self) -> impl Iterator<Item = ISignal> + Send + use<> {
594        self.element()
595            .get_sub_element(ElementName::ISignalRefs)
596            .into_iter()
597            .flat_map(|elem| elem.sub_elements())
598            .filter_map(|elem| {
599                elem.get_reference_target()
600                    .ok()
601                    .and_then(|elem| ISignal::try_from(elem).ok())
602            })
603    }
604
605    /// add a data transformation to this signal group
606    pub fn add_data_transformation(
607        &self,
608        data_transformation: &DataTransformation,
609    ) -> Result<(), AutosarAbstractionError> {
610        let cbst = self
611            .element()
612            .get_or_create_sub_element(ElementName::ComBasedSignalGroupTransformations)?;
613        cbst.create_sub_element(ElementName::DataTransformationRefConditional)?
614            .create_sub_element(ElementName::DataTransformationRef)?
615            .set_reference_target(data_transformation.element())?;
616        Ok(())
617    }
618
619    /// get all data transformations that are applied to this signal group
620    pub fn data_transformations(&self) -> impl Iterator<Item = DataTransformation> + Send + use<> {
621        self.element()
622            .get_sub_element(ElementName::ComBasedSignalGroupTransformations)
623            .into_iter()
624            .flat_map(|elem| elem.sub_elements())
625            .filter_map(|elem| elem.get_sub_element(ElementName::DataTransformationRef))
626            .filter_map(|elem| elem.get_reference_target().ok())
627            .filter_map(|elem| elem.try_into().ok())
628    }
629
630    /// create E2E transformation properties for this signal group
631    pub fn create_e2e_transformation_isignal_props(
632        &self,
633        transformer: &TransformationTechnology,
634    ) -> Result<EndToEndTransformationISignalProps, AutosarAbstractionError> {
635        let tsp = self
636            .element()
637            .get_or_create_sub_element(ElementName::TransformationISignalPropss)?;
638        EndToEndTransformationISignalProps::new(tsp, transformer)
639    }
640
641    /// create SomeIp transformation properties for this signal group
642    pub fn create_someip_transformation_isignal_props(
643        &self,
644        transformer: &TransformationTechnology,
645    ) -> Result<SomeIpTransformationISignalProps, AutosarAbstractionError> {
646        let tsp = self
647            .element()
648            .get_or_create_sub_element(ElementName::TransformationISignalPropss)?;
649        SomeIpTransformationISignalProps::new(tsp, transformer)
650    }
651
652    /// get all transformation properties that are applied to this signal group
653    pub fn transformation_isignal_props(&self) -> impl Iterator<Item = TransformationISignalProps> + Send + use<> {
654        self.element()
655            .get_sub_element(ElementName::TransformationISignalPropss)
656            .into_iter()
657            .flat_map(|elem| elem.sub_elements())
658            .filter_map(|elem| TransformationISignalProps::try_from(elem).ok())
659    }
660}
661
662//##################################################################
663
664/// A signal group refers to a set of signals that shall always be kept together. A signal group is used to
665/// guarantee the atomic transfer of AUTOSAR composite data types.
666///
667/// Use [`ArPackage::create_system_signal_group`] to create a new system signal group
668#[derive(Debug, Clone, PartialEq, Eq, Hash)]
669pub struct SystemSignalGroup(Element);
670abstraction_element!(SystemSignalGroup, SystemSignalGroup);
671impl IdentifiableAbstractionElement for SystemSignalGroup {}
672
673impl SystemSignalGroup {
674    /// Create a new system signal group
675    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
676        let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
677        let signalgroup = pkg_elements.create_named_sub_element(ElementName::SystemSignalGroup, name)?;
678
679        Ok(Self(signalgroup))
680    }
681
682    /// Add a signal to the signal group
683    pub fn add_signal(&self, signal: &SystemSignal) -> Result<(), AutosarAbstractionError> {
684        let ssrefs = self
685            .element()
686            .get_or_create_sub_element(ElementName::SystemSignalRefs)?;
687
688        // check if the signal already exists in ssrefs?
689
690        ssrefs
691            .create_sub_element(ElementName::SystemSignalRef)?
692            .set_reference_target(signal.element())?;
693
694        Ok(())
695    }
696
697    /// Iterator over all [`SystemSignal`]s in this group
698    pub fn signals(&self) -> impl Iterator<Item = SystemSignal> + Send + use<> {
699        self.element()
700            .get_sub_element(ElementName::SystemSignalRefs)
701            .into_iter()
702            .flat_map(|elem| elem.sub_elements())
703            .filter_map(|elem| {
704                elem.get_reference_target()
705                    .ok()
706                    .and_then(|elem| SystemSignal::try_from(elem).ok())
707            })
708    }
709}
710
711//##################################################################
712
713/// an `ISignalTriggering` triggers a signal in a PDU
714#[derive(Debug, Clone, PartialEq, Eq, Hash)]
715pub struct ISignalTriggering(Element);
716abstraction_element!(ISignalTriggering, ISignalTriggering);
717impl IdentifiableAbstractionElement for ISignalTriggering {}
718
719impl ISignalTriggering {
720    pub(crate) fn new<T: AbstractPhysicalChannel>(
721        signal: &ISignal,
722        channel: &T,
723    ) -> Result<Self, AutosarAbstractionError> {
724        let model = channel.element().model()?;
725        let base_path = channel.element().path()?;
726        let signal_name = signal
727            .name()
728            .ok_or(AutosarAbstractionError::InvalidParameter("invalid signal".to_string()))?;
729        let pt_name = format!("ST_{signal_name}");
730        let pt_name = make_unique_name(&model, &base_path, &pt_name);
731
732        let triggerings = channel
733            .element()
734            .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
735        let st_elem = triggerings.create_named_sub_element(ElementName::ISignalTriggering, &pt_name)?;
736        st_elem
737            .create_sub_element(ElementName::ISignalRef)?
738            .set_reference_target(signal.element())?;
739
740        let pt = Self(st_elem);
741
742        Ok(pt)
743    }
744
745    /// remove this `ISignalTriggering` from the model
746    pub fn remove(self, deep: bool) -> Result<(), AutosarAbstractionError> {
747        let opt_signal = self.signal();
748        for sp in self.signal_ports() {
749            sp.remove(deep)?;
750        }
751
752        AbstractionElement::remove(self, deep)?;
753
754        if deep
755            && let Some(signal) = opt_signal
756            && !is_used_system_element(signal.element())
757        {
758            // remove the signal if it became unused
759            signal.remove(deep)?;
760        }
761
762        Ok(())
763    }
764
765    pub(crate) fn new_group(
766        signal_group: &ISignalGroup,
767        channel: &PhysicalChannel,
768    ) -> Result<Self, AutosarAbstractionError> {
769        let model = channel.element().model()?;
770        let base_path = channel.element().path()?;
771        let signal_name = signal_group.name().ok_or(AutosarAbstractionError::InvalidParameter(
772            "invalid signal group".to_string(),
773        ))?;
774        let pt_name = format!("ST_{signal_name}");
775        let pt_name = make_unique_name(&model, &base_path, &pt_name);
776
777        let triggerings = channel
778            .element()
779            .get_or_create_sub_element(ElementName::ISignalTriggerings)?;
780        let st_elem = triggerings.create_named_sub_element(ElementName::ISignalTriggering, &pt_name)?;
781        st_elem
782            .create_sub_element(ElementName::ISignalGroupRef)?
783            .set_reference_target(signal_group.element())?;
784
785        let pt = Self(st_elem);
786
787        Ok(pt)
788    }
789
790    /// get the physical channel that contains this signal triggering
791    pub fn physical_channel(&self) -> Result<PhysicalChannel, AutosarAbstractionError> {
792        let channel_elem = self.element().named_parent()?.ok_or(AutosarDataError::ItemDeleted)?;
793        PhysicalChannel::try_from(channel_elem)
794    }
795
796    /// connect this signal triggering to an ECU
797    pub fn connect_to_ecu(
798        &self,
799        ecu: &EcuInstance,
800        direction: CommunicationDirection,
801    ) -> Result<ISignalPort, AutosarAbstractionError> {
802        for signal_port in self.signal_ports() {
803            if let (Ok(existing_ecu), Some(existing_direction)) =
804                (signal_port.ecu(), signal_port.communication_direction())
805                && existing_ecu == *ecu
806                && existing_direction == direction
807            {
808                return Ok(signal_port);
809            }
810        }
811
812        let channel = self.physical_channel()?;
813        let connector = channel
814            .ecu_connector(ecu)
815            .ok_or(AutosarAbstractionError::InvalidParameter(
816                "The ECU is not connected to the channel".to_string(),
817            ))?;
818
819        let name = self.name().ok_or(AutosarDataError::ItemDeleted)?;
820        let suffix = match direction {
821            CommunicationDirection::In => "Rx",
822            CommunicationDirection::Out => "Tx",
823        };
824        let port_name = format!("{name}_{suffix}",);
825        let sp_elem = connector
826            .element()
827            .get_or_create_sub_element(ElementName::EcuCommPortInstances)?
828            .create_named_sub_element(ElementName::ISignalPort, &port_name)?;
829        sp_elem
830            .create_sub_element(ElementName::CommunicationDirection)?
831            .set_character_data::<EnumItem>(direction.into())?;
832
833        self.element()
834            .get_or_create_sub_element(ElementName::ISignalPortRefs)?
835            .create_sub_element(ElementName::ISignalPortRef)?
836            .set_reference_target(&sp_elem)?;
837
838        Ok(ISignalPort(sp_elem))
839    }
840
841    /// get the signal that is triggered by this triggering
842    pub fn signal(&self) -> Option<ISignal> {
843        let signal_elem = self
844            .element()
845            .get_sub_element(ElementName::ISignalRef)?
846            .get_reference_target()
847            .ok()?;
848        ISignal::try_from(signal_elem).ok()
849    }
850
851    /// create an iterator over all signal ports that are connected to this signal triggering
852    pub fn signal_ports(&self) -> impl Iterator<Item = ISignalPort> + Send + use<> {
853        self.element()
854            .get_sub_element(ElementName::ISignalPortRefs)
855            .into_iter()
856            .flat_map(|elem| elem.sub_elements())
857            .filter_map(|elem| {
858                elem.get_reference_target()
859                    .ok()
860                    .and_then(|elem| ISignalPort::try_from(elem).ok())
861            })
862    }
863}
864
865//##################################################################
866
867/// The `ISignalPort` allows an ECU to send or receive a Signal
868#[derive(Debug, Clone, PartialEq, Eq, Hash)]
869pub struct ISignalPort(Element);
870abstraction_element!(ISignalPort, ISignalPort);
871impl IdentifiableAbstractionElement for ISignalPort {}
872
873impl ISignalPort {
874    /// get the ECU that is connected to this signal port
875    pub fn ecu(&self) -> Result<EcuInstance, AutosarAbstractionError> {
876        let comm_connector_elem = self.element().named_parent()?.unwrap();
877        let ecu_elem = comm_connector_elem.named_parent()?.unwrap();
878        EcuInstance::try_from(ecu_elem)
879    }
880
881    /// set the communication direction of this port
882    pub fn set_communication_direction(
883        &self,
884        direction: CommunicationDirection,
885    ) -> Result<(), AutosarAbstractionError> {
886        self.element()
887            .get_or_create_sub_element(ElementName::CommunicationDirection)?
888            .set_character_data::<EnumItem>(direction.into())?;
889        Ok(())
890    }
891
892    /// get the communication direction of this port
893    #[must_use]
894    pub fn communication_direction(&self) -> Option<CommunicationDirection> {
895        self.element()
896            .get_sub_element(ElementName::CommunicationDirection)?
897            .character_data()?
898            .enum_value()?
899            .try_into()
900            .ok()
901    }
902}
903
904//##################################################################
905
906/// The `TransferProperty` defines if or how the signal influences the transfer of the PDU
907#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
908pub enum TransferProperty {
909    /// The signal is pending; it does not trigger the transfer of the PDU
910    Pending,
911    /// The signal triggers the transfer of the PDU
912    Triggered,
913    /// The signal triggers the transfer of the PDU if the value changes
914    TriggeredOnChange,
915    /// The signal triggers the transfer of the PDU if the value changes without repetition
916    TriggeredOnChangeWithoutRepetition,
917    /// The signal triggers the transfer of the PDU without repetition
918    TriggeredWithoutRepetition,
919}
920
921impl From<TransferProperty> for EnumItem {
922    fn from(value: TransferProperty) -> Self {
923        match value {
924            TransferProperty::Pending => EnumItem::Pending,
925            TransferProperty::Triggered => EnumItem::Triggered,
926            TransferProperty::TriggeredOnChange => EnumItem::TriggeredOnChange,
927            TransferProperty::TriggeredOnChangeWithoutRepetition => EnumItem::TriggeredOnChangeWithoutRepetition,
928            TransferProperty::TriggeredWithoutRepetition => EnumItem::TriggeredWithoutRepetition,
929        }
930    }
931}
932
933impl TryFrom<EnumItem> for TransferProperty {
934    type Error = AutosarAbstractionError;
935
936    fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
937        match value {
938            EnumItem::Pending => Ok(TransferProperty::Pending),
939            EnumItem::Triggered => Ok(TransferProperty::Triggered),
940            EnumItem::TriggeredOnChange => Ok(TransferProperty::TriggeredOnChange),
941            EnumItem::TriggeredOnChangeWithoutRepetition => Ok(TransferProperty::TriggeredOnChangeWithoutRepetition),
942            EnumItem::TriggeredWithoutRepetition => Ok(TransferProperty::TriggeredWithoutRepetition),
943            _ => Err(AutosarAbstractionError::ValueConversionError {
944                value: value.to_string(),
945                dest: "TransferProperty".to_string(),
946            }),
947        }
948    }
949}
950
951//##################################################################
952
953#[cfg(test)]
954mod tests {
955    use super::*;
956    use crate::{
957        AutosarModelAbstraction, ByteOrder, SystemCategory,
958        communication::{
959            AbstractFrame, AbstractPdu, CanAddressingMode, CanFrameType, DataTransformationSet, SignalPdu,
960            SomeIpMessageType, SomeIpTransformationTechnologyConfig, TransformationTechnologyConfig,
961        },
962        datatype::{BaseTypeEncoding, CompuMethodContent, NumericalValueSpecification, SwBaseType, Unit},
963    };
964    use autosar_data::AutosarVersion;
965
966    #[test]
967    fn test_signal() {
968        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
969        let package = model.get_or_create_package("/test").unwrap();
970        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
971        let unit = Unit::new("unit", &package, Some("Unit Name")).unwrap();
972        let compu_method = CompuMethod::new("compu_method", &package, CompuMethodContent::Identical).unwrap();
973        let data_constr = DataConstr::new("data_constr", &package).unwrap();
974        let sw_base_type =
975            SwBaseType::new("sw_base_type", &package, 8, BaseTypeEncoding::None, None, None, None).unwrap();
976
977        let sys_signal = package.create_system_signal("sys_signal").unwrap();
978        let signal = system
979            .create_isignal("signal", &package, 8, &sys_signal, Some(&sw_base_type))
980            .unwrap();
981
982        sys_signal.set_unit(&unit).unwrap();
983        sys_signal.set_compu_method(&compu_method).unwrap();
984        sys_signal.set_data_constr(&data_constr).unwrap();
985
986        assert_eq!(signal.length(), Some(8));
987        assert_eq!(signal.datatype(), Some(sw_base_type));
988        assert_eq!(signal.system_signal(), Some(sys_signal.clone()));
989        assert_eq!(sys_signal.unit(), Some(unit));
990        assert_eq!(sys_signal.compu_method(), Some(compu_method));
991        assert_eq!(sys_signal.data_constr(), Some(data_constr));
992
993        // mappings
994        assert_eq!(signal.mappings().len(), 0);
995        let ipdu = system.create_isignal_ipdu("ipdu", &package, 8).unwrap();
996        let mapping = ipdu
997            .map_signal(
998                &signal,
999                0,
1000                ByteOrder::MostSignificantByteLast,
1001                None,
1002                TransferProperty::Triggered,
1003            )
1004            .unwrap();
1005        assert_eq!(signal.mappings().len(), 1);
1006        assert_eq!(signal.mappings()[0], mapping.clone());
1007        assert_eq!(mapping.signal().unwrap(), signal);
1008
1009        // init value
1010        let init_value = NumericalValueSpecification {
1011            label: None,
1012            value: 0.0,
1013        };
1014        signal.set_init_value(Some(init_value.clone())).unwrap();
1015        assert_eq!(signal.init_value(), Some(init_value.into()));
1016
1017        signal.set_init_value::<ValueSpecification>(None).unwrap();
1018        assert_eq!(signal.init_value(), None);
1019    }
1020
1021    #[test]
1022    fn test_signal_data_transformations() {
1023        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
1024        let package = model.get_or_create_package("/test").unwrap();
1025        let sw_base_type =
1026            SwBaseType::new("sw_base_type", &package, 8, BaseTypeEncoding::None, None, None, None).unwrap();
1027        let signal = ISignal::new(
1028            "signal",
1029            &package,
1030            8,
1031            &SystemSignal::new("sys_signal", &package).unwrap(),
1032            Some(&sw_base_type),
1033        )
1034        .unwrap();
1035
1036        let dts = DataTransformationSet::new("data_transformation_set", &package).unwrap();
1037        let transformer = dts
1038            .create_transformation_technology(
1039                "someip_xf",
1040                &TransformationTechnologyConfig::SomeIp(SomeIpTransformationTechnologyConfig {
1041                    alignment: 8,
1042                    byte_order: ByteOrder::MostSignificantByteFirst,
1043                    interface_version: 1,
1044                }),
1045            )
1046            .unwrap();
1047        let data_transformation = dts
1048            .create_data_transformation("someip_trans", &[&transformer], false)
1049            .unwrap();
1050
1051        signal.add_data_transformation(&data_transformation).unwrap();
1052
1053        assert_eq!(signal.data_transformations().count(), 1);
1054        assert_eq!(signal.data_transformations().next(), Some(data_transformation));
1055
1056        let someip_props = signal.create_someip_transformation_isignal_props(&transformer).unwrap();
1057        someip_props.set_legacy_strings(Some(true)).unwrap();
1058        someip_props.set_interface_version(Some(1)).unwrap();
1059        someip_props.set_dynamic_length(Some(true)).unwrap();
1060        someip_props.set_message_type(Some(SomeIpMessageType::Request)).unwrap();
1061        someip_props.set_size_of_array_length(Some(8)).unwrap();
1062        someip_props.set_size_of_string_length(Some(16)).unwrap();
1063        someip_props.set_size_of_struct_length(Some(32)).unwrap();
1064        someip_props.set_size_of_union_length(Some(64)).unwrap();
1065
1066        assert_eq!(signal.transformation_isignal_props().count(), 1);
1067    }
1068
1069    #[test]
1070    fn test_signal_group_data_transformations() {
1071        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
1072        let package = model.get_or_create_package("/test").unwrap();
1073
1074        let signal_group = ISignalGroup::new(
1075            "signal_group",
1076            &package,
1077            &SystemSignalGroup::new("sys_signal_group", &package).unwrap(),
1078        )
1079        .unwrap();
1080
1081        let dts = DataTransformationSet::new("data_transformation_set", &package).unwrap();
1082        let transformer = dts
1083            .create_transformation_technology(
1084                "someip_xf",
1085                &TransformationTechnologyConfig::SomeIp(SomeIpTransformationTechnologyConfig {
1086                    alignment: 8,
1087                    byte_order: ByteOrder::MostSignificantByteFirst,
1088                    interface_version: 1,
1089                }),
1090            )
1091            .unwrap();
1092        let data_transformation = dts
1093            .create_data_transformation("someip_trans", &[&transformer], false)
1094            .unwrap();
1095
1096        signal_group.add_data_transformation(&data_transformation).unwrap();
1097        assert_eq!(signal_group.data_transformations().count(), 1);
1098        assert_eq!(signal_group.data_transformations().next(), Some(data_transformation));
1099
1100        let _someipxf_props = signal_group
1101            .create_someip_transformation_isignal_props(&transformer)
1102            .unwrap();
1103        // the referenced transformer is not an E2E transformer, so no E2E properties can be created
1104        let result = signal_group.create_e2e_transformation_isignal_props(&transformer);
1105        assert!(result.is_err());
1106
1107        assert_eq!(signal_group.transformation_isignal_props().count(), 1);
1108    }
1109
1110    #[test]
1111    fn test_signal_group() {
1112        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
1113        let package = model.get_or_create_package("/test").unwrap();
1114        let sys_signal_group = SystemSignalGroup::new("sys_signal_group", &package).unwrap();
1115        let signal_group = ISignalGroup::new("signal_group", &package, &sys_signal_group).unwrap();
1116        assert_eq!(signal_group.system_signal_group(), Some(sys_signal_group.clone()));
1117
1118        let sys_signal = SystemSignal::new("sys_signal", &package).unwrap();
1119        let signal = ISignal::new("signal", &package, 8, &sys_signal, None).unwrap();
1120        assert_eq!(signal.system_signal(), Some(sys_signal.clone()));
1121
1122        sys_signal_group.add_signal(&sys_signal).unwrap();
1123        assert_eq!(sys_signal.signal_group(), Some(sys_signal_group.clone()));
1124        assert_eq!(sys_signal_group.signals().count(), 1);
1125
1126        signal_group.add_signal(&signal).unwrap();
1127        assert_eq!(signal_group.signals().count(), 1);
1128    }
1129
1130    #[test]
1131    fn test_signal_triggering() {
1132        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
1133        let package = model.get_or_create_package("/test").unwrap();
1134        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1135        let cluster = system.create_can_cluster("cluster", &package, None).unwrap();
1136        let channel = cluster.create_physical_channel("channel").unwrap();
1137
1138        let can_frame = system.create_can_frame("frame", &package, 8).unwrap();
1139        channel
1140            .trigger_frame(&can_frame, 0x100, CanAddressingMode::Standard, CanFrameType::Can20)
1141            .unwrap();
1142        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
1143        can_frame
1144            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
1145            .unwrap();
1146
1147        let sw_base_type =
1148            SwBaseType::new("sw_base_type", &package, 8, BaseTypeEncoding::None, None, None, None).unwrap();
1149
1150        let sys_signal = package.create_system_signal("sys_signal").unwrap();
1151        let signal = system
1152            .create_isignal("signal", &package, 8, &sys_signal, Some(&sw_base_type))
1153            .unwrap();
1154
1155        pdu.map_signal(
1156            &signal,
1157            0,
1158            ByteOrder::MostSignificantByteLast,
1159            None,
1160            TransferProperty::Pending,
1161        )
1162        .unwrap();
1163        let pt = pdu.pdu_triggerings()[0].clone();
1164
1165        // signal triggering
1166        let st = signal.signal_triggerings()[0].clone();
1167        assert_eq!(st, pt.signal_triggerings().next().unwrap());
1168
1169        assert_eq!(st.physical_channel().unwrap(), PhysicalChannel::Can(channel.clone()));
1170
1171        let ecuinstance = system.create_ecu_instance("ecu", &package).unwrap();
1172        let controller = ecuinstance.create_can_communication_controller("controller").unwrap();
1173        controller.connect_physical_channel("connection", &channel).unwrap();
1174
1175        assert_eq!(st.signal_ports().count(), 0);
1176        let signal_port = st.connect_to_ecu(&ecuinstance, CommunicationDirection::In).unwrap();
1177        assert_eq!(st.signal_ports().count(), 1);
1178        assert_eq!(signal_port.ecu().unwrap(), ecuinstance);
1179        assert_eq!(signal_port.communication_direction(), Some(CommunicationDirection::In));
1180        signal_port
1181            .set_communication_direction(CommunicationDirection::Out)
1182            .unwrap();
1183        assert_eq!(signal_port.communication_direction(), Some(CommunicationDirection::Out));
1184        signal_port.set_name("new_name").unwrap();
1185        assert_eq!(signal_port.name().unwrap(), "new_name");
1186    }
1187
1188    #[test]
1189    fn test_remove_signal() {
1190        let model = AutosarModelAbstraction::create("test.arxml", AutosarVersion::LATEST);
1191        let package = model.get_or_create_package("/test").unwrap();
1192        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
1193        let sw_base_type =
1194            SwBaseType::new("sw_base_type", &package, 8, BaseTypeEncoding::None, None, None, None).unwrap();
1195        let sys_signal = package.create_system_signal("sys_signal").unwrap();
1196        let signal = system
1197            .create_isignal("signal", &package, 8, &sys_signal, Some(&sw_base_type))
1198            .unwrap();
1199
1200        let cluster = system.create_can_cluster("cluster", &package, None).unwrap();
1201        let channel = cluster.create_physical_channel("channel").unwrap();
1202        let can_frame = system.create_can_frame("frame", &package, 8).unwrap();
1203        channel
1204            .trigger_frame(&can_frame, 0x100, CanAddressingMode::Standard, CanFrameType::Can20)
1205            .unwrap();
1206        let pdu = system.create_isignal_ipdu("pdu", &package, 8).unwrap();
1207        can_frame
1208            .map_pdu(&pdu, 0, ByteOrder::MostSignificantByteLast, None)
1209            .unwrap();
1210        pdu.map_signal(
1211            &signal,
1212            0,
1213            ByteOrder::MostSignificantByteLast,
1214            None,
1215            TransferProperty::Pending,
1216        )
1217        .unwrap();
1218
1219        signal.remove(true).unwrap();
1220
1221        assert_eq!(channel.signal_triggerings().count(), 0);
1222        assert_eq!(pdu.mapped_signals().count(), 0);
1223    }
1224}