autosar_e2e/profiles/
profile7m.rs

1//! # E2E Profile 7M Implementation
2//!
3//! Profile 7M is identical to Profile 7 but includes additional fields
4//! in CRC calculation: message_type, message_result, and source_id
5
6use crate::profile7::{Profile7, Profile7Config}; // Reuse Profile7Config
7use crate::{E2EProfile, E2EResult, E2EStatus};
8
9const BITS_PER_BYTE: u32 = 8;
10
11/// Check Item for E2E Profile 7
12#[derive(Debug, Clone)]
13pub struct Profile7mCheck {
14    rx_source_id: u32,
15    rx_message_type: u8,
16    rx_message_result: u8,
17}
18
19/// E2E Profile 7m Implementation - minimal code by reusing Profile7 logic
20#[derive(Clone)]
21pub struct Profile7m {
22    base: Profile7,
23    config: Profile7Config,
24    pub message_type: u8,
25    pub message_result: u8,
26    pub source_id: u32,
27}
28
29impl Profile7m {
30    fn write_source_id(&self, data: &mut [u8]) {
31        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
32        data[offset + 20..=offset + 23].copy_from_slice(&self.source_id.to_be_bytes());
33    }
34    fn write_message_type(&self, data: &mut [u8]) {
35        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
36        data[offset + 20] = (data[offset + 20] & 0x3F) | ((self.message_type & 0x03) << 6);
37    }
38    fn write_message_result(&self, data: &mut [u8]) {
39        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
40        data[offset + 20] = (data[offset + 20] & 0xCF) | ((self.message_result & 0x03) << 4);
41    }
42    fn read_source_id(&self, data: &[u8]) -> u32 {
43        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
44        u32::from_be_bytes([
45            data[offset + 20],
46            data[offset + 21],
47            data[offset + 22],
48            data[offset + 23],
49        ]) & 0x0FFFFFFF
50    }
51    fn read_message_type(&self, data: &[u8]) -> u8 {
52        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
53        (data[offset + 20] >> 6) & 0x03
54    }
55    fn read_message_result(&self, data: &[u8]) -> u8 {
56        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
57        (data[offset + 20] >> 4) & 0x03
58    }
59    fn do_checks(&mut self, check_items: Profile7mCheck) -> E2EStatus {
60        if self.source_id != check_items.rx_source_id {
61            return E2EStatus::SourceIdError;
62        }
63        if self.message_result != check_items.rx_message_result {
64            return E2EStatus::MessageResultError;
65        }
66        if self.message_type != check_items.rx_message_type {
67            return E2EStatus::MessageTypeError;
68        }
69        E2EStatus::Ok
70    }
71}
72
73impl E2EProfile for Profile7m {
74    type Config = Profile7Config;
75
76    fn new(config: Self::Config) -> E2EResult<Self> {
77        // Validate using Profile7's validation
78        let base = crate::profile7::Profile7::new(config.clone())?; // This validates config
79        Ok(Self {
80            base,
81            config,
82            message_type: 0x00,
83            message_result: 0x00,
84            source_id: 0x0a0b0c0d,
85        })
86    }
87
88    fn protect(&mut self, data: &mut [u8]) -> E2EResult<()> {
89        // Write Profile7m specific fields first
90        self.write_source_id(data);
91        self.write_message_result(data);
92        self.write_message_type(data);
93        self.base.protect(data)?;
94        Ok(())
95    }
96
97    fn check(&mut self, data: &[u8]) -> E2EResult<E2EStatus> {
98        let mut status = self.base.check(data)?;
99        let check_items = Profile7mCheck {
100            rx_source_id: self.read_source_id(data),
101            rx_message_result: self.read_message_result(data),
102            rx_message_type: self.read_message_type(data),
103        };
104        if (status == E2EStatus::Ok) || (status == E2EStatus::OkSomeLost) {
105            status = self.do_checks(check_items);
106        }
107        Ok(status)
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    #[test]
115    fn test_profile7m_basic_request_example() {
116        let config = Profile7Config {
117            min_data_length: 192,
118            ..Default::default()
119        };
120
121        let mut profile_tx = Profile7m::new(config.clone()).unwrap();
122        let mut profile_rx = Profile7m::new(config).unwrap();
123
124        let mut data = vec![
125            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127        ];
128        profile_tx.source_id = 0x00123456;
129        profile_tx.message_result = 0;
130        profile_tx.message_type = 0;
131        profile_tx.protect(&mut data).unwrap();
132        // CRC check
133        assert_eq!(data[0], 0xae);
134        assert_eq!(data[1], 0x96);
135        assert_eq!(data[2], 0xa7);
136        assert_eq!(data[3], 0xd0);
137        assert_eq!(data[4], 0xa5);
138        assert_eq!(data[5], 0x01);
139        assert_eq!(data[6], 0x75);
140        assert_eq!(data[7], 0x94);
141        // length check
142        assert_eq!(data[8], 0x00);
143        assert_eq!(data[9], 0x00);
144        assert_eq!(data[10], 0x00);
145        assert_eq!(data[11], 0x1c);
146        // counter check
147        assert_eq!(data[12], 0x00);
148        assert_eq!(data[13], 0x00);
149        assert_eq!(data[14], 0x00);
150        assert_eq!(data[15], 0x00);
151        // data id check
152        assert_eq!(data[16], 0x0a);
153        assert_eq!(data[17], 0x0b);
154        assert_eq!(data[18], 0x0c);
155        assert_eq!(data[19], 0x0d);
156        // message type/result/source id check
157        assert_eq!(data[20], 0x00);
158        assert_eq!(data[21], 0x12);
159        assert_eq!(data[22], 0x34);
160        assert_eq!(data[23], 0x56);
161        profile_rx.source_id = 0x00123456;
162        profile_rx.message_result = 0;
163        profile_rx.message_type = 0;
164        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
165    }
166
167    #[test]
168    fn test_profile7m_basic_response_example() {
169        let config = Profile7Config {
170            min_data_length: 192,
171            ..Default::default()
172        };
173
174        let mut profile_tx = Profile7m::new(config.clone()).unwrap();
175        let mut profile_rx = Profile7m::new(config).unwrap();
176
177        let mut data = vec![
178            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180        ];
181        profile_tx.source_id = 0x00123456;
182        profile_tx.message_result = 0;
183        profile_tx.message_type = 1;
184        profile_tx.protect(&mut data).unwrap();
185        // CRC check
186        assert_eq!(data[0], 0xa6);
187        assert_eq!(data[1], 0x2d);
188        assert_eq!(data[2], 0x64);
189        assert_eq!(data[3], 0x86);
190        assert_eq!(data[4], 0xe8);
191        assert_eq!(data[5], 0x3f);
192        assert_eq!(data[6], 0x2c);
193        assert_eq!(data[7], 0xaf);
194        // length check
195        assert_eq!(data[8], 0x00);
196        assert_eq!(data[9], 0x00);
197        assert_eq!(data[10], 0x00);
198        assert_eq!(data[11], 0x1c);
199        // counter check
200        assert_eq!(data[12], 0x00);
201        assert_eq!(data[13], 0x00);
202        assert_eq!(data[14], 0x00);
203        assert_eq!(data[15], 0x00);
204        // data id check
205        assert_eq!(data[16], 0x0a);
206        assert_eq!(data[17], 0x0b);
207        assert_eq!(data[18], 0x0c);
208        assert_eq!(data[19], 0x0d);
209        // message type/result/source id check
210        assert_eq!(data[20], 0x40);
211        assert_eq!(data[21], 0x12);
212        assert_eq!(data[22], 0x34);
213        assert_eq!(data[23], 0x56);
214        profile_rx.source_id = 0x00123456;
215        profile_rx.message_result = 0;
216        profile_rx.message_type = 1;
217        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
218    }
219
220    #[test]
221    fn test_profile7m_basic_error_example() {
222        let config = Profile7Config {
223            min_data_length: 192,
224            ..Default::default()
225        };
226
227        let mut profile_tx = Profile7m::new(config.clone()).unwrap();
228        let mut profile_rx = Profile7m::new(config).unwrap();
229
230        let mut data = vec![
231            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233        ];
234        profile_tx.source_id = 0x00123456;
235        profile_tx.message_result = 1;
236        profile_tx.message_type = 1;
237        profile_tx.protect(&mut data).unwrap();
238        // CRC check
239        assert_eq!(data[0], 0x09);
240        assert_eq!(data[1], 0xd9);
241        assert_eq!(data[2], 0xe8);
242        assert_eq!(data[3], 0x0c);
243        assert_eq!(data[4], 0x47);
244        assert_eq!(data[5], 0x34);
245        assert_eq!(data[6], 0x32);
246        assert_eq!(data[7], 0x02);
247        // length check
248        assert_eq!(data[8], 0x00);
249        assert_eq!(data[9], 0x00);
250        assert_eq!(data[10], 0x00);
251        assert_eq!(data[11], 0x1c);
252        // counter check
253        assert_eq!(data[12], 0x00);
254        assert_eq!(data[13], 0x00);
255        assert_eq!(data[14], 0x00);
256        assert_eq!(data[15], 0x00);
257        // data id check
258        assert_eq!(data[16], 0x0a);
259        assert_eq!(data[17], 0x0b);
260        assert_eq!(data[18], 0x0c);
261        assert_eq!(data[19], 0x0d);
262        // message type/result/source id check
263        assert_eq!(data[20], 0x50);
264        assert_eq!(data[21], 0x12);
265        assert_eq!(data[22], 0x34);
266        assert_eq!(data[23], 0x56);
267        profile_rx.source_id = 0x00123456;
268        profile_rx.message_result = 1;
269        profile_rx.message_type = 1;
270        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
271    }
272}