Add button combos

This commit is contained in:
Marc Riera Irigoyen 2023-04-30 21:38:03 +02:00
parent 1c7eb05cab
commit 8bd5b463c1
12 changed files with 194 additions and 84 deletions

View file

@ -20,16 +20,16 @@ This mod allows you to use your Densha de GO! Plug & Play as a USB controller fo
Connect the Plug & Play to a PC or console using the data cable. Press one of the following button combinations to select the controller you want to emulate:
| Controller | Button combination | Notes |
|-----------------------------------------|-----------------------|----------------------------------------------|
| One handle controller (Nintendo Switch) | UP | |
| Two handle controller (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD |
| 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 | |
| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | Beta, currently undetected by game |
| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | |
| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | Beta, currently undetected by game |
| Controller | Button combination | Notes |
|-----------------------------------------|-----------------------|--------------------------------------------------|
| 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 "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 | |
| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | |
| Multi Train Controller (PS2) - P5/B5 | C + Power handle at 2 | |
| Multi Train Controller (PS2) - P5/B7 | C + Power handle at 3 | Beta, currently undetected by game |
Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual.
@ -43,3 +43,11 @@ When no controller is selected, RNDIS access is enabled in the device. You can a
- During the first installation, the device's kernel is backed up to a folder named *BACKUP* in the root of the USB drive. Copy its contents to a safe location.
- If detected, the [original mod by GMMan](https://github.com/GMMan/dengo-plug-and-play-controller) will be uninstalled to avoid conflicts.
## Compilation
To compile the program yourself, you will need Rust and toolchain for Armv7-A. The easiest way is to install [cross](https://github.com/cross-rs/cross) and run:
```cross build --target arm-unknown-linux-musleabi --release```
The Linux kernel source can be found [here](https://github.com/MarcRiera/dengo-plug-and-play-kernel).

View file

@ -42,6 +42,7 @@ pub struct DeviceDescriptor {
b_device_sub_class: u8,
id_vendor: u16,
id_product: u16,
bcd_device: u16,
i_manufacturer: &'static str,
i_product: &'static str,
i_serial_number: &'static str,
@ -175,6 +176,7 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device
.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("bcdDevice=")+&device.bcd_device.to_string())
.arg(String::from("iManufacturer=")+device.i_manufacturer)
.arg(String::from("iProduct=")+device.i_product)
.arg(String::from("iSerialNumber=")+device.i_serial_number)
@ -213,6 +215,7 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device
fs::write(gadget.join(Path::new("bDeviceSubClass")), &device.b_device_sub_class.to_string()).ok();
fs::write(gadget.join(Path::new("idVendor")), format!("{:x}", &device.id_vendor)).ok();
fs::write(gadget.join(Path::new("idProduct")), format!("{:x}", &device.id_product)).ok();
fs::write(gadget.join(Path::new("bcdDevice")), format!("{:x}", &device.bcd_device)).ok();
fs::write(gadget.join(Path::new("iManufacturer")), &device.i_manufacturer.to_string()).ok();
fs::write(gadget.join(Path::new("iProduct")), &device.i_product.to_string()).ok();
fs::write(gadget.join(Path::new("iSerial")), &device.i_serial_number.to_string()).ok();

View file

@ -13,7 +13,7 @@ pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x0
0x07, 0x05, 0x81, 0x03, 0x08, 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: 0x0AE4, id_product: 0x0003, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0003, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play", i_serial_number: "DGOC-44U"};
pub const HID_REPORT_DESCRIPTOR: [u8; 63] = [
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)

View file

@ -12,7 +12,7 @@ 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: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", i_serial_number: "SOTP-031201"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0400, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B2-B7 mode)", i_serial_number: "SOTP-031201"};
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];
@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) {
handle = BRAKE_NOTCHES[state.brake as usize];
}
// Calculate data for buttons 1
// Calculate data for buttons
let mut buttons1 = Buttons1::NONE;
if state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
// Calculate data for buttons 2
let mut buttons2 = Buttons2::NONE;
if state.button_up { buttons2.insert(Buttons2::UP) }
if state.button_down { buttons2.insert(Buttons2::DOWN) }
if state.button_left { buttons2.insert(Buttons2::LEFT) }
if !state.button_select_hold && state.button_select && state.button_a {
buttons1.insert(Buttons1::A2);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_d {
buttons1.insert(Buttons1::S);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_up {
state.reverser = 0x80;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_left {
state.reverser = 0x00;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_down {
state.reverser = 0x40;
state.combo = true;
}
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) }
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) }
if state.button_right { buttons2.insert(Buttons2::RIGHT) }
if state.button_start { buttons2.insert(Buttons2::START) }
if state.button_select { buttons2.insert(Buttons2::SELECT) }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) }
// Assemble data and send it to endpoint
let data = [0x1, handle, buttons1.bits, buttons2.bits];
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok();
}

