forked from NaxdyOrg/NaxGCC-FW
chore: move calibrate to config
This commit is contained in:
parent
7878c283e6
commit
5408d37560
3 changed files with 154 additions and 152 deletions
150
src/calibrate.rs
150
src/calibrate.rs
|
@ -1,150 +0,0 @@
|
||||||
use defmt::Format;
|
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pubsub::Subscriber};
|
|
||||||
use embassy_time::Timer;
|
|
||||||
|
|
||||||
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
|
||||||
|
|
||||||
const CALIBRATION_ENTRY_COMBO: [AwaitableButtons; 4] = [
|
|
||||||
AwaitableButtons::Start,
|
|
||||||
AwaitableButtons::A,
|
|
||||||
AwaitableButtons::X,
|
|
||||||
AwaitableButtons::Y,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// This doesn't need to be super fast, since it's only used
|
|
||||||
/// in calibration mode.
|
|
||||||
const BUTTON_POLL_INTERVAL_MILLIS: u64 = 20;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Format)]
|
|
||||||
enum AwaitableButtons {
|
|
||||||
A,
|
|
||||||
B,
|
|
||||||
X,
|
|
||||||
Y,
|
|
||||||
Up,
|
|
||||||
Down,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Start,
|
|
||||||
L,
|
|
||||||
R,
|
|
||||||
}
|
|
||||||
|
|
||||||
trait WaitForButtonPress {
|
|
||||||
/// Wait for a single button press.
|
|
||||||
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons);
|
|
||||||
|
|
||||||
/// Wait for multiple buttons to be pressed simultaneously.
|
|
||||||
async fn wait_for_simultaneous_button_presses<const N: usize>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[AwaitableButtons; N],
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Wait for a single button press of specified buttons, and return the button that was pressed.
|
|
||||||
async fn wait_and_filter_button_press<const N: usize>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[AwaitableButtons; N],
|
|
||||||
) -> AwaitableButtons;
|
|
||||||
|
|
||||||
/// 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>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[[AwaitableButtons; N]; M],
|
|
||||||
) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, const I: usize, const J: usize, const K: usize> WaitForButtonPress
|
|
||||||
for Subscriber<'a, CriticalSectionRawMutex, GcReport, I, J, K>
|
|
||||||
{
|
|
||||||
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons) {
|
|
||||||
loop {
|
|
||||||
if match self.next_message_pure().await {
|
|
||||||
report => is_awaitable_button_pressed(&report, button_to_wait_for),
|
|
||||||
} {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_for_simultaneous_button_presses<const N: usize>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[AwaitableButtons; N],
|
|
||||||
) {
|
|
||||||
loop {
|
|
||||||
if match self.next_message_pure().await {
|
|
||||||
report => buttons_to_wait_for
|
|
||||||
.iter()
|
|
||||||
.all(|button| is_awaitable_button_pressed(&report, button)),
|
|
||||||
} {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_and_filter_button_press<const N: usize>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[AwaitableButtons; N],
|
|
||||||
) -> AwaitableButtons {
|
|
||||||
loop {
|
|
||||||
match self.next_message_pure().await {
|
|
||||||
report => {
|
|
||||||
for button in buttons_to_wait_for {
|
|
||||||
if is_awaitable_button_pressed(&report, button) {
|
|
||||||
return *button;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_and_filter_simultaneous_button_presses<const N: usize, const M: usize>(
|
|
||||||
&mut self,
|
|
||||||
buttons_to_wait_for: &[[AwaitableButtons; N]; M],
|
|
||||||
) -> usize {
|
|
||||||
loop {
|
|
||||||
match self.next_message_pure().await {
|
|
||||||
report => {
|
|
||||||
for (i, buttons) in buttons_to_wait_for.iter().enumerate() {
|
|
||||||
if buttons
|
|
||||||
.iter()
|
|
||||||
.all(|button| is_awaitable_button_pressed(&report, button))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_awaitable_button_pressed(report: &GcReport, button_to_wait_for: &AwaitableButtons) -> bool {
|
|
||||||
match button_to_wait_for {
|
|
||||||
AwaitableButtons::A => report.buttons_1.button_a,
|
|
||||||
AwaitableButtons::B => report.buttons_1.button_b,
|
|
||||||
AwaitableButtons::X => report.buttons_1.button_x,
|
|
||||||
AwaitableButtons::Y => report.buttons_1.button_y,
|
|
||||||
AwaitableButtons::Up => report.buttons_1.dpad_up,
|
|
||||||
AwaitableButtons::Down => report.buttons_1.dpad_down,
|
|
||||||
AwaitableButtons::Left => report.buttons_1.dpad_left,
|
|
||||||
AwaitableButtons::Right => report.buttons_1.dpad_right,
|
|
||||||
AwaitableButtons::Start => report.buttons_2.button_start,
|
|
||||||
AwaitableButtons::L => report.buttons_2.button_l,
|
|
||||||
AwaitableButtons::R => report.buttons_2.button_r,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn calibration_loop() {
|
|
||||||
let mut gcc_subscriber = CHANNEL_GCC_STATE.subscriber().unwrap();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
gcc_subscriber
|
|
||||||
.wait_for_simultaneous_button_presses(&CALIBRATION_ENTRY_COMBO)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
152
src/config.rs
152
src/config.rs
|
@ -1,5 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* Storage for controller configuration, including helper functions & types, as well as sane defaults.
|
* Storage for controller configuration, including helper functions & types, as well as sane defaults.
|
||||||
|
* Also includes necessary logic for configuring the controller & calibrating the sticks.
|
||||||
*/
|
*/
|
||||||
use core::f32::consts::PI;
|
use core::f32::consts::PI;
|
||||||
|
|
||||||
|
@ -16,6 +17,22 @@ use crate::{
|
||||||
ADDR_OFFSET, FLASH_SIZE,
|
ADDR_OFFSET, FLASH_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pubsub::Subscriber};
|
||||||
|
use embassy_time::Timer;
|
||||||
|
|
||||||
|
use crate::{gcc_hid::GcReport, input::CHANNEL_GCC_STATE};
|
||||||
|
|
||||||
|
const CONFIG_MODE_ENTRY_COMBO: [AwaitableButtons; 4] = [
|
||||||
|
AwaitableButtons::Start,
|
||||||
|
AwaitableButtons::A,
|
||||||
|
AwaitableButtons::X,
|
||||||
|
AwaitableButtons::Y,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// This doesn't need to be super fast, since it's only used
|
||||||
|
/// in config mode.
|
||||||
|
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 = 2;
|
pub const CONTROLLER_CONFIG_REVISION: u8 = 2;
|
||||||
|
@ -98,6 +115,21 @@ const DEFAULT_ANGLES: [f32; NO_OF_NOTCHES] = [
|
||||||
PI * 15. / 8.,
|
PI * 15. / 8.,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Format)]
|
||||||
|
enum AwaitableButtons {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Start,
|
||||||
|
L,
|
||||||
|
R,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Format, PackedStruct)]
|
#[derive(Debug, Clone, Format, PackedStruct)]
|
||||||
#[packed_struct(endian = "msb")]
|
#[packed_struct(endian = "msb")]
|
||||||
pub struct StickConfig {
|
pub struct StickConfig {
|
||||||
|
@ -199,3 +231,123 @@ impl ControllerConfig {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait WaitForButtonPress {
|
||||||
|
/// Wait for a single button press.
|
||||||
|
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons);
|
||||||
|
|
||||||
|
/// Wait for multiple buttons to be pressed simultaneously.
|
||||||
|
async fn wait_for_simultaneous_button_presses<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[AwaitableButtons; N],
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Wait for a single button press of specified buttons, and return the button that was pressed.
|
||||||
|
async fn wait_and_filter_button_press<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[AwaitableButtons; N],
|
||||||
|
) -> AwaitableButtons;
|
||||||
|
|
||||||
|
/// 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>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[[AwaitableButtons; N]; M],
|
||||||
|
) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, const I: usize, const J: usize, const K: usize> WaitForButtonPress
|
||||||
|
for Subscriber<'a, CriticalSectionRawMutex, GcReport, I, J, K>
|
||||||
|
{
|
||||||
|
async fn wait_for_button_press(&mut self, button_to_wait_for: &AwaitableButtons) {
|
||||||
|
loop {
|
||||||
|
if match self.next_message_pure().await {
|
||||||
|
report => is_awaitable_button_pressed(&report, button_to_wait_for),
|
||||||
|
} {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_for_simultaneous_button_presses<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[AwaitableButtons; N],
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
if match self.next_message_pure().await {
|
||||||
|
report => buttons_to_wait_for
|
||||||
|
.iter()
|
||||||
|
.all(|button| is_awaitable_button_pressed(&report, button)),
|
||||||
|
} {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_and_filter_button_press<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[AwaitableButtons; N],
|
||||||
|
) -> AwaitableButtons {
|
||||||
|
loop {
|
||||||
|
match self.next_message_pure().await {
|
||||||
|
report => {
|
||||||
|
for button in buttons_to_wait_for {
|
||||||
|
if is_awaitable_button_pressed(&report, button) {
|
||||||
|
return *button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn wait_and_filter_simultaneous_button_presses<const N: usize, const M: usize>(
|
||||||
|
&mut self,
|
||||||
|
buttons_to_wait_for: &[[AwaitableButtons; N]; M],
|
||||||
|
) -> usize {
|
||||||
|
loop {
|
||||||
|
match self.next_message_pure().await {
|
||||||
|
report => {
|
||||||
|
for (i, buttons) in buttons_to_wait_for.iter().enumerate() {
|
||||||
|
if buttons
|
||||||
|
.iter()
|
||||||
|
.all(|button| is_awaitable_button_pressed(&report, button))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timer::after_millis(BUTTON_POLL_INTERVAL_MILLIS).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_awaitable_button_pressed(report: &GcReport, button_to_wait_for: &AwaitableButtons) -> bool {
|
||||||
|
match button_to_wait_for {
|
||||||
|
AwaitableButtons::A => report.buttons_1.button_a,
|
||||||
|
AwaitableButtons::B => report.buttons_1.button_b,
|
||||||
|
AwaitableButtons::X => report.buttons_1.button_x,
|
||||||
|
AwaitableButtons::Y => report.buttons_1.button_y,
|
||||||
|
AwaitableButtons::Up => report.buttons_1.dpad_up,
|
||||||
|
AwaitableButtons::Down => report.buttons_1.dpad_down,
|
||||||
|
AwaitableButtons::Left => report.buttons_1.dpad_left,
|
||||||
|
AwaitableButtons::Right => report.buttons_1.dpad_right,
|
||||||
|
AwaitableButtons::Start => report.buttons_2.button_start,
|
||||||
|
AwaitableButtons::L => report.buttons_2.button_l,
|
||||||
|
AwaitableButtons::R => report.buttons_2.button_r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
pub async fn config_task() {
|
||||||
|
let mut gcc_subscriber = CHANNEL_GCC_STATE.subscriber().unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
gcc_subscriber
|
||||||
|
.wait_for_simultaneous_button_presses(&CONFIG_MODE_ENTRY_COMBO)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
mod calibrate;
|
|
||||||
mod config;
|
mod config;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod gcc_hid;
|
mod gcc_hid;
|
||||||
|
@ -12,7 +11,7 @@ mod helpers;
|
||||||
mod input;
|
mod input;
|
||||||
mod stick;
|
mod stick;
|
||||||
|
|
||||||
use calibrate::calibration_loop;
|
use config::config_task;
|
||||||
use config::ControllerConfig;
|
use config::ControllerConfig;
|
||||||
use defmt::{debug, info};
|
use defmt::{debug, info};
|
||||||
use embassy_executor::Executor;
|
use embassy_executor::Executor;
|
||||||
|
@ -119,6 +118,7 @@ fn main() -> ! {
|
||||||
// pwm_brake.set_counter(255);
|
// pwm_brake.set_counter(255);
|
||||||
|
|
||||||
executor0.run(|spawner| {
|
executor0.run(|spawner| {
|
||||||
|
spawner.spawn(config_task()).unwrap();
|
||||||
spawner
|
spawner
|
||||||
.spawn(update_stick_states_task(
|
.spawn(update_stick_states_task(
|
||||||
spi,
|
spi,
|
||||||
|
|
Loading…
Reference in a new issue