sftool_lib/common/
write_flash.rs1use crate::common::ram_command::{Command, RamCommand, Response};
2use crate::progress::{ProgressOperation, ProgressStatus};
3use crate::{Error, Result, SifliToolTrait, WriteFlashFile};
4use std::io::{BufReader, Read, Write};
5
6pub struct FlashWriter;
8
9impl FlashWriter {
10 pub fn erase_all<T>(tool: &mut T, write_flash_files: &[WriteFlashFile]) -> Result<()>
12 where
13 T: SifliToolTrait + RamCommand,
14 {
15 let progress = tool.progress();
16 let spinner = progress.create_spinner(ProgressOperation::EraseAllRegions);
17
18 let mut erase_address: Vec<u32> = Vec::new();
19 for f in write_flash_files.iter() {
20 let address = f.address & 0xFF00_0000;
21 if erase_address.contains(&address) {
23 continue;
24 }
25 tool.command(Command::EraseAll { address: f.address })?;
26 erase_address.push(address);
27 }
28
29 spinner.finish(ProgressStatus::Success);
30 Ok(())
31 }
32
33 pub fn verify<T>(tool: &mut T, address: u32, len: u32, crc: u32) -> Result<()>
35 where
36 T: SifliToolTrait + RamCommand,
37 {
38 let progress = tool.progress();
39 let spinner = progress.create_spinner(ProgressOperation::Verify { address, len });
40
41 let response = tool.command(Command::Verify { address, len, crc })?;
42 if response != Response::Ok {
43 return Err(Error::protocol(format!(
44 "verify failed for 0x{:08X}..0x{:08X}",
45 address,
46 address + len.saturating_sub(1)
47 )));
48 }
49
50 spinner.finish(ProgressStatus::Success);
51 Ok(())
52 }
53
54 pub fn write_file_incremental<T>(
56 tool: &mut T,
57 file: &WriteFlashFile,
58 verify: bool,
59 ) -> Result<()>
60 where
61 T: SifliToolTrait + RamCommand,
62 {
63 let progress = tool.progress();
64 let re_download_spinner = progress.create_spinner(ProgressOperation::CheckRedownload {
65 address: file.address,
66 size: file.file.metadata()?.len(),
67 });
68
69 let response = tool.command(Command::Verify {
70 address: file.address,
71 len: file.file.metadata()?.len() as u32,
72 crc: file.crc32,
73 })?;
74
75 if response == Response::Ok {
76 re_download_spinner.finish(ProgressStatus::Skipped);
77 return Ok(());
78 }
79
80 re_download_spinner.finish(ProgressStatus::Required);
81
82 let download_bar = progress.create_bar(
83 file.file.metadata()?.len(),
84 ProgressOperation::WriteFlash {
85 address: file.address,
86 size: file.file.metadata()?.len(),
87 },
88 );
89
90 let res = tool.command(Command::WriteAndErase {
91 address: file.address,
92 len: file.file.metadata()?.len() as u32,
93 })?;
94 if res != Response::RxWait {
95 return Err(Error::protocol(format!(
96 "write flash failed to start at 0x{:08X}",
97 file.address
98 )));
99 }
100
101 let mut buffer = vec![0u8; 128 * 1024];
102 let mut reader = BufReader::new(&file.file);
103
104 loop {
105 let bytes_read = reader.read(&mut buffer)?;
106 if bytes_read == 0 {
107 break;
108 }
109 let res = tool.send_data(&buffer[..bytes_read])?;
110 if res == Response::RxWait {
111 download_bar.inc(bytes_read as u64);
112 continue;
113 } else if res != Response::Ok {
114 return Err(Error::protocol(format!(
115 "write flash failed during transfer at 0x{:08X}",
116 file.address
117 )));
118 }
119 }
120
121 download_bar.finish(ProgressStatus::Success);
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 ProgressOperation::WriteFlash {
150 address: file.address,
151 size: file.file.metadata()?.len(),
152 },
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,
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(Error::protocol(format!(
176 "write flash failed during transfer at 0x{:08X}",
177 address
178 )));
179 }
180 address += bytes_read as u32;
181 download_bar.inc(bytes_read as u64);
182 }
183
184 download_bar.finish(ProgressStatus::Success);
185
186 if verify {
188 Self::verify(
189 tool,
190 file.address,
191 file.file.metadata()?.len() as u32,
192 file.crc32,
193 )?;
194 }
195
196 Ok(())
197 }
198}