View file

@ -12,7 +12,7 @@ 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: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P4/B7 mode)", i_serial_number: "SOTP-031201"};
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];
@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) {
handle = BRAKE_NOTCHES[state.brake as usize];
}
// Calculate data for buttons 1
// Calculate data for buttons
let mut buttons1 = Buttons1::NONE;
if state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
// Calculate data for buttons 2
let mut buttons2 = Buttons2::NONE;
if state.button_up { buttons2.insert(Buttons2::UP) }
if state.button_down { buttons2.insert(Buttons2::DOWN) }
if state.button_left { buttons2.insert(Buttons2::LEFT) }
if !state.button_select_hold && state.button_select && state.button_a {
buttons1.insert(Buttons1::A2);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_d {
buttons1.insert(Buttons1::S);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_up {
state.reverser = 0x80;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_left {
state.reverser = 0x00;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_down {
state.reverser = 0x40;
state.combo = true;
}
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) }
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) }
if state.button_right { buttons2.insert(Buttons2::RIGHT) }
if state.button_start { buttons2.insert(Buttons2::START) }
if state.button_select { buttons2.insert(Buttons2::SELECT) }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) }
// Assemble data and send it to endpoint
let data = [0x1, handle, buttons1.bits, buttons2.bits];
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok();
}

View file

@ -12,7 +12,7 @@ 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: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x1C06, id_product: 0x77A7, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B5 mode)", i_serial_number: "SOTP-031201"};
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];
@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) {
handle = BRAKE_NOTCHES[state.brake as usize];
}
// Calculate data for buttons 1
// Calculate data for buttons
let mut buttons1 = Buttons1::NONE;
if state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
// Calculate data for buttons 2
let mut buttons2 = Buttons2::NONE;
if state.button_up { buttons2.insert(Buttons2::UP) }
if state.button_down { buttons2.insert(Buttons2::DOWN) }
if state.button_left { buttons2.insert(Buttons2::LEFT) }
if !state.button_select_hold && state.button_select && state.button_a {
buttons1.insert(Buttons1::A2);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_d {
buttons1.insert(Buttons1::S);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_up {
state.reverser = 0x20;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_left {
state.reverser = 0x00;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_down {
state.reverser = 0x10;
state.combo = true;
}
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) }
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) }
if state.button_right { buttons2.insert(Buttons2::RIGHT) }
if state.button_start { buttons2.insert(Buttons2::START) }
if state.button_select { buttons2.insert(Buttons2::SELECT) }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) }
// Assemble data and send it to endpoint
let data = [0x1, handle, buttons1.bits, buttons2.bits];
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok();
}

View file

@ -12,7 +12,7 @@ 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: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x00, b_device_sub_class: 0x0, id_vendor: 0x0AE4, id_product: 0x0101, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (MTC P5/B7 mode)", i_serial_number: "SOTP-031201"};
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];
@ -45,24 +45,42 @@ pub fn update_gadget(state: &mut ControllerState) {
handle = BRAKE_NOTCHES[state.brake as usize];
}
// Calculate data for buttons 1
// Calculate data for buttons
let mut buttons1 = Buttons1::NONE;
if state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
// Calculate data for buttons 2
let mut buttons2 = Buttons2::NONE;
if state.button_up { buttons2.insert(Buttons2::UP) }
if state.button_down { buttons2.insert(Buttons2::DOWN) }
if state.button_left { buttons2.insert(Buttons2::LEFT) }
if !state.button_select_hold && state.button_select && state.button_a {
buttons1.insert(Buttons1::A2);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_d {
buttons1.insert(Buttons1::S);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_up {
state.reverser = 0x80;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_left {
state.reverser = 0x00;
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_down {
state.reverser = 0x40;
state.combo = true;
}
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) }
if state.button_b { buttons1.insert(Buttons1::B) }
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) }
if state.button_d { buttons1.insert(Buttons1::D) }
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) }
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) }
if state.button_right { buttons2.insert(Buttons2::RIGHT) }
if state.button_start { buttons2.insert(Buttons2::START) }
if state.button_select { buttons2.insert(Buttons2::SELECT) }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) }
// Assemble data and send it to endpoint
let data = [0x1, handle, buttons1.bits, buttons2.bits];
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok();
}

View file

@ -12,7 +12,7 @@ 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: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Type 2 mode)", i_serial_number: "TCPP20010"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0xFF, b_device_sub_class: 0x4, id_vendor: 0x0AE4, id_product: 0x0004, bcd_device: 0x0102, 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];

