diff --git a/src/controller/emulated.rs b/src/controller/emulated.rs index 9db4a7f..dfc6c6e 100644 --- a/src/controller/emulated.rs +++ b/src/controller/emulated.rs @@ -1,4 +1,6 @@ use std::thread; +use std::thread::sleep; +use std::time::Duration; use std::fs; use std::fs::File; use std::io::{Read, Write}; @@ -6,6 +8,7 @@ use std::process::Command; use std::path::Path; use crate::controller::physical::ControllerState; + mod dgoc44u; mod tcpp20009; mod tcpp20011; @@ -14,6 +17,7 @@ mod sotp031201_p4b2b7; mod sotp031201_p5b5; mod sotp031201_p5b7; mod vok00106; +mod zkns001; const FFS_MOUNT: &str = "/tmp/ffs"; const ENDPOINT0: &str = "/tmp/ffs/ep0"; @@ -30,6 +34,7 @@ pub enum ControllerModel { SOTP031201P5B5, SOTP031201P5B7, VOK00106, + ZKNS001, } pub struct DeviceDescriptor { @@ -46,11 +51,16 @@ pub fn set_model(state: &ControllerState) -> Option { let model; let model_name; let descriptors: (&DeviceDescriptor, &[u8], &[u8]); - if !state.button_right { + if state.button_right { model_name = "DGOC44-U"; model = ControllerModel::DGOC44U; descriptors = (&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS); } + else if state.button_up { + model_name = "ZKNS-001"; + model = ControllerModel::ZKNS001; + descriptors = (&zkns001::DEVICE_DESCRIPTOR, &zkns001::DESCRIPTORS, &zkns001::STRINGS); + } else if state.button_d { model_name = "TCPP-20009"; model = ControllerModel::TCPP20009; @@ -120,16 +130,24 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) { ControllerModel::VOK00106 => { vok00106::update_gadget(state); } + ControllerModel::ZKNS001 => { + zkns001::update_gadget(state); + } } } pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { - if data[1] == 6 { - let report; + println!("CTRL TRANSFER: {:?}", data); + if data[1] == 6 && data[3] == 34 { + // Get HID report descriptor + let report: Option<&[u8]>; match model { ControllerModel::DGOC44U => { report = Some(&dgoc44u::HID_REPORT_DESCRIPTOR); } + ControllerModel::ZKNS001 => { + report = Some(&zkns001::HID_REPORT_DESCRIPTOR); + } _ => { report = None; } @@ -143,8 +161,9 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) { None => (), } } - else { + else if data[1] == 9 { // Other control transfer, pass it to emulated controller loop + super::physical::set_lamp(true); } } @@ -173,8 +192,9 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device // Control transfer received handle_ctrl_transfer(controller_model, &buffer[0..8]); } - } + // Wait between cycles + sleep(Duration::from_millis(10)); } } }); diff --git a/src/controller/emulated/dgoc44u.rs b/src/controller/emulated/dgoc44u.rs index a77685d..30479d0 100644 --- a/src/controller/emulated/dgoc44u.rs +++ b/src/controller/emulated/dgoc44u.rs @@ -4,13 +4,13 @@ use bitflags::bitflags; use crate::controller::physical::ControllerState; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; -pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, +pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 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, +0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x28, 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]; +0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x28]; 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"}; @@ -54,21 +54,20 @@ 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]; bitflags! { - struct Buttons: u8 { - const NONE = 0; - const B = 1; - const A = 2; - const C = 4; - const D = 8; - const SELECT = 16; - const START = 32; - const UP = Self::SELECT.bits | Self::D.bits; - const DOWN = Self::SELECT.bits | Self::B.bits; - const LEFT = Self::SELECT.bits | Self::A.bits; - const RIGHT = Self::SELECT.bits | Self::C.bits; - } + struct Buttons: u8 { + const NONE = 0; + const B = 1; + const A = 2; + const C = 4; + const D = 8; + const SELECT = 16; + const START = 32; + const UP = Self::SELECT.bits | Self::D.bits; + const DOWN = Self::SELECT.bits | Self::B.bits; + const LEFT = Self::SELECT.bits | Self::A.bits; + const RIGHT = Self::SELECT.bits | Self::C.bits; } - +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/sotp031201_p4b2b7.rs b/src/controller/emulated/sotp031201_p4b2b7.rs index d4d5ad7..e5527e4 100644 --- a/src/controller/emulated/sotp031201_p4b2b7.rs +++ b/src/controller/emulated/sotp031201_p4b2b7.rs @@ -18,25 +18,25 @@ const POWER_NOTCHES: [u8; 6] = [0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x01]; bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const S = 1; - const D = 2; - const A = 4; - const A2 = 8; - const B = 16; - const C = 32; - } - struct Buttons2: u8 { - const NONE = 0; - const START = 1; - const SELECT = 2; - const UP = 4; - const DOWN = 8; - const LEFT = 16; - const RIGHT = 32; - } + struct Buttons1: u8 { + const NONE = 0; + const S = 1; + const D = 2; + const A = 4; + const A2 = 8; + const B = 16; + const C = 32; } + struct Buttons2: u8 { + const NONE = 0; + const START = 1; + const SELECT = 2; + const UP = 4; + const DOWN = 8; + const LEFT = 16; + const RIGHT = 32; + } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/sotp031201_p4b7.rs b/src/controller/emulated/sotp031201_p4b7.rs index 2838817..e2f7e04 100644 --- a/src/controller/emulated/sotp031201_p4b7.rs +++ b/src/controller/emulated/sotp031201_p4b7.rs @@ -18,25 +18,25 @@ const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const S = 1; - const D = 2; - const A = 4; - const A2 = 8; - const B = 16; - const C = 32; - } - struct Buttons2: u8 { - const NONE = 0; - const START = 1; - const SELECT = 2; - const UP = 4; - const DOWN = 8; - const LEFT = 16; - const RIGHT = 32; - } + struct Buttons1: u8 { + const NONE = 0; + const S = 1; + const D = 2; + const A = 4; + const A2 = 8; + const B = 16; + const C = 32; } + struct Buttons2: u8 { + const NONE = 0; + const START = 1; + const SELECT = 2; + const UP = 4; + const DOWN = 8; + const LEFT = 16; + const RIGHT = 32; + } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/sotp031201_p5b5.rs b/src/controller/emulated/sotp031201_p5b5.rs index a1ac9db..5dc9e7b 100644 --- a/src/controller/emulated/sotp031201_p5b5.rs +++ b/src/controller/emulated/sotp031201_p5b5.rs @@ -18,25 +18,25 @@ const POWER_NOTCHES: [u8; 6] = [0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C]; const BRAKE_NOTCHES: [u8; 10] = [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01]; bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const S = 1; - const D = 2; - const A = 4; - const A2 = 8; - const B = 16; - const C = 32; - } - struct Buttons2: u8 { - const NONE = 0; - const START = 1; - const SELECT = 2; - const UP = 4; - const DOWN = 8; - const LEFT = 16; - const RIGHT = 32; - } + struct Buttons1: u8 { + const NONE = 0; + const S = 1; + const D = 2; + const A = 4; + const A2 = 8; + const B = 16; + const C = 32; } + struct Buttons2: u8 { + const NONE = 0; + const START = 1; + const SELECT = 2; + const UP = 4; + const DOWN = 8; + const LEFT = 16; + const RIGHT = 32; + } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/sotp031201_p5b7.rs b/src/controller/emulated/sotp031201_p5b7.rs index e1f0c47..503b26b 100644 --- a/src/controller/emulated/sotp031201_p5b7.rs +++ b/src/controller/emulated/sotp031201_p5b7.rs @@ -18,25 +18,25 @@ const POWER_NOTCHES: [u8; 6] = [0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01]; bitflags! { - struct Buttons1: u8 { - const NONE = 0; - const S = 1; - const D = 2; - const A = 4; - const A2 = 8; - const B = 16; - const C = 32; - } - struct Buttons2: u8 { - const NONE = 0; - const START = 1; - const SELECT = 2; - const UP = 4; - const DOWN = 8; - const LEFT = 16; - const RIGHT = 32; - } + struct Buttons1: u8 { + const NONE = 0; + const S = 1; + const D = 2; + const A = 4; + const A2 = 8; + const B = 16; + const C = 32; } + struct Buttons2: u8 { + const NONE = 0; + const START = 1; + const SELECT = 2; + const UP = 4; + const DOWN = 8; + const LEFT = 16; + const RIGHT = 32; + } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/tcpp20009.rs b/src/controller/emulated/tcpp20009.rs index 705832b..3442ba2 100644 --- a/src/controller/emulated/tcpp20009.rs +++ b/src/controller/emulated/tcpp20009.rs @@ -18,16 +18,16 @@ 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]; bitflags! { - struct Buttons: u8 { - const NONE = 0; - const B = 1; - const A = 2; - const C = 4; - const D = 8; - const SELECT = 16; - const START = 32; - } + struct Buttons: u8 { + const NONE = 0; + const B = 1; + const A = 2; + const C = 4; + const D = 8; + const SELECT = 16; + const START = 32; } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/tcpp20011.rs b/src/controller/emulated/tcpp20011.rs index a1259a2..6437a53 100644 --- a/src/controller/emulated/tcpp20011.rs +++ b/src/controller/emulated/tcpp20011.rs @@ -12,22 +12,22 @@ pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0 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: 0x5, id_vendor: 0x0AE4, id_product: 0x0005, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Shinkansen)", i_serial_number: "TCPP20011"}; +pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x5, id_vendor: 0x0AE4, id_product: 0x0005, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Shinkansen mode)", i_serial_number: "TCPP20011"}; const POWER_NOTCHES: [u8; 6] = [0x12, 0x36, 0x5A, 0x90, 0xC6, 0xFB]; const BRAKE_NOTCHES: [u8; 10] = [0x1C, 0x38, 0x54, 0x70, 0x8B, 0xA7, 0xC3, 0xDF, 0xDF, 0xFB]; bitflags! { - struct Buttons: u8 { - const NONE = 0; - const D = 1; - const C = 2; - const B = 4; - const A = 8; - const SELECT = 16; - const START = 32; - } + struct Buttons: u8 { + const NONE = 0; + const D = 1; + const C = 2; + const B = 4; + const A = 8; + const SELECT = 16; + const START = 32; } +} pub fn update_gadget(state: &mut ControllerState) { // Calculate data for handles diff --git a/src/controller/emulated/zkns001.rs b/src/controller/emulated/zkns001.rs new file mode 100644 index 0000000..3b55f57 --- /dev/null +++ b/src/controller/emulated/zkns001.rs @@ -0,0 +1,123 @@ +use std::fs::File; +use std::io::{Write}; +use bitflags::bitflags; +use crate::controller::physical::ControllerState; +use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; + +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, 0x5E, 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, 0x5E, 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: 0x33DD, id_product: 0x0001, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (NS One Handle mode)", i_serial_number: "ZKNS-001"}; + +pub const HID_REPORT_DESCRIPTOR: [u8; 94] = [ + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x05, // Usage (Game Pad) + 0xA1, 0x01, // Collection (Application) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0E, // Report Count (14) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x0E, // Usage Maximum (0x0E) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x02, // Report Count (2) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x25, 0x07, // Logical Maximum (7) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) + 0x09, 0x39, // Usage (Hat switch) + 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) + 0x65, 0x00, // Unit (None) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x75, 0x08, // Report Size (8) + 0x95, 0x08, // Report Count (8) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x0A, 0x4F, 0x48, // Usage (0x484F) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection +]; + +const POWER_NOTCHES: [u8; 6] = [0x80, 0x9F, 0xB7, 0xCE, 0xE6, 0xFF]; +const BRAKE_NOTCHES: [u8; 10] = [0x80, 0x65, 0x57, 0x49, 0x3C, 0x2E, 0x20, 0x13, 0x05, 0x00]; + +bitflags! { + struct Buttons1: u8 { + const NONE = 0; + const Y = 1; + const B = 2; + const A = 4; + const X = 8; + const ZL = 64; + } + struct Buttons2: u8 { + const NONE = 0; + const SELECT = 1; + const START = 2; + } +} + +pub fn update_gadget(state: &mut ControllerState) { + // Calculate data for handles + let mut handle = POWER_NOTCHES[state.power as usize]; + if state.brake > 0 { + handle = BRAKE_NOTCHES[state.brake as usize]; + } + + // Calculate data for buttons 1 + let mut buttons1 = Buttons1::NONE; + if state.button_a { buttons1.insert(Buttons1::Y) } + if state.button_b { buttons1.insert(Buttons1::B) } + if state.button_c { buttons1.insert(Buttons1::A) } + if state.button_d { buttons1.insert(Buttons1::X) } + if state.brake == 9 { buttons1.insert(Buttons1::ZL) } + + // Calculate data for buttons 2 + let mut buttons2 = Buttons2::NONE; + if state.button_start { buttons2.insert(Buttons2::START) } + if state.button_select { buttons2.insert(Buttons2::SELECT) } + + // Calculate data for D-pad + let mut dpad: u8 = 0xF; + if state.button_up { dpad = 0x0 } + if state.button_down { dpad = 0x4 } + if state.button_left { dpad = 0x6 } + if state.button_right { dpad = 0x2 } + if state.button_up & state.button_left { dpad = 0x7 } + if state.button_up & state.button_right { dpad = 0x1 } + if state.button_down & state.button_left { dpad = 0x5 } + if state.button_down & state.button_right { dpad = 0x3 } + + // Assemble data and send it to gadget + let data = [buttons1.bits, buttons2.bits, dpad, 0x80, handle, 0x80, 0x80, 0x00]; + if let Ok(mut file) = File::create(ENDPOINT1) { + file.write(&data).ok(); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 313b39a..5290fe3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,7 @@ fn main() -> Result<()> { set_rumble(controller_state.rumble); // Wait between cycles - sleep(Duration::from_millis(20)); + sleep(Duration::from_millis(5)); } } return Result::Ok(());