mirror of
https://github.com/4yn/slidershim.git
synced 2024-11-30 16:24:27 +01:00
Frontend polling
This commit is contained in:
parent
bfb7f7dc95
commit
8a67094c9a
117
src-tauri/res/www/index-go.html
Normal file
117
src-tauri/res/www/index-go.html
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>slidershim-brokenithm</title>
|
||||
<meta charset="utf8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<link rel="apple-touch-icon" href="favicon.ico" />
|
||||
<style>
|
||||
#fullscreen {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
background: #000000;
|
||||
color: hotpink;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
touch-action: none;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.air-container {
|
||||
/* display: flex; */
|
||||
display: none;
|
||||
flex-flow: column nowrap;
|
||||
align-items: stretch;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.touch-container {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: stretch;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.grow > * {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.key {
|
||||
flex: 1;
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
.key[data-active] {
|
||||
background-color: hotpink;
|
||||
}
|
||||
|
||||
.key.air[data-active] {
|
||||
background-color: skyblue;
|
||||
}
|
||||
|
||||
canvas {
|
||||
touch-action: none;
|
||||
margin: 0px -1.5625vw;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="fullscreen">
|
||||
<!-- Offset for LED display -->
|
||||
<div class="container">
|
||||
<div class="air-container grow"></div>
|
||||
<div class="touch-container grow">
|
||||
<canvas id="canvas" width="33" height="1"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Hitbox Divs -->
|
||||
<div class="container" id="main">
|
||||
<div class="air-container grow">
|
||||
<div class="air key" data-air="1" data-kflag="5"></div>
|
||||
<div class="air key" data-air="1" data-kflag="4"></div>
|
||||
<div class="air key" data-air="1" data-kflag="3"></div>
|
||||
<div class="air key" data-air="1" data-kflag="2"></div>
|
||||
<div class="air key" data-air="1" data-kflag="1"></div>
|
||||
<div class="air key" data-air="1" data-kflag="0"></div>
|
||||
</div>
|
||||
<div class="touch-container grow">
|
||||
<div class="key" data-kflag="0"></div>
|
||||
<div class="key" data-kflag="2"></div>
|
||||
<div class="key" data-kflag="4"></div>
|
||||
<div class="key" data-kflag="6"></div>
|
||||
<div class="key" data-kflag="8"></div>
|
||||
<div class="key" data-kflag="10"></div>
|
||||
<div class="key" data-kflag="12"></div>
|
||||
<div class="key" data-kflag="14"></div>
|
||||
<div class="key" data-kflag="16"></div>
|
||||
<div class="key" data-kflag="18"></div>
|
||||
<div class="key" data-kflag="20"></div>
|
||||
<div class="key" data-kflag="22"></div>
|
||||
<div class="key" data-kflag="24"></div>
|
||||
<div class="key" data-kflag="26"></div>
|
||||
<div class="key" data-kflag="28"></div>
|
||||
<div class="key" data-kflag="30"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/config.js"></script>
|
||||
<script src="/app.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>brokenithm-kb</title>
|
||||
<title>slidershim-brokenithm</title>
|
||||
<meta charset="utf8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
|
@ -2,7 +2,7 @@ extern crate slidershim;
|
||||
|
||||
use std::io;
|
||||
|
||||
use slidershim::slider_io::{Config, Manager};
|
||||
use slidershim::slider_io::{Config, Context};
|
||||
|
||||
fn main() {
|
||||
env_logger::Builder::new()
|
||||
@ -57,7 +57,7 @@ fn main() {
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
let manager = Manager::new(config);
|
||||
let manager = Context::new(config);
|
||||
|
||||
let mut input = String::new();
|
||||
let string = io::stdin().read_line(&mut input).unwrap();
|
||||
|
@ -18,10 +18,12 @@ use tauri::{
|
||||
};
|
||||
|
||||
fn show_window<R: Runtime>(handle: &AppHandle<R>) {
|
||||
handle.emit_all("ackShow", "");
|
||||
handle.get_window("main").unwrap().show().ok();
|
||||
}
|
||||
|
||||
fn hide_window<R: Runtime>(handle: &AppHandle<R>) {
|
||||
handle.emit_all("ackHide", "");
|
||||
handle.get_window("main").unwrap().hide().ok();
|
||||
}
|
||||
|
||||
@ -36,14 +38,13 @@ fn main() {
|
||||
.init();
|
||||
|
||||
let config = Arc::new(Mutex::new(Some(slider_io::Config::default())));
|
||||
let manager: Arc<Mutex<Option<slider_io::Manager>>> = Arc::new(Mutex::new(None));
|
||||
let manager = Arc::new(Mutex::new(slider_io::Manager::new()));
|
||||
{
|
||||
let config_handle = config.lock().unwrap();
|
||||
let config_handle_ref = config_handle.as_ref().unwrap();
|
||||
config_handle_ref.save();
|
||||
// let mut manager_handle = manager.lock().unwrap();
|
||||
// manager_handle.take();
|
||||
// manager_handle.replace(slider_io::Manager::new(config_handle_ref.clone()));
|
||||
let manager_handle = manager.lock().unwrap();
|
||||
manager_handle.update_config(config_handle_ref.clone());
|
||||
}
|
||||
|
||||
tauri::Builder::default()
|
||||
@ -95,12 +96,9 @@ fn main() {
|
||||
// UI ready event
|
||||
let app_handle = app.handle();
|
||||
let config_clone = Arc::clone(&config);
|
||||
app.listen_global("heartbeat", move |_| {
|
||||
let handle = AsyncHandle::try_current();
|
||||
println!("handle, {:?}", handle);
|
||||
|
||||
app.listen_global("ready", move |_| {
|
||||
let config_handle = config_clone.lock().unwrap();
|
||||
info!("Heartbeat received");
|
||||
info!("Start signal received");
|
||||
app_handle
|
||||
.emit_all(
|
||||
"showConfig",
|
||||
@ -109,6 +107,23 @@ fn main() {
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
// UI update event
|
||||
let app_handle = app.handle();
|
||||
let manager_clone = Arc::clone(&manager);
|
||||
app.listen_global("queryState", move |event| {
|
||||
// app_handle.emit_all("showState", "@@@");
|
||||
let snapshot = {
|
||||
let manager_handle = manager_clone.lock().unwrap();
|
||||
manager_handle.try_get_state().map(|x| x.snapshot())
|
||||
};
|
||||
match snapshot {
|
||||
Some(snapshot) => {
|
||||
app_handle.emit_all("showState", snapshot);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
|
||||
// Config set event
|
||||
let config_clone = Arc::clone(&config);
|
||||
let manager_clone = Arc::clone(&manager);
|
||||
@ -121,9 +136,8 @@ fn main() {
|
||||
config_handle.replace(new_config);
|
||||
let config_handle_ref = config_handle.as_ref().unwrap();
|
||||
config_handle_ref.save();
|
||||
let mut manager_handle = manager_clone.lock().unwrap();
|
||||
manager_handle.take();
|
||||
manager_handle.replace(slider_io::Manager::new(config_handle_ref.clone()));
|
||||
let manager_handle = manager_clone.lock().unwrap();
|
||||
manager_handle.update_config(config_handle_ref.clone());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -9,7 +9,7 @@ use hyper::{
|
||||
};
|
||||
use log::{error, info};
|
||||
use path_clean::PathClean;
|
||||
use std::{convert::Infallible, future::Future, net::SocketAddr, path::PathBuf};
|
||||
use std::{convert::Infallible, env::current_exe, future::Future, net::SocketAddr};
|
||||
use tokio::fs::File;
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
@ -29,15 +29,17 @@ async fn error_response() -> Result<Response<Body>, Infallible> {
|
||||
}
|
||||
|
||||
async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
|
||||
let mut pb = PathBuf::from("res/www/");
|
||||
let mut pb = current_exe().unwrap();
|
||||
pb.pop();
|
||||
pb.push("res/www");
|
||||
pb.push(path);
|
||||
pb.clean();
|
||||
|
||||
// println!("CWD {:?}", std::env::current_dir());
|
||||
// println!("Serving file {:?}", pb);
|
||||
|
||||
match File::open(pb).await {
|
||||
match File::open(&pb).await {
|
||||
Ok(f) => {
|
||||
info!("Serving file {:?}", pb);
|
||||
let stream = FramedRead::new(f, BytesCodec::new());
|
||||
let body = Body::wrap_stream(stream);
|
||||
Ok(Response::new(body))
|
||||
@ -154,6 +156,7 @@ async fn handle_request(
|
||||
request: Request<Body>,
|
||||
remote_addr: SocketAddr,
|
||||
state: FullState,
|
||||
ground_only: bool,
|
||||
) -> Result<Response<Body>, Infallible> {
|
||||
let method = request.method();
|
||||
let path = request.uri().path();
|
||||
@ -170,7 +173,10 @@ async fn handle_request(
|
||||
request.uri().path(),
|
||||
request.headers().contains_key(header::UPGRADE),
|
||||
) {
|
||||
("/", false) | ("/index.html", false) => serve_file("index.html").await,
|
||||
("/", false) | ("/index.html", false) => match ground_only {
|
||||
false => serve_file("index.html").await,
|
||||
true => serve_file("index-go.html").await,
|
||||
},
|
||||
(filename, false) => serve_file(&filename[1..]).await,
|
||||
("/ws", true) => handle_websocket(request, state).await,
|
||||
_ => error_response().await,
|
||||
@ -179,12 +185,14 @@ async fn handle_request(
|
||||
|
||||
pub struct BrokenithmJob {
|
||||
state: FullState,
|
||||
ground_only: bool,
|
||||
}
|
||||
|
||||
impl BrokenithmJob {
|
||||
pub fn new(state: &FullState) -> Self {
|
||||
pub fn new(state: &FullState, ground_only: &bool) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
ground_only: *ground_only,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,13 +201,14 @@ impl BrokenithmJob {
|
||||
impl AsyncJob for BrokenithmJob {
|
||||
async fn run<F: Future<Output = ()> + Send>(self, stop_signal: F) {
|
||||
let state = self.state.clone();
|
||||
let ground_only = self.ground_only;
|
||||
let make_svc = make_service_fn(|conn: &AddrStream| {
|
||||
let remote_addr = conn.remote_addr();
|
||||
let make_svc_state = state.clone();
|
||||
async move {
|
||||
Ok::<_, Infallible>(service_fn(move |request: Request<Body>| {
|
||||
let svc_state = make_svc_state.clone();
|
||||
handle_request(request, remote_addr, svc_state)
|
||||
handle_request(request, remote_addr, svc_state, ground_only)
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
64
src-tauri/src/slider_io/context.rs
Normal file
64
src-tauri/src/slider_io/context.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use log::info;
|
||||
|
||||
use crate::slider_io::{
|
||||
brokenithm::BrokenithmJob,
|
||||
config::{Config, DeviceMode},
|
||||
controller_state::FullState,
|
||||
device::HidDeviceJob,
|
||||
led::LedJob,
|
||||
output::OutputJob,
|
||||
worker::{AsyncWorker, ThreadWorker},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Context {
|
||||
state: FullState,
|
||||
config: Config,
|
||||
device_worker: Option<ThreadWorker>,
|
||||
brokenithm_worker: Option<AsyncWorker>,
|
||||
output_worker: ThreadWorker,
|
||||
led_worker: ThreadWorker,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(config: Config) -> Self {
|
||||
info!("Context creating");
|
||||
info!("Device config {:?}", config.device_mode);
|
||||
info!("Output config {:?}", config.output_mode);
|
||||
info!("LED config {:?}", config.led_mode);
|
||||
|
||||
let state = FullState::new();
|
||||
|
||||
let (device_worker, brokenithm_worker) = match &config.device_mode {
|
||||
DeviceMode::Brokenithm { ground_only } => (
|
||||
None,
|
||||
Some(AsyncWorker::new(
|
||||
"brokenithm",
|
||||
BrokenithmJob::new(&state, ground_only),
|
||||
)),
|
||||
),
|
||||
other => (
|
||||
Some(ThreadWorker::new(
|
||||
"device",
|
||||
HidDeviceJob::from_config(&state, other),
|
||||
)),
|
||||
None,
|
||||
),
|
||||
};
|
||||
let output_worker = ThreadWorker::new("output", OutputJob::new(&state, &config.output_mode));
|
||||
let led_worker = ThreadWorker::new("led", LedJob::new(&state, &config.led_mode));
|
||||
|
||||
Self {
|
||||
state,
|
||||
config,
|
||||
device_worker,
|
||||
brokenithm_worker,
|
||||
output_worker,
|
||||
led_worker,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_state(&self) -> FullState {
|
||||
self.state.clone()
|
||||
}
|
||||
}
|
@ -74,6 +74,21 @@ impl FullState {
|
||||
pub fn clone_led(&self) -> Arc<Mutex<LedState>> {
|
||||
Arc::clone(&self.led_state)
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Vec<u8> {
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
{
|
||||
let controller_state_handle = self.controller_state.lock().unwrap();
|
||||
buf.extend(controller_state_handle.ground_state);
|
||||
buf.extend(controller_state_handle.air_state);
|
||||
};
|
||||
{
|
||||
let led_state_handle = self.led_state.lock().unwrap();
|
||||
buf.extend(led_state_handle.led_state);
|
||||
};
|
||||
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for FullState {
|
||||
|
@ -31,8 +31,8 @@ const YUANCON_KB_MAP: [usize; 41] = [
|
||||
#[rustfmt::skip]
|
||||
const DEEMO_KB_MAP: [usize; 41] = [
|
||||
0x41, 0x41, 0x41, 0x41, // A
|
||||
0x35, 0x35, 0x35, 0x35, // S
|
||||
0x4f, 0x4f, 0x4f, 0x4f, // D
|
||||
0x53, 0x53, 0x53, 0x53, // S
|
||||
0x44, 0x44, 0x44, 0x44, // D
|
||||
0x46, 0x46, 0x46, 0x46, // F
|
||||
0x4a, 0x4a, 0x4a, 0x4a, // J
|
||||
0x4b, 0x4b, 0x4b, 0x4b, // K
|
||||
|
@ -1,57 +1,94 @@
|
||||
use log::info;
|
||||
|
||||
use crate::slider_io::{
|
||||
brokenithm::BrokenithmJob,
|
||||
config::{Config, DeviceMode},
|
||||
controller_state::FullState,
|
||||
device::HidDeviceJob,
|
||||
led::LedJob,
|
||||
output::OutputJob,
|
||||
worker::{AsyncWorker, ThreadWorker},
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
thread::{self, JoinHandle},
|
||||
};
|
||||
use tokio::{
|
||||
select,
|
||||
sync::{mpsc, oneshot},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
use crate::slider_io::{config::Config, context::Context};
|
||||
|
||||
use super::controller_state::FullState;
|
||||
|
||||
pub struct Manager {
|
||||
state: FullState,
|
||||
config: Config,
|
||||
device_worker: Option<ThreadWorker>,
|
||||
brokenithm_worker: Option<AsyncWorker>,
|
||||
output_worker: ThreadWorker,
|
||||
led_worker: ThreadWorker,
|
||||
state: Arc<Mutex<Option<FullState>>>,
|
||||
join_handle: Option<JoinHandle<()>>,
|
||||
tx_config: mpsc::UnboundedSender<Config>,
|
||||
tx_stop: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
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);
|
||||
pub fn new() -> Self {
|
||||
let state = Arc::new(Mutex::new(None));
|
||||
let (tx_config, mut rx_config) = mpsc::unbounded_channel::<Config>();
|
||||
let (tx_stop, rx_stop) = oneshot::channel::<()>();
|
||||
|
||||
let state = FullState::new();
|
||||
let context: Arc<Mutex<Option<Context>>> = Arc::new(Mutex::new(None));
|
||||
|
||||
let (device_worker, brokenithm_worker) = match &config.device_mode {
|
||||
DeviceMode::Brokenithm { .. } => (
|
||||
None,
|
||||
Some(AsyncWorker::new("brokenithm", BrokenithmJob::new(&state))),
|
||||
),
|
||||
other => (
|
||||
Some(ThreadWorker::new(
|
||||
"device",
|
||||
HidDeviceJob::from_config(&state, other),
|
||||
)),
|
||||
None,
|
||||
),
|
||||
};
|
||||
let output_worker = ThreadWorker::new("output", OutputJob::new(&state, &config.output_mode));
|
||||
let led_worker = ThreadWorker::new("led", LedJob::new(&state, &config.led_mode));
|
||||
let state_cloned = Arc::clone(&state);
|
||||
let context_cloned = Arc::clone(&context);
|
||||
|
||||
let join_handle = thread::spawn(move || {
|
||||
info!("Manager thread started");
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(1)
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
runtime.block_on(async move {
|
||||
info!("Manager runtime started");
|
||||
|
||||
select! {
|
||||
_ = async {
|
||||
loop {
|
||||
match rx_config.recv().await {
|
||||
Some(config) => {
|
||||
info!("Rebuilding context");
|
||||
let mut context_handle = context_cloned.lock().unwrap();
|
||||
context_handle.take();
|
||||
|
||||
let new_context = Context::new(config);
|
||||
let new_state = new_context.clone_state();
|
||||
context_handle.replace(new_context);
|
||||
|
||||
let mut state_handle = state_cloned.lock().unwrap();
|
||||
state_handle.replace(new_state);
|
||||
},
|
||||
None => {
|
||||
let mut context_handle = context_cloned.lock().unwrap();
|
||||
context_handle.take();
|
||||
}
|
||||
}
|
||||
}
|
||||
} => {},
|
||||
_ = rx_stop => {}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Self {
|
||||
state,
|
||||
config,
|
||||
device_worker,
|
||||
brokenithm_worker,
|
||||
output_worker,
|
||||
led_worker,
|
||||
join_handle: Some(join_handle),
|
||||
tx_config,
|
||||
tx_stop: Some(tx_stop),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_config(&self, config: Config) {
|
||||
self.tx_config.send(config).unwrap();
|
||||
}
|
||||
|
||||
pub fn try_get_state(&self) -> Option<FullState> {
|
||||
let state_handle = self.state.lock().unwrap();
|
||||
state_handle.as_ref().map(|x| x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Manager {
|
||||
fn drop(&mut self) {
|
||||
self.tx_stop.take().unwrap().send(()).unwrap();
|
||||
self.join_handle.take().unwrap().join().unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ mod device;
|
||||
mod led;
|
||||
mod output;
|
||||
|
||||
mod context;
|
||||
mod manager;
|
||||
|
||||
pub use config::Config;
|
||||
|
@ -9,7 +9,7 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
use tokio::{runtime::Runtime, sync::oneshot, task};
|
||||
use tokio::{sync::oneshot, task};
|
||||
|
||||
pub trait ThreadJob: Send {
|
||||
fn setup(&mut self) -> bool;
|
||||
@ -68,7 +68,6 @@ pub trait AsyncJob: Send + 'static {
|
||||
|
||||
pub struct AsyncWorker {
|
||||
name: &'static str,
|
||||
runtime: Runtime,
|
||||
task: Option<task::JoinHandle<()>>,
|
||||
stop_signal: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
@ -81,13 +80,8 @@ impl AsyncWorker {
|
||||
info!("Async worker starting {}", name);
|
||||
|
||||
let (send_stop, recv_stop) = oneshot::channel::<()>();
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.worker_threads(1)
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let task = runtime.spawn(async move {
|
||||
let task = tokio::spawn(async move {
|
||||
job
|
||||
.run(async move {
|
||||
recv_stop.await.unwrap();
|
||||
@ -97,7 +91,6 @@ impl AsyncWorker {
|
||||
|
||||
AsyncWorker {
|
||||
name,
|
||||
runtime,
|
||||
task: Some(task),
|
||||
stop_signal: Some(send_stop),
|
||||
}
|
||||
@ -108,20 +101,7 @@ impl Drop for AsyncWorker {
|
||||
fn drop(&mut self) {
|
||||
info!("Async worker stopping {}", self.name);
|
||||
|
||||
if self.stop_signal.is_some() {
|
||||
let send_stop = self.stop_signal.take().unwrap();
|
||||
send_stop.send(()).unwrap();
|
||||
// self.runtime.block_on(async move {
|
||||
// send_stop.send(()).unwrap();
|
||||
// });
|
||||
}
|
||||
|
||||
if self.task.is_some() {
|
||||
// let task = self.task.take().unwrap();
|
||||
// self.runtime.block_on(async move {
|
||||
// task.await;
|
||||
// info!("Async worker stopping internal {}", name);
|
||||
// });
|
||||
}
|
||||
self.stop_signal.take().unwrap().send(()).unwrap();
|
||||
self.task.take();
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,27 @@
|
||||
|
||||
let debugstr = "";
|
||||
|
||||
let polling = null;
|
||||
let tick = 0;
|
||||
let previewData = Array(131).fill(0);
|
||||
|
||||
function updatePolling(enabled) {
|
||||
if (!!polling) {
|
||||
clearInterval(polling);
|
||||
polling = null;
|
||||
}
|
||||
if (enabled) {
|
||||
polling = setInterval(async () => {
|
||||
tick += 1;
|
||||
await emit("queryState", "");
|
||||
}, 50);
|
||||
}
|
||||
// console.log(enabled, polling, tick);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
// console.log(emit, listen);
|
||||
await listen("showConfig", (event) => {
|
||||
console.log("heartbeat", event);
|
||||
debugstr = event.payload;
|
||||
const payload: any = JSON.parse(event.payload as any);
|
||||
deviceMode = payload.deviceMode || "none";
|
||||
@ -32,7 +49,22 @@
|
||||
ledWebsocketUrl = payload.ledWebsocketUrl || "http://localhost:3001";
|
||||
ledSerialPort = payload.ledSerialPort || "COM5";
|
||||
});
|
||||
await emit("heartbeat", "");
|
||||
|
||||
await listen("showState", (event) => {
|
||||
previewData = event.payload;
|
||||
});
|
||||
|
||||
await emit("ready", "");
|
||||
|
||||
updatePolling(true);
|
||||
await listen("ackShow", (event) => {
|
||||
console.log("ackShow");
|
||||
updatePolling(true);
|
||||
});
|
||||
await listen("ackHide", (event) => {
|
||||
console.log("ackHide");
|
||||
updatePolling(false);
|
||||
});
|
||||
});
|
||||
|
||||
async function setConfig() {
|
||||
@ -73,7 +105,7 @@
|
||||
{debugstr}
|
||||
</div> -->
|
||||
<div class="row">
|
||||
<Preview />
|
||||
<Preview data={previewData} />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">Input Device</div>
|
||||
@ -84,7 +116,7 @@
|
||||
<option value="tasoller-two">GAMO2 Tasoller, 2.0 HID Firmware</option>
|
||||
<option value="yuancon">Yuancon Laverita, HID Firmware</option>
|
||||
<option value="brokenithm">Brokenithm</option>
|
||||
<option value="brokenithm-ground">Brokenithm, Ground only</option>
|
||||
<option value="brokenithm-ground">Brokenithm, Ground only (WIP)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,22 +1,44 @@
|
||||
<script lang="ts">
|
||||
export let data: Array<number>;
|
||||
|
||||
let topDatas = Array(16).fill(0);
|
||||
let botDatas = Array(16).fill(0);
|
||||
let ledDatas = Array(31).fill(0).map((_, idx) => ({
|
||||
color: !!(idx % 2) ? "f0f" : "ff0",
|
||||
spec: idx % 2
|
||||
}))
|
||||
let ledDatas = Array(31)
|
||||
.fill(0)
|
||||
.map((_, idx) => ({
|
||||
color: !!(idx % 2) ? "#f0f" : "#ff0",
|
||||
spec: idx % 2,
|
||||
}));
|
||||
|
||||
$: {
|
||||
if (data.length === 131) {
|
||||
// console.log(data);
|
||||
for (let i = 0; i < 16; i++) {
|
||||
topDatas[i] = data[i * 2 + 1];
|
||||
botDatas[i] = data[i * 2];
|
||||
}
|
||||
for (let i = 0; i < 31; i++) {
|
||||
ledDatas[i].color = `rgb(${data[38 + i * 3]}, ${data[39 + i * 3]}, ${
|
||||
data[40 + i * 3]
|
||||
})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<main class="preview">
|
||||
<div class="air"></div>
|
||||
<div class="air" />
|
||||
<div class="ground">
|
||||
<div class="ground-led">
|
||||
<div class="ground-row">
|
||||
<div class="ground-led-2"></div>
|
||||
{#each ledDatas as {color, spec}, idx (idx)}
|
||||
<div class={`ground-led-${spec}`} style={`background-color: #${color}`}></div>
|
||||
<div class="ground-led-2" />
|
||||
{#each ledDatas as { color, spec }, idx (idx)}
|
||||
<div
|
||||
class={`ground-led-${spec}`}
|
||||
style={`background-color: ${color}`}
|
||||
/>
|
||||
{/each}
|
||||
<div class="ground-led-2"></div>
|
||||
<div class="ground-led-2" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="ground-btn">
|
||||
|
Loading…
Reference in New Issue
Block a user