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 download_bar.finish_with_message("Download success!");
121
122 if verify {
124 Self::verify(
125 tool,
126 file.address,
127 file.file.metadata()?.len() as u32,
128 file.crc32,
129 )?;
130 }
131
132 Ok(())
133 }
134
135 pub fn write_file_full_erase<T>(
137 tool: &mut T,
138 file: &WriteFlashFile,
139 verify: bool,
140 packet_size: usize,
141 ) -> Result<(), std::io::Error>
142 where
143 T: SifliToolTrait + RamCommand,
144 {
145 let progress = tool.progress();
146 let download_bar = progress.create_bar(
147 file.file.metadata()?.len(),
148 format!("Download at 0x{:08X}...", file.address),
149 );
150
151 let mut buffer = vec![0u8; packet_size];
152 let mut reader = BufReader::new(&file.file);
153
154 let mut address = file.address;
155 loop {
156 let bytes_read = reader.read(&mut buffer)?;
157 if bytes_read == 0 {
158 break;
159 }
160 tool.port().write_all(
161 Command::Write {
162 address: address,
163 len: bytes_read as u32,
164 }
165 .to_string()
166 .as_bytes(),
167 )?;
168 tool.port().flush()?;
169 let res = tool.send_data(&buffer[..bytes_read])?;
170 if res != Response::Ok {
171 return Err(std::io::Error::new(
172 std::io::ErrorKind::InvalidData,
173 "Write flash failed",
174 ));
175 }
176 address += bytes_read as u32;
177 download_bar.inc(bytes_read as u64);
178 }
179
180 download_bar.finish_with_message("Download success!");
181
182 if verify {
184 Self::verify(
185 tool,
186 file.address,
187 file.file.metadata()?.len() as u32,
188 file.crc32,
189 )?;
190 }
191
192 Ok(())
193 }
194}