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