Skip to main content

sftool_lib/common/
write_flash.rs

1use crate::common::ram_command::{Command, RamCommand, Response};
2use crate::common::serial_io::for_tool;
3use crate::progress::{ProgressOperation, ProgressStatus};
4use crate::{Error, Result, SifliToolTrait, WriteFlashFile};
5use std::io::{BufReader, Read};
6
7/// 通用的Flash写入操作实现
8pub struct FlashWriter;
9
10impl FlashWriter {
11    /// 擦除所有Flash区域
12    pub fn erase_all<T>(tool: &mut T, write_flash_files: &[WriteFlashFile]) -> Result<()>
13    where
14        T: SifliToolTrait + RamCommand,
15    {
16        tool.check_cancelled()?;
17        let progress = tool.progress();
18        let spinner = progress.create_spinner(ProgressOperation::EraseAllRegions);
19
20        let mut erase_address: Vec<u32> = Vec::new();
21        for f in write_flash_files.iter() {
22            tool.check_cancelled()?;
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(ProgressStatus::Success);
33        Ok(())
34    }
35
36    /// 验证数据
37    pub fn verify<T>(tool: &mut T, address: u32, len: u32, crc: u32) -> Result<()>
38    where
39        T: SifliToolTrait + RamCommand,
40    {
41        tool.check_cancelled()?;
42        let progress = tool.progress();
43        let spinner = progress.create_spinner(ProgressOperation::Verify { address, len });
44
45        let response = tool.command(Command::Verify { address, len, crc })?;
46        if response != Response::Ok {
47            return Err(Error::protocol(format!(
48                "verify failed for 0x{:08X}..0x{:08X}",
49                address,
50                address + len.saturating_sub(1)
51            )));
52        }
53
54        spinner.finish(ProgressStatus::Success);
55        Ok(())
56    }
57
58    /// 写入单个文件到Flash(非全擦除模式)
59    pub fn write_file_incremental<T>(
60        tool: &mut T,
61        file: &WriteFlashFile,
62        verify: bool,
63    ) -> Result<()>
64    where
65        T: SifliToolTrait + RamCommand,
66    {
67        tool.check_cancelled()?;
68        let progress = tool.progress();
69        let re_download_spinner = progress.create_spinner(ProgressOperation::CheckRedownload {
70            address: file.address,
71            size: file.file.metadata()?.len(),
72        });
73
74        let response = tool.command(Command::Verify {
75            address: file.address,
76            len: file.file.metadata()?.len() as u32,
77            crc: file.crc32,
78        })?;
79
80        if response == Response::Ok {
81            re_download_spinner.finish(ProgressStatus::Skipped);
82            return Ok(());
83        }
84
85        re_download_spinner.finish(ProgressStatus::Required);
86
87        let download_bar = progress.create_bar(
88            file.file.metadata()?.len(),
89            ProgressOperation::WriteFlash {
90                address: file.address,
91                size: file.file.metadata()?.len(),
92            },
93        );
94
95        let res = tool.command(Command::WriteAndErase {
96            address: file.address,
97            len: file.file.metadata()?.len() as u32,
98        })?;
99        if res != Response::RxWait {
100            return Err(Error::protocol(format!(
101                "write flash failed to start at 0x{:08X}",
102                file.address
103            )));
104        }
105
106        let mut buffer = vec![0u8; 128 * 1024];
107        let mut reader = BufReader::new(&file.file);
108
109        loop {
110            tool.check_cancelled()?;
111            let bytes_read = reader.read(&mut buffer)?;
112            if bytes_read == 0 {
113                break;
114            }
115            tool.check_cancelled()?;
116            let res = tool.send_data(&buffer[..bytes_read])?;
117            if res == Response::RxWait {
118                download_bar.inc(bytes_read as u64);
119                continue;
120            } else if res != Response::Ok {
121                return Err(Error::protocol(format!(
122                    "write flash failed during transfer at 0x{:08X}",
123                    file.address
124                )));
125            }
126        }
127
128        download_bar.finish(ProgressStatus::Success);
129
130        // verify
131        if verify {
132            tool.check_cancelled()?;
133            Self::verify(
134                tool,
135                file.address,
136                file.file.metadata()?.len() as u32,
137                file.crc32,
138            )?;
139        }
140
141        Ok(())
142    }
143
144    /// 写入单个文件到Flash(全擦除模式)
145    pub fn write_file_full_erase<T>(
146        tool: &mut T,
147        file: &WriteFlashFile,
148        verify: bool,
149        packet_size: usize,
150    ) -> Result<()>
151    where
152        T: SifliToolTrait + RamCommand,
153    {
154        tool.check_cancelled()?;
155        let progress = tool.progress();
156        let download_bar = progress.create_bar(
157            file.file.metadata()?.len(),
158            ProgressOperation::WriteFlash {
159                address: file.address,
160                size: file.file.metadata()?.len(),
161            },
162        );
163
164        let mut buffer = vec![0u8; packet_size];
165        let mut reader = BufReader::new(&file.file);
166
167        let mut address = file.address;
168        loop {
169            tool.check_cancelled()?;
170            let bytes_read = reader.read(&mut buffer)?;
171            if bytes_read == 0 {
172                break;
173            }
174            tool.check_cancelled()?;
175            {
176                let mut io = for_tool(tool);
177                io.write_all(
178                    Command::Write {
179                        address,
180                        len: bytes_read as u32,
181                    }
182                    .to_string()
183                    .as_bytes(),
184                )?;
185                io.flush()?;
186            }
187            let res = tool.send_data(&buffer[..bytes_read])?;
188            if res != Response::Ok {
189                return Err(Error::protocol(format!(
190                    "write flash failed during transfer at 0x{:08X}",
191                    address
192                )));
193            }
194            address += bytes_read as u32;
195            download_bar.inc(bytes_read as u64);
196        }
197
198        download_bar.finish(ProgressStatus::Success);
199
200        // verify
201        if verify {
202            tool.check_cancelled()?;
203            Self::verify(
204                tool,
205                file.address,
206                file.file.metadata()?.len() as u32,
207                file.crc32,
208            )?;
209        }
210
211        Ok(())
212    }
213}