mirror of
https://github.com/4yn/slidershim.git
synced 2025-02-01 20:18:07 +01:00
voltex hid controller
This commit is contained in:
parent
2b20902179
commit
93240ef4af
102
src-tauri/Cargo.lock
generated
102
src-tauri/Cargo.lock
generated
@ -2,6 +2,27 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "CoreFoundation-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"mach 0.1.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "IOKit-sys"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a"
|
||||||
|
dependencies = [
|
||||||
|
"CoreFoundation-sys",
|
||||||
|
"libc",
|
||||||
|
"mach 0.1.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -1524,6 +1545,26 @@ version = "0.2.114"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50"
|
checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libudev"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libudev-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libudev-sys"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libusb1-sys"
|
name = "libusb1-sys"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -1587,6 +1628,24 @@ dependencies = [
|
|||||||
"objc-foundation",
|
"objc-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@ -1745,6 +1804,19 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cc",
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"libc",
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.17.0"
|
version = "0.17.0"
|
||||||
@ -2748,6 +2820,23 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serialport"
|
||||||
|
version = "4.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d8cd7c0f22290ee2c01457009fa6fc1cae4153d5608a924e5dc423babc2c655"
|
||||||
|
dependencies = [
|
||||||
|
"CoreFoundation-sys",
|
||||||
|
"IOKit-sys",
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"libudev",
|
||||||
|
"mach 0.2.3",
|
||||||
|
"nix 0.16.1",
|
||||||
|
"regex",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -2800,8 +2889,10 @@ dependencies = [
|
|||||||
"rusb",
|
"rusb",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serialport",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
|
"vigem-client",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3484,6 +3575,15 @@ version = "0.9.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vigem-client"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "965e349c8ec4eb36c06878b99952f35b9f459e6912419837ecb85fb5502a6de3"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -3841,7 +3941,7 @@ dependencies = [
|
|||||||
"fastrand",
|
"fastrand",
|
||||||
"futures",
|
"futures",
|
||||||
"nb-connect",
|
"nb-connect",
|
||||||
"nix",
|
"nix 0.17.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"polling",
|
"polling",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
|
@ -19,6 +19,8 @@ serde_json = "1.0"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.0.0-beta.8", features = ["api-all", "system-tray"] }
|
tauri = { version = "1.0.0-beta.8", features = ["api-all", "system-tray"] }
|
||||||
rusb = "0.9.0"
|
rusb = "0.9.0"
|
||||||
|
serialport = "4.0.1"
|
||||||
|
vigem-client = "0.1.1"
|
||||||
palette = "0.6.0"
|
palette = "0.6.0"
|
||||||
winapi = "0.3.9"
|
winapi = "0.3.9"
|
||||||
directories = "4.0.1"
|
directories = "4.0.1"
|
||||||
|
11
src-tauri/src/bin/test_serial.rs
Normal file
11
src-tauri/src/bin/test_serial.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// extern crate slidershim;
|
||||||
|
|
||||||
|
use serialport::available_ports;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let res = available_ports();
|
||||||
|
println!("{:?}", res);
|
||||||
|
let mut input = String::new();
|
||||||
|
let string = io::stdin().read_line(&mut input).unwrap();
|
||||||
|
}
|
@ -9,6 +9,31 @@ fn main() {
|
|||||||
.filter_level(log::LevelFilter::Debug)
|
.filter_level(log::LevelFilter::Debug)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
// voltex?
|
||||||
|
let config = Config::from_str(
|
||||||
|
r#"{
|
||||||
|
"deviceMode": "yuancon",
|
||||||
|
"outputMode": "gamepad-voltex",
|
||||||
|
"keyboardSensitivity": 50,
|
||||||
|
"ledMode": "reactive-voltex",
|
||||||
|
"ledSensitivity": 50
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// serial?
|
||||||
|
// let config = Config::from_str(
|
||||||
|
// r#"{
|
||||||
|
// "deviceMode": "yuancon",
|
||||||
|
// "outputMode": "kb-32-tasoller",
|
||||||
|
// "keyboardSensitivity": 50,
|
||||||
|
// "ledMode": "serial",
|
||||||
|
// "ledSerialPort": "COM5"
|
||||||
|
// }"#,
|
||||||
|
// )
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
// basic
|
||||||
// let config = Config::from_str(
|
// let config = Config::from_str(
|
||||||
// r#"{
|
// r#"{
|
||||||
// "deviceMode": "yuancon",
|
// "deviceMode": "yuancon",
|
||||||
@ -20,17 +45,7 @@ fn main() {
|
|||||||
// )
|
// )
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
let config = Config::from_str(
|
// tasoller/
|
||||||
r#"{
|
|
||||||
"deviceMode": "yuancon",
|
|
||||||
"outputMode": "kb-voltex",
|
|
||||||
"keyboardSensitivity": 50,
|
|
||||||
"ledMode": "reactive-voltex",
|
|
||||||
"ledSensitivity": 50
|
|
||||||
}"#,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// let config = Config::from_str(
|
// let config = Config::from_str(
|
||||||
// r#"{
|
// r#"{
|
||||||
// "deviceMode": "tasoller-two",
|
// "deviceMode": "tasoller-two",
|
||||||
|
@ -20,6 +20,7 @@ pub enum KeyboardLayout {
|
|||||||
Yuancon,
|
Yuancon,
|
||||||
Deemo,
|
Deemo,
|
||||||
Voltex,
|
Voltex,
|
||||||
|
GamepadVoltex,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -52,6 +53,9 @@ pub enum LedMode {
|
|||||||
Websocket {
|
Websocket {
|
||||||
url: String,
|
url: String,
|
||||||
},
|
},
|
||||||
|
Serial {
|
||||||
|
port: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -95,8 +99,12 @@ impl Config {
|
|||||||
layout: KeyboardLayout::Voltex,
|
layout: KeyboardLayout::Voltex,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
|
"gamepad-voltex" => OutputMode::Keyboard {
|
||||||
|
layout: KeyboardLayout::GamepadVoltex,
|
||||||
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
|
},
|
||||||
"websocket" => OutputMode::Websocket {
|
"websocket" => OutputMode::Websocket {
|
||||||
url: v["outputWebsocketUrl"].to_string(),
|
url: v["outputWebsocketUrl"].as_str()?.to_string(),
|
||||||
},
|
},
|
||||||
_ => panic!("Invalid output mode"),
|
_ => panic!("Invalid output mode"),
|
||||||
},
|
},
|
||||||
@ -121,7 +129,10 @@ impl Config {
|
|||||||
"attract" => LedMode::Attract,
|
"attract" => LedMode::Attract,
|
||||||
"test" => LedMode::Test,
|
"test" => LedMode::Test,
|
||||||
"websocket" => LedMode::Websocket {
|
"websocket" => LedMode::Websocket {
|
||||||
url: v["ledWebsocketUrl"].to_string(),
|
url: v["ledWebsocketUrl"].as_str()?.to_string(),
|
||||||
|
},
|
||||||
|
"serial" => LedMode::Serial {
|
||||||
|
port: v["ledSerialPort"].as_str()?.to_string(),
|
||||||
},
|
},
|
||||||
_ => panic!("Invalid led mode"),
|
_ => panic!("Invalid led mode"),
|
||||||
},
|
},
|
||||||
@ -137,7 +148,8 @@ impl Config {
|
|||||||
"keyboardSensitivity": 20,
|
"keyboardSensitivity": 20,
|
||||||
"outputWebsocketUrl": "localhost:3000",
|
"outputWebsocketUrl": "localhost:3000",
|
||||||
"ledSensitivity": 20,
|
"ledSensitivity": 20,
|
||||||
"ledWebsocketUrl": "localhost:3001"
|
"ledWebsocketUrl": "localhost:3001",
|
||||||
|
"ledSerialPort": "COM5"
|
||||||
}"#,
|
}"#,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
error,
|
error::Error,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
thread,
|
thread,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
@ -12,27 +12,10 @@ use rusb::{self, DeviceHandle, GlobalContext};
|
|||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::DeviceMode,
|
config::DeviceMode,
|
||||||
controller_state::{ControllerState, FullState, LedState},
|
controller_state::{ControllerState, FullState, LedState},
|
||||||
|
utils::{Buffer, ShimError},
|
||||||
worker::Job,
|
worker::Job,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Buffer {
|
|
||||||
pub data: [u8; 256],
|
|
||||||
pub len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Buffer {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Buffer {
|
|
||||||
data: [0; 256],
|
|
||||||
len: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn slice(&self) -> &[u8] {
|
|
||||||
&self.data[0..self.len]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
|
type HidReadCallback = fn(&Buffer, &mut ControllerState) -> ();
|
||||||
type HidLedCallback = fn(&mut Buffer, &LedState) -> ();
|
type HidLedCallback = fn(&mut Buffer, &LedState) -> ();
|
||||||
|
|
||||||
@ -204,11 +187,12 @@ impl HidDeviceJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_impl(&mut self) -> Result<(), Box<dyn error::Error>> {
|
fn setup_impl(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
info!("Device finding vid {} pid {}", self.vid, self.pid);
|
info!("Device finding vid {} pid {}", self.vid, self.pid);
|
||||||
let handle = rusb::open_device_with_vid_pid(self.vid, self.pid);
|
let handle = rusb::open_device_with_vid_pid(self.vid, self.pid);
|
||||||
if handle.is_none() {
|
if handle.is_none() {
|
||||||
error!("Could not find device");
|
error!("Device not found");
|
||||||
|
return Err(Box::new(ShimError));
|
||||||
}
|
}
|
||||||
let mut handle = handle.unwrap();
|
let mut handle = handle.unwrap();
|
||||||
info!("Device found {:?}", handle);
|
info!("Device found {:?}", handle);
|
||||||
@ -229,8 +213,17 @@ impl HidDeviceJob {
|
|||||||
const TIMEOUT: Duration = Duration::from_millis(20);
|
const TIMEOUT: Duration = Duration::from_millis(20);
|
||||||
|
|
||||||
impl Job for HidDeviceJob {
|
impl Job for HidDeviceJob {
|
||||||
fn setup(&mut self) {
|
fn setup(&mut self) -> bool {
|
||||||
self.setup_impl().unwrap();
|
match self.setup_impl() {
|
||||||
|
Ok(r) => {
|
||||||
|
info!("Device OK");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Device setup failed, exiting thread early");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
@ -276,7 +269,9 @@ impl Job for HidDeviceJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {
|
fn teardown(&mut self) {
|
||||||
let handle = self.handle.as_mut().unwrap();
|
if self.handle.is_some() {
|
||||||
handle.release_interface(0).ok();
|
let handle = self.handle.as_mut().unwrap();
|
||||||
|
handle.release_interface(0).ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
src-tauri/src/slider_io/gamepad.rs
Normal file
101
src-tauri/src/slider_io/gamepad.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use vigem_client::{Client, TargetId, XButtons, XGamepad, Xbox360Wired};
|
||||||
|
|
||||||
|
use crate::slider_io::{output::OutputHandler, voltex::VoltexState};
|
||||||
|
|
||||||
|
pub struct GamepadOutput {
|
||||||
|
target: Xbox360Wired<Client>,
|
||||||
|
gamepad: XGamepad,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GamepadOutput {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let client = Client::connect().unwrap();
|
||||||
|
let mut target = Xbox360Wired::new(client, TargetId::XBOX360_WIRED);
|
||||||
|
target.plugin().unwrap();
|
||||||
|
target.wait_ready().unwrap();
|
||||||
|
Self {
|
||||||
|
target,
|
||||||
|
gamepad: XGamepad::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputHandler for GamepadOutput {
|
||||||
|
fn tick(&mut self, flat_controller_state: &Vec<bool>) {
|
||||||
|
let voltex_state = VoltexState::from_flat(flat_controller_state);
|
||||||
|
|
||||||
|
let buttons = voltex_state
|
||||||
|
.bt
|
||||||
|
.iter()
|
||||||
|
.chain(voltex_state.fx.iter())
|
||||||
|
.chain(voltex_state.extra.iter())
|
||||||
|
.zip([
|
||||||
|
XButtons::A,
|
||||||
|
XButtons::B,
|
||||||
|
XButtons::X,
|
||||||
|
XButtons::Y,
|
||||||
|
XButtons::LB,
|
||||||
|
XButtons::RB,
|
||||||
|
XButtons::START,
|
||||||
|
XButtons::BACK,
|
||||||
|
XButtons::GUIDE,
|
||||||
|
])
|
||||||
|
.fold(0, |buttons, (state, code)| {
|
||||||
|
buttons
|
||||||
|
| match state {
|
||||||
|
true => code,
|
||||||
|
false => 0,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let lx = (match voltex_state.laser[0] {
|
||||||
|
true => -30000,
|
||||||
|
false => 0,
|
||||||
|
} + match voltex_state.laser[1] {
|
||||||
|
true => 30000,
|
||||||
|
false => 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
let rx = (match voltex_state.laser[2] {
|
||||||
|
true => -30000,
|
||||||
|
false => 0,
|
||||||
|
} + match voltex_state.laser[3] {
|
||||||
|
true => 30000,
|
||||||
|
false => 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut dirty = false;
|
||||||
|
if self.gamepad.buttons.raw != buttons {
|
||||||
|
self.gamepad.buttons.raw = buttons;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
if self.gamepad.thumb_lx != lx {
|
||||||
|
self.gamepad.thumb_lx = lx;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
if self.gamepad.thumb_rx != rx {
|
||||||
|
self.gamepad.thumb_rx = rx;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if dirty {
|
||||||
|
self.target.update(&self.gamepad).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.gamepad = XGamepad::default();
|
||||||
|
self.target.update(&self.gamepad).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for GamepadOutput {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.target.unplug().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dammit vigem_client::Event
|
||||||
|
unsafe impl Send for GamepadOutput {}
|
@ -5,7 +5,7 @@ use winapi::{
|
|||||||
um::winuser::{SendInput, INPUT, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_KEYUP},
|
um::winuser::{SendInput, INPUT, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_KEYUP},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::slider_io::config::KeyboardLayout;
|
use crate::slider_io::{config::KeyboardLayout, output::OutputHandler};
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
const TASOLLER_KB_MAP: [usize; 41] = [
|
const TASOLLER_KB_MAP: [usize; 41] = [
|
||||||
@ -80,6 +80,7 @@ impl KeyboardOutput {
|
|||||||
KeyboardLayout::Yuancon => &YUANCON_KB_MAP,
|
KeyboardLayout::Yuancon => &YUANCON_KB_MAP,
|
||||||
KeyboardLayout::Deemo => &DEEMO_KB_MAP,
|
KeyboardLayout::Deemo => &DEEMO_KB_MAP,
|
||||||
KeyboardLayout::Voltex => &VOLTEX_KB_MAP,
|
KeyboardLayout::Voltex => &VOLTEX_KB_MAP,
|
||||||
|
_ => panic!("Not implemented"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ground_to_idx = [0 as usize; 41];
|
let mut ground_to_idx = [0 as usize; 41];
|
||||||
@ -121,21 +122,6 @@ impl KeyboardOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, flat_controller_state: &Vec<bool>) {
|
|
||||||
self.next_keys.fill(false);
|
|
||||||
for (idx, x) in flat_controller_state.iter().enumerate() {
|
|
||||||
if *x {
|
|
||||||
self.next_keys[self.ground_to_idx[idx]] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
|
||||||
self.next_keys.fill(false);
|
|
||||||
self.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send(&mut self) {
|
fn send(&mut self) {
|
||||||
self.n_kb_buf = 0;
|
self.n_kb_buf = 0;
|
||||||
|
|
||||||
@ -178,3 +164,26 @@ impl KeyboardOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OutputHandler for KeyboardOutput {
|
||||||
|
fn tick(&mut self, flat_controller_state: &Vec<bool>) {
|
||||||
|
self.next_keys.fill(false);
|
||||||
|
for (idx, x) in flat_controller_state.iter().enumerate() {
|
||||||
|
if *x {
|
||||||
|
self.next_keys[self.ground_to_idx[idx]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
self.next_keys.fill(false);
|
||||||
|
self.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for KeyboardOutput {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,17 +4,23 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use log::{error, info};
|
||||||
|
|
||||||
use palette::{FromColor, Hsv, Srgb};
|
use palette::{FromColor, Hsv, Srgb};
|
||||||
|
use serialport::{ClearBuffer, SerialPort, StopBits};
|
||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::{LedMode, ReactiveLayout},
|
config::{LedMode, ReactiveLayout},
|
||||||
controller_state::{FullState, LedState},
|
controller_state::{FullState, LedState},
|
||||||
|
utils::Buffer,
|
||||||
|
voltex::VoltexState,
|
||||||
worker::Job,
|
worker::Job,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct LedJob {
|
pub struct LedJob {
|
||||||
state: FullState,
|
state: FullState,
|
||||||
mode: LedMode,
|
mode: LedMode,
|
||||||
|
serial_port: Option<Box<dyn SerialPort>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LedJob {
|
impl LedJob {
|
||||||
@ -22,10 +28,16 @@ impl LedJob {
|
|||||||
Self {
|
Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
mode: mode.clone(),
|
mode: mode.clone(),
|
||||||
|
serial_port: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_lights(&self, flat_controller_state: Option<&Vec<bool>>, led_state: &mut LedState) {
|
fn calc_lights(
|
||||||
|
&self,
|
||||||
|
flat_controller_state: Option<&Vec<bool>>,
|
||||||
|
serial_buffer: Option<&Buffer>,
|
||||||
|
led_state: &mut LedState,
|
||||||
|
) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
LedMode::Reactive { layout, .. } => {
|
LedMode::Reactive { layout, .. } => {
|
||||||
let flat_controller_state = flat_controller_state.unwrap();
|
let flat_controller_state = flat_controller_state.unwrap();
|
||||||
@ -63,47 +75,40 @@ impl LedJob {
|
|||||||
}
|
}
|
||||||
led_state.paint(27, &[64, 0, 0]);
|
led_state.paint(27, &[64, 0, 0]);
|
||||||
|
|
||||||
// Left laser left
|
let voltex_state = VoltexState::from_flat(flat_controller_state);
|
||||||
if flat_controller_state[0..4].contains(&true) {
|
|
||||||
for idx in 0..3 {
|
|
||||||
led_state.paint(idx, &[0, 0, 255]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Left laser right
|
// Left laser
|
||||||
if flat_controller_state[4..8].contains(&true) {
|
for (idx, state) in voltex_state.laser[0..2].iter().enumerate() {
|
||||||
for idx in 4..7 {
|
if *state {
|
||||||
led_state.paint(idx, &[0, 0, 255]);
|
led_state.paint(0 + idx * 4, &[0, 0, 255]);
|
||||||
|
led_state.paint(1 + idx * 4, &[0, 0, 255]);
|
||||||
|
led_state.paint(2 + idx * 4, &[0, 0, 255]);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Right laser left
|
// Right laser
|
||||||
if flat_controller_state[24..28].contains(&true) {
|
for (idx, state) in voltex_state.laser[2..4].iter().enumerate() {
|
||||||
for idx in 24..27 {
|
if *state {
|
||||||
led_state.paint(idx, &[255, 0, 0]);
|
led_state.paint(24 + idx * 4, &[255, 0, 0]);
|
||||||
|
led_state.paint(25 + idx * 4, &[255, 0, 0]);
|
||||||
|
led_state.paint(26 + idx * 4, &[255, 0, 0]);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
// Right laser right
|
|
||||||
if flat_controller_state[28..32].contains(&true) {
|
|
||||||
for idx in 28..31 {
|
|
||||||
led_state.paint(idx, &[255, 0, 0]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
for (btn_idx, btn_banks) in flat_controller_state[8..24].chunks(4).enumerate() {
|
for (idx, state) in voltex_state.bt.iter().enumerate() {
|
||||||
if btn_banks.iter().skip(1).step_by(2).any(|x| *x) {
|
if *state {
|
||||||
led_state.paint(8 + btn_idx * 4, &[255, 255, 255]);
|
led_state.paint(8 + idx * 4, &[255, 255, 255]);
|
||||||
led_state.paint(10 + btn_idx * 4, &[255, 255, 255]);
|
led_state.paint(10 + idx * 4, &[255, 255, 255]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fx
|
// Fx
|
||||||
for (fx_idx, fx_banks) in flat_controller_state[8..24].chunks(8).enumerate() {
|
for (idx, state) in voltex_state.fx.iter().enumerate() {
|
||||||
if fx_banks.iter().step_by(2).any(|x| *x) {
|
if *state {
|
||||||
led_state.paint(9 + fx_idx * 8, &[255, 0, 0]);
|
led_state.paint(9 + idx * 8, &[255, 0, 0]);
|
||||||
led_state.paint(11 + fx_idx * 8, &[255, 0, 0]);
|
led_state.paint(11 + idx * 8, &[255, 0, 0]);
|
||||||
led_state.paint(13 + fx_idx * 8, &[255, 0, 0]);
|
led_state.paint(13 + idx * 8, &[255, 0, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,6 +123,26 @@ impl LedJob {
|
|||||||
led_state.paint(idx, &[color.red, color.green, color.blue]);
|
led_state.paint(idx, &[color.red, color.green, color.blue]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LedMode::Serial { .. } => {
|
||||||
|
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialProcessor.h
|
||||||
|
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialProcessor.cpp
|
||||||
|
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialLeds.h
|
||||||
|
// https://github.com/jmontineri/OpeNITHM/blob/89e9a43f7484e8949cd31bbff79c32f21ea3ec1d/Firmware/OpeNITHM/SerialLeds.cpp
|
||||||
|
if let Some(serial_buffer) = serial_buffer {
|
||||||
|
// println!("buffer {:?}", serial_buffer.data);
|
||||||
|
if serial_buffer.data[0] == 0xaa && serial_buffer.data[1] == 0xaa {
|
||||||
|
for (idx, buf_chunk) in serial_buffer.data[2..95]
|
||||||
|
.chunks(3)
|
||||||
|
.take(31)
|
||||||
|
.rev()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
led_state.paint(idx, &[(*buf_chunk)[1], (*buf_chunk)[2], (*buf_chunk)[0]]);
|
||||||
|
}
|
||||||
|
println!("leds {:?}", led_state.led_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => panic!("Not implemented"),
|
_ => panic!("Not implemented"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,22 +151,77 @@ impl LedJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Job for LedJob {
|
impl Job for LedJob {
|
||||||
fn setup(&mut self) {}
|
fn setup(&mut self) -> bool {
|
||||||
|
match &self.mode {
|
||||||
|
LedMode::Serial { port } => {
|
||||||
|
info!(
|
||||||
|
"Serial port for led opening at {} {:?}",
|
||||||
|
port.as_str(),
|
||||||
|
115200
|
||||||
|
);
|
||||||
|
self.serial_port = match serialport::new(port, 115200).open() {
|
||||||
|
Ok(s) => {
|
||||||
|
info!("Serial port opened");
|
||||||
|
Some(s)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Serial port could not open, exiting thread early");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.serial_port.is_some()
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
let flat_controller_state: Option<Vec<bool>> = match self.mode {
|
let mut flat_controller_state: Option<Vec<bool>> = None;
|
||||||
|
let mut serial_buffer: Option<Buffer> = None;
|
||||||
|
|
||||||
|
// Do the IO here
|
||||||
|
match self.mode {
|
||||||
LedMode::Reactive { sensitivity, .. } => {
|
LedMode::Reactive { sensitivity, .. } => {
|
||||||
let controller_state_handle = self.state.controller_state.lock().unwrap();
|
let controller_state_handle = self.state.controller_state.lock().unwrap();
|
||||||
Some(controller_state_handle.flat(&sensitivity))
|
flat_controller_state = Some(controller_state_handle.flat(&sensitivity));
|
||||||
}
|
}
|
||||||
_ => None,
|
LedMode::Serial { .. } => {
|
||||||
};
|
if let Some(serial_port) = self.serial_port.as_mut() {
|
||||||
|
let mut serial_data_avail = serial_port.bytes_to_read().unwrap_or(0);
|
||||||
|
if serial_data_avail < 100 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if serial_data_avail % 100 == 0 {
|
||||||
|
let mut serial_buffer_working = Buffer::new();
|
||||||
|
serial_port
|
||||||
|
.as_mut()
|
||||||
|
.read_exact(&mut serial_buffer_working.data[..100])
|
||||||
|
.ok()
|
||||||
|
.unwrap();
|
||||||
|
serial_data_avail -= 100;
|
||||||
|
serial_buffer = Some(serial_buffer_working);
|
||||||
|
}
|
||||||
|
|
||||||
|
if serial_data_avail > 0 {
|
||||||
|
serial_port.clear(ClearBuffer::All);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then calculate and transfer
|
||||||
{
|
{
|
||||||
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
||||||
self.calc_lights(flat_controller_state.as_ref(), led_state_handle.deref_mut());
|
self.calc_lights(
|
||||||
|
flat_controller_state.as_ref(),
|
||||||
|
serial_buffer.as_ref(),
|
||||||
|
led_state_handle.deref_mut(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(33));
|
thread::sleep(Duration::from_millis(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {}
|
fn teardown(&mut self) {}
|
||||||
|
@ -2,7 +2,7 @@ use log::info;
|
|||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::Config, controller_state::FullState, device::HidDeviceJob, led::LedJob,
|
config::Config, controller_state::FullState, device::HidDeviceJob, led::LedJob,
|
||||||
output::KeyboardOutputJob, worker::Worker,
|
output::OutputJob, worker::Worker,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
@ -15,13 +15,16 @@ pub struct Manager {
|
|||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
pub fn new(config: Config) -> Self {
|
pub fn new(config: Config) -> Self {
|
||||||
|
info!("Starting manager");
|
||||||
|
info!("Device config {:?}", config.device_mode);
|
||||||
|
info!("Output config {:?}", config.output_mode);
|
||||||
|
info!("LED config {:?}", config.led_mode);
|
||||||
|
|
||||||
let state = FullState::new();
|
let state = FullState::new();
|
||||||
let device_worker = Worker::new(HidDeviceJob::from_config(&state, &config.device_mode));
|
let device_worker = Worker::new(HidDeviceJob::from_config(&state, &config.device_mode));
|
||||||
let output_worker = Worker::new(KeyboardOutputJob::new(&state, &config.output_mode));
|
let output_worker = Worker::new(OutputJob::new(&state, &config.output_mode));
|
||||||
let led_worker = Worker::new(LedJob::new(&state, &config.led_mode));
|
let led_worker = Worker::new(LedJob::new(&state, &config.led_mode));
|
||||||
|
|
||||||
info!("Starting manager with config: {:?}", config);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
state,
|
state,
|
||||||
config,
|
config,
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
mod config;
|
mod config;
|
||||||
|
mod utils;
|
||||||
mod controller_state;
|
|
||||||
mod worker;
|
mod worker;
|
||||||
|
|
||||||
|
mod controller_state;
|
||||||
|
mod voltex;
|
||||||
|
|
||||||
|
mod gamepad;
|
||||||
mod keyboard;
|
mod keyboard;
|
||||||
|
|
||||||
mod device;
|
mod device;
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
use std::{thread, time::Duration};
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::OutputMode, controller_state::FullState, keyboard::KeyboardOutput, worker::Job,
|
config::{KeyboardLayout, OutputMode},
|
||||||
|
controller_state::FullState,
|
||||||
|
gamepad::GamepadOutput,
|
||||||
|
keyboard::KeyboardOutput,
|
||||||
|
worker::Job,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct KeyboardOutputJob {
|
pub trait OutputHandler: Send + Drop {
|
||||||
state: FullState,
|
fn tick(&mut self, flat_controller_state: &Vec<bool>);
|
||||||
sensitivity: u8,
|
fn reset(&mut self);
|
||||||
keyboard_output: KeyboardOutput,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardOutputJob {
|
pub struct OutputJob {
|
||||||
|
state: FullState,
|
||||||
|
sensitivity: u8,
|
||||||
|
handler: Box<dyn OutputHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputJob {
|
||||||
pub fn new(state: &FullState, mode: &OutputMode) -> Self {
|
pub fn new(state: &FullState, mode: &OutputMode) -> Self {
|
||||||
match mode {
|
match mode {
|
||||||
OutputMode::Keyboard {
|
OutputMode::Keyboard {
|
||||||
@ -19,15 +28,20 @@ impl KeyboardOutputJob {
|
|||||||
} => Self {
|
} => Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
sensitivity: *sensitivity,
|
sensitivity: *sensitivity,
|
||||||
keyboard_output: KeyboardOutput::new(layout.clone()),
|
handler: match layout {
|
||||||
|
KeyboardLayout::GamepadVoltex => Box::new(GamepadOutput::new()),
|
||||||
|
layout => Box::new(KeyboardOutput::new(layout.clone())),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
_ => panic!("Not implemented"),
|
_ => panic!("Not implemented"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Job for KeyboardOutputJob {
|
impl Job for OutputJob {
|
||||||
fn setup(&mut self) {}
|
fn setup(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
let flat_controller_state: Vec<bool>;
|
let flat_controller_state: Vec<bool>;
|
||||||
@ -36,11 +50,11 @@ impl Job for KeyboardOutputJob {
|
|||||||
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
|
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.keyboard_output.tick(&flat_controller_state);
|
self.handler.tick(&flat_controller_state);
|
||||||
thread::sleep(Duration::from_millis(10));
|
thread::sleep(Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {
|
fn teardown(&mut self) {
|
||||||
self.keyboard_output.reset();
|
self.handler.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
src-tauri/src/slider_io/utils.rs
Normal file
34
src-tauri/src/slider_io/utils.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::{error::Error, fmt};
|
||||||
|
|
||||||
|
pub struct Buffer {
|
||||||
|
pub data: [u8; 256],
|
||||||
|
pub len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Buffer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Buffer {
|
||||||
|
data: [0; 256],
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn slice(&self) -> &[u8] {
|
||||||
|
&self.data[0..self.len]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ShimError;
|
||||||
|
|
||||||
|
impl<'a> fmt::Display for ShimError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "ShimError")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for ShimError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"shimError"
|
||||||
|
}
|
||||||
|
}
|
39
src-tauri/src/slider_io/voltex.rs
Normal file
39
src-tauri/src/slider_io/voltex.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
pub struct VoltexState {
|
||||||
|
pub laser: [bool; 4],
|
||||||
|
pub bt: [bool; 4],
|
||||||
|
pub fx: [bool; 2],
|
||||||
|
pub extra: [bool; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VoltexState {
|
||||||
|
pub fn from_flat(flat_controller_state: &Vec<bool>) -> Self {
|
||||||
|
let mut voltex_state = Self {
|
||||||
|
laser: [false; 4],
|
||||||
|
bt: [false; 4],
|
||||||
|
fx: [false; 2],
|
||||||
|
extra: [false; 3],
|
||||||
|
};
|
||||||
|
|
||||||
|
voltex_state.laser[0] = flat_controller_state[0..4].contains(&true);
|
||||||
|
voltex_state.laser[1] = flat_controller_state[4..8].contains(&true);
|
||||||
|
voltex_state.laser[2] = flat_controller_state[24..28].contains(&true);
|
||||||
|
voltex_state.laser[3] = flat_controller_state[28..32].contains(&true);
|
||||||
|
|
||||||
|
for i in 0..4 {
|
||||||
|
voltex_state.bt[i] = flat_controller_state[9 + i * 4] || flat_controller_state[11 + i * 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..2 {
|
||||||
|
voltex_state.fx[i] = flat_controller_state[8 + i * 8]
|
||||||
|
|| flat_controller_state[10 + i * 8]
|
||||||
|
|| flat_controller_state[12 + i * 8]
|
||||||
|
|| flat_controller_state[14 + i * 8];
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..3 {
|
||||||
|
voltex_state.extra[i] = flat_controller_state[38 + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
voltex_state
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub trait Job: Send {
|
pub trait Job: Send {
|
||||||
fn setup(&mut self);
|
fn setup(&mut self) -> bool;
|
||||||
fn tick(&mut self);
|
fn tick(&mut self);
|
||||||
fn teardown(&mut self);
|
fn teardown(&mut self);
|
||||||
}
|
}
|
||||||
@ -24,12 +24,14 @@ impl Worker {
|
|||||||
let stop_signal_clone = Arc::clone(&stop_signal);
|
let stop_signal_clone = Arc::clone(&stop_signal);
|
||||||
Self {
|
Self {
|
||||||
thread: Some(thread::spawn(move || {
|
thread: Some(thread::spawn(move || {
|
||||||
job.setup();
|
let setup_res = job.setup();
|
||||||
|
stop_signal_clone.store(!setup_res, Ordering::SeqCst);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
job.tick();
|
|
||||||
if stop_signal_clone.load(Ordering::SeqCst) {
|
if stop_signal_clone.load(Ordering::SeqCst) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
job.tick();
|
||||||
}
|
}
|
||||||
job.teardown();
|
job.teardown();
|
||||||
})),
|
})),
|
||||||
@ -40,7 +42,7 @@ impl Worker {
|
|||||||
|
|
||||||
impl Drop for Worker {
|
impl Drop for Worker {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.stop_signal.swap(true, Ordering::SeqCst);
|
self.stop_signal.store(true, Ordering::SeqCst);
|
||||||
if self.thread.is_some() {
|
if self.thread.is_some() {
|
||||||
self.thread.take().unwrap().join().ok();
|
self.thread.take().unwrap().join().ok();
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
let outputWebsocketUrl = "http://localhost:3000";
|
let outputWebsocketUrl = "http://localhost:3000";
|
||||||
let ledSensitivity = 20;
|
let ledSensitivity = 20;
|
||||||
let ledWebsocketUrl = "http://localhost:3001";
|
let ledWebsocketUrl = "http://localhost:3001";
|
||||||
|
let ledSerialPort = "COM5";
|
||||||
|
|
||||||
let debugstr = "";
|
let debugstr = "";
|
||||||
|
|
||||||
@ -21,13 +22,15 @@
|
|||||||
console.log("heartbeat", event);
|
console.log("heartbeat", event);
|
||||||
debugstr = event.payload;
|
debugstr = event.payload;
|
||||||
const payload: any = JSON.parse(event.payload as any);
|
const payload: any = JSON.parse(event.payload as any);
|
||||||
deviceMode = payload.deviceMode;
|
deviceMode = payload.deviceMode || "none";
|
||||||
outputMode = payload.outputMode;
|
outputMode = payload.outputMode || "none";
|
||||||
ledMode = payload.ledMode;
|
ledMode = payload.ledMode || "none";
|
||||||
keyboardSensitivity = payload.keyboardSensitivity;
|
keyboardSensitivity = payload.keyboardSensitivity || 20;
|
||||||
outputWebsocketUrl = payload.outputWebsocketUrl;
|
outputWebsocketUrl =
|
||||||
ledSensitivity = payload.ledSensitivity;
|
payload.outputWebsocketUrl || "http://localhost:3000/";
|
||||||
ledWebsocketUrl = payload.ledWebsocketUrl;
|
ledSensitivity = payload.ledSensitivity || 20;
|
||||||
|
ledWebsocketUrl = payload.ledWebsocketUrl || "http://localhost:3001";
|
||||||
|
ledSerialPort = payload.ledSerialPort || "COM5";
|
||||||
});
|
});
|
||||||
await emit("heartbeat", "");
|
await emit("heartbeat", "");
|
||||||
});
|
});
|
||||||
@ -44,6 +47,7 @@
|
|||||||
outputWebsocketUrl,
|
outputWebsocketUrl,
|
||||||
ledSensitivity,
|
ledSensitivity,
|
||||||
ledWebsocketUrl,
|
ledWebsocketUrl,
|
||||||
|
ledSerialPort,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
console.log("Done");
|
console.log("Done");
|
||||||
@ -144,6 +148,7 @@
|
|||||||
<option value="attract">Rainbow Attract Mode</option>
|
<option value="attract">Rainbow Attract Mode</option>
|
||||||
<option value="test">LED Test</option>
|
<option value="test">LED Test</option>
|
||||||
<option value="websocket">Websocket</option>
|
<option value="websocket">Websocket</option>
|
||||||
|
<option value="serial">Serial</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -181,6 +186,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if ledMode === "serial"}
|
||||||
|
<div class="row">
|
||||||
|
<div class="label">LED Serial Port</div>
|
||||||
|
<div class="input">
|
||||||
|
<select bind:value={ledSerialPort}>
|
||||||
|
<option value="COM1">COM1</option>
|
||||||
|
<option value="COM2">COM2</option>
|
||||||
|
<option value="COM3">COM3</option>
|
||||||
|
<option value="COM4">COM4</option>
|
||||||
|
<option value="COM5">COM5</option>
|
||||||
|
<option value="COM6">COM6</option>
|
||||||
|
<option value="COM7">COM7</option>
|
||||||
|
<option value="COM8">COM8</option>
|
||||||
|
<option value="COM9">COM9</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<button on:click={async () => await setConfig()}>Apply</button>
|
<button on:click={async () => await setConfig()}>Apply</button>
|
||||||
<button on:click={async () => await hide()}>Hide</button>
|
<button on:click={async () => await hide()}>Hide</button>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user