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