1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-24 05:50:12 +01:00

some error handling

This commit is contained in:
4yn 2022-02-07 15:56:03 +08:00
parent 6f052554ce
commit afa5a46c65
11 changed files with 168 additions and 129 deletions

View File

@ -3,7 +3,7 @@
- major
- acio support
- qol
- proper error handling
- more error handling
- comments
- when umiguri comes out
- ouptut websocket

View File

@ -41,10 +41,9 @@ fn main() {
{
let log_file_path = slider_io::Config::get_log_file_path().unwrap();
simple_logging::log_to_file(log_file_path.as_path(), log::LevelFilter::Debug).unwrap();
// simple_logging::log_to_file("./log.txt", log::LevelFilter::Debug).unwrap();
}
let config = Arc::new(Mutex::new(Some(slider_io::Config::default())));
let config = Arc::new(Mutex::new(Some(slider_io::Config::load())));
let manager = Arc::new(Mutex::new(slider_io::Manager::new()));
{
let config_handle = config.lock().unwrap();

View File

@ -46,24 +46,6 @@ static BROKENITHM_BIN_FILES: phf::Map<&'static str, (&'static [u8], &'static str
};
async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
// let mut pb = current_exe().unwrap();
// pb.pop();
// pb.push("res/www");
// pb.push(path);
// pb.clean();
// println!("CWD {:?}", std::env::current_dir());
// 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))
// }
// Err(_) => error_response().await,
// }
match (
BROKENITHM_STR_FILES.get(path),
BROKENITHM_BIN_FILES.get(path),
@ -120,33 +102,30 @@ async fn handle_brokenithm(
Some(msg) => match msg {
Ok(msg) => match msg {
Message::Text(msg) => {
let mut chars = msg.chars();
let head = chars.next().unwrap();
match head {
'a' => {
msg_write_handle
.send(Message::Text("alive".to_string()))
.ok();
}
'b' => {
let flat_state: Vec<bool> = chars
.map(|x| match x {
'0' => false,
'1' => true,
_ => unreachable!(),
})
.collect();
let mut controller_state_handle = state_handle.controller_state.lock().unwrap();
for (idx, c) in flat_state[0..32].iter().enumerate() {
controller_state_handle.ground_state[idx] = match c {
false => 0,
true => 255,
}
let chars = msg.chars().collect::<Vec<char>>();
match chars.len() {
6 => {
if chars[0] == 'a' {
msg_write_handle
.send(Message::Text("alive".to_string()))
.ok();
}
for (idx, c) in flat_state[32..38].iter().enumerate() {
controller_state_handle.air_state[idx] = match c {
false => 0,
true => 1,
}
39 => {
if chars[0] == 'b' {
let mut controller_state_handle = state_handle.controller_state.lock().unwrap();
for (idx, c) in chars[0..32].iter().enumerate() {
controller_state_handle.ground_state[idx] = match *c == '1' {
false => 0,
true => 255,
}
}
for (idx, c) in chars[32..38].iter().enumerate() {
controller_state_handle.air_state[idx] = match *c == '1' {
false => 0,
true => 1,
}
}
}
}

View File

@ -213,27 +213,10 @@ impl Config {
})
}
fn factory() -> Self {
Self::from_str(
r#"{
"deviceMode": "none",
"outputMode": "none",
"ledMode": "none",
"keyboardSensitivity": 20,
"outputWebsocketUrl": "localhost:3000",
"outputPolling": "60",
"ledSensitivity": 20,
"ledWebsocketUrl": "localhost:3001",
"ledSerialPort": "COM5"
}"#,
)
.unwrap()
}
pub fn get_log_file_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap();
fs::create_dir_all(config_dir).ok()?;
let log_path = config_dir.join("log.txt");
@ -243,7 +226,7 @@ impl Config {
pub fn get_brokenithm_qr_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap();
fs::create_dir_all(config_dir).ok()?;
let brokenithm_qr_path = config_dir.join("brokenithm.png");
@ -262,18 +245,35 @@ impl Config {
return Some(Box::new(brokenithm_qr_path));
}
fn get_saved_path() -> Option<Box<PathBuf>> {
fn get_config_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap();
fs::create_dir_all(config_dir).ok()?;
let config_path = config_dir.join("config.json");
return Some(Box::new(config_path));
}
fn default() -> Self {
Self::from_str(
r#"{
"deviceMode": "none",
"outputMode": "none",
"ledMode": "none",
"keyboardSensitivity": 20,
"outputWebsocketUrl": "localhost:3000",
"outputPolling": "60",
"ledSensitivity": 20,
"ledWebsocketUrl": "localhost:3001",
"ledSerialPort": "COM5"
}"#,
)
.unwrap()
}
fn load_saved() -> Option<Self> {
let config_path = Self::get_saved_path()?;
let config_path = Self::get_config_path()?;
if !config_path.exists() {
return None;
}
@ -282,22 +282,22 @@ impl Config {
return Self::from_str(saved_data.as_str());
}
pub fn default() -> Self {
pub fn load() -> Self {
Self::load_saved()
.or_else(|| {
warn!("Config loading from file failed, using default");
Some(Self::factory())
Some(Self::default())
})
.unwrap()
}
pub fn save(&self) -> Option<()> {
info!("Config saving...");
let config_path = Self::get_saved_path()?;
let config_path = Self::get_config_path()?;
info!("Config saving to {:?}", config_path);
fs::write(config_path.as_path(), self.raw.as_str()).unwrap();
info!("Config saved");
Some(())
}
}

View File

@ -185,7 +185,7 @@ impl HidDeviceJob {
}
}
fn setup_impl(&mut self) -> Result<(), Box<dyn Error>> {
fn get_handle(&mut self) -> Result<(), Box<dyn Error>> {
info!("Device finding vid {} pid {}", self.vid, self.pid);
let handle = rusb::open_device_with_vid_pid(self.vid, self.pid);
if handle.is_none() {
@ -212,7 +212,7 @@ const TIMEOUT: Duration = Duration::from_millis(20);
impl ThreadJob for HidDeviceJob {
fn setup(&mut self) -> bool {
match self.setup_impl() {
match self.get_handle() {
Ok(_) => {
info!("Device OK");
true
@ -279,8 +279,7 @@ impl ThreadJob for HidDeviceJob {
}
fn teardown(&mut self) {
if self.handle.is_some() {
let handle = self.handle.as_mut().unwrap();
if let Some(handle) = self.handle.as_mut() {
handle.release_interface(0).ok();
}
}

View File

@ -1,3 +1,5 @@
use log::error;
use std::error::Error;
use vigem_client::{Client, TargetId, XButtons, XGamepad, Xbox360Wired};
use crate::slider_io::{config::GamepadLayout, output::OutputHandler, voltex::VoltexState};
@ -9,25 +11,49 @@ pub struct GamepadOutput {
}
impl GamepadOutput {
pub fn new(layout: GamepadLayout) -> Self {
let client = Client::connect().unwrap();
pub fn new(layout: GamepadLayout) -> Option<Self> {
let target = Self::get_target();
let use_air = match layout {
GamepadLayout::Neardayo => true,
_ => false,
};
match target {
Ok(target) => Some(Self {
target,
use_air,
gamepad: XGamepad::default(),
}),
Err(e) => {
error!("Gamepad connection error: {}", e);
error!("Gamepad connection error: Is ViGEMBus missing?");
None
}
}
}
fn get_target() -> Result<Xbox360Wired<Client>, Box<dyn Error>> {
let client = Client::connect()?;
let mut target = Xbox360Wired::new(client, TargetId::XBOX360_WIRED);
target.plugin().unwrap();
target.wait_ready().unwrap();
Self {
target,
use_air,
gamepad: XGamepad::default(),
target.plugin()?;
target.wait_ready()?;
Ok(target)
}
fn update(&mut self) -> bool {
match self.target.update(&self.gamepad) {
Ok(_) => true,
Err(e) => {
error!("Gamepad update error: {}", e);
false
}
}
}
}
impl OutputHandler for GamepadOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) {
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
let voltex_state = VoltexState::from_flat(flat_controller_state);
let buttons = voltex_state
@ -84,20 +110,26 @@ impl OutputHandler for GamepadOutput {
dirty = true;
}
if dirty {
self.target.update(&self.gamepad).unwrap();
match dirty {
true => self.update(),
false => true,
}
}
fn reset(&mut self) {
self.gamepad = XGamepad::default();
self.target.update(&self.gamepad).unwrap();
self.update();
}
}
impl Drop for GamepadOutput {
fn drop(&mut self) {
self.target.unplug().unwrap();
match self.target.unplug() {
Ok(_) => {}
Err(e) => {
error!("Gamepad unplug error: {}", e);
}
}
}
}

View File

@ -165,7 +165,7 @@ impl KeyboardOutput {
}
impl OutputHandler for KeyboardOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) {
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
self.next_keys.fill(false);
for (idx, x) in flat_controller_state.iter().enumerate() {
if *x {
@ -173,6 +173,7 @@ impl OutputHandler for KeyboardOutput {
}
}
self.send();
true
}
fn reset(&mut self) {

View File

@ -98,7 +98,11 @@ impl Manager {
impl Drop for Manager {
fn drop(&mut self) {
self.tx_stop.take().unwrap().send(()).unwrap();
self.join_handle.take().unwrap().join().unwrap();
if let Some(tx_stop) = self.tx_stop.take() {
tx_stop.send(()).ok();
}
if let Some(join_handle) = self.join_handle.take() {
join_handle.join().ok();
}
}
}

View File

@ -1,3 +1,4 @@
use log::error;
use std::time::Duration;
use crate::slider_io::{
@ -6,48 +7,65 @@ use crate::slider_io::{
};
pub trait OutputHandler: Send {
fn tick(&mut self, flat_controller_state: &Vec<bool>);
fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool;
fn reset(&mut self);
}
pub struct OutputJob {
state: FullState,
mode: OutputMode,
t: u64,
sensitivity: u8,
handler: Box<dyn OutputHandler>,
handler: Option<Box<dyn OutputHandler>>,
}
impl OutputJob {
pub fn new(state: &FullState, mode: &OutputMode) -> Self {
match mode {
OutputMode::Keyboard {
layout,
polling,
sensitivity,
} => Self {
state: state.clone(),
t: polling.to_t_u64(),
sensitivity: *sensitivity,
handler: Box::new(KeyboardOutput::new(layout.clone())),
},
OutputMode::Gamepad {
layout,
polling,
sensitivity,
} => Self {
state: state.clone(),
t: polling.to_t_u64(),
sensitivity: *sensitivity,
handler: Box::new(GamepadOutput::new(layout.clone())),
},
_ => panic!("Not implemented"),
Self {
state: state.clone(),
mode: mode.clone(),
t: 0,
sensitivity: 0,
handler: None,
}
}
}
impl ThreadJob for OutputJob {
fn setup(&mut self) -> bool {
true
match self.mode {
OutputMode::Keyboard {
layout,
polling,
sensitivity,
} => {
self.t = polling.to_t_u64();
self.sensitivity = sensitivity;
self.handler = Some(Box::new(KeyboardOutput::new(layout.clone())));
true
}
OutputMode::Gamepad {
layout,
polling,
sensitivity,
} => {
self.t = polling.to_t_u64();
self.sensitivity = sensitivity;
let handler = GamepadOutput::new(layout.clone());
match handler {
Some(handler) => {
self.handler = Some(Box::new(handler));
true
}
None => false,
}
}
_ => {
error!("Not implemented");
false
}
}
}
fn tick(&mut self) -> bool {
@ -57,14 +75,17 @@ impl ThreadJob for OutputJob {
flat_controller_state = controller_state_handle.flat(&self.sensitivity);
}
self.handler.tick(&flat_controller_state);
// thread::sleep(Duration::from_millis(self.t));
if let Some(handler) = self.handler.as_mut() {
handler.tick(&flat_controller_state);
}
spin_sleep::sleep(Duration::from_micros(self.t));
true
}
fn teardown(&mut self) {
self.handler.reset();
if let Some(handler) = self.handler.as_mut() {
handler.reset();
}
}
}

View File

@ -84,9 +84,11 @@ impl LoopTimer {
}
}
// pub fn reset(&mut self) {
// self.buf = vec![Instant::now(); 100];
// }
#[allow(dead_code)]
pub fn reset(&mut self) {
self.buf = vec![Instant::now() - Duration::from_secs(10); 100];
self.cur = 0;
}
pub fn fork(&self) -> Arc<AtomicF64> {
Arc::clone(&self.freq)

View File

@ -59,9 +59,9 @@ impl Drop for ThreadWorker {
info!("Thread worker stopping {}", self.name);
self.stop_signal.store(true, Ordering::SeqCst);
if self.thread.is_some() {
self.thread.take().unwrap().join().ok();
}
if let Some(thread) = self.thread.take() {
thread.join().ok();
};
}
}
@ -88,7 +88,7 @@ impl AsyncWorker {
let task = tokio::spawn(async move {
job
.run(async move {
recv_stop.await.unwrap();
recv_stop.await.ok();
})
.await;
});
@ -105,7 +105,9 @@ impl Drop for AsyncWorker {
fn drop(&mut self) {
info!("Async worker stopping {}", self.name);
self.stop_signal.take().unwrap().send(()).unwrap();
if let Some(stop_signal) = self.stop_signal.take() {
stop_signal.send(()).ok();
}
self.task.take();
}
}