sftool_lib/
ram_command.rs

1use crate::ram_stub::CHIP_FILE_NAME;
2use crate::sifli_debug::{SifliUartCommand, SifliUartResponse};
3use crate::{Operation, SifliTool, ram_stub};
4use indicatif::{ProgressBar, ProgressStyle};
5use probe_rs::MemoryMappedRegister;
6use probe_rs::architecture::arm::core::registers::cortex_m::{PC, SP};
7use std::cmp::PartialEq;
8use std::io::{Error, Write};
9use std::str::FromStr;
10use std::time::Duration;
11use strum::{Display, EnumString};
12
13#[derive(EnumString, Display, Debug, Clone, PartialEq, Eq)]
14pub enum Command {
15    #[strum(to_string = "burn_erase_all 0x{address:08x}\r")]
16    EraseAll { address: u32 },
17
18    #[strum(to_string = "burn_verify 0x{address:08x} 0x{len:08x} 0x{crc:08x}\r")]
19    Verify { address: u32, len: u32, crc: u32 },
20
21    #[strum(to_string = "burn_erase_write 0x{address:08x} 0x{len:08x}\r")]
22    WriteAndErase { address: u32, len: u32 },
23
24    #[strum(to_string = "burn_write 0x{address:08x} 0x{len:08x}\r")]
25    Write { address: u32, len: u32 },
26
27    #[strum(to_string = "burn_reset\r")]
28    SoftReset,
29
30    #[strum(to_string = "burn_speed {baud} {delay}\r")]
31    SetBaud { baud: u32, delay: u32 },
32}
33
34#[derive(EnumString, Display, Debug, Clone, PartialEq, Eq)]
35pub enum Response {
36    #[strum(serialize = "OK")]
37    Ok,
38    #[strum(serialize = "Fail")]
39    Fail,
40    #[strum(serialize = "RX_WAIT")]
41    RxWait,
42}
43
44const RESPONSE_STR_TABLE: [&str; 3] = ["OK", "Fail", "RX_WAIT"];
45
46pub trait RamCommand {
47    fn command(&mut self, cmd: Command) -> Result<Response, std::io::Error>;
48    fn send_data(&mut self, data: &[u8]) -> Result<Response, std::io::Error>;
49}
50
51const TIMEOUT: u128 = 4000; //ms
52
53impl RamCommand for SifliTool {
54    fn command(&mut self, cmd: Command) -> Result<Response, std::io::Error> {
55        self.port.write_all(cmd.to_string().as_bytes())?;
56        self.port.flush()?;
57        self.port.clear(serialport::ClearBuffer::All)?;
58
59        let timeout = match cmd {
60            Command::EraseAll { .. } => 30 * 1000,
61            _ => TIMEOUT,
62        };
63
64        if let Command::SetBaud { .. } = cmd {
65            return Ok(Response::Ok);
66        }
67
68        let mut buffer = Vec::new();
69        let now = std::time::SystemTime::now();
70        loop {
71            let elapsed = now.elapsed().unwrap().as_millis();
72            if elapsed > timeout {
73                return Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "Timeout"));
74            }
75
76            let mut byte = [0];
77            let ret = self.port.read_exact(&mut byte);
78            if ret.is_err() {
79                continue;
80            }
81            buffer.push(byte[0]);
82
83            for response_str in RESPONSE_STR_TABLE.iter() {
84                let response_bytes = response_str.as_bytes();
85                // 对比buffer和response_bytes,如果buffer中包含response_str,就认为接收完毕
86                // 不需要转成字符串,直接对比字节
87                let exists = buffer
88                    .windows(response_bytes.len())
89                    .any(|window| window == response_bytes);
90                if exists {
91                    return Response::from_str(response_str).map_err(|e| {
92                        std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
93                    });
94                }
95            }
96        }
97    }
98
99    fn send_data(&mut self, data: &[u8]) -> Result<Response, Error> {
100        if !self.base.compat {
101            self.port.write_all(data)?;
102            self.port.flush()?;
103        } else {
104            // 每次只发256字节
105            for chunk in data.chunks(256) {
106                self.port.write_all(chunk)?;
107                self.port.flush()?;
108                std::thread::sleep(std::time::Duration::from_millis(10));
109            }
110        }
111
112        let mut buffer = Vec::new();
113        let now = std::time::SystemTime::now();
114        loop {
115            let elapsed = now.elapsed().unwrap().as_millis();
116            if elapsed > TIMEOUT {
117                return Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "Timeout"));
118            }
119
120            let mut byte = [0];
121            let ret = self.port.read_exact(&mut byte);
122            if ret.is_err() {
123                continue;
124            }
125            buffer.push(byte[0]);
126
127            // 一旦buffer出现RESPONSE_STR_TABLE中的任意一个,不一定是结束字节,也可能是在buffer中间出现,就认为接收完毕
128            for response_str in RESPONSE_STR_TABLE.iter() {
129                let response_bytes = response_str.as_bytes();
130                let exists = buffer
131                    .windows(response_bytes.len())
132                    .any(|window| window == response_bytes);
133                if exists {
134                    return Response::from_str(response_str).map_err(|e| {
135                        std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
136                    });
137                }
138            }
139        }
140    }
141}
142
143pub trait DownloadStub {
144    fn download_stub(&mut self) -> Result<(), std::io::Error>;
145}
146
147impl SifliTool {
148    fn download_stub(&mut self) -> Result<(), std::io::Error> {
149        let spinner = ProgressBar::new_spinner();
150        if !self.base.quiet {
151            spinner.enable_steady_tick(std::time::Duration::from_millis(100));
152            spinner.set_style(ProgressStyle::with_template("[{prefix}] {spinner} {msg}").unwrap());
153            spinner.set_prefix(format!("0x{:02X}", self.step));
154            spinner.set_message("Download stub...");
155        }
156        self.step = self.step.wrapping_add(1);
157        
158        /// 1. reset and halt
159        ///    1.1. reset_catch_set
160        use probe_rs::architecture::arm::core::armv7m::Demcr;
161        let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
162        let mut demcr = Demcr(demcr);
163        demcr.set_vc_corereset(true);
164        self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
165        /// 1.2. reset_system
166        use probe_rs::architecture::arm::core::armv7m::Aircr;
167
168        let mut aircr = Aircr(0);
169        aircr.vectkey();
170        aircr.set_sysresetreq(true);
171        self.debug_write_word32(Aircr::get_mmio_address() as u32, aircr.into())?;
172
173        // 1.3. Re-enter debug mode
174        let _ = self.debug_command(SifliUartCommand::Enter)?;
175
176        // 1.4. halt
177        self.debug_halt()?;
178
179        // 1.5. reset_catch_clear
180        let demcr = self.debug_read_word32(Demcr::get_mmio_address() as u32)?;
181        let mut demcr = Demcr(demcr);
182        demcr.set_vc_corereset(false);
183        self.debug_write_word32(Demcr::get_mmio_address() as u32, demcr.into())?;
184
185        std::thread::sleep(std::time::Duration::from_millis(100));
186        // 2. Download stub
187        let stub = ram_stub::RamStubFile::get(
188            CHIP_FILE_NAME
189                .get(format!("{}_{}", self.base.chip, self.base.memory_type).as_str())
190                .expect("REASON"),
191        );
192        let Some(stub) = stub else {
193            if !self.base.quiet {
194                spinner.finish_with_message("No stub file found for the given chip and memory type");
195            }
196            return Err(std::io::Error::new(
197                std::io::ErrorKind::NotFound,
198                "No stub file found for the given chip and memory type",
199            ));
200        };
201
202        let packet_size = if self.base.compat { 256 } else { 64 * 1024 };
203
204        let mut addr = 0x2005_A000;
205        let mut data = &stub.data[..];
206        while !data.is_empty() {
207            let chunk = &data[..std::cmp::min(data.len(), packet_size)];
208            self.debug_write_memory(addr, chunk)?;
209            addr += chunk.len() as u32;
210            data = &data[chunk.len()..];
211        }
212
213        // 3. run ram stub
214        // 3.1. set SP and PC
215        let sp = u32::from_le_bytes(
216            stub.data[0..4]
217                .try_into()
218                .expect("slice with exactly 4 bytes"),
219        );
220        let pc = u32::from_le_bytes(
221            stub.data[4..8]
222                .try_into()
223                .expect("slice with exactly 4 bytes"),
224        );
225        self.debug_write_core_reg(PC.id, pc)?;
226        self.debug_write_core_reg(SP.id, sp)?;
227
228        // 3.2. run
229        self.debug_run()?;
230
231        if !self.base.quiet {
232            spinner.finish_with_message("Download stub success!");
233        }
234
235        Ok(())
236    }
237
238    fn attempt_connect(&mut self) -> Result<(), std::io::Error> {
239        let infinite_attempts = self.base.connect_attempts <= 0;
240        let mut remaining_attempts = if infinite_attempts {
241            None
242        } else {
243            Some(self.base.connect_attempts)
244        };
245        loop {
246            if self.base.before == Operation::DefaultReset {
247                // 使用RTS引脚复位
248                self.port.write_request_to_send(true)?;
249                std::thread::sleep(Duration::from_millis(100));
250                self.port.write_request_to_send(false)?;
251                std::thread::sleep(Duration::from_millis(100));
252            }
253            let value = match self.debug_command(SifliUartCommand::Enter) {
254                Ok(SifliUartResponse::Enter) => Ok(()),
255                _ => Err(std::io::Error::new(
256                    std::io::ErrorKind::Other,
257                    "Failed to enter debug mode",
258                )),
259            };
260            // 如果有限重试,检查是否还有机会
261            if let Some(ref mut attempts) = remaining_attempts {
262                if *attempts == 0 {
263                    break; // 超过最大重试次数则退出循环
264                }
265                *attempts -= 1;
266            }
267
268            let spinner = ProgressBar::new_spinner();
269            if !self.base.quiet {
270                spinner.enable_steady_tick(Duration::from_millis(100));
271                spinner
272                    .set_style(ProgressStyle::with_template("[{prefix}] {spinner} {msg}").unwrap());
273                spinner.set_prefix(format!("0x{:02X}", self.step));
274                self.step = self.step.wrapping_add(1);
275                spinner.set_message("Connecting to chip...");
276            }
277
278            // 尝试连接
279            match value {
280                Ok(_) => {
281                    if !self.base.quiet {
282                        spinner.finish_with_message("Connected success!");
283                    }
284                    return Ok(());
285                }
286                Err(_) => {
287                    if !self.base.quiet {
288                        spinner.finish_with_message("Failed to connect to the chip, retrying...");
289                    }
290                    std::thread::sleep(Duration::from_millis(500));
291                }
292            }
293        }
294        Err(std::io::Error::new(
295            std::io::ErrorKind::Other,
296            "Failed to connect to the chip",
297        ))
298    }
299}
300
301impl DownloadStub for SifliTool {
302    fn download_stub(&mut self) -> Result<(), std::io::Error> {
303        self.attempt_connect()?;
304        self.download_stub()?;
305
306        std::thread::sleep(std::time::Duration::from_millis(100));
307        self.port.clear(serialport::ClearBuffer::All)?;
308
309        // 1s之内串口发b"\r\n"字符串,并等待是否有"msh >"回复,200ms发一次b"\r\n"
310        let mut buffer = Vec::new();
311        let mut now = std::time::SystemTime::now();
312        const RETRY: u32 = 5;
313        let mut retry_count = 0;
314        self.port.write_all(b"\r\n")?;
315        self.port.flush()?;
316        loop {
317            let elapsed = now.elapsed().unwrap().as_millis();
318            if elapsed > 200 {
319                retry_count += 1;
320                now = std::time::SystemTime::now();
321                self.port.write_all(b"\r\n")?;
322                self.port.flush()?;
323                buffer.clear();
324            }
325            if retry_count > RETRY {
326                return Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "Timeout"));
327            }
328
329            let mut byte = [0];
330            let ret = self.port.read_exact(&mut byte);
331            if ret.is_err() {
332                continue;
333            }
334            buffer.push(byte[0]);
335
336            // 一旦buffer出现"msh >"字符串,就认为接收完毕
337            if buffer.windows(5).any(|window| window == b"msh >") {
338                break;
339            }
340        }
341        Ok(())
342    }
343}