sdmmc_core/command/class/class11/cmd48/
arg.rs

1#![allow(clippy::len_without_is_empty)]
2#![allow(clippy::manual_range_contains)]
3
4use crate::lib_bitfield;
5use crate::result::{Error, Result};
6use crate::util;
7
8mod addr;
9mod mio;
10
11pub use addr::*;
12pub use mio::*;
13
14lib_bitfield! {
15    /// Argumentument for CMD48.
16    pub Argument(u32): u32 {
17        raw_mio: 31;
18        raw_fno: 30, 27;
19        raw_addr: 25, 9;
20        raw_len: 8, 0;
21    }
22}
23
24impl Argument {
25    /// Represents the byte length of the [Argument].
26    pub const LEN: usize = 4;
27    /// Represents the default value of the [Argument].
28    pub const DEFAULT: u32 = 0;
29
30    const LEN_MIN: usize = 1;
31    const LEN_MAX: usize = 512;
32
33    /// Creates a new [Argument].
34    pub const fn new() -> Self {
35        Self(Self::DEFAULT)
36    }
37
38    /// Gets the `mio` field of the [Argument].
39    pub const fn mio(&self) -> Mio {
40        Mio::from_bool(self.raw_mio())
41    }
42
43    /// Sets the `mio` field of the [Argument].
44    pub fn set_mio(&mut self, val: Mio) {
45        self.set_raw_mio(val.into_bool());
46    }
47
48    /// Gets the `fno` field of the [Argument].
49    pub const fn fno(&self) -> u8 {
50        util::fno_masked(self.mio(), self.raw_fno() as u8, false)
51    }
52
53    /// Sets the `fno` field of the [Argument].
54    ///
55    /// # Note
56    ///
57    /// The function number range depends on the [Mio] field:
58    ///
59    /// - [Mio::Memory]: `0 - 15`
60    /// - [Mio::Io]: `0 - 7`
61    pub fn set_fno(&mut self, val: u8) {
62        self.set_raw_fno(util::fno_masked(self.mio(), val, true) as u32);
63    }
64
65    /// Gets the `addr` field for the [Argument].
66    pub const fn addr(&self) -> Address {
67        Address::from_bits(self.raw_addr())
68    }
69
70    /// Sets the `addr` field for the [Argument].
71    pub fn set_addr(&mut self, val: Address) {
72        self.set_raw_addr(val.bits());
73    }
74
75    /// Gets the `len` field for the [Argument].
76    ///
77    /// The length is adjusted to its semantic value (`raw_len + 1`).
78    pub const fn len(&self) -> usize {
79        (self.raw_len() as usize) + 1
80    }
81
82    /// Sets the `len` field for the [Argument].
83    ///
84    /// The valid range for the length is `1-512` bytes.
85    ///
86    /// Input `val` as the unadjusted length, it is adjusted automatically.
87    ///
88    /// # Note
89    ///
90    /// Panics if `val` is outside the valid range.
91    pub fn set_len(&mut self, val: usize) {
92        self.try_set_len(val).unwrap();
93    }
94
95    /// Attempts to set the `len` field for the [Argument].
96    ///
97    /// The valid range for the length is `1-512` bytes.
98    ///
99    /// Input `val` as the unadjusted length, it is adjusted automatically.
100    ///
101    /// # Note
102    ///
103    /// Returns an error if `val` is outside the valid range.
104    pub fn try_set_len(&mut self, val: usize) -> Result<()> {
105        if val < Self::LEN_MIN || val > Self::LEN_MAX {
106            Err(Error::invalid_field_variant("cmd::argument::len", val))
107        } else {
108            self.set_raw_len((val - 1) as u32);
109            Ok(())
110        }
111    }
112
113    /// Attempts to convert a [`u32`] into an [`Argument`].
114    pub const fn try_from_bits(val: u32) -> Result<Self> {
115        Ok(Self(val))
116    }
117
118    /// Converts the [Argument] into a byte array.
119    pub const fn bytes(&self) -> [u8; Self::LEN] {
120        self.0.to_be_bytes()
121    }
122
123    /// Attempts to convert a byte slice into an [`Argument`].
124    pub const fn try_from_bytes(val: &[u8]) -> Result<Self> {
125        match val.len() {
126            len if len < Self::LEN => Err(Error::invalid_length(len, Self::LEN)),
127            _ => Self::try_from_bits(u32::from_be_bytes([val[0], val[1], val[2], val[3]])),
128        }
129    }
130}
131
132impl Default for Argument {
133    fn default() -> Self {
134        Self::new()
135    }
136}
137
138impl From<Argument> for u32 {
139    fn from(val: Argument) -> Self {
140        val.bits()
141    }
142}
143
144impl From<Argument> for [u8; Argument::LEN] {
145    fn from(val: Argument) -> Self {
146        val.bytes()
147    }
148}
149
150impl TryFrom<u32> for Argument {
151    type Error = Error;
152
153    fn try_from(val: u32) -> Result<Self> {
154        Self::try_from_bits(val)
155    }
156}
157
158impl TryFrom<&[u8]> for Argument {
159    type Error = Error;
160
161    fn try_from(val: &[u8]) -> Result<Self> {
162        Self::try_from_bytes(val)
163    }
164}
165
166impl<const N: usize> TryFrom<&[u8; N]> for Argument {
167    type Error = Error;
168
169    fn try_from(val: &[u8; N]) -> Result<Self> {
170        Self::try_from_bytes(val.as_ref())
171    }
172}
173
174impl<const N: usize> TryFrom<[u8; N]> for Argument {
175    type Error = Error;
176
177    fn try_from(val: [u8; N]) -> Result<Self> {
178        Self::try_from_bytes(val.as_ref())
179    }
180}
181
182#[cfg(test)]
183mod tests {
184    use super::*;
185
186    #[test]
187    fn test_fields() {
188        let new_mio = Mio::new();
189        let new_addr = Address::new();
190
191        (1..=u32::BITS)
192            .map(|r| ((1u64 << r) - 1) as u32)
193            .for_each(|raw_arg| {
194                let mut exp_arg = Argument(raw_arg);
195                let raw = raw_arg.to_be_bytes();
196
197                let exp_mio = Mio::from_bool((raw_arg & 0x8000_0000) != 0);
198
199                let raw_fno = ((raw_arg & 0x7800_0000) >> 27) as u8;
200                let exp_fno = util::fno_masked(exp_mio, raw_fno, false);
201
202                let raw_addr = (raw_arg & 0x3fffe00) >> 9;
203                let exp_addr = Address::from_bits(raw_addr);
204
205                let exp_len = ((raw_arg & 0x1ff) + 1) as usize;
206
207                assert_eq!(Argument::try_from_bits(raw_arg), Ok(exp_arg));
208                assert_eq!(Argument::try_from_bytes(&raw), Ok(exp_arg));
209                assert_eq!(Argument::try_from(raw_arg), Ok(exp_arg));
210                assert_eq!(Argument::try_from(&raw), Ok(exp_arg));
211                assert_eq!(Argument::try_from(raw), Ok(exp_arg));
212
213                assert_eq!(exp_arg.bits(), raw_arg);
214                assert_eq!(exp_arg.bytes(), raw);
215
216                assert_eq!(exp_arg.mio(), exp_mio);
217
218                exp_arg.set_mio(new_mio);
219                assert_eq!(exp_arg.mio(), new_mio);
220
221                exp_arg.set_mio(exp_mio);
222                assert_eq!(exp_arg.mio(), exp_mio);
223
224                assert_eq!(exp_arg.fno(), exp_fno);
225
226                exp_arg.set_fno(0);
227                assert_eq!(exp_arg.fno(), 0);
228
229                exp_arg.set_fno(exp_fno);
230                assert_eq!(exp_arg.fno(), exp_fno);
231
232                assert_eq!(exp_arg.addr(), exp_addr);
233
234                exp_arg.set_addr(new_addr);
235                assert_eq!(exp_arg.addr(), new_addr);
236
237                exp_arg.set_addr(exp_addr);
238                assert_eq!(exp_arg.addr(), exp_addr);
239
240                assert_eq!(exp_arg.len(), exp_len);
241
242                exp_arg.set_len(1);
243                assert_eq!(exp_arg.len(), 1);
244
245                exp_arg.set_len(exp_len);
246                assert_eq!(exp_arg.len(), exp_len);
247            });
248    }
249}