1use crate::Error;
2use probe_rs::{config::MemoryRegion, Core, MemoryInterface};
3use scroll::{Pread, LE};
4use std::cmp::min;
5
6pub trait RttChannel {
8 fn number(&self) -> usize;
10
11 fn name(&self) -> Option<&str>;
13
14 fn buffer_size(&self) -> usize;
17}
18
19#[derive(Debug)]
20pub(crate) struct Channel {
21 number: usize,
22 core_id: usize,
23 ptr: u32,
24 name: Option<String>,
25 buffer_ptr: u32,
26 size: u32,
27}
28
29impl Channel {
43 pub(crate) const SIZE: usize = 24;
45
46 const O_NAME: usize = 0;
48 const O_BUFFER_PTR: usize = 4;
49 const O_SIZE: usize = 8;
50 const O_WRITE: usize = 12;
51 const O_READ: usize = 16;
52 const O_FLAGS: usize = 20;
53
54 pub(crate) fn from(
55 core: &mut Core,
56 number: usize,
57 memory_map: &[MemoryRegion],
58 ptr: u32,
59 mem: &[u8],
60 ) -> Result<Option<Channel>, Error> {
61 let buffer_ptr: u32 = match mem.pread_with(Self::O_BUFFER_PTR, LE) {
62 Ok(buffer_ptr) => buffer_ptr,
63 Err(_error) => return Err(Error::MemoryRead("RTT channel address".to_string())),
64 };
65
66 if buffer_ptr == 0 {
67 return Ok(None);
69 }
70
71 let name_ptr: u32 = match mem.pread_with(Self::O_NAME, LE) {
72 Ok(name_ptr) => name_ptr,
73 Err(_error) => return Err(Error::MemoryRead("RTT channel name".to_string())),
74 };
75
76 let name = if name_ptr == 0 {
77 None
78 } else {
79 read_c_string(core, memory_map, name_ptr)?
80 };
81
82 Ok(Some(Channel {
83 number,
84 core_id: core.id(),
85 ptr,
86 name,
87 buffer_ptr,
88 size: mem.pread_with(Self::O_SIZE, LE).unwrap(),
89 }))
90 }
91
92 pub(crate) fn validate_core_id(&self, core: &mut Core) -> Result<(), Error> {
94 if core.id() == self.core_id {
95 Ok(())
96 } else {
97 Err(Error::IncorrectCoreSpecified(self.core_id, core.id()))
98 }
99 }
100
101 pub fn name(&self) -> Option<&str> {
102 self.name.as_ref().map(|s| s.as_ref())
103 }
104
105 pub fn buffer_size(&self) -> usize {
106 self.size as usize
107 }
108
109 fn read_pointers(&self, core: &mut Core, dir: &'static str) -> Result<(u32, u32), Error> {
110 self.validate_core_id(core)?;
111 let mut block = [0u32; 2];
112 core.read_32((self.ptr + Self::O_WRITE as u32).into(), block.as_mut())?;
113
114 let write: u32 = block[0];
115 let read: u32 = block[1];
116
117 let validate = |which, value| {
118 if value >= self.size {
119 Err(Error::ControlBlockCorrupted(format!(
120 "{} pointer is {} while buffer size is {} for {:?} channel {} ({})",
121 which,
122 value,
123 self.size,
124 dir,
125 self.number,
126 self.name().unwrap_or("no name"),
127 )))
128 } else {
129 Ok(())
130 }
131 };
132
133 validate("write", write)?;
134 validate("read", read)?;
135
136 Ok((write, read))
137 }
138}
139
140#[derive(Debug)]
142pub struct UpChannel(pub(crate) Channel);
143
144impl UpChannel {
145 pub fn number(&self) -> usize {
147 self.0.number
148 }
149
150 pub fn name(&self) -> Option<&str> {
152 self.0.name()
153 }
154
155 pub fn buffer_size(&self) -> usize {
158 self.0.buffer_size()
159 }
160
161 pub fn mode(&self, core: &mut Core) -> Result<ChannelMode, Error> {
165 self.0.validate_core_id(core)?;
166
167 let flags = core.read_word_32((self.0.ptr + Channel::O_FLAGS as u32).into())?;
168
169 match flags & 0x3 {
170 0 => Ok(ChannelMode::NoBlockSkip),
171 1 => Ok(ChannelMode::NoBlockTrim),
172 2 => Ok(ChannelMode::BlockIfFull),
173 _ => Err(Error::ControlBlockCorrupted(String::from(
174 "The channel mode flags are invalid",
175 ))),
176 }
177 }
178
179 pub fn set_mode(&self, core: &mut Core, mode: ChannelMode) -> Result<(), Error> {
183 self.0.validate_core_id(core)?;
184 let flags = core.read_word_32((self.0.ptr + Channel::O_FLAGS as u32).into())?;
185
186 let new_flags = (flags & !3) | (mode as u32);
187 core.write_word_32((self.0.ptr + Channel::O_FLAGS as u32).into(), new_flags)?;
188
189 Ok(())
190 }
191
192 fn read_core(&self, core: &mut Core, mut buf: &mut [u8]) -> Result<(u32, usize), Error> {
193 self.0.validate_core_id(core)?;
194 let (write, mut read) = self.0.read_pointers(core, "up")?;
195
196 let mut total = 0;
197
198 while !buf.is_empty() {
200 let count = min(self.readable_contiguous(write, read), buf.len());
201 if count == 0 {
202 break;
203 }
204
205 core.read((self.0.buffer_ptr + read).into(), &mut buf[..count])?;
206
207 total += count;
208 read += count as u32;
209
210 if read >= self.0.size {
211 read = 0;
213 }
214
215 buf = &mut buf[count..];
216 }
217
218 Ok((read, total))
219 }
220
221 pub fn read(&self, core: &mut Core, buf: &mut [u8]) -> Result<usize, Error> {
227 self.0.validate_core_id(core)?;
228 let (read, total) = self.read_core(core, buf)?;
229
230 if total > 0 {
231 core.write_word_32((self.0.ptr + Channel::O_READ as u32).into(), read)?;
233 }
234
235 Ok(total)
236 }
237
238 pub fn peek(&self, core: &mut Core, buf: &mut [u8]) -> Result<usize, Error> {
244 self.0.validate_core_id(core)?;
245 Ok(self.read_core(core, buf)?.1)
246 }
247
248 fn readable_contiguous(&self, write: u32, read: u32) -> usize {
250 (if read > write {
251 self.0.size - read
252 } else {
253 write - read
254 }) as usize
255 }
256}
257
258impl RttChannel for UpChannel {
259 fn number(&self) -> usize {
261 self.0.number
262 }
263
264 fn name(&self) -> Option<&str> {
265 self.0.name()
266 }
267 fn buffer_size(&self) -> usize {
268 self.0.buffer_size()
269 }
270}
271
272#[derive(Debug)]
274pub struct DownChannel(pub(crate) Channel);
275
276impl DownChannel {
277 pub fn number(&self) -> usize {
279 self.0.number
280 }
281
282 pub fn name(&self) -> Option<&str> {
284 self.0.name()
285 }
286
287 pub fn buffer_size(&self) -> usize {
290 self.0.buffer_size()
291 }
292
293 pub fn write(&self, core: &mut Core, mut buf: &[u8]) -> Result<usize, Error> {
298 self.0.validate_core_id(core)?;
299 let (mut write, read) = self.0.read_pointers(core, "down")?;
300
301 if self.writable_contiguous(write, read) == 0 {
302 return Ok(0);
304 }
305
306 let mut total = 0;
307
308 while !buf.is_empty() {
310 let count = min(self.writable_contiguous(write, read), buf.len());
311 if count == 0 {
312 break;
313 }
314
315 core.write_8((self.0.buffer_ptr + write).into(), &buf[..count])?;
316
317 total += count;
318 write += count as u32;
319
320 if write >= self.0.size {
321 write = 0;
323 }
324
325 buf = &buf[count..];
326 }
327
328 core.write_word_32((self.0.ptr + Channel::O_WRITE as u32).into(), write)?;
330
331 Ok(total)
332 }
333
334 fn writable_contiguous(&self, write: u32, read: u32) -> usize {
336 (if read > write {
337 read - write - 1
338 } else if read == 0 {
339 self.0.size - write - 1
340 } else {
341 self.0.size - write
342 }) as usize
343 }
344}
345
346impl RttChannel for DownChannel {
347 fn number(&self) -> usize {
349 self.0.number
350 }
351
352 fn name(&self) -> Option<&str> {
353 self.0.name()
354 }
355 fn buffer_size(&self) -> usize {
356 self.0.buffer_size()
357 }
358}
359
360fn read_c_string(
362 core: &mut Core,
363 memory_map: &[MemoryRegion],
364 ptr: u32,
365) -> Result<Option<String>, Error> {
366 let range = memory_map
368 .iter()
369 .filter_map(|r| match r {
370 MemoryRegion::Nvm(r) => Some(&r.range),
371 MemoryRegion::Ram(r) => Some(&r.range),
372 _ => None,
373 })
374 .find(|r| r.contains(&(ptr as u64)));
375
376 let range = match range {
378 Some(r) => r,
379 None => return Ok(None),
380 };
381
382 let mut bytes = vec![0u8; min(128, (range.end - ptr as u64) as usize)];
384 core.read(ptr.into(), bytes.as_mut())?;
385
386 let return_value = bytes
387 .iter()
388 .position(|&b| b == 0)
389 .map(|p| String::from_utf8_lossy(&bytes[..p]).into_owned());
390 tracing::debug!(
391 "probe-rs-rtt::Channel::read_c_string() result = {:?}",
392 return_value
393 );
394 Ok(return_value)
396}
397
398#[derive(Clone, Copy, Eq, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
401#[repr(u32)]
402pub enum ChannelMode {
403 NoBlockSkip = 0,
405
406 NoBlockTrim = 1,
408
409 BlockIfFull = 2,
413}