sftool_lib/sf32lb58/
mod.rs

1//! SF32LB58 芯片特定实现模块
2
3pub mod erase_flash;
4pub mod ram_command;
5pub mod read_flash;
6pub mod reset;
7pub mod speed;
8pub mod write_flash;
9
10use crate::sf32lb58::ram_command::DownloadStub;
11use crate::{Result, SifliTool, SifliToolBase, SifliToolTrait};
12use serialport::SerialPort;
13use std::io::Write;
14use std::time::Duration;
15
16pub struct SF32LB58Tool {
17    pub base: SifliToolBase,
18    pub port: Box<dyn SerialPort>,
19}
20
21// 为 SF32LB58Tool 实现 Send 和 Sync
22unsafe impl Send for SF32LB58Tool {}
23unsafe impl Sync for SF32LB58Tool {}
24
25/// DFU协议命令类型
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[repr(u8)]
28enum DfuCommandType {
29    ImageHeader = 1,
30    ImageBody = 2,
31    Config = 3,
32    End = 4,
33}
34
35/// DFU配置类型
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37#[repr(u8)]
38enum DfuConfigType {
39    BootPatchSig = 10,
40}
41
42impl SF32LB58Tool {
43    // DFU协议常量
44    const BLOCK_SIZE: usize = 512;
45    const HDR_SIZE: usize = 32 + 296;
46    const CHUNK_OVERHEAD: usize = 32 + 4;
47
48    /// 发送DFU命令的通用方法
49    fn send_dfu_command(&mut self, data_len: usize, delay_ms: Option<u64>) -> Result<()> {
50        let cmd = format!("dfu_recv {}\r", data_len);
51        tracing::trace!("Sending DFU command: {}", cmd.trim());
52
53        self.port.write_all(cmd.as_bytes())?;
54        self.port.flush()?;
55
56        if let Some(delay) = delay_ms {
57            std::thread::sleep(Duration::from_millis(delay));
58        }
59
60        Ok(())
61    }
62
63    /// 发送DFU数据的通用方法
64    fn send_dfu_data(&mut self, header: &[u8], data: &[u8], delay_ms: Option<u64>) -> Result<()> {
65        tracing::trace!(
66            "Sending DFU data: header={:?}, data_len={}",
67            header,
68            data.len()
69        );
70
71        self.port.write_all(header)?;
72        self.port.write_all(data)?;
73        self.port.flush()?;
74
75        if let Some(delay) = delay_ms {
76            std::thread::sleep(Duration::from_millis(delay));
77        }
78
79        Ok(())
80    }
81
82    fn download_stub_impl(&mut self) -> Result<()> {
83        use crate::ram_stub::{self, CHIP_FILE_NAME, SIG_PUB_FILE};
84
85        tracing::info!("Starting SF32LB58 stub download process");
86        self.port.clear(serialport::ClearBuffer::All)?;
87
88        let progress = self.progress();
89        let spinner = progress.create_spinner("Download stub...");
90
91        // 1. 下载签名公钥文件 (58X_sig_pub.der)
92        tracing::debug!("Loading signature public key file: {}", SIG_PUB_FILE);
93        let sig_pub_data = ram_stub::RamStubFile::get(SIG_PUB_FILE).ok_or_else(|| {
94            tracing::error!("Signature public key file not found: {}", SIG_PUB_FILE);
95            std::io::Error::new(
96                std::io::ErrorKind::NotFound,
97                "58X_sig_pub.der file not found",
98            )
99        })?;
100
101        spinner.set_message("Downloading signature key...");
102        self.download_boot_patch_sigkey(&sig_pub_data.data)?;
103
104        // 2. 下载RAM stub文件
105        let memory_type_key = format!("sf32lb58_{}", self.base.memory_type);
106        tracing::debug!("Looking for stub file with key: {}", memory_type_key);
107
108        let stub_file_name = CHIP_FILE_NAME
109            .get(memory_type_key.as_str())
110            .ok_or_else(|| {
111                tracing::error!("No stub file found for chip type: {}", memory_type_key);
112                std::io::Error::new(
113                    std::io::ErrorKind::NotFound,
114                    format!(
115                        "No stub file found for the given chip and memory type: {}",
116                        memory_type_key
117                    ),
118                )
119            })?;
120
121        tracing::debug!("Loading RAM stub file: {}", stub_file_name);
122        let stub = ram_stub::RamStubFile::get(stub_file_name).ok_or_else(|| {
123            tracing::error!("Stub file not found: {}", stub_file_name);
124            std::io::Error::new(
125                std::io::ErrorKind::NotFound,
126                format!("Stub file not found: {}", stub_file_name),
127            )
128        })?;
129
130        spinner.set_message("Downloading RAM stub...");
131
132        // 发送下载镜像命令(flashid = 9 对应RAM stub)
133        self.download_image(&stub.data, 9)?;
134
135        spinner.finish_with_message("Download stub success!");
136
137        tracing::info!("SF32LB58 stub download completed successfully");
138        Ok(())
139    }
140
141    /// 下载引导补丁签名密钥
142    fn download_boot_patch_sigkey(&mut self, sig_data: &[u8]) -> Result<()> {
143        tracing::info!(
144            "Starting boot patch signature key download, size: {} bytes",
145            sig_data.len()
146        );
147
148        let header = [
149            DfuCommandType::Config as u8,
150            DfuConfigType::BootPatchSig as u8,
151        ];
152        let total_len = 2 + sig_data.len();
153
154        self.send_dfu_command(total_len, Some(10))?;
155        self.send_dfu_data(&header, sig_data, Some(4))?;
156
157        tracing::debug!("Waiting for boot patch signature key response...");
158        self.wait_for_ok_response(3000)?;
159
160        tracing::info!("Boot patch signature key downloaded successfully");
161        Ok(())
162    }
163
164    /// 下载镜像文件
165    fn download_image(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
166        tracing::info!(
167            "Starting image download: flash_id={}, size={} bytes",
168            flash_id,
169            data.len()
170        );
171
172        // 1. 发送镜像头部
173        self.download_image_header(data, flash_id)?;
174
175        // 2. 发送镜像主体
176        self.download_image_body(data, flash_id)?;
177
178        // 3. 发送结束标志
179        self.download_image_end(flash_id)?;
180
181        tracing::info!("Image download completed successfully");
182        Ok(())
183    }
184
185    /// 下载镜像头部
186    fn download_image_header(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
187        tracing::debug!("Downloading image header...");
188
189        let header = [DfuCommandType::ImageHeader as u8, flash_id];
190        let total_len = 2 + Self::HDR_SIZE;
191
192        self.send_dfu_command(total_len, Some(10))?;
193        self.send_dfu_data(&header, &data[0..Self::HDR_SIZE], None)?;
194
195        tracing::debug!("Waiting for image header response...");
196        self.wait_for_ok_response(3000)?;
197
198        tracing::debug!("Image header downloaded successfully");
199        Ok(())
200    }
201
202    /// 下载镜像主体
203    fn download_image_body(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
204        tracing::debug!("Downloading image body...");
205
206        let body_header = [DfuCommandType::ImageBody as u8, flash_id];
207        let mut offset = Self::HDR_SIZE;
208        let mut chunk_count = 0;
209
210        while offset < data.len() {
211            let remaining = data.len() - offset;
212            let chunk_size = std::cmp::min(remaining, Self::CHUNK_OVERHEAD + Self::BLOCK_SIZE);
213
214            tracing::trace!(
215                "Sending chunk {}: offset={}, size={}",
216                chunk_count,
217                offset,
218                chunk_size
219            );
220
221            let total_len = 2 + chunk_size;
222            self.send_dfu_command(total_len, Some(10))?;
223            self.send_dfu_data(&body_header, &data[offset..offset + chunk_size], None)?;
224
225            tracing::trace!("Waiting for chunk {} response...", chunk_count);
226            self.wait_for_ok_response(3000)?;
227
228            offset += chunk_size;
229            chunk_count += 1;
230        }
231
232        tracing::debug!("Image body downloaded successfully: {} chunks", chunk_count);
233        Ok(())
234    }
235
236    /// 下载镜像结束标志
237    fn download_image_end(&mut self, flash_id: u8) -> Result<()> {
238        tracing::debug!("Sending image end marker...");
239
240        let end_header = [DfuCommandType::End as u8, flash_id];
241
242        self.send_dfu_command(2, Some(10))?;
243        self.send_dfu_data(&end_header, &[], None)?;
244
245        tracing::debug!("Waiting for image end response...");
246        self.wait_for_ok_response(5000)?;
247
248        tracing::debug!("Image end marker sent successfully");
249        Ok(())
250    }
251
252    /// 等待OK响应
253    fn wait_for_ok_response(&mut self, timeout_ms: u64) -> Result<()> {
254        use std::io::Read;
255
256        let mut buffer = Vec::new();
257        let start_time = std::time::SystemTime::now();
258        let mut last_log_time = start_time;
259
260        tracing::trace!("Waiting for OK response with timeout: {}ms", timeout_ms);
261
262        loop {
263            let elapsed = start_time.elapsed().unwrap().as_millis() as u64;
264            if elapsed > timeout_ms {
265                let response_str = String::from_utf8_lossy(&buffer);
266                tracing::error!(
267                    "Timeout waiting for OK response after {}ms. Received: '{}'",
268                    elapsed,
269                    response_str
270                );
271                return Err(std::io::Error::new(
272                    std::io::ErrorKind::TimedOut,
273                    format!("Timeout waiting for OK response: {}", response_str),
274                )
275                .into());
276            }
277
278            // 每秒记录一次等待状态
279            if elapsed > 0
280                && elapsed.is_multiple_of(1000)
281                && start_time.elapsed().unwrap()
282                    > last_log_time.elapsed().unwrap() + Duration::from_secs(1)
283            {
284                tracing::trace!("Still waiting for response... elapsed: {}ms", elapsed);
285                last_log_time = std::time::SystemTime::now();
286            }
287
288            let mut byte = [0];
289            if self.port.read_exact(&mut byte).is_ok() {
290                buffer.push(byte[0]);
291
292                // 检查是否收到"OK"响应
293                if buffer.windows(2).any(|window| window == b"OK") {
294                    let response_str = String::from_utf8_lossy(&buffer);
295                    tracing::trace!(
296                        "Received OK response after {}ms: '{}'",
297                        elapsed,
298                        response_str
299                    );
300                    return Ok(());
301                }
302
303                // 检查是否收到"Fail"响应
304                if buffer.windows(4).any(|window| window == b"Fail") {
305                    let response_str = String::from_utf8_lossy(&buffer);
306                    tracing::error!(
307                        "Received Fail response after {}ms: '{}'",
308                        elapsed,
309                        response_str
310                    );
311                    return Err(std::io::Error::other(format!(
312                        "Received Fail response: {}",
313                        response_str
314                    ))
315                    .into());
316                }
317
318                // 限制缓冲区大小,避免内存占用过多
319                if buffer.len() > 1024 {
320                    let response_str = String::from_utf8_lossy(&buffer);
321                    tracing::warn!(
322                        "Response buffer too large ({}), truncating. Content: '{}'",
323                        buffer.len(),
324                        response_str
325                    );
326                    buffer.drain(..512); // 保留后半部分
327                }
328            }
329        }
330    }
331}
332
333impl SifliTool for SF32LB58Tool {
334    fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
335        let mut port = serialport::new(&base.port_name, 1000000)
336            .timeout(Duration::from_secs(5))
337            .open()
338            .unwrap();
339        port.write_request_to_send(false).unwrap();
340        std::thread::sleep(Duration::from_millis(100));
341
342        let mut tool = Box::new(Self { base, port });
343        if tool.base.before.should_download_stub() {
344            tool.download_stub().expect("Failed to download stub");
345        }
346        tool
347    }
348}
349
350impl SifliToolTrait for SF32LB58Tool {
351    fn port(&mut self) -> &mut Box<dyn SerialPort> {
352        &mut self.port
353    }
354
355    fn base(&self) -> &SifliToolBase {
356        &self.base
357    }
358
359    fn set_speed(&mut self, _baud: u32) -> Result<()> {
360        todo!("SF32LB58Tool::set_speed not implemented yet")
361    }
362
363    fn soft_reset(&mut self) -> Result<()> {
364        use crate::reset::Reset;
365        Reset::soft_reset(self)
366    }
367}