autosar_data_abstraction/communication/pdu/
isignal_ipdu.rs

1use crate::communication::{AbstractIpdu, AbstractPdu, IPdu, ISignal, ISignalGroup, Pdu, TransferProperty};
2use crate::{
3    AbstractionElement, ArPackage, AutosarAbstractionError, ByteOrder, IdentifiableAbstractionElement,
4    abstraction_element, make_unique_name,
5};
6use autosar_data::{Element, ElementName, EnumItem};
7
8//##################################################################
9
10/// Trait for PDUs that can contain signals, i.e., ISignalIPdu and NmPdu
11pub trait SignalPdu: AbstractPdu {
12    /// returns an iterator over all signals and signal groups mapped to the PDU
13    fn mapped_signals(&self) -> impl Iterator<Item = ISignalToIPduMapping> + Send + use<Self> {
14        self.element()
15            .get_sub_element(ElementName::ISignalToPduMappings)
16            .into_iter()
17            .flat_map(|mappings| mappings.sub_elements())
18            .filter_map(|elem| ISignalToIPduMapping::try_from(elem).ok())
19    }
20
21    /// map a signal to the `ISignalIPdu` or `NmPdu`
22    ///
23    /// If this signal is part of a signal group, then the group must be mapped first
24    fn map_signal(
25        &self,
26        signal: &ISignal,
27        start_position: u32,
28        byte_order: ByteOrder,
29        update_bit: Option<u32>,
30        transfer_property: TransferProperty,
31    ) -> Result<ISignalToIPduMapping, AutosarAbstractionError>;
32
33    /// map a signal group to the PDU
34    fn map_signal_group(&self, signal_group: &ISignalGroup) -> Result<ISignalToIPduMapping, AutosarAbstractionError>;
35}
36
37// helper to verify signal placement for SignalPdus
38pub(crate) fn verify_signal_mapping(
39    pdu: &impl SignalPdu,
40    signal: &ISignal,
41    start_position: u32,
42    byte_order: ByteOrder,
43    update_bit: Option<u32>,
44    signal_name: &String,
45) -> Result<(), AutosarAbstractionError> {
46    let length = pdu.length().unwrap_or(0);
47    let mut validator = SignalMappingValidator::new(length);
48    for mapping in pdu.mapped_signals() {
49        if let (Some(m_signal), Some(m_start_pos), Some(m_byte_order)) =
50            (mapping.signal(), mapping.start_position(), mapping.byte_order())
51        {
52            let len = m_signal.length().unwrap_or(0);
53            validator.add_signal(m_start_pos, len, m_byte_order, mapping.update_bit());
54        }
55    }
56    if !validator.add_signal(start_position, signal.length().unwrap_or(0), byte_order, update_bit) {
57        return Err(AutosarAbstractionError::InvalidParameter(format!(
58            "Cannot map signal {signal_name} to an overlapping position in the pdu"
59        )));
60    }
61
62    // build a bitmap of all signals that are already mapped in this pdu
63    // add the new signal to the validator bitmap to see if it overlaps any existing signals
64    if let Some(signal_group) = signal.signal_group() {
65        if !pdu
66            .mapped_signals()
67            .filter_map(|mapping| mapping.signal_group())
68            .any(|grp| grp == signal_group)
69        {
70            return Err(AutosarAbstractionError::InvalidParameter(
71                "Cannot map signal to pdu, because it is part of an unmapped signal group.".to_string(),
72            ));
73        }
74    }
75    Ok(())
76}
77
78//##################################################################
79
80/// Represents the `IPdus` handled by Com
81#[derive(Debug, Clone, PartialEq, Eq, Hash)]
82pub struct ISignalIPdu(Element);
83abstraction_element!(ISignalIPdu, ISignalIPdu);
84impl IdentifiableAbstractionElement for ISignalIPdu {}
85
86impl ISignalIPdu {
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::ISignalIPdu, 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    /// map a signal to the `ISignalIPdu`
98    ///
99    /// If this signal is part of a signal group, then the group must be mapped first
100    pub fn map_signal(
101        &self,
102        signal: &ISignal,
103        start_position: u32,
104        byte_order: ByteOrder,
105        update_bit: Option<u32>,
106        transfer_property: TransferProperty,
107    ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
108        let signal_name = signal
109            .name()
110            .ok_or(AutosarAbstractionError::InvalidParameter("invalid signal".to_string()))?;
111
112        verify_signal_mapping(self, signal, start_position, byte_order, update_bit, &signal_name)?;
113
114        // add a pdu triggering for the newly mapped PDU to each frame triggering of this frame
115        for pt in self.pdu_triggerings() {
116            let st = pt.create_signal_triggering(signal)?;
117            for pdu_port in pt.pdu_ports() {
118                if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
119                    st.connect_to_ecu(&ecu, direction)?;
120                }
121            }
122        }
123
124        // create and return the new mapping
125        let model = self.element().model()?;
126        let base_path = self.element().path()?;
127        let name = make_unique_name(&model, &base_path, &signal_name);
128
129        let mappings = self
130            .element()
131            .get_or_create_sub_element(ElementName::ISignalToPduMappings)?;
132
133        ISignalToIPduMapping::new_with_signal(
134            &name,
135            &mappings,
136            signal,
137            start_position,
138            byte_order,
139            update_bit,
140            transfer_property,
141        )
142    }
143
144    /// map a signal group to the PDU
145    pub fn map_signal_group(
146        &self,
147        signal_group: &ISignalGroup,
148    ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
149        let signal_group_name = signal_group.name().ok_or(AutosarAbstractionError::InvalidParameter(
150            "invalid signal group".to_string(),
151        ))?;
152
153        // add a pdu triggering for the newly mapped PDU to each frame triggering of this frame
154        for pt in self.pdu_triggerings() {
155            let st = pt.create_signal_group_triggering(signal_group)?;
156            for pdu_port in pt.pdu_ports() {
157                if let (Ok(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
158                    st.connect_to_ecu(&ecu, direction)?;
159                }
160            }
161        }
162
163        // create and return the new mapping
164        let model = self.element().model()?;
165        let base_path = self.element().path()?;
166        let name = make_unique_name(&model, &base_path, &signal_group_name);
167
168        let mappings = self
169            .element()
170            .get_or_create_sub_element(ElementName::ISignalToPduMappings)?;
171
172        ISignalToIPduMapping::new_with_group(&name, &mappings, signal_group)
173    }
174
175    /// set the transmission timing of the PDU
176    pub fn set_timing(&self, timing_spec: &IpduTiming) -> Result<(), AutosarAbstractionError> {
177        let _ = self
178            .element()
179            .remove_sub_element_kind(ElementName::IPduTimingSpecifications);
180
181        let timing_elem = self
182            .element()
183            .create_sub_element(ElementName::IPduTimingSpecifications)?
184            .create_sub_element(ElementName::IPduTiming)?;
185        if let Some(min_delay) = timing_spec.minimum_delay {
186            timing_elem
187                .create_sub_element(ElementName::MinimumDelay)?
188                .set_character_data(min_delay)?;
189        }
190        if let Some(transmission_mode_true_timing) = &timing_spec.transmission_mode_true_timing {
191            let tmtt_elem = timing_elem
192                .get_or_create_sub_element(ElementName::TransmissionModeDeclaration)?
193                .create_sub_element(ElementName::TransmissionModeTrueTiming)?;
194            Self::set_transmission_mode_timinig(tmtt_elem, transmission_mode_true_timing)?;
195        }
196        if let Some(transmission_mode_false_timing) = &timing_spec.transmission_mode_false_timing {
197            let tmtf_elem = timing_elem
198                .get_or_create_sub_element(ElementName::TransmissionModeDeclaration)?
199                .create_sub_element(ElementName::TransmissionModeFalseTiming)?;
200            Self::set_transmission_mode_timinig(tmtf_elem, transmission_mode_false_timing)?;
201        }
202
203        Ok(())
204    }
205
206    /// Helper function to set the transmission mode timing, used by `ISignalIPdu::set_timing` for both true and false timing
207    fn set_transmission_mode_timinig(
208        timing_element: Element,
209        transmission_mode_timing: &TransmissionModeTiming,
210    ) -> Result<(), AutosarAbstractionError> {
211        if let Some(cyclic_timing) = &transmission_mode_timing.cyclic_timing {
212            let ct_elem = timing_element.create_sub_element(ElementName::CyclicTiming)?;
213            ct_elem
214                .create_sub_element(ElementName::TimePeriod)?
215                .create_sub_element(ElementName::Value)?
216                .set_character_data(cyclic_timing.time_period)?;
217            if let Some(time_offset) = cyclic_timing.time_offset {
218                ct_elem
219                    .create_sub_element(ElementName::TimeOffset)?
220                    .create_sub_element(ElementName::Value)?
221                    .set_character_data(time_offset)?;
222            }
223        }
224        if let Some(event_controlled_timing) = &transmission_mode_timing.event_controlled_timing {
225            let ect_elem = timing_element.create_sub_element(ElementName::EventControlledTiming)?;
226            ect_elem
227                .create_sub_element(ElementName::NumberOfRepetitions)?
228                .set_character_data(u64::from(event_controlled_timing.number_of_repetitions))?;
229            if let Some(repetition_period) = event_controlled_timing.repetition_period {
230                ect_elem
231                    .create_sub_element(ElementName::RepetitionPeriod)?
232                    .create_sub_element(ElementName::Value)?
233                    .set_character_data(repetition_period)?;
234            }
235        }
236
237        Ok(())
238    }
239
240    /// get the transmission timing of the PDU
241    #[must_use]
242    pub fn timing(&self) -> Option<IpduTiming> {
243        let timing_elem = self
244            .element()
245            .get_sub_element(ElementName::IPduTimingSpecifications)?
246            .get_sub_element(ElementName::IPduTiming)?;
247        let minimum_delay = timing_elem
248            .get_sub_element(ElementName::MinimumDelay)
249            .and_then(|md| md.character_data())
250            .and_then(|cdata| cdata.parse_float());
251        let transmission_mode_true_timing = timing_elem
252            .get_sub_element(ElementName::TransmissionModeDeclaration)
253            .and_then(|tmd| tmd.get_sub_element(ElementName::TransmissionModeTrueTiming))
254            .and_then(|tmtt| Self::transmission_mode_timing(&tmtt));
255        let transmission_mode_false_timing = timing_elem
256            .get_sub_element(ElementName::TransmissionModeDeclaration)
257            .and_then(|tmd| tmd.get_sub_element(ElementName::TransmissionModeFalseTiming))
258            .and_then(|tmtf| Self::transmission_mode_timing(&tmtf));
259
260        Some(IpduTiming {
261            minimum_delay,
262            transmission_mode_true_timing,
263            transmission_mode_false_timing,
264        })
265    }
266
267    /// Helper function to get the transmission mode timing, used by `ISignalIPdu::timing` for both true and false modes
268    fn transmission_mode_timing(timing_elem: &Element) -> Option<TransmissionModeTiming> {
269        let cyclic_timing = timing_elem.get_sub_element(ElementName::CyclicTiming).and_then(|ct| {
270            let time_period = ct
271                .get_sub_element(ElementName::TimePeriod)
272                .and_then(|tp| tp.get_sub_element(ElementName::Value))
273                .and_then(|val| val.character_data())
274                .and_then(|cdata| cdata.parse_float());
275            let time_offset = ct
276                .get_sub_element(ElementName::TimeOffset)
277                .and_then(|to| to.get_sub_element(ElementName::Value))
278                .and_then(|val| val.character_data())
279                .and_then(|cdata| cdata.parse_float());
280            time_period.map(|tp| CyclicTiming {
281                time_period: tp,
282                time_offset,
283            })
284        });
285        let event_controlled_timing = timing_elem
286            .get_sub_element(ElementName::EventControlledTiming)
287            .and_then(|ect| {
288                let number_of_repetitions = ect
289                    .get_sub_element(ElementName::NumberOfRepetitions)
290                    .and_then(|nr| nr.character_data())
291                    .and_then(|cdata| cdata.parse_integer());
292                let repetition_period = ect
293                    .get_sub_element(ElementName::RepetitionPeriod)
294                    .and_then(|rp| rp.get_sub_element(ElementName::Value))
295                    .and_then(|val| val.character_data())
296                    .and_then(|cdata| cdata.parse_float());
297                number_of_repetitions.map(|nr| EventControlledTiming {
298                    number_of_repetitions: nr,
299                    repetition_period,
300                })
301            });
302
303        Some(TransmissionModeTiming {
304            cyclic_timing,
305            event_controlled_timing,
306        })
307    }
308}
309
310impl SignalPdu for ISignalIPdu {
311    fn map_signal(
312        &self,
313        signal: &ISignal,
314        start_position: u32,
315        byte_order: ByteOrder,
316        update_bit: Option<u32>,
317        transfer_property: TransferProperty,
318    ) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
319        ISignalIPdu::map_signal(self, signal, start_position, byte_order, update_bit, transfer_property)
320    }
321
322    fn map_signal_group(&self, signal_group: &ISignalGroup) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
323        ISignalIPdu::map_signal_group(self, signal_group)
324    }
325}
326
327impl AbstractPdu for ISignalIPdu {}
328
329impl AbstractIpdu for ISignalIPdu {}
330
331impl From<ISignalIPdu> for Pdu {
332    fn from(value: ISignalIPdu) -> Self {
333        Pdu::ISignalIPdu(value)
334    }
335}
336
337impl From<ISignalIPdu> for IPdu {
338    fn from(value: ISignalIPdu) -> Self {
339        IPdu::ISignalIPdu(value)
340    }
341}
342
343//##################################################################
344
345/// `ISignalToIPduMapping` connects an `ISignal` or `ISignalGroup` to an `ISignalToIPdu`
346#[derive(Debug, Clone, PartialEq, Eq, Hash)]
347pub struct ISignalToIPduMapping(Element);
348abstraction_element!(ISignalToIPduMapping, ISignalToIPduMapping);
349impl IdentifiableAbstractionElement for ISignalToIPduMapping {}
350
351impl ISignalToIPduMapping {
352    pub(crate) fn new_with_signal(
353        name: &str,
354        mappings: &Element,
355        signal: &ISignal,
356        start_position: u32,
357        byte_order: ByteOrder,
358        update_bit: Option<u32>,
359        transfer_property: TransferProperty,
360    ) -> Result<Self, AutosarAbstractionError> {
361        let signal_mapping = mappings.create_named_sub_element(ElementName::ISignalToIPduMapping, name)?;
362        signal_mapping
363            .create_sub_element(ElementName::ISignalRef)?
364            .set_reference_target(signal.element())?;
365        signal_mapping
366            .create_sub_element(ElementName::PackingByteOrder)?
367            .set_character_data::<EnumItem>(byte_order.into())?;
368        signal_mapping
369            .create_sub_element(ElementName::StartPosition)?
370            .set_character_data(u64::from(start_position))?;
371        signal_mapping
372            .create_sub_element(ElementName::TransferProperty)?
373            .set_character_data::<EnumItem>(transfer_property.into())?;
374        if let Some(update_bit_pos) = update_bit {
375            signal_mapping
376                .create_sub_element(ElementName::UpdateIndicationBitPosition)?
377                .set_character_data(u64::from(update_bit_pos))?;
378        }
379
380        Ok(Self(signal_mapping))
381    }
382
383    pub(crate) fn new_with_group(
384        name: &str,
385        mappings: &Element,
386        signal_group: &ISignalGroup,
387    ) -> Result<Self, AutosarAbstractionError> {
388        let signal_mapping = mappings.create_named_sub_element(ElementName::ISignalToIPduMapping, name)?;
389        signal_mapping
390            .create_sub_element(ElementName::ISignalGroupRef)?
391            .set_reference_target(signal_group.element())?;
392
393        Ok(Self(signal_mapping))
394    }
395
396    /// Reference to the signal that is mapped to the PDU.
397    /// Every mapping contains either a signal or a signal group.
398    #[must_use]
399    pub fn signal(&self) -> Option<ISignal> {
400        self.element()
401            .get_sub_element(ElementName::ISignalRef)
402            .and_then(|sigref| sigref.get_reference_target().ok())
403            .and_then(|signal_elem| ISignal::try_from(signal_elem).ok())
404    }
405
406    /// Set the byte order of the data in the mapped signal.
407    pub fn set_byte_order(&self, byte_order: ByteOrder) -> Result<(), AutosarAbstractionError> {
408        self.element()
409            .get_or_create_sub_element(ElementName::PackingByteOrder)?
410            .set_character_data::<EnumItem>(byte_order.into())?;
411        Ok(())
412    }
413
414    /// Byte order of the data in the signal.
415    #[must_use]
416    pub fn byte_order(&self) -> Option<ByteOrder> {
417        self.element()
418            .get_sub_element(ElementName::PackingByteOrder)
419            .and_then(|pbo| pbo.character_data())
420            .and_then(|cdata| cdata.enum_value())
421            .and_then(|enumval| enumval.try_into().ok())
422    }
423
424    /// Start position of the signal data within the PDU (bit position).
425    /// The start position is mandatory if the mapping describes a signal.
426    #[must_use]
427    pub fn start_position(&self) -> Option<u32> {
428        self.element()
429            .get_sub_element(ElementName::StartPosition)
430            .and_then(|sp_elem| sp_elem.character_data())
431            .and_then(|cdata| cdata.parse_integer())
432    }
433
434    /// Bit position of the update bit for the mapped signal. Not all signals use an update bit.
435    /// This is never used for signal groups
436    #[must_use]
437    pub fn update_bit(&self) -> Option<u32> {
438        self.element()
439            .get_sub_element(ElementName::UpdateIndicationBitPosition)
440            .and_then(|uibp| uibp.character_data())
441            .and_then(|cdata| cdata.parse_integer())
442    }
443
444    /// Set the transfer property of the mapped signal
445    pub fn set_transfer_property(&self, transfer_property: TransferProperty) -> Result<(), AutosarAbstractionError> {
446        self.element()
447            .get_or_create_sub_element(ElementName::TransferProperty)?
448            .set_character_data::<EnumItem>(transfer_property.into())?;
449        Ok(())
450    }
451
452    /// Get the transfer property of the mapped signal
453    #[must_use]
454    pub fn transfer_property(&self) -> Option<TransferProperty> {
455        self.element()
456            .get_sub_element(ElementName::TransferProperty)
457            .and_then(|pbo| pbo.character_data())
458            .and_then(|cdata| cdata.enum_value())
459            .and_then(|enumval| enumval.try_into().ok())
460    }
461
462    /// Reference to the signal group that is mapped to the PDU.
463    /// Every mapping contains either a signal or a signal group.
464    #[must_use]
465    pub fn signal_group(&self) -> Option<ISignalGroup> {
466        self.element()
467            .get_sub_element(ElementName::ISignalGroupRef)
468            .and_then(|sgref| sgref.get_reference_target().ok())
469            .and_then(|siggrp_elem| ISignalGroup::try_from(siggrp_elem).ok())
470    }
471}
472
473//##################################################################
474
475/// Timing specification for an IPDU
476#[derive(Debug, Clone, PartialEq)]
477pub struct IpduTiming {
478    /// minimum delay in seconds between two transmissions of the PDU
479    pub minimum_delay: Option<f64>,
480    /// timing specification if the COM transmission mode is true
481    pub transmission_mode_true_timing: Option<TransmissionModeTiming>,
482    /// timing specification if the COM transmission mode is false
483    pub transmission_mode_false_timing: Option<TransmissionModeTiming>,
484}
485
486/// Cyclic and event controlled timing parameters for an IPDU
487#[derive(Debug, Clone, PartialEq)]
488pub struct TransmissionModeTiming {
489    /// cyclic timing parameters
490    pub cyclic_timing: Option<CyclicTiming>,
491    /// event controlled timing parameters
492    pub event_controlled_timing: Option<EventControlledTiming>,
493}
494
495/// Cyclic timing parameters for an IPDU
496#[derive(Debug, Clone, PartialEq)]
497pub struct CyclicTiming {
498    /// period of repetition in seconds
499    pub time_period: f64,
500    /// delay until the first transmission of the PDU in seconds
501    pub time_offset: Option<f64>,
502}
503
504/// Event controlled timing parameters for an IPDU
505#[derive(Debug, Clone, PartialEq)]
506pub struct EventControlledTiming {
507    /// The PDU will be sent (number of repetitions + 1) times. If number of repetitions is 0, then the PDU is sent exactly once.
508    pub number_of_repetitions: u32,
509    /// time in seconds between two transmissions of the PDU
510    pub repetition_period: Option<f64>,
511}
512
513//##################################################################
514
515/// Helper struct to validate signal mappings
516pub struct SignalMappingValidator {
517    bitmap: Vec<u8>,
518}
519
520impl SignalMappingValidator {
521    /// Create a new validator for a PDU with the given length
522    #[must_use]
523    pub fn new(length: u32) -> Self {
524        Self {
525            bitmap: vec![0; length as usize],
526        }
527    }
528
529    /// add a signal to the validator
530    ///
531    /// This will mark the bits in the bitmap that are used by the signal.
532    /// If the signal overlaps with any previously added signal, then the method will return false.
533    pub fn add_signal(
534        &mut self,
535        bit_position: u32,
536        bit_length: u64,
537        byte_order: ByteOrder,
538        update_bit: Option<u32>,
539    ) -> bool {
540        let bit_position = u64::from(bit_position);
541        let first_byte = (bit_position / 8) as usize;
542        let bit_offset = bit_position % 8; // bit position inside the first byte
543        let first_byte_bits; // number of bits in the first byte
544        let mut first_mask;
545
546        if byte_order == ByteOrder::MostSignificantByteFirst {
547            // MostSignificantByteFirst / big endian
548            // bit-position: 5, length: 10
549            // byte   |               0               |               1               |
550            // bit    | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
551            // signal | 4   5   6   7   8   9                           0   1   2   3
552            first_byte_bits = (bit_offset + 1).min(bit_length);
553            first_mask = ((1u16 << (bit_offset + 1)) - 1) as u8;
554            if bit_offset + 1 != first_byte_bits {
555                let pos2 = bit_offset - first_byte_bits;
556                let subtract_mask = (1u8 << pos2) - 1;
557                first_mask -= subtract_mask;
558            }
559        } else {
560            // MostSignificantByteLast / little endian
561            // bit-position: 5, length: 10
562            // byte   |               0               |               1               |
563            // bit    | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
564            // signal |                     0   1   2   3   4   5   6   7   8   9
565            first_byte_bits = (8 - bit_offset).min(bit_length); // value range 1 - 8
566            first_mask = !((1u16 << bit_offset) - 1) as u8; // 0b1111_1110, 0b1111_1100, 0b1111_1000, ..., 0b1000_0000
567            if bit_offset + first_byte_bits < 8 {
568                let pos2 = bit_offset + first_byte_bits;
569                let subtract_mask = !((1u8 << pos2) - 1);
570                first_mask -= subtract_mask;
571            }
572        }
573        let full_bytes = (bit_length - first_byte_bits) as usize / 8;
574        let end_bits = (bit_length - first_byte_bits) % 8;
575
576        let mut result = self.apply_mask(first_mask, first_byte);
577        result &= self.apply_full_bytes(first_byte + 1, full_bytes);
578
579        // handle any bits in a partial trailing byte
580        if end_bits > 0 {
581            let end_mask = if byte_order == ByteOrder::MostSignificantByteFirst {
582                !((1u8 << end_bits) - 1)
583            } else {
584                (1u8 << end_bits) - 1
585            };
586            result &= self.apply_mask(end_mask, first_byte + full_bytes + 1);
587        }
588
589        // handle the update bit, if any
590        if let Some(update_bit) = update_bit {
591            let position = (update_bit / 8) as usize;
592            let bit_pos = update_bit % 8;
593            let mask = 1 << bit_pos;
594            result &= self.apply_mask(mask, position);
595        }
596
597        result
598    }
599
600    fn apply_mask(&mut self, mask: u8, position: usize) -> bool {
601        if position < self.bitmap.len() {
602            // check if any of the masked bits were already set
603            let result = self.bitmap[position] & mask == 0;
604            // set the masked bits
605            self.bitmap[position] |= mask;
606            result
607        } else {
608            false
609        }
610    }
611
612    fn apply_full_bytes(&mut self, position: usize, count: usize) -> bool {
613        let mut result = true;
614        if count > 0 {
615            let limit = self.bitmap.len().min(position + count);
616            for idx in position..limit {
617                result &= self.apply_mask(0xff, idx);
618            }
619            // make sure all of the signal bytes are inside the pdu length
620            result &= limit == position + count;
621        }
622        result
623    }
624}
625
626//##################################################################
627
628#[cfg(test)]
629mod test {
630    use super::*;
631    use crate::{AutosarModelAbstraction, ByteOrder, SystemCategory};
632    use autosar_data::AutosarVersion;
633
634    #[test]
635    fn isignal_ipdu() {
636        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
637        let package = model.get_or_create_package("/pkg").unwrap();
638        let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
639
640        let pdu = system.create_isignal_ipdu("isignal_ipdu", &package, 8).unwrap();
641        assert_eq!(pdu.name().unwrap(), "isignal_ipdu");
642        assert_eq!(pdu.length().unwrap(), 8);
643
644        // create a signal and map it to the PDU
645        let syssignal = package.create_system_signal("syssignal").unwrap();
646        let isignal = system.create_isignal("isignal", &package, 4, &syssignal, None).unwrap();
647        let mapping = pdu
648            .map_signal(
649                &isignal,
650                0,
651                ByteOrder::MostSignificantByteFirst,
652                Some(5),
653                TransferProperty::Triggered,
654            )
655            .unwrap();
656        assert_eq!(mapping.signal().unwrap(), isignal);
657        assert_eq!(mapping.start_position().unwrap(), 0);
658        assert_eq!(mapping.update_bit(), Some(5));
659        assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteFirst);
660        mapping.set_byte_order(ByteOrder::MostSignificantByteLast).unwrap();
661        assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteLast);
662        assert_eq!(mapping.transfer_property().unwrap(), TransferProperty::Triggered);
663        mapping.set_transfer_property(TransferProperty::Pending).unwrap();
664        assert_eq!(mapping.transfer_property().unwrap(), TransferProperty::Pending);
665
666        // create a signal group which contains a signal
667        let syssignal_group = package.create_system_signal_group("syssignal_group").unwrap();
668        let signal_group = system
669            .create_isignal_group("signal_group", &package, &syssignal_group)
670            .unwrap();
671        let grouped_syssignal = package.create_system_signal("groups_syssignal").unwrap();
672        syssignal_group.add_signal(&grouped_syssignal).unwrap();
673        let grouped_isignal = system
674            .create_isignal("grouped_isignal", &package, 4, &grouped_syssignal, None)
675            .unwrap();
676        signal_group.add_signal(&grouped_isignal).unwrap();
677        assert_eq!(grouped_isignal.signal_group().unwrap(), signal_group);
678
679        // map the signal to the PDU - this should fail, because the signal is part of an unmapped signal group
680        let result = pdu.map_signal(
681            &grouped_isignal,
682            9,
683            ByteOrder::MostSignificantByteFirst,
684            None,
685            TransferProperty::Triggered,
686        );
687        assert!(result.is_err());
688
689        // map the signal group to the PDU
690        let mapping = pdu.map_signal_group(&signal_group).unwrap();
691        assert_eq!(mapping.signal_group().unwrap(), signal_group);
692
693        // map the grouped signal to the PDU - this should now work
694        let _mapping = pdu
695            .map_signal(
696                &grouped_isignal,
697                9,
698                ByteOrder::MostSignificantByteFirst,
699                None,
700                TransferProperty::Triggered,
701            )
702            .unwrap();
703    }
704
705    #[test]
706    fn validate_signal_mapping() {
707        // create a validator and add a 2-bit signal
708        let mut validator = SignalMappingValidator::new(4);
709        let result = validator.add_signal(0, 2, ByteOrder::MostSignificantByteLast, None);
710        assert!(result);
711        assert_eq!(validator.bitmap[0], 0x03);
712
713        // create a validator and add a little-endian 9-bit signal
714        let mut validator = SignalMappingValidator::new(4);
715        let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteLast, None);
716        assert!(result);
717        assert_eq!(validator.bitmap[0], 0xE0);
718        assert_eq!(validator.bitmap[1], 0x7F);
719
720        // create a validator and add a big-endian 9-bit signal
721        let mut validator = SignalMappingValidator::new(4);
722        let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteFirst, None);
723        assert!(result);
724        assert_eq!(validator.bitmap[0], 0x3F);
725        assert_eq!(validator.bitmap[1], 0xF0);
726
727        // add another signal to the existing validator
728        let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteLast, None);
729        // it returns false (the signals overlap), but the bitmap is still updated
730        assert!(!result);
731        assert_eq!(validator.bitmap[0], 0xFF);
732        assert_eq!(validator.bitmap[1], 0xFF);
733
734        // create a validator and add a 32-bit signal
735        let mut validator = SignalMappingValidator::new(4);
736        let result = validator.add_signal(0, 32, ByteOrder::MostSignificantByteLast, None);
737        assert!(result);
738        assert_eq!(validator.bitmap[0], 0xFF);
739        assert_eq!(validator.bitmap[1], 0xFF);
740        assert_eq!(validator.bitmap[2], 0xFF);
741        assert_eq!(validator.bitmap[3], 0xFF);
742
743        // create a validator and add a big-endian 32-bit signal
744        let mut validator = SignalMappingValidator::new(4);
745        let result = validator.add_signal(7, 32, ByteOrder::MostSignificantByteFirst, None);
746        assert!(result);
747        assert_eq!(validator.bitmap[0], 0xFF);
748        assert_eq!(validator.bitmap[1], 0xFF);
749        assert_eq!(validator.bitmap[2], 0xFF);
750        assert_eq!(validator.bitmap[3], 0xFF);
751
752        // multiple mixed signals
753        let mut validator = SignalMappingValidator::new(8);
754        let result = validator.add_signal(7, 16, ByteOrder::MostSignificantByteFirst, Some(60));
755        assert!(result);
756        let result = validator.add_signal(16, 3, ByteOrder::MostSignificantByteLast, Some(61));
757        assert!(result);
758        let result = validator.add_signal(19, 7, ByteOrder::MostSignificantByteLast, Some(62));
759        assert!(result);
760        let result = validator.add_signal(26, 30, ByteOrder::MostSignificantByteLast, Some(63));
761        assert!(result);
762        let result = validator.add_signal(59, 4, ByteOrder::MostSignificantByteFirst, None);
763        assert!(result);
764        assert_eq!(validator.bitmap, [0xFF; 8]);
765    }
766
767    #[test]
768    fn ipdu_timing() {
769        let model = AutosarModelAbstraction::create("filename", AutosarVersion::Autosar_00048);
770        let package = model.get_or_create_package("/pkg").unwrap();
771        let pdu = ISignalIPdu::new("pdu_name", &package, 8).unwrap();
772
773        let timing_spec = IpduTiming {
774            minimum_delay: Some(0.1),
775            transmission_mode_true_timing: Some(TransmissionModeTiming {
776                cyclic_timing: Some(CyclicTiming {
777                    time_period: 0.2,
778                    time_offset: Some(0.3),
779                }),
780                event_controlled_timing: Some(EventControlledTiming {
781                    number_of_repetitions: 4,
782                    repetition_period: Some(0.5),
783                }),
784            }),
785            transmission_mode_false_timing: Some(TransmissionModeTiming {
786                cyclic_timing: Some(CyclicTiming {
787                    time_period: 0.6,
788                    time_offset: Some(0.7),
789                }),
790                event_controlled_timing: Some(EventControlledTiming {
791                    number_of_repetitions: 8,
792                    repetition_period: Some(0.9),
793                }),
794            }),
795        };
796        pdu.set_timing(&timing_spec).unwrap();
797        let timing_spec2 = pdu.timing().unwrap();
798        assert_eq!(timing_spec, timing_spec2);
799    }
800}