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