use crate::{
peripheral::{Peripheral, PeripheralRef},
peripherals::trace::RegisterBlock,
system::PeripheralClockControl,
};
#[derive(Debug, Clone, Copy)]
pub enum Error {
NotStarted,
}
#[derive(Debug, Clone, Copy)]
pub struct TraceResult {
pub valid_start_index: usize,
pub valid_length: usize,
}
pub struct Trace<'d, T> {
peripheral: PeripheralRef<'d, T>,
buffer: Option<&'d mut [u8]>,
}
impl<'d, T> Trace<'d, T>
where
T: Instance,
{
pub fn new(peripheral: impl Peripheral<P = T> + 'd) -> Self {
crate::into_ref!(peripheral);
PeripheralClockControl::enable(crate::system::Peripheral::Trace0);
Self {
peripheral,
buffer: None,
}
}
pub fn start_trace(&mut self, buffer: &'d mut [u8]) {
let reg_block = self.peripheral.register_block();
reg_block.mem_start_addr().modify(|_, w| {
w.mem_start_addr()
.variant(buffer.as_ptr() as *const _ as u32)
});
reg_block.mem_end_addr().modify(|_, w| {
w.mem_end_addr()
.variant((buffer.as_ptr() as *const _ as u32) + (buffer.len() as u32))
});
reg_block
.mem_addr_update()
.write(|w| w.mem_current_addr_update().set_bit());
reg_block
.intr_ena()
.modify(|_, w| w.mem_full_intr_ena().set_bit());
reg_block
.trigger()
.write(|w| w.mem_loop().set_bit().restart_ena().set_bit());
reg_block.intr_clr().write(|w| {
w.fifo_overflow_intr_clr()
.set_bit()
.mem_full_intr_clr()
.set_bit()
});
self.buffer.replace(buffer);
reg_block.trigger().write(|w| w.on().set_bit());
}
pub fn stop_trace(&mut self) -> Result<TraceResult, Error> {
let reg_block = self.peripheral.register_block();
reg_block
.trigger()
.write(|w| w.off().set_bit().restart_ena().clear_bit());
if self.buffer.is_none() {
return Err(Error::NotStarted);
}
let buffer = self.buffer.take().unwrap();
while !reg_block.fifo_status().read().fifo_empty().bit_is_set() {}
let overflow = reg_block.intr_raw().read().mem_full_intr_raw().bit();
let idx = if overflow {
reg_block
.mem_current_addr()
.read()
.mem_current_addr()
.bits()
- &buffer as *const _ as u32
} else {
0
};
let len = if overflow {
buffer.len()
} else {
reg_block
.mem_current_addr()
.read()
.mem_current_addr()
.bits() as usize
- buffer.as_ptr() as *const _ as usize
- 14 };
let mut valid = false;
let mut fourteen_zeroes = false;
let mut zeroes = 0;
let start_index = if !valid {
let mut i = 0;
loop {
let b = unsafe {
buffer
.as_ptr()
.add((i + idx as usize) % buffer.len())
.read_volatile()
};
if !valid {
if b == 0 {
zeroes += 1;
} else {
zeroes = 0;
}
if zeroes >= 14 {
fourteen_zeroes = true;
}
if fourteen_zeroes && b != 0 {
valid = true;
}
}
if valid {
break i;
}
i += 1;
}
} else {
0
};
Ok(TraceResult {
valid_start_index: start_index,
valid_length: len,
})
}
}
pub trait Instance {
fn register_block(&self) -> &RegisterBlock;
}
impl Instance for crate::peripherals::TRACE0 {
fn register_block(&self) -> &RegisterBlock {
self
}
}