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, SIG_PUB_FILE, load_stub_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文件 - 支持外部 stub 文件
105        let chip_memory_key = format!("sf32lb58_{}", self.base.memory_type);
106        let stub = load_stub_file(self.base.external_stub_path.as_deref(), &chip_memory_key)?;
107
108        spinner.set_message("Downloading RAM stub...");
109
110        // 发送下载镜像命令(flashid = 9 对应RAM stub)
111        self.download_image(&stub.data, 9)?;
112
113        spinner.finish_with_message("Download stub success!");
114
115        tracing::info!("SF32LB58 stub download completed successfully");
116        Ok(())
117    }
118
119    /// 下载引导补丁签名密钥
120    fn download_boot_patch_sigkey(&mut self, sig_data: &[u8]) -> Result<()> {
121        tracing::info!(
122            "Starting boot patch signature key download, size: {} bytes",
123            sig_data.len()
124        );
125
126        let header = [
127            DfuCommandType::Config as u8,
128            DfuConfigType::BootPatchSig as u8,
129        ];
130        let total_len = 2 + sig_data.len();
131
132        self.send_dfu_command(total_len, Some(10))?;
133        self.send_dfu_data(&header, sig_data, Some(4))?;
134
135        tracing::debug!("Waiting for boot patch signature key response...");
136        self.wait_for_ok_response(3000)?;
137
138        tracing::info!("Boot patch signature key downloaded successfully");
139        Ok(())
140    }
141
142    /// 下载镜像文件
143    fn download_image(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
144        tracing::info!(
145            "Starting image download: flash_id={}, size={} bytes",
146            flash_id,
147            data.len()
148        );
149
150        // 1. 发送镜像头部
151        self.download_image_header(data, flash_id)?;
152
153        // 2. 发送镜像主体
154        self.download_image_body(data, flash_id)?;
155
156        // 3. 发送结束标志
157        self.download_image_end(flash_id)?;
158
159        tracing::info!("Image download completed successfully");
160        Ok(())
161    }
162
163    /// 下载镜像头部
164    fn download_image_header(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
165        tracing::debug!("Downloading image header...");
166
167        let header = [DfuCommandType::ImageHeader as u8, flash_id];
168        let total_len = 2 + Self::HDR_SIZE;
169
170        self.send_dfu_command(total_len, Some(10))?;
171        self.send_dfu_data(&header, &data[0..Self::HDR_SIZE], None)?;
172
173        tracing::debug!("Waiting for image header response...");
174        self.wait_for_ok_response(3000)?;
175
176        tracing::debug!("Image header downloaded successfully");
177        Ok(())
178    }
179
180    /// 下载镜像主体
181    fn download_image_body(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
182        tracing::debug!("Downloading image body...");
183
184        let body_header = [DfuCommandType::ImageBody as u8, flash_id];
185        let mut offset = Self::HDR_SIZE;
186        let mut chunk_count = 0;
187
188        while offset < data.len() {
189            let remaining = data.len() - offset;
190            let chunk_size = std::cmp::min(remaining, Self::CHUNK_OVERHEAD + Self::BLOCK_SIZE);
191
192            tracing::trace!(
193                "Sending chunk {}: offset={}, size={}",
194                chunk_count,
195                offset,
196                chunk_size
197            );
198
199            let total_len = 2 + chunk_size;
200            self.send_dfu_command(total_len, Some(10))?;
201            self.send_dfu_data(&body_header, &data[offset..offset + chunk_size], None)?;
202
203            tracing::trace!("Waiting for chunk {} response...", chunk_count);
204            self.wait_for_ok_response(3000)?;
205
206            offset += chunk_size;
207            chunk_count += 1;
208        }
209
210        tracing::debug!("Image body downloaded successfully: {} chunks", chunk_count);
211        Ok(())
212    }
213
214    /// 下载镜像结束标志
215    fn download_image_end(&mut self, flash_id: u8) -> Result<()> {
216        tracing::debug!("Sending image end marker...");
217
218        let end_header = [DfuCommandType::End as u8, flash_id];
219
220        self.send_dfu_command(2, Some(10))?;
221        self.send_dfu_data(&end_header, &[], None)?;
222
223        tracing::debug!("Waiting for image end response...");
224        self.wait_for_ok_response(5000)?;
225
226        tracing::debug!("Image end marker sent successfully");
227        Ok(())
228    }
229
230    /// 等待OK响应
231    fn wait_for_ok_response(&mut self, timeout_ms: u64) -> Result<()> {
232        use std::io::Read;
233
234        let mut buffer = Vec::new();
235        let start_time = std::time::SystemTime::now();
236        let mut last_log_time = start_time;
237
238        tracing::trace!("Waiting for OK response with timeout: {}ms", timeout_ms);
239
240        loop {
241            let elapsed = start_time.elapsed().unwrap().as_millis() as u64;
242            if elapsed > timeout_ms {
243                let response_str = String::from_utf8_lossy(&buffer);
244                tracing::error!(
245                    "Timeout waiting for OK response after {}ms. Received: '{}'",
246                    elapsed,
247                    response_str
248                );
249                return Err(std::io::Error::new(
250                    std::io::ErrorKind::TimedOut,
251                    format!("Timeout waiting for OK response: {}", response_str),
252                )
253                .into());
254            }
255
256            // 每秒记录一次等待状态
257            if elapsed > 0
258                && elapsed.is_multiple_of(1000)
259                && start_time.elapsed().unwrap()
260                    > last_log_time.elapsed().unwrap() + Duration::from_secs(1)
261            {
262                tracing::trace!("Still waiting for response... elapsed: {}ms", elapsed);
263                last_log_time = std::time::SystemTime::now();
264            }
265
266            let mut byte = [0];
267            if self.port.read_exact(&mut byte).is_ok() {
268                buffer.push(byte[0]);
269
270                // 检查是否收到"OK"响应
271                if buffer.windows(2).any(|window| window == b"OK") {
272                    let response_str = String::from_utf8_lossy(&buffer);
273                    tracing::trace!(
274                        "Received OK response after {}ms: '{}'",
275                        elapsed,
276                        response_str
277                    );
278                    return Ok(());
279                }
280
281                // 检查是否收到"Fail"响应
282                if buffer.windows(4).any(|window| window == b"Fail") {
283                    let response_str = String::from_utf8_lossy(&buffer);
284                    tracing::error!(
285                        "Received Fail response after {}ms: '{}'",
286                        elapsed,
287                        response_str
288                    );
289                    return Err(std::io::Error::other(format!(
290                        "Received Fail response: {}",
291                        response_str
292                    ))
293                    .into());
294                }
295
296                // 限制缓冲区大小,避免内存占用过多
297                if buffer.len() > 1024 {
298                    let response_str = String::from_utf8_lossy(&buffer);
299                    tracing::warn!(
300                        "Response buffer too large ({}), truncating. Content: '{}'",
301                        buffer.len(),
302                        response_str
303                    );
304                    buffer.drain(..512); // 保留后半部分
305                }
306            }
307        }
308    }
309}
310
311impl SifliTool for SF32LB58Tool {
312    fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
313        let mut port = serialport::new(&base.port_name, 1000000)
314            .timeout(Duration::from_secs(5))
315            .open()
316            .unwrap();
317        port.write_request_to_send(false).unwrap();
318        std::thread::sleep(Duration::from_millis(100));
319
320        let mut tool = Box::new(Self { base, port });
321        if tool.base.before.should_download_stub() {
322            tool.download_stub().expect("Failed to download stub");
323        }
324        tool
325    }
326}
327
328impl SifliToolTrait for SF32LB58Tool {
329    fn port(&mut self) -> &mut Box<dyn SerialPort> {
330        &mut self.port
331    }
332
333    fn base(&self) -> &SifliToolBase {
334        &self.base
335    }
336
337    fn set_speed(&mut self, _baud: u32) -> Result<()> {
338        todo!("SF32LB58Tool::set_speed not implemented yet")
339    }
340
341    fn soft_reset(&mut self) -> Result<()> {
342        use crate::reset::Reset;
343        Reset::soft_reset(self)
344    }
345}