probe_rs/architecture/arm/swo/
mod.rs

1//! SWO tracing related functions.
2
3use std::time::Duration;
4
5use crate::architecture::arm::communication_interface::ArmDebugInterface;
6
7use super::ArmError;
8
9/// The protocol the SWO pin should use for data transmission.
10#[derive(Debug, Copy, Clone)]
11pub enum SwoMode {
12    /// UART
13    Uart,
14    /// Manchester
15    Manchester,
16}
17
18/// The config for the SWO pin.
19#[derive(Debug, Copy, Clone)]
20pub struct SwoConfig {
21    /// SWO mode: either UART or Manchester.
22    mode: SwoMode,
23
24    /// Baud rate of SWO, in Hz.
25    ///
26    /// This value is used to configure what baud rate the target
27    /// generates and to configure what baud rate the probe receives,
28    /// so must be a baud rate supported by both target and probe.
29    baud: u32,
30
31    /// Clock input to TPIU in Hz. This is often the system clock (HCLK/SYSCLK etc).
32    tpiu_clk: u32,
33
34    /// Whether to enable TPIU formatting.
35    /// This is required to use ETM over SWO, but otherwise
36    /// adds overhead if only DWT/ITM data is used.
37    tpiu_continuous_formatting: bool,
38}
39
40impl SwoConfig {
41    /// Create a new SwoConfig using the specified TPIU clock in Hz.
42    ///
43    /// By default the UART mode is used at 1MBd and
44    /// TPIU continuous formatting is disabled (DWT/ITM only).
45    pub fn new(tpiu_clk: u32) -> Self {
46        SwoConfig {
47            mode: SwoMode::Uart,
48            baud: 1_000_000,
49            tpiu_clk,
50            tpiu_continuous_formatting: false,
51        }
52    }
53
54    /// Set the baud rate in Hz.
55    pub fn set_baud(mut self, baud: u32) -> Self {
56        self.baud = baud;
57        self
58    }
59
60    /// Set the mode in this SwoConfig.
61    pub fn set_mode(mut self, mode: SwoMode) -> Self {
62        self.mode = mode;
63        self
64    }
65
66    /// Set the mode to UART
67    pub fn set_mode_uart(mut self) -> Self {
68        self.mode = SwoMode::Uart;
69        self
70    }
71
72    /// Set the mode to Manchester
73    pub fn set_mode_manchester(mut self) -> Self {
74        self.mode = SwoMode::Manchester;
75        self
76    }
77
78    /// Set the TPIU continuous formatting setting.
79    pub fn set_continuous_formatting(mut self, enabled: bool) -> Self {
80        self.tpiu_continuous_formatting = enabled;
81        self
82    }
83
84    /// The SWO mode.
85    pub fn mode(&self) -> SwoMode {
86        self.mode
87    }
88
89    /// Baud rate of SWO, in Hz.
90    ///
91    /// This value is used to configure what baud rate the target generates
92    /// and to configure what baud rate the probe receives,
93    /// so must be a baud rate supported by both target and probe.
94    pub fn baud(&self) -> u32 {
95        self.baud
96    }
97
98    /// Clock input to TPIU in Hz. This is often the system clock (HCLK/SYSCLK etc).
99    pub fn tpiu_clk(&self) -> u32 {
100        self.tpiu_clk
101    }
102
103    /// Whether to enable TPIU formatting. This is required to use ETM over
104    /// SWO, but otherwise adds overhead if only DWT/ITM data is used.
105    pub fn tpiu_continuous_formatting(&self) -> bool {
106        self.tpiu_continuous_formatting
107    }
108}
109
110/// An interface to operate SWO to be implemented on drivers that support SWO.
111pub trait SwoAccess {
112    /// Configure a SwoAccess interface for reading SWO data.
113    fn enable_swo(&mut self, config: &SwoConfig) -> Result<(), ArmError>;
114
115    /// Disable SWO reading on this SwoAccess interface.
116    fn disable_swo(&mut self) -> Result<(), ArmError>;
117
118    /// Read any available SWO data without waiting.
119    ///
120    /// Returns a `Vec<u8>` of received SWO bytes since the last `read_swo()` call.
121    /// If no data was available, returns an empty Vec.
122    fn read_swo(&mut self) -> Result<Vec<u8>, ArmError> {
123        self.read_swo_timeout(Duration::from_millis(10))
124    }
125
126    /// Read SWO data for up to `timeout` duration.
127    ///
128    /// If no data is received before the timeout, returns an empty Vec.
129    /// May return earlier than `timeout` if the receive buffer fills up.
130    fn read_swo_timeout(&mut self, timeout: Duration) -> Result<Vec<u8>, ArmError>;
131
132    /// Request an estimated best time to wait between polls of `read_swo`.
133    ///
134    /// A probe can implement this if it can work out a sensible time to
135    /// wait between polls, for example using the probe's internal buffer
136    /// size and SWO baud rate, or a 0s duration if reads can block for
137    /// new data.
138    ///
139    /// The default implementation computes an estimated interval based on the buffer
140    /// size, mode, and baud rate.
141    fn swo_poll_interval_hint(&mut self, config: &SwoConfig) -> Option<Duration> {
142        match self.swo_buffer_size() {
143            Some(size) => poll_interval_from_buf_size(config, size),
144            None => None,
145        }
146    }
147
148    /// Request the probe SWO buffer size, if known.
149    fn swo_buffer_size(&mut self) -> Option<usize> {
150        None
151    }
152}
153
154/// Helper function to compute a poll interval from a SwoConfig and SWO buffer size.
155pub(crate) fn poll_interval_from_buf_size(config: &SwoConfig, buf_size: usize) -> Option<Duration> {
156    let time_to_full_ms = match config.mode() {
157        // In UART, the output data is at the baud rate with 10 clocks per byte.
158        SwoMode::Uart => (1000 * buf_size as u32) / (config.baud() / 10),
159
160        // In Manchester, the output data is at half the baud rate with
161        // between 8.25 and 10 clocks per byte, so use a conservative 8 clocks/byte.
162        SwoMode::Manchester => (500 * buf_size as u32) / (config.baud() / 8),
163    };
164
165    // Poll frequently enough to catch the buffer at 1/4 full
166    Some(Duration::from_millis(time_to_full_ms as u64 / 4))
167}
168
169/// A reader interface to pull SWO data from the underlying driver.
170pub struct SwoReader<'a> {
171    interface: &'a mut dyn ArmDebugInterface,
172    buf: Vec<u8>,
173}
174
175impl<'a> SwoReader<'a> {
176    pub(crate) fn new(interface: &'a mut dyn ArmDebugInterface) -> Self {
177        Self {
178            interface,
179            buf: Vec::new(),
180        }
181    }
182}
183
184impl std::io::Read for SwoReader<'_> {
185    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
186        use std::{cmp, io::Error, mem};
187
188        // Always buffer: this pulls data as quickly as possible from
189        // the target to clear it's embedded trace buffer, minimizing
190        // the chance of an overflow event during which packets are
191        // lost.
192        self.buf
193            .append(&mut self.interface.read_swo().map_err(Error::other)?);
194
195        let swo = {
196            let next_buf = self.buf.split_off(cmp::min(self.buf.len(), buf.len()));
197            mem::replace(&mut self.buf, next_buf)
198        };
199
200        buf[..swo.len()].copy_from_slice(&swo);
201        Ok(swo.len())
202    }
203}