mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
194 lines
7.1 KiB
Rust
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(())
|
|
}
|