cat_dev/fsemul/sdio/proto/
write.rs1use 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 SdioControlWriteRequest {
13 lba: u32,
14 blocks: u32,
15 channel: u32,
16}
17
18impl SdioControlWriteRequest {
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 SdioControlWriteRequest {
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 != 1 {
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 From<&SdioControlWriteRequest> for Bytes {
165 fn from(value: &SdioControlWriteRequest) -> Self {
166 let mut serialized = BytesMut::with_capacity(512);
167 serialized.put_u32_le(1);
168 serialized.put_u32_le(value.lba);
169 serialized.put_u32_le(value.blocks);
170 serialized.put_u32_le(value.channel);
171 serialized.extend_from_slice(&[0; 0x1F0]);
172 serialized.freeze()
173 }
174}
175
176impl From<SdioControlWriteRequest> for Bytes {
177 fn from(value: SdioControlWriteRequest) -> Self {
178 Self::from(&value)
179 }
180}
181
182const CONTROL_WRITE_REQUEST_FIELDS: &[NamedField<'static>] = &[
183 NamedField::new("raw_lba"),
184 NamedField::new("blocks"),
185 NamedField::new("channel"),
186];
187
188impl Structable for SdioControlWriteRequest {
189 fn definition(&self) -> StructDef<'_> {
190 StructDef::new_static(
191 "SdioControlReadRequest",
192 Fields::Named(CONTROL_WRITE_REQUEST_FIELDS),
193 )
194 }
195}
196
197impl Valuable for SdioControlWriteRequest {
198 fn as_value(&self) -> Value<'_> {
199 Value::Structable(self)
200 }
201
202 fn visit(&self, visitor: &mut dyn Visit) {
203 visitor.visit_named_fields(&NamedValues::new(
204 CONTROL_WRITE_REQUEST_FIELDS,
205 &[
206 Valuable::as_value(&self.lba),
207 Valuable::as_value(&self.blocks),
208 Valuable::as_value(&self.channel),
209 ],
210 ));
211 }
212}
213
214#[cfg(test)]
215mod unit_tests {
216 }