Can i haz Structure?
This commit is contained in:
@@ -7,6 +7,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crossbeam_channel::{Receiver, bounded};
|
||||
use embedded_graphics_core::{
|
||||
pixelcolor::BinaryColor,
|
||||
prelude::{Dimensions, DrawTarget, Point, Size},
|
||||
@@ -24,6 +25,10 @@ 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 DEADZONE: f32 = 10.0;
|
||||
const CENTER: f32 = 127.5;
|
||||
const RANGE: f32 = 117.5;
|
||||
|
||||
const BUTTON_MAP: &[(Button, usize, u8)] = &[
|
||||
// buf[6]
|
||||
(Button::Action, 6, 0b00000001),
|
||||
@@ -85,14 +90,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct G13 {
|
||||
display: G13Display,
|
||||
input: G13Input,
|
||||
rx: Option<Receiver<G13Event>>,
|
||||
interface: Interface,
|
||||
img_buffer: Arc<RwLock<[u8; G13_LCD_BUF_SIZE as usize + 8]>>,
|
||||
}
|
||||
|
||||
impl G13 {
|
||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let img_buffer = [0u8; G13_LCD_BUF_SIZE as usize + 8];
|
||||
|
||||
let Ok(mut devices) = nusb::list_devices().wait() else {
|
||||
return Err("No devices found".into());
|
||||
};
|
||||
@@ -113,30 +120,43 @@ impl G13 {
|
||||
Err(e) => return Err(format!("Unable to claim interface: {:#?}", e).into()),
|
||||
};
|
||||
|
||||
let input = G13Input::new(interface.clone());
|
||||
let (tx, rx) = bounded(0);
|
||||
|
||||
let _tx = tx.clone();
|
||||
std::thread::spawn(move || {
|
||||
for event in input {
|
||||
let Some(event) = event else {
|
||||
continue;
|
||||
};
|
||||
if _tx.send(event).is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Self {
|
||||
input: G13Input::new(interface.clone()),
|
||||
display: G13Display::new(interface),
|
||||
interface,
|
||||
img_buffer: Arc::new(RwLock::new(img_buffer)),
|
||||
rx: Some(rx),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn split(self) -> (G13Display, G13Input) {
|
||||
(self.display, self.input)
|
||||
pub fn events(&mut self) -> Receiver<G13Event> {
|
||||
self.rx.take().expect("events() can only be called once")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum G13Event {
|
||||
Axis(u8, u8),
|
||||
Axis(f32, f32),
|
||||
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,
|
||||
axis: Vec2<f32>,
|
||||
}
|
||||
|
||||
impl G13Input {
|
||||
@@ -145,25 +165,8 @@ impl G13Input {
|
||||
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 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
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -197,60 +200,39 @@ impl Iterator for G13Input {
|
||||
|
||||
for &(button, index, mask) in BUTTON_MAP {
|
||||
if let Some(event) = self.handle_button(button, buf[index] & mask != 0) {
|
||||
self.calibrating = false;
|
||||
// self.calibrating = false;
|
||||
return Some(Some(event));
|
||||
}
|
||||
}
|
||||
|
||||
let axis = Vec2::new(buf[1], buf[2]);
|
||||
|
||||
if self.axis == axis {
|
||||
let mut input = Vec2::new(axis.x as f32 - CENTER, axis.y as f32 - CENTER);
|
||||
|
||||
input.x = apply_deadzone(input.x);
|
||||
input.y = apply_deadzone(input.y);
|
||||
|
||||
if self.axis == input {
|
||||
return Some(None);
|
||||
}
|
||||
|
||||
self.axis = axis;
|
||||
self.axis = input;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
let x_output = map_range(self.axis.x, xmin, xmax);
|
||||
let y_output = map_range(self.axis.y, ymin, ymax);
|
||||
|
||||
Some(Some(G13Event::Axis(x_output as u8, y_output as u8)))
|
||||
Some(Some(G13Event::Axis(input.x / RANGE, input.y / RANGE)))
|
||||
}
|
||||
}
|
||||
|
||||
fn map_range(v: u8, in_min: u8, in_max: u8) -> f64 {
|
||||
if in_min == in_max {
|
||||
return 0.0;
|
||||
fn apply_deadzone(v: f32) -> f32 {
|
||||
if v.abs() <= DEADZONE {
|
||||
0.0
|
||||
} else if v > 0.0 {
|
||||
v - DEADZONE
|
||||
} else {
|
||||
v + DEADZONE
|
||||
}
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
impl G13 {
|
||||
pub fn set_lcd_color(&self, r: u8, g: u8, b: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||
self.interface
|
||||
.control_out(
|
||||
@@ -287,7 +269,7 @@ impl G13Display {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dimensions for G13Display {
|
||||
impl Dimensions for G13 {
|
||||
fn bounding_box(&self) -> Rectangle {
|
||||
Rectangle::new(
|
||||
Point::new(0, 0),
|
||||
@@ -296,7 +278,7 @@ impl Dimensions for G13Display {
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawTarget for G13Display {
|
||||
impl DrawTarget for G13 {
|
||||
type Color = BinaryColor;
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user