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