diff --git a/Cargo.toml b/Cargo.toml index 9ca323b..1c12fe8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ddgo-pnp-controller" -version = "1.3.0" +version = "1.2.1" edition = "2024" [dependencies] diff --git a/README.md b/README.md index af02d85..c275d7d 100644 --- a/README.md +++ b/README.md @@ -37,38 +37,17 @@ Connect the Plug & Play to a PC or console using the data cable. Press one of th | One handle controller (Nintendo Switch) | UP | SELECT+START=HOME, SELECT+LEFT=L, SELECT+RIGHT=R | | Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD | | Two handle controller (PS1) | DOWN + Power handle at 0 | Hold D to disable handles and enable D-Pad | -| Two handle controller (N64) | DOWN + Power handle at 1 | | -| Two handle controller (SAT) | DOWN + Power handle at 2 | | | Two handle controller "Type 2" (PS2) | D | | | Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | | Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P4/B2-B7 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | -| Generic Train Controller | A | | Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual. If you need more information regarding each controller and supported software, please check the [Densha de GO! controller documentation](https://marcriera.github.io/ddgo-controller-docs). -## Usage with emulators - -### Nintendo 64 - -Use mode *Two handle controller (N64)*. In the emulator's settings, assign the controller to **port 3**. The controller should map automatically. Make sure to enable the setting **Independent C-Buttons controls**. - -### PlayStation - -Use mode *Two handle controller (PS1)*. In the emulator's settings, configure a regular analog/digital controller (**not a Densha de GO! controller**). The controller should map automatically. If the handles become unresponsive at some point., press **D**. - -### PlayStation 2 - -Use mode *Generic Train Controller*. In the emulator's settings, configure a USB Densha de GO! controller and map the buttons/axes manually. - -### Sega Saturn - -Use mode *Two handle controller (SAT)*.The controller should map automatically. - ## RNDIS access (advanced users) When no controller is selected, RNDIS access is enabled in the device. You can access SSH on the Plug & Play at 169.254.215.100. SFTP is not supported out of the box, but SCP is available. Keep in mind the root filesystem is mounted read-only by default. diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index e7ab56b..8f054b8 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -15,12 +15,9 @@ mod sotp031201_p4b2b7; mod sotp031201_p4b7; mod sotp031201_p5b5; mod sotp031201_p5b7; -mod tc5175290; -mod tcpp20003; mod tcpp20009; mod tcpp20011; mod zkns001; -mod generic; const FFS_MOUNT: &str = "/tmp/ffs"; const ENDPOINT0: &str = "/tmp/ffs/ep0"; @@ -30,17 +27,14 @@ const ANDROID_GADGET: &str = "/sys/class/android_usb/android0"; #[derive(PartialEq, Debug, Clone, Copy)] pub enum ControllerModel { DGOC44U, - SLPH00051, + TCPP20009, + TCPP20011, SOTP031201P4B7, SOTP031201P4B2B7, SOTP031201P5B5, SOTP031201P5B7, - TC5175290, - TCPP20003, - TCPP20009, - TCPP20011, ZKNS001, - GENERIC, + SLPH00051, } pub struct DeviceDescriptor { @@ -82,22 +76,6 @@ pub fn set_model(state: &ControllerState) -> Option { &slph00051::DESCRIPTORS, &slph00051::STRINGS, ); - } else if state.button_down && state.power == 1 { - model_name = "TCPP-20004"; - model = ControllerModel::TCPP20003; - descriptors = ( - &tcpp20003::DEVICE_DESCRIPTOR, - &tcpp20003::DESCRIPTORS, - &tcpp20003::STRINGS, - ); - } else if state.button_down && state.power == 2 { - model_name = "TC-5175290"; - model = ControllerModel::TC5175290; - descriptors = ( - &tc5175290::DEVICE_DESCRIPTOR, - &tc5175290::DESCRIPTORS, - &tc5175290::STRINGS, - ); } else if state.button_d { model_name = "TCPP-20009"; model = ControllerModel::TCPP20009; @@ -106,14 +84,6 @@ pub fn set_model(state: &ControllerState) -> Option { &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS, ); - } else if state.button_a { - model_name = "Generic Train Controller"; - model = ControllerModel::GENERIC; - descriptors = ( - &generic::DEVICE_DESCRIPTOR, - &generic::DESCRIPTORS, - &generic::STRINGS, - ); } else if state.button_b { model_name = "TCPP-20011"; model = ControllerModel::TCPP20011; @@ -169,12 +139,6 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::DGOC44U => { dgoc44u::update_gadget(state); } - ControllerModel::TC5175290 => { - tc5175290::update_gadget(state); - } - ControllerModel::TCPP20003 => { - tcpp20003::update_gadget(state); - } ControllerModel::TCPP20009 => { tcpp20009::update_gadget(state); } @@ -199,9 +163,6 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::SLPH00051 => { slph00051::update_gadget(state); } - ControllerModel::GENERIC => { - generic::update_gadget(state); - } } } @@ -220,15 +181,6 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { ControllerModel::SLPH00051 => { report = Some(&slph00051::HID_REPORT_DESCRIPTOR); } - ControllerModel::TC5175290 => { - report = Some(&tc5175290::HID_REPORT_DESCRIPTOR); - } - ControllerModel::TCPP20003 => { - report = Some(&tcpp20003::HID_REPORT_DESCRIPTOR); - } - ControllerModel::GENERIC => { - report = Some(&generic::HID_REPORT_DESCRIPTOR); - } _ => { report = None; } @@ -246,15 +198,6 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { ControllerModel::SLPH00051 => { slph00051::handle_ctrl_transfer(data); } - ControllerModel::TC5175290 => { - tc5175290::handle_ctrl_transfer(data); - } - ControllerModel::TCPP20003 => { - tcpp20003::handle_ctrl_transfer(data); - } - ControllerModel::GENERIC => { - generic::handle_ctrl_transfer(data); - } _ => (), } } diff --git a/src/controller/emulated/generic.rs b/src/controller/emulated/generic.rs deleted file mode 100644 index 601d548..0000000 --- a/src/controller/emulated/generic.rs +++ /dev/null @@ -1,307 +0,0 @@ -use crate::controller::emulated::{DeviceDescriptor, ENDPOINT0, ENDPOINT1}; -use crate::controller::physical::ControllerState; -use bitflags::bitflags; -use std::fs::File; -use std::io::Write; - -pub const DESCRIPTORS: [u8; 80] = [ - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, -]; -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: 0x054C, - id_product: 0x0268, - bcd_device: 0x0100, - i_manufacturer: "TAITO", - i_product: "Densha de Go! Plug & Play (Generic Train Controller mode)", - i_serial_number: "GENERIC-TRAIN-CONTROLLER", -}; - -const POWER_NOTCHES: [u8; 6] = [0x80, 0x94, 0xAC, 0xCC, 0xE4, 0xFF]; -const BRAKE_NOTCHES: [u8; 10] = [0x80, 0x91, 0x9F, 0xAD, 0xBB, 0xC9, 0xD7, 0xE5, 0xF3, 0xFF]; - -pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Physical) - 0xA1, 0x02, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: reserved byte - 0x75, 0x01, // Report Size (1) - 0x95, 0x13, // Report Count (19) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x35, 0x00, // Physical Minimum (0) - 0x45, 0x01, // Physical Maximum (1) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x13, // Usage Maximum (0x13) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0D, // Report Count (13) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Undefined) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: four joysticks - 0xC0, // End Collection - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x75, 0x08, // Report Size (8) - 0x95, 0x27, // Report Count (39) - 0x09, 0x01, // Usage (Pointer) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0x91, - 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0x02, // Report ID (2) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEE, // Report ID (238) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEF, // Report ID (239) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xC0, // End Collection -]; - -const F2_REPORT: [u8; 64] = [ - 0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -const F5_REPORT: [u8; 64] = [ - 0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const SELECT = 1; - const L3 = 2; - const R3 = 4; - const START = 8; - const UP = 16; - const RIGHT = 32; - const DOWN = 64; - const LEFT = 128; - } - struct Buttons2: u8 { - const NONE = 0; - const L2 = 1; - const R2 = 2; - const L1 = 4; - const R1 = 8; - const TRIANGLE = 16; - const CIRCLE = 32; - const CROSS = 64; - const SQUARE = 128; - } -} - -pub fn update_gadget(state: &mut ControllerState) { - // Calculate data for handles - let power = POWER_NOTCHES[state.power as usize]; - let brake = BRAKE_NOTCHES[state.brake as usize]; - - // Calculate data for buttons - let mut buttons1 = Buttons1::NONE; - let mut buttons2 = Buttons2::NONE; - - if state.button_a { - buttons2.insert(Buttons2::SQUARE) - } - if state.button_b { - buttons2.insert(Buttons2::CROSS) - } - if state.button_c { - buttons2.insert(Buttons2::CIRCLE) - } - if state.button_d { - buttons2.insert(Buttons2::TRIANGLE) - } - if state.button_start { - buttons1.insert(Buttons1::START) - } - if state.button_select { - buttons1.insert(Buttons1::SELECT) - } - if state.button_up { - buttons1.insert(Buttons1::UP) - } - if state.button_down { - buttons1.insert(Buttons1::DOWN) - } - if state.button_left { - buttons1.insert(Buttons1::LEFT) - } - if state.button_right { - buttons1.insert(Buttons1::RIGHT) - } - - let btn_up = if buttons1.contains(Buttons1::UP) { - 0xFF - } else { - 0x0 - }; - let btn_right = if buttons1.contains(Buttons1::RIGHT) { - 0xFF - } else { - 0x0 - }; - let btn_down = if buttons1.contains(Buttons1::DOWN) { - 0xFF - } else { - 0x0 - }; - let btn_left = if buttons1.contains(Buttons1::LEFT) { - 0xFF - } else { - 0x0 - }; - let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) { - 0xFF - } else { - 0x0 - }; - let btn_circle = if buttons2.contains(Buttons2::CIRCLE) { - 0xFF - } else { - 0x0 - }; - let btn_cross = if buttons2.contains(Buttons2::CROSS) { - 0xFF - } else { - 0x0 - }; - let btn_square = if buttons2.contains(Buttons2::SQUARE) { - 0xFF - } else { - 0x0 - }; - - // Assemble data and send it to gadget - let data = [ - 0x1, - 0x0, - buttons1.bits, - buttons2.bits, - 0x0, - 0x0, - power, - brake, - 0x80, - 0x80, - 0x0, - 0x0, - 0x0, - 0x0, - btn_up, - btn_right, - btn_down, - btn_left, - 0x0, - 0x0, - 0x0, - 0x0, - btn_triangle, - btn_circle, - btn_cross, - btn_square, - 0x0, - 0x0, - 0x0, - 0x3, - 0xEF, - 0x14, - 0x0, - 0x0, - 0x0, - 0x0, - 0x23, - 0x1A, - 0x77, - 0x1, - 0x81, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - ]; - if let Ok(mut file) = File::create(ENDPOINT1) { - file.write(&data).ok(); - } -} - -pub fn handle_ctrl_transfer(data: &[u8]) { - if data[1] == 1 && data[2] == 0xF2 { - // Init 1 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F2_REPORT).unwrap(); - } - } else if data[1] == 1 && data[2] == 0xF5 { - // Init 2 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F5_REPORT).unwrap(); - } - } -} diff --git a/src/controller/emulated/tc5175290.rs b/src/controller/emulated/tc5175290.rs deleted file mode 100644 index 82e5c3c..0000000 --- a/src/controller/emulated/tc5175290.rs +++ /dev/null @@ -1,361 +0,0 @@ -use crate::controller::emulated::{DeviceDescriptor, ENDPOINT0, ENDPOINT1}; -use crate::controller::physical::ControllerState; -use bitflags::bitflags; -use std::fs::File; -use std::io::Write; - -pub const DESCRIPTORS: [u8; 80] = [ - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, -]; -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: 0x054C, - id_product: 0x0268, - bcd_device: 0x0100, - i_manufacturer: "TAITO", - i_product: "Densha de Go! Plug & Play (SAT Two Handle mode)", - i_serial_number: "TC-5175290", -}; - -pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Physical) - 0xA1, 0x02, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: reserved byte - 0x75, 0x01, // Report Size (1) - 0x95, 0x13, // Report Count (19) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x35, 0x00, // Physical Minimum (0) - 0x45, 0x01, // Physical Maximum (1) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x13, // Usage Maximum (0x13) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0D, // Report Count (13) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Undefined) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: four joysticks - 0xC0, // End Collection - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x75, 0x08, // Report Size (8) - 0x95, 0x27, // Report Count (39) - 0x09, 0x01, // Usage (Pointer) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0x91, - 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0x02, // Report ID (2) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEE, // Report ID (238) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEF, // Report ID (239) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xC0, // End Collection -]; - -const F2_REPORT: [u8; 64] = [ - 0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -const F5_REPORT: [u8; 64] = [ - 0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const SELECT = 1; - const L3 = 2; - const R3 = 4; - const START = 8; - const UP = 16; - const RIGHT = 32; - const DOWN = 64; - const LEFT = 128; - } - struct Buttons2: u8 { - const NONE = 0; - const L2 = 1; - const R2 = 2; - const L1 = 4; - const R1 = 8; - const TRIANGLE = 16; - const CIRCLE = 32; - const CROSS = 64; - const SQUARE = 128; - } -} - -pub fn update_gadget(state: &mut ControllerState) { - let mut buttons1 = Buttons1::NONE; - let mut buttons2 = Buttons2::NONE; - - // Calculate data for handles - match state.power { - 0 => { - buttons2.insert(Buttons2::TRIANGLE | Buttons2::L1); - } - 1 => { - buttons2.insert(Buttons2::SQUARE | Buttons2::L1); - } - 2 => { - buttons2.insert(Buttons2::L1); - } - 3 => { - buttons2.insert(Buttons2::TRIANGLE | Buttons2::SQUARE); - } - 4 => { - buttons2.insert(Buttons2::TRIANGLE); - } - _ => { - buttons2.insert(Buttons2::SQUARE); - } - } - match state.brake { - 0 => { - buttons1.insert(Buttons1::DOWN | Buttons1::LEFT); - buttons2.insert(Buttons2::R2); - } - 1 => { - buttons1.insert(Buttons1::DOWN | Buttons1::LEFT); - buttons2.insert(Buttons2::L2); - } - 2 => { - buttons1.insert(Buttons1::DOWN | Buttons1::LEFT); - } - 3 => { - buttons1.insert(Buttons1::LEFT); - buttons2.insert(Buttons2::R2 | Buttons2::L2); - } - 4 => { - buttons1.insert(Buttons1::LEFT); - buttons2.insert(Buttons2::R2); - } - 5 => { - buttons1.insert(Buttons1::LEFT); - buttons2.insert(Buttons2::L2); - } - 6 => { - buttons1.insert(Buttons1::LEFT); - } - 7 => { - buttons1.insert(Buttons1::DOWN); - buttons2.insert(Buttons2::R2 | Buttons2::L2); - } - 8 => { - buttons1.insert(Buttons1::DOWN); - buttons2.insert(Buttons2::R2); - } - _ => (), - } - - // Calculate data for buttons - if state.button_a { - buttons2.insert(Buttons2::CROSS) - } - if state.button_b { - buttons2.insert(Buttons2::CIRCLE) - } - if state.button_c { - buttons2.insert(Buttons2::R1) - } - if state.button_start { - buttons1.insert(Buttons1::START) - } - - let btn_up = if buttons1.contains(Buttons1::UP) { - 0xFF - } else { - 0x0 - }; - let btn_right = if buttons1.contains(Buttons1::RIGHT) { - 0xFF - } else { - 0x0 - }; - let btn_down = if buttons1.contains(Buttons1::DOWN) { - 0xFF - } else { - 0x0 - }; - let btn_left = if buttons1.contains(Buttons1::LEFT) { - 0xFF - } else { - 0x0 - }; - let btn_l2 = if buttons2.contains(Buttons2::L2) { - 0xFF - } else { - 0x0 - }; - let btn_r2 = if buttons2.contains(Buttons2::R2) { - 0xFF - } else { - 0x0 - }; - let btn_l1 = if buttons2.contains(Buttons2::L1) { - 0xFF - } else { - 0x0 - }; - let btn_r1 = if buttons2.contains(Buttons2::R1) { - 0xFF - } else { - 0x0 - }; - let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) { - 0xFF - } else { - 0x0 - }; - let btn_circle = if buttons2.contains(Buttons2::CIRCLE) { - 0xFF - } else { - 0x0 - }; - let btn_cross = if buttons2.contains(Buttons2::CROSS) { - 0xFF - } else { - 0x0 - }; - let btn_square = if buttons2.contains(Buttons2::SQUARE) { - 0xFF - } else { - 0x0 - }; - - // Assemble data and send it to gadget - let data = [ - 0x1, - 0x0, - buttons1.bits, - buttons2.bits, - 0x0, - 0x0, - 0x80, - 0x80, - 0x80, - 0x80, - 0x0, - 0x0, - 0x0, - 0x0, - btn_up, - btn_right, - btn_down, - btn_left, - btn_l2, - btn_r2, - btn_l1, - btn_r1, - btn_triangle, - btn_circle, - btn_cross, - btn_square, - 0x0, - 0x0, - 0x0, - 0x3, - 0xEF, - 0x14, - 0x0, - 0x0, - 0x0, - 0x0, - 0x23, - 0x1A, - 0x77, - 0x1, - 0x81, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - ]; - if let Ok(mut file) = File::create(ENDPOINT1) { - file.write(&data).ok(); - } -} - -pub fn handle_ctrl_transfer(data: &[u8]) { - if data[1] == 1 && data[2] == 0xF2 { - // Init 1 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F2_REPORT).unwrap(); - } - } else if data[1] == 1 && data[2] == 0xF5 { - // Init 2 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F5_REPORT).unwrap(); - } - } -} diff --git a/src/controller/emulated/tcpp20003.rs b/src/controller/emulated/tcpp20003.rs deleted file mode 100644 index 33032a3..0000000 --- a/src/controller/emulated/tcpp20003.rs +++ /dev/null @@ -1,359 +0,0 @@ -use crate::controller::emulated::{DeviceDescriptor, ENDPOINT0, ENDPOINT1}; -use crate::controller::physical::ControllerState; -use bitflags::bitflags; -use std::fs::File; -use std::io::Write; - -pub const DESCRIPTORS: [u8; 80] = [ - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, - 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, - 0x94, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05, -]; -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: 0x054C, - id_product: 0x0268, - bcd_device: 0x0100, - i_manufacturer: "TAITO", - i_product: "Densha de Go! Plug & Play (N64 Two Handle mode)", - i_serial_number: "TCPP-20004", -}; - -pub const HID_REPORT_DESCRIPTOR: [u8; 148] = [ - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x04, // Usage (Joystick) - 0xA1, 0x01, // Collection (Physical) - 0xA1, 0x02, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: reserved byte - 0x75, 0x01, // Report Size (1) - 0x95, 0x13, // Report Count (19) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x35, 0x00, // Physical Minimum (0) - 0x45, 0x01, // Physical Maximum (1) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x13, // Usage Maximum (0x13) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x01, // Report Size (1) - 0x95, 0x0D, // Report Count (13) - 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) - 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Undefined) - 0x75, 0x08, // Report Size (8) - 0x95, 0x04, // Report Count (4) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0xFF, 0x00, // Physical Maximum (255) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x35, // Usage (Rz) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - // NOTE: four joysticks - 0xC0, // End Collection - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x75, 0x08, // Report Size (8) - 0x95, 0x27, // Report Count (39) - 0x09, 0x01, // Usage (Pointer) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0x91, - 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0x02, // Report ID (2) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEE, // Report ID (238) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xA1, 0x02, // Collection (Application) - 0x85, 0xEF, // Report ID (239) - 0x75, 0x08, // Report Size (8) - 0x95, 0x30, // Report Count (48) - 0x09, 0x01, // Usage (Pointer) - 0xB1, - 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0xC0, // End Collection - 0xC0, // End Collection -]; - -const F2_REPORT: [u8; 64] = [ - 0xF2, 0xFF, 0xFF, 0x0, 0x0, 0x6, 0xF5, 0x48, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -const F5_REPORT: [u8; 64] = [ - 0x1, 0x0, 0x0, 0x23, 0x6, 0x7C, 0xB9, 0xB, 0xE2, 0x49, 0x0, 0x3, 0x50, 0x81, 0xD8, 0x1, 0x8A, - 0x13, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, - 0x0, 0x4, 0x0, 0x1, 0x2, 0x7, 0x0, 0x17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, -]; - -bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const SELECT = 1; - const L3 = 2; - const R3 = 4; - const START = 8; - const UP = 16; - const RIGHT = 32; - const DOWN = 64; - const LEFT = 128; - } - struct Buttons2: u8 { - const NONE = 0; - const L2 = 1; - const R2 = 2; - const L1 = 4; - const R1 = 8; - const TRIANGLE = 16; - const CIRCLE = 32; - const CROSS = 64; - const SQUARE = 128; - } -} - -pub fn update_gadget(state: &mut ControllerState) { - let mut buttons1 = Buttons1::NONE; - let mut buttons2 = Buttons2::NONE; - - // Calculate data for handles - match state.power { - 0 => { - buttons1.insert(Buttons1::UP); - buttons2.insert(Buttons2::L2); - } - 1 => { - buttons1.insert(Buttons1::RIGHT); - buttons2.insert(Buttons2::L2); - } - 2 => { - buttons2.insert(Buttons2::L2); - } - 3 => { - buttons1.insert(Buttons1::UP | Buttons1::RIGHT); - } - 4 => { - buttons1.insert(Buttons1::UP); - } - _ => { - buttons1.insert(Buttons1::RIGHT); - } - } - match state.brake { - 0 => { - buttons2.insert(Buttons2::L1 | Buttons2::CIRCLE | Buttons2::TRIANGLE); - } - 1 => { - buttons2.insert(Buttons2::R1 | Buttons2::CIRCLE | Buttons2::TRIANGLE); - } - 2 => { - buttons2.insert(Buttons2::CIRCLE | Buttons2::TRIANGLE); - } - 3 => { - buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::TRIANGLE); - } - 4 => { - buttons2.insert(Buttons2::L1 | Buttons2::TRIANGLE); - } - 5 => { - buttons2.insert(Buttons2::R1 | Buttons2::TRIANGLE); - } - 6 => { - buttons2.insert(Buttons2::TRIANGLE); - } - 7 => { - buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::CIRCLE); - } - 8 => { - buttons2.insert(Buttons2::L1 | Buttons2::CIRCLE); - } - _ => (), - } - - // Calculate data for buttons - if state.button_a { - buttons2.insert(Buttons2::SQUARE) - } - if state.button_b { - buttons2.insert(Buttons2::CROSS) - } - if state.button_c { - buttons1.insert(Buttons1::SELECT) - } - if state.button_start { - buttons1.insert(Buttons1::START) - } - if state.button_select { - buttons2.insert(Buttons2::R2) - } - - let btn_up = if buttons1.contains(Buttons1::UP) { - 0xFF - } else { - 0x0 - }; - let btn_right = if buttons1.contains(Buttons1::RIGHT) { - 0xFF - } else { - 0x0 - }; - let btn_down = if buttons1.contains(Buttons1::DOWN) { - 0xFF - } else { - 0x0 - }; - let btn_left = if buttons1.contains(Buttons1::LEFT) { - 0xFF - } else { - 0x0 - }; - let btn_l2 = if buttons2.contains(Buttons2::L2) { - 0xFF - } else { - 0x0 - }; - let btn_r2 = if buttons2.contains(Buttons2::R2) { - 0xFF - } else { - 0x0 - }; - let btn_l1 = if buttons2.contains(Buttons2::L1) { - 0xFF - } else { - 0x0 - }; - let btn_r1 = if buttons2.contains(Buttons2::R1) { - 0xFF - } else { - 0x0 - }; - let btn_triangle = if buttons2.contains(Buttons2::TRIANGLE) { - 0xFF - } else { - 0x0 - }; - let btn_circle = if buttons2.contains(Buttons2::CIRCLE) { - 0xFF - } else { - 0x0 - }; - let btn_cross = if buttons2.contains(Buttons2::CROSS) { - 0xFF - } else { - 0x0 - }; - let btn_square = if buttons2.contains(Buttons2::SQUARE) { - 0xFF - } else { - 0x0 - }; - - // Assemble data and send it to gadget - let data = [ - 0x1, - 0x0, - buttons1.bits, - buttons2.bits, - 0x0, - 0x0, - 0x80, - 0x80, - 0x80, - 0x80, - 0x0, - 0x0, - 0x0, - 0x0, - btn_up, - btn_right, - btn_down, - btn_left, - btn_l2, - btn_r2, - btn_l1, - btn_r1, - btn_triangle, - btn_circle, - btn_cross, - btn_square, - 0x0, - 0x0, - 0x0, - 0x3, - 0xEF, - 0x14, - 0x0, - 0x0, - 0x0, - 0x0, - 0x23, - 0x1A, - 0x77, - 0x1, - 0x81, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - 0x1, - 0xFE, - ]; - if let Ok(mut file) = File::create(ENDPOINT1) { - file.write(&data).ok(); - } -} - -pub fn handle_ctrl_transfer(data: &[u8]) { - if data[1] == 1 && data[2] == 0xF2 { - // Init 1 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F2_REPORT).unwrap(); - } - } else if data[1] == 1 && data[2] == 0xF5 { - // Init 2 - if let Ok(mut file) = File::create(ENDPOINT0) { - file.write(&F5_REPORT).unwrap(); - } - } -}