Skip to main content

sftool_lib/sf32lb55/
mod.rs

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