Skip to main content

ace_uds/message/services/
write_memory_by_address.rs

1use crate::UdsError;
2use ace_macros::FrameCodec;
3
4#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, FrameCodec)]
5#[frame(error = UdsError)]
6pub struct WriteMemoryByAddressRequest<'a> {
7    pub address_and_length_format_identifier: u8,
8    #[frame(
9        length = "(address_and_length_format_identifier & 0x0F) as usize",
10        bytes
11    )]
12    pub memory_address: &'a [u8],
13    #[frame(length = "(address_and_length_format_identifier >> 4) as usize", bytes)]
14    pub memory_size: &'a [u8],
15    #[frame(read_all, bytes)]
16    pub data_record: &'a [u8],
17}
18
19#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, FrameCodec)]
20#[frame(error = UdsError)]
21pub struct WriteMemoryByAddressResponse<'a> {
22    pub address_and_length_format_identifier: u8,
23    #[frame(
24        length = "(address_and_length_format_identifier & 0x0F) as usize",
25        bytes
26    )]
27    pub memory_address: &'a [u8],
28    #[frame(length = "(address_and_length_format_identifier >> 4) as usize", bytes)]
29    pub memory_size: &'a [u8],
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35    use ace_core::codec::{decode_from_slice, FrameWrite};
36
37    #[cfg(feature = "alloc")]
38    use alloc::borrow::ToOwned;
39    #[cfg(feature = "alloc")]
40    use alloc::vec;
41
42    // address_and_length_format_identifier = 0x12:
43    //   low nibble  = 2 → memory_address is 2 bytes
44    //   high nibble = 1 → memory_size    is 1 byte
45    //   remainder        → data_record
46    const REQUEST_FRAME: &[u8] = &[0x12, 0xAA, 0xBB, 0x04, 0xDE, 0xAD, 0xBE, 0xEF];
47
48    // address_and_length_format_identifier = 0x12:
49    //   low nibble  = 2 → memory_address is 2 bytes
50    //   high nibble = 1 → memory_size    is 1 byte
51    const RESPONSE_FRAME: &[u8] = &[0x12, 0xAA, 0xBB, 0x04];
52
53    #[test]
54    fn request_decode() {
55        let req: WriteMemoryByAddressRequest = decode_from_slice(REQUEST_FRAME).unwrap();
56        assert_eq!(req.address_and_length_format_identifier, 0x12);
57        assert_eq!(req.memory_address, &[0xAA, 0xBB]);
58        assert_eq!(req.memory_size, &[0x04]);
59        assert_eq!(req.data_record, &[0xDE, 0xAD, 0xBE, 0xEF]);
60    }
61
62    #[test]
63    fn request_encode_roundtrip() {
64        let req: WriteMemoryByAddressRequest = decode_from_slice(REQUEST_FRAME).unwrap();
65        let mut buf = [0u8; 64];
66        req.encode(&mut buf.as_mut()).unwrap();
67        assert_eq!(&buf[..REQUEST_FRAME.len()], REQUEST_FRAME);
68    }
69
70    #[test]
71    fn response_decode() {
72        let resp: WriteMemoryByAddressResponse = decode_from_slice(RESPONSE_FRAME).unwrap();
73        assert_eq!(resp.address_and_length_format_identifier, 0x12);
74        assert_eq!(resp.memory_address, &[0xAA, 0xBB]);
75        assert_eq!(resp.memory_size, &[0x04]);
76    }
77
78    #[test]
79    fn response_encode_roundtrip() {
80        let resp: WriteMemoryByAddressResponse = decode_from_slice(RESPONSE_FRAME).unwrap();
81        let mut buf = [0u8; 64];
82        resp.encode(&mut buf.as_mut()).unwrap();
83        assert_eq!(&buf[..RESPONSE_FRAME.len()], RESPONSE_FRAME);
84    }
85
86    #[test]
87    fn request_truncated_address() {
88        // claims 3 address bytes but only 2 present
89        let bad: &[u8] = &[0x13, 0xAA, 0xBB];
90        let result = decode_from_slice::<WriteMemoryByAddressRequest>(bad);
91        assert!(result.is_err());
92    }
93
94    #[test]
95    fn request_truncated_size() {
96        // claims 2 size bytes but only 1 present after address
97        let bad: &[u8] = &[0x22, 0xAA, 0xBB, 0x04];
98        let result = decode_from_slice::<WriteMemoryByAddressRequest>(bad);
99        assert!(result.is_err());
100    }
101
102    #[test]
103    fn response_truncated() {
104        // claims 2 address bytes but only 1 present
105        let bad: &[u8] = &[0x12, 0xAA];
106        let result = decode_from_slice::<WriteMemoryByAddressResponse>(bad);
107        assert!(result.is_err());
108    }
109
110    #[cfg(feature = "alloc")]
111    #[test]
112    fn request_to_owned() {
113        let req: WriteMemoryByAddressRequest = decode_from_slice(REQUEST_FRAME).unwrap();
114        let owned = req.to_owned();
115        assert_eq!(owned.address_and_length_format_identifier, 0x12);
116        assert_eq!(owned.memory_address, vec![0xAA, 0xBB]);
117        assert_eq!(owned.memory_size, vec![0x04]);
118        assert_eq!(owned.data_record, vec![0xDE, 0xAD, 0xBE, 0xEF]);
119    }
120
121    #[cfg(feature = "alloc")]
122    #[test]
123    fn response_to_owned() {
124        let resp: WriteMemoryByAddressResponse = decode_from_slice(RESPONSE_FRAME).unwrap();
125        let owned = resp.to_owned();
126        assert_eq!(owned.address_and_length_format_identifier, 0x12);
127        assert_eq!(owned.memory_address, vec![0xAA, 0xBB]);
128        assert_eq!(owned.memory_size, vec![0x04]);
129    }
130
131    #[cfg(feature = "alloc")]
132    #[test]
133    fn owned_request_encode_roundtrip() {
134        let owned: WriteMemoryByAddressRequestOwned = decode_from_slice(REQUEST_FRAME).unwrap();
135        let mut buf = [0u8; 64];
136        owned.encode(&mut buf.as_mut()).unwrap();
137        assert_eq!(&buf[..REQUEST_FRAME.len()], REQUEST_FRAME);
138    }
139
140    #[cfg(feature = "alloc")]
141    #[test]
142    fn owned_response_encode_roundtrip() {
143        let owned: WriteMemoryByAddressResponseOwned = decode_from_slice(RESPONSE_FRAME).unwrap();
144        let mut buf = [0u8; 64];
145        owned.encode(&mut buf.as_mut()).unwrap();
146        assert_eq!(&buf[..RESPONSE_FRAME.len()], RESPONSE_FRAME);
147    }
148}