probe_rs/probe/sifliuart/
mod.rs

1//! SiFli UART Debug Probe, Only support SiFli chip.
2//! Refer to <https://webfile.lovemcu.cn/file/user%20manual/UM5201-SF32LB52x-%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8C%20V0p81.pdf#153> for specific communication formats
3
4mod arm;
5
6use crate::Error;
7use crate::architecture::arm::sequences::ArmDebugSequence;
8use crate::architecture::arm::{ArmDebugInterface, ArmError};
9use crate::probe::sifliuart::arm::SifliUartArmDebug;
10use crate::probe::{
11    DebugProbe, DebugProbeError, DebugProbeInfo, DebugProbeSelector, ProbeCreationError,
12    ProbeFactory, WireProtocol,
13};
14use serialport::{SerialPort, SerialPortType, available_ports};
15use std::io::{BufReader, BufWriter, Read, Write};
16use std::sync::Arc;
17use std::time::{Duration, Instant};
18use std::{env, fmt};
19
20const START_WORD: [u8; 2] = [0x7E, 0x79];
21
22const DEFUALT_RECV_TIMEOUT: Duration = Duration::from_secs(3);
23
24const DEFUALT_UART_BAUD: u32 = 1000000;
25
26#[derive(Debug)]
27pub(crate) enum SifliUartCommand<'a> {
28    Enter,
29    Exit,
30    MEMRead { addr: u32, len: u16 },
31    MEMWrite { addr: u32, data: &'a [u32] },
32}
33
34enum SifliUartResponse {
35    Enter,
36    Exit,
37    MEMRead { data: Vec<u8> },
38    MEMWrite,
39}
40
41impl fmt::Display for SifliUartCommand<'_> {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            SifliUartCommand::Enter => write!(f, "Enter"),
45            SifliUartCommand::Exit => write!(f, "Exit"),
46            SifliUartCommand::MEMRead { addr, len } => {
47                write!(f, "MEMRead {{ addr: {addr:#X}, len: {len:#X} }}")
48            }
49            SifliUartCommand::MEMWrite { addr, data } => {
50                write!(f, "MEMWrite {{ addr: {addr:#X}, data: [")?;
51                for (i, d) in data.iter().enumerate() {
52                    if i > 0 {
53                        write!(f, ", ")?;
54                    }
55                    write!(f, "{d:#X}")?;
56                }
57                write!(f, "] }}")
58            }
59        }
60    }
61}
62
63impl fmt::Display for SifliUartResponse {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        match self {
66            SifliUartResponse::Enter => write!(f, "Enter"),
67            SifliUartResponse::Exit => write!(f, "Exit"),
68            SifliUartResponse::MEMRead { data } => {
69                write!(f, "MEMRead {{ data: [")?;
70                for (i, byte) in data.iter().enumerate() {
71                    if i > 0 {
72                        write!(f, ", ")?;
73                    }
74                    write!(f, "{byte:#04X}")?;
75                }
76                write!(f, "] }}")
77            }
78            SifliUartResponse::MEMWrite => write!(f, "MEMWrite"),
79        }
80    }
81}
82
83#[derive(Debug, thiserror::Error)]
84enum CommandError {
85    ParameterError(std::io::Error),
86    // Error(u64),
87    // Unsupported(u64),
88    ProbeError(std::io::Error),
89    // UnsupportedVersion(u64),
90}
91
92impl fmt::Display for CommandError {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        match self {
95            CommandError::ParameterError(e) => write!(f, "ParameterError({e})"),
96            // CommandError::Error(e) => write!(f, "Error({})", e),
97            // CommandError::Unsupported(e) => write!(f, "Unsupported({})", e),
98            CommandError::ProbeError(e) => write!(f, "ProbeError({e})"),
99            // CommandError::UnsupportedVersion(e) => write!(f, "UnsupportedVersion({})", e),
100        }
101    }
102}
103
104/// SiFli UART Debug Probe, Only support SiFli chip.
105pub struct SifliUart {
106    reader: BufReader<Box<dyn Read + Send>>,
107    writer: BufWriter<Box<dyn Write + Send>>,
108    _serial_port: Box<dyn SerialPort>,
109    baud: u32,
110}
111
112impl fmt::Debug for SifliUart {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        f.debug_struct("SifliUart")
115            .field("baud", &self.baud)
116            .finish()
117    }
118}
119
120impl fmt::Display for SifliUart {
121    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
122        write!(f, "Sifli UART Debug Probe")
123    }
124}
125
126impl SifliUart {
127    /// Create a new SiFli UART Debug Probe.
128    pub fn new(
129        reader: Box<dyn Read + Send>,
130        writer: Box<dyn Write + Send>,
131        port: Box<dyn SerialPort>,
132    ) -> Result<Self, DebugProbeError> {
133        let reader = BufReader::new(reader);
134        let writer = BufWriter::new(writer);
135
136        let probe = SifliUart {
137            reader,
138            writer,
139            baud: DEFUALT_UART_BAUD,
140            _serial_port: port,
141        };
142        Ok(probe)
143    }
144
145    fn create_header(len: u16) -> Vec<u8> {
146        let mut header = vec![];
147        header.extend_from_slice(&START_WORD);
148        header.extend_from_slice(&len.to_le_bytes());
149        header.push(0x10);
150        header.push(0x00);
151        header
152    }
153
154    fn send(
155        writer: &mut BufWriter<Box<dyn Write + Send>>,
156        command: &SifliUartCommand,
157    ) -> Result<(), CommandError> {
158        let mut send_data = vec![];
159        match command {
160            SifliUartCommand::Enter => {
161                let temp = [0x41, 0x54, 0x53, 0x46, 0x33, 0x32, 0x05, 0x21];
162                send_data.extend_from_slice(&temp);
163            }
164            SifliUartCommand::Exit => {
165                let temp = [0x41, 0x54, 0x53, 0x46, 0x33, 0x32, 0x18, 0x21];
166                send_data.extend_from_slice(&temp);
167            }
168            SifliUartCommand::MEMRead { addr, len } => {
169                send_data.push(0x40);
170                send_data.push(0x72);
171                send_data.extend_from_slice(&addr.to_le_bytes());
172                send_data.extend_from_slice(&len.to_le_bytes());
173            }
174            SifliUartCommand::MEMWrite { addr, data } => {
175                send_data.push(0x40);
176                send_data.push(0x77);
177                send_data.extend_from_slice(&addr.to_le_bytes());
178                send_data.extend_from_slice(&(data.len() as u16).to_le_bytes());
179                for d in data.iter() {
180                    send_data.extend_from_slice(&d.to_le_bytes());
181                }
182            }
183        }
184
185        let header = Self::create_header(send_data.len() as u16);
186        writer
187            .write_all(&header)
188            .map_err(CommandError::ProbeError)?;
189        writer
190            .write_all(&send_data)
191            .map_err(CommandError::ProbeError)?;
192        writer.flush().map_err(CommandError::ProbeError)?;
193
194        Ok(())
195    }
196
197    fn recv(
198        reader: &mut BufReader<Box<dyn Read + Send>>,
199    ) -> Result<SifliUartResponse, CommandError> {
200        let start_time = Instant::now();
201        let mut buffer = vec![];
202        let mut recv_data = vec![];
203
204        loop {
205            if start_time.elapsed() >= DEFUALT_RECV_TIMEOUT {
206                return Err(CommandError::ParameterError(std::io::Error::new(
207                    std::io::ErrorKind::TimedOut,
208                    "Timeout",
209                )));
210            }
211
212            let mut byte = [0; 1];
213            if reader.read_exact(&mut byte).is_err() {
214                continue;
215            }
216
217            if (byte[0] == START_WORD[0]) || (buffer.len() == 1 && byte[0] == START_WORD[1]) {
218                buffer.push(byte[0]);
219            } else {
220                buffer.clear();
221            }
222            tracing::info!("Recv buffer: {:?}", buffer);
223
224            if buffer.ends_with(&START_WORD) {
225                let err = Err(CommandError::ParameterError(std::io::Error::new(
226                    std::io::ErrorKind::InvalidData,
227                    "Invalid frame size",
228                )));
229                recv_data.clear();
230                // Header Length
231                let mut temp = [0; 2];
232                if reader.read_exact(&mut temp).is_err() {
233                    return err;
234                }
235                let size = u16::from_le_bytes(temp);
236                tracing::info!("Recv size: {}", size);
237
238                // Header channel and crc
239                if reader.read_exact(&mut temp).is_err() {
240                    return err;
241                }
242
243                while recv_data.len() < size as usize {
244                    if reader.read_exact(&mut byte).is_err() {
245                        return err;
246                    }
247                    recv_data.push(byte[0]);
248                    tracing::info!("Recv data: {:?}", recv_data);
249                }
250                break;
251            } else if buffer.len() == 2 {
252                buffer.clear();
253            }
254        }
255
256        if recv_data[recv_data.len() - 1] != 0x06 {
257            return Err(CommandError::ParameterError(std::io::Error::new(
258                std::io::ErrorKind::InvalidData,
259                "Invalid end of frame",
260            )));
261        }
262
263        match recv_data[0] {
264            0xD1 => Ok(SifliUartResponse::Enter),
265            0xD0 => Ok(SifliUartResponse::Exit),
266            0xD2 => {
267                let data = recv_data[1..recv_data.len() - 1].to_vec();
268                Ok(SifliUartResponse::MEMRead { data })
269            }
270            0xD3 => Ok(SifliUartResponse::MEMWrite),
271            _ => Err(CommandError::ParameterError(std::io::Error::new(
272                std::io::ErrorKind::InvalidData,
273                "Invalid frame type",
274            ))),
275        }
276    }
277
278    fn command(&mut self, command: SifliUartCommand) -> Result<SifliUartResponse, CommandError> {
279        tracing::info!("Command: {}", command);
280        let ret = Self::send(&mut self.writer, &command);
281        if let Err(e) = ret {
282            tracing::error!("Command send error: {:?}", e);
283            return Err(e);
284        }
285
286        match command {
287            SifliUartCommand::Exit => Ok(SifliUartResponse::Exit),
288            _ => Self::recv(&mut self.reader),
289        }
290    }
291}
292
293impl DebugProbe for SifliUart {
294    fn get_name(&self) -> &str {
295        "Sifli UART Debug Probe"
296    }
297
298    fn speed_khz(&self) -> u32 {
299        self.baud / 1000
300    }
301
302    fn set_speed(&mut self, speed_khz: u32) -> Result<u32, DebugProbeError> {
303        self.baud = speed_khz * 1000;
304
305        Ok(speed_khz)
306    }
307
308    fn attach(&mut self) -> Result<(), DebugProbeError> {
309        let ret = self.command(SifliUartCommand::Enter);
310        if let Err(e) = ret {
311            tracing::error!("Enter command error: {:?}", e);
312            return Err(DebugProbeError::NotAttached);
313        }
314        Ok(())
315    }
316
317    fn detach(&mut self) -> Result<(), Error> {
318        let ret = self.command(SifliUartCommand::Exit);
319        if let Err(e) = ret {
320            tracing::error!("Exit command error: {:?}", e);
321            return Err(Error::from(DebugProbeError::Other(
322                "Exit command error".to_string(),
323            )));
324        }
325        Ok(())
326    }
327
328    fn target_reset(&mut self) -> Result<(), DebugProbeError> {
329        todo!()
330    }
331
332    fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
333        todo!()
334    }
335
336    fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
337        todo!()
338    }
339
340    fn select_protocol(&mut self, protocol: WireProtocol) -> Result<(), DebugProbeError> {
341        match protocol {
342            WireProtocol::Swd => Ok(()),
343            _ => Err(DebugProbeError::UnsupportedProtocol(protocol)),
344        }
345    }
346
347    fn active_protocol(&self) -> Option<WireProtocol> {
348        Some(WireProtocol::Swd)
349    }
350
351    fn has_arm_interface(&self) -> bool {
352        true
353    }
354
355    fn try_get_arm_debug_interface<'probe>(
356        self: Box<Self>,
357        sequence: Arc<dyn ArmDebugSequence>,
358    ) -> Result<Box<dyn ArmDebugInterface + 'probe>, (Box<dyn DebugProbe>, ArmError)> {
359        Ok(Box::new(SifliUartArmDebug::new(self, sequence)))
360    }
361
362    fn into_probe(self: Box<Self>) -> Box<dyn DebugProbe> {
363        self
364    }
365}
366
367/// Factory for creating [`SifliUart`] probes.
368#[derive(Debug)]
369pub struct SifliUartFactory;
370
371impl SifliUartFactory {
372    fn is_sifli_uart(port_type: SerialPortType, port_name: &str) -> Option<DebugProbeInfo> {
373        // Only accept /dev/cu.* values on macos, to avoid having two
374        // copies of the port (both /dev/tty.* and /dev/cu.*)
375        if cfg!(target_os = "macos") && !port_name.contains("/cu.") {
376            return None;
377        }
378
379        let usb_info = match port_type {
380            SerialPortType::UsbPort(info) => info,
381            _ => return None,
382        };
383
384        if env::var("SIFLI_UART_DEBUG").is_err()
385            && (usb_info.product.is_none()
386                || !usb_info
387                    .product
388                    .as_ref()
389                    .unwrap()
390                    .to_lowercase()
391                    .contains("sifli"))
392        {
393            return None;
394        }
395
396        let vendor_id = usb_info.vid;
397        let product_id = usb_info.pid;
398        let serial_number = Some(port_name.to_string()); //We set serial_number to the serial device number to make it easier to specify the
399        let interface = usb_info.interface;
400        let identifier = "Sifli uart debug probe".to_string();
401
402        Some(DebugProbeInfo {
403            identifier,
404            vendor_id,
405            product_id,
406            serial_number,
407            probe_factory: &SifliUartFactory,
408            interface,
409            is_hid_interface: false,
410        })
411    }
412
413    fn open_port(&self, port_name: &str) -> Result<Box<dyn DebugProbe>, DebugProbeError> {
414        let mut port = serialport::new(port_name, DEFUALT_UART_BAUD)
415            .dtr_on_open(false)
416            .timeout(Duration::from_secs(3))
417            .open()
418            .map_err(|_| {
419                DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
420            })?;
421        port.write_data_terminal_ready(false).map_err(|_| {
422            DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
423        })?;
424        port.write_request_to_send(false).map_err(|_| {
425            DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
426        })?;
427
428        let reader = port.try_clone().map_err(|_| {
429            DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
430        })?;
431        let writer = reader.try_clone().map_err(|_| {
432            DebugProbeError::ProbeCouldNotBeCreated(ProbeCreationError::CouldNotOpen)
433        })?;
434
435        SifliUart::new(Box::new(reader), Box::new(writer), port)
436            .map(|probe| Box::new(probe) as Box<dyn DebugProbe>)
437    }
438}
439
440impl std::fmt::Display for SifliUartFactory {
441    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
442        f.write_str("SifliUart")
443    }
444}
445
446impl ProbeFactory for SifliUartFactory {
447    fn open(&self, selector: &DebugProbeSelector) -> Result<Box<dyn DebugProbe>, DebugProbeError> {
448        let Ok(ports) = available_ports() else {
449            return Err(DebugProbeError::ProbeCouldNotBeCreated(
450                ProbeCreationError::CouldNotOpen,
451            ));
452        };
453
454        if selector.serial_number.is_some() {
455            return self.open_port(selector.serial_number.as_ref().unwrap());
456        }
457
458        for port in ports {
459            let Some(_info) = SifliUartFactory::is_sifli_uart(port.port_type, &port.port_name)
460            else {
461                continue;
462            };
463
464            return self.open_port(&port.port_name);
465        }
466
467        Err(DebugProbeError::ProbeCouldNotBeCreated(
468            ProbeCreationError::NotFound,
469        ))
470    }
471
472    fn list_probes(&self) -> Vec<DebugProbeInfo> {
473        let mut probes = vec![];
474        let Ok(ports) = available_ports() else {
475            return probes;
476        };
477        for port in ports {
478            let Some(info) = SifliUartFactory::is_sifli_uart(port.port_type, &port.port_name)
479            else {
480                continue;
481            };
482            probes.push(info);
483        }
484        probes
485    }
486}