chore: refactor HID file organization
This commit is contained in:
parent
c5d247cc96
commit
7faf9d05f9
8 changed files with 160 additions and 144 deletions
|
@ -17,6 +17,7 @@ use packed_struct::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helpers::{PackedFloat, ToPackedFloatArray, ToRegularArray, XyValuePair},
|
helpers::{PackedFloat, ToPackedFloatArray, ToRegularArray, XyValuePair},
|
||||||
|
hid::gcc::{GcButtons1, GcButtons2, GcState},
|
||||||
input::{
|
input::{
|
||||||
read_ext_adc, Stick, StickAxis, FLOAT_ORIGIN, SPI_ACS_SHARED, SPI_CCS_SHARED, SPI_SHARED,
|
read_ext_adc, Stick, StickAxis, FLOAT_ORIGIN, SPI_ACS_SHARED, SPI_CCS_SHARED, SPI_SHARED,
|
||||||
},
|
},
|
||||||
|
@ -25,10 +26,7 @@ use crate::{
|
||||||
LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
|
LinearizedCalibration, NotchCalibration, NotchStatus, CALIBRATION_ORDER,
|
||||||
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
|
NOTCH_ADJUSTMENT_ORDER, NO_OF_ADJ_NOTCHES, NO_OF_CALIBRATION_POINTS, NO_OF_NOTCHES,
|
||||||
},
|
},
|
||||||
usb_comms::{
|
usb_comms::{MUTEX_INPUT_CONSISTENCY_MODE, SIGNAL_CHANGE_RUMBLE_STRENGTH},
|
||||||
GcButtons1, GcButtons2, MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE,
|
|
||||||
SIGNAL_CHANGE_RUMBLE_STRENGTH,
|
|
||||||
},
|
|
||||||
ADDR_OFFSET, FLASH_SIZE,
|
ADDR_OFFSET, FLASH_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +37,7 @@ use embassy_sync::{
|
||||||
};
|
};
|
||||||
use embassy_time::Timer;
|
use embassy_time::Timer;
|
||||||
|
|
||||||
use crate::{input::CHANNEL_GCC_STATE, usb_comms::GcState};
|
use crate::input::CHANNEL_GCC_STATE;
|
||||||
|
|
||||||
/// Whether we are currently calibrating the sticks. Updates are dispatched when the status changes.
|
/// Whether we are currently calibrating the sticks. Updates are dispatched when the status changes.
|
||||||
/// Initial status is assumed to be false.
|
/// Initial status is assumed to be false.
|
||||||
|
|
141
src/hid/gcc.rs
Normal file
141
src/hid/gcc.rs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
use defmt::{info, trace, Format};
|
||||||
|
use embassy_usb::{
|
||||||
|
class::hid::{ReportId, RequestHandler},
|
||||||
|
control::OutResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::usb_comms::{HidReportBuilder, SIGNAL_RUMBLE};
|
||||||
|
use packed_struct::{derive::PackedStruct, PackedStruct};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||||
|
pub struct GcButtons1 {
|
||||||
|
#[packed_field(bits = "0")]
|
||||||
|
pub button_a: bool,
|
||||||
|
#[packed_field(bits = "1")]
|
||||||
|
pub button_b: bool,
|
||||||
|
#[packed_field(bits = "2")]
|
||||||
|
pub button_x: bool,
|
||||||
|
#[packed_field(bits = "3")]
|
||||||
|
pub button_y: bool,
|
||||||
|
#[packed_field(bits = "4")]
|
||||||
|
pub dpad_left: bool,
|
||||||
|
#[packed_field(bits = "5")]
|
||||||
|
pub dpad_right: bool,
|
||||||
|
#[packed_field(bits = "6")]
|
||||||
|
pub dpad_down: bool,
|
||||||
|
#[packed_field(bits = "7")]
|
||||||
|
pub dpad_up: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
||||||
|
pub struct GcButtons2 {
|
||||||
|
#[packed_field(bits = "0")]
|
||||||
|
pub button_start: bool,
|
||||||
|
#[packed_field(bits = "1")]
|
||||||
|
pub button_z: bool,
|
||||||
|
#[packed_field(bits = "2")]
|
||||||
|
pub button_r: bool,
|
||||||
|
#[packed_field(bits = "3")]
|
||||||
|
pub button_l: bool,
|
||||||
|
#[packed_field(bits = "4..=7")]
|
||||||
|
pub blank1: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Struct representing the controller state. Used for HID communications in
|
||||||
|
/// GCC adapter mode, as well as for the internal representation of the controller.
|
||||||
|
///
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
||||||
|
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
|
||||||
|
pub struct GcState {
|
||||||
|
#[packed_field(bits = "0..=7")]
|
||||||
|
pub buttons_1: GcButtons1,
|
||||||
|
#[packed_field(bits = "8..=15")]
|
||||||
|
pub buttons_2: GcButtons2,
|
||||||
|
#[packed_field(bits = "16..=23")]
|
||||||
|
pub stick_x: u8,
|
||||||
|
#[packed_field(bits = "24..=31")]
|
||||||
|
pub stick_y: u8,
|
||||||
|
#[packed_field(bits = "32..=39")]
|
||||||
|
pub cstick_x: u8,
|
||||||
|
#[packed_field(bits = "40..=47")]
|
||||||
|
pub cstick_y: u8,
|
||||||
|
#[packed_field(bits = "48..=55")]
|
||||||
|
pub trigger_l: u8,
|
||||||
|
#[packed_field(bits = "56..=63")]
|
||||||
|
pub trigger_r: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GcState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
buttons_1: GcButtons1::default(),
|
||||||
|
buttons_2: GcButtons2::default(),
|
||||||
|
stick_x: 127,
|
||||||
|
stick_y: 127,
|
||||||
|
cstick_x: 127,
|
||||||
|
cstick_y: 127,
|
||||||
|
trigger_l: 0,
|
||||||
|
trigger_r: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GcReportBuilder {
|
||||||
|
gc_first: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HidReportBuilder<37> for GcReportBuilder {
|
||||||
|
async fn get_hid_report(&mut self, state: &GcState) -> [u8; 37] {
|
||||||
|
let mut buffer = [0u8; 37];
|
||||||
|
|
||||||
|
buffer[0] = 0x21;
|
||||||
|
buffer[1] |= 0x14;
|
||||||
|
|
||||||
|
let data = state.pack().expect("Failed to pack GC input data");
|
||||||
|
|
||||||
|
if !self.gc_first {
|
||||||
|
buffer[1] |= 0x04;
|
||||||
|
buffer[10] |= 0x04;
|
||||||
|
buffer[19] |= 0x04;
|
||||||
|
buffer[28] |= 0x04;
|
||||||
|
self.gc_first = true;
|
||||||
|
} else {
|
||||||
|
// controller in "port 1"
|
||||||
|
buffer[2..=9].copy_from_slice(&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GccRequestHandler;
|
||||||
|
|
||||||
|
impl RequestHandler for GccRequestHandler {
|
||||||
|
fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
|
||||||
|
info!("Get report for {:?}", id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
|
||||||
|
trace!("Set report for {:?}: {:x}", id, data);
|
||||||
|
|
||||||
|
if data.len() > 1 {
|
||||||
|
SIGNAL_RUMBLE.signal((data[1] & 0x01) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
OutResponse::Accepted
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
|
||||||
|
info!("Set idle rate for {:?} to {:?}", id, dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
|
||||||
|
info!("Get idle rate for {:?}", id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
2
src/hid/mod.rs
Normal file
2
src/hid/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod gcc;
|
||||||
|
pub mod procon;
|
|
@ -18,7 +18,9 @@ use embassy_usb::{
|
||||||
use packed_struct::{derive::PackedStruct, PackedStruct};
|
use packed_struct::{derive::PackedStruct, PackedStruct};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
|
||||||
use crate::usb_comms::{GcState, HidReportBuilder};
|
use crate::usb_comms::HidReportBuilder;
|
||||||
|
|
||||||
|
use super::gcc::GcState;
|
||||||
|
|
||||||
const SW_INFO_SET_MAC: u8 = 0x01;
|
const SW_INFO_SET_MAC: u8 = 0x01;
|
||||||
|
|
|
@ -22,9 +22,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
filter::{run_waveshaping, FilterGains, KalmanState, WaveshapingValues, FILTER_GAINS},
|
filter::{run_waveshaping, FilterGains, KalmanState, WaveshapingValues, FILTER_GAINS},
|
||||||
helpers::XyValuePair,
|
helpers::XyValuePair,
|
||||||
|
hid::gcc::GcState,
|
||||||
input_filter::{DummyFilter, InputFilter},
|
input_filter::{DummyFilter, InputFilter},
|
||||||
stick::{linearize, notch_remap, StickParams},
|
stick::{linearize, notch_remap, StickParams},
|
||||||
usb_comms::{GcState, MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE},
|
usb_comms::{MUTEX_CONTROLLER_MODE, MUTEX_INPUT_CONSISTENCY_MODE},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Used to send the button state to the usb task and the calibration task
|
/// Used to send the button state to the usb task and the calibration task
|
||||||
|
|
|
@ -2,7 +2,7 @@ use defmt::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{is_awaitable_button_pressed, AwaitableButtons},
|
config::{is_awaitable_button_pressed, AwaitableButtons},
|
||||||
usb_comms::GcState,
|
hid::gcc::GcState,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
mod config;
|
mod config;
|
||||||
mod filter;
|
mod filter;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
mod hid;
|
||||||
mod input;
|
mod input;
|
||||||
mod input_filter;
|
mod input_filter;
|
||||||
mod procon_hid;
|
|
||||||
mod stick;
|
mod stick;
|
||||||
mod usb_comms;
|
mod usb_comms;
|
||||||
|
|
||||||
|
|
142
src/usb_comms.rs
142
src/usb_comms.rs
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
use core::{default::Default, future::Future};
|
use core::{default::Default, future::Future};
|
||||||
|
|
||||||
use defmt::{debug, info, trace, warn, Format};
|
use defmt::{debug, info, trace, warn};
|
||||||
use embassy_futures::join::join;
|
use embassy_futures::join::join;
|
||||||
use embassy_rp::{
|
use embassy_rp::{
|
||||||
peripherals::{PIN_25, PIN_29, PWM_SLICE4, PWM_SLICE6, USB},
|
peripherals::{PIN_25, PIN_29, PWM_SLICE4, PWM_SLICE6, USB},
|
||||||
|
@ -15,22 +15,23 @@ use embassy_rp::{
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, signal::Signal};
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, signal::Signal};
|
||||||
use embassy_time::{Duration, Instant, Timer};
|
use embassy_time::{Duration, Instant, Timer};
|
||||||
use embassy_usb::{
|
use embassy_usb::{
|
||||||
class::hid::{HidReader, HidReaderWriter, HidWriter, ReportId, RequestHandler, State},
|
class::hid::{HidReader, HidReaderWriter, HidWriter, RequestHandler, State},
|
||||||
control::OutResponse,
|
|
||||||
driver::Driver,
|
driver::Driver,
|
||||||
msos::{self, windows_version},
|
msos::{self, windows_version},
|
||||||
Builder, Handler, UsbDevice,
|
Builder, Handler, UsbDevice,
|
||||||
};
|
};
|
||||||
use libm::powf;
|
use libm::powf;
|
||||||
use packed_struct::{derive::PackedStruct, PackedStruct};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{ControllerMode, InputConsistencyMode},
|
config::{ControllerMode, InputConsistencyMode},
|
||||||
|
hid::{
|
||||||
|
gcc::{GcReportBuilder, GcState, GccRequestHandler},
|
||||||
|
procon::{ProconReportBuilder, ProconRequestHandler, PROCON_REPORT_DESCRIPTOR},
|
||||||
|
},
|
||||||
input::CHANNEL_GCC_STATE,
|
input::CHANNEL_GCC_STATE,
|
||||||
procon_hid::{ProconReportBuilder, ProconRequestHandler, PROCON_REPORT_DESCRIPTOR},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static SIGNAL_RUMBLE: Signal<CriticalSectionRawMutex, bool> = Signal::new();
|
pub static SIGNAL_RUMBLE: Signal<CriticalSectionRawMutex, bool> = Signal::new();
|
||||||
|
|
||||||
/// We could turn the config change signal into a PubSubChannel instead, but that
|
/// We could turn the config change signal into a PubSubChannel instead, but that
|
||||||
/// would just transmit unnecessary amounts of data.
|
/// would just transmit unnecessary amounts of data.
|
||||||
|
@ -116,135 +117,6 @@ struct UsbConfig {
|
||||||
report_descriptor: &'static [u8],
|
report_descriptor: &'static [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
|
||||||
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
|
||||||
pub struct GcButtons1 {
|
|
||||||
#[packed_field(bits = "0")]
|
|
||||||
pub button_a: bool,
|
|
||||||
#[packed_field(bits = "1")]
|
|
||||||
pub button_b: bool,
|
|
||||||
#[packed_field(bits = "2")]
|
|
||||||
pub button_x: bool,
|
|
||||||
#[packed_field(bits = "3")]
|
|
||||||
pub button_y: bool,
|
|
||||||
#[packed_field(bits = "4")]
|
|
||||||
pub dpad_left: bool,
|
|
||||||
#[packed_field(bits = "5")]
|
|
||||||
pub dpad_right: bool,
|
|
||||||
#[packed_field(bits = "6")]
|
|
||||||
pub dpad_down: bool,
|
|
||||||
#[packed_field(bits = "7")]
|
|
||||||
pub dpad_up: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, PackedStruct, Format)]
|
|
||||||
#[packed_struct(bit_numbering = "lsb0", size_bytes = "1")]
|
|
||||||
pub struct GcButtons2 {
|
|
||||||
#[packed_field(bits = "0")]
|
|
||||||
pub button_start: bool,
|
|
||||||
#[packed_field(bits = "1")]
|
|
||||||
pub button_z: bool,
|
|
||||||
#[packed_field(bits = "2")]
|
|
||||||
pub button_r: bool,
|
|
||||||
#[packed_field(bits = "3")]
|
|
||||||
pub button_l: bool,
|
|
||||||
#[packed_field(bits = "4..=7")]
|
|
||||||
pub blank1: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PackedStruct, Format)]
|
|
||||||
#[packed_struct(bit_numbering = "msb0", size_bytes = "8")]
|
|
||||||
pub struct GcState {
|
|
||||||
#[packed_field(bits = "0..=7")]
|
|
||||||
pub buttons_1: GcButtons1,
|
|
||||||
#[packed_field(bits = "8..=15")]
|
|
||||||
pub buttons_2: GcButtons2,
|
|
||||||
#[packed_field(bits = "16..=23")]
|
|
||||||
pub stick_x: u8,
|
|
||||||
#[packed_field(bits = "24..=31")]
|
|
||||||
pub stick_y: u8,
|
|
||||||
#[packed_field(bits = "32..=39")]
|
|
||||||
pub cstick_x: u8,
|
|
||||||
#[packed_field(bits = "40..=47")]
|
|
||||||
pub cstick_y: u8,
|
|
||||||
#[packed_field(bits = "48..=55")]
|
|
||||||
pub trigger_l: u8,
|
|
||||||
#[packed_field(bits = "56..=63")]
|
|
||||||
pub trigger_r: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for GcState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
buttons_1: GcButtons1::default(),
|
|
||||||
buttons_2: GcButtons2::default(),
|
|
||||||
stick_x: 127,
|
|
||||||
stick_y: 127,
|
|
||||||
cstick_x: 127,
|
|
||||||
cstick_y: 127,
|
|
||||||
trigger_l: 0,
|
|
||||||
trigger_r: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct GcReportBuilder {
|
|
||||||
gc_first: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HidReportBuilder<37> for GcReportBuilder {
|
|
||||||
async fn get_hid_report(&mut self, state: &GcState) -> [u8; 37] {
|
|
||||||
let mut buffer = [0u8; 37];
|
|
||||||
|
|
||||||
buffer[0] = 0x21;
|
|
||||||
buffer[1] |= 0x14;
|
|
||||||
|
|
||||||
let data = state.pack().expect("Failed to pack GC input data");
|
|
||||||
|
|
||||||
if !self.gc_first {
|
|
||||||
buffer[1] |= 0x04;
|
|
||||||
buffer[10] |= 0x04;
|
|
||||||
buffer[19] |= 0x04;
|
|
||||||
buffer[28] |= 0x04;
|
|
||||||
self.gc_first = true;
|
|
||||||
} else {
|
|
||||||
// controller in "port 1"
|
|
||||||
buffer[2..=9].copy_from_slice(&data);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GccRequestHandler;
|
|
||||||
|
|
||||||
impl RequestHandler for GccRequestHandler {
|
|
||||||
fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
|
|
||||||
info!("Get report for {:?}", id);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse {
|
|
||||||
trace!("Set report for {:?}: {:x}", id, data);
|
|
||||||
|
|
||||||
if data.len() > 1 {
|
|
||||||
SIGNAL_RUMBLE.signal((data[1] & 0x01) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
OutResponse::Accepted
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
|
|
||||||
info!("Set idle rate for {:?} to {:?}", id, dur);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_idle_ms(&mut self, id: Option<ReportId>) -> Option<u32> {
|
|
||||||
info!("Get idle rate for {:?}", id);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyDeviceHandler {
|
struct MyDeviceHandler {
|
||||||
configured: bool,
|
configured: bool,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue