autosar_data_abstraction/communication/frame/
can.rs1use crate::communication::{
2 AbstractFrame, AbstractFrameTriggering, AbstractPdu, CanPhysicalChannel, CommunicationDirection, Frame, FramePort,
3 FrameTriggering, Pdu, PduToFrameMapping, PduTriggering,
4};
5use crate::{
6 AbstractionElement, ArPackage, AutosarAbstractionError, ByteOrder, EcuInstance, IdentifiableAbstractionElement,
7 abstraction_element, make_unique_name,
8};
9use autosar_data::{Element, ElementName, EnumItem};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct CanFrame(Element);
14abstraction_element!(CanFrame, CanFrame);
15impl IdentifiableAbstractionElement for CanFrame {}
16
17impl CanFrame {
18 pub(crate) fn new(name: &str, package: &ArPackage, byte_length: u64) -> Result<Self, AutosarAbstractionError> {
19 let pkg_elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
20 let can_frame = pkg_elements.create_named_sub_element(ElementName::CanFrame, name)?;
21
22 can_frame
23 .create_sub_element(ElementName::FrameLength)?
24 .set_character_data(byte_length.to_string())?;
25
26 Ok(Self(can_frame))
27 }
28}
29
30impl AbstractFrame for CanFrame {
31 type FrameTriggeringType = CanFrameTriggering;
32
33 fn frame_triggerings(&self) -> Vec<CanFrameTriggering> {
35 let model_result = self.element().model();
36 let path_result = self.element().path();
37 if let (Ok(model), Ok(path)) = (model_result, path_result) {
38 model
39 .get_references_to(&path)
40 .iter()
41 .filter_map(|e| {
42 e.upgrade()
43 .and_then(|ref_elem| ref_elem.named_parent().ok().flatten())
44 .and_then(|elem| CanFrameTriggering::try_from(elem).ok())
45 })
46 .collect()
47 } else {
48 vec![]
49 }
50 }
51
52 fn map_pdu<T: AbstractPdu>(
54 &self,
55 gen_pdu: &T,
56 start_position: u32,
57 byte_order: ByteOrder,
58 update_bit: Option<u32>,
59 ) -> Result<PduToFrameMapping, AutosarAbstractionError> {
60 Frame::Can(self.clone()).map_pdu(gen_pdu, start_position, byte_order, update_bit)
61 }
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Hash)]
68pub struct CanFrameTriggering(Element);
69abstraction_element!(CanFrameTriggering, CanFrameTriggering);
70impl IdentifiableAbstractionElement for CanFrameTriggering {}
71
72impl CanFrameTriggering {
73 pub(crate) fn new(
74 channel: &CanPhysicalChannel,
75 frame: &CanFrame,
76 identifier: u32,
77 addressing_mode: CanAddressingMode,
78 frame_type: CanFrameType,
79 ) -> Result<Self, AutosarAbstractionError> {
80 let model = channel.element().model()?;
81 let base_path = channel.element().path()?;
82 let frame_name = frame
83 .name()
84 .ok_or(AutosarAbstractionError::InvalidParameter("invalid frame".to_string()))?;
85 let ft_name = format!("FT_{frame_name}");
86 let ft_name = make_unique_name(&model, &base_path, &ft_name);
87
88 let frame_triggerings = channel
89 .element()
90 .get_or_create_sub_element(ElementName::FrameTriggerings)?;
91 let can_triggering = frame_triggerings.create_named_sub_element(ElementName::CanFrameTriggering, &ft_name)?;
92
93 can_triggering
94 .create_sub_element(ElementName::FrameRef)?
95 .set_reference_target(frame.element())?;
96
97 let ft = Self(can_triggering);
98 ft.set_addressing_mode(addressing_mode)?;
99 ft.set_frame_type(frame_type)?;
100 if let Err(error) = ft.set_identifier(identifier) {
101 let _ = frame_triggerings.remove_sub_element(ft.0);
102 return Err(error);
103 }
104
105 for pdu_mapping in frame.mapped_pdus() {
106 if let Some(pdu) = pdu_mapping.pdu() {
107 ft.add_pdu_triggering(&pdu)?;
108 }
109 }
110
111 Ok(ft)
112 }
113
114 pub fn set_identifier(&self, identifier: u32) -> Result<(), AutosarAbstractionError> {
116 let amode = self.addressing_mode().unwrap_or(CanAddressingMode::Standard);
117 if amode == CanAddressingMode::Standard && identifier > 0x7ff {
118 return Err(AutosarAbstractionError::InvalidParameter(format!(
119 "CAN-ID {identifier} is outside the 11-bit range allowed by standard addressing"
120 )));
121 } else if identifier > 0x1fff_ffff {
122 return Err(AutosarAbstractionError::InvalidParameter(format!(
123 "CAN-ID {identifier} is outside the 29-bit range allowed by extended addressing"
124 )));
125 }
126 self.element()
127 .get_or_create_sub_element(ElementName::Identifier)?
128 .set_character_data(identifier.to_string())?;
129
130 Ok(())
131 }
132
133 #[must_use]
135 pub fn identifier(&self) -> Option<u32> {
136 self.element()
137 .get_sub_element(ElementName::Identifier)?
138 .character_data()?
139 .parse_integer()
140 }
141
142 pub fn set_addressing_mode(&self, addressing_mode: CanAddressingMode) -> Result<(), AutosarAbstractionError> {
144 self.element()
145 .get_or_create_sub_element(ElementName::CanAddressingMode)?
146 .set_character_data::<EnumItem>(addressing_mode.into())?;
147
148 Ok(())
149 }
150
151 #[must_use]
153 pub fn addressing_mode(&self) -> Option<CanAddressingMode> {
154 self.element()
155 .get_sub_element(ElementName::CanAddressingMode)?
156 .character_data()?
157 .enum_value()?
158 .try_into()
159 .ok()
160 }
161
162 pub fn set_frame_type(&self, frame_type: CanFrameType) -> Result<(), AutosarAbstractionError> {
164 self.element()
165 .get_or_create_sub_element(ElementName::CanFrameRxBehavior)?
166 .set_character_data::<EnumItem>(frame_type.into())?;
167 self.element()
168 .get_or_create_sub_element(ElementName::CanFrameTxBehavior)?
169 .set_character_data::<EnumItem>(frame_type.into())?;
170
171 Ok(())
172 }
173
174 #[must_use]
176 pub fn frame_type(&self) -> Option<CanFrameType> {
177 self.element()
178 .get_sub_element(ElementName::CanFrameTxBehavior)?
179 .character_data()?
180 .enum_value()?
181 .try_into()
182 .ok()
183 }
184
185 pub(crate) fn add_pdu_triggering(&self, pdu: &Pdu) -> Result<PduTriggering, AutosarAbstractionError> {
186 FrameTriggering::Can(self.clone()).add_pdu_triggering(pdu)
187 }
188
189 pub fn physical_channel(&self) -> Result<CanPhysicalChannel, AutosarAbstractionError> {
191 let channel_elem = self.element().named_parent()?.unwrap();
192 CanPhysicalChannel::try_from(channel_elem)
193 }
194
195 pub fn connect_to_ecu(
199 &self,
200 ecu: &EcuInstance,
201 direction: CommunicationDirection,
202 ) -> Result<FramePort, AutosarAbstractionError> {
203 FrameTriggering::Can(self.clone()).connect_to_ecu(ecu, direction)
204 }
205}
206
207impl AbstractFrameTriggering for CanFrameTriggering {
208 type FrameType = CanFrame;
209}
210
211impl From<CanFrameTriggering> for FrameTriggering {
212 fn from(cft: CanFrameTriggering) -> Self {
213 FrameTriggering::Can(cft)
214 }
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub enum CanAddressingMode {
222 Standard,
224 Extended,
226}
227
228impl TryFrom<EnumItem> for CanAddressingMode {
229 type Error = AutosarAbstractionError;
230
231 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
232 match value {
233 EnumItem::Standard => Ok(CanAddressingMode::Standard),
234 EnumItem::Extended => Ok(CanAddressingMode::Extended),
235 _ => Err(AutosarAbstractionError::ValueConversionError {
236 value: value.to_string(),
237 dest: "CanAddressingMode".to_string(),
238 }),
239 }
240 }
241}
242
243impl From<CanAddressingMode> for EnumItem {
244 fn from(value: CanAddressingMode) -> Self {
245 match value {
246 CanAddressingMode::Standard => EnumItem::Standard,
247 CanAddressingMode::Extended => EnumItem::Extended,
248 }
249 }
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq)]
256pub enum CanFrameType {
257 Can20,
259 CanFd,
261 Any,
263}
264
265impl TryFrom<EnumItem> for CanFrameType {
266 type Error = AutosarAbstractionError;
267
268 fn try_from(value: EnumItem) -> Result<Self, Self::Error> {
269 match value {
270 EnumItem::Can20 => Ok(CanFrameType::Can20),
271 EnumItem::CanFd => Ok(CanFrameType::CanFd),
272 EnumItem::Any => Ok(CanFrameType::Any),
273 _ => Err(AutosarAbstractionError::ValueConversionError {
274 value: value.to_string(),
275 dest: "CanFrameType".to_string(),
276 }),
277 }
278 }
279}
280
281impl From<CanFrameType> for EnumItem {
282 fn from(value: CanFrameType) -> Self {
283 match value {
284 CanFrameType::Can20 => EnumItem::Can20,
285 CanFrameType::CanFd => EnumItem::CanFd,
286 CanFrameType::Any => EnumItem::Any,
287 }
288 }
289}
290
291#[cfg(test)]
294mod test {
295 use super::*;
296 use crate::{AutosarModelAbstraction, ByteOrder, SystemCategory, communication::AbstractPhysicalChannel};
297 use autosar_data::AutosarVersion;
298
299 #[test]
300 fn can_frame() {
301 let model = AutosarModelAbstraction::create("test", AutosarVersion::LATEST);
302 let package = model.get_or_create_package("/package").unwrap();
303 let system = package.create_system("System", SystemCategory::EcuExtract).unwrap();
304 let can_cluster = system.create_can_cluster("Cluster", &package, None).unwrap();
305 let channel = can_cluster.create_physical_channel("Channel").unwrap();
306
307 let ecu_instance = system.create_ecu_instance("ECU", &package).unwrap();
308 let can_controller = ecu_instance.create_can_communication_controller("Controller").unwrap();
309 can_controller.connect_physical_channel("connection", &channel).unwrap();
310 assert_eq!(channel.connectors().count(), 1);
311 assert_eq!(channel.connectors().next().unwrap().name().unwrap(), "connection");
312
313 let pdu1 = system.create_isignal_ipdu("pdu1", &package, 8).unwrap();
314 let pdu2 = system.create_isignal_ipdu("pdu2", &package, 8).unwrap();
315
316 let frame1 = system.create_can_frame("frame1", &package, 8).unwrap();
318 let frame2 = system.create_can_frame("frame2", &package, 8).unwrap();
319
320 assert_eq!(frame1.length().unwrap(), 8);
321 frame1.set_length(6).unwrap();
322 assert_eq!(frame1.length().unwrap(), 6);
323
324 let mapping1 = frame1
326 .map_pdu(&pdu1, 7, ByteOrder::MostSignificantByteFirst, None)
327 .unwrap();
328 assert!(frame1.mapped_pdus().count() == 1);
329 assert_eq!(frame1.mapped_pdus().next().unwrap(), mapping1);
330
331 let frame_triggering1 = channel
333 .trigger_frame(&frame1, 0x123, CanAddressingMode::Standard, CanFrameType::Can20)
334 .unwrap();
335 assert_eq!(frame1.frame_triggerings().len(), 1);
336 let frame_triggering2 = channel
337 .trigger_frame(&frame2, 0x456, CanAddressingMode::Standard, CanFrameType::Can20)
338 .unwrap();
339 assert_eq!(frame2.frame_triggerings().len(), 1);
340 assert_eq!(channel.frame_triggerings().count(), 2);
341
342 let result = frame_triggering1.set_identifier(0xffff_ffff);
344 assert!(result.is_err());
345
346 assert_eq!(frame_triggering1.pdu_triggerings().count(), 1);
348 assert_eq!(frame_triggering2.pdu_triggerings().count(), 0);
350
351 let mapping2 = frame2
353 .map_pdu(&pdu2, 7, ByteOrder::MostSignificantByteFirst, None)
354 .unwrap();
355 assert!(frame2.mapped_pdus().count() == 1);
356 assert_eq!(frame2.mapped_pdus().next().unwrap(), mapping2);
357
358 assert_eq!(frame_triggering2.pdu_triggerings().count(), 1);
360
361 let port1 = frame_triggering1
363 .connect_to_ecu(&ecu_instance, CommunicationDirection::Out)
364 .unwrap();
365 let port2 = frame_triggering2
366 .connect_to_ecu(&ecu_instance, CommunicationDirection::In)
367 .unwrap();
368
369 assert_eq!(frame_triggering1.identifier().unwrap(), 0x123);
370 assert_eq!(
371 frame_triggering1.addressing_mode().unwrap(),
372 CanAddressingMode::Standard
373 );
374 assert_eq!(frame_triggering1.frame_type().unwrap(), CanFrameType::Can20);
375 assert_eq!(frame_triggering1.frame().unwrap(), frame1);
376 assert_eq!(frame_triggering1.physical_channel().unwrap(), channel);
377
378 assert_eq!(mapping1.pdu().unwrap(), pdu1.into());
379 assert_eq!(mapping1.byte_order().unwrap(), ByteOrder::MostSignificantByteFirst);
380 assert_eq!(mapping1.start_position().unwrap(), 7);
381 assert_eq!(mapping1.update_bit(), None);
382
383 assert_eq!(port1.ecu().unwrap(), ecu_instance);
384 assert_eq!(port1.communication_direction().unwrap(), CommunicationDirection::Out);
385 assert_eq!(port2.ecu().unwrap(), ecu_instance);
386 assert_eq!(port2.communication_direction().unwrap(), CommunicationDirection::In);
387 port2.set_communication_direction(CommunicationDirection::Out).unwrap();
388 assert_eq!(port2.communication_direction().unwrap(), CommunicationDirection::Out);
389 }
390}