1use deku::prelude::*;
8
9#[cfg(not(feature = "std"))]
10use alloc::{format, string::String};
11#[allow(unused_imports)]
12use log::{debug, error, info, trace, warn};
13
14use crate::{Reader, STM32F4_FLASH_BASE, STM32F4_RAM_BASE, Source, read_str_at_ptr};
15
16#[derive(Debug, serde::Serialize, serde::Deserialize)]
19pub struct OneRomLab {
20 pub flash: Option<LabFlash>,
21 pub ram: Option<LabRam>,
23}
24
25#[derive(Debug, serde::Serialize, serde::Deserialize)]
29pub struct LabFlash {
30 pub major_version: String,
31 pub minor_version: String,
32 pub patch_version: String,
33 pub build_number: String,
34 pub mcu: String,
35 pub hw_rev: String,
36 pub features: String,
37 pub rtt_ptr: u32,
38}
39
40#[derive(Debug, serde::Serialize, serde::Deserialize)]
44pub struct LabRam {
45 pub rom_data_ptr: u32,
46 pub rpc_cmd_channel_ptr: u32,
47 pub rpc_rsp_channel_ptr: u32,
48 pub rpc_cmd_channel_size: u16,
49 pub rpc_rsp_channel_size: u16,
50}
51
52#[derive(Debug, DekuRead, DekuWrite)]
53#[deku(endian = "little", magic = b"ONEL")]
54struct LabFlashInt {
61 major_version_ptr: u32,
62 major_version_len: u32,
63
64 minor_version_ptr: u32,
65 minor_version_len: u32,
66
67 patch_version_ptr: u32,
68 patch_version_len: u32,
69
70 build_number_ptr: u32,
71 build_number_len: u32,
72
73 mcu_ptr: u32,
74 mcu_len: u32,
75
76 hw_rev_ptr: u32,
77 hw_rev_len: u32,
78
79 features_ptr: u32,
80 features_len: u32,
81
82 rtt_ptr: u32,
83}
84
85impl LabFlashInt {
86 const SIZE: usize = 256;
87 const OFFSET: usize = 0x200;
88 const _SOURCE: Source = Source::Ram;
89
90 const fn size() -> usize {
91 Self::SIZE
92 }
93
94 const fn offset() -> usize {
95 Self::OFFSET
96 }
97
98 const fn _source() -> Source {
99 Self::_SOURCE
100 }
101
102 fn parse_and_validate(data: &[u8]) -> Result<Self, String> {
103 if data.len() < Self::size() {
104 return Err("Lab flash data too short".into());
105 }
106
107 let (_, info) = Self::from_bytes((data, 0))
108 .map_err(|e| format!("Failed to parse Lab flash data: {}", e))?;
109
110 Ok(info)
111 }
112}
113
114#[derive(Debug, DekuRead, DekuWrite)]
115#[deku(endian = "little", magic = b"onel")]
116struct LabRamInt {
120 rom_data_ptr: u32,
121 rpc_cmd_channel_ptr: u32,
122 rpc_rsp_channel_ptr: u32,
123 rpc_cmd_channel_size: u16,
124 rpc_rsp_channel_size: u16,
125}
126
127impl LabRamInt {
128 const SIZE: usize = 256;
129 const OFFSET: usize = 0;
130 const _SOURCE: Source = Source::Ram;
131
132 const fn size() -> usize {
133 Self::SIZE
134 }
135
136 const fn offset() -> usize {
137 Self::OFFSET
138 }
139
140 const fn _source() -> Source {
141 Self::_SOURCE
142 }
143
144 fn parse_and_validate(data: &[u8]) -> Result<Self, String> {
145 if data.len() < Self::size() {
146 return Err("Lab RAM data too short".into());
147 }
148
149 let (_, info) = Self::from_bytes((data, 0))
150 .map_err(|e| format!("Failed to parse Lab RAM data: {}", e))?;
151
152 Ok(info)
153 }
154}
155
156pub struct LabParser<'a, R: Reader> {
157 reader: &'a mut R,
158 base_flash_address: u32,
159 base_ram_address: u32,
160}
161
162impl<'a, R: Reader> LabParser<'a, R> {
163 pub fn new(reader: &'a mut R) -> Self {
164 Self {
165 reader,
166 base_flash_address: STM32F4_FLASH_BASE,
167 base_ram_address: STM32F4_RAM_BASE,
168 }
169 }
170
171 pub fn with_base_flash_address(
172 reader: &'a mut R,
173 base_flash_address: u32,
174 base_ram_address: u32,
175 ) -> Self {
176 Self {
177 reader,
178 base_flash_address,
179 base_ram_address,
180 }
181 }
182
183 async fn retrieve_flash_info(&mut self) -> Result<LabFlashInt, String> {
184 let addr = self.base_flash_address + LabFlashInt::offset() as u32;
185 let mut buf = [0u8; LabFlashInt::size()];
186 self.reader
187 .read(addr, &mut buf)
188 .await
189 .map_err(|_| "Failed to read Lab Flash info")?;
190 LabFlashInt::parse_and_validate(&buf)
191 }
192
193 async fn retrieve_ram_info(&mut self) -> Result<LabRamInt, String> {
194 let addr = self.base_ram_address + LabRamInt::offset() as u32;
195 let mut buf = [0u8; LabRamInt::size()];
196 self.reader
197 .read(addr, &mut buf)
198 .await
199 .map_err(|_| "Failed to read Lab RAM info")?;
200 LabRamInt::parse_and_validate(&buf)
201 }
202
203 pub async fn detect(&mut self) -> bool {
204 self.retrieve_flash_info().await.is_ok()
205 }
206
207 pub async fn parse(&mut self) -> OneRomLab {
208 let flash = match self.parse_flash().await {
209 Ok(info) => Some(info),
210 Err(e) => {
211 warn!("Failed to parse flash: {e}");
212 None
213 }
214 };
215 let ram = match self.parse_ram().await {
216 Ok(info) => Some(info),
217 Err(e) => {
218 warn!("Failed to parse RAM: {e}");
219 None
220 }
221 };
222
223 OneRomLab { flash, ram }
224 }
225
226 async fn parse_flash(&mut self) -> Result<LabFlash, String> {
227 let info = self
228 .retrieve_flash_info()
229 .await
230 .inspect_err(|e| warn!("Failed to retrieve flash: {e}"))?;
231
232 let major_version = self
233 .read_flash_str_at_ptr(info.major_version_len, info.major_version_ptr)
234 .await
235 .inspect_err(|e| warn!("Failed to read major version: {e}"))?;
236 let minor_version = self
237 .read_flash_str_at_ptr(info.minor_version_len, info.minor_version_ptr)
238 .await
239 .inspect_err(|e| warn!("Failed to read minor version: {e}"))?;
240 let patch_version = self
241 .read_flash_str_at_ptr(info.patch_version_len, info.patch_version_ptr)
242 .await
243 .inspect_err(|e| warn!("Failed to read patch version: {e}"))?;
244 let build_number = self
245 .read_flash_str_at_ptr(info.build_number_len, info.build_number_ptr)
246 .await
247 .inspect_err(|e| warn!("Failed to read build number: {e}"))?;
248 let mcu = self
249 .read_flash_str_at_ptr(info.mcu_len, info.mcu_ptr)
250 .await
251 .inspect_err(|e| warn!("Failed to read MCU: {e}"))?;
252 let hw_rev = self
253 .read_flash_str_at_ptr(info.hw_rev_len, info.hw_rev_ptr)
254 .await
255 .inspect_err(|e| warn!("Failed to read HW revision: {e}"))?;
256 let features = self
257 .read_flash_str_at_ptr(info.features_len, info.features_ptr)
258 .await
259 .inspect_err(|e| warn!("Failed to read features: {e}"))?;
260
261 let flash = LabFlash {
262 major_version,
263 minor_version,
264 patch_version,
265 build_number,
266 mcu,
267 hw_rev,
268 features,
269 rtt_ptr: info.rtt_ptr,
270 };
271
272 Ok(flash)
273 }
274
275 async fn parse_ram(&mut self) -> Result<LabRam, String> {
276 let info = self.retrieve_ram_info().await?;
277
278 let ram = LabRam {
279 rom_data_ptr: info.rom_data_ptr,
280 rpc_cmd_channel_ptr: info.rpc_cmd_channel_ptr,
281 rpc_rsp_channel_ptr: info.rpc_rsp_channel_ptr,
282 rpc_cmd_channel_size: info.rpc_cmd_channel_size,
283 rpc_rsp_channel_size: info.rpc_rsp_channel_size,
284 };
285
286 Ok(ram)
287 }
288
289 async fn read_flash_str_at_ptr(&mut self, len: u32, ptr: u32) -> Result<String, String> {
290 if len > 0 && ptr < self.base_flash_address {
291 return Err(format!("Invalid pointer: 0x{:08X}", ptr));
292 }
293
294 read_str_at_ptr(self.reader, len, ptr).await
295 }
296}