diff --git a/Cargo.toml b/Cargo.toml index 4d91c40..7ca56bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,5 @@ edition = "2021" [package.metadata.cross.target.arm-unknown-linux-musleabi] pre-build = ["apt-get update && apt-get install -y python3"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -evdev-rs = "0.6.1" +evdev = "0.12.1" diff --git a/src/main.rs b/src/main.rs index 35d4201..2ac10d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,150 +1,58 @@ -use std::fs::File; -use std::io::Write; +mod physical_controller; +mod virtual_controller; +mod state; + use std::io::Result; use std::process::Command; -use std::time::{Duration, Instant}; +use std::time::Duration; use std::thread::sleep; -use evdev_rs::Device; -use evdev_rs::InputEvent; -use evdev_rs::ReadFlag; -use evdev_rs::enums::EventCode; -use evdev_rs::enums::EV_KEY; - -#[derive(Default)] -struct ControllerState { - power: u8, - brake: u8, - button_sl: bool, - button_st: bool, - button_a: bool, - button_b: bool, - button_c: bool, - button_d: bool, - button_up: bool, - button_down: bool, - button_left: bool, - button_right: bool, -} - -#[derive(PartialEq)] -enum ControllerModel { - NONE, - DGOC44U, - TYPE2, -} +use virtual_controller::ControllerModel; fn main() -> Result<()> { - let d1 = Device::new_from_path("/dev/input/event1"); - let d2 = Device::new_from_path("/dev/input/event2"); + match physical_controller::init() { + Ok(mut dev) => { + // Wait 3 seconds and get current state of the controller + println!("Press a button to select the controller model..."); + sleep(Duration::from_secs(3)); + let mut controller_state = physical_controller::get_state(dev); + let controller_model = virtual_controller::set_model(&controller_state); - match (d1, d2) { - (Ok(d1), Ok(d2)) => { - let mut controller_state: ControllerState = Default::default(); - let mut controller_model: ControllerModel = ControllerModel::NONE; - - // Save current time and 5 seconds in the future to check for pressed buttons later - let start_time = Instant::now(); - let init_time = start_time + Duration::from_secs(5); - - // Turn on door light to indicate selection mode - set_lamp(true); - println!("Hold a button to select the controller model..."); + // If no model selected, quit + if controller_model == ControllerModel::NONE { + return Result::Ok(()); + } + + // Vibrate to end selection mode + physical_controller::set_rumble(true); + sleep(Duration::from_millis(500)); + physical_controller::set_rumble(false); + + // Stop main game + stop_game(); loop { - // Process events from both input devices - for device in [&d1, &d2] { - let ev = device.next_event(ReadFlag::NORMAL); - match ev { - Ok(ev) => read_input(ev.1, &mut controller_state), + // Process events from input devices + /*for mut device in [&mut d1, &mut d2] { + let evs = device.fetch_events(); + match evs { + Ok(evs) => { + for event in evs { + if event.event_type() == EventType::KEY { + physical_controller::read_input(&mut controller_state, Key(event.code()), event.value()); + } + } + }, Err(_e) => (), } - } - - // If init time has passed, try to select model or quit - if controller_model == ControllerModel::NONE && Instant::now() >= init_time { - if controller_state.button_right { - controller_model = ControllerModel::DGOC44U; - println!("Selected controller DGOC44-U, starting gadget..."); - } - else if controller_state.button_left { - controller_model = ControllerModel::TYPE2; - println!("Selected controller TCPP-20009, starting gadget..."); - } - else - { - // Turn off door light and quit - set_lamp(false); - println!("No controller selected, exiting..."); - break; - } - // Turn off door light and vibrate to end selection mode - set_lamp(false); - set_rumble(true); - sleep(Duration::from_millis(500)); - set_rumble(false); - - // Stop main game - stop_game(); - } + }*/ } }, - _ => println!("ERROR: Could not read input devices! Stopping..."), + Err(_e) => println!("ERROR: Could not read input devices! Exiting."), } Ok(()) } -fn read_input(event: InputEvent, controller: &mut ControllerState) { - // Save input status to object for easier processing - match event.event_code{ - EventCode::EV_KEY(EV_KEY::KEY_0)=>if event.value == 1 {controller.power = 0}, - EventCode::EV_KEY(EV_KEY::KEY_1)=>if event.value == 1 {controller.power = 1}, - EventCode::EV_KEY(EV_KEY::KEY_2)=>if event.value == 1 {controller.power = 2}, - EventCode::EV_KEY(EV_KEY::KEY_3)=>if event.value == 1 {controller.power = 3}, - EventCode::EV_KEY(EV_KEY::KEY_4)=>if event.value == 1 {controller.power = 4}, - EventCode::EV_KEY(EV_KEY::KEY_5)=>if event.value == 1 {controller.power = 5}, - EventCode::EV_KEY(EV_KEY::KEY_B)=>if event.value == 1 {controller.brake = 0}, - EventCode::EV_KEY(EV_KEY::KEY_C)=>if event.value == 1 {controller.brake = 1}, - EventCode::EV_KEY(EV_KEY::KEY_D)=>if event.value == 1 {controller.brake = 2}, - EventCode::EV_KEY(EV_KEY::KEY_E)=>if event.value == 1 {controller.brake = 3}, - EventCode::EV_KEY(EV_KEY::KEY_F)=>if event.value == 1 {controller.brake = 4}, - EventCode::EV_KEY(EV_KEY::KEY_G)=>if event.value == 1 {controller.brake = 5}, - EventCode::EV_KEY(EV_KEY::KEY_H)=>if event.value == 1 {controller.brake = 6}, - EventCode::EV_KEY(EV_KEY::KEY_I)=>if event.value == 1 {controller.brake = 7}, - EventCode::EV_KEY(EV_KEY::KEY_J)=>if event.value == 1 {controller.brake = 8}, - EventCode::EV_KEY(EV_KEY::KEY_P)=>if event.value == 1 {controller.brake = 9}, - EventCode::EV_KEY(EV_KEY::KEY_SPACE)=>controller.button_sl = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_ENTER)=>controller.button_st = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_A)=>controller.button_a = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_Z)=>controller.button_b = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_X)=>controller.button_c = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_S)=>controller.button_d = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_UP)=>controller.button_up = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_DOWN)=>controller.button_down = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_LEFT)=>controller.button_left = event.value != 0, - EventCode::EV_KEY(EV_KEY::KEY_RIGHT)=>controller.button_right = event.value != 0, - _=>(), - } -} - -fn set_lamp(status: bool) { - if let Ok(mut out) = File::create("/sys/class/leds/led2/brightness") { - out.write(if status {b"1"} else {b"0"}).ok(); - } - else { - println!("WARNING: Could not set door lamp status!") - } -} - -fn set_rumble(status: bool) { - if let Ok(mut out) = File::create("/sys/class/leds/led1/brightness") { - out.write(if status {b"1"} else {b"0"}).ok(); - } - else { - println!("WARNING: Could not set rumble motor status!") - } -} - fn stop_game() { Command::new("/etc/init.d/S99dgtype3").arg("stop").output().ok(); } \ No newline at end of file diff --git a/src/physical_controller.rs b/src/physical_controller.rs new file mode 100644 index 0000000..9806a98 --- /dev/null +++ b/src/physical_controller.rs @@ -0,0 +1,81 @@ +use std::fs::File; +use std::io::Write; +use std::io::Result; + +use evdev::Device; +use evdev::Key; + +use crate::state::ControllerState; + +const USED_KEYS: [Key; 26] = [Key::KEY_0, Key::KEY_1, Key::KEY_2, Key::KEY_3, Key::KEY_4, Key::KEY_5, + Key::KEY_B, Key::KEY_C, Key::KEY_D, Key::KEY_E, Key::KEY_F, Key::KEY_G, Key::KEY_H, Key::KEY_I, Key::KEY_J, Key::KEY_P, + Key::KEY_SPACE, Key::KEY_ENTER, Key::KEY_A, Key::KEY_Z, Key::KEY_X, Key::KEY_S, Key::KEY_UP, Key::KEY_DOWN, Key::KEY_LEFT, Key::KEY_RIGHT]; + +pub fn init() -> Result<[Device; 2]> { + let d1 = Device::open("/dev/input/event14")?; + let d2 = Device::open("/dev/input/event14")?; + Ok([d1, d2]) +} + +pub fn get_state(dev: [Device; 2]) -> ControllerState { + let mut state: ControllerState = Default::default(); + for d in dev { + if let Ok(key_vals) = d.get_key_state() { + for key in USED_KEYS { + read_input(&mut state, key, key_vals.contains(key)); + } + } + } + return state; +} + +fn read_input(controller: &mut ControllerState, key: Key, value: bool) { + // Save input status to object for processing + match key{ + Key::KEY_0=>if value {controller.power = 0}, + Key::KEY_1=>if value {controller.power = 1}, + Key::KEY_2=>if value {controller.power = 2}, + Key::KEY_3=>if value {controller.power = 3}, + Key::KEY_4=>if value {controller.power = 4}, + Key::KEY_5=>if value {controller.power = 5}, + Key::KEY_B=>if value {controller.brake = 0}, + Key::KEY_C=>if value {controller.brake = 1}, + Key::KEY_D=>if value {controller.brake = 2}, + Key::KEY_E=>if value {controller.brake = 3}, + Key::KEY_F=>if value {controller.brake = 4}, + Key::KEY_G=>if value {controller.brake = 5}, + Key::KEY_H=>if value {controller.brake = 6}, + Key::KEY_I=>if value {controller.brake = 7}, + Key::KEY_J=>if value {controller.brake = 8}, + Key::KEY_P=>if value {controller.brake = 9}, + Key::KEY_SPACE=>controller.button_select = value, + Key::KEY_ENTER=>controller.button_start = value, + Key::KEY_A=>controller.button_a = value, + Key::KEY_Z=>controller.button_b = value, + Key::KEY_X=>controller.button_c = value, + Key::KEY_S=>controller.button_d = value, + Key::KEY_UP=>controller.button_up = value, + Key::KEY_DOWN=>controller.button_down = value, + Key::KEY_LEFT=>controller.button_left = value, + Key::KEY_RIGHT=>controller.button_right = value, + _=>(), + } +} + +pub fn set_lamp(status: bool) { + if let Ok(mut out) = File::create("/sys/class/leds/led2/brightness") { + out.write(if status {b"1"} else {b"0"}).ok(); + } + else { + println!("WARNING: Could not set door lamp status!") + } +} + +pub fn set_rumble(status: bool) { + if let Ok(mut out) = File::create("/sys/class/leds/led1/brightness") { + out.write(if status {b"1"} else {b"0"}).ok(); + } + else { + println!("WARNING: Could not set rumble motor status!") + } +} \ No newline at end of file diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..e22d5a2 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,15 @@ +#[derive(Default)] +pub struct ControllerState { + pub power: u8, + pub brake: u8, + pub button_select: bool, + pub button_start: bool, + pub button_a: bool, + pub button_b: bool, + pub button_c: bool, + pub button_d: bool, + pub button_up: bool, + pub button_down: bool, + pub button_left: bool, + pub button_right: bool, +} \ No newline at end of file diff --git a/src/virtual_controller.rs b/src/virtual_controller.rs new file mode 100644 index 0000000..5479e0b --- /dev/null +++ b/src/virtual_controller.rs @@ -0,0 +1,23 @@ +use crate::state::ControllerState; + +#[derive(PartialEq)] +pub enum ControllerModel { + NONE, + DGOC44U, + TYPE2, +} + +pub fn set_model(state: &ControllerState) -> ControllerModel { + if state.button_right { + println!("Selected controller DGOC44-U."); + return ControllerModel::DGOC44U; + } + else if state.button_left { + println!("Selected controller TCPP-20009."); + return ControllerModel::TYPE2; + } + else { + println!("No controller selected."); + return ControllerModel::NONE; + } +} \ No newline at end of file