1use crate::fsemul::sdio::{
4 errors::{SdioApiError, SdioProtocolError},
5 proto::SDIO_BLOCK_SIZE_AS_U32,
6};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
9
10#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct SdioControlReadRequest {
13 lba: u32,
14 blocks: u32,
15 channel: u32,
16}
17
18impl SdioControlReadRequest {
19 pub fn new(lba: u32, blocks: u32, channel: u32) -> Result<Self, SdioApiError> {
32 if lba < SDIO_BLOCK_SIZE_AS_U32 || !lba.is_multiple_of(SDIO_BLOCK_SIZE_AS_U32) {
33 return Err(SdioApiError::InvalidLBA(lba));
34 }
35 let as_bytes = channel.to_le_bytes();
36 if as_bytes[0] >= 0xC {
37 return Err(SdioApiError::InvalidChannel(as_bytes[0], channel));
38 }
39
40 Ok(Self {
41 lba: lba / SDIO_BLOCK_SIZE_AS_U32,
42 blocks,
43 channel,
44 })
45 }
46
47 pub fn new_with_raw_lba(raw_lba: u32, blocks: u32, channel: u32) -> Result<Self, SdioApiError> {
57 let as_bytes = channel.to_le_bytes();
58 if as_bytes[0] >= 0xC {
59 return Err(SdioApiError::InvalidChannel(as_bytes[0], channel));
60 }
61
62 Ok(Self {
63 lba: raw_lba,
64 blocks,
65 channel,
66 })
67 }
68
69 #[must_use]
71 pub const fn lba(&self) -> u32 {
72 self.lba * SDIO_BLOCK_SIZE_AS_U32
73 }
74
75 pub fn set_raw_lba(&mut self, new_lba: u32) {
81 self.lba = new_lba;
82 }
83
84 pub fn set_lba(&mut self, new_lba: u32) -> Result<(), SdioApiError> {
91 if new_lba < SDIO_BLOCK_SIZE_AS_U32 || !new_lba.is_multiple_of(SDIO_BLOCK_SIZE_AS_U32) {
92 return Err(SdioApiError::InvalidLBA(new_lba));
93 }
94
95 self.lba = new_lba / SDIO_BLOCK_SIZE_AS_U32;
96 Ok(())
97 }
98
99 #[must_use]
101 pub const fn blocks(&self) -> u32 {
102 self.blocks
103 }
104
105 pub fn set_blocks(&mut self, new_blocks: u32) {
107 self.blocks = new_blocks;
108 }
109
110 #[must_use]
112 pub const fn channel(&self) -> u32 {
113 self.channel
114 }
115
116 pub fn set_channel(&mut self, new_channel: u32) -> Result<(), SdioApiError> {
123 let as_bytes = new_channel.to_le_bytes();
124 if as_bytes[0] >= 0xC {
125 return Err(SdioApiError::InvalidChannel(as_bytes[0], new_channel));
126 }
127
128 self.channel = new_channel;
129 Ok(())
130 }
131}
132
133impl TryFrom<Bytes> for SdioControlReadRequest {
134 type Error = SdioProtocolError;
135
136 fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
137 if value.len() != 512 {
138 return Err(SdioProtocolError::PrintfInvalidSize(value.len()));
139 }
140 let packet_type = value.get_u16_le();
141 if packet_type != 0 {
142 return Err(SdioProtocolError::UnknownPrintfPacketType(packet_type));
143 }
144 _ = value.get_u16_le();
145
146 let lba = value.get_u32_le();
147 let blocks = value.get_u32_le();
148 if value[0] >= 0xC {
149 return Err(SdioProtocolError::PrintfInvalidChannel(
150 value[0],
151 u32::from_le_bytes([value[0], value[1], value[2], value[3]]),
152 ));
153 }
154 let channel = value.get_u32_le();
155
156 Ok(Self {
157 lba,
158 blocks,
159 channel,
160 })
161 }
162}
163
164impl TryFrom<&SdioControlReadRequest> for Bytes {
165 type Error = SdioProtocolError;
166
167 fn try_from(value: &SdioControlReadRequest) -> Result<Self, Self::Error> {
168 let channel_first_byte = value.channel.to_le_bytes()[0];
169 if channel_first_byte >= 0xC {
170 return Err(SdioProtocolError::PrintfInvalidChannel(
171 channel_first_byte,
172 value.channel,
173 ));
174 }
175 let mut serialized = BytesMut::with_capacity(512);
176 serialized.put_u32_le(0);
177 serialized.put_u32_le(value.lba);
178 serialized.put_u32_le(value.blocks);
179 serialized.put_u32_le(value.channel);
180 serialized.extend_from_slice(&[0; 0x1F0]);
181 Ok(serialized.freeze())
182 }
183}
184
185impl TryFrom<SdioControlReadRequest> for Bytes {
186 type Error = SdioProtocolError;
187
188 fn try_from(value: SdioControlReadRequest) -> Result<Self, Self::Error> {
189 Self::try_from(&value)
190 }
191}
192
193const CONTROL_READ_REQUEST_FIELDS: &[NamedField<'static>] = &[
194 NamedField::new("raw_lba"),
195 NamedField::new("blocks"),
196 NamedField::new("channel"),
197];
198
199impl Structable for SdioControlReadRequest {
200 fn definition(&self) -> StructDef<'_> {
201 StructDef::new_static(
202 "SdioControlReadRequest",
203 Fields::Named(CONTROL_READ_REQUEST_FIELDS),
204 )
205 }
206}
207
208impl Valuable for SdioControlReadRequest {
209 fn as_value(&self) -> Value<'_> {
210 Value::Structable(self)
211 }
212
213 fn visit(&self, visitor: &mut dyn Visit) {
214 visitor.visit_named_fields(&NamedValues::new(
215 CONTROL_READ_REQUEST_FIELDS,
216 &[
217 Valuable::as_value(&self.lba),
218 Valuable::as_value(&self.blocks),
219 Valuable::as_value(&self.channel),
220 ],
221 ));
222 }
223}
224
225#[cfg(test)]
226mod unit_tests {
227 use super::*;
228
229 #[test]
230 pub fn parse_read_request() {
231 {
233 let read_request = SdioControlReadRequest::try_from(Bytes::from(vec![
234 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 ]))
272 .expect("Failed to parse real life SDIO Control Read Request");
273
274 assert_eq!(
275 read_request.lba(),
276 0xFFFF_0000,
277 "Failed to parse correct address to read from on a real life read request.",
278 );
279 assert_eq!(
280 read_request.blocks(),
281 2,
282 "Failed to parse correct amount of blocks to read from real life read request.",
283 );
284 assert_eq!(
285 read_request.channel(),
286 0,
287 "Failed to parse the correct channel to read from on a real life read request.",
288 );
289 }
290 }
291}