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