use cortex_m::singleton;
#[allow(unused_imports)]
use defmt::trace;
use defmt::{debug, warn, Format, Formatter};
#[cfg(feature = "rgba_status")]
use crate::components::Rgba;
#[cfg(feature = "triple_status")]
use crate::components::Triple;
use crate::{
components::{StatusLed, StatusLedBase},
interrupt::BUFFERS,
};
pub const LONGTERM_SIZE: usize = 45000;
pub type DetectionEvent = (SampleCounter, u8);
#[derive(Copy, Clone, Default, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, Format)]
pub struct SampleCounter(pub usize);
impl SampleCounter {
pub fn get_counter(&self) -> usize {
self.0
}
pub fn increment(&mut self) {
match self.0.checked_add(1) {
None => critical_section::with(|cs| {
debug!("critical_section: counter set_error overflow");
#[cfg(feature = "rgba_status")]
StatusLedBase::<Rgba>::set_error(
cs,
Some("No ADC transfer in progress! Unable to collect latest readings"),
);
#[cfg(feature = "triple_status")]
StatusLedBase::<Triple>::set_error(
cs,
Some("No ADC transfer in progress! Unable to collect latest readings"),
);
}),
Some(new_counter) => self.0 = new_counter,
}
}
pub fn wrapping_counter_add(&self, rhs: usize, limit: usize) -> usize {
if self.0 + rhs >= limit {
rhs - (limit - self.0)
} else {
self.0 + rhs
}
}
pub fn wrapping_counter_sub(&self, rhs: usize, limit: usize) -> usize {
if self.0.wrapping_sub(rhs) >= limit {
limit - (rhs - self.0)
} else {
self.0 - rhs
}
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, Format)]
pub struct Buffers {
longterm_buffer: [u8; LONGTERM_SIZE],
current_sample: SampleCounter,
detection_events: [Option<DetectionEvent>; 10],
await_confirm: bool,
}
impl Buffers {
const INIT_TRIGGER_DELTA: i16 = 2;
const INIT_RESTORE_DELTA: i16 = 2;
pub const NO_BUFFER_PANIC_MSG: &'static str =
"Buffers have not been initialized or are not currently available in mutex";
pub fn init() {
match singleton!(:Buffers = Self {
longterm_buffer: [0u8; LONGTERM_SIZE],
current_sample: SampleCounter::default(),
detection_events: [None; 10],
await_confirm: false
}) {
Some(init_buffers) => {
debug!("critical_section: init buffers");
critical_section::with(|cs| BUFFERS.replace(cs, Some(init_buffers)));
}
None => warn!("Buffers have already been initiated"),
}
}
pub fn current_wrapped(&self) -> SampleCounter {
SampleCounter(self.current_sample.get_counter() % LONGTERM_SIZE)
}
pub fn insert(&mut self, sample: u8) {
let new_head = self
.current_wrapped()
.wrapping_counter_add(1, LONGTERM_SIZE);
self.longterm_buffer[new_head] = sample;
self.current_sample.increment();
#[cfg(feature = "trace_avg_samples")]
if self.current_sample.get_counter() % 250 == 0 {
self.trace_avg_samples();
}
}
#[cfg(any(doc, feature = "trace_avg_samples"))]
pub fn trace_avg_samples(&self) {
let first_sample = self
.current_wrapped()
.wrapping_counter_sub(250, LONGTERM_SIZE);
let new_samples = self
.longterm_buffer
.get(first_sample..first_sample + 250)
.unwrap();
trace!("Here are the last 250 samples:\n{=[u8]}", new_samples)
}
pub fn detect_contact(&mut self) -> bool {
debug!("Checking for contact");
if !self.await_confirm {
let prev_sample = self.current_sample.wrapping_counter_sub(1, LONGTERM_SIZE);
if i16::abs(
self.longterm_buffer[prev_sample] as i16
- self.longterm_buffer[self.current_sample.get_counter()] as i16,
) >= Self::INIT_TRIGGER_DELTA
{
self.await_confirm = true;
}
return false;
} else {
self.await_confirm = false; let prev_high_sample = self.current_sample.wrapping_counter_sub(2, LONGTERM_SIZE);
if i16::abs(
self.longterm_buffer[prev_high_sample] as i16
- self.longterm_buffer[self.current_sample.get_counter()] as i16,
) >= 1
{
self.add_detection_event();
return true;
}
}
false
}
pub fn detect_end_contact(&mut self) -> bool {
debug!("Checking for end of contact");
if let Some(last_detection) = self.detection_events[0] {
if self
.current_sample
.wrapping_counter_sub(last_detection.0.get_counter(), LONGTERM_SIZE)
>= 150
{
self.await_confirm = false;
return true;
} else if !self.await_confirm
&& i16::abs(
self.longterm_buffer[self.current_sample.get_counter()] as i16
- last_detection.1 as i16,
) >= Self::INIT_RESTORE_DELTA
{
self.await_confirm = true;
}
return false;
} else if self.await_confirm {
self.await_confirm = false;
if let Some(last_detection) = self.detection_events[0] {
if i16::abs(
self.longterm_buffer[self.current_sample.get_counter()] as i16
- last_detection.1 as i16,
) >= 1
{
return true;
}
}
} else {
warn!("End contact detection was called before any detection events have occurred.");
}
false
}
pub fn detection_idx(&self) -> usize {
self.current_sample.get_counter() - 1
}
fn add_detection_event(&mut self) {
self.detection_events.rotate_right(1);
self.detection_events[0] = Some((
self.current_sample,
self.longterm_buffer[self.current_sample.get_counter()],
));
}
}
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct DetectionMsg(pub SampleCounter);
impl DetectionMsg {
pub fn create(buffer: &Buffers) -> Self {
Self(SampleCounter(buffer.detection_idx()))
}
}
impl Format for DetectionMsg {
fn format(&self, fmt: Formatter) {
defmt::write!(
fmt,
"contact detected on sample {}! Adding to detection events",
self.0
)
}
}
pub fn create_avg_buffer() -> Option<&'static mut [u8; 4000]> {
singleton!(: [u8; 4000] = [0u8; 4000])
}