Files
asusctl/simulators/src/simulator.rs
2023-07-03 20:14:14 +12:00

194 lines
7.1 KiB
Rust

use std::env;
use std::error::Error;
use std::str::FromStr;
use log::error;
use rog_anime::usb::{PROD_ID, VENDOR_ID};
use rog_anime::{AnimeType, USB_PREFIX2};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use uhid_virt::{Bus, CreateParams, UHIDDevice};
mod animatrix;
use animatrix::*;
pub struct VirtAnimeMatrix {
device: UHIDDevice<std::fs::File>,
buffer: [u8; 640],
animatrix: AniMatrix,
}
impl VirtAnimeMatrix {
pub fn new(model: AnimeType) -> Self {
VirtAnimeMatrix {
buffer: [0; 640],
animatrix: AniMatrix::new(model),
device: UHIDDevice::create(CreateParams {
name: String::from("ROG_Virtual Anime Matrix"),
phys: String::from(""),
uniq: String::from(""),
bus: Bus::USB,
vendor: VENDOR_ID as u32,
product: PROD_ID as u32,
version: 0,
country: 0,
// This is a device which emits the usage code as a whole, rather than as bits
rd_data: [
0x06, 0x31, 0xff, // Usage Page (Vendor Defined 0xFF31)
0x09, 0x76, // Usage (0x76)
0xa1, 0x01, // Collection (Application)
0x85, 0x5a, // Report ID (90)
0x19, 0x00, // Usage Minimum (0x00)
0x2a, 0xff, 0x00, // Usage Maximum (0xFF)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x05, // Report Count (5)
0x81,
0x00, /* Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null
* Position) */
0x19, 0x00, // Usage Minimum (0x00)
0x2a, 0xff, 0x00, // Usage Maximum (0xFF)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x3f, // Report Count (63)
0xb1,
0x00, /* Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null
* Position,Non-volatile) */
0xc0, // End Collection
0x06, 0x31, 0xff, // Usage Page (Vendor Defined 0xFF31)
0x09, 0x80, // Usage (0x80)
0xa1, 0x01, // Collection (Application)
0x85, 0x5e, // Report ID (94)
0x19, 0x00, // Usage Minimum (0x00)
0x2a, 0xff, 0x00, // Usage Maximum (0xFF)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x05, // Report Count (5)
0x81,
0x00, /* Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null
* Position) */
0x19, 0x00, // Usage Minimum (0x00)
0x2a, 0xff, 0x00, // Usage Maximum (0xFF)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x96, 0x7f, 0x02, // Report Count (639)
0xb1,
0x00, /* Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null
* Position,Non-volatile) */
0xc0, /* End Collection */
/* 85 bytes */
]
.to_vec(),
})
.map_err(|err| error!("Could not create virtual device: {:?}", err))
.expect("Could not create virtual device"),
}
}
// /// A single on/off key press
// pub fn press(&mut self, input: [u8; 32]) {
// self.device.write(&input).unwrap();
// let mut reset = [0u8; 32];
// reset[0] = input[0];
// self.device.write(&reset).unwrap();
// }
pub fn read(&mut self) {
if let Ok(uhid_virt::OutputEvent::Output { data }) = self.device.read() {
for (i, b) in self.buffer.iter_mut().enumerate() {
*b = 0;
if let Some(n) = data.get(i) {
*b = *n;
}
}
}
}
}
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<String> = env::args().collect();
if args.len() <= 1 {
println!("Must supply arg, one of <GA401, GA402, GU604>");
return Ok(());
}
let anime_type = AnimeType::from_str(&args[1])?;
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
.window("rust-sdl2 demo", 1260, 760)
.position_centered()
.build()
.unwrap();
let mut canvas = window.into_canvas().build().unwrap();
let mut dev = VirtAnimeMatrix::new(anime_type);
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear();
let mut event_pump = sdl_context.event_pump().unwrap();
'running: loop {
dev.read(); // it's blocking, and damned hard to sync with arc/mutex
// let one = dev.buffer[0..7] != USB_PREFIX2;
let index = dev.buffer[3];
let w = dev.animatrix.led_shape().horizontal * 6;
let h = dev.animatrix.led_shape().vertical * 6;
let mut y_offset = 0;
for (y_count, row) in dev.animatrix.rows().iter().enumerate() {
if row.0 == index {
let start = row.1;
let end = start + row.2;
if row.1 < 10 && row.2 < 15 {
if index == 0x74 {
y_offset = 1;
} else if index == 0xe7 {
y_offset = 2;
}
}
for (x_count, b) in dev.buffer[start..=end].iter().enumerate() {
canvas.set_draw_color(Color::RGB(*b, *b, *b));
let x: i32 = w + x_count as i32 * w
- if (y_count + y_offset as usize) % 2 != 0 {
0
} else {
w / 2
}
+ row.3 * w;
let y = y_count as i32 * h - y_offset * h;
canvas
.fill_rect(Rect::new(x, y, w as u32, h as u32))
.unwrap();
}
}
}
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'running,
_ => {}
}
}
if dev.buffer[0..7] == USB_PREFIX2 {
canvas.present();
}
// ::std::thread::sleep(Duration::from_millis(50));
}
Ok(())
}