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::common::serial_io::{for_tool, sleep_with_cancel};
11use crate::progress::{ProgressOperation, ProgressStatus, StubStage};
12use crate::sf32lb55::ram_command::DownloadStub;
13use crate::{Result, SifliTool, SifliToolBase, SifliToolTrait};
14use serialport::SerialPort;
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        {
55            let mut io = for_tool(self);
56            io.write_all(cmd.as_bytes())?;
57            io.flush()?;
58        }
59
60        if let Some(delay) = delay_ms {
61            sleep_with_cancel(&self.base.cancel_token, Duration::from_millis(delay))?;
62        }
63
64        Ok(())
65    }
66
67    /// 发送DFU数据的通用方法
68    fn send_dfu_data(&mut self, header: &[u8], data: &[u8], delay_ms: Option<u64>) -> Result<()> {
69        tracing::trace!(
70            "Sending DFU data: header={:?}, data_len={}",
71            header,
72            data.len()
73        );
74
75        {
76            let mut io = for_tool(self);
77            io.write_all(header)?;
78            io.write_all(data)?;
79            io.flush()?;
80        }
81
82        if let Some(delay) = delay_ms {
83            sleep_with_cancel(&self.base.cancel_token, Duration::from_millis(delay))?;
84        }
85
86        Ok(())
87    }
88
89    fn download_stub_impl(&mut self) -> Result<()> {
90        use crate::ram_stub::{self, SIG_PUB_FILE, load_stub_file};
91
92        tracing::info!("Starting SF32LB55 stub download process");
93        {
94            let mut io = for_tool(self);
95            io.clear(serialport::ClearBuffer::All)?;
96        }
97
98        let progress = self.progress();
99        let spinner = progress.create_spinner(ProgressOperation::DownloadStub {
100            stage: StubStage::Start,
101        });
102
103        // 1. 下载签名公钥文件 (58X_sig_pub.der)
104        tracing::debug!("Loading signature public key file: {}", SIG_PUB_FILE);
105        let sig_pub_data = ram_stub::RamStubFile::get(SIG_PUB_FILE).ok_or_else(|| {
106            tracing::error!("Signature public key file not found: {}", SIG_PUB_FILE);
107            std::io::Error::new(
108                std::io::ErrorKind::NotFound,
109                "58X_sig_pub.der file not found",
110            )
111        })?;
112
113        spinner.set_operation(ProgressOperation::DownloadStub {
114            stage: StubStage::SignatureKey,
115        });
116        self.download_boot_patch_sigkey(&sig_pub_data.data)?;
117
118        // 2. 下载RAM stub文件 - 支持外部 stub 文件
119        let chip_memory_key = format!("sf32lb55_{}", self.base.memory_type);
120        let stub = load_stub_file(self.base.external_stub_path.as_deref(), &chip_memory_key)?;
121
122        spinner.set_operation(ProgressOperation::DownloadStub {
123            stage: StubStage::RamStub,
124        });
125
126        // 发送下载镜像命令(flashid = 9 对应RAM stub)
127        self.download_image(&stub.data, 9)?;
128
129        spinner.finish(ProgressStatus::Success);
130
131        tracing::info!("SF32LB55 stub download completed successfully");
132        Ok(())
133    }
134
135    /// 下载引导补丁签名密钥
136    fn download_boot_patch_sigkey(&mut self, sig_data: &[u8]) -> Result<()> {
137        tracing::info!(
138            "Starting boot patch signature key download, size: {} bytes",
139            sig_data.len()
140        );
141
142        let header = [
143            DfuCommandType::Config as u8,
144            DfuConfigType::BootPatchSig as u8,
145        ];
146        let total_len = 2 + sig_data.len();
147
148        self.send_dfu_command(total_len, Some(10))?;
149        self.send_dfu_data(&header, sig_data, Some(4))?;
150
151        tracing::debug!("Waiting for boot patch signature key response...");
152        self.wait_for_ok_response(3000)?;
153
154        tracing::info!("Boot patch signature key downloaded successfully");
155        Ok(())
156    }
157
158    /// 下载镜像文件
159    fn download_image(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
160        tracing::info!(
161            "Starting image download: flash_id={}, size={} bytes",
162            flash_id,
163            data.len()
164        );
165
166        // 1. 发送镜像头部
167        self.download_image_header(data, flash_id)?;
168
169        // 2. 发送镜像主体
170        self.download_image_body(data, flash_id)?;
171
172        // 3. 发送结束标志
173        self.download_image_end(flash_id)?;
174
175        tracing::info!("Image download completed successfully");
176        Ok(())
177    }
178
179    /// 下载镜像头部
180    fn download_image_header(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
181        tracing::debug!("Downloading image header...");
182
183        let header = [DfuCommandType::ImageHeader as u8, flash_id];
184        let total_len = 2 + Self::HDR_SIZE;
185
186        self.send_dfu_command(total_len, Some(10))?;
187        self.send_dfu_data(&header, &data[0..Self::HDR_SIZE], None)?;
188
189        tracing::debug!("Waiting for image header response...");
190        self.wait_for_ok_response(3000)?;
191
192        tracing::debug!("Image header downloaded successfully");
193        Ok(())
194    }
195
196    /// 下载镜像主体
197    fn download_image_body(&mut self, data: &[u8], flash_id: u8) -> Result<()> {
198        tracing::debug!("Downloading image body...");
199
200        let body_header = [DfuCommandType::ImageBody as u8, flash_id];
201        let mut offset = Self::HDR_SIZE;
202        let mut chunk_count = 0;
203
204        while offset < data.len() {
205            self.base.check_cancelled()?;
206            let remaining = data.len() - offset;
207            let chunk_size = std::cmp::min(remaining, Self::CHUNK_OVERHEAD + Self::BLOCK_SIZE);
208
209            tracing::trace!(
210                "Sending chunk {}: offset={}, size={}",
211                chunk_count,
212                offset,
213                chunk_size
214            );
215
216            let total_len = 2 + chunk_size;
217            self.send_dfu_command(total_len, Some(10))?;
218            self.send_dfu_data(&body_header, &data[offset..offset + chunk_size], None)?;
219
220            tracing::trace!("Waiting for chunk {} response...", chunk_count);
221            self.wait_for_ok_response(3000)?;
222
223            offset += chunk_size;
224            chunk_count += 1;
225        }
226
227        tracing::debug!("Image body downloaded successfully: {} chunks", chunk_count);
228        Ok(())
229    }
230
231    /// 下载镜像结束标志
232    fn download_image_end(&mut self, flash_id: u8) -> Result<()> {
233        tracing::debug!("Sending image end marker...");
234
235        let end_header = [DfuCommandType::End as u8, flash_id];
236
237        self.send_dfu_command(2, Some(10))?;
238        self.send_dfu_data(&end_header, &[], None)?;
239
240        tracing::debug!("Waiting for image end response...");
241        self.wait_for_ok_response(5000)?;
242
243        tracing::debug!("Image end marker sent successfully");
244        Ok(())
245    }
246
247    /// 等待OK响应
248    fn wait_for_ok_response(&mut self, timeout_ms: u64) -> Result<()> {
249        tracing::trace!("Waiting for OK response with timeout: {}ms", timeout_ms);
250        let matched = {
251            let mut io = for_tool(self);
252            io.wait_for_patterns(
253                &[b"OK", b"Fail"],
254                Duration::from_millis(timeout_ms),
255                "OK response",
256            )?
257        };
258
259        let response_str = String::from_utf8_lossy(&matched.buffer);
260        if matched.index == 0 {
261            tracing::trace!("Received OK response: '{}'", response_str);
262            return Ok(());
263        }
264
265        tracing::error!("Received Fail response: '{}'", response_str);
266        Err(std::io::Error::other(format!("Received Fail response: {}", response_str)).into())
267    }
268}
269
270impl SifliTool for SF32LB55Tool {
271    fn create_tool(base: SifliToolBase) -> Box<dyn SifliTool> {
272        let mut port = serialport::new(&base.port_name, 1000000)
273            .timeout(Duration::from_secs(5))
274            .open()
275            .unwrap();
276        port.write_request_to_send(false).unwrap();
277        std::thread::sleep(Duration::from_millis(100));
278
279        let mut tool = Box::new(Self { base, port });
280        if tool.base.before.should_download_stub() {
281            tool.download_stub().expect("Failed to download stub");
282        }
283        tool
284    }
285}
286
287impl SifliToolTrait for SF32LB55Tool {
288    fn port(&mut self) -> &mut Box<dyn SerialPort> {
289        &mut self.port
290    }
291
292    fn base(&self) -> &SifliToolBase {
293        &self.base
294    }
295
296    fn set_speed(&mut self, _baud: u32) -> Result<()> {
297        todo!("SF32LB55Tool::set_speed not implemented yet")
298    }
299
300    fn soft_reset(&mut self) -> Result<()> {
301        use crate::reset::Reset;
302        Reset::soft_reset(self)
303    }
304}