Skip to main content

sftool_lib/
lib.rs

1pub mod erase_flash;
2mod ram_stub;
3pub mod read_flash;
4pub mod reset;
5pub mod speed;
6pub mod stub_config;
7pub mod utils;
8pub mod write_flash;
9
10pub mod error;
11
12// 进度条回调系统
13pub mod progress;
14
15// 公共模块,包含可复用的逻辑
16pub mod common;
17
18// 芯片特定的实现模块
19pub mod sf32lb52;
20pub mod sf32lb55;
21pub mod sf32lb56;
22pub mod sf32lb57;
23pub mod sf32lb58;
24
25// 重新导出 trait,使其在 crate 外部可用
26pub use crate::erase_flash::EraseFlashTrait;
27pub use crate::read_flash::ReadFlashTrait;
28pub use crate::write_flash::WriteFlashTrait;
29pub use error::{Error, Result};
30
31use crate::progress::{ProgressHelper, ProgressSinkArc, no_op_progress_sink};
32use serialport::SerialPort;
33use std::sync::{
34    Arc,
35    atomic::{AtomicBool, Ordering},
36};
37
38#[derive(Clone, Default)]
39pub struct CancelToken {
40    cancelled: Arc<AtomicBool>,
41}
42
43impl CancelToken {
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    pub fn cancel(&self) {
49        self.cancelled.store(true, Ordering::SeqCst);
50    }
51
52    pub fn is_cancelled(&self) -> bool {
53        self.cancelled.load(Ordering::SeqCst)
54    }
55
56    pub fn check_cancelled(&self) -> Result<()> {
57        if self.is_cancelled() {
58            Err(Error::Cancelled)
59        } else {
60            Ok(())
61        }
62    }
63}
64
65/// Load stub image bytes for the given chip and memory type.
66pub fn load_stub_bytes(
67    external_path: Option<&str>,
68    chip_type: ChipType,
69    memory_type: &str,
70) -> Result<Vec<u8>> {
71    let chip_key = match chip_type {
72        ChipType::SF32LB52 => "sf32lb52",
73        ChipType::SF32LB55 => "sf32lb55",
74        ChipType::SF32LB56 => "sf32lb56",
75        ChipType::SF32LB57 => "sf32lb57",
76        ChipType::SF32LB58 => "sf32lb58",
77    };
78    let key = format!("{}_{}", chip_key, memory_type.to_lowercase());
79    let stub = ram_stub::load_stub_file(external_path, &key)?;
80    Ok(stub.data.into_owned())
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
84#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
85pub enum BeforeOperation {
86    #[cfg_attr(feature = "cli", clap(name = "default_reset"))]
87    DefaultReset,
88    #[cfg_attr(feature = "cli", clap(name = "no_reset"))]
89    NoReset,
90    #[cfg_attr(feature = "cli", clap(name = "no_reset_no_sync"))]
91    NoResetNoSync,
92}
93
94impl BeforeOperation {
95    pub fn requires_reset(&self) -> bool {
96        matches!(self, Self::DefaultReset)
97    }
98
99    pub fn should_download_stub(&self) -> bool {
100        !matches!(self, Self::NoResetNoSync)
101    }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
105#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
106pub enum AfterOperation {
107    #[cfg_attr(feature = "cli", clap(name = "no_reset"))]
108    NoReset,
109    #[cfg_attr(feature = "cli", clap(name = "soft_reset"))]
110    SoftReset,
111}
112
113impl AfterOperation {
114    pub fn requires_soft_reset(&self) -> bool {
115        matches!(self, Self::SoftReset)
116    }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
120#[cfg_attr(feature = "cli", derive(clap::ValueEnum))]
121pub enum ChipType {
122    #[cfg_attr(feature = "cli", clap(name = "SF32LB52"))]
123    SF32LB52,
124    #[cfg_attr(feature = "cli", clap(name = "SF32LB55"))]
125    SF32LB55,
126    #[cfg_attr(feature = "cli", clap(name = "SF32LB56"))]
127    SF32LB56,
128    #[cfg_attr(feature = "cli", clap(name = "SF32LB57"))]
129    SF32LB57,
130    #[cfg_attr(feature = "cli", clap(name = "SF32LB58"))]
131    SF32LB58,
132}
133
134#[derive(Clone)]
135pub struct SifliToolBase {
136    pub port_name: String,
137    pub before: BeforeOperation,
138    pub memory_type: String,
139    pub baud: u32,
140    pub connect_attempts: i8,
141    pub compat: bool,
142    pub progress_sink: ProgressSinkArc,
143    pub progress_helper: Arc<ProgressHelper>,
144    pub cancel_token: CancelToken,
145    /// 外部 stub 文件路径,如果指定则优先使用外部文件而非内嵌文件
146    pub external_stub_path: Option<String>,
147}
148
149impl SifliToolBase {
150    /// 创建一个使用默认空进度回调的 SifliToolBase
151    pub fn new_with_no_progress(
152        port_name: String,
153        before: BeforeOperation,
154        memory_type: String,
155        baud: u32,
156        connect_attempts: i8,
157        compat: bool,
158    ) -> Self {
159        let progress_sink = no_op_progress_sink();
160        let progress_helper = Arc::new(ProgressHelper::new(progress_sink.clone(), 0));
161        Self {
162            port_name,
163            before,
164            memory_type,
165            baud,
166            connect_attempts,
167            compat,
168            progress_sink,
169            progress_helper,
170            cancel_token: CancelToken::new(),
171            external_stub_path: None,
172        }
173    }
174
175    /// 创建一个使用自定义进度回调的 SifliToolBase
176    pub fn new_with_progress(
177        port_name: String,
178        before: BeforeOperation,
179        memory_type: String,
180        baud: u32,
181        connect_attempts: i8,
182        compat: bool,
183        progress_sink: ProgressSinkArc,
184    ) -> Self {
185        let progress_helper = Arc::new(ProgressHelper::new(progress_sink.clone(), 0));
186        Self {
187            port_name,
188            before,
189            memory_type,
190            baud,
191            connect_attempts,
192            compat,
193            progress_sink,
194            progress_helper,
195            cancel_token: CancelToken::new(),
196            external_stub_path: None,
197        }
198    }
199
200    /// 创建一个使用自定义进度回调和外部 stub 文件的 SifliToolBase
201    #[allow(clippy::too_many_arguments)]
202    pub fn new_with_external_stub(
203        port_name: String,
204        before: BeforeOperation,
205        memory_type: String,
206        baud: u32,
207        connect_attempts: i8,
208        compat: bool,
209        progress_sink: ProgressSinkArc,
210        external_stub_path: Option<String>,
211    ) -> Self {
212        let progress_helper = Arc::new(ProgressHelper::new(progress_sink.clone(), 0));
213        Self {
214            port_name,
215            before,
216            memory_type,
217            baud,
218            connect_attempts,
219            compat,
220            progress_sink,
221            progress_helper,
222            cancel_token: CancelToken::new(),
223            external_stub_path,
224        }
225    }
226
227    #[allow(clippy::too_many_arguments)]
228    pub fn new_with_external_stub_and_cancel(
229        port_name: String,
230        before: BeforeOperation,
231        memory_type: String,
232        baud: u32,
233        connect_attempts: i8,
234        compat: bool,
235        progress_sink: ProgressSinkArc,
236        external_stub_path: Option<String>,
237        cancel_token: CancelToken,
238    ) -> Self {
239        let progress_helper = Arc::new(ProgressHelper::new(progress_sink.clone(), 0));
240        Self {
241            port_name,
242            before,
243            memory_type,
244            baud,
245            connect_attempts,
246            compat,
247            progress_sink,
248            progress_helper,
249            cancel_token,
250            external_stub_path,
251        }
252    }
253
254    pub fn check_cancelled(&self) -> Result<()> {
255        self.cancel_token.check_cancelled()
256    }
257}
258
259pub struct WriteFlashParams {
260    pub files: Vec<WriteFlashFile>,
261    pub verify: bool,
262    pub no_compress: bool,
263    pub erase_all: bool,
264}
265
266#[derive(Debug)]
267pub struct WriteFlashFile {
268    pub address: u32,
269    pub file: std::fs::File,
270    pub crc32: u32,
271}
272
273pub struct ReadFlashParams {
274    pub files: Vec<ReadFlashFile>,
275}
276
277#[derive(Debug)]
278pub struct ReadFlashFile {
279    pub file_path: String,
280    pub address: u32,
281    pub size: u32,
282}
283
284#[derive(Clone)]
285pub struct EraseFlashParams {
286    pub address: u32,
287}
288
289pub struct EraseRegionParams {
290    pub regions: Vec<EraseRegionFile>,
291}
292
293#[derive(Debug)]
294pub struct EraseRegionFile {
295    pub address: u32,
296    pub size: u32,
297}
298
299pub trait SifliToolTrait: Send + Sync {
300    /// 获取串口的可变引用
301    fn port(&mut self) -> &mut Box<dyn SerialPort>;
302
303    /// 获取基础配置的引用
304    fn base(&self) -> &SifliToolBase;
305
306    /// 获取进度助手
307    fn progress(&mut self) -> Arc<ProgressHelper> {
308        // 使用共享的进度助手,它会自动处理步骤计数
309        self.base().progress_helper.clone()
310    }
311
312    fn check_cancelled(&self) -> Result<()> {
313        self.base().check_cancelled()
314    }
315
316    fn set_speed(&mut self, baud: u32) -> Result<()>;
317    fn soft_reset(&mut self) -> Result<()>;
318}
319
320pub trait SifliTool:
321    SifliToolTrait + WriteFlashTrait + ReadFlashTrait + EraseFlashTrait + Send + Sync
322{
323    /// 工厂函数,根据芯片类型创建对应的 SifliTool 实现
324    fn create_tool(base_param: SifliToolBase) -> Box<dyn SifliTool>
325    where
326        Self: Sized;
327}
328
329/// 工厂函数,根据芯片类型创建对应的 SifliTool 实现
330pub fn create_sifli_tool(chip_type: ChipType, base_param: SifliToolBase) -> Box<dyn SifliTool> {
331    match chip_type {
332        ChipType::SF32LB52 => sf32lb52::SF32LB52Tool::create_tool(base_param),
333        ChipType::SF32LB55 => sf32lb55::SF32LB55Tool::create_tool(base_param),
334        ChipType::SF32LB56 => sf32lb56::SF32LB56Tool::create_tool(base_param),
335        ChipType::SF32LB57 => sf32lb57::SF32LB57Tool::create_tool(base_param),
336        ChipType::SF32LB58 => sf32lb58::SF32LB58Tool::create_tool(base_param),
337    }
338}