sdmmc_core/command/class/class11/cmd48/
arg.rs1#![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 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 pub const LEN: usize = 4;
27 pub const DEFAULT: u32 = 0;
29
30 const LEN_MIN: usize = 1;
31 const LEN_MAX: usize = 512;
32
33 pub const fn new() -> Self {
35 Self(Self::DEFAULT)
36 }
37
38 pub const fn mio(&self) -> Mio {
40 Mio::from_bool(self.raw_mio())
41 }
42
43 pub fn set_mio(&mut self, val: Mio) {
45 self.set_raw_mio(val.into_bool());
46 }
47
48 pub const fn fno(&self) -> u8 {
50 util::fno_masked(self.mio(), self.raw_fno() as u8, false)
51 }
52
53 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 pub const fn addr(&self) -> Address {
67 Address::from_bits(self.raw_addr())
68 }
69
70 pub fn set_addr(&mut self, val: Address) {
72 self.set_raw_addr(val.bits());
73 }
74
75 pub const fn len(&self) -> usize {
79 (self.raw_len() as usize) + 1
80 }
81
82 pub fn set_len(&mut self, val: usize) {
92 self.try_set_len(val).unwrap();
93 }
94
95 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 pub const fn try_from_bits(val: u32) -> Result<Self> {
115 Ok(Self(val))
116 }
117
118 pub const fn bytes(&self) -> [u8; Self::LEN] {
120 self.0.to_be_bytes()
121 }
122
123 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}