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