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
12pub mod progress;
14
15pub mod common;
17
18pub mod sf32lb52;
20pub mod sf32lb55;
21pub mod sf32lb56;
22pub mod sf32lb57;
23pub mod sf32lb58;
24
25pub 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
65pub 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 pub external_stub_path: Option<String>,
147}
148
149impl SifliToolBase {
150 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 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 #[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 fn port(&mut self) -> &mut Box<dyn SerialPort>;
302
303 fn base(&self) -> &SifliToolBase;
305
306 fn progress(&mut self) -> Arc<ProgressHelper> {
308 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 fn create_tool(base_param: SifliToolBase) -> Box<dyn SifliTool>
325 where
326 Self: Sized;
327}
328
329pub 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}