sftool_lib/common/
read_flash.rs

1use 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/// 通用的Flash读取文件结构
9#[derive(Debug)]
10pub struct ReadFlashFile {
11    pub file_path: String,
12    pub address: u32,
13    pub size: u32,
14}
15
16/// 通用的Flash读取操作实现
17pub struct FlashReader;
18
19impl FlashReader {
20    /// 解析读取文件信息 (filename@address:size格式)
21    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    /// 从Flash读取数据的通用实现
48    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        // 创建临时文件
62        let mut temp_file = tempfile()?;
63        let packet_size = 128 * 1024; // 128KB chunks
64        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            // 发送读取命令
71            let _ = tool.command(Command::Read {
72                address: current_address,
73                len: chunk_size,
74            });
75
76            // 读取数据
77            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                        // 超时检查
93                        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            // 写入临时文件
105            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        // 将临时文件内容写入目标文件
116        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}