autosar_e2e/profiles/
profile4m.rs

1//! # E2E Profile 4M Implementation
2//!
3//! Profile 4M is identical to Profile 4 but includes additional fields
4//! in CRC calculation: message_type, message_result, and source_id
5
6use crate::profile4::{Profile4, Profile4Config}; // Reuse Profile4Config
7use crate::{E2EProfile, E2EResult, E2EStatus};
8
9const BITS_PER_BYTE: u16 = 8;
10
11/// Check Item for E2E Profile 4
12#[derive(Debug, Clone)]
13pub struct Profile4mCheck {
14    rx_source_id: u32,
15    rx_message_type: u8,
16    rx_message_result: u8,
17}
18
19/// E2E Profile 4m Implementation - minimal code by reusing Profile4 logic
20#[derive(Clone)]
21pub struct Profile4m {
22    base: Profile4,
23    config: Profile4Config,
24    pub message_type: u8,
25    pub message_result: u8,
26    pub source_id: u32,
27}
28
29impl Profile4m {
30    fn write_source_id(&self, data: &mut [u8]) {
31        let offset = (self.config.offset / BITS_PER_BYTE) as usize;
32        data[offset + 12..=offset + 15].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 + 12] = (data[offset + 12] & 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 + 12] = (data[offset + 12] & 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 + 12],
46            data[offset + 13],
47            data[offset + 14],
48            data[offset + 15],
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 + 12] >> 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 + 12] >> 4) & 0x03
58    }
59    fn do_checks(&mut self, check_items: Profile4mCheck) -> 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 Profile4m {
74    type Config = Profile4Config;
75
76    fn new(config: Self::Config) -> E2EResult<Self> {
77        // Validate using Profile4's validation
78        let base = crate::profile4::Profile4::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 Profile4m 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 = Profile4mCheck {
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_profile4m_basic_request_example() {
116        let mut profile_tx = Profile4m::new(Profile4Config::default()).unwrap();
117        let mut profile_rx = Profile4m::new(Profile4Config::default()).unwrap();
118
119        let mut data = vec![
120            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122        ];
123        profile_tx.source_id = 0x00123456;
124        profile_tx.message_result = 0;
125        profile_tx.message_type = 0;
126        profile_tx.protect(&mut data).unwrap();
127        // length check
128        assert_eq!(data[0], 0x00);
129        assert_eq!(data[1], 0x14);
130        // counter check
131        assert_eq!(data[2], 0x00);
132        assert_eq!(data[3], 0x00);
133        // data id check
134        assert_eq!(data[4], 0x0a);
135        assert_eq!(data[5], 0x0b);
136        assert_eq!(data[6], 0x0c);
137        assert_eq!(data[7], 0x0d);
138        // crc check
139        assert_eq!(data[8], 0xae);
140        assert_eq!(data[9], 0x67);
141        assert_eq!(data[10], 0x4c);
142        assert_eq!(data[11], 0xa0);
143        // data check
144        assert_eq!(data[12], 0x00);
145        assert_eq!(data[13], 0x12);
146        assert_eq!(data[14], 0x34);
147        assert_eq!(data[15], 0x56);
148        profile_rx.source_id = 0x00123456;
149        profile_rx.message_result = 0;
150        profile_rx.message_type = 0;
151        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
152    }
153    #[test]
154    fn test_profile4m_basic_response_example() {
155        let mut profile_tx = Profile4m::new(Profile4Config::default()).unwrap();
156        let mut profile_rx = Profile4m::new(Profile4Config::default()).unwrap();
157
158        let mut data = vec![
159            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161        ];
162        profile_tx.source_id = 0x00123456;
163        profile_tx.message_result = 0;
164        profile_tx.message_type = 1;
165        profile_tx.protect(&mut data).unwrap();
166        // length check
167        assert_eq!(data[0], 0x00);
168        assert_eq!(data[1], 0x14);
169        // counter check
170        assert_eq!(data[2], 0x00);
171        assert_eq!(data[3], 0x00);
172        // data id check
173        assert_eq!(data[4], 0x0a);
174        assert_eq!(data[5], 0x0b);
175        assert_eq!(data[6], 0x0c);
176        assert_eq!(data[7], 0x0d);
177        // crc check
178        assert_eq!(data[8], 0x85);
179        assert_eq!(data[9], 0x25);
180        assert_eq!(data[10], 0x76);
181        assert_eq!(data[11], 0x19);
182        // data check
183        assert_eq!(data[12], 0x40);
184        assert_eq!(data[13], 0x12);
185        assert_eq!(data[14], 0x34);
186        assert_eq!(data[15], 0x56);
187        profile_rx.source_id = 0x00123456;
188        profile_rx.message_result = 0;
189        profile_rx.message_type = 1;
190        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
191    }
192    #[test]
193    fn test_profile4m_basic_error_example() {
194        let mut profile_tx = Profile4m::new(Profile4Config::default()).unwrap();
195        let mut profile_rx = Profile4m::new(Profile4Config::default()).unwrap();
196
197        let mut data = vec![
198            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200        ];
201        profile_tx.source_id = 0x00123456;
202        profile_tx.message_result = 1;
203        profile_tx.message_type = 1;
204        profile_tx.protect(&mut data).unwrap();
205        // length check
206        assert_eq!(data[0], 0x00);
207        assert_eq!(data[1], 0x14);
208        // counter check
209        assert_eq!(data[2], 0x00);
210        assert_eq!(data[3], 0x00);
211        // data id check
212        assert_eq!(data[4], 0x0a);
213        assert_eq!(data[5], 0x0b);
214        assert_eq!(data[6], 0x0c);
215        assert_eq!(data[7], 0x0d);
216        // crc check
217        assert_eq!(data[8], 0x23);
218        assert_eq!(data[9], 0x45);
219        assert_eq!(data[10], 0x57);
220        assert_eq!(data[11], 0x0f);
221        // data check
222        assert_eq!(data[12], 0x50);
223        assert_eq!(data[13], 0x12);
224        assert_eq!(data[14], 0x34);
225        assert_eq!(data[15], 0x56);
226        profile_rx.source_id = 0x00123456;
227        profile_rx.message_result = 1;
228        profile_rx.message_type = 1;
229        assert_eq!(profile_rx.check(&data).unwrap(), E2EStatus::Ok);
230    }
231}