Moved USB and Config functions to their own files

This commit is contained in:
sebgab 2023-02-06 11:46:27 +01:00
parent d9aae15559
commit 32267df99c
3 changed files with 141 additions and 127 deletions

78
src/config_parsing.rs Normal file
View File

@ -0,0 +1,78 @@
extern crate json;
extern crate colored;
use std::path::Path;
#[derive(Debug)]
pub struct KeyboardLighting {
pub lighting_type: String,
pub rows: u16,
pub cols: u16
}
#[derive(Debug, Clone)]
pub struct KeyboardLayout {
pub rows: u16,
pub cols: u16,
pub keys: Vec<String>
}
#[derive(Debug)]
pub struct KeyboardConfig {
pub name: String,
pub vendor_id: u16,
pub product_id: u16,
pub layout: KeyboardLayout,
pub lighting: KeyboardLighting
}
pub fn parse_config(config_path: &Path) -> KeyboardConfig{
let mut parsed_json = json::parse(&std::fs::read_to_string(config_path).unwrap()).unwrap();
// General info
let extracted_name: String = parsed_json["name"].as_str().expect("ERROR: Failed to parse name").to_string();
let extracted_vendor_id: u16 = u16::from_str_radix(parsed_json["vendor_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
let extracted_product_id: u16 = u16::from_str_radix(parsed_json["product_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
// Layout
let extracted_layout_rows: u16 = parsed_json["layout"]["rows"].as_u16().expect("ERROR: Failed to parse layout rows");
let extracted_layout_cols: u16 = parsed_json["layout"]["cols"].as_u16().expect("ERROR: Failed to parse layout cols");
let mut extracted_layout_keys: Vec<String> = Vec::new();
let mut keys: std::collections::VecDeque<String> = std::collections::VecDeque::new();
for i in 0..extracted_layout_rows {
let mut row: json::JsonValue = parsed_json["layout"]["keys"].pop();
for j in 0..extracted_layout_cols {
keys.push_front(row.pop().as_str().expect("ERROR: Failed to extract key names").to_string());
}
}
for i in 0..keys.len() {
extracted_layout_keys.push(keys.pop_front().expect("ERROR: Empty key value"));
}
let keyboard_layout = KeyboardLayout {
rows: extracted_layout_rows,
cols: extracted_layout_cols,
keys: extracted_layout_keys
};
// Lighting
let extracted_lighting_type: String = parsed_json["lighting"]["type"].as_str().expect("ERROR: Failed to parse lighting type").to_string();
let extracted_lighting_rows: u16 = parsed_json["lighting"]["layout"]["rows"].as_u16().expect("ERROR: Failed to parse lighting rows");
let extracted_lighting_cols: u16 = parsed_json["lighting"]["layout"]["cols"].as_u16().expect("ERROR: Failed to parse lighting cols");
let keyboard_lighting = KeyboardLighting {
lighting_type: extracted_lighting_type,
rows: extracted_lighting_rows,
cols: extracted_lighting_cols
};
let keyboard_config = KeyboardConfig {
name: extracted_name,
vendor_id: extracted_vendor_id,
product_id: extracted_product_id,
layout: keyboard_layout,
lighting: keyboard_lighting
};
return keyboard_config;
}

View File

@ -1,38 +1,16 @@
extern crate libusb;
extern crate colored;
extern crate json;
// Config
mod config_parsing;
use config_parsing::*;
use std::path::Path;
use std::{cell::Cell, rc::Rc};
use colored::Colorize;
// USB
mod usb_communications;
use usb_communications::*;
use iced::{Sandbox, Settings, Vector};
use iced::widget::{Row, Column, Button, Text, Container, Slider};
#[derive(Debug)]
struct KeyboardLighting {
lighting_type: String,
rows: u16,
cols: u16
}
#[derive(Debug, Clone)]
struct KeyboardLayout {
rows: u16,
cols: u16,
keys: Vec<String>
}
#[derive(Debug)]
struct KeyboardConfig {
name: String,
vendor_id: u16,
product_id: u16,
layout: KeyboardLayout,
lighting: KeyboardLighting
}
use iced::widget::{Row, Column, Button, Text, Slider};
/*
#[derive(Debug)]
@ -64,63 +42,12 @@ enum MainPageMessages {
row: u8,
col: u8
},
UpdatedSlider_R(u8),
UpdatedSlider_G(u8),
UpdatedSlider_B(u8)
UpdatedSliderRed(u8),
UpdatedSliderGreen(u8),
UpdatedSliderBlue(u8)
}
fn parse_config(config_path: &Path) -> KeyboardConfig{
let mut parsed_json = json::parse(&std::fs::read_to_string(config_path).unwrap()).unwrap();
// General info
let extracted_name: String = parsed_json["name"].as_str().expect("ERROR: Failed to parse name").to_string();
let extracted_vendor_id: u16 = u16::from_str_radix(parsed_json["vendor_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
let extracted_product_id: u16 = u16::from_str_radix(parsed_json["product_id"].as_str().expect("ERROR: Failed to parse name"), 16).unwrap();
// Layout
let extracted_layout_rows: u16 = parsed_json["layout"]["rows"].as_u16().expect("ERROR: Failed to parse layout rows");
let extracted_layout_cols: u16 = parsed_json["layout"]["cols"].as_u16().expect("ERROR: Failed to parse layout cols");
let mut extracted_layout_keys: Vec<String> = Vec::new();
let mut keys: std::collections::VecDeque<String> = std::collections::VecDeque::new();
for i in 0..extracted_layout_rows {
let mut row: json::JsonValue = parsed_json["layout"]["keys"].pop();
for j in 0..extracted_layout_cols {
keys.push_front(row.pop().as_str().expect("ERROR: Failed to extract key names").to_string());
}
}
for i in 0..keys.len() {
extracted_layout_keys.push(keys.pop_front().expect("ERROR: Empty key value"));
}
let keyboard_layout = KeyboardLayout {
rows: extracted_layout_rows,
cols: extracted_layout_cols,
keys: extracted_layout_keys
};
// Lighting
let extracted_lighting_type: String = parsed_json["lighting"]["type"].as_str().expect("ERROR: Failed to parse lighting type").to_string();
let extracted_lighting_rows: u16 = parsed_json["lighting"]["layout"]["rows"].as_u16().expect("ERROR: Failed to parse lighting rows");
let extracted_lighting_cols: u16 = parsed_json["lighting"]["layout"]["cols"].as_u16().expect("ERROR: Failed to parse lighting cols");
let keyboard_lighting = KeyboardLighting {
lighting_type: extracted_lighting_type,
rows: extracted_lighting_rows,
cols: extracted_lighting_cols
};
let keyboard_config = KeyboardConfig {
name: extracted_name,
vendor_id: extracted_vendor_id,
product_id: extracted_product_id,
layout: keyboard_layout,
lighting: keyboard_lighting
};
return keyboard_config;
}
fn main() -> Result<(), iced::Error> {
// Printing the parsed config for debug purposes
@ -131,44 +58,6 @@ fn main() -> Result<(), iced::Error> {
MainPage::run(Settings::default())
}
// USB Code
fn send_lighting_update(col: u8, row: u8, r: u8, g: u8, b: u8, _a: u8) {
println!("Sending lighting update!");
let config: KeyboardConfig = parse_config(&Path::new("numpad_config.json"));
let context = libusb::Context::new().unwrap(); // Get a new USB context
for device in context.devices().unwrap().iter() { // Iterate through all the devices
let device_desc = device.device_descriptor().unwrap(); // Get a descriptor for the device
if device_desc.vendor_id() == config.vendor_id && device_desc.product_id() == config.product_id { // Check if the devie is the device we are looking for
println!("Supported keyboard discovered, claiming it.");
let mut device_handle: libusb::DeviceHandle = device.open().unwrap(); // Get a handle for the device
if device_handle.kernel_driver_active(0).unwrap() { // If the device has an active kernel driver, detach it
println!("Interface has kernel driver, detaching...");
device_handle.detach_kernel_driver(0).unwrap();
}
device_handle.claim_interface(0).unwrap(); // Now that the device is free we claim it
match device_handle.write_control(
libusb::request_type(libusb::Direction::Out, libusb::RequestType::Class, libusb::Recipient::Interface), // The request is outband and uses HID specific features tergeting an interface
0x09, 0x0301, 0, // We want to send a SET_REPORT request, that is a custom feature, with the feature being lighting, we want to send it to endpoint 0
&[r, g, b, row, col], std::time::Duration::from_secs(1)) { // First we send the row, then the column, then the Red, Green, Blue, and lastly the brightness
Ok(n) => {
println!("{}", format!("Successfully wrote {} bytes!", n).green());
},
Err(e) => {
eprintln!("{}{:?}", format!("Failed to write with error: ").red().bold(), e);
}
}
device_handle.release_interface(0).unwrap(); // Release the interface
device_handle.attach_kernel_driver(0).unwrap(); // Re-attach the kernel driver
}
}
}
// UI Code
impl Sandbox for MainPage {
@ -200,9 +89,9 @@ impl Sandbox for MainPage {
fn update(&mut self, message: Self::Message) {
match message {
MainPageMessages::UpdatedSlider_R(value) => { self.slider_values.slider_r = value; }
MainPageMessages::UpdatedSlider_G(value) => { self.slider_values.slider_g = value; }
MainPageMessages::UpdatedSlider_B(value) => { self.slider_values.slider_b = value; }
MainPageMessages::UpdatedSliderRed(value) => { self.slider_values.slider_r = value; }
MainPageMessages::UpdatedSliderGreen(value) => { self.slider_values.slider_g = value; }
MainPageMessages::UpdatedSliderBlue(value) => { self.slider_values.slider_b = value; }
MainPageMessages::UpdateColor { row, col } => {
println!("{:?}", message);
send_lighting_update(col, row, self.slider_values.slider_r, self.slider_values.slider_g, self.slider_values.slider_b, 0x0);
@ -283,9 +172,9 @@ impl Sandbox for MainPage {
// Create the color selector
let slider_r = Slider::new(0..=255, self.slider_values.slider_r, MainPageMessages::UpdatedSlider_R);
let slider_g = Slider::new(0..=255, self.slider_values.slider_g, MainPageMessages::UpdatedSlider_G);
let slider_b = Slider::new(0..=255, self.slider_values.slider_b, MainPageMessages::UpdatedSlider_B);
let slider_r = Slider::new(0..=255, self.slider_values.slider_r, MainPageMessages::UpdatedSliderRed);
let slider_g = Slider::new(0..=255, self.slider_values.slider_g, MainPageMessages::UpdatedSliderGreen);
let slider_b = Slider::new(0..=255, self.slider_values.slider_b, MainPageMessages::UpdatedSliderBlue);
let color_selector_col = Column::new()
.push(slider_r)
.push(slider_g)

47
src/usb_communications.rs Normal file
View File

@ -0,0 +1,47 @@
extern crate libusb;
extern crate colored;
use crate::config_parsing::*;
use std::path::Path;
use colored::Colorize;
// USB Code
pub fn send_lighting_update(col: u8, row: u8, r: u8, g: u8, b: u8, _a: u8) {
println!("Sending lighting update!");
let config: KeyboardConfig = parse_config(&Path::new("numpad_config.json"));
let context = libusb::Context::new().unwrap(); // Get a new USB context
for device in context.devices().unwrap().iter() { // Iterate through all the devices
let device_desc = device.device_descriptor().unwrap(); // Get a descriptor for the device
if device_desc.vendor_id() == config.vendor_id && device_desc.product_id() == config.product_id { // Check if the devie is the device we are looking for
println!("Supported keyboard discovered, claiming it.");
let mut device_handle: libusb::DeviceHandle = device.open().unwrap(); // Get a handle for the device
if device_handle.kernel_driver_active(0).unwrap() { // If the device has an active kernel driver, detach it
println!("Interface has kernel driver, detaching...");
device_handle.detach_kernel_driver(0).unwrap();
}
device_handle.claim_interface(0).unwrap(); // Now that the device is free we claim it
match device_handle.write_control(
libusb::request_type(libusb::Direction::Out, libusb::RequestType::Class, libusb::Recipient::Interface), // The request is outband and uses HID specific features tergeting an interface
0x09, 0x0301, 0, // We want to send a SET_REPORT request, that is a custom feature, with the feature being lighting, we want to send it to endpoint 0
&[r, g, b, row, col], std::time::Duration::from_secs(1)) { // First we send the row, then the column, then the Red, Green, Blue, and lastly the brightness
Ok(n) => {
println!("{}", format!("Successfully wrote {} bytes!", n).green());
},
Err(e) => {
eprintln!("{}{:?}", format!("Failed to write with error: ").red().bold(), e);
}
}
device_handle.release_interface(0).unwrap(); // Release the interface
device_handle.attach_kernel_driver(0).unwrap(); // Re-attach the kernel driver
}
}
}