sftool_lib/common/
write_flash.rs

1use crate::SifliToolTrait;
2use crate::WriteFlashFile;
3use crate::common::ram_command::{Command, RamCommand, Response};
4use std::io::{BufReader, Read, Write};
5
6/// 通用的Flash写入操作实现
7pub struct FlashWriter;
8
9impl FlashWriter {
10    /// 擦除所有Flash区域
11    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            // 如果ERASE_ADDRESS中的地址已经被擦除过,则跳过
25            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    /// 验证数据
37    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    /// 写入单个文件到Flash(非全擦除模式)
57    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        // verify
123        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    /// 写入单个文件到Flash(全擦除模式)
136    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        // verify
183        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}