Pre-bevy minigame commit
This commit is contained in:
14
driver/src/joystick/axis.rs
Normal file
14
driver/src/joystick/axis.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Axis {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
pub fn all_axes() -> slice::Iter<'static, Self> {
|
||||
use Axis::*;
|
||||
[X, Y].iter()
|
||||
}
|
||||
}
|
||||
58
driver/src/joystick/button.rs
Normal file
58
driver/src/joystick/button.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use std::slice;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Button {
|
||||
Action,
|
||||
Screen1,
|
||||
Screen2,
|
||||
Screen3,
|
||||
Screen4,
|
||||
Light,
|
||||
|
||||
M1,
|
||||
M2,
|
||||
M3,
|
||||
MR,
|
||||
|
||||
G1,
|
||||
G2,
|
||||
G3,
|
||||
G4,
|
||||
G5,
|
||||
G6,
|
||||
G7,
|
||||
|
||||
G8,
|
||||
G9,
|
||||
G10,
|
||||
G11,
|
||||
G12,
|
||||
G13,
|
||||
G14,
|
||||
|
||||
G15,
|
||||
G16,
|
||||
G17,
|
||||
G18,
|
||||
G19,
|
||||
|
||||
G20,
|
||||
G21,
|
||||
G22,
|
||||
|
||||
Stick1,
|
||||
Stick2,
|
||||
Stick3,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
pub fn all_buttons() -> slice::Iter<'static, Self> {
|
||||
use Button::*;
|
||||
[
|
||||
Action, Screen1, Screen2, Screen3, Screen4, Light, M1, M2, M3, MR, G1, G2, G3, G4, G5,
|
||||
G6, G7, G8, G9, G10, G11, G12, G13, G14, G15, G16, G17, G18, G19, G20, G21, G22,
|
||||
Stick1, Stick2, Stick3,
|
||||
]
|
||||
.iter()
|
||||
}
|
||||
}
|
||||
7
driver/src/joystick/mod.rs
Normal file
7
driver/src/joystick/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
// gracefully stolen from https://github.com/gwilymk/arduino-joystick/tree/master/joystick-daemon/src/joystick <3
|
||||
|
||||
mod axis;
|
||||
mod button;
|
||||
|
||||
pub use axis::Axis;
|
||||
pub use button::Button;
|
||||
241
driver/src/lib.rs
Normal file
241
driver/src/lib.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
pub mod joystick;
|
||||
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
sync::{Arc, RwLock},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use embedded_graphics_core::{
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::{Dimensions, DrawTarget, Point, Size},
|
||||
primitives::Rectangle,
|
||||
};
|
||||
use nusb::{
|
||||
Interface, MaybeFuture,
|
||||
transfer::{ControlOut, ControlType, In, Interrupt, Out, Recipient},
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G13 {
|
||||
interface: Interface,
|
||||
img_buffer: [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,
|
||||
pub previous_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,
|
||||
}
|
||||
|
||||
impl G13 {
|
||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let Ok(mut devices) = nusb::list_devices().wait() else {
|
||||
return Err("No devices found".into());
|
||||
};
|
||||
|
||||
let Some(device) = devices.find(|d| d.vendor_id() == 0x046d && d.product_id() == 0xc21c)
|
||||
else {
|
||||
return Err("No device found".into());
|
||||
};
|
||||
|
||||
let Ok(device) = device.open().wait() else {
|
||||
return Err("Unable to open device".into());
|
||||
};
|
||||
|
||||
let _ = device.detach_kernel_driver(0);
|
||||
|
||||
let interface = match device.claim_interface(0).wait() {
|
||||
Ok(i) => i,
|
||||
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,
|
||||
state: Arc::new(RwLock::new(Default::default())),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn state(&self) -> State {
|
||||
*self.state.read().expect("Poisoned")
|
||||
}
|
||||
|
||||
pub fn read(&self) -> Result<State, Box<dyn std::error::Error>> {
|
||||
let mut state = self.state();
|
||||
|
||||
state.previous_buttons = state.buttons;
|
||||
let mut reader = self.interface.endpoint::<Interrupt, In>(0x81)?.reader(8);
|
||||
let mut buf = [0; 8];
|
||||
reader.read_exact(&mut buf)?;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
state.buttons.stick1 = buf[7] & 0b00000010 != 0;
|
||||
state.buttons.stick2 = buf[7] & 0b00000100 != 0;
|
||||
state.buttons.stick3 = buf[7] & 0b00001000 != 0;
|
||||
|
||||
*self.state.write().expect("Poisoned") = state;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.interface
|
||||
.control_out(
|
||||
ControlOut {
|
||||
control_type: ControlType::Class,
|
||||
recipient: Recipient::Interface,
|
||||
request: 9,
|
||||
value: 0x307,
|
||||
index: 0,
|
||||
data: &[5, r, g, b, 0],
|
||||
},
|
||||
Duration::from_secs(2),
|
||||
)
|
||||
.wait()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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(&self.img_buffer);
|
||||
|
||||
let mut w = self.interface.endpoint::<Interrupt, Out>(0x02)?.writer(64);
|
||||
w.write_all(&buffer)?;
|
||||
w.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Dimensions for G13 {
|
||||
fn bounding_box(&self) -> Rectangle {
|
||||
Rectangle::new(
|
||||
Point::new(0, 0),
|
||||
Size::new(G13_LCD_COLUMNS as u32, G13_LCD_ROWS as u32),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for G13 {
|
||||
type Color = BinaryColor;
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
|
||||
where
|
||||
I: IntoIterator<Item = embedded_graphics_core::Pixel<Self::Color>>,
|
||||
{
|
||||
for p in pixels {
|
||||
if p.0.x < 0 || p.0.x > G13_LCD_COLUMNS - 1 || p.0.y < 0 || p.0.y > G13_LCD_ROWS - 1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let offset = p.0.x + (p.0.y / 8) * (G13_LCD_BYTES_PER_ROW) * 8;
|
||||
let mask = 1 << (p.0.y.rem_euclid(8));
|
||||
|
||||
if p.1.is_on() {
|
||||
self.img_buffer[offset as usize] |= mask;
|
||||
} else {
|
||||
self.img_buffer[offset as usize] &= !mask;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user