input as events
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
pub mod joystick;
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
io::{Read, Write},
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
@@ -16,62 +17,78 @@ use nusb::{
|
||||
transfer::{ControlOut, ControlType, In, Interrupt, Out, Recipient},
|
||||
};
|
||||
|
||||
use crate::joystick::Button;
|
||||
|
||||
pub const G13_LCD_COLUMNS: i32 = 160;
|
||||
pub const G13_LCD_ROWS: i32 = 43;
|
||||
pub const G13_LCD_BYTES_PER_ROW: i32 = G13_LCD_COLUMNS / 8;
|
||||
pub const G13_LCD_BUF_SIZE: i32 = (G13_LCD_ROWS + 5) * G13_LCD_BYTES_PER_ROW;
|
||||
|
||||
const BUTTON_MAP: &[(Button, usize, u8)] = &[
|
||||
// buf[6]
|
||||
(Button::Action, 6, 0b00000001),
|
||||
(Button::Screen1, 6, 0b00000010),
|
||||
(Button::Screen2, 6, 0b00000100),
|
||||
(Button::Screen3, 6, 0b00001000),
|
||||
(Button::Screen4, 6, 0b00010000),
|
||||
(Button::M1, 6, 0b00100000),
|
||||
(Button::M2, 6, 0b01000000),
|
||||
(Button::M3, 6, 0b10000000),
|
||||
// buf[7]
|
||||
(Button::Light, 7, 0b01000000),
|
||||
(Button::MR, 7, 0b00000001),
|
||||
(Button::Stick1, 7, 0b00000010),
|
||||
(Button::Stick2, 7, 0b00000100),
|
||||
(Button::Stick3, 7, 0b00001000),
|
||||
// buf[3]
|
||||
(Button::G1, 3, 0b00000001),
|
||||
(Button::G2, 3, 0b00000010),
|
||||
(Button::G3, 3, 0b00000100),
|
||||
(Button::G4, 3, 0b00001000),
|
||||
(Button::G5, 3, 0b00010000),
|
||||
(Button::G6, 3, 0b00100000),
|
||||
(Button::G7, 3, 0b01000000),
|
||||
(Button::G8, 3, 0b10000000),
|
||||
// buf[4]
|
||||
(Button::G9, 4, 0b00000001),
|
||||
(Button::G10, 4, 0b00000010),
|
||||
(Button::G11, 4, 0b00000100),
|
||||
(Button::G12, 4, 0b00001000),
|
||||
(Button::G13, 4, 0b00010000),
|
||||
(Button::G14, 4, 0b00100000),
|
||||
(Button::G15, 4, 0b01000000),
|
||||
(Button::G16, 4, 0b10000000),
|
||||
// buf[5]
|
||||
(Button::G17, 5, 0b00000001),
|
||||
(Button::G18, 5, 0b00000010),
|
||||
(Button::G19, 5, 0b00000100),
|
||||
(Button::G20, 5, 0b00001000),
|
||||
(Button::G21, 5, 0b00010000),
|
||||
(Button::G22, 5, 0b00100000),
|
||||
];
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Vec2<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T> Vec2<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
pub fn new(x: T, y: T) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G13 {
|
||||
interface: Interface,
|
||||
img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>,
|
||||
state: Arc<RwLock<State>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct State {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub buttons: Buttons,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Buttons {
|
||||
pub action: bool,
|
||||
pub screen1: bool,
|
||||
pub screen2: bool,
|
||||
pub screen3: bool,
|
||||
pub screen4: bool,
|
||||
pub light: bool,
|
||||
pub m1: bool,
|
||||
pub m2: bool,
|
||||
pub m3: bool,
|
||||
pub mr: bool,
|
||||
pub g1: bool,
|
||||
pub g2: bool,
|
||||
pub g3: bool,
|
||||
pub g4: bool,
|
||||
pub g5: bool,
|
||||
pub g6: bool,
|
||||
pub g7: bool,
|
||||
pub g8: bool,
|
||||
pub g9: bool,
|
||||
pub g10: bool,
|
||||
pub g11: bool,
|
||||
pub g12: bool,
|
||||
pub g13: bool,
|
||||
pub g14: bool,
|
||||
pub g15: bool,
|
||||
pub g16: bool,
|
||||
pub g17: bool,
|
||||
pub g18: bool,
|
||||
pub g19: bool,
|
||||
pub g20: bool,
|
||||
pub g21: bool,
|
||||
pub g22: bool,
|
||||
pub stick1: bool,
|
||||
pub stick2: bool,
|
||||
pub stick3: bool,
|
||||
display: G13Display,
|
||||
input: G13Input,
|
||||
}
|
||||
|
||||
impl G13 {
|
||||
@@ -96,80 +113,142 @@ impl G13 {
|
||||
Err(e) => return Err(format!("Unable to claim interface: {:#?}", e).into()),
|
||||
};
|
||||
|
||||
let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8];
|
||||
let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8];
|
||||
buffer[0] = 0x03;
|
||||
buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer);
|
||||
|
||||
let mut w = interface.endpoint::<Interrupt, Out>(0x02)?.writer(64);
|
||||
w.write_all(&buffer)?;
|
||||
w.flush()?;
|
||||
|
||||
Ok(Self {
|
||||
interface,
|
||||
img_buffer: Arc::new(RwLock::new(img_buffer)),
|
||||
state: Arc::new(RwLock::new(Default::default())),
|
||||
input: G13Input::new(interface.clone()),
|
||||
display: G13Display::new(interface),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn state(&self) -> State {
|
||||
*self.state.read().expect("Poisoned")
|
||||
pub fn split(self) -> (G13Display, G13Input) {
|
||||
(self.display, self.input)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum G13Event {
|
||||
Axis(u8, u8),
|
||||
Button(Button, (bool, bool)), // (old, new)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G13Input {
|
||||
interface: Interface,
|
||||
buttons: HashMap<Button, bool>,
|
||||
axis: Vec2<u8>,
|
||||
calibrated_axis: (Vec2<u8>, Vec2<u8>), // this needs to be saved/loaded
|
||||
calibrating: bool,
|
||||
}
|
||||
|
||||
impl G13Input {
|
||||
pub fn new(interface: Interface) -> Self {
|
||||
Self {
|
||||
interface,
|
||||
buttons: HashMap::new(),
|
||||
axis: Default::default(),
|
||||
calibrated_axis: (Vec2::new(127, 127), Vec2::new(127, 127)),
|
||||
calibrating: false,
|
||||
}
|
||||
}
|
||||
pub fn calibrate(mut self) -> Self {
|
||||
self.calibrating = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn read(&self) -> Result<State, Box<dyn std::error::Error>> {
|
||||
let mut state = self.state();
|
||||
pub fn with_calibration_axis(mut self, min: Vec2<u8>, max: Vec2<u8>) -> Self {
|
||||
self.calibrated_axis.0 = min;
|
||||
self.calibrated_axis.1 = max;
|
||||
self.calibrating = false;
|
||||
self
|
||||
}
|
||||
|
||||
let mut reader = self.interface.endpoint::<Interrupt, In>(0x81)?.reader(8);
|
||||
pub fn get_calibration_axis(&self) -> (Vec2<u8>, Vec2<u8>) {
|
||||
self.calibrated_axis
|
||||
}
|
||||
|
||||
fn handle_button(&mut self, button: Button, value: bool) -> Option<G13Event> {
|
||||
if let Entry::Vacant(e) = self.buttons.entry(button) {
|
||||
e.insert(value);
|
||||
if value {
|
||||
return Some(G13Event::Button(button, (!value, value)));
|
||||
}
|
||||
}
|
||||
|
||||
let prev = self.buttons[&button];
|
||||
if self.buttons[&button] == value {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.buttons.insert(button, value);
|
||||
Some(G13Event::Button(button, (prev, value)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for G13Input {
|
||||
type Item = Option<G13Event>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut reader = self
|
||||
.interface
|
||||
.endpoint::<Interrupt, In>(0x81)
|
||||
.ok()?
|
||||
.reader(8);
|
||||
let mut buf = [0; 8];
|
||||
reader.read_exact(&mut buf)?;
|
||||
reader.read_exact(&mut buf).ok()?;
|
||||
|
||||
state.x = (((buf[1] as f64) / 256.0 * 1024.0) - 512.0) as i32;
|
||||
state.y = (((buf[2] as f64) / 256.0 * 1024.0) - 512.0) as i32;
|
||||
for &(button, index, mask) in BUTTON_MAP {
|
||||
if let Some(event) = self.handle_button(button, buf[index] & mask != 0) {
|
||||
self.calibrating = false;
|
||||
return Some(Some(event));
|
||||
}
|
||||
}
|
||||
|
||||
state.buttons.action = buf[6] & 0b00000001 != 0;
|
||||
state.buttons.screen1 = buf[6] & 0b00000010 != 0;
|
||||
state.buttons.screen2 = buf[6] & 0b00000100 != 0;
|
||||
state.buttons.screen3 = buf[6] & 0b00001000 != 0;
|
||||
state.buttons.screen4 = buf[6] & 0b00010000 != 0;
|
||||
state.buttons.light = buf[7] & 0b0100000 != 0;
|
||||
let axis = Vec2::new(buf[1], buf[2]);
|
||||
|
||||
state.buttons.m1 = buf[6] & 0b00100000 != 0;
|
||||
state.buttons.m2 = buf[6] & 0b01000000 != 0;
|
||||
state.buttons.m3 = buf[6] & 0b10000000 != 0;
|
||||
state.buttons.mr = buf[7] & 0b00000001 != 0;
|
||||
if self.axis == axis {
|
||||
return Some(None);
|
||||
}
|
||||
|
||||
state.buttons.g1 = buf[3] & 0b00000001 != 0;
|
||||
state.buttons.g2 = buf[3] & 0b00000010 != 0;
|
||||
state.buttons.g3 = buf[3] & 0b00000100 != 0;
|
||||
state.buttons.g4 = buf[3] & 0b00001000 != 0;
|
||||
state.buttons.g5 = buf[3] & 0b00010000 != 0;
|
||||
state.buttons.g6 = buf[3] & 0b00100000 != 0;
|
||||
state.buttons.g7 = buf[3] & 0b01000000 != 0;
|
||||
state.buttons.g8 = buf[3] & 0b10000000 != 0;
|
||||
self.axis = axis;
|
||||
|
||||
state.buttons.g9 = buf[4] & 0b00000001 != 0;
|
||||
state.buttons.g10 = buf[4] & 0b00000010 != 0;
|
||||
state.buttons.g11 = buf[4] & 0b00000100 != 0;
|
||||
state.buttons.g12 = buf[4] & 0b00001000 != 0;
|
||||
state.buttons.g13 = buf[4] & 0b00010000 != 0;
|
||||
state.buttons.g14 = buf[4] & 0b00100000 != 0;
|
||||
state.buttons.g15 = buf[4] & 0b01000000 != 0;
|
||||
state.buttons.g16 = buf[4] & 0b10000000 != 0;
|
||||
self.calibrated_axis.0.x = self.calibrated_axis.0.x.min(axis.x);
|
||||
self.calibrated_axis.1.x = self.calibrated_axis.1.x.max(axis.x);
|
||||
self.calibrated_axis.0.y = self.calibrated_axis.0.y.min(axis.y);
|
||||
self.calibrated_axis.1.y = self.calibrated_axis.1.y.max(axis.y);
|
||||
|
||||
state.buttons.g17 = buf[5] & 0b00000001 != 0;
|
||||
state.buttons.g18 = buf[5] & 0b00000010 != 0;
|
||||
state.buttons.g19 = buf[5] & 0b00000100 != 0;
|
||||
state.buttons.g20 = buf[5] & 0b00001000 != 0;
|
||||
state.buttons.g21 = buf[5] & 0b00010000 != 0;
|
||||
state.buttons.g22 = buf[5] & 0b00100000 != 0;
|
||||
let (xmin, xmax) = (self.calibrated_axis.0.x, self.calibrated_axis.1.x);
|
||||
let (ymin, ymax) = (self.calibrated_axis.0.y, self.calibrated_axis.1.y);
|
||||
|
||||
state.buttons.stick1 = buf[7] & 0b00000010 != 0;
|
||||
state.buttons.stick2 = buf[7] & 0b00000100 != 0;
|
||||
state.buttons.stick3 = buf[7] & 0b00001000 != 0;
|
||||
let x_output = map_range(self.axis.x, xmin, xmax);
|
||||
let y_output = map_range(self.axis.y, ymin, ymax);
|
||||
|
||||
*self.state.write().expect("Poisoned") = state;
|
||||
Some(Some(G13Event::Axis(x_output as u8, y_output as u8)))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(state)
|
||||
fn map_range(v: u8, in_min: u8, in_max: u8) -> f64 {
|
||||
if in_min == in_max {
|
||||
return 0.0;
|
||||
}
|
||||
255.0 * (v as f64 - in_min as f64) / (in_max as f64 - in_min as f64)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G13Display {
|
||||
interface: Interface,
|
||||
img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>,
|
||||
}
|
||||
|
||||
impl G13Display {
|
||||
pub fn new(interface: Interface) -> Self {
|
||||
let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8];
|
||||
// let mut buffer = [0u8; G13_LCD_BUF_SIZE as usize + 32 + 8];
|
||||
// buffer[0] = 0x03;
|
||||
// buffer[32..G13_LCD_BUF_SIZE as usize + 32 + 8].copy_from_slice(&img_buffer);
|
||||
|
||||
Self {
|
||||
interface,
|
||||
img_buffer: Arc::new(RwLock::new(img_buffer)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -202,9 +281,13 @@ impl G13 {
|
||||
w.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Size {
|
||||
Size::new(G13_LCD_COLUMNS as u32, G13_LCD_ROWS as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Dimensions for G13 {
|
||||
impl Dimensions for G13Display {
|
||||
fn bounding_box(&self) -> Rectangle {
|
||||
Rectangle::new(
|
||||
Point::new(0, 0),
|
||||
@@ -213,7 +296,7 @@ impl Dimensions for G13 {
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for G13 {
|
||||
impl DrawTarget for G13Display {
|
||||
type Color = BinaryColor;
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user