sftool_lib/common/
erase_flash.rs1use crate::common::ram_command::{Command, RamCommand};
2use crate::progress::{EraseFlashStyle, EraseRegionStyle, ProgressOperation, ProgressStatus};
3use crate::utils::Utils;
4use crate::{Error, Result, SifliToolTrait};
5
6pub struct EraseOps;
8
9impl EraseOps {
10 pub fn erase_all<T>(tool: &mut T, address: u32) -> Result<()>
12 where
13 T: SifliToolTrait + RamCommand,
14 {
15 let progress = tool.progress();
16 let progress_bar = progress.create_spinner(ProgressOperation::EraseFlash {
17 address,
18 style: EraseFlashStyle::Complete,
19 });
20
21 let _ = tool.command(Command::EraseAll { address });
23
24 let mut buffer = Vec::new();
25 let now = std::time::SystemTime::now();
26
27 loop {
29 let elapsed = now.elapsed().unwrap().as_millis();
30 if elapsed > 30000 {
31 return Err(Error::timeout(format!(
32 "erasing flash at 0x{:08X}",
33 address
34 )));
35 }
36
37 let mut byte = [0];
38 let ret = tool.port().read_exact(&mut byte);
39 if ret.is_err() {
40 continue;
41 }
42 buffer.push(byte[0]);
43
44 if buffer.windows(2).any(|window| window == b"OK") {
45 break;
46 }
47 }
48
49 progress_bar.finish(ProgressStatus::Success);
50
51 Ok(())
52 }
53
54 pub fn erase_region<T>(tool: &mut T, address: u32, len: u32) -> Result<()>
56 where
57 T: SifliToolTrait + RamCommand,
58 {
59 let progress = tool.progress();
60 let progress_bar = progress.create_spinner(ProgressOperation::EraseRegion {
61 address,
62 len,
63 style: EraseRegionStyle::Range,
64 });
65
66 let _ = tool.command(Command::Erase { address, len });
68
69 let mut buffer = Vec::new();
70 let now = std::time::SystemTime::now();
71
72 loop {
74 let elapsed = now.elapsed().unwrap().as_millis();
75 if elapsed > 30000 {
76 return Err(Error::timeout(format!(
77 "erasing region 0x{:08X}..0x{:08X}",
78 address,
79 address + len.saturating_sub(1)
80 )));
81 }
82
83 let mut byte = [0];
84 let ret = tool.port().read_exact(&mut byte);
85 if ret.is_err() {
86 continue;
87 }
88 buffer.push(byte[0]);
89
90 if buffer.windows(2).any(|window| window == b"OK") {
91 break;
92 }
93 }
94
95 progress_bar.finish(ProgressStatus::Success);
96
97 Ok(())
98 }
99
100 pub fn parse_address(address_str: &str) -> Result<u32> {
102 Utils::str_to_u32(address_str)
103 .map_err(|e| Error::invalid_input(format!("Invalid address '{}': {}", address_str, e)))
104 }
105
106 pub fn parse_region(region_spec: &str) -> Result<(u32, u32)> {
108 let Some((addr_str, size_str)) = region_spec.split_once(':') else {
109 return Err(Error::invalid_input(format!(
110 "Invalid region format: {}. Expected: address:size",
111 region_spec
112 )));
113 };
114
115 let address = Utils::str_to_u32(addr_str)
116 .map_err(|e| Error::invalid_input(format!("Invalid address '{}': {}", addr_str, e)))?;
117 let len = Utils::str_to_u32(size_str)
118 .map_err(|e| Error::invalid_input(format!("Invalid size '{}': {}", size_str, e)))?;
119
120 Ok((address, len))
121 }
122}