sftool_lib/common/
write_flash.rs1use crate::common::ram_command::{Command, RamCommand, Response};
2use crate::common::serial_io::for_tool;
3use crate::progress::{ProgressOperation, ProgressStatus};
4use crate::{Error, Result, SifliToolTrait, WriteFlashFile};
5use std::io::{BufReader, Read};
6
7pub struct FlashWriter;
9
10impl FlashWriter {
11 pub fn erase_all<T>(tool: &mut T, write_flash_files: &[WriteFlashFile]) -> Result<()>
13 where
14 T: SifliToolTrait + RamCommand,
15 {
16 tool.check_cancelled()?;
17 let progress = tool.progress();
18 let spinner = progress.create_spinner(ProgressOperation::EraseAllRegions);
19
20 let mut erase_address: Vec<u32> = Vec::new();
21 for f in write_flash_files.iter() {
22 tool.check_cancelled()?;
23 let address = f.address & 0xFF00_0000;
24 if erase_address.contains(&address) {
26 continue;
27 }
28 tool.command(Command::EraseAll { address: f.address })?;
29 erase_address.push(address);
30 }
31
32 spinner.finish(ProgressStatus::Success);
33 Ok(())
34 }
35
36 pub fn verify<T>(tool: &mut T, address: u32, len: u32, crc: u32) -> Result<()>
38 where
39 T: SifliToolTrait + RamCommand,
40 {
41 tool.check_cancelled()?;
42 let progress = tool.progress();
43 let spinner = progress.create_spinner(ProgressOperation::Verify { address, len });
44
45 let response = tool.command(Command::Verify { address, len, crc })?;
46 if response != Response::Ok {
47 return Err(Error::protocol(format!(
48 "verify failed for 0x{:08X}..0x{:08X}",
49 address,
50 address + len.saturating_sub(1)
51 )));
52 }
53
54 spinner.finish(ProgressStatus::Success);
55 Ok(())
56 }
57
58 pub fn write_file_incremental<T>(
60 tool: &mut T,
61 file: &WriteFlashFile,
62 verify: bool,
63 ) -> Result<()>
64 where
65 T: SifliToolTrait + RamCommand,
66 {
67 tool.check_cancelled()?;
68 let progress = tool.progress();
69 let re_download_spinner = progress.create_spinner(ProgressOperation::CheckRedownload {
70 address: file.address,
71 size: file.file.metadata()?.len(),
72 });
73
74 let response = tool.command(Command::Verify {
75 address: file.address,
76 len: file.file.metadata()?.len() as u32,
77 crc: file.crc32,
78 })?;
79
80 if response == Response::Ok {
81 re_download_spinner.finish(ProgressStatus::Skipped);
82 return Ok(());
83 }
84
85 re_download_spinner.finish(ProgressStatus::Required);
86
87 let download_bar = progress.create_bar(
88 file.file.metadata()?.len(),
89 ProgressOperation::WriteFlash {
90 address: file.address,
91 size: file.file.metadata()?.len(),
92 },
93 );
94
95 let res = tool.command(Command::WriteAndErase {
96 address: file.address,
97 len: file.file.metadata()?.len() as u32,
98 })?;
99 if res != Response::RxWait {
100 return Err(Error::protocol(format!(
101 "write flash failed to start at 0x{:08X}",
102 file.address
103 )));
104 }
105
106 let mut buffer = vec![0u8; 128 * 1024];
107 let mut reader = BufReader::new(&file.file);
108
109 loop {
110 tool.check_cancelled()?;
111 let bytes_read = reader.read(&mut buffer)?;
112 if bytes_read == 0 {
113 break;
114 }
115 tool.check_cancelled()?;
116 let res = tool.send_data(&buffer[..bytes_read])?;
117 if res == Response::RxWait {
118 download_bar.inc(bytes_read as u64);
119 continue;
120 } else if res != Response::Ok {
121 return Err(Error::protocol(format!(
122 "write flash failed during transfer at 0x{:08X}",
123 file.address
124 )));
125 }
126 }
127
128 download_bar.finish(ProgressStatus::Success);
129
130 if verify {
132 tool.check_cancelled()?;
133 Self::verify(
134 tool,
135 file.address,
136 file.file.metadata()?.len() as u32,
137 file.crc32,
138 )?;
139 }
140
141 Ok(())
142 }
143
144 pub fn write_file_full_erase<T>(
146 tool: &mut T,
147 file: &WriteFlashFile,
148 verify: bool,
149 packet_size: usize,
150 ) -> Result<()>
151 where
152 T: SifliToolTrait + RamCommand,
153 {
154 tool.check_cancelled()?;
155 let progress = tool.progress();
156 let download_bar = progress.create_bar(
157 file.file.metadata()?.len(),
158 ProgressOperation::WriteFlash {
159 address: file.address,
160 size: file.file.metadata()?.len(),
161 },
162 );
163
164 let mut buffer = vec![0u8; packet_size];
165 let mut reader = BufReader::new(&file.file);
166
167 let mut address = file.address;
168 loop {
169 tool.check_cancelled()?;
170 let bytes_read = reader.read(&mut buffer)?;
171 if bytes_read == 0 {
172 break;
173 }
174 tool.check_cancelled()?;
175 {
176 let mut io = for_tool(tool);
177 io.write_all(
178 Command::Write {
179 address,
180 len: bytes_read as u32,
181 }
182 .to_string()
183 .as_bytes(),
184 )?;
185 io.flush()?;
186 }
187 let res = tool.send_data(&buffer[..bytes_read])?;
188 if res != Response::Ok {
189 return Err(Error::protocol(format!(
190 "write flash failed during transfer at 0x{:08X}",
191 address
192 )));
193 }
194 address += bytes_read as u32;
195 download_bar.inc(bytes_read as u64);
196 }
197
198 download_bar.finish(ProgressStatus::Success);
199
200 if verify {
202 tool.check_cancelled()?;
203 Self::verify(
204 tool,
205 file.address,
206 file.file.metadata()?.len() as u32,
207 file.crc32,
208 )?;
209 }
210
211 Ok(())
212 }
213}