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 sf32lb58;
23
24pub 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
64pub 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 pub external_stub_path: Option<String>,
143}
144
145impl SifliToolBase {
146 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 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 #[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 fn port(&mut self) -> &mut Box<dyn SerialPort>;
298
299 fn base(&self) -> &SifliToolBase;
301
302 fn progress(&mut self) -> Arc<ProgressHelper> {
304 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 fn create_tool(base_param: SifliToolBase) -> Box<dyn SifliTool>
321 where
322 Self: Sized;
323}
324
325pub 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}