sftool_lib/common/
read_flash.rs1use crate::common::ram_command::{Command, RamCommand};
2use crate::utils::Utils;
3use crate::{Error, Result, SifliToolTrait};
4use std::fs::File;
5use std::io::{Read, Seek, Write};
6use tempfile::tempfile;
7
8#[derive(Debug)]
10pub struct ReadFlashFile {
11 pub file_path: String,
12 pub address: u32,
13 pub size: u32,
14}
15
16pub struct FlashReader;
18
19impl FlashReader {
20 pub fn parse_file_info(file_spec: &str) -> Result<ReadFlashFile> {
22 let Some((file_path, addr_size)) = file_spec.split_once('@') else {
23 return Err(Error::invalid_input(format!(
24 "Invalid format: {}. Expected: filename@address:size",
25 file_spec
26 )));
27 };
28 let Some((addr, size)) = addr_size.split_once(':') else {
29 return Err(Error::invalid_input(format!(
30 "Invalid format: {}. Expected: filename@address:size",
31 file_spec
32 )));
33 };
34
35 let address = Utils::str_to_u32(addr)
36 .map_err(|e| Error::invalid_input(format!("Invalid address '{}': {}", addr, e)))?;
37 let size = Utils::str_to_u32(size)
38 .map_err(|e| Error::invalid_input(format!("Invalid size '{}': {}", size, e)))?;
39
40 Ok(ReadFlashFile {
41 file_path: file_path.to_string(),
42 address,
43 size,
44 })
45 }
46
47 pub fn read_flash_data<T>(
49 tool: &mut T,
50 address: u32,
51 size: u32,
52 output_path: &str,
53 ) -> Result<()>
54 where
55 T: SifliToolTrait + RamCommand,
56 {
57 let progress = tool.progress();
58 let progress_bar =
59 progress.create_bar(size as u64, format!("Reading from 0x{:08X}...", address));
60
61 let mut temp_file = tempfile()?;
63 let packet_size = 128 * 1024; let mut remaining = size;
65 let mut current_address = address;
66
67 while remaining > 0 {
68 let chunk_size = std::cmp::min(remaining, packet_size);
69
70 let _ = tool.command(Command::Read {
72 address: current_address,
73 len: chunk_size,
74 });
75
76 let mut buffer = vec![0u8; chunk_size as usize];
78 let mut total_read = 0;
79 let start_time = std::time::SystemTime::now();
80
81 while total_read < chunk_size {
82 let remaining_in_chunk = chunk_size - total_read;
83 let mut chunk_buffer = vec![0u8; remaining_in_chunk as usize];
84
85 match tool.port().read_exact(&mut chunk_buffer) {
86 Ok(_) => {
87 buffer[total_read as usize..(total_read + remaining_in_chunk) as usize]
88 .copy_from_slice(&chunk_buffer);
89 total_read += remaining_in_chunk;
90 }
91 Err(_) => {
92 if start_time.elapsed().unwrap().as_millis() > 10000 {
94 return Err(Error::timeout(format!(
95 "reading flash at 0x{:08X}",
96 current_address
97 )));
98 }
99 continue;
100 }
101 }
102 }
103
104 temp_file.write_all(&buffer)?;
106
107 remaining -= chunk_size;
108 current_address += chunk_size;
109
110 progress_bar.inc(chunk_size as u64);
111 }
112
113 progress_bar.finish_with_message("Read complete");
114
115 temp_file.seek(std::io::SeekFrom::Start(0))?;
117 let mut output_file = File::create(output_path)?;
118 std::io::copy(&mut temp_file, &mut output_file)?;
119
120 Ok(())
121 }
122}