use crate::communication::{AbstractIpdu, AbstractPdu, ISignal, ISignalGroup, Pdu, TransferProperty};
use crate::{abstraction_element, make_unique_name, AbstractionElement, ArPackage, AutosarAbstractionError, ByteOrder};
use autosar_data::{Element, ElementName, EnumItem};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ISignalIPdu(Element);
abstraction_element!(ISignalIPdu, ISignalIPdu);
impl ISignalIPdu {
pub(crate) fn new(name: &str, package: &ArPackage, length: u32) -> Result<Self, AutosarAbstractionError> {
let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
let elem_pdu = pkg_elements.create_named_sub_element(ElementName::ISignalIPdu, name)?;
elem_pdu
.create_sub_element(ElementName::Length)?
.set_character_data(length.to_string())?;
Ok(Self(elem_pdu))
}
pub fn mapped_signals(&self) -> impl Iterator<Item = ISignalToIPduMapping> {
self.element()
.get_sub_element(ElementName::ISignalToPduMappings)
.into_iter()
.flat_map(|mappings| mappings.sub_elements())
.filter_map(|elem| ISignalToIPduMapping::try_from(elem).ok())
}
pub fn map_signal(
&self,
signal: &ISignal,
start_position: u32,
byte_order: ByteOrder,
update_bit: Option<u32>,
transfer_property: TransferProperty,
) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
let signal_name = signal
.name()
.ok_or(AutosarAbstractionError::InvalidParameter("invalid signal".to_string()))?;
let length = self.length().unwrap_or(0);
let mut validator = SignalMappingValidator::new(length);
for mapping in self.mapped_signals() {
if let (Some(m_signal), Some(m_start_pos), Some(m_byte_order)) =
(mapping.signal(), mapping.start_position(), mapping.byte_order())
{
let len = m_signal.length().unwrap_or(0);
validator.add_signal(m_start_pos, len, m_byte_order, mapping.update_bit());
}
}
if !validator.add_signal(start_position, signal.length().unwrap_or(0), byte_order, update_bit) {
return Err(AutosarAbstractionError::InvalidParameter(format!(
"Cannot map signal {signal_name} to an overalapping position in the pdu"
)));
}
if let Some(signal_group) = signal.signal_group() {
if !self
.mapped_signals()
.filter_map(|mapping| mapping.signal_group())
.any(|grp| grp == signal_group)
{
return Err(AutosarAbstractionError::InvalidParameter(
"Cannot map signal to pdu, because it is part of an unmapped signal group.".to_string(),
));
}
}
for pt in self.pdu_triggerings() {
let st = pt.add_signal_triggering(signal)?;
for pdu_port in pt.pdu_ports() {
if let (Some(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
st.connect_to_ecu(&ecu, direction)?;
}
}
}
let model = self.element().model()?;
let base_path = self.element().path()?;
let name = make_unique_name(&model, &base_path, &signal_name);
let mappings = self
.element()
.get_or_create_sub_element(ElementName::ISignalToPduMappings)?;
ISignalToIPduMapping::new_with_signal(
&name,
&mappings,
signal,
start_position,
byte_order,
update_bit,
transfer_property,
)
}
pub fn map_signal_group(
&self,
signal_group: &ISignalGroup,
) -> Result<ISignalToIPduMapping, AutosarAbstractionError> {
let signal_group_name = signal_group.name().ok_or(AutosarAbstractionError::InvalidParameter(
"invalid signal group".to_string(),
))?;
for pt in self.pdu_triggerings() {
let st = pt.add_signal_group_triggering(signal_group)?;
for pdu_port in pt.pdu_ports() {
if let (Some(ecu), Some(direction)) = (pdu_port.ecu(), pdu_port.communication_direction()) {
st.connect_to_ecu(&ecu, direction)?;
}
}
}
let model = self.element().model()?;
let base_path = self.element().path()?;
let name = make_unique_name(&model, &base_path, &signal_group_name);
let mappings = self
.element()
.get_or_create_sub_element(ElementName::ISignalToPduMappings)?;
ISignalToIPduMapping::new_with_group(&name, &mappings, signal_group)
}
pub fn set_timing(&self, timing_spec: &IpduTiming) -> Result<(), AutosarAbstractionError> {
if let Some(timing_elem) = self.element().get_sub_element(ElementName::IPduTimingSpecifications) {
self.element().remove_sub_element(timing_elem)?;
}
let timing_elem = self
.element()
.create_sub_element(ElementName::IPduTimingSpecifications)?
.create_sub_element(ElementName::IPduTiming)?;
if let Some(min_delay) = timing_spec.minimum_delay {
timing_elem
.create_sub_element(ElementName::MinimumDelay)?
.set_character_data(min_delay)?;
}
if let Some(transmission_mode_true_timing) = &timing_spec.transmission_mode_true_timing {
let tmtt_elem = timing_elem
.get_or_create_sub_element(ElementName::TransmissionModeDeclaration)?
.create_sub_element(ElementName::TransmissionModeTrueTiming)?;
Self::set_transmission_mode_timinig(tmtt_elem, transmission_mode_true_timing)?;
}
if let Some(transmission_mode_false_timing) = &timing_spec.transmission_mode_false_timing {
let tmtf_elem = timing_elem
.get_or_create_sub_element(ElementName::TransmissionModeDeclaration)?
.create_sub_element(ElementName::TransmissionModeFalseTiming)?;
Self::set_transmission_mode_timinig(tmtf_elem, transmission_mode_false_timing)?;
}
Ok(())
}
fn set_transmission_mode_timinig(
timing_element: Element,
transmission_mode_timing: &TransmissionModeTiming,
) -> Result<(), AutosarAbstractionError> {
if let Some(cyclic_timing) = &transmission_mode_timing.cyclic_timing {
let ct_elem = timing_element.create_sub_element(ElementName::CyclicTiming)?;
ct_elem
.create_sub_element(ElementName::TimePeriod)?
.create_sub_element(ElementName::Value)?
.set_character_data(cyclic_timing.time_period)?;
if let Some(time_offset) = cyclic_timing.time_offset {
ct_elem
.create_sub_element(ElementName::TimeOffset)?
.create_sub_element(ElementName::Value)?
.set_character_data(time_offset)?;
}
}
if let Some(event_controlled_timing) = &transmission_mode_timing.event_controlled_timing {
let ect_elem = timing_element.create_sub_element(ElementName::EventControlledTiming)?;
ect_elem
.create_sub_element(ElementName::NumberOfRepetitions)?
.set_character_data(u64::from(event_controlled_timing.number_of_repetitions))?;
if let Some(repetition_period) = event_controlled_timing.repetition_period {
ect_elem
.create_sub_element(ElementName::RepetitionPeriod)?
.create_sub_element(ElementName::Value)?
.set_character_data(repetition_period)?;
}
}
Ok(())
}
#[must_use]
pub fn timing(&self) -> Option<IpduTiming> {
let timing_elem = self
.element()
.get_sub_element(ElementName::IPduTimingSpecifications)?
.get_sub_element(ElementName::IPduTiming)?;
let minimum_delay = timing_elem
.get_sub_element(ElementName::MinimumDelay)
.and_then(|md| md.character_data())
.and_then(|cdata| cdata.parse_float());
let transmission_mode_true_timing = timing_elem
.get_sub_element(ElementName::TransmissionModeDeclaration)
.and_then(|tmd| tmd.get_sub_element(ElementName::TransmissionModeTrueTiming))
.and_then(|tmtt| Self::transmission_mode_timing(&tmtt));
let transmission_mode_false_timing = timing_elem
.get_sub_element(ElementName::TransmissionModeDeclaration)
.and_then(|tmd| tmd.get_sub_element(ElementName::TransmissionModeFalseTiming))
.and_then(|tmtf| Self::transmission_mode_timing(&tmtf));
Some(IpduTiming {
minimum_delay,
transmission_mode_true_timing,
transmission_mode_false_timing,
})
}
fn transmission_mode_timing(timing_elem: &Element) -> Option<TransmissionModeTiming> {
let cyclic_timing = timing_elem.get_sub_element(ElementName::CyclicTiming).and_then(|ct| {
let time_period = ct
.get_sub_element(ElementName::TimePeriod)
.and_then(|tp| tp.get_sub_element(ElementName::Value))
.and_then(|val| val.character_data())
.and_then(|cdata| cdata.parse_float());
let time_offset = ct
.get_sub_element(ElementName::TimeOffset)
.and_then(|to| to.get_sub_element(ElementName::Value))
.and_then(|val| val.character_data())
.and_then(|cdata| cdata.parse_float());
time_period.map(|tp| CyclicTiming {
time_period: tp,
time_offset,
})
});
let event_controlled_timing = timing_elem
.get_sub_element(ElementName::EventControlledTiming)
.and_then(|ect| {
let number_of_repetitions = ect
.get_sub_element(ElementName::NumberOfRepetitions)
.and_then(|nr| nr.character_data())
.and_then(|cdata| cdata.parse_integer());
let repetition_period = ect
.get_sub_element(ElementName::RepetitionPeriod)
.and_then(|rp| rp.get_sub_element(ElementName::Value))
.and_then(|val| val.character_data())
.and_then(|cdata| cdata.parse_float());
number_of_repetitions.map(|nr| EventControlledTiming {
number_of_repetitions: nr,
repetition_period,
})
});
Some(TransmissionModeTiming {
cyclic_timing,
event_controlled_timing,
})
}
}
impl AbstractPdu for ISignalIPdu {}
impl AbstractIpdu for ISignalIPdu {}
impl From<ISignalIPdu> for Pdu {
fn from(value: ISignalIPdu) -> Self {
Pdu::ISignalIPdu(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ISignalToIPduMapping(Element);
abstraction_element!(ISignalToIPduMapping, ISignalToIPduMapping);
impl ISignalToIPduMapping {
fn new_with_signal(
name: &str,
mappings: &Element,
signal: &ISignal,
start_position: u32,
byte_order: ByteOrder,
update_bit: Option<u32>,
transfer_property: TransferProperty,
) -> Result<Self, AutosarAbstractionError> {
let signal_mapping = mappings.create_named_sub_element(ElementName::ISignalToIPduMapping, name)?;
signal_mapping
.create_sub_element(ElementName::ISignalRef)?
.set_reference_target(signal.element())?;
signal_mapping
.create_sub_element(ElementName::PackingByteOrder)?
.set_character_data::<EnumItem>(byte_order.into())?;
signal_mapping
.create_sub_element(ElementName::StartPosition)?
.set_character_data(u64::from(start_position))?;
signal_mapping
.create_sub_element(ElementName::TransferProperty)?
.set_character_data::<EnumItem>(transfer_property.into())?;
if let Some(update_bit_pos) = update_bit {
signal_mapping
.create_sub_element(ElementName::UpdateIndicationBitPosition)?
.set_character_data(u64::from(update_bit_pos))?;
}
Ok(Self(signal_mapping))
}
fn new_with_group(
name: &str,
mappings: &Element,
signal_group: &ISignalGroup,
) -> Result<Self, AutosarAbstractionError> {
let signal_mapping = mappings.create_named_sub_element(ElementName::ISignalToIPduMapping, name)?;
signal_mapping
.create_sub_element(ElementName::ISignalGroupRef)?
.set_reference_target(signal_group.element())?;
Ok(Self(signal_mapping))
}
#[must_use]
pub fn signal(&self) -> Option<ISignal> {
self.element()
.get_sub_element(ElementName::ISignalRef)
.and_then(|sigref| sigref.get_reference_target().ok())
.and_then(|signal_elem| ISignal::try_from(signal_elem).ok())
}
pub fn set_byte_order(&self, byte_order: ByteOrder) -> Result<(), AutosarAbstractionError> {
self.element()
.get_or_create_sub_element(ElementName::PackingByteOrder)?
.set_character_data::<EnumItem>(byte_order.into())?;
Ok(())
}
#[must_use]
pub fn byte_order(&self) -> Option<ByteOrder> {
self.element()
.get_sub_element(ElementName::PackingByteOrder)
.and_then(|pbo| pbo.character_data())
.and_then(|cdata| cdata.enum_value())
.and_then(|enumval| enumval.try_into().ok())
}
#[must_use]
pub fn start_position(&self) -> Option<u32> {
self.element()
.get_sub_element(ElementName::StartPosition)
.and_then(|sp_elem| sp_elem.character_data())
.and_then(|cdata| cdata.parse_integer())
}
#[must_use]
pub fn update_bit(&self) -> Option<u32> {
self.element()
.get_sub_element(ElementName::UpdateIndicationBitPosition)
.and_then(|uibp| uibp.character_data())
.and_then(|cdata| cdata.parse_integer())
}
pub fn set_transfer_property(&self, transfer_property: TransferProperty) -> Result<(), AutosarAbstractionError> {
self.element()
.get_or_create_sub_element(ElementName::TransferProperty)?
.set_character_data::<EnumItem>(transfer_property.into())?;
Ok(())
}
#[must_use]
pub fn transfer_property(&self) -> Option<TransferProperty> {
self.element()
.get_sub_element(ElementName::TransferProperty)
.and_then(|pbo| pbo.character_data())
.and_then(|cdata| cdata.enum_value())
.and_then(|enumval| enumval.try_into().ok())
}
#[must_use]
pub fn signal_group(&self) -> Option<ISignalGroup> {
self.element()
.get_sub_element(ElementName::ISignalGroupRef)
.and_then(|sgref| sgref.get_reference_target().ok())
.and_then(|siggrp_elem| ISignalGroup::try_from(siggrp_elem).ok())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct IpduTiming {
pub minimum_delay: Option<f64>,
pub transmission_mode_true_timing: Option<TransmissionModeTiming>,
pub transmission_mode_false_timing: Option<TransmissionModeTiming>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TransmissionModeTiming {
pub cyclic_timing: Option<CyclicTiming>,
pub event_controlled_timing: Option<EventControlledTiming>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct CyclicTiming {
pub time_period: f64,
pub time_offset: Option<f64>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EventControlledTiming {
pub number_of_repetitions: u32,
pub repetition_period: Option<f64>,
}
pub struct SignalMappingValidator {
bitmap: Vec<u8>,
}
impl SignalMappingValidator {
#[must_use]
pub fn new(length: u32) -> Self {
Self {
bitmap: vec![0; length as usize],
}
}
pub fn add_signal(
&mut self,
bit_position: u32,
bit_length: u64,
byte_order: ByteOrder,
update_bit: Option<u32>,
) -> bool {
let bit_position = u64::from(bit_position);
let first_byte = (bit_position / 8) as usize;
let bit_offset = bit_position % 8; let first_byte_bits; let mut first_mask;
if byte_order == ByteOrder::MostSignificantByteFirst {
first_byte_bits = (bit_offset + 1).min(bit_length);
first_mask = ((1u16 << (bit_offset + 1)) - 1) as u8;
if bit_offset + 1 != first_byte_bits {
let pos2 = bit_offset - first_byte_bits;
let subtract_mask = (1u8 << pos2) - 1;
first_mask -= subtract_mask;
}
} else {
first_byte_bits = (8 - bit_offset).min(bit_length); first_mask = !((1u16 << bit_offset) - 1) as u8; if bit_offset + first_byte_bits < 8 {
let pos2 = bit_offset + first_byte_bits;
let subtract_mask = !((1u8 << pos2) - 1);
first_mask -= subtract_mask;
}
}
let full_bytes = (bit_length - first_byte_bits) as usize / 8;
let end_bits = (bit_length - first_byte_bits) % 8;
let mut result = self.apply_mask(first_mask, first_byte);
result &= self.apply_full_bytes(first_byte + 1, full_bytes);
if end_bits > 0 {
let end_mask = if byte_order == ByteOrder::MostSignificantByteFirst {
!((1u8 << end_bits) - 1)
} else {
(1u8 << end_bits) - 1
};
result &= self.apply_mask(end_mask, first_byte + full_bytes + 1);
}
if let Some(update_bit) = update_bit {
let position = (update_bit / 8) as usize;
let bit_pos = update_bit % 8;
let mask = 1 << bit_pos;
result &= self.apply_mask(mask, position);
}
result
}
fn apply_mask(&mut self, mask: u8, position: usize) -> bool {
if position < self.bitmap.len() {
let result = self.bitmap[position] & mask == 0;
self.bitmap[position] |= mask;
result
} else {
false
}
}
fn apply_full_bytes(&mut self, position: usize, count: usize) -> bool {
let mut result = true;
if count > 0 {
let limit = self.bitmap.len().min(position + count);
for idx in position..limit {
result &= self.apply_mask(0xff, idx);
}
result &= limit == position + count;
}
result
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{ByteOrder, SystemCategory};
use autosar_data::{AutosarModel, AutosarVersion};
#[test]
fn isignal_ipdu() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::Autosar_00048).unwrap();
let package = ArPackage::get_or_create(&model, "/pkg").unwrap();
let system = package.create_system("system", SystemCategory::EcuExtract).unwrap();
let pdu = system.create_isignal_ipdu("isignal_ipdu", &package, 8).unwrap();
assert_eq!(pdu.name().unwrap(), "isignal_ipdu");
assert_eq!(pdu.length().unwrap(), 8);
let syssignal = package.create_system_signal("syssignal").unwrap();
let isignal = system.create_isignal("isignal", &package, 4, &syssignal, None).unwrap();
let mapping = pdu
.map_signal(
&isignal,
0,
ByteOrder::MostSignificantByteFirst,
Some(5),
TransferProperty::Triggered,
)
.unwrap();
assert_eq!(mapping.signal().unwrap(), isignal);
assert_eq!(mapping.start_position().unwrap(), 0);
assert_eq!(mapping.update_bit(), Some(5));
assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteFirst);
mapping.set_byte_order(ByteOrder::MostSignificantByteLast).unwrap();
assert_eq!(mapping.byte_order().unwrap(), ByteOrder::MostSignificantByteLast);
assert_eq!(mapping.transfer_property().unwrap(), TransferProperty::Triggered);
mapping.set_transfer_property(TransferProperty::Pending).unwrap();
assert_eq!(mapping.transfer_property().unwrap(), TransferProperty::Pending);
let syssignal_group = package.create_system_signal_group("syssignal_group").unwrap();
let signal_group = system
.create_i_signal_group("signal_group", &package, &syssignal_group)
.unwrap();
let grouped_syssignal = package.create_system_signal("groups_syssignal").unwrap();
syssignal_group.add_signal(&grouped_syssignal).unwrap();
let grouped_isignal = system
.create_isignal("grouped_isignal", &package, 4, &grouped_syssignal, None)
.unwrap();
signal_group.add_signal(&grouped_isignal).unwrap();
assert_eq!(grouped_isignal.signal_group().unwrap(), signal_group);
let result = pdu.map_signal(
&grouped_isignal,
9,
ByteOrder::MostSignificantByteFirst,
None,
TransferProperty::Triggered,
);
assert!(result.is_err());
let mapping = pdu.map_signal_group(&signal_group).unwrap();
assert_eq!(mapping.signal_group().unwrap(), signal_group);
let _mapping = pdu
.map_signal(
&grouped_isignal,
9,
ByteOrder::MostSignificantByteFirst,
None,
TransferProperty::Triggered,
)
.unwrap();
}
#[test]
fn validate_signal_mapping() {
let mut validator = SignalMappingValidator::new(4);
let result = validator.add_signal(0, 2, ByteOrder::MostSignificantByteLast, None);
assert!(result);
assert_eq!(validator.bitmap[0], 0x03);
let mut validator = SignalMappingValidator::new(4);
let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteLast, None);
assert!(result);
assert_eq!(validator.bitmap[0], 0xE0);
assert_eq!(validator.bitmap[1], 0x7F);
let mut validator = SignalMappingValidator::new(4);
let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteFirst, None);
assert!(result);
assert_eq!(validator.bitmap[0], 0x3F);
assert_eq!(validator.bitmap[1], 0xF0);
let result = validator.add_signal(5, 10, ByteOrder::MostSignificantByteLast, None);
assert!(!result);
assert_eq!(validator.bitmap[0], 0xFF);
assert_eq!(validator.bitmap[1], 0xFF);
let mut validator = SignalMappingValidator::new(4);
let result = validator.add_signal(0, 32, ByteOrder::MostSignificantByteLast, None);
assert!(result);
assert_eq!(validator.bitmap[0], 0xFF);
assert_eq!(validator.bitmap[1], 0xFF);
assert_eq!(validator.bitmap[2], 0xFF);
assert_eq!(validator.bitmap[3], 0xFF);
let mut validator = SignalMappingValidator::new(4);
let result = validator.add_signal(7, 32, ByteOrder::MostSignificantByteFirst, None);
assert!(result);
assert_eq!(validator.bitmap[0], 0xFF);
assert_eq!(validator.bitmap[1], 0xFF);
assert_eq!(validator.bitmap[2], 0xFF);
assert_eq!(validator.bitmap[3], 0xFF);
let mut validator = SignalMappingValidator::new(8);
let result = validator.add_signal(7, 16, ByteOrder::MostSignificantByteFirst, Some(60));
assert!(result);
let result = validator.add_signal(16, 3, ByteOrder::MostSignificantByteLast, Some(61));
assert!(result);
let result = validator.add_signal(19, 7, ByteOrder::MostSignificantByteLast, Some(62));
assert!(result);
let result = validator.add_signal(26, 30, ByteOrder::MostSignificantByteLast, Some(63));
assert!(result);
let result = validator.add_signal(59, 4, ByteOrder::MostSignificantByteFirst, None);
assert!(result);
assert_eq!(validator.bitmap, [0xFF; 8]);
}
#[test]
fn ipdu_timing() {
let model = AutosarModel::new();
let _file = model.create_file("filename", AutosarVersion::Autosar_00048).unwrap();
let package = ArPackage::get_or_create(&model, "/pkg").unwrap();
let pdu = ISignalIPdu::new("pdu_name", &package, 8).unwrap();
let timing_spec = IpduTiming {
minimum_delay: Some(0.1),
transmission_mode_true_timing: Some(TransmissionModeTiming {
cyclic_timing: Some(CyclicTiming {
time_period: 0.2,
time_offset: Some(0.3),
}),
event_controlled_timing: Some(EventControlledTiming {
number_of_repetitions: 4,
repetition_period: Some(0.5),
}),
}),
transmission_mode_false_timing: Some(TransmissionModeTiming {
cyclic_timing: Some(CyclicTiming {
time_period: 0.6,
time_offset: Some(0.7),
}),
event_controlled_timing: Some(EventControlledTiming {
number_of_repetitions: 8,
repetition_period: Some(0.9),
}),
}),
};
pdu.set_timing(&timing_spec).unwrap();
let timing_spec2 = pdu.timing().unwrap();
assert_eq!(timing_spec, timing_spec2);
}
}