mirror of
https://github.com/4yn/slidershim.git
synced 2024-12-18 07:05:52 +01:00
async output and led
This commit is contained in:
parent
afa5a46c65
commit
2ae7a81f22
80
src-tauri/Cargo.lock
generated
80
src-tauri/Cargo.lock
generated
@ -1666,9 +1666,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.5"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
@ -2132,7 +2132,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core",
|
"parking_lot_core 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core 0.9.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2150,10 +2160,17 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "path-clean"
|
name = "parking_lot_core"
|
||||||
version = "0.1.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd"
|
checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall 0.2.10",
|
||||||
|
"smallvec",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathdiff"
|
name = "pathdiff"
|
||||||
@ -2939,7 +2956,7 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slidershim"
|
name = "slidershim"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"atomic_float",
|
"atomic_float",
|
||||||
@ -2954,7 +2971,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"open",
|
"open",
|
||||||
"palette",
|
"palette",
|
||||||
"path-clean",
|
"parking_lot 0.12.0",
|
||||||
"phf 0.10.1",
|
"phf 0.10.1",
|
||||||
"qrcode",
|
"qrcode",
|
||||||
"rusb",
|
"rusb",
|
||||||
@ -3037,7 +3054,7 @@ checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"parking_lot",
|
"parking_lot 0.11.2",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.8.0",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde",
|
"serde",
|
||||||
@ -3177,7 +3194,7 @@ dependencies = [
|
|||||||
"ndk-glue",
|
"ndk-glue",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"objc",
|
"objc",
|
||||||
"parking_lot",
|
"parking_lot 0.11.2",
|
||||||
"raw-window-handle 0.3.4",
|
"raw-window-handle 0.3.4",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"serde",
|
"serde",
|
||||||
@ -3971,6 +3988,49 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.32.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "slidershim"
|
name = "slidershim"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
description = "slidershim"
|
description = "slidershim"
|
||||||
authors = ["4yn"]
|
authors = ["4yn"]
|
||||||
license = ""
|
license = ""
|
||||||
@ -9,45 +9,54 @@ default-run = "slidershim"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
build = "src/build.rs"
|
build = "src/build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "1.0.0-beta.4" }
|
tauri-build = { version = "1.0.0-beta.4" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "1.0"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
# logging
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
env_logger = "0.9.0"
|
env_logger = "0.9.0"
|
||||||
simple-logging = "2.0.2"
|
simple-logging = "2.0.2"
|
||||||
open = "2.0.2"
|
|
||||||
|
# threads
|
||||||
|
parking_lot = "0.12.0"
|
||||||
atomic_float = "0.1.0"
|
atomic_float = "0.1.0"
|
||||||
spin_sleep = "1.0.0"
|
spin_sleep = "1.0.0"
|
||||||
tauri = { version = "1.0.0-beta.8", features = ["shell-open", "system-tray"] }
|
|
||||||
|
|
||||||
|
# async
|
||||||
futures = "0.3.19"
|
futures = "0.3.19"
|
||||||
futures-util = "0.3.19"
|
futures-util = "0.3.19"
|
||||||
async-trait = "0.1.52"
|
async-trait = "0.1.52"
|
||||||
tokio = { version="1.16.1", features= ["rt-multi-thread","macros"] }
|
tokio = { version="1.16.1", features= ["rt-multi-thread","macros"] }
|
||||||
tokio-util = "0.6.9"
|
tokio-util = "0.6.9"
|
||||||
|
|
||||||
|
# UI
|
||||||
|
tauri = { version = "1.0.0-beta.8", features = ["shell-open", "system-tray"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
open = "2.0.2"
|
||||||
directories = "4.0.1"
|
directories = "4.0.1"
|
||||||
|
image = "0.23.14"
|
||||||
|
|
||||||
|
# device and system
|
||||||
rusb = "0.9.0"
|
rusb = "0.9.0"
|
||||||
serialport = "4.0.1"
|
serialport = "4.0.1"
|
||||||
vigem-client = "0.1.1"
|
vigem-client = "0.1.1"
|
||||||
palette = "0.6.0"
|
|
||||||
winapi = "0.3.9"
|
winapi = "0.3.9"
|
||||||
ipconfig = "0.3.0"
|
ipconfig = "0.3.0"
|
||||||
|
|
||||||
|
# webserver
|
||||||
hyper = { version="0.14.16", features= ["server", "http1", "http2", "tcp", "stream", "runtime"] }
|
hyper = { version="0.14.16", features= ["server", "http1", "http2", "tcp", "stream", "runtime"] }
|
||||||
phf = { version = "0.10.1", features = ["macros"] }
|
phf = { version = "0.10.1", features = ["macros"] }
|
||||||
base64 = "0.13.0"
|
|
||||||
image = "0.23.14"
|
|
||||||
qrcode = { version="0.12.0", features= ["image"] }
|
|
||||||
path-clean = "0.1.0"
|
|
||||||
tungstenite = { version="0.16.0", default-features=false }
|
tungstenite = { version="0.16.0", default-features=false }
|
||||||
tokio-tungstenite = "0.16.1"
|
tokio-tungstenite = "0.16.1"
|
||||||
|
|
||||||
|
# webserver utils
|
||||||
|
base64 = "0.13.0"
|
||||||
|
palette = "0.6.0"
|
||||||
|
qrcode = { version="0.12.0", features= ["image"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "custom-protocol" ]
|
default = [ "custom-protocol" ]
|
||||||
custom-protocol = [ "tauri/custom-protocol" ]
|
custom-protocol = [ "tauri/custom-protocol" ]
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
mod slider_io;
|
mod slider_io;
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use parking_lot::Mutex;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
@ -46,10 +47,10 @@ fn main() {
|
|||||||
let config = Arc::new(Mutex::new(Some(slider_io::Config::load())));
|
let config = Arc::new(Mutex::new(Some(slider_io::Config::load())));
|
||||||
let manager = Arc::new(Mutex::new(slider_io::Manager::new()));
|
let manager = Arc::new(Mutex::new(slider_io::Manager::new()));
|
||||||
{
|
{
|
||||||
let config_handle = config.lock().unwrap();
|
let config_handle = config.lock();
|
||||||
let config_handle_ref = config_handle.as_ref().unwrap();
|
let config_handle_ref = config_handle.as_ref().unwrap();
|
||||||
config_handle_ref.save();
|
config_handle_ref.save();
|
||||||
let manager_handle = manager.lock().unwrap();
|
let manager_handle = manager.lock();
|
||||||
manager_handle.update_config(config_handle_ref.clone());
|
manager_handle.update_config(config_handle_ref.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ fn main() {
|
|||||||
let app_handle = app.handle();
|
let app_handle = app.handle();
|
||||||
let config_clone = Arc::clone(&config);
|
let config_clone = Arc::clone(&config);
|
||||||
app.listen_global("ready", move |_| {
|
app.listen_global("ready", move |_| {
|
||||||
let config_handle = config_clone.lock().unwrap();
|
let config_handle = config_clone.lock();
|
||||||
info!("Start signal received");
|
info!("Start signal received");
|
||||||
app_handle
|
app_handle
|
||||||
.emit_all(
|
.emit_all(
|
||||||
@ -140,7 +141,7 @@ fn main() {
|
|||||||
app.listen_global("queryState", move |_| {
|
app.listen_global("queryState", move |_| {
|
||||||
// app_handle.emit_all("showState", "@@@");
|
// app_handle.emit_all("showState", "@@@");
|
||||||
let (snapshot, timer) = {
|
let (snapshot, timer) = {
|
||||||
let manager_handle = manager_clone.lock().unwrap();
|
let manager_handle = manager_clone.lock();
|
||||||
(
|
(
|
||||||
manager_handle.try_get_state().map(|x| x.snapshot()),
|
manager_handle.try_get_state().map(|x| x.snapshot()),
|
||||||
manager_handle.get_timer_state(),
|
manager_handle.get_timer_state(),
|
||||||
@ -163,12 +164,12 @@ fn main() {
|
|||||||
let payload = event.payload().unwrap();
|
let payload = event.payload().unwrap();
|
||||||
info!("Config applied {}", payload);
|
info!("Config applied {}", payload);
|
||||||
if let Some(new_config) = slider_io::Config::from_str(payload) {
|
if let Some(new_config) = slider_io::Config::from_str(payload) {
|
||||||
let mut config_handle = config_clone.lock().unwrap();
|
let mut config_handle = config_clone.lock();
|
||||||
config_handle.take();
|
config_handle.take();
|
||||||
config_handle.replace(new_config);
|
config_handle.replace(new_config);
|
||||||
let config_handle_ref = config_handle.as_ref().unwrap();
|
let config_handle_ref = config_handle.as_ref().unwrap();
|
||||||
config_handle_ref.save();
|
config_handle_ref.save();
|
||||||
let manager_handle = manager_clone.lock().unwrap();
|
let manager_handle = manager_clone.lock();
|
||||||
manager_handle.update_config(config_handle_ref.clone());
|
manager_handle.update_config(config_handle_ref.clone());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,7 @@ use tokio::{
|
|||||||
use tokio_tungstenite::WebSocketStream;
|
use tokio_tungstenite::WebSocketStream;
|
||||||
use tungstenite::{handshake, Message};
|
use tungstenite::{handshake, Message};
|
||||||
|
|
||||||
use crate::slider_io::{controller_state::FullState, worker::AsyncJob};
|
use crate::slider_io::{controller_state::FullState, worker::AsyncHaltableJob};
|
||||||
|
|
||||||
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
|
// https://levelup.gitconnected.com/handling-websocket-and-http-on-the-same-port-with-rust-f65b770722c9
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ async fn handle_brokenithm(
|
|||||||
}
|
}
|
||||||
39 => {
|
39 => {
|
||||||
if chars[0] == 'b' {
|
if chars[0] == 'b' {
|
||||||
let mut controller_state_handle = state_handle.controller_state.lock().unwrap();
|
let mut controller_state_handle = state_handle.controller_state.lock();
|
||||||
for (idx, c) in chars[0..32].iter().enumerate() {
|
for (idx, c) in chars[0..32].iter().enumerate() {
|
||||||
controller_state_handle.ground_state[idx] = match *c == '1' {
|
controller_state_handle.ground_state[idx] = match *c == '1' {
|
||||||
false => 0,
|
false => 0,
|
||||||
@ -167,7 +167,7 @@ async fn handle_brokenithm(
|
|||||||
loop {
|
loop {
|
||||||
let mut led_data = vec![0; 93];
|
let mut led_data = vec![0; 93];
|
||||||
{
|
{
|
||||||
let led_state_handle = state_handle.led_state.lock().unwrap();
|
let led_state_handle = state_handle.led_state.lock();
|
||||||
(&mut led_data).copy_from_slice(&led_state_handle.led_state);
|
(&mut led_data).copy_from_slice(&led_state_handle.led_state);
|
||||||
}
|
}
|
||||||
msg_write_handle.send(Message::Binary(led_data)).ok();
|
msg_write_handle.send(Message::Binary(led_data)).ok();
|
||||||
@ -273,7 +273,7 @@ impl BrokenithmJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl AsyncJob for BrokenithmJob {
|
impl AsyncHaltableJob for BrokenithmJob {
|
||||||
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
||||||
let state = self.state.clone();
|
let state = self.state.clone();
|
||||||
let ground_only = self.ground_only;
|
let ground_only = self.ground_only;
|
||||||
|
@ -8,11 +8,18 @@ use std::{convert::TryFrom, fs, path::PathBuf};
|
|||||||
use crate::slider_io::utils::list_ips;
|
use crate::slider_io::utils::list_ips;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DeviceMode {
|
pub enum HardwareSpec {
|
||||||
None,
|
|
||||||
TasollerOne,
|
TasollerOne,
|
||||||
TasollerTwo,
|
TasollerTwo,
|
||||||
Yuancon,
|
Yuancon,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum DeviceMode {
|
||||||
|
None,
|
||||||
|
Hardware {
|
||||||
|
spec: HardwareSpec,
|
||||||
|
},
|
||||||
Brokenithm {
|
Brokenithm {
|
||||||
ground_only: bool,
|
ground_only: bool,
|
||||||
led_enabled: bool,
|
led_enabled: bool,
|
||||||
@ -20,7 +27,7 @@ pub enum DeviceMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum OutputPolling {
|
pub enum PollingRate {
|
||||||
Sixty,
|
Sixty,
|
||||||
Hundred,
|
Hundred,
|
||||||
TwoHundredFifty,
|
TwoHundredFifty,
|
||||||
@ -28,35 +35,13 @@ pub enum OutputPolling {
|
|||||||
Thousand,
|
Thousand,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputPolling {
|
|
||||||
pub fn from_str(s: &str) -> Option<Self> {
|
|
||||||
match s {
|
|
||||||
"60" => Some(OutputPolling::Sixty),
|
|
||||||
"100" => Some(OutputPolling::Hundred),
|
|
||||||
"250" => Some(OutputPolling::TwoHundredFifty),
|
|
||||||
"500" => Some(OutputPolling::FiveHundred),
|
|
||||||
"1000" => Some(OutputPolling::Thousand),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_t_u64(&self) -> u64 {
|
|
||||||
match self {
|
|
||||||
OutputPolling::Sixty => 16666,
|
|
||||||
OutputPolling::Hundred => 10000,
|
|
||||||
OutputPolling::TwoHundredFifty => 4000,
|
|
||||||
OutputPolling::FiveHundred => 2000,
|
|
||||||
OutputPolling::Thousand => 1000,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum KeyboardLayout {
|
pub enum KeyboardLayout {
|
||||||
Tasoller,
|
Tasoller,
|
||||||
Yuancon,
|
Yuancon,
|
||||||
Deemo,
|
Deemo,
|
||||||
Voltex,
|
Voltex,
|
||||||
|
Neardayo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -65,22 +50,45 @@ pub enum GamepadLayout {
|
|||||||
Neardayo,
|
Neardayo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PollingRate {
|
||||||
|
pub fn from_str(s: &str) -> Option<Self> {
|
||||||
|
match s {
|
||||||
|
"60" => Some(PollingRate::Sixty),
|
||||||
|
"100" => Some(PollingRate::Hundred),
|
||||||
|
"250" => Some(PollingRate::TwoHundredFifty),
|
||||||
|
"500" => Some(PollingRate::FiveHundred),
|
||||||
|
"1000" => Some(PollingRate::Thousand),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_t_u64(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
PollingRate::Sixty => 16666,
|
||||||
|
PollingRate::Hundred => 10000,
|
||||||
|
PollingRate::TwoHundredFifty => 4000,
|
||||||
|
PollingRate::FiveHundred => 2000,
|
||||||
|
PollingRate::Thousand => 1000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum OutputMode {
|
pub enum OutputMode {
|
||||||
None,
|
None,
|
||||||
Keyboard {
|
Keyboard {
|
||||||
layout: KeyboardLayout,
|
layout: KeyboardLayout,
|
||||||
polling: OutputPolling,
|
polling: PollingRate,
|
||||||
sensitivity: u8,
|
sensitivity: u8,
|
||||||
},
|
},
|
||||||
Gamepad {
|
Gamepad {
|
||||||
layout: GamepadLayout,
|
layout: GamepadLayout,
|
||||||
polling: OutputPolling,
|
polling: PollingRate,
|
||||||
sensitivity: u8,
|
sensitivity: u8,
|
||||||
},
|
},
|
||||||
Websocket {
|
Websocket {
|
||||||
url: String,
|
url: String,
|
||||||
polling: OutputPolling,
|
polling: PollingRate,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,9 +131,15 @@ impl Config {
|
|||||||
raw: s.to_string(),
|
raw: s.to_string(),
|
||||||
device_mode: match v["deviceMode"].as_str()? {
|
device_mode: match v["deviceMode"].as_str()? {
|
||||||
"none" => DeviceMode::None,
|
"none" => DeviceMode::None,
|
||||||
"tasoller-one" => DeviceMode::TasollerOne,
|
"tasoller-one" => DeviceMode::Hardware {
|
||||||
"tasoller-two" => DeviceMode::TasollerTwo,
|
spec: HardwareSpec::TasollerOne,
|
||||||
"yuancon" => DeviceMode::Yuancon,
|
},
|
||||||
|
"tasoller-two" => DeviceMode::Hardware {
|
||||||
|
spec: HardwareSpec::TasollerTwo,
|
||||||
|
},
|
||||||
|
"yuancon" => DeviceMode::Hardware {
|
||||||
|
spec: HardwareSpec::Yuancon,
|
||||||
|
},
|
||||||
"brokenithm" => DeviceMode::Brokenithm {
|
"brokenithm" => DeviceMode::Brokenithm {
|
||||||
ground_only: false,
|
ground_only: false,
|
||||||
led_enabled: false,
|
led_enabled: false,
|
||||||
@ -148,37 +162,42 @@ impl Config {
|
|||||||
"none" => OutputMode::None,
|
"none" => OutputMode::None,
|
||||||
"kb-32-tasoller" => OutputMode::Keyboard {
|
"kb-32-tasoller" => OutputMode::Keyboard {
|
||||||
layout: KeyboardLayout::Tasoller,
|
layout: KeyboardLayout::Tasoller,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"kb-32-yuancon" => OutputMode::Keyboard {
|
"kb-32-yuancon" => OutputMode::Keyboard {
|
||||||
layout: KeyboardLayout::Yuancon,
|
layout: KeyboardLayout::Yuancon,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"kb-8-deemo" => OutputMode::Keyboard {
|
"kb-8-deemo" => OutputMode::Keyboard {
|
||||||
layout: KeyboardLayout::Deemo,
|
layout: KeyboardLayout::Deemo,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"kb-voltex" => OutputMode::Keyboard {
|
"kb-voltex" => OutputMode::Keyboard {
|
||||||
layout: KeyboardLayout::Voltex,
|
layout: KeyboardLayout::Voltex,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
|
},
|
||||||
|
"kb-neardayo" => OutputMode::Keyboard {
|
||||||
|
layout: KeyboardLayout::Neardayo,
|
||||||
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"gamepad-voltex" => OutputMode::Gamepad {
|
"gamepad-voltex" => OutputMode::Gamepad {
|
||||||
layout: GamepadLayout::Voltex,
|
layout: GamepadLayout::Voltex,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"gamepad-neardayo" => OutputMode::Gamepad {
|
"gamepad-neardayo" => OutputMode::Gamepad {
|
||||||
layout: GamepadLayout::Neardayo,
|
layout: GamepadLayout::Neardayo,
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
sensitivity: u8::try_from(v["keyboardSensitivity"].as_i64()?).ok()?,
|
||||||
},
|
},
|
||||||
"websocket" => OutputMode::Websocket {
|
"websocket" => OutputMode::Websocket {
|
||||||
url: v["outputWebsocketUrl"].as_str()?.to_string(),
|
url: v["outputWebsocketUrl"].as_str()?.to_string(),
|
||||||
polling: OutputPolling::from_str(v["outputPolling"].as_str()?)?,
|
polling: PollingRate::from_str(v["outputPolling"].as_str()?)?,
|
||||||
},
|
},
|
||||||
_ => panic!("Invalid output mode"),
|
_ => panic!("Invalid output mode"),
|
||||||
},
|
},
|
||||||
@ -259,11 +278,12 @@ impl Config {
|
|||||||
Self::from_str(
|
Self::from_str(
|
||||||
r#"{
|
r#"{
|
||||||
"deviceMode": "none",
|
"deviceMode": "none",
|
||||||
|
"devicePolling": "100",
|
||||||
"outputMode": "none",
|
"outputMode": "none",
|
||||||
"ledMode": "none",
|
"ledMode": "none",
|
||||||
"keyboardSensitivity": 20,
|
"keyboardSensitivity": 20,
|
||||||
"outputWebsocketUrl": "localhost:3000",
|
"outputWebsocketUrl": "localhost:3000",
|
||||||
"outputPolling": "60",
|
"outputPolling": "100",
|
||||||
"ledSensitivity": 20,
|
"ledSensitivity": 20,
|
||||||
"ledWebsocketUrl": "localhost:3001",
|
"ledWebsocketUrl": "localhost:3001",
|
||||||
"ledSerialPort": "COM5"
|
"ledSerialPort": "COM5"
|
||||||
|
@ -10,7 +10,7 @@ use crate::slider_io::{
|
|||||||
led::LedJob,
|
led::LedJob,
|
||||||
output::OutputJob,
|
output::OutputJob,
|
||||||
utils::LoopTimer,
|
utils::LoopTimer,
|
||||||
worker::{AsyncWorker, ThreadWorker},
|
worker::{AsyncHaltableWorker, AsyncWorker, ThreadWorker},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -18,9 +18,9 @@ pub struct Context {
|
|||||||
state: FullState,
|
state: FullState,
|
||||||
config: Config,
|
config: Config,
|
||||||
device_worker: Option<ThreadWorker>,
|
device_worker: Option<ThreadWorker>,
|
||||||
brokenithm_worker: Option<AsyncWorker>,
|
brokenithm_worker: Option<AsyncHaltableWorker>,
|
||||||
output_worker: Option<ThreadWorker>,
|
output_worker: Option<AsyncWorker>,
|
||||||
led_worker: Option<ThreadWorker>,
|
led_worker: Option<AsyncWorker>,
|
||||||
timers: Vec<(&'static str, Arc<AtomicF64>)>,
|
timers: Vec<(&'static str, Arc<AtomicF64>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,18 +41,18 @@ impl Context {
|
|||||||
led_enabled,
|
led_enabled,
|
||||||
} => (
|
} => (
|
||||||
None,
|
None,
|
||||||
Some(AsyncWorker::new(
|
Some(AsyncHaltableWorker::new(
|
||||||
"brokenithm",
|
"brokenithm",
|
||||||
BrokenithmJob::new(&state, ground_only, led_enabled),
|
BrokenithmJob::new(&state, ground_only, led_enabled),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
_ => (
|
DeviceMode::Hardware { spec } => (
|
||||||
{
|
{
|
||||||
let timer = LoopTimer::new();
|
let timer = LoopTimer::new();
|
||||||
timers.push(("d", timer.fork()));
|
timers.push(("d", timer.fork()));
|
||||||
Some(ThreadWorker::new(
|
Some(ThreadWorker::new(
|
||||||
"device",
|
"device",
|
||||||
HidDeviceJob::from_config(&state, &config.device_mode),
|
HidDeviceJob::from_config(&state, spec),
|
||||||
timer,
|
timer,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
@ -64,7 +64,7 @@ impl Context {
|
|||||||
_ => {
|
_ => {
|
||||||
let timer = LoopTimer::new();
|
let timer = LoopTimer::new();
|
||||||
timers.push(("o", timer.fork()));
|
timers.push(("o", timer.fork()));
|
||||||
Some(ThreadWorker::new(
|
Some(AsyncWorker::new(
|
||||||
"output",
|
"output",
|
||||||
OutputJob::new(&state, &config.output_mode),
|
OutputJob::new(&state, &config.output_mode),
|
||||||
timer,
|
timer,
|
||||||
@ -76,7 +76,7 @@ impl Context {
|
|||||||
_ => {
|
_ => {
|
||||||
let timer = LoopTimer::new();
|
let timer = LoopTimer::new();
|
||||||
timers.push(("l", timer.fork()));
|
timers.push(("l", timer.fork()));
|
||||||
Some(ThreadWorker::new(
|
Some(AsyncWorker::new(
|
||||||
"led",
|
"led",
|
||||||
LedJob::new(&state, &config.led_mode),
|
LedJob::new(&state, &config.led_mode),
|
||||||
timer,
|
timer,
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use std::{
|
use parking_lot::Mutex;
|
||||||
sync::{Arc, Mutex},
|
use std::{sync::Arc, time::Instant};
|
||||||
time::Instant,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct ControllerState {
|
pub struct ControllerState {
|
||||||
pub ground_state: [u8; 32],
|
pub ground_state: [u8; 32],
|
||||||
@ -84,13 +82,13 @@ impl FullState {
|
|||||||
pub fn snapshot(&self) -> Vec<u8> {
|
pub fn snapshot(&self) -> Vec<u8> {
|
||||||
let mut buf: Vec<u8> = vec![];
|
let mut buf: Vec<u8> = vec![];
|
||||||
{
|
{
|
||||||
let controller_state_handle = self.controller_state.lock().unwrap();
|
let controller_state_handle = self.controller_state.lock();
|
||||||
buf.extend(controller_state_handle.ground_state);
|
buf.extend(controller_state_handle.ground_state);
|
||||||
buf.extend(controller_state_handle.air_state);
|
buf.extend(controller_state_handle.air_state);
|
||||||
buf.extend(controller_state_handle.extra_state);
|
buf.extend(controller_state_handle.extra_state);
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
let led_state_handle = self.led_state.lock().unwrap();
|
let led_state_handle = self.led_state.lock();
|
||||||
buf.extend(led_state_handle.led_state);
|
buf.extend(led_state_handle.led_state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@ use log::{error, info};
|
|||||||
use rusb::{self, DeviceHandle, GlobalContext};
|
use rusb::{self, DeviceHandle, GlobalContext};
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
|
mem::swap,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::DeviceMode,
|
config::HardwareSpec,
|
||||||
controller_state::{ControllerState, FullState, LedState},
|
controller_state::{ControllerState, FullState, LedState},
|
||||||
utils::{Buffer, ShimError},
|
utils::{Buffer, ShimError},
|
||||||
worker::ThreadJob,
|
worker::ThreadJob,
|
||||||
@ -23,6 +24,7 @@ enum WriteType {
|
|||||||
|
|
||||||
pub struct HidDeviceJob {
|
pub struct HidDeviceJob {
|
||||||
state: FullState,
|
state: FullState,
|
||||||
|
|
||||||
vid: u16,
|
vid: u16,
|
||||||
pid: u16,
|
pid: u16,
|
||||||
read_endpoint: u8,
|
read_endpoint: u8,
|
||||||
@ -30,6 +32,7 @@ pub struct HidDeviceJob {
|
|||||||
|
|
||||||
read_callback: HidReadCallback,
|
read_callback: HidReadCallback,
|
||||||
read_buf: Buffer,
|
read_buf: Buffer,
|
||||||
|
last_read_buf: Buffer,
|
||||||
|
|
||||||
led_write_type: WriteType,
|
led_write_type: WriteType,
|
||||||
led_callback: HidLedCallback,
|
led_callback: HidLedCallback,
|
||||||
@ -57,6 +60,7 @@ impl HidDeviceJob {
|
|||||||
led_endpoint,
|
led_endpoint,
|
||||||
read_callback,
|
read_callback,
|
||||||
read_buf: Buffer::new(),
|
read_buf: Buffer::new(),
|
||||||
|
last_read_buf: Buffer::new(),
|
||||||
led_write_type: led_type,
|
led_write_type: led_type,
|
||||||
led_callback,
|
led_callback,
|
||||||
led_buf: Buffer::new(),
|
led_buf: Buffer::new(),
|
||||||
@ -64,9 +68,9 @@ impl HidDeviceJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_config(state: &FullState, mode: &DeviceMode) -> Self {
|
pub fn from_config(state: &FullState, spec: &HardwareSpec) -> Self {
|
||||||
match mode {
|
match spec {
|
||||||
DeviceMode::TasollerOne => Self::new(
|
HardwareSpec::TasollerOne => Self::new(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
0x1ccf,
|
0x1ccf,
|
||||||
0x2333,
|
0x2333,
|
||||||
@ -108,7 +112,7 @@ impl HidDeviceJob {
|
|||||||
buf.data[96..240].fill(0);
|
buf.data[96..240].fill(0);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DeviceMode::TasollerTwo => Self::new(
|
HardwareSpec::TasollerTwo => Self::new(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
0x1ccf,
|
0x1ccf,
|
||||||
0x2333,
|
0x2333,
|
||||||
@ -146,7 +150,7 @@ impl HidDeviceJob {
|
|||||||
buf.data[96..240].fill(0);
|
buf.data[96..240].fill(0);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DeviceMode::Yuancon => Self::new(
|
HardwareSpec::Yuancon => Self::new(
|
||||||
state.clone(),
|
state.clone(),
|
||||||
0x1973,
|
0x1973,
|
||||||
0x2001,
|
0x2001,
|
||||||
@ -164,7 +168,7 @@ impl HidDeviceJob {
|
|||||||
controller_state.air_state[i ^ 1] = (buf.data[0] >> i) & 1;
|
controller_state.air_state[i ^ 1] = (buf.data[0] >> i) & 1;
|
||||||
}
|
}
|
||||||
for i in 0..3 {
|
for i in 0..3 {
|
||||||
controller_state.extra_state[i] = (buf.data[1] >> i) & 1;
|
controller_state.extra_state[2 - i] = (buf.data[1] >> i) & 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WriteType::Interrupt,
|
WriteType::Interrupt,
|
||||||
@ -181,7 +185,6 @@ impl HidDeviceJob {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_ => panic!("Not implemented"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,17 +242,19 @@ impl ThreadJob for HidDeviceJob {
|
|||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
self.read_buf.len = res;
|
self.read_buf.len = res;
|
||||||
// debug!("{:?}", self.read_buf.slice());
|
// debug!("{:?}", self.read_buf.slice());
|
||||||
if self.read_buf.len != 0 {
|
// if self.read_buf.len != 0 {
|
||||||
|
if (self.read_buf.len != 0) && (self.read_buf.slice() != self.last_read_buf.slice()) {
|
||||||
work = true;
|
work = true;
|
||||||
let mut controller_state_handle = self.state.controller_state.lock().unwrap();
|
let mut controller_state_handle = self.state.controller_state.lock();
|
||||||
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
|
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
|
||||||
|
swap(&mut self.read_buf, &mut self.last_read_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Led loop
|
// Led loop
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let mut led_state_handle = self.state.led_state.lock().unwrap();
|
let mut led_state_handle = self.state.led_state.lock();
|
||||||
if led_state_handle.dirty {
|
if led_state_handle.dirty {
|
||||||
(self.led_callback)(&mut self.led_buf, led_state_handle.deref());
|
(self.led_callback)(&mut self.led_buf, led_state_handle.deref());
|
||||||
led_state_handle.dirty = false;
|
led_state_handle.dirty = false;
|
||||||
@ -269,7 +274,7 @@ impl ThreadJob for HidDeviceJob {
|
|||||||
})
|
})
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
if res == self.led_buf.len + 1 {
|
if res == self.led_buf.len + 1 {
|
||||||
work = true;
|
// work = true;
|
||||||
self.led_buf.len = 0;
|
self.led_buf.len = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,8 +282,10 @@ impl ThreadJob for HidDeviceJob {
|
|||||||
|
|
||||||
work
|
work
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {
|
impl Drop for HidDeviceJob {
|
||||||
|
fn drop(&mut self) {
|
||||||
if let Some(handle) = self.handle.as_mut() {
|
if let Some(handle) = self.handle.as_mut() {
|
||||||
handle.release_interface(0).ok();
|
handle.release_interface(0).ok();
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,48 @@ use vigem_client::{Client, TargetId, XButtons, XGamepad, Xbox360Wired};
|
|||||||
|
|
||||||
use crate::slider_io::{config::GamepadLayout, output::OutputHandler, voltex::VoltexState};
|
use crate::slider_io::{config::GamepadLayout, output::OutputHandler, voltex::VoltexState};
|
||||||
|
|
||||||
|
struct LastWind {
|
||||||
|
left: bool,
|
||||||
|
right: bool,
|
||||||
|
out: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LastWind {
|
||||||
|
fn new() -> Self {
|
||||||
|
LastWind {
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
out: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, left: bool, right: bool) -> i16 {
|
||||||
|
let out = match (left, right) {
|
||||||
|
(false, false) => 0,
|
||||||
|
(true, false) => -1,
|
||||||
|
(false, true) => 1,
|
||||||
|
(true, true) => match (self.left, self.right) {
|
||||||
|
(false, false) => 0,
|
||||||
|
(true, false) => 1,
|
||||||
|
(false, true) => -1,
|
||||||
|
(true, true) => self.out,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.left = left;
|
||||||
|
self.right = right;
|
||||||
|
self.out = out;
|
||||||
|
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GamepadOutput {
|
pub struct GamepadOutput {
|
||||||
target: Xbox360Wired<Client>,
|
target: Xbox360Wired<Client>,
|
||||||
use_air: bool,
|
use_air: bool,
|
||||||
gamepad: XGamepad,
|
gamepad: XGamepad,
|
||||||
|
left_wind: LastWind,
|
||||||
|
right_wind: LastWind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GamepadOutput {
|
impl GamepadOutput {
|
||||||
@ -23,6 +61,8 @@ impl GamepadOutput {
|
|||||||
target,
|
target,
|
||||||
use_air,
|
use_air,
|
||||||
gamepad: XGamepad::default(),
|
gamepad: XGamepad::default(),
|
||||||
|
left_wind: LastWind::new(),
|
||||||
|
right_wind: LastWind::new(),
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Gamepad connection error: {}", e);
|
error!("Gamepad connection error: {}", e);
|
||||||
@ -80,21 +120,17 @@ impl OutputHandler for GamepadOutput {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let lx = (match voltex_state.laser[0] || (self.use_air && flat_controller_state[34]) {
|
let lx = self.left_wind.update(
|
||||||
true => -30000,
|
voltex_state.laser[0] || (self.use_air && flat_controller_state[32]),
|
||||||
false => 0,
|
voltex_state.laser[1]
|
||||||
} + match voltex_state.laser[1] || (self.use_air && flat_controller_state[35]) {
|
|| (self.use_air && (flat_controller_state[33] || flat_controller_state[34])),
|
||||||
true => 30000,
|
) * 20000;
|
||||||
false => 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
let rx = (match voltex_state.laser[2] || (self.use_air && flat_controller_state[36]) {
|
let rx = self.right_wind.update(
|
||||||
true => -30000,
|
voltex_state.laser[2]
|
||||||
false => 0,
|
|| (self.use_air && (flat_controller_state[35] || flat_controller_state[36])),
|
||||||
} + match voltex_state.laser[3] || (self.use_air && flat_controller_state[37]) {
|
voltex_state.laser[3] || (self.use_air && flat_controller_state[37]),
|
||||||
true => 30000,
|
) * 20000;
|
||||||
false => 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut dirty = false;
|
let mut dirty = false;
|
||||||
if self.gamepad.buttons.raw != buttons {
|
if self.gamepad.buttons.raw != buttons {
|
||||||
|
@ -60,6 +60,24 @@ const VOLTEX_KB_MAP: [usize; 41] = [
|
|||||||
0x31, 0x1b, 0x0d, // 1, VK_ESCAPE, VK_RETURN
|
0x31, 0x1b, 0x0d, // 1, VK_ESCAPE, VK_RETURN
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
const VOLTEX_KB_MAP_NEARDAYO: [usize; 41] = [
|
||||||
|
0x57, 0x57, 0x57, 0x57, // W
|
||||||
|
0x45, 0x45, 0x45, 0x45, // E
|
||||||
|
0x43, 0x44,
|
||||||
|
0x43, 0x44,
|
||||||
|
0x43, 0x46, // D
|
||||||
|
0x43, 0x46, // C // F
|
||||||
|
0x4d, 0x4a, // M // J
|
||||||
|
0x4d, 0x4a, // K
|
||||||
|
0x4d, 0x4b,
|
||||||
|
0x4d, 0x4b,
|
||||||
|
0x4f, 0x4f, 0x4f, 0x4f, // O
|
||||||
|
0x50, 0x50, 0x50, 0x50, // P
|
||||||
|
0x57, 0x45, 0x45, 0x4f, 0x4f, 0x50, // Disabled
|
||||||
|
0x31, 0x1b, 0x0d, // 1, VK_ESCAPE, VK_RETURN
|
||||||
|
];
|
||||||
|
|
||||||
pub struct KeyboardOutput {
|
pub struct KeyboardOutput {
|
||||||
ground_to_idx: [usize; 41],
|
ground_to_idx: [usize; 41],
|
||||||
idx_to_keycode: [u16; 41],
|
idx_to_keycode: [u16; 41],
|
||||||
@ -78,6 +96,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,
|
||||||
|
KeyboardLayout::Neardayo => &VOLTEX_KB_MAP_NEARDAYO,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ground_to_idx = [0 as usize; 41];
|
let mut ground_to_idx = [0 as usize; 41];
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use palette::{FromColor, Hsv, Srgb};
|
use palette::{FromColor, Hsv, Srgb};
|
||||||
use serialport::{ClearBuffer, SerialPort};
|
use serialport::{ClearBuffer, SerialPort};
|
||||||
@ -5,19 +6,22 @@ use std::{
|
|||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
use tokio::time::{interval, Interval};
|
||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::{LedMode, ReactiveLayout},
|
config::{LedMode, ReactiveLayout},
|
||||||
controller_state::{FullState, LedState},
|
controller_state::{FullState, LedState},
|
||||||
utils::Buffer,
|
utils::Buffer,
|
||||||
voltex::VoltexState,
|
voltex::VoltexState,
|
||||||
worker::ThreadJob,
|
worker::AsyncJob,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct LedJob {
|
pub struct LedJob {
|
||||||
state: FullState,
|
state: FullState,
|
||||||
mode: LedMode,
|
mode: LedMode,
|
||||||
serial_port: Option<Box<dyn SerialPort>>,
|
serial_port: Option<Box<dyn SerialPort>>,
|
||||||
|
started: Instant,
|
||||||
|
timer: Interval,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LedJob {
|
impl LedJob {
|
||||||
@ -26,6 +30,8 @@ impl LedJob {
|
|||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
mode: mode.clone(),
|
mode: mode.clone(),
|
||||||
serial_port: None,
|
serial_port: None,
|
||||||
|
started: Instant::now(),
|
||||||
|
timer: interval(Duration::from_micros(33333)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,29 +72,29 @@ impl LedJob {
|
|||||||
led_state.led_state.fill(0);
|
led_state.led_state.fill(0);
|
||||||
|
|
||||||
// Fixed
|
// Fixed
|
||||||
led_state.paint(3, &[0, 0, 64]);
|
led_state.paint(3, &[10, 100, 180]);
|
||||||
for idx in 0..5 {
|
for idx in 0..5 {
|
||||||
led_state.paint(7 + idx * 4, &[64, 64, 64]);
|
led_state.paint(7 + idx * 4, &[64, 64, 64]);
|
||||||
}
|
}
|
||||||
led_state.paint(27, &[64, 0, 0]);
|
led_state.paint(27, &[180, 10, 110]);
|
||||||
|
|
||||||
let voltex_state = VoltexState::from_flat(flat_controller_state);
|
let voltex_state = VoltexState::from_flat(flat_controller_state);
|
||||||
|
|
||||||
// Left laser
|
// Left laser
|
||||||
for (idx, state) in voltex_state.laser[0..2].iter().enumerate() {
|
for (idx, state) in voltex_state.laser[0..2].iter().enumerate() {
|
||||||
if *state {
|
if *state {
|
||||||
led_state.paint(0 + idx * 4, &[0, 0, 255]);
|
led_state.paint(0 + idx * 4, &[70, 230, 250]);
|
||||||
led_state.paint(1 + idx * 4, &[0, 0, 255]);
|
led_state.paint(1 + idx * 4, &[70, 230, 250]);
|
||||||
led_state.paint(2 + idx * 4, &[0, 0, 255]);
|
led_state.paint(2 + idx * 4, &[70, 230, 250]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right laser
|
// Right laser
|
||||||
for (idx, state) in voltex_state.laser[2..4].iter().enumerate() {
|
for (idx, state) in voltex_state.laser[2..4].iter().enumerate() {
|
||||||
if *state {
|
if *state {
|
||||||
led_state.paint(24 + idx * 4, &[255, 0, 0]);
|
led_state.paint(24 + idx * 4, &[250, 60, 200]);
|
||||||
led_state.paint(25 + idx * 4, &[255, 0, 0]);
|
led_state.paint(25 + idx * 4, &[255, 60, 200]);
|
||||||
led_state.paint(26 + idx * 4, &[255, 0, 0]);
|
led_state.paint(26 + idx * 4, &[255, 60, 200]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,17 +109,20 @@ impl LedJob {
|
|||||||
// Fx
|
// Fx
|
||||||
for (idx, state) in voltex_state.fx.iter().enumerate() {
|
for (idx, state) in voltex_state.fx.iter().enumerate() {
|
||||||
if *state {
|
if *state {
|
||||||
led_state.paint(9 + idx * 8, &[255, 0, 0]);
|
led_state.paint(9 + idx * 8, &[250, 100, 30]);
|
||||||
led_state.paint(11 + idx * 8, &[255, 0, 0]);
|
led_state.paint(11 + idx * 8, &[250, 100, 30]);
|
||||||
led_state.paint(13 + idx * 8, &[255, 0, 0]);
|
led_state.paint(13 + idx * 8, &[250, 100, 30]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LedMode::Attract => {
|
LedMode::Attract => {
|
||||||
let now = Instant::now();
|
let theta = self
|
||||||
let theta = (now - led_state.start).div_duration_f64(Duration::from_secs(4)) % 1.0;
|
.started
|
||||||
|
.elapsed()
|
||||||
|
.div_duration_f64(Duration::from_secs(4))
|
||||||
|
% 1.0;
|
||||||
for idx in 0..31 {
|
for idx in 0..31 {
|
||||||
let slice_theta = (&theta + (idx as f64) / 32.0) % 1.0;
|
let slice_theta = (&theta + (idx as f64) / 32.0) % 1.0;
|
||||||
let color = Srgb::from_color(Hsv::new(slice_theta * 360.0, 1.0, 1.0)).into_format::<u8>();
|
let color = Srgb::from_color(Hsv::new(slice_theta * 360.0, 1.0, 1.0)).into_format::<u8>();
|
||||||
@ -147,8 +156,9 @@ impl LedJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadJob for LedJob {
|
#[async_trait]
|
||||||
fn setup(&mut self) -> bool {
|
impl AsyncJob for LedJob {
|
||||||
|
async fn setup(&mut self) -> bool {
|
||||||
match &self.mode {
|
match &self.mode {
|
||||||
LedMode::Serial { port } => {
|
LedMode::Serial { port } => {
|
||||||
info!(
|
info!(
|
||||||
@ -173,14 +183,14 @@ impl ThreadJob for LedJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) -> bool {
|
async fn tick(&mut self) -> bool {
|
||||||
let mut flat_controller_state: Option<Vec<bool>> = None;
|
let mut flat_controller_state: Option<Vec<bool>> = None;
|
||||||
let mut serial_buffer: Option<Buffer> = None;
|
let mut serial_buffer: Option<Buffer> = None;
|
||||||
|
|
||||||
// Do the IO here
|
// Do the IO here
|
||||||
match self.mode {
|
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();
|
||||||
flat_controller_state = Some(controller_state_handle.flat(&sensitivity));
|
flat_controller_state = Some(controller_state_handle.flat(&sensitivity));
|
||||||
}
|
}
|
||||||
LedMode::Serial { .. } => {
|
LedMode::Serial { .. } => {
|
||||||
@ -209,7 +219,7 @@ impl ThreadJob for LedJob {
|
|||||||
|
|
||||||
// Then calculate and transfer
|
// 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();
|
||||||
self.calc_lights(
|
self.calc_lights(
|
||||||
flat_controller_state.as_ref(),
|
flat_controller_state.as_ref(),
|
||||||
serial_buffer.as_ref(),
|
serial_buffer.as_ref(),
|
||||||
@ -217,10 +227,9 @@ impl ThreadJob for LedJob {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
// thread::sleep(Duration::from_millis(30));
|
// thread::sleep(Duration::from_millis(30));
|
||||||
spin_sleep::sleep(Duration::from_micros(33333));
|
// spin_sleep::sleep(Duration::from_micros(33333));
|
||||||
|
self.timer.tick().await;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use log::info;
|
use log::info;
|
||||||
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::Arc,
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
@ -34,7 +35,7 @@ impl Manager {
|
|||||||
let join_handle = thread::spawn(move || {
|
let join_handle = thread::spawn(move || {
|
||||||
info!("Manager thread started");
|
info!("Manager thread started");
|
||||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||||
.worker_threads(2)
|
.worker_threads(4)
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -47,18 +48,18 @@ impl Manager {
|
|||||||
match rx_config.recv().await {
|
match rx_config.recv().await {
|
||||||
Some(config) => {
|
Some(config) => {
|
||||||
info!("Rebuilding context");
|
info!("Rebuilding context");
|
||||||
let mut context_handle = context_cloned.lock().unwrap();
|
let mut context_handle = context_cloned.lock();
|
||||||
context_handle.take();
|
context_handle.take();
|
||||||
|
|
||||||
let new_context = Context::new(config);
|
let new_context = Context::new(config);
|
||||||
let new_state = new_context.clone_state();
|
let new_state = new_context.clone_state();
|
||||||
context_handle.replace(new_context);
|
context_handle.replace(new_context);
|
||||||
|
|
||||||
let mut state_handle = state_cloned.lock().unwrap();
|
let mut state_handle = state_cloned.lock();
|
||||||
state_handle.replace(new_state);
|
state_handle.replace(new_state);
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let mut context_handle = context_cloned.lock().unwrap();
|
let mut context_handle = context_cloned.lock();
|
||||||
context_handle.take();
|
context_handle.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,12 +84,12 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_get_state(&self) -> Option<FullState> {
|
pub fn try_get_state(&self) -> Option<FullState> {
|
||||||
let state_handle = self.state.lock().unwrap();
|
let state_handle = self.state.lock();
|
||||||
state_handle.as_ref().map(|x| x.clone())
|
state_handle.as_ref().map(|x| x.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_timer_state(&self) -> String {
|
pub fn get_timer_state(&self) -> String {
|
||||||
let context_handle = self.context.lock().unwrap();
|
let context_handle = self.context.lock();
|
||||||
context_handle
|
context_handle
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|context| context.timer_state())
|
.map(|context| context.timer_state())
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
use log::error;
|
use log::error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use tokio::time::{interval, Interval};
|
||||||
|
|
||||||
use crate::slider_io::{
|
use crate::slider_io::{
|
||||||
config::OutputMode, controller_state::FullState, gamepad::GamepadOutput,
|
config::OutputMode, controller_state::FullState, gamepad::GamepadOutput,
|
||||||
keyboard::KeyboardOutput, worker::ThreadJob,
|
keyboard::KeyboardOutput, worker::AsyncJob,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait OutputHandler: Send {
|
pub trait OutputHandler: Send {
|
||||||
@ -14,9 +16,9 @@ pub trait OutputHandler: Send {
|
|||||||
pub struct OutputJob {
|
pub struct OutputJob {
|
||||||
state: FullState,
|
state: FullState,
|
||||||
mode: OutputMode,
|
mode: OutputMode,
|
||||||
t: u64,
|
|
||||||
sensitivity: u8,
|
sensitivity: u8,
|
||||||
handler: Option<Box<dyn OutputHandler>>,
|
handler: Option<Box<dyn OutputHandler>>,
|
||||||
|
timer: Interval,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputJob {
|
impl OutputJob {
|
||||||
@ -24,24 +26,25 @@ impl OutputJob {
|
|||||||
Self {
|
Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
mode: mode.clone(),
|
mode: mode.clone(),
|
||||||
t: 0,
|
|
||||||
sensitivity: 0,
|
sensitivity: 0,
|
||||||
handler: None,
|
handler: None,
|
||||||
|
timer: interval(Duration::MAX),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadJob for OutputJob {
|
#[async_trait]
|
||||||
fn setup(&mut self) -> bool {
|
impl AsyncJob for OutputJob {
|
||||||
|
async fn setup(&mut self) -> bool {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
OutputMode::Keyboard {
|
OutputMode::Keyboard {
|
||||||
layout,
|
layout,
|
||||||
polling,
|
polling,
|
||||||
sensitivity,
|
sensitivity,
|
||||||
} => {
|
} => {
|
||||||
self.t = polling.to_t_u64();
|
|
||||||
self.sensitivity = sensitivity;
|
self.sensitivity = sensitivity;
|
||||||
self.handler = Some(Box::new(KeyboardOutput::new(layout.clone())));
|
self.handler = Some(Box::new(KeyboardOutput::new(layout.clone())));
|
||||||
|
self.timer = interval(Duration::from_micros(polling.to_t_u64()));
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -50,9 +53,10 @@ impl ThreadJob for OutputJob {
|
|||||||
polling,
|
polling,
|
||||||
sensitivity,
|
sensitivity,
|
||||||
} => {
|
} => {
|
||||||
self.t = polling.to_t_u64();
|
|
||||||
self.sensitivity = sensitivity;
|
self.sensitivity = sensitivity;
|
||||||
let handler = GamepadOutput::new(layout.clone());
|
let handler = GamepadOutput::new(layout.clone());
|
||||||
|
self.timer = interval(Duration::from_micros(polling.to_t_u64()));
|
||||||
|
|
||||||
match handler {
|
match handler {
|
||||||
Some(handler) => {
|
Some(handler) => {
|
||||||
self.handler = Some(Box::new(handler));
|
self.handler = Some(Box::new(handler));
|
||||||
@ -68,22 +72,24 @@ impl ThreadJob for OutputJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) -> bool {
|
async fn tick(&mut self) -> bool {
|
||||||
let flat_controller_state: Vec<bool>;
|
let flat_controller_state: Vec<bool>;
|
||||||
{
|
{
|
||||||
let controller_state_handle = self.state.controller_state.lock().unwrap();
|
let controller_state_handle = self.state.controller_state.lock();
|
||||||
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
|
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handler) = self.handler.as_mut() {
|
if let Some(handler) = self.handler.as_mut() {
|
||||||
handler.tick(&flat_controller_state);
|
handler.tick(&flat_controller_state);
|
||||||
}
|
}
|
||||||
spin_sleep::sleep(Duration::from_micros(self.t));
|
self.timer.tick().await;
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn teardown(&mut self) {
|
impl Drop for OutputJob {
|
||||||
|
fn drop(&mut self) {
|
||||||
if let Some(handler) = self.handler.as_mut() {
|
if let Some(handler) = self.handler.as_mut() {
|
||||||
handler.reset();
|
handler.reset();
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ use crate::slider_io::utils::LoopTimer;
|
|||||||
pub trait ThreadJob: Send {
|
pub trait ThreadJob: Send {
|
||||||
fn setup(&mut self) -> bool;
|
fn setup(&mut self) -> bool;
|
||||||
fn tick(&mut self) -> bool;
|
fn tick(&mut self) -> bool;
|
||||||
fn teardown(&mut self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ThreadWorker {
|
pub struct ThreadWorker {
|
||||||
@ -46,8 +45,7 @@ impl ThreadWorker {
|
|||||||
timer.tick();
|
timer.tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info!("Thread worker stopping internal {}", name);
|
info!("Thread worker received stop {}", name);
|
||||||
job.teardown();
|
|
||||||
})),
|
})),
|
||||||
stop_signal,
|
stop_signal,
|
||||||
}
|
}
|
||||||
@ -56,32 +54,88 @@ impl ThreadWorker {
|
|||||||
|
|
||||||
impl Drop for ThreadWorker {
|
impl Drop for ThreadWorker {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("Thread worker stopping {}", self.name);
|
info!("Thread worker stopping gracefully {}", self.name);
|
||||||
|
|
||||||
self.stop_signal.store(true, Ordering::SeqCst);
|
self.stop_signal.store(true, Ordering::SeqCst);
|
||||||
if let Some(thread) = self.thread.take() {
|
if let Some(thread) = self.thread.take() {
|
||||||
thread.join().ok();
|
thread.join().ok();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
info!("Thread worker stopped {}", self.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AsyncJob: Send + 'static {
|
pub trait AsyncJob: Send + 'static {
|
||||||
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F);
|
async fn setup(&mut self) -> bool;
|
||||||
|
async fn tick(&mut self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AsyncWorker {
|
pub struct AsyncWorker {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
task: Option<task::JoinHandle<()>>,
|
task: Option<task::JoinHandle<()>>,
|
||||||
stop_signal: Option<oneshot::Sender<()>>,
|
stop_signal: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncWorker {
|
impl AsyncWorker {
|
||||||
pub fn new<T>(name: &'static str, job: T) -> AsyncWorker
|
pub fn new<T>(name: &'static str, mut job: T, mut timer: LoopTimer) -> Self
|
||||||
where
|
where
|
||||||
T: AsyncJob,
|
T: AsyncJob,
|
||||||
{
|
{
|
||||||
info!("Async worker starting {}", name);
|
let stop_signal = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
|
let stop_signal_clone = Arc::clone(&stop_signal);
|
||||||
|
let task = tokio::spawn(async move {
|
||||||
|
let setup_res = job.setup().await;
|
||||||
|
stop_signal_clone.store(!setup_res, Ordering::SeqCst);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if stop_signal_clone.load(Ordering::SeqCst) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if job.tick().await {
|
||||||
|
timer.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("Async worker received stop {}", name);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
task: Some(task),
|
||||||
|
stop_signal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AsyncWorker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
info!("Async worker stopping gracefully {}", self.name);
|
||||||
|
|
||||||
|
self.stop_signal.store(true, Ordering::SeqCst);
|
||||||
|
drop(self.task.take());
|
||||||
|
|
||||||
|
info!("Async worker stopped {}", self.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait AsyncHaltableJob: Send + 'static {
|
||||||
|
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AsyncHaltableWorker {
|
||||||
|
name: &'static str,
|
||||||
|
task: Option<task::JoinHandle<()>>,
|
||||||
|
stop_signal: Option<oneshot::Sender<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncHaltableWorker {
|
||||||
|
pub fn new<T>(name: &'static str, job: T) -> Self
|
||||||
|
where
|
||||||
|
T: AsyncHaltableJob,
|
||||||
|
{
|
||||||
|
info!("AsyncHaltable worker starting {}", name);
|
||||||
|
|
||||||
let (send_stop, recv_stop) = oneshot::channel::<()>();
|
let (send_stop, recv_stop) = oneshot::channel::<()>();
|
||||||
|
|
||||||
@ -89,11 +143,12 @@ impl AsyncWorker {
|
|||||||
job
|
job
|
||||||
.run(async move {
|
.run(async move {
|
||||||
recv_stop.await.ok();
|
recv_stop.await.ok();
|
||||||
|
info!("AsyncHaltable worker received stop {}", name);
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
AsyncWorker {
|
Self {
|
||||||
name,
|
name,
|
||||||
task: Some(task),
|
task: Some(task),
|
||||||
stop_signal: Some(send_stop),
|
stop_signal: Some(send_stop),
|
||||||
@ -101,13 +156,14 @@ impl AsyncWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for AsyncWorker {
|
impl Drop for AsyncHaltableWorker {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!("Async worker stopping {}", self.name);
|
info!("AsyncHaltable worker stopping gracefully {}", self.name);
|
||||||
|
|
||||||
if let Some(stop_signal) = self.stop_signal.take() {
|
if let Some(stop_signal) = self.stop_signal.take() {
|
||||||
stop_signal.send(()).ok();
|
stop_signal.send(()).ok();
|
||||||
}
|
}
|
||||||
self.task.take();
|
self.task.take();
|
||||||
|
info!("AsyncHaltable worker stopped {}", self.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"package": {
|
"package": {
|
||||||
"productName": "slidershim",
|
"productName": "slidershim",
|
||||||
"version": "0.1.3"
|
"version": "0.1.4"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"distDir": "../public",
|
"distDir": "../public",
|
||||||
|
@ -179,6 +179,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="label">Output Mode</div>
|
<div class="label">Output Mode</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
@ -189,6 +190,7 @@
|
|||||||
<option value="kb-32-yuancon">Keyboard 32-zone, Yuancon Layout</option>
|
<option value="kb-32-yuancon">Keyboard 32-zone, Yuancon Layout</option>
|
||||||
<option value="kb-8-deemo">Keyboard 8-zone, Deemo Layout</option>
|
<option value="kb-8-deemo">Keyboard 8-zone, Deemo Layout</option>
|
||||||
<option value="kb-voltex">Keyboard 10-zone, Voltex Layout</option>
|
<option value="kb-voltex">Keyboard 10-zone, Voltex Layout</option>
|
||||||
|
<option value="kb-neardayo">Keyboard 10-zone, Neardayo Layout</option>
|
||||||
<option value="gamepad-voltex">XBOX 360 Gamepad, Voltex Layout</option>
|
<option value="gamepad-voltex">XBOX 360 Gamepad, Voltex Layout</option>
|
||||||
<option value="gamepad-neardayo"
|
<option value="gamepad-neardayo"
|
||||||
>XBOX 360 Gamepad, Neardayo Layout</option
|
>XBOX 360 Gamepad, Neardayo Layout</option
|
||||||
@ -206,7 +208,7 @@
|
|||||||
<option value="100">100 Hz</option>
|
<option value="100">100 Hz</option>
|
||||||
<option value="250">250 Hz</option>
|
<option value="250">250 Hz</option>
|
||||||
<option value="500">500 Hz</option>
|
<option value="500">500 Hz</option>
|
||||||
<option value="1000">1000 Hz (Unstable, may use a lot of CPU)</option>
|
<option value="1000">1000 Hz</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -263,6 +265,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="label">LED Mode</div>
|
<div class="label">LED Mode</div>
|
||||||
<div class="input">
|
<div class="input">
|
||||||
|
Loading…
Reference in New Issue
Block a user