1use crate::{errors::NetworkParseError, fsemul::sdio::errors::SDIOProtocolError};
11use bytes::{Bytes, BytesMut};
12use tokio::io::Error as IoError;
13use tokio_util::codec::{Decoder, Encoder};
14use tracing::debug;
15use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
16
17pub const SDIO_BLOCK_SIZE: usize = 0x200_usize;
19pub const SDIO_BLOCK_SIZE_AS_U32: u32 = 0x200_u32;
21pub const SDIO_TCP_PACKET_SIZE: usize = 0x10000_usize;
23pub const SDIO_BLOCKS_PER_PACKET: usize = SDIO_TCP_PACKET_SIZE / SDIO_BLOCK_SIZE;
25
26#[derive(Copy, Clone, Debug, PartialEq, Eq)]
30pub struct ChunkSDIOControlCodec;
31
32impl Decoder for ChunkSDIOControlCodec {
33 type Item = BytesMut;
34 type Error = IoError;
35
36 fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
37 if src.len() < 512 {
38 Ok(None)
39 } else {
40 Ok(Some(src.split_to(512)))
41 }
42 }
43}
44
45impl Encoder<Bytes> for ChunkSDIOControlCodec {
46 type Error = IoError;
47
48 fn encode(&mut self, item: Bytes, dst: &mut BytesMut) -> Result<(), Self::Error> {
49 dst.reserve(512);
50 dst.extend(item);
51 Ok(())
52 }
53}
54
55#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
57pub enum SdioControlPacketType {
58 Message,
60 Read,
62 Write,
64 StartBlockChannel,
69 StartControlListeningChannel,
74}
75
76impl From<SdioControlPacketType> for u8 {
77 fn from(value: SdioControlPacketType) -> Self {
78 match value {
79 SdioControlPacketType::Message => 8,
80 SdioControlPacketType::Read => 0,
81 SdioControlPacketType::Write => 1,
82 SdioControlPacketType::StartBlockChannel => 0xA,
83 SdioControlPacketType::StartControlListeningChannel => 0xB,
84 }
85 }
86}
87
88impl TryFrom<u8> for SdioControlPacketType {
89 type Error = SDIOProtocolError;
90
91 fn try_from(value: u8) -> Result<Self, Self::Error> {
92 match value {
93 0 => Ok(Self::Read),
94 1 => Ok(Self::Write),
95 8 => Ok(Self::Message),
96 0xA => Ok(Self::StartBlockChannel),
97 0xB => Ok(Self::StartControlListeningChannel),
98 _ => Err(SDIOProtocolError::UnknownPrintfPacketType(value)),
99 }
100 }
101}
102
103#[derive(Debug, PartialEq, Eq)]
105pub struct SdioControlReadRequest {
106 lba: u32,
107 blocks: u32,
108 channel: u32,
109}
110
111impl SdioControlReadRequest {
112 #[must_use]
114 pub const fn lba(&self) -> u32 {
115 self.lba * SDIO_BLOCK_SIZE_AS_U32
116 }
117
118 #[must_use]
120 pub const fn blocks(&self) -> u32 {
121 self.blocks
122 }
123
124 #[must_use]
126 pub const fn channel(&self) -> u32 {
127 self.channel
128 }
129}
130
131impl TryFrom<Bytes> for SdioControlReadRequest {
132 type Error = SDIOProtocolError;
133
134 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
135 if value.len() != 512 {
136 return Err(SDIOProtocolError::PrintfInvalidSize(value.len()));
137 }
138 if value[0] != 0 {
139 return Err(SDIOProtocolError::UnknownPrintfPacketType(value[0]));
140 }
141
142 let lba = u32::from_le_bytes([value[4], value[5], value[6], value[7]]);
143 let blocks = u32::from_le_bytes([value[8], value[9], value[10], value[11]]);
144 let channel = u32::from_le_bytes([value[12], value[13], value[14], value[15]]);
145 if value[12] >= 0xC {
146 return Err(SDIOProtocolError::PrintfInvalidChannel(value[12], channel));
147 }
148
149 Ok(Self {
150 lba,
151 blocks,
152 channel,
153 })
154 }
155}
156
157const CONTROL_READ_REQUEST_FIELDS: &[NamedField<'static>] = &[
158 NamedField::new("lba"),
159 NamedField::new("blocks"),
160 NamedField::new("channel"),
161];
162
163impl Structable for SdioControlReadRequest {
164 fn definition(&self) -> StructDef<'_> {
165 StructDef::new_static(
166 "SdioControlReadRequest",
167 Fields::Named(CONTROL_READ_REQUEST_FIELDS),
168 )
169 }
170}
171
172impl Valuable for SdioControlReadRequest {
173 fn as_value(&self) -> Value<'_> {
174 Value::Structable(self)
175 }
176
177 fn visit(&self, visitor: &mut dyn Visit) {
178 visitor.visit_named_fields(&NamedValues::new(
179 CONTROL_READ_REQUEST_FIELDS,
180 &[
181 Valuable::as_value(&self.lba),
182 Valuable::as_value(&self.blocks),
183 Valuable::as_value(&self.channel),
184 ],
185 ));
186 }
187}
188
189#[derive(Debug, PartialEq, Eq)]
191pub struct SdioControlWriteRequest {
192 lba: u32,
193 blocks: u32,
194 channel: u32,
195}
196
197impl SdioControlWriteRequest {
198 #[must_use]
200 pub const fn lba(&self) -> u32 {
201 self.lba * SDIO_BLOCK_SIZE_AS_U32
202 }
203
204 #[must_use]
206 pub const fn blocks(&self) -> u32 {
207 self.blocks
208 }
209
210 #[must_use]
212 pub const fn channel(&self) -> u32 {
213 self.channel
214 }
215}
216
217impl TryFrom<Bytes> for SdioControlWriteRequest {
218 type Error = SDIOProtocolError;
219
220 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
221 if value.len() != 512 {
222 return Err(SDIOProtocolError::PrintfInvalidSize(value.len()));
223 }
224 if value[0] != 1 {
225 return Err(SDIOProtocolError::UnknownPrintfPacketType(value[0]));
226 }
227
228 let lba = u32::from_le_bytes([value[4], value[5], value[6], value[7]]);
229 let blocks = u32::from_le_bytes([value[8], value[9], value[10], value[11]]);
230 let channel = u32::from_le_bytes([value[12], value[13], value[14], value[15]]);
231 if value[12] >= 0xC {
232 return Err(SDIOProtocolError::PrintfInvalidChannel(value[12], channel));
233 }
234
235 Ok(Self {
236 lba,
237 blocks,
238 channel,
239 })
240 }
241}
242
243const CONTROL_WRITE_REQUEST_FIELDS: &[NamedField<'static>] = &[
244 NamedField::new("lba"),
245 NamedField::new("blocks"),
246 NamedField::new("channel"),
247];
248
249impl Structable for SdioControlWriteRequest {
250 fn definition(&self) -> StructDef<'_> {
251 StructDef::new_static(
252 "SdioControlReadRequest",
253 Fields::Named(CONTROL_WRITE_REQUEST_FIELDS),
254 )
255 }
256}
257
258impl Valuable for SdioControlWriteRequest {
259 fn as_value(&self) -> Value<'_> {
260 Value::Structable(self)
261 }
262
263 fn visit(&self, visitor: &mut dyn Visit) {
264 visitor.visit_named_fields(&NamedValues::new(
265 CONTROL_WRITE_REQUEST_FIELDS,
266 &[
267 Valuable::as_value(&self.lba),
268 Valuable::as_value(&self.blocks),
269 Valuable::as_value(&self.channel),
270 ],
271 ));
272 }
273}
274
275#[derive(Clone, Debug, PartialEq, Eq, Valuable)]
276pub enum SdioControlMessage {
277 Printf(String),
279}
280
281#[derive(Debug, PartialEq, Eq)]
283pub struct SdioControlMessageRequest {
284 character_length: u16,
285 messages: Vec<SdioControlMessage>,
286}
287
288impl SdioControlMessageRequest {
289 #[must_use]
290 pub const fn character_length(&self) -> u16 {
291 self.character_length
292 }
293
294 #[must_use]
295 pub const fn messages(&self) -> &Vec<SdioControlMessage> {
296 &self.messages
297 }
298
299 #[must_use]
300 pub fn messages_owned(self) -> Vec<SdioControlMessage> {
301 self.messages
302 }
303}
304
305impl TryFrom<Bytes> for SdioControlMessageRequest {
306 type Error = NetworkParseError;
307
308 #[allow(
309 clippy::never_loop,
311 )]
312 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
313 if value.len() != 512 {
314 return Err(SDIOProtocolError::PrintfInvalidSize(value.len()).into());
315 }
316 if value[0] != 8 {
317 return Err(SDIOProtocolError::UnknownPrintfPacketType(value[0]).into());
318 }
319
320 let character_length = u16::from_le_bytes([value[0x2], value[0x3]]);
321 let mut messages = Vec::with_capacity(1);
322 loop {
323 let message_ty = u16::from_le_bytes([
324 value[4 + (messages.len() * 4)],
325 value[4 + (messages.len() * 4) + 1],
326 ]);
327 if message_ty == 4 {
329 let mut buff = value.slice((4 + (messages.len() * 4) + 8)..);
331 if let Some(eol) = buff.iter().position(|item| *item == 0x0) {
332 buff.truncate(eol);
333 }
334 messages.push(SdioControlMessage::Printf(
335 String::from_utf8_lossy(&buff).to_string(),
339 ));
340 break;
342 } else if message_ty == 9 {
343 debug!(
344 buff = format!("{:02X}", value),
345 "Unknown message type == 9 for SDIO, Not Sure How to Respond?"
346 );
347 break;
348 }
349
350 return Err(SDIOProtocolError::UnknownPrintfMessageType(message_ty).into());
351 }
352
353 Ok(Self {
354 character_length,
355 messages,
356 })
357 }
358}
359
360const MESSAGE_REQUEST_FIELDS: &[NamedField<'static>] = &[
361 NamedField::new("character_length"),
362 NamedField::new("messages"),
363];
364
365impl Structable for SdioControlMessageRequest {
366 fn definition(&self) -> StructDef<'_> {
367 StructDef::new_static(
368 "SdioControlMessageRequest",
369 Fields::Named(MESSAGE_REQUEST_FIELDS),
370 )
371 }
372}
373
374impl Valuable for SdioControlMessageRequest {
375 fn as_value(&self) -> Value<'_> {
376 Value::Structable(self)
377 }
378
379 fn visit(&self, visitor: &mut dyn Visit) {
380 visitor.visit_named_fields(&NamedValues::new(
381 MESSAGE_REQUEST_FIELDS,
382 &[
383 Valuable::as_value(&self.character_length),
384 Valuable::as_value(&self.messages),
385 ],
386 ));
387 }
388}
389
390#[cfg(test)]
391mod unit_tests {
392 use super::*;
393
394 #[test]
395 pub fn decoder_chunks_chunkily() {
396 {
398 let mut codec = ChunkSDIOControlCodec;
399 let mut buff = BytesMut::with_capacity(0);
400
401 codec
402 .decode(&mut buff)
403 .expect("Failed to call SDIO Control codec on empty.");
404 }
405
406 {
408 let mut codec = ChunkSDIOControlCodec;
409 let mut buff = BytesMut::zeroed(511);
410
411 assert_eq!(
412 codec.decode(&mut buff).expect("Failed to call SDIO Control Codec"),
413 None,
414 "Codec could not successfully decode a buffer that was one byte too short for SDIO Control.",
415 );
416 }
417
418 {
420 let mut codec = ChunkSDIOControlCodec;
421 let mut buff = BytesMut::with_capacity(1024);
422
423 buff.extend(vec![0x1; 512]);
424 buff.extend(vec![0x2; 512]);
425
426 assert_eq!(
427 codec.decode(&mut buff).expect("Failed to call SDIO Control Codec"),
428 Some(BytesMut::from(&*vec![0x1_u8; 512])),
429 "Codec did not successfully decode first part of a too large packet to SDIO Control.",
430 );
431 assert_eq!(
432 codec.decode(&mut buff).expect("Failed to call SDIO Control Codec"),
433 Some(BytesMut::from(&*vec![0x2_u8; 512])),
434 "Codec did not successfully decode second part of a too large packet to SDIO Control."
435 );
436 }
437
438 {
440 let mut codec = ChunkSDIOControlCodec;
441 let mut buff = BytesMut::zeroed(512);
442
443 assert_eq!(
444 codec
445 .decode(&mut buff)
446 .expect("Failed to call SDIO Control Codec"),
447 Some(BytesMut::zeroed(512)),
448 "Codec did not succsesfully decode a just right packet size to SDIO Control.",
449 );
450 }
451 }
452
453 #[test]
454 pub fn roundtrip_control_packet_type() {
455 for packet_ty in vec![
456 SdioControlPacketType::Message,
457 SdioControlPacketType::Read,
458 SdioControlPacketType::Write,
459 ] {
460 assert_eq!(
461 Ok(packet_ty),
462 SdioControlPacketType::try_from(u8::from(packet_ty)),
463 "Round-tripped control packet type was not the same?"
464 );
465 }
466 }
467
468 #[test]
469 pub fn parse_read_request() {
470 {
472 let read_request = SdioControlReadRequest::try_from(Bytes::from(vec![
473 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
474 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
495 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
498 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
499 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
500 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
501 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
502 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 ]))
511 .expect("Failed to parse real life SDIO Control Read Request");
512
513 assert_eq!(
514 read_request.lba(),
515 0xFFFF_0000,
516 "Failed to parse correct address to read from on a real life read request.",
517 );
518 assert_eq!(
519 read_request.blocks(),
520 2,
521 "Failed to parse correct amount of blocks to read from real life read request.",
522 );
523 assert_eq!(
524 read_request.channel(),
525 0,
526 "Failed to parse the correct channel to read from on a real life read request.",
527 );
528 }
529 }
530
531 #[test]
534 pub fn parse_real_life_message_request() {
535 {
536 let message_request = SdioControlMessageRequest::try_from(Bytes::from(vec![
537 0x08, 0x00, 0x3a, 0x00, 0x04, 0x00, 0x0c, 0x00, 0xff, 0xff, 0x3a, 0x00, 0x42, 0x4f,
538 0x4f, 0x54, 0x31, 0x3a, 0x20, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x44,
539 0x55, 0x41, 0x4c, 0x20, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72,
540 0x20, 0x61, 0x74, 0x20, 0x30, 0x78, 0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
541 0x2e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 0x08, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04,
545 0x18, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00,
546 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
550 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
551 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
552 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
553 0x00, 0x00, 0x00, 0x10, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
554 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x40, 0x00, 0x04,
555 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
557 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
560 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
561 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x82,
563 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
564 0x00, 0x00, 0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
570 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
571 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x01, 0x08, 0x00, 0x00, 0x20, 0x00,
572 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0xc0,
573 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
574 ]))
575 .expect("Failed to parse real life SDIO Control Message Request");
576
577 assert_eq!(
578 message_request.messages(),
579 &vec![SdioControlMessage::Printf(
580 "BOOT1: Running DUAL bootloader at 0x08000000.\n".to_owned()
581 )],
582 "Cannot Parse SDIO Control Message Request.",
583 );
584 }
585 }
586}