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