diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 0e004a6..ce10ded 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -3,36 +3,46 @@ use std::fs::File; use std::io::{Read, Write}; use std::process::Command; -use crate::state::ControllerState; +use crate::controller::physical::ControllerState; mod dgoc44u; mod tcpp20009; mod vok00106; #[derive(PartialEq)] pub enum ControllerModel { - NONE, DGOC44U, TCPP20009, VOK00106, } -pub fn set_model(state: &ControllerState) -> ControllerModel { +pub struct DeviceDescriptor { + b_device_class: u8, + b_device_sub_class: u8, + id_vendor: u16, + id_product: u16, + i_manufacturer: &'static str, + i_product: &'static str, + i_serial_number: &'static str, +} + +pub fn set_model(state: &ControllerState) -> Option { if state.button_right { println!("Selected controller DGOC44-U."); - init_gadget(); - return ControllerModel::DGOC44U; + init_gadget(&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS); + return Some(ControllerModel::DGOC44U); } else if state.button_up { println!("Selected controller TCPP-20009."); - return ControllerModel::TCPP20009; + init_gadget(&tcpp20009::DEVICE_DESCRIPTOR, &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS); + return Some(ControllerModel::TCPP20009); } else if state.button_a { println!("Selected controller VOK-00106."); - return ControllerModel::VOK00106; + return Some(ControllerModel::VOK00106); } else { println!("No controller selected."); - return ControllerModel::NONE; + return None; } } @@ -47,19 +57,21 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::VOK00106 => { vok00106::update_gadget(state); } - _ => (), } } -fn init_gadget() { - Command::new("modprobe").args(["g_ffs"]).output(); - Command::new("mkdir").args(["-p","/tmp/ffs-mascon"]).output(); - Command::new("mount").args(["-t","functionfs","mascon","/tmp/ffs-mascon"]).output(); - - let descriptors = [0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, - 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x00]; - let strings = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; +fn init_gadget(device: &DeviceDescriptor, descriptors: &[u8], strings: &[u8]) { + Command::new("modprobe").arg("g_ffs") + .arg(String::from("bDeviceClass=")+&device.b_device_class.to_string()) + .arg(String::from("bDeviceSubclass=")+&device.b_device_sub_class.to_string()) + .arg(String::from("idVendor=")+&device.id_vendor.to_string()) + .arg(String::from("idProduct=")+&device.id_product.to_string()) + .arg(String::from("iManufacturer=")+device.i_manufacturer) + .arg(String::from("iProduct=")+device.i_product) + .arg(String::from("iSerialNumber=")+device.i_serial_number) + .output().ok(); + Command::new("mkdir").args(["-p","/tmp/ffs-mascon"]).output().ok(); + Command::new("mount").args(["-t","functionfs","mascon","/tmp/ffs-mascon"]).output().ok(); thread::spawn(move || { if let Ok(mut ep0) = File::open("/tmp/ffs-mascon/ep0") { @@ -70,9 +82,9 @@ fn init_gadget() { } }); if let Ok(mut ep0) = File::create("/tmp/ffs-mascon/ep0") { - ep0.write(&descriptors).ok(); + ep0.write(descriptors).ok(); println!("USB Gadget: Descriptors written to EP0"); - ep0.write(&strings).ok(); + ep0.write(strings).ok(); println!("USB Gadget: Strings written to EP0"); } } diff --git a/src/controller/emulated/dgoc44u.rs b/src/controller/emulated/dgoc44u.rs index 0f67d0e..fa0657e 100644 --- a/src/controller/emulated/dgoc44u.rs +++ b/src/controller/emulated/dgoc44u.rs @@ -1,5 +1,14 @@ use bitflags::bitflags; -use crate::state::ControllerState; +use crate::controller::physical::ControllerState; +use crate::controller::emulated::DeviceDescriptor; + +pub const DESCRIPTORS: [u8; 41] = [0x03, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, +0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, +0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; +pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"}; const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00]; const BRAKE_NOTCHES: [u8; 10] = [0x79, 0x8A, 0x94, 0x9A, 0xA2, 0xA8, 0xAF, 0xB2, 0xB5, 0xB9]; @@ -20,6 +29,7 @@ bitflags! { } } + pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles let power = POWER_NOTCHES[state.power as usize]; diff --git a/src/controller/emulated/tcpp20009.rs b/src/controller/emulated/tcpp20009.rs index 81c1c93..e47025c 100644 --- a/src/controller/emulated/tcpp20009.rs +++ b/src/controller/emulated/tcpp20009.rs @@ -1,5 +1,13 @@ use bitflags::bitflags; -use crate::state::ControllerState; +use crate::controller::physical::ControllerState; +use crate::controller::emulated::DeviceDescriptor; + +pub const DESCRIPTORS: [u8; 32] = [0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, +0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, +0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14]; +pub const STRINGS: [u8; 16] = [0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Type 2 mode)", i_serial_number: "TCPP20010"}; const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00]; const BRAKE_NOTCHES: [u8; 10] = [0x79, 0x8A, 0x94, 0x9A, 0xA2, 0xA8, 0xAF, 0xB2, 0xB5, 0xB9]; diff --git a/src/controller/emulated/vok00106.rs b/src/controller/emulated/vok00106.rs index 5c6f8b5..ce975db 100644 --- a/src/controller/emulated/vok00106.rs +++ b/src/controller/emulated/vok00106.rs @@ -1,4 +1,4 @@ -use crate::state::ControllerState; +use crate::controller::physical::ControllerState; const POWER_NOTCHES: [&str; 6] = ["TSA50", "TSA55", "TSA65", "TSA75", "TSA85", "TSA95"]; const BRAKE_NOTCHES: [&str; 10] = ["TSA50", "TSA45", "TSA35", "TSA25", "TSA15", "TSA05", "TSE99", "TSB40", "TSB30", "TSB20"]; diff --git a/src/controller/physical.rs b/src/controller/physical.rs index 94f3131..f3818fe 100644 --- a/src/controller/physical.rs +++ b/src/controller/physical.rs @@ -5,7 +5,23 @@ use std::io::Result; use evdev::Device; use evdev::Key; -use crate::state::ControllerState; +#[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, + pub lamp: bool, + pub rumble: bool, +} 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, diff --git a/src/main.rs b/src/main.rs index 186a49e..313b39a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,10 @@ mod controller; -mod state; use std::io::Result; use std::process::Command; use std::time::Duration; use std::thread::sleep; -use controller::emulated::ControllerModel; use controller::physical::{set_lamp,set_rumble}; fn main() -> Result<()> { @@ -17,35 +15,34 @@ fn main() -> Result<()> { sleep(Duration::from_secs(3)); let mut controller_state = Default::default(); controller::physical::get_state(&mut controller_state, &dev); - let controller_model = controller::emulated::set_model(&controller_state); - // If no model selected, quit - if controller_model == ControllerModel::NONE { - return Result::Ok(()); - } - - // Stop main game - stop_game(); - - // Vibrate to end selection mode - set_rumble(true); - sleep(Duration::from_millis(500)); - set_rumble(false); - - loop { - // Fetch events from input devices - controller::physical::get_state(&mut controller_state, &dev); - - // Send input to virtual controller - controller::emulated::set_state(&mut controller_state, &controller_model); - - // Update lamp and rumble - set_lamp(controller_state.lamp); - set_rumble(controller_state.rumble); - - // Wait between cycles - sleep(Duration::from_millis(20)); + // Check selected controller model + if let Some(controller_model) = controller::emulated::set_model(&controller_state) { + + // Stop main game + stop_game(); + + // Vibrate to end selection mode + set_rumble(true); + sleep(Duration::from_millis(500)); + set_rumble(false); + + loop { + // Fetch events from input devices + controller::physical::get_state(&mut controller_state, &dev); + + // Send input to virtual controller + controller::emulated::set_state(&mut controller_state, &controller_model); + + // Update lamp and rumble + set_lamp(controller_state.lamp); + set_rumble(controller_state.rumble); + + // Wait between cycles + sleep(Duration::from_millis(20)); + } } + return Result::Ok(()); }, Err(_e) => println!("ERROR: Could not read input devices! Exiting."), } diff --git a/src/state.rs b/src/state.rs deleted file mode 100644 index 6960331..0000000 --- a/src/state.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[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, - pub lamp: bool, - pub rumble: bool, -} \ No newline at end of file