feat: implement notch-adjustment (rudimentary)

This commit is contained in:
Naxdy 2024-04-01 23:07:06 +02:00
parent 03d5c478ef
commit d5dbaaaa49
Signed by: Naxdy
GPG key ID: CC15075846BCE91B
4 changed files with 231 additions and 32 deletions

View file

@ -18,8 +18,9 @@ use crate::{
SPI_SHARED, SPI_SHARED,
}, },
stick::{ stick::{
calc_stick_values, legalize_notches, AppliedCalibration, NotchStatus, CALIBRATION_ORDER, calc_stick_values, legalize_notches, AppliedCalibration, CleanedCalibrationPoints,
NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES, LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
}, },
ADDR_OFFSET, FLASH_SIZE, ADDR_OFFSET, FLASH_SIZE,
}; };
@ -29,7 +30,7 @@ use embassy_sync::{
pubsub::{PubSubBehavior, Subscriber}, pubsub::{PubSubBehavior, Subscriber},
signal::Signal, signal::Signal,
}; };
use embassy_time::Timer; use embassy_time::{Duration, Ticker, Timer};
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE}; use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
@ -73,7 +74,7 @@ const BUTTON_POLL_INTERVAL_MILLIS: u64 = 20;
/// This needs to be incremented for ANY change to ControllerConfig /// This needs to be incremented for ANY change to ControllerConfig
/// else we risk loading uninitialized memory. /// else we risk loading uninitialized memory.
pub const CONTROLLER_CONFIG_REVISION: u8 = 1; pub const CONTROLLER_CONFIG_REVISION: u8 = 2;
pub const DEFAULT_NOTCH_STATUS: [NotchStatus; NO_OF_NOTCHES] = [ pub const DEFAULT_NOTCH_STATUS: [NotchStatus; NO_OF_NOTCHES] = [
NotchStatus::Cardinal, NotchStatus::Cardinal,
@ -175,6 +176,14 @@ enum AwaitableButtons {
R, R,
} }
#[derive(Clone, Copy, Debug, Format)]
enum NotchAdjustmentType {
Clockwise,
CounterClockwise,
Reset,
None,
}
#[derive(Debug, Clone, Format, PackedStruct)] #[derive(Debug, Clone, Format, PackedStruct)]
#[packed_struct(endian = "msb")] #[packed_struct(endian = "msb")]
pub struct StickConfig { pub struct StickConfig {
@ -300,6 +309,12 @@ trait WaitForButtonPress {
buttons_to_wait_for: &[AwaitableButtons; N], buttons_to_wait_for: &[AwaitableButtons; N],
) -> AwaitableButtons; ) -> AwaitableButtons;
/// See if one of the buttons in buttons_to_look_out_for is pressed, and return the pressed button, otherwise None.
fn filter_button_press_if_present<const N: usize>(
&mut self,
buttons_to_look_out_for: &[AwaitableButtons; N],
) -> Option<AwaitableButtons>;
/// Wait for multiple possible button combinations to be pressed simultaneously, and return the index of the combination that was pressed. /// Wait for multiple possible button combinations to be pressed simultaneously, and return the index of the combination that was pressed.
async fn wait_and_filter_simultaneous_button_presses<const N: usize, const M: usize>( async fn wait_and_filter_simultaneous_button_presses<const N: usize, const M: usize>(
&mut self, &mut self,
@ -388,6 +403,23 @@ impl<'a, T: RawMutex, const I: usize, const J: usize, const K: usize> WaitForBut
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await; Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
} }
} }
fn filter_button_press_if_present<const N: usize>(
&mut self,
buttons_to_look_out_for: &[AwaitableButtons; N],
) -> Option<AwaitableButtons> {
let report = self.try_next_message_pure();
if let Some(report) = report {
for button in buttons_to_look_out_for {
if is_awaitable_button_pressed(&report, button) {
return Some(*button);
}
}
}
return None;
}
} }
fn is_awaitable_button_pressed(report: &GcReport, button_to_wait_for: &AwaitableButtons) -> bool { fn is_awaitable_button_pressed(report: &GcReport, button_to_wait_for: &AwaitableButtons) -> bool {
@ -426,6 +458,71 @@ impl<'a> StickCalibrationProcess<'a> {
} }
} }
fn adjust_notch(&mut self, notch_adjustment_type: NotchAdjustmentType) -> Option<(f32, f32)> {
let notch_idx =
NOTCH_ADJUSTMENT_ORDER[self.calibration_step as usize - NO_OF_CALIBRATION_POINTS];
if self.applied_calibration.cleaned_calibration.notch_status[notch_idx]
== NotchStatus::TertInactive
{
return None;
}
// assumes a tick rate of 1ms
match notch_adjustment_type {
NotchAdjustmentType::Clockwise => {
self.applied_calibration.notch_angles[notch_idx] -= 0.000075;
}
NotchAdjustmentType::CounterClockwise => {
self.applied_calibration.notch_angles[notch_idx] += 0.000075;
}
NotchAdjustmentType::Reset => {
self.applied_calibration.notch_angles[notch_idx] = DEFAULT_ANGLES[notch_idx];
}
NotchAdjustmentType::None => {
return None;
}
}
match notch_adjustment_type {
NotchAdjustmentType::Clockwise
| NotchAdjustmentType::CounterClockwise
| NotchAdjustmentType::Reset => {
let cleaned_calibration_points =
CleanedCalibrationPoints::from_temp_calibration_points(
&self.cal_points.map(|e| e.x),
&self.cal_points.map(|e| e.y),
&self.applied_calibration.notch_angles,
);
let linearized_calibration =
LinearizedCalibration::from_calibration_points(&cleaned_calibration_points);
self.applied_calibration.stick_params.fit_coeffs = XyValuePair {
x: linearized_calibration.fit_coeffs.x.map(|e| e as f32),
y: linearized_calibration.fit_coeffs.y.map(|e| e as f32),
};
let notch_calibration = NotchCalibration::from_cleaned_and_linearized_calibration(
&cleaned_calibration_points,
&linearized_calibration,
);
self.applied_calibration.stick_params.affine_coeffs =
notch_calibration.affine_coeffs;
self.applied_calibration.stick_params.boundary_angles =
notch_calibration.boundary_angles;
}
NotchAdjustmentType::None => return None,
}
Some(
match calc_stick_values(self.applied_calibration.measured_notch_angles[notch_idx]) {
(x, y) => (x + FLOAT_ORIGIN, y + FLOAT_ORIGIN),
},
)
}
async fn calibration_advance(&mut self) -> bool { async fn calibration_advance(&mut self) -> bool {
info!( info!(
"Running calibration advance on stick {} at step {}", "Running calibration advance on stick {} at step {}",
@ -484,6 +581,32 @@ impl<'a> StickCalibrationProcess<'a> {
} }
if self.calibration_step >= NO_OF_CALIBRATION_POINTS as u8 { if self.calibration_step >= NO_OF_CALIBRATION_POINTS as u8 {
let mut notch_idx = NOTCH_ADJUSTMENT_ORDER[min(
self.calibration_step - NO_OF_CALIBRATION_POINTS as u8,
NO_OF_ADJ_NOTCHES as u8 - 1,
) as usize];
while self.applied_calibration.cleaned_calibration.notch_status[notch_idx]
== NotchStatus::TertInactive
&& self.calibration_step < NO_OF_CALIBRATION_POINTS as u8 + NO_OF_ADJ_NOTCHES as u8
{
stick_config.angles = *legalize_notches(
self.calibration_step as usize,
&self.applied_calibration.measured_notch_angles,
&stick_config.angles.map(|e| *e),
)
.to_packed_float_array();
self.calibration_step += 1;
notch_idx = NOTCH_ADJUSTMENT_ORDER[min(
self.calibration_step - NO_OF_CALIBRATION_POINTS as u8,
NO_OF_ADJ_NOTCHES as u8 - 1,
) as usize];
}
}
if self.calibration_step >= NO_OF_CALIBRATION_POINTS as u8 + NO_OF_ADJ_NOTCHES as u8 {
stick_config.cal_points_x = self.cal_points.map(|p| p.x.into()); stick_config.cal_points_x = self.cal_points.map(|p| p.x.into());
stick_config.cal_points_y = self.cal_points.map(|p| p.y.into()); stick_config.cal_points_y = self.cal_points.map(|p| p.y.into());
@ -502,11 +625,15 @@ impl<'a> StickCalibrationProcess<'a> {
SIGNAL_IS_CALIBRATING.signal(true); SIGNAL_IS_CALIBRATING.signal(true);
while { while {
if self.calibration_step < NO_OF_CALIBRATION_POINTS as u8 {
// Calibration phase
let (x, y) = get_stick_display_coords(self.calibration_step as usize); let (x, y) = get_stick_display_coords(self.calibration_step as usize);
debug!( debug!(
"Raw display coords for step {}: {}, {}", "Raw display coords for step {}: {}, {}",
self.calibration_step, x, y self.calibration_step, x, y
); );
SIGNAL_OVERRIDE_STICK_STATE.signal(Some(OverrideStickState { SIGNAL_OVERRIDE_STICK_STATE.signal(Some(OverrideStickState {
x: x as u8, x: x as u8,
y: y as u8, y: y as u8,
@ -521,11 +648,77 @@ impl<'a> StickCalibrationProcess<'a> {
.await; .await;
// Prevent accidental double presses // Prevent accidental double presses
Timer::after_millis(20).await; Timer::after_millis(100).await;
gcc_subscriber gcc_subscriber
.wait_for_button_press(&AwaitableButtons::A) .wait_for_button_press(&AwaitableButtons::A)
.await; .await;
} else {
// Notch adjustment phase
gcc_subscriber
.wait_for_button_release(&AwaitableButtons::A)
.await;
Timer::after_millis(100).await;
let mut ticker = Ticker::every(Duration::from_millis(20));
let notch_idx = NOTCH_ADJUSTMENT_ORDER
[self.calibration_step as usize - NO_OF_CALIBRATION_POINTS];
let (init_x, init_y) =
calc_stick_values(self.applied_calibration.measured_notch_angles[notch_idx]);
SIGNAL_OVERRIDE_STICK_STATE.signal(Some(OverrideStickState {
x: (init_x + FLOAT_ORIGIN) as u8,
y: (init_y + FLOAT_ORIGIN) as u8,
which_stick: match self.which_stick {
Stick::ControlStick => Stick::CStick,
Stick::CStick => Stick::ControlStick,
},
}));
'adjust: loop {
let btn_result = gcc_subscriber.filter_button_press_if_present(&[
AwaitableButtons::A,
AwaitableButtons::B,
AwaitableButtons::X,
AwaitableButtons::Y,
]);
let override_result = match btn_result {
Some(btn) => match btn {
AwaitableButtons::A => {
debug!("Btn A release pressed");
break 'adjust;
}
AwaitableButtons::B => self.adjust_notch(NotchAdjustmentType::Reset),
AwaitableButtons::X => {
self.adjust_notch(NotchAdjustmentType::Clockwise)
}
AwaitableButtons::Y => {
self.adjust_notch(NotchAdjustmentType::CounterClockwise)
}
_ => self.adjust_notch(NotchAdjustmentType::None),
},
None => self.adjust_notch(NotchAdjustmentType::None),
};
if let Some((x, y)) = override_result {
SIGNAL_OVERRIDE_STICK_STATE.signal(Some(OverrideStickState {
x: x as u8,
y: y as u8,
which_stick: match self.which_stick {
Stick::ControlStick => Stick::CStick,
Stick::CStick => Stick::ControlStick,
},
}));
}
ticker.next().await;
}
};
!self.calibration_advance().await !self.calibration_advance().await
} {} } {}

View file

@ -360,7 +360,7 @@ pub async fn usb_transfer_task(
trace!("Report Written: {:08b}", report); trace!("Report Written: {:08b}", report);
let currtime = Instant::now(); let currtime = Instant::now();
let polltime = currtime.duration_since(lasttime); let polltime = currtime.duration_since(lasttime);
debug!("Report written in {}us", polltime.as_micros()); trace!("Report written in {}us", polltime.as_micros());
lasttime = currtime; lasttime = currtime;
} }
Err(e) => warn!("Failed to send report: {:?}", e), Err(e) => warn!("Failed to send report: {:?}", e),

View file

@ -453,7 +453,7 @@ pub async fn update_button_state_task(
} }
if let Some(override_stick_state_opt) = SIGNAL_OVERRIDE_STICK_STATE.try_take() { if let Some(override_stick_state_opt) = SIGNAL_OVERRIDE_STICK_STATE.try_take() {
debug!("Overridden stick state: {:?}", override_stick_state_opt); trace!("Overridden stick state: {:?}", override_stick_state_opt);
override_stick_state = override_stick_state_opt; override_stick_state = override_stick_state_opt;
} }
@ -566,6 +566,12 @@ pub async fn update_stick_states_task(
ticker.next().await; ticker.next().await;
// we need this because during calibration, we might
// not run at the desired interval
if is_calibrating {
yield_now().await;
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
// give other tasks a chance to do something // give other tasks a chance to do something

View file

@ -232,7 +232,7 @@ impl CleanedCalibrationPoints {
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct LinearizedCalibration { pub struct LinearizedCalibration {
pub fit_coeffs: XyValuePair<[f64; NUM_COEFFS]>, pub fit_coeffs: XyValuePair<[f64; NUM_COEFFS]>,
pub linearized_points: XyValuePair<[f32; NO_OF_NOTCHES + 1]>, pub linearized_points: XyValuePair<[f32; NO_OF_NOTCHES + 1]>,
@ -313,13 +313,13 @@ impl LinearizedCalibration {
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct NotchCalibration { pub struct NotchCalibration {
affine_coeffs: [[f32; 4]; 16], pub affine_coeffs: [[f32; 4]; 16],
boundary_angles: [f32; 16], pub boundary_angles: [f32; 16],
} }
impl NotchCalibration { impl NotchCalibration {
fn from_cleaned_and_linearized_calibration( pub fn from_cleaned_and_linearized_calibration(
cleaned_calibration_points: &CleanedCalibrationPoints, cleaned_calibration_points: &CleanedCalibrationPoints,
linearized_calibration: &LinearizedCalibration, linearized_calibration: &LinearizedCalibration,
) -> Self { ) -> Self {