use adder_codec_core::{DeltaT, D, D_MAX};
use std::cmp::min;
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum DecimationMode {
Standard,
AggressiveRoi,
Manual,
}
#[derive(Default)]
pub(crate) struct DController {
pub(crate) lookahead_d: D,
delta_t_predicted: DeltaT,
}
pub trait DControl {
fn throttle_decimation(&mut self, d: &mut D, delta_t_max: DeltaT);
fn update_decimation(&mut self, d: &mut D, delta_t: DeltaT, delta_t_max: DeltaT);
fn set_lookahead_d(&mut self, d: D);
fn update_roi_factor(&mut self, roi_factor: u8);
}
#[derive(Default)]
pub(crate) struct Standard {
pub(crate) controller: DController,
unstable_bits: u8,
delta_t_stable: DeltaT,
}
#[allow(dead_code)]
impl Standard {
pub fn new() -> Standard {
Standard {
controller: DController {
lookahead_d: u8::MAX,
delta_t_predicted: 500,
},
unstable_bits: 0,
delta_t_stable: 0,
}
}
}
impl DControl for Standard {
fn throttle_decimation(&mut self, d: &mut D, delta_t_max: DeltaT) {
self.unstable_bits = 32; throttle_decimation_general(&mut self.controller, d, delta_t_max);
}
fn update_decimation(&mut self, d: &mut D, delta_t: DeltaT, delta_t_max: DeltaT) {
let last_unstable_bits = self.unstable_bits;
let delta_t_predicted = &mut self.controller.delta_t_predicted;
for i in (0..32).rev() {
if (*delta_t_predicted >> i) & 1 != ((delta_t >> i) & 1) && self.unstable_bits == 0 {
self.unstable_bits = i;
}
}
if self.unstable_bits == 0 {
self.delta_t_stable = min(self.delta_t_stable + delta_t, delta_t_max);
} else {
self.delta_t_stable = 0;
}
if last_unstable_bits > 0
&& self.unstable_bits < last_unstable_bits
&& *delta_t_predicted << 1 < delta_t_max
{
if *d < D_MAX && *delta_t_predicted << 1 <= delta_t_max / 2 {
*d += 1;
*delta_t_predicted <<= 1;
} else {
*delta_t_predicted = delta_t;
}
} else if self.unstable_bits > last_unstable_bits + 1 {
if *d > 0 {
*d -= 1;
} else {
*delta_t_predicted = delta_t;
}
} else if *d < D_MAX
&& (delta_t << 1 <= (delta_t_max * 2) / 3
|| (*delta_t_predicted << 1 < delta_t_max
&& self.unstable_bits == 0
&& self.delta_t_stable >= delta_t_max))
{
*delta_t_predicted = delta_t << 1;
*d += 1;
} else {
*delta_t_predicted = delta_t;
}
if self.controller.lookahead_d != 255 {
*d = self.controller.lookahead_d;
}
}
fn set_lookahead_d(&mut self, d: D) {
self.controller.lookahead_d = d;
}
fn update_roi_factor(&mut self, _roi_factor: u8) {
}
}
fn throttle_decimation_general(controller: &mut DController, d: &mut D, delta_t_max: DeltaT) {
let old_d = *d;
let threshold = controller.delta_t_predicted as f32 * 1.2;
if *d > 0 && delta_t_max > threshold as u32 {
*d = fast_math::log2_raw(f32::from(*d)) as D;
if *d > 0 && *d == old_d {
*d -= 1;
}
controller.delta_t_predicted >>= old_d - *d;
} else if *d > 0 {
*d -= 1;
controller.delta_t_predicted = delta_t_max >> 1;
}
if *d > controller.lookahead_d && controller.lookahead_d != 255 {
*d = controller.lookahead_d;
}
}
#[derive(Default)]
pub(crate) struct Aggressive {
pub(crate) controller: DController,
roi_factor: u8,
ref_time: DeltaT,
}
#[allow(dead_code)]
impl Aggressive {
pub fn new(ref_time: DeltaT, _delta_t_max: DeltaT) -> Aggressive {
Aggressive {
controller: DController {
lookahead_d: u8::MAX,
delta_t_predicted: 500,
},
roi_factor: 1_u8,
ref_time,
}
}
}
impl DControl for Aggressive {
fn throttle_decimation(&mut self, d: &mut D, delta_t_max: DeltaT) {
throttle_decimation_general(&mut self.controller, d, delta_t_max);
}
fn update_decimation(&mut self, d: &mut D, delta_t: DeltaT, delta_t_max: DeltaT) {
if self.roi_factor == (delta_t_max / self.ref_time) as u8 {
if *d < D_MAX && delta_t << 1 <= self.ref_time {
*d += 1;
} else if *d > 0 && delta_t > self.ref_time {
*d = adder_codec_core::D_START;
}
} else if *d < D_MAX
&& (delta_t << 1) as f32 <= (delta_t_max / u32::from(self.roi_factor)) as f32 * 0.8
{
*d += 1;
} else if *d > 0 && delta_t > delta_t_max / u32::from(self.roi_factor) {
*d -= 1;
}
if *d > self.controller.lookahead_d && self.controller.lookahead_d != 255 {
*d = self.controller.lookahead_d;
}
}
fn set_lookahead_d(&mut self, d: D) {
self.controller.lookahead_d = d;
}
fn update_roi_factor(&mut self, roi_factor: u8) {
if roi_factor > 1 {
self.roi_factor = roi_factor;
} else if self.roi_factor > 1 {
self.roi_factor -= 1;
}
}
}
#[derive(Default)]
pub(crate) struct Manual {}
#[allow(dead_code)]
impl Manual {
pub fn new() -> Manual {
Manual {}
}
}
impl DControl for Manual {
fn throttle_decimation(&mut self, _d: &mut D, _delta_t_max: DeltaT) {
todo!()
}
fn update_decimation(&mut self, _d: &mut D, _delta_t: DeltaT, _delta_t_max: DeltaT) {
todo!()
}
fn set_lookahead_d(&mut self, _d: D) {
todo!()
}
fn update_roi_factor(&mut self, _roi_factor: u8) {
todo!()
}
}
unsafe impl Sync for DController {}
unsafe impl Send for DController {}