View file

@ -12,7 +12,7 @@ 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 mode)", 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, bcd_device: 0x0102, 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];

View file

@ -12,7 +12,7 @@ pub const DESCRIPTORS: [u8; 76] = [0x01, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x0
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01,];
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: 0x02, b_device_sub_class: 0x0, id_vendor: 0x067B, id_product: 0x2303, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Master Controller II mode)", i_serial_number: "VOK-00106"};
pub const DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x02, b_device_sub_class: 0x0, id_vendor: 0x067B, id_product: 0x2303, bcd_device: 0x0102, i_manufacturer: "TAITO", i_product: "Densha de Go! Plug & Play (Master Controller II mode)", i_serial_number: "VOK-00106"};
const POWER_NOTCHES: [&str; 6] = ["TSA50", "TSA55", "TSA65", "TSA75", "TSA85", "TSA95"];

View file

@ -15,7 +15,7 @@ pub const DESCRIPTORS: [u8; 80] = [0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x0
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 DEVICE_DESCRIPTOR: DeviceDescriptor = DeviceDescriptor{b_device_class: 0x0, b_device_sub_class: 0x0, id_vendor: 0x33DD, id_product: 0x0001, bcd_device: 0x0106, 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)
@ -94,32 +94,39 @@ pub fn update_gadget(state: &mut ControllerState) {
handle = BRAKE_NOTCHES[state.brake as usize];
}
// Calculate data for buttons 1
// Calculate data for buttons
let mut buttons1 = Buttons1::NONE;
let mut buttons2 = Buttons2::NONE;
if !state.button_select_hold && state.button_select && state.button_left {
buttons1.insert(Buttons1::L);
state.combo = true;
}
if !state.button_select_hold && state.button_select && state.button_right {
buttons1.insert(Buttons1::R);
state.combo = true;
}
if !state.button_select_hold && state.button_start && state.button_select {
buttons2.insert(Buttons2::HOME);
state.combo = true;
}
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) }
if state.button_select && state.button_left { buttons1.insert(Buttons1::L) }
if state.button_select && state.button_right { buttons1.insert(Buttons1::R) }
// Calculate data for buttons 2
let mut buttons2 = Buttons2::NONE;
if state.button_start && !state.button_select { buttons2.insert(Buttons2::START) }
if state.button_select && !state.button_start { buttons2.insert(Buttons2::SELECT) }
if state.button_start && state.button_select { buttons2.insert(Buttons2::HOME) }
if !state.combo && state.button_start { buttons2.insert(Buttons2::START) }
if !state.combo && state.button_select_hold { 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 }
if !state.combo && state.button_left { dpad = 0x6 }
if !state.combo && state.button_right { dpad = 0x2 }
if !state.combo && state.button_up & state.button_left { dpad = 0x7 }
if !state.combo && state.button_up & state.button_right { dpad = 0x1 }
if !state.combo && state.button_down & state.button_left { dpad = 0x5 }
if !state.combo && 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];

View file

@ -1,6 +1,7 @@
use std::fs::File;
use std::io::Write;
use std::io::Result;
use std::time::{Instant,Duration};
use evdev::Device;
use evdev::Key;
@ -10,6 +11,8 @@ pub struct ControllerState {
pub power: u8,
pub brake: u8,
pub button_select: bool,
pub button_select_hold: bool,
pub button_select_time: Option<Instant>,
pub button_start: bool,
pub button_a: bool,
pub button_b: bool,
@ -21,8 +24,12 @@ pub struct ControllerState {
pub button_right: bool,
pub lamp: bool,
pub rumble: bool,
pub combo: bool,
pub reverser: u8,
}
const HOLD_DELAY: Duration = Duration::from_millis(750);
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];
@ -47,7 +54,7 @@ pub fn get_state(state: &mut ControllerState, dev: &[Device; 2]) {
fn read_input(controller: &mut ControllerState, key: Key, value: bool) {
// Save input status to object for processing
match key{
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},
@ -64,7 +71,20 @@ fn read_input(controller: &mut ControllerState, key: Key, value: bool) {
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_SPACE=> {
if !controller.button_select && value {
controller.button_select_time = Some(Instant::now());
}
else if !value {
controller.button_select_time = None;
controller.combo = false;
}
controller.button_select = value;
controller.button_select_hold = value;
if let Some(time) = controller.button_select_time {
controller.button_select_hold = time.elapsed() > HOLD_DELAY && !controller.combo;
}
},
Key::KEY_ENTER=>controller.button_start = value,
Key::KEY_A=>controller.button_a = value,
Key::KEY_Z=>controller.button_b = value,