Refactor gamepad code to be sync

This commit is contained in:
zaubentrucker 2024-12-25 00:42:02 +01:00
parent 9a450cfe9c
commit efcc13bea7

View file

@ -4,11 +4,11 @@ use gilrs::Button::LeftTrigger2;
use gilrs::Button::RightTrigger2; use gilrs::Button::RightTrigger2;
use gilrs::EventType::*; use gilrs::EventType::*;
use gilrs::Gilrs; use gilrs::Gilrs;
use std::sync::mpsc;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use tokio::sync::mpsc;
#[derive(Debug)] #[derive(Debug)]
pub enum Axis { pub enum Axis {
@ -41,73 +41,70 @@ pub enum GamepadEvent {
/// } /// }
/// ``` /// ```
pub struct Gamepad { pub struct Gamepad {
speed_setpoint: Mutex<(f32, f32, f32)>, gilrs: Gilrs,
// Cached speed setpoint for (X, Y, Positive-Z, Negative-Z)
speed_setpoint: (f32, f32, f32, f32),
} }
impl Gamepad { impl Gamepad {
/// Create a new `Gamepad` and spawn the underlying tasks for updating internal setpoints /// Create a new `Gamepad` and spawn the underlying tasks for updating internal setpoints
/// ///
/// The tasks are terminated on drop. /// The tasks are terminated on drop.
pub async fn new() -> Result<Arc<Self>, gilrs::Error> { pub fn new() -> Result<Self, gilrs::Error> {
let (gamepad_tx, gamepad_rx) = mpsc::channel(8); let gilrs = Gilrs::new().unwrap();
let res = Arc::new(Gamepad { for (_id, gamepad) in gilrs.gamepads() {
speed_setpoint: Mutex::new((0.0, 0.0, 0.0)), println!(
}); "Found gamepad {}: {:?}",
tokio::task::spawn_blocking(move || { gamepad.name(),
let mut gilrs = Gilrs::new().unwrap(); gamepad.power_info()
for (_id, gamepad) in gilrs.gamepads() { );
println!("{} is {:?}", gamepad.name(), gamepad.power_info()); }
}
loop {
sleep(Duration::from_millis(1));
if let Some(event) = gilrs.next_event() {
if let Some(internal_event) = Self::map_event(event) {
if gamepad_tx.blocking_send(internal_event).is_err() {
// receiver dropped
break;
}
}
}
}
});
tokio::spawn(Self::handle_events(res.clone(), gamepad_rx)); Ok(Self {
gilrs,
Ok(res) speed_setpoint: (0.0, 0.0, 0.0, 0.0),
})
} }
/// Get the current speed that the user is dialing in on the gamepad fn get_next(&mut self) -> Option<GamepadEvent> {
pub fn speed_setpoint(&self) -> (f32, f32, f32) { self.gilrs
*self.speed_setpoint.lock().unwrap() .next_event()
.and_then(|event| Self::map_event(event))
} }
/// Update the setpoints in accordance to incoming `GamepadEvent`s // Get all `GamepadEvent`s since the last call
async fn handle_events(self_arc: Arc<Self>, mut events_rx: mpsc::Receiver<GamepadEvent>) { pub fn get_pending(&mut self) -> Vec<GamepadEvent> {
// There is two z-axes that counter each other. (0..).map_while(|_| self.get_next()).collect()
let mut z_positive = 0.0; }
let mut z_negative = 0.0;
while let Some(event) = events_rx.recv().await { /// Update the current speed via the movements on the controller and return the current setpoint
///
/// If you don't want to update, just supply an empty `updates` slice
pub fn speed_setpoint(&mut self, updates: &[GamepadEvent]) -> (f32, f32, f32) {
for event in updates {
match event { match event {
GamepadEvent::TerminatePressed => break, GamepadEvent::TerminatePressed => break,
GamepadEvent::AxisPosition(axis, value) => { GamepadEvent::AxisPosition(axis, value) => {
// I won't panic if you don't panic! // I won't panic if you don't panic!
let mut speed_setpoint = self_arc.speed_setpoint.lock().unwrap(); let mut speed_setpoint = self.speed_setpoint;
match axis { match axis {
Axis::X => speed_setpoint.0 = value, Axis::X => speed_setpoint.0 = *value,
Axis::Y => speed_setpoint.1 = value, Axis::Y => speed_setpoint.1 = *value,
Axis::ZPositive => { Axis::ZPositive => {
z_positive = value; speed_setpoint.2 = *value;
speed_setpoint.2 = z_positive - z_negative;
} }
Axis::ZNegative => { Axis::ZNegative => {
z_negative = value; speed_setpoint.3 = *value;
speed_setpoint.2 = z_positive - z_negative;
} }
} }
} }
} }
} }
println!("Game pad quit!") (
self.speed_setpoint.0,
self.speed_setpoint.1,
self.speed_setpoint.2 - self.speed_setpoint.3,
)
} }
fn map_event(event: gilrs::Event) -> Option<GamepadEvent> { fn map_event(event: gilrs::Event) -> Option<GamepadEvent> {