mirror of
https://github.com/4yn/slidershim.git
synced 2024-11-23 21:40:57 +01:00
timer
This commit is contained in:
parent
a5c89f00cb
commit
98509250d6
@ -33,7 +33,7 @@ body {
|
||||
background: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
justify-content: space-between;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -42,8 +42,13 @@ body {
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.titlebar-front {
|
||||
background: #0000;
|
||||
}
|
||||
|
||||
.header-icon {
|
||||
max-height: 100%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.header-icon img {
|
||||
@ -54,6 +59,15 @@ body {
|
||||
.header {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 500;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.header-space {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.header-timer {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
/* main */
|
||||
|
@ -13,12 +13,5 @@
|
||||
<script defer src="/build/bundle.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div data-tauri-drag-region class="titlebar">
|
||||
<div data-tauri-drag-region class="header-icon">
|
||||
<img src="/icon.png" />
|
||||
</div>
|
||||
<div data-tauri-drag-region class="header"> slidershim</div>
|
||||
</div>
|
||||
</body>
|
||||
<body></body>
|
||||
</html>
|
||||
|
20
src-tauri/Cargo.lock
generated
20
src-tauri/Cargo.lock
generated
@ -115,6 +115,12 @@ dependencies = [
|
||||
"system-deps 3.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic_float"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62af46d040ba9df09edc6528dae9d8e49f5f3e82f55b7d2ec31a733c38dbc49d"
|
||||
|
||||
[[package]]
|
||||
name = "attohttpc"
|
||||
version = "0.17.0"
|
||||
@ -2933,9 +2939,10 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
|
||||
|
||||
[[package]]
|
||||
name = "slidershim"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atomic_float",
|
||||
"base64",
|
||||
"directories",
|
||||
"env_logger",
|
||||
@ -2954,6 +2961,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serialport",
|
||||
"simple-logging",
|
||||
"spin_sleep",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tokio",
|
||||
@ -2995,6 +3003,16 @@ dependencies = [
|
||||
"system-deps 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin_sleep"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a98101bdc3833e192713c2af0b0dd2614f50d1cf1f7a97c5221b7aac052acc7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "slidershim"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
description = "slidershim"
|
||||
authors = ["4yn"]
|
||||
license = ""
|
||||
@ -21,8 +21,11 @@ log = "0.4.14"
|
||||
env_logger = "0.9.0"
|
||||
simple-logging = "2.0.2"
|
||||
open = "2.0.2"
|
||||
atomic_float = "0.1.0"
|
||||
spin_sleep = "1.0.0"
|
||||
tauri = { version = "1.0.0-beta.8", features = ["shell-open", "system-tray"] }
|
||||
|
||||
|
||||
futures = "0.3.19"
|
||||
futures-util = "0.3.19"
|
||||
async-trait = "0.1.52"
|
||||
|
@ -140,9 +140,12 @@ fn main() {
|
||||
let manager_clone = Arc::clone(&manager);
|
||||
app.listen_global("queryState", move |_| {
|
||||
// app_handle.emit_all("showState", "@@@");
|
||||
let snapshot = {
|
||||
let (snapshot, timer) = {
|
||||
let manager_handle = manager_clone.lock().unwrap();
|
||||
manager_handle.try_get_state().map(|x| x.snapshot())
|
||||
(
|
||||
manager_handle.try_get_state().map(|x| x.snapshot()),
|
||||
manager_handle.get_timer_state(),
|
||||
)
|
||||
};
|
||||
match snapshot {
|
||||
Some(snapshot) => {
|
||||
@ -150,6 +153,8 @@ fn main() {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
app_handle.emit_all("showTimerState", timer).ok();
|
||||
});
|
||||
|
||||
// Config set event
|
||||
|
@ -1,4 +1,6 @@
|
||||
use atomic_float::AtomicF64;
|
||||
use log::info;
|
||||
use std::sync::{atomic::Ordering, Arc};
|
||||
|
||||
use crate::slider_io::{
|
||||
brokenithm::BrokenithmJob,
|
||||
@ -7,6 +9,7 @@ use crate::slider_io::{
|
||||
device::HidDeviceJob,
|
||||
led::LedJob,
|
||||
output::OutputJob,
|
||||
utils::LoopTimer,
|
||||
worker::{AsyncWorker, ThreadWorker},
|
||||
};
|
||||
|
||||
@ -18,6 +21,7 @@ pub struct Context {
|
||||
brokenithm_worker: Option<AsyncWorker>,
|
||||
output_worker: Option<ThreadWorker>,
|
||||
led_worker: Option<ThreadWorker>,
|
||||
timers: Vec<(&'static str, Arc<AtomicF64>)>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@ -28,6 +32,7 @@ impl Context {
|
||||
info!("LED config {:?}", config.led_mode);
|
||||
|
||||
let state = FullState::new();
|
||||
let mut timers = vec![];
|
||||
|
||||
let (device_worker, brokenithm_worker) = match &config.device_mode {
|
||||
DeviceMode::None => (None, None),
|
||||
@ -42,26 +47,41 @@ impl Context {
|
||||
)),
|
||||
),
|
||||
_ => (
|
||||
Some(ThreadWorker::new(
|
||||
"device",
|
||||
HidDeviceJob::from_config(&state, &config.device_mode),
|
||||
)),
|
||||
{
|
||||
let timer = LoopTimer::new();
|
||||
timers.push(("d", timer.fork()));
|
||||
Some(ThreadWorker::new(
|
||||
"device",
|
||||
HidDeviceJob::from_config(&state, &config.device_mode),
|
||||
timer,
|
||||
))
|
||||
},
|
||||
None,
|
||||
),
|
||||
};
|
||||
let output_worker = match &config.output_mode {
|
||||
OutputMode::None => None,
|
||||
_ => Some(ThreadWorker::new(
|
||||
"output",
|
||||
OutputJob::new(&state, &config.output_mode),
|
||||
)),
|
||||
_ => {
|
||||
let timer = LoopTimer::new();
|
||||
timers.push(("o", timer.fork()));
|
||||
Some(ThreadWorker::new(
|
||||
"output",
|
||||
OutputJob::new(&state, &config.output_mode),
|
||||
timer,
|
||||
))
|
||||
}
|
||||
};
|
||||
let led_worker = match &config.led_mode {
|
||||
LedMode::None => None,
|
||||
_ => Some(ThreadWorker::new(
|
||||
"led",
|
||||
LedJob::new(&state, &config.led_mode),
|
||||
)),
|
||||
_ => {
|
||||
let timer = LoopTimer::new();
|
||||
timers.push(("l", timer.fork()));
|
||||
Some(ThreadWorker::new(
|
||||
"led",
|
||||
LedJob::new(&state, &config.led_mode),
|
||||
timer,
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
Self {
|
||||
@ -71,10 +91,20 @@ impl Context {
|
||||
brokenithm_worker,
|
||||
output_worker,
|
||||
led_worker,
|
||||
timers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_state(&self) -> FullState {
|
||||
self.state.clone()
|
||||
}
|
||||
|
||||
pub fn timer_state(&self) -> String {
|
||||
self
|
||||
.timers
|
||||
.iter()
|
||||
.map(|(s, f)| format!("{}:{:.1}/s", s, f.load(Ordering::SeqCst)))
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +101,9 @@ impl HidDeviceJob {
|
||||
.take(31)
|
||||
.zip(led_state.led_state.chunks(3).rev())
|
||||
{
|
||||
buf_chunk[0] = state_chunk[2];
|
||||
buf_chunk[0] = state_chunk[1];
|
||||
buf_chunk[1] = state_chunk[0];
|
||||
buf_chunk[2] = state_chunk[1];
|
||||
buf_chunk[2] = state_chunk[2];
|
||||
}
|
||||
buf.data[96..240].fill(0);
|
||||
},
|
||||
@ -139,9 +139,9 @@ impl HidDeviceJob {
|
||||
.take(31)
|
||||
.zip(led_state.led_state.chunks(3).rev())
|
||||
{
|
||||
buf_chunk[0] = state_chunk[2];
|
||||
buf_chunk[0] = state_chunk[1];
|
||||
buf_chunk[1] = state_chunk[0];
|
||||
buf_chunk[2] = state_chunk[1];
|
||||
buf_chunk[2] = state_chunk[2];
|
||||
}
|
||||
buf.data[96..240].fill(0);
|
||||
},
|
||||
@ -224,9 +224,10 @@ impl ThreadJob for HidDeviceJob {
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self) {
|
||||
fn tick(&mut self) -> bool {
|
||||
// Input loop
|
||||
let handle = self.handle.as_mut().unwrap();
|
||||
let mut work = false;
|
||||
|
||||
{
|
||||
let res = handle
|
||||
@ -239,6 +240,7 @@ impl ThreadJob for HidDeviceJob {
|
||||
self.read_buf.len = res;
|
||||
// debug!("{:?}", self.read_buf.slice());
|
||||
if self.read_buf.len != 0 {
|
||||
work = true;
|
||||
let mut controller_state_handle = self.state.controller_state.lock().unwrap();
|
||||
(self.read_callback)(&self.read_buf, controller_state_handle.deref_mut());
|
||||
}
|
||||
@ -267,12 +269,13 @@ impl ThreadJob for HidDeviceJob {
|
||||
})
|
||||
.unwrap_or(0);
|
||||
if res == self.led_buf.len + 1 {
|
||||
work = true;
|
||||
self.led_buf.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thread::sleep(Duration::from_millis(10));
|
||||
work
|
||||
}
|
||||
|
||||
fn teardown(&mut self) {
|
||||
|
@ -174,7 +174,7 @@ impl ThreadJob for LedJob {
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self) {
|
||||
fn tick(&mut self) -> bool {
|
||||
let mut flat_controller_state: Option<Vec<bool>> = None;
|
||||
let mut serial_buffer: Option<Buffer> = None;
|
||||
|
||||
@ -217,7 +217,10 @@ impl ThreadJob for LedJob {
|
||||
led_state_handle.deref_mut(),
|
||||
);
|
||||
}
|
||||
thread::sleep(Duration::from_millis(30));
|
||||
// thread::sleep(Duration::from_millis(30));
|
||||
spin_sleep::sleep(Duration::from_millis(30));
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn teardown(&mut self) {}
|
||||
|
@ -14,6 +14,7 @@ use super::controller_state::FullState;
|
||||
|
||||
pub struct Manager {
|
||||
state: Arc<Mutex<Option<FullState>>>,
|
||||
context: Arc<Mutex<Option<Context>>>,
|
||||
join_handle: Option<JoinHandle<()>>,
|
||||
tx_config: mpsc::UnboundedSender<Config>,
|
||||
tx_stop: Option<oneshot::Sender<()>>,
|
||||
@ -70,6 +71,7 @@ impl Manager {
|
||||
|
||||
Self {
|
||||
state,
|
||||
context,
|
||||
join_handle: Some(join_handle),
|
||||
tx_config,
|
||||
tx_stop: Some(tx_stop),
|
||||
@ -84,6 +86,14 @@ impl Manager {
|
||||
let state_handle = self.state.lock().unwrap();
|
||||
state_handle.as_ref().map(|x| x.clone())
|
||||
}
|
||||
|
||||
pub fn get_timer_state(&self) -> String {
|
||||
let context_handle = self.context.lock().unwrap();
|
||||
context_handle
|
||||
.as_ref()
|
||||
.map(|context| context.timer_state())
|
||||
.unwrap_or("".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Manager {
|
||||
|
@ -50,7 +50,7 @@ impl ThreadJob for OutputJob {
|
||||
true
|
||||
}
|
||||
|
||||
fn tick(&mut self) {
|
||||
fn tick(&mut self) -> bool {
|
||||
let flat_controller_state: Vec<bool>;
|
||||
{
|
||||
let controller_state_handle = self.state.controller_state.lock().unwrap();
|
||||
@ -58,7 +58,10 @@ impl ThreadJob for OutputJob {
|
||||
}
|
||||
|
||||
self.handler.tick(&flat_controller_state);
|
||||
thread::sleep(Duration::from_millis(self.t));
|
||||
// thread::sleep(Duration::from_millis(self.t));
|
||||
spin_sleep::sleep(Duration::from_millis(self.t));
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn teardown(&mut self) {
|
||||
|
@ -1,4 +1,10 @@
|
||||
use std::{error::Error, fmt};
|
||||
use atomic_float::AtomicF64;
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub struct Buffer {
|
||||
pub data: [u8; 256],
|
||||
@ -44,3 +50,45 @@ pub fn list_ips() -> Result<Vec<String>, Box<dyn Error>> {
|
||||
|
||||
Ok(ips)
|
||||
}
|
||||
|
||||
pub struct LoopTimer {
|
||||
cap: usize,
|
||||
cur: usize,
|
||||
buf: Vec<Instant>,
|
||||
freq: Arc<AtomicF64>,
|
||||
}
|
||||
|
||||
impl LoopTimer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cap: 100,
|
||||
cur: 0,
|
||||
buf: vec![Instant::now() - Duration::from_secs(10); 100],
|
||||
freq: Arc::new(AtomicF64::new(0.0)),
|
||||
}
|
||||
}
|
||||
pub fn tick(&mut self) {
|
||||
let last = self.buf[self.cur];
|
||||
let now = Instant::now();
|
||||
self.buf[self.cur] = now;
|
||||
|
||||
let delta = (now - last) / 100 + Duration::from_micros(1);
|
||||
let freq = Duration::from_millis(1000)
|
||||
.div_duration_f64(delta)
|
||||
.clamp(0.0, 9999.0);
|
||||
self.freq.store(freq, Ordering::SeqCst);
|
||||
|
||||
self.cur = match self.cur + 1 {
|
||||
cur if cur == self.cap => 0,
|
||||
cur => cur,
|
||||
}
|
||||
}
|
||||
|
||||
// pub fn reset(&mut self) {
|
||||
// self.buf = vec![Instant::now(); 100];
|
||||
// }
|
||||
|
||||
pub fn fork(&self) -> Arc<AtomicF64> {
|
||||
Arc::clone(&self.freq)
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ use std::{
|
||||
|
||||
use tokio::{sync::oneshot, task};
|
||||
|
||||
use crate::slider_io::utils::LoopTimer;
|
||||
|
||||
pub trait ThreadJob: Send {
|
||||
fn setup(&mut self) -> bool;
|
||||
fn tick(&mut self);
|
||||
fn tick(&mut self) -> bool;
|
||||
fn teardown(&mut self);
|
||||
}
|
||||
|
||||
@ -24,7 +26,7 @@ pub struct ThreadWorker {
|
||||
}
|
||||
|
||||
impl ThreadWorker {
|
||||
pub fn new<T: 'static + ThreadJob>(name: &'static str, mut job: T) -> Self {
|
||||
pub fn new<T: 'static + ThreadJob>(name: &'static str, mut job: T, mut timer: LoopTimer) -> Self {
|
||||
info!("Thread worker starting {}", name);
|
||||
|
||||
let stop_signal = Arc::new(AtomicBool::new(false));
|
||||
@ -40,7 +42,9 @@ impl ThreadWorker {
|
||||
if stop_signal_clone.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
job.tick();
|
||||
if job.tick() {
|
||||
timer.tick();
|
||||
}
|
||||
}
|
||||
info!("Thread worker stopping internal {}", name);
|
||||
job.teardown();
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "slidershim",
|
||||
"version": "0.1.2"
|
||||
"version": "0.1.3"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../public",
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { emit, listen } from "@tauri-apps/api/event";
|
||||
import { open } from "@tauri-apps/api/shell";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
|
||||
import Link from "./Link.svelte";
|
||||
import Preview from "./Preview.svelte";
|
||||
@ -24,11 +24,12 @@
|
||||
}
|
||||
|
||||
// let debugstr = "";
|
||||
|
||||
let versionString = "";
|
||||
let ips: Array<string> = [];
|
||||
let polling = null;
|
||||
let tick = 0;
|
||||
let previewData = Array(131).fill(0);
|
||||
let timerData = "";
|
||||
|
||||
function updatePolling(enabled) {
|
||||
if (!!polling) {
|
||||
@ -65,6 +66,9 @@
|
||||
await listen("showState", (event) => {
|
||||
previewData = event.payload as any;
|
||||
});
|
||||
await listen("showTimerState", (event) => {
|
||||
timerData = event.payload as string;
|
||||
});
|
||||
|
||||
await listen("listIps", (event) => {
|
||||
ips = (event.payload as Array<string>).filter(
|
||||
@ -83,6 +87,8 @@
|
||||
console.log("ackHide");
|
||||
updatePolling(false);
|
||||
});
|
||||
|
||||
versionString = ` ${await getVersion()}`;
|
||||
});
|
||||
|
||||
// Emit events
|
||||
@ -124,16 +130,20 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="titlebar">
|
||||
<div class="header-icon">
|
||||
<img src="/icon.png" />
|
||||
</div>
|
||||
<div class="header">
|
||||
slidershim{versionString}
|
||||
</div>
|
||||
<div class="header-space" />
|
||||
<div class="header-timer">
|
||||
{timerData}
|
||||
</div>
|
||||
</div>
|
||||
<div data-tauri-drag-region class="titlebar titlebar-front" />
|
||||
<main class="main">
|
||||
<!-- <div class="row titlebar" data-tauri-drag-region> -->
|
||||
<!-- <div class="header"> -->
|
||||
<!-- slidershim by @4yn -->
|
||||
<!-- slidershim -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div>
|
||||
{debugstr}
|
||||
</div> -->
|
||||
<div class="row">
|
||||
<Preview data={previewData} />
|
||||
</div>
|
||||
@ -148,7 +158,9 @@
|
||||
<option value="brokenithm">Brokenithm</option>
|
||||
<option value="brokenithm-led">Brokenithm + Led</option>
|
||||
<option value="brokenithm-ground">Brokenithm, Ground only</option>
|
||||
<option value="brokenithm-ground-led">Brokenithm + Led, Ground only</option>
|
||||
<option value="brokenithm-ground-led"
|
||||
>Brokenithm + Led, Ground only</option
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -192,7 +204,7 @@
|
||||
<option value="100">100 Hz</option>
|
||||
<option value="330">330 Hz</option>
|
||||
<option value="500">500 Hz</option>
|
||||
<option value="1000">1000 Hz</option>
|
||||
<option value="1000">1000 Hz (Unstable, may use a lot of CPU)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user