Use local patched jlink_rtt module
This commit is contained in:
parent
53f2596665
commit
963a1a2bbf
|
@ -22,7 +22,7 @@ default-target = "targets/aarch64-vesper-metta.json"
|
|||
unstable = []
|
||||
realtime = []
|
||||
noserial = []
|
||||
jlink = ['jlink_rtt']
|
||||
jlink = [] #'jlink_rtt'
|
||||
|
||||
#[lib]
|
||||
#name = "nucleus"
|
||||
|
@ -37,7 +37,7 @@ bitflags = "1.0.1"
|
|||
register = "0.3.2"
|
||||
cortex-a = "2.4"
|
||||
#embedded-serial = "0.5.0"
|
||||
jlink_rtt = { version = "0.1.0", optional = true }
|
||||
# jlink_rtt = { version = "0.1.0", optional = true }
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort" # @todo try panic_rtt when feature jlink
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
// Custom implementation of JLink RTT debug protocol
|
||||
// jlink_rtt crate has too many strange bugs
|
||||
|
||||
/// This module implements a limited version of the Segger
|
||||
/// Real Time Transfer protocol between the debugger host
|
||||
/// and the target program.
|
||||
/// RTT works by scanning memory to look for a control block
|
||||
/// containing a magic string (it is also possible to tell
|
||||
/// the monitor exactly where to find this block).
|
||||
/// The control block defines a set of "up" channels
|
||||
/// and "down" channels that are named pipes of communication
|
||||
/// between the two systems.
|
||||
/// Each of these channels is implemented as a simple
|
||||
/// ring buffer.
|
||||
/// The cost of logging data to RTT is the cost of formatting
|
||||
/// and writing it to the ring buffer in memory.
|
||||
use core::fmt;
|
||||
use core::ptr;
|
||||
|
||||
static mut UP_BUF: [u8; 1024] = [0u8; 1024];
|
||||
static mut DOWN_BUF: [u8; 16] = [0u8; 16];
|
||||
|
||||
/// Ring buffer for communicating between target and host.
|
||||
/// This must be binary compatible with the RTT implementation
|
||||
/// in the JLINK device.
|
||||
#[repr(C)]
|
||||
struct Buffer {
|
||||
name: *const u8,
|
||||
buf_start: *mut u8,
|
||||
size_of_buffer: u32,
|
||||
/// Position of next item to be written
|
||||
/// Volatile as the host may change it.
|
||||
write_offset: u32,
|
||||
/// Position of next item to be read by host.
|
||||
/// Volatile as the host may change it.
|
||||
read_offset: u32,
|
||||
/// In the segger library these flags control blocking
|
||||
/// or non-blocking behavior. Those functions are
|
||||
/// implemented differently here.
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
fn init(&mut self, buf: &mut [u8]) {
|
||||
self.name = b"Terminal\0".as_ptr();
|
||||
self.buf_start = buf.as_mut_ptr();
|
||||
self.size_of_buffer = buf.len() as u32;
|
||||
self.write_offset = 0;
|
||||
self.read_offset = 0;
|
||||
self.flags = 0; // Non-blocking mode
|
||||
}
|
||||
|
||||
fn get_read_offset(&self) -> u32 {
|
||||
unsafe { ptr::read_volatile(&self.read_offset as *const u32) }
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn set_read_offset(&mut self, offset: u32) {
|
||||
unsafe {
|
||||
ptr::write_volatile(&mut self.read_offset as *mut u32, offset);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_write_offset(&self) -> u32 {
|
||||
unsafe { ptr::read_volatile(&self.write_offset as *const u32) }
|
||||
}
|
||||
|
||||
fn set_write_offset(&mut self, offset: u32) {
|
||||
unsafe {
|
||||
ptr::write_volatile(&mut self.write_offset as *mut u32, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write data to the ring buffer.
|
||||
/// Returns true if all of the data was written, which
|
||||
/// will always be the case if blocking==true.
|
||||
/// Returns false if blocking==false and the buffer was
|
||||
/// full.
|
||||
fn write(&mut self, buf: &[u8], blocking: bool) -> bool {
|
||||
let mut buf = buf;
|
||||
let mut write_off = self.get_write_offset() as usize;
|
||||
let size_of_buffer = self.size_of_buffer as usize;
|
||||
while buf.len() > 0 {
|
||||
let read_off = self.get_read_offset() as usize;
|
||||
|
||||
let wrapping_capacity = if read_off > write_off {
|
||||
read_off - write_off - 1
|
||||
} else {
|
||||
size_of_buffer - (write_off - read_off + 1)
|
||||
};
|
||||
|
||||
// If we're full and non-blocking, return now.
|
||||
// Otherwise, we'll spin with a series of 0 byte
|
||||
// length increments until the host consumes data
|
||||
// from the ring buffer.
|
||||
if wrapping_capacity == 0 && !blocking {
|
||||
return false;
|
||||
}
|
||||
|
||||
let flat_capacity = size_of_buffer - write_off;
|
||||
|
||||
let to_copy = buf.len().min(flat_capacity).min(wrapping_capacity);
|
||||
|
||||
unsafe {
|
||||
ptr::copy(
|
||||
buf.as_ptr(),
|
||||
self.buf_start.offset(write_off as isize),
|
||||
to_copy,
|
||||
);
|
||||
}
|
||||
|
||||
write_off += to_copy;
|
||||
if write_off == size_of_buffer {
|
||||
write_off = 0;
|
||||
}
|
||||
self.set_write_offset(write_off as u32);
|
||||
|
||||
buf = &buf[to_copy..];
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// The ControlBlock is the magic struct that the JLINK looks
|
||||
/// for to discover the ring buffers.
|
||||
#[repr(C)]
|
||||
pub struct ControlBlock {
|
||||
/// Initialized to "SEGGER RTT"
|
||||
id: [u8; 16],
|
||||
/// Initialized to NUM_UP
|
||||
max_up_buffers: i32,
|
||||
/// Initialized to NUM_DOWN
|
||||
max_down_buffers: i32,
|
||||
/// Note that RTT allows for this to be an array of
|
||||
/// "up" buffers of size max_up_buffers, but for simplicity
|
||||
/// just a single buffer is implemented here.
|
||||
up: Buffer,
|
||||
/// Note that RTT allows for this to be an array of
|
||||
/// "down" buffers of size max_down_buffers, but for simplicity
|
||||
/// just a single buffer is implemented here.
|
||||
down: Buffer,
|
||||
}
|
||||
|
||||
unsafe impl Sync for ControlBlock {}
|
||||
|
||||
impl ControlBlock {
|
||||
fn init(&mut self) {
|
||||
if self.id[0] == b'S' {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unsafe: use of mutable static
|
||||
// mutable statics can be mutated by multiple threads: aliasing violations
|
||||
// or data races will cause undefined behavior
|
||||
unsafe {
|
||||
self.up.init(&mut UP_BUF);
|
||||
self.down.init(&mut DOWN_BUF);
|
||||
}
|
||||
|
||||
// Compose the ident string such that we won't
|
||||
// emit the string sequence in flash
|
||||
self.id.copy_from_slice(b"_EGGER:RTT\0\0\0\0\0\0");
|
||||
self.id[0] = b'S';
|
||||
self.id[6] = b' ';
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut _SEGGER_RTT: ControlBlock = ControlBlock {
|
||||
id: [0u8; 16],
|
||||
max_up_buffers: 1,
|
||||
max_down_buffers: 1,
|
||||
up: Buffer {
|
||||
name: 0 as *const u8,
|
||||
buf_start: 0 as *mut u8,
|
||||
read_offset: 0,
|
||||
write_offset: 0,
|
||||
flags: 0,
|
||||
size_of_buffer: 0,
|
||||
},
|
||||
down: Buffer {
|
||||
name: 0 as *const u8,
|
||||
buf_start: 0 as *mut u8,
|
||||
write_offset: 0,
|
||||
read_offset: 0,
|
||||
flags: 0,
|
||||
size_of_buffer: 0,
|
||||
},
|
||||
};
|
||||
|
||||
/// A blocking output stream allowing data to be logged from the
|
||||
/// target to the host.
|
||||
/// Implements fmt::Write.
|
||||
pub struct Output {}
|
||||
|
||||
impl Output {
|
||||
/// Create a blocking output stream
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
unsafe {
|
||||
_SEGGER_RTT.init();
|
||||
}
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Output {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
unsafe {
|
||||
_SEGGER_RTT.up.write(s.as_bytes(), true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A non-blocking output stream allowing data to be logged from the
|
||||
/// target to the host.
|
||||
/// Implements fmt::Write.
|
||||
pub struct NonBlockingOutput {
|
||||
blocked: bool,
|
||||
}
|
||||
|
||||
impl NonBlockingOutput {
|
||||
/// Create a non-blocking output stream
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self { blocked: false }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for NonBlockingOutput {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if !self.blocked {
|
||||
unsafe {
|
||||
_SEGGER_RTT.init();
|
||||
if !_SEGGER_RTT.up.write(s.as_bytes(), false) {
|
||||
self.blocked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ extern crate rlibc;
|
|||
pub mod arch;
|
||||
pub use arch::*;
|
||||
mod devices;
|
||||
mod jlink_rtt;
|
||||
mod macros;
|
||||
pub mod platform;
|
||||
mod sync;
|
||||
|
|
Loading…
Reference in New Issue