Compare commits

..

12 commits
v1.0.0 ... main

Author SHA1 Message Date
Marc Riera
5d70ae00d4 Release: 1.2.1 2025-03-23 21:38:42 +01:00
Marc Riera
a6b99f2817 Update to Rust 2024 and formatting changes 2025-03-23 21:21:45 +01:00
Marc Riera
122ce1a82f Release: 1.2.0 2023-12-10 16:18:55 +01:00
Marc Riera
bd2213f14f Fix D combo with MTC 2023-12-10 16:17:04 +01:00
Marc Riera
8aa9a02c21
Update README.md 2023-11-05 09:50:17 +01:00
Marc Riera Irigoyen
8ed2d1300c Remove unused code 2023-06-28 19:18:02 +02:00
Marc Riera
7011359bb6 Ensure the backup folder is created 2023-06-08 23:52:35 +02:00
Marc Riera
8b443ccb5e Release: 1.1.0 2023-06-01 22:02:58 +02:00
Marc Riera
b2daa5d017 Finish SLPH-00051 support 2023-06-01 21:58:32 +02:00
Marc Riera Irigoyen
f317be0f15 MTC: fix P5/B7 2023-06-01 17:34:21 +02:00
Marc Riera Irigoyen
1f84543091 Handle control requests for Dualshock 3 2023-05-22 18:30:11 +02:00
Marc Riera
c6013f2b74 Basic support for SLPH-00051 2023-05-20 12:35:45 +02:00
17 changed files with 1237 additions and 430 deletions

View file

@ -1,8 +1,8 @@
[package] [package]
name = "ddgo-pnp-controller" name = "ddgo-pnp-controller"
version = "1.0.0" version = "1.2.1"
edition = "2021" edition = "2024"
[dependencies] [dependencies]
bitflags = "1.3.2" bitflags = "1.3.2"
evdev = "0.12.1" evdev = "0.12.2"

View file

@ -16,19 +16,33 @@ This mod allows you to use your Densha de GO! Plug & Play as a USB controller fo
4. Plug the USB drive to the OTG adapter, plug the adapter to the Plug & Play and plug the data cable to the adapter and a power source. 4. Plug the USB drive to the OTG adapter, plug the adapter to the Plug & Play and plug the data cable to the adapter and a power source.
5. Turn on the Plug & Play. The door lamp will turn on to show the installation has begun. Once it has finished, the lamp will turn off. Turn off the unit and remove everything. 5. Turn on the Plug & Play. The door lamp will turn on to show the installation has begun. Once it has finished, the lamp will turn off. Turn off the unit and remove everything.
## Uninstallation
To completely remove the mod, follow these steps. **You need the backup of the original kernel created during installation**.
1. Prepare the USB flash drive by formatting it with a single FAT32 partition.
2. Download the latest release from the [Releases](https://github.com/MarcRiera/ddgo-pnp-controller/releases) section.
3. Extract the content to the root of the USB drive.
4. Create an empty file named `revert` on the root of the USB drive.
5. Put the original (backup) files `uImage` and `mali.ko` into a folder named `BACKUP` on the root of the USB drive.
6. Plug the USB drive to the OTG adapter, plug the adapter to the Plug & Play and plug the data cable to the adapter and a power source.
7. Turn on the Plug & Play. The door lamp will turn on to show the uninstallation has begun. Once it has finished, the lamp will turn off. Turn off the unit and remove everything.
## Usage ## Usage
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: 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 | | Controller | Button combination | Notes |
|-----------------------------------------|-----------------------|--------------------------------------------------| |-----------------------------------------|--------------------------|--------------------------------------------------|
| One handle controller (Nintendo Switch) | UP | SELECT+START=HOME, SELECT+LEFT=L, SELECT+RIGHT=R | | 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 (PC) | RIGHT | D-Pad is mapped to SELECT+ABCD |
| Two handle controller "Type 2" (PS2) | D | | | Two handle controller (PS1) | DOWN + Power handle at 0 | Hold D to disable handles and enable D-Pad |
| Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 | | Two handle controller "Type 2" (PS2) | D | |
| Multi Train Controller (PS2) - P4/B7 | C + Power handle at 0 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | Shinkansen controller (PS2) | B | Power notches are mapped to P2-P4-P7-P10-P13 |
| Multi Train Controller (PS2) - P4/B2-B6 | C + Power handle at 1 | SELECT+A=A2, SELECT+D=ATS, SELECT+D-Pad=Reverser | | 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) - P5/B5 | C + Power handle at 2 | 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 |
Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual. Hold the buttons until the controller vibrates to confirm selection. If no button is pressed, you can play with the Plug & Play as usual.

View file

@ -33,6 +33,25 @@ if ! mount -o remount,rw /; then
error_exit error_exit
fi fi
# Create backup folder
mkdir -p "${USB_ROOT}/BACKUP"
# Revert changes flag detected, restore original files
if [ -f "${USB_ROOT}/revert" ]; then
if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] || [ ! -f "${USB_ROOT}/BACKUP/mali.ko" ]; then
echo "Backup not found, cannot revert."
error_exit
fi
cp "${USB_ROOT}/BACKUP/uImage" /tmp/boot/uImage
cp "${USB_ROOT}/BACKUP/mali.ko" /lib/modules/3.4.113/extra/mali.ko
rm /etc/init.d/S40usbotg
rm /usr/bin/rndis-gadget.sh
rm /usr/bin/ddgo-pnp-controller
rm "${USB_ROOT}/revert"
poweroff
exit
fi
# Backup original kernel # Backup original kernel
if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] && [ ! -f "/usr/bin/input_relay" ] && [ ! -f "/usr/bin/ddgo-pnp-controller" ]; then if [ ! -f "${USB_ROOT}/BACKUP/uImage" ] && [ ! -f "/usr/bin/input_relay" ] && [ ! -f "/usr/bin/ddgo-pnp-controller" ]; then
if ! cp /tmp/boot/uImage "${USB_ROOT}/BACKUP/"; then if ! cp /tmp/boot/uImage "${USB_ROOT}/BACKUP/"; then

View file

@ -1,2 +1,2 @@
pub mod physical;
pub mod emulated; pub mod emulated;
pub mod physical;

View file

@ -1,22 +1,22 @@
use std::thread;
use std::thread::sleep;
use std::time::Duration;
use std::fs; use std::fs;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::process::Command;
use std::path::Path; use std::path::Path;
use std::process::Command;
use std::thread;
use std::thread::sleep;
use std::time::Duration;
use crate::controller::physical::ControllerState; use crate::controller::physical::ControllerState;
mod dgoc44u; mod dgoc44u;
mod tcpp20009; mod slph00051;
mod tcpp20011;
mod sotp031201_p4b7;
mod sotp031201_p4b2b7; mod sotp031201_p4b2b7;
mod sotp031201_p4b7;
mod sotp031201_p5b5; mod sotp031201_p5b5;
mod sotp031201_p5b7; mod sotp031201_p5b7;
mod vok00106; mod tcpp20009;
mod tcpp20011;
mod zkns001; mod zkns001;
const FFS_MOUNT: &str = "/tmp/ffs"; const FFS_MOUNT: &str = "/tmp/ffs";
@ -33,8 +33,8 @@ pub enum ControllerModel {
SOTP031201P4B2B7, SOTP031201P4B2B7,
SOTP031201P5B5, SOTP031201P5B5,
SOTP031201P5B7, SOTP031201P5B7,
VOK00106,
ZKNS001, ZKNS001,
SLPH00051,
} }
pub struct DeviceDescriptor { pub struct DeviceDescriptor {
@ -55,49 +55,76 @@ pub fn set_model(state: &ControllerState) -> Option<ControllerModel> {
if state.button_right { if state.button_right {
model_name = "DGOC44-U"; model_name = "DGOC44-U";
model = ControllerModel::DGOC44U; model = ControllerModel::DGOC44U;
descriptors = (&dgoc44u::DEVICE_DESCRIPTOR, &dgoc44u::DESCRIPTORS, &dgoc44u::STRINGS); descriptors = (
} &dgoc44u::DEVICE_DESCRIPTOR,
else if state.button_up { &dgoc44u::DESCRIPTORS,
&dgoc44u::STRINGS,
);
} else if state.button_up {
model_name = "ZKNS-001"; model_name = "ZKNS-001";
model = ControllerModel::ZKNS001; model = ControllerModel::ZKNS001;
descriptors = (&zkns001::DEVICE_DESCRIPTOR, &zkns001::DESCRIPTORS, &zkns001::STRINGS); descriptors = (
} &zkns001::DEVICE_DESCRIPTOR,
else if state.button_d { &zkns001::DESCRIPTORS,
&zkns001::STRINGS,
);
} else if state.button_down && state.power == 0 {
model_name = "SLPH-00051";
model = ControllerModel::SLPH00051;
descriptors = (
&slph00051::DEVICE_DESCRIPTOR,
&slph00051::DESCRIPTORS,
&slph00051::STRINGS,
);
} else if state.button_d {
model_name = "TCPP-20009"; model_name = "TCPP-20009";
model = ControllerModel::TCPP20009; model = ControllerModel::TCPP20009;
descriptors = (&tcpp20009::DEVICE_DESCRIPTOR, &tcpp20009::DESCRIPTORS, &tcpp20009::STRINGS); descriptors = (
} &tcpp20009::DEVICE_DESCRIPTOR,
else if state.button_b { &tcpp20009::DESCRIPTORS,
&tcpp20009::STRINGS,
);
} else if state.button_b {
model_name = "TCPP-20011"; model_name = "TCPP-20011";
model = ControllerModel::TCPP20011; model = ControllerModel::TCPP20011;
descriptors = (&tcpp20011::DEVICE_DESCRIPTOR, &tcpp20011::DESCRIPTORS, &tcpp20011::STRINGS); descriptors = (
} &tcpp20011::DEVICE_DESCRIPTOR,
else if state.button_c && state.power == 0 { &tcpp20011::DESCRIPTORS,
&tcpp20011::STRINGS,
);
} else if state.button_c && state.power == 0 {
model_name = "SOTP-031201 (P4/B7 mode)"; model_name = "SOTP-031201 (P4/B7 mode)";
model = ControllerModel::SOTP031201P4B7; model = ControllerModel::SOTP031201P4B7;
descriptors = (&sotp031201_p4b7::DEVICE_DESCRIPTOR, &sotp031201_p4b7::DESCRIPTORS, &sotp031201_p4b7::STRINGS); descriptors = (
} &sotp031201_p4b7::DEVICE_DESCRIPTOR,
else if state.button_c && state.power == 1 { &sotp031201_p4b7::DESCRIPTORS,
&sotp031201_p4b7::STRINGS,
);
} else if state.button_c && state.power == 1 {
model_name = "SOTP-031201 (P4/B2-B7 mode)"; model_name = "SOTP-031201 (P4/B2-B7 mode)";
model = ControllerModel::SOTP031201P4B2B7; model = ControllerModel::SOTP031201P4B2B7;
descriptors = (&sotp031201_p4b2b7::DEVICE_DESCRIPTOR, &sotp031201_p4b2b7::DESCRIPTORS, &sotp031201_p4b2b7::STRINGS); descriptors = (
} &sotp031201_p4b2b7::DEVICE_DESCRIPTOR,
else if state.button_c && state.power == 2 { &sotp031201_p4b2b7::DESCRIPTORS,
&sotp031201_p4b2b7::STRINGS,
);
} else if state.button_c && state.power == 2 {
model_name = "SOTP-031201 (P5/B5 mode)"; model_name = "SOTP-031201 (P5/B5 mode)";
model = ControllerModel::SOTP031201P5B5; model = ControllerModel::SOTP031201P5B5;
descriptors = (&sotp031201_p5b5::DEVICE_DESCRIPTOR, &sotp031201_p5b5::DESCRIPTORS, &sotp031201_p5b5::STRINGS); descriptors = (
} &sotp031201_p5b5::DEVICE_DESCRIPTOR,
/* else if state.button_c && state.power == 3 { &sotp031201_p5b5::DESCRIPTORS,
&sotp031201_p5b5::STRINGS,
);
} else if state.button_c && state.power == 3 {
model_name = "SOTP-031201 (P5/B7 mode)"; model_name = "SOTP-031201 (P5/B7 mode)";
model = ControllerModel::SOTP031201P5B7; model = ControllerModel::SOTP031201P5B7;
descriptors = (&sotp031201_p5b7::DEVICE_DESCRIPTOR, &sotp031201_p5b7::DESCRIPTORS, &sotp031201_p5b7::STRINGS); descriptors = (
} &sotp031201_p5b7::DEVICE_DESCRIPTOR,
else if state.button_a { &sotp031201_p5b7::DESCRIPTORS,
model_name = "VOK-00106"; &sotp031201_p5b7::STRINGS,
model = ControllerModel::VOK00106; );
descriptors = (&vok00106::DEVICE_DESCRIPTOR, &vok00106::DESCRIPTORS, &vok00106::STRINGS); } else {
} */
else {
println!("ddgo-pnp-controller: No controller selected, starting RNDIS gadget."); println!("ddgo-pnp-controller: No controller selected, starting RNDIS gadget.");
Command::new("rndis-gadget.sh").output().ok(); Command::new("rndis-gadget.sh").output().ok();
return None; return None;
@ -130,12 +157,12 @@ pub fn set_state(state: &mut ControllerState, model: &ControllerModel) {
ControllerModel::SOTP031201P5B7 => { ControllerModel::SOTP031201P5B7 => {
sotp031201_p5b7::update_gadget(state); sotp031201_p5b7::update_gadget(state);
} }
ControllerModel::VOK00106 => {
vok00106::update_gadget(state);
}
ControllerModel::ZKNS001 => { ControllerModel::ZKNS001 => {
zkns001::update_gadget(state); zkns001::update_gadget(state);
} }
ControllerModel::SLPH00051 => {
slph00051::update_gadget(state);
}
} }
} }
@ -151,6 +178,9 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) {
ControllerModel::ZKNS001 => { ControllerModel::ZKNS001 => {
report = Some(&zkns001::HID_REPORT_DESCRIPTOR); report = Some(&zkns001::HID_REPORT_DESCRIPTOR);
} }
ControllerModel::SLPH00051 => {
report = Some(&slph00051::HID_REPORT_DESCRIPTOR);
}
_ => { _ => {
report = None; report = None;
} }
@ -163,25 +193,38 @@ pub fn handle_ctrl_transfer(model: ControllerModel, data: &[u8]) {
} }
None => (), None => (),
} }
} } else {
else if data[1] == 9 { match model {
ControllerModel::SLPH00051 => {
slph00051::handle_ctrl_transfer(data);
}
_ => (),
}
} }
} }
fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&DeviceDescriptor, &[u8], &[u8])) { fn init_gadget(
model: &ControllerModel,
(device, descriptors, strings): (&DeviceDescriptor, &[u8], &[u8]),
) {
// Init g_ffs kernel module // Init g_ffs kernel module
Command::new("modprobe").arg("g_ffs") Command::new("modprobe")
.arg(String::from("bDeviceClass=")+&device.b_device_class.to_string()) .arg("g_ffs")
.arg(String::from("bDeviceSubClass=")+&device.b_device_sub_class.to_string()) .arg(String::from("bDeviceClass=") + &device.b_device_class.to_string())
.arg(String::from("idVendor=")+&device.id_vendor.to_string()) .arg(String::from("bDeviceSubClass=") + &device.b_device_sub_class.to_string())
.arg(String::from("idProduct=")+&device.id_product.to_string()) .arg(String::from("idVendor=") + &device.id_vendor.to_string())
.arg(String::from("bcdDevice=")+&device.bcd_device.to_string()) .arg(String::from("idProduct=") + &device.id_product.to_string())
.arg(String::from("iManufacturer=")+device.i_manufacturer) .arg(String::from("bcdDevice=") + &device.bcd_device.to_string())
.arg(String::from("iProduct=")+device.i_product) .arg(String::from("iManufacturer=") + device.i_manufacturer)
.arg(String::from("iSerialNumber=")+device.i_serial_number) .arg(String::from("iProduct=") + device.i_product)
.output().ok(); .arg(String::from("iSerialNumber=") + device.i_serial_number)
Command::new("mkdir").args(["-p",&FFS_MOUNT]).output().ok(); .output()
Command::new("mount").args(["-t","functionfs","ffs",&FFS_MOUNT]).output().ok(); .ok();
Command::new("mkdir").args(["-p", &FFS_MOUNT]).output().ok();
Command::new("mount")
.args(["-t", "functionfs", "ffs", &FFS_MOUNT])
.output()
.ok();
let controller_model = model.clone(); let controller_model = model.clone();
@ -210,14 +253,46 @@ fn init_gadget(model: &ControllerModel, (device, descriptors, strings): (&Device
// Init Android Gadget for old 3.4 kernel // Init Android Gadget for old 3.4 kernel
let gadget = Path::new(&ANDROID_GADGET); let gadget = Path::new(&ANDROID_GADGET);
if gadget.is_dir() { if gadget.is_dir() {
fs::write(gadget.join(Path::new("bDeviceClass")), &device.b_device_class.to_string()).ok(); fs::write(
fs::write(gadget.join(Path::new("bDeviceSubClass")), &device.b_device_sub_class.to_string()).ok(); gadget.join(Path::new("bDeviceClass")),
fs::write(gadget.join(Path::new("idVendor")), format!("{:x}", &device.id_vendor)).ok(); &device.b_device_class.to_string(),
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(); .ok();
fs::write(gadget.join(Path::new("iManufacturer")), &device.i_manufacturer.to_string()).ok(); fs::write(
fs::write(gadget.join(Path::new("iProduct")), &device.i_product.to_string()).ok(); gadget.join(Path::new("bDeviceSubClass")),
fs::write(gadget.join(Path::new("iSerial")), &device.i_serial_number.to_string()).ok(); &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();
fs::write(gadget.join(Path::new("functions")), "ffs").ok(); fs::write(gadget.join(Path::new("functions")), "ffs").ok();
fs::write(gadget.join(Path::new("f_ffs/aliases")), "ffs").ok(); fs::write(gadget.join(Path::new("f_ffs/aliases")), "ffs").ok();
fs::write(gadget.join(Path::new("enable")), "1").ok(); fs::write(gadget.join(Path::new("enable")), "1").ok();

View file

@ -1,53 +1,65 @@
use std::fs::File; use std::fs::File;
use std::io::{Write}; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 66] = [0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 66] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x05, 0x3F, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x05, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00,
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3F, 0x00, 0x00, 0x05,
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 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, bcd_device: 0x0102, 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] = [ pub const HID_REPORT_DESCRIPTOR: [u8; 63] = [
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick) 0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application) 0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer) 0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical) 0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X) 0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y) 0x09, 0x31, // Usage (Y)
0x15, 0x00, // Logical Minimum (0) 0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255) 0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2) 0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection 0xC0, // End Collection
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1) 0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, // Usage Page (Button) 0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01) 0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x06, // Usage Maximum (0x06) 0x29, 0x06, // Usage Maximum (0x06)
0x15, 0x00, // Logical Minimum (0) 0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1) 0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0) 0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1) 0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1) 0x75, 0x01, // Report Size (1)
0x95, 0x06, // Report Count (6) 0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x02, // Report Count (2) 0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2) 0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0 // End Collection 0xC0, // End Collection
]; ];
const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00]; const POWER_NOTCHES: [u8; 6] = [0x81, 0x6D, 0x54, 0x3F, 0x21, 0x00];
@ -76,16 +88,36 @@ pub fn update_gadget(state: &mut ControllerState) {
// Calculate data for buttons // Calculate data for buttons
let mut buttons = Buttons::NONE; let mut buttons = Buttons::NONE;
if state.button_a { buttons.insert(Buttons::A) } if state.button_a {
if state.button_b { buttons.insert(Buttons::B) } buttons.insert(Buttons::A)
if state.button_c { buttons.insert(Buttons::C) } }
if state.button_d { buttons.insert(Buttons::D) } if state.button_b {
if state.button_select { buttons.insert(Buttons::SELECT) } buttons.insert(Buttons::B)
if state.button_start { buttons.insert(Buttons::START) } }
if state.button_up { buttons.insert(Buttons::UP) } if state.button_c {
if state.button_down { buttons.insert(Buttons::DOWN) } buttons.insert(Buttons::C)
if state.button_left { buttons.insert(Buttons::LEFT) } }
if state.button_right { buttons.insert(Buttons::RIGHT) } if state.button_d {
buttons.insert(Buttons::D)
}
if state.button_select {
buttons.insert(Buttons::SELECT)
}
if state.button_start {
buttons.insert(Buttons::START)
}
if state.button_up {
buttons.insert(Buttons::UP)
}
if state.button_down {
buttons.insert(Buttons::DOWN)
}
if state.button_left {
buttons.insert(Buttons::LEFT)
}
if state.button_right {
buttons.insert(Buttons::RIGHT)
}
// Assemble data and send it to gadget // Assemble data and send it to gadget
let data = [brake, power, 0, buttons.bits, 0, 0]; let data = [brake, power, 0, buttons.bits, 0, 0];

View file

@ -0,0 +1,377 @@
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 (PS1 Two Handle mode)",
i_serial_number: "SLPH-00051",
};
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;
// If D is pressed, D-pad mode is active
if !state.button_d {
// Calculate data for handles
buttons1.insert(Buttons1::UP | Buttons1::DOWN);
match state.power {
0 => {
buttons1.insert(Buttons1::LEFT | Buttons1::RIGHT);
}
1 => {
buttons1.insert(Buttons1::RIGHT);
buttons2.insert(Buttons2::TRIANGLE);
}
2 => {
buttons1.insert(Buttons1::RIGHT);
}
3 => {
buttons1.insert(Buttons1::LEFT);
buttons2.insert(Buttons2::TRIANGLE);
}
4 => {
buttons1.insert(Buttons1::LEFT);
}
_ => {
buttons2.insert(Buttons2::TRIANGLE);
}
}
match state.brake {
0 => {
buttons2.insert(Buttons2::L2 | Buttons2::R1 | Buttons2::R2);
}
1 => {
buttons2.insert(Buttons2::L1 | Buttons2::R1 | Buttons2::R2);
}
2 => {
buttons2.insert(Buttons2::R1 | Buttons2::R2);
}
3 => {
buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R2);
}
4 => {
buttons2.insert(Buttons2::L2 | Buttons2::R2);
}
5 => {
buttons2.insert(Buttons2::L1 | Buttons2::R2);
}
6 => {
buttons2.insert(Buttons2::R2);
}
7 => {
buttons2.insert(Buttons2::L1 | Buttons2::L2 | Buttons2::R1);
}
8 => {
buttons2.insert(Buttons2::L2 | Buttons2::R1);
}
_ => (),
}
} else {
// D-pad mode
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)
}
}
// Calculate data for buttons
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_start {
buttons1.insert(Buttons1::START)
}
if state.button_select {
buttons1.insert(Buttons1::SELECT)
}
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();
}
}
}

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0400, 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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x01];
@ -68,16 +79,36 @@ pub fn update_gadget(state: &mut ControllerState) {
state.reverser = 0x40; state.reverser = 0x40;
state.combo = true; state.combo = true;
} }
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if !state.combo && state.button_a {
if state.button_b { buttons1.insert(Buttons1::B) } buttons1.insert(Buttons1::A)
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } }
if state.button_d { buttons1.insert(Buttons1::D) } if state.button_b {
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } buttons1.insert(Buttons1::B)
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_c {
if state.button_right { buttons2.insert(Buttons2::RIGHT) } buttons1.insert(Buttons1::C)
if state.button_start { buttons2.insert(Buttons2::START) } }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } if !state.combo && 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.combo && state.button_select_hold {
buttons2.insert(Buttons2::SELECT)
}
// Assemble data and send it to endpoint // Assemble data and send it to endpoint
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0102, 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: 0x0300,
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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01];
@ -68,16 +79,36 @@ pub fn update_gadget(state: &mut ControllerState) {
state.reverser = 0x40; state.reverser = 0x40;
state.combo = true; state.combo = true;
} }
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if !state.combo && state.button_a {
if state.button_b { buttons1.insert(Buttons1::B) } buttons1.insert(Buttons1::A)
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } }
if state.button_d { buttons1.insert(Buttons1::D) } if state.button_b {
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } buttons1.insert(Buttons1::B)
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_c {
if state.button_right { buttons2.insert(Buttons2::RIGHT) } buttons1.insert(Buttons1::C)
if state.button_start { buttons2.insert(Buttons2::START) } }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } if !state.combo && 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.combo && state.button_select_hold {
buttons2.insert(Buttons2::SELECT)
}
// Assemble data and send it to endpoint // Assemble data and send it to endpoint
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0102, 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: 0x0202,
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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01];
@ -68,16 +79,36 @@ pub fn update_gadget(state: &mut ControllerState) {
state.reverser = 0x10; state.reverser = 0x10;
state.combo = true; state.combo = true;
} }
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if !state.combo && state.button_a {
if state.button_b { buttons1.insert(Buttons1::B) } buttons1.insert(Buttons1::A)
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } }
if state.button_d { buttons1.insert(Buttons1::D) } if state.button_b {
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } buttons1.insert(Buttons1::B)
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_c {
if state.button_right { buttons2.insert(Buttons2::RIGHT) } buttons1.insert(Buttons1::C)
if state.button_start { buttons2.insert(Buttons2::START) } }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } if !state.combo && 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.combo && state.button_select_hold {
buttons2.insert(Buttons2::SELECT)
}
// Assemble data and send it to endpoint // Assemble data and send it to endpoint
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0102, 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: 0x0800,
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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x01];
@ -68,16 +79,36 @@ pub fn update_gadget(state: &mut ControllerState) {
state.reverser = 0x40; state.reverser = 0x40;
state.combo = true; state.combo = true;
} }
if !state.combo && state.button_a { buttons1.insert(Buttons1::A) } if !state.combo && state.button_a {
if state.button_b { buttons1.insert(Buttons1::B) } buttons1.insert(Buttons1::A)
if !state.combo && state.button_c { buttons1.insert(Buttons1::C) } }
if state.button_d { buttons1.insert(Buttons1::D) } if state.button_b {
if !state.combo && state.button_up { buttons2.insert(Buttons2::UP) } buttons1.insert(Buttons1::B)
if !state.combo && state.button_down { buttons2.insert(Buttons2::DOWN) } }
if !state.combo && state.button_left { buttons2.insert(Buttons2::LEFT) } if state.button_c {
if state.button_right { buttons2.insert(Buttons2::RIGHT) } buttons1.insert(Buttons1::C)
if state.button_start { buttons2.insert(Buttons2::START) } }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } if !state.combo && 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.combo && state.button_select_hold {
buttons2.insert(Buttons2::SELECT)
}
// Assemble data and send it to endpoint // Assemble data and send it to endpoint
let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits]; let data = [0x1, state.reverser + handle, buttons1.bits, buttons2.bits];

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0102, 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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x79, 0x8A, 0x94, 0x9A, 0xA2, 0xA8, 0xAF, 0xB2, 0xB5, 0xB9];
@ -36,23 +47,51 @@ pub fn update_gadget(state: &mut ControllerState) {
// Calculate data for buttons // Calculate data for buttons
let mut buttons = Buttons::NONE; let mut buttons = Buttons::NONE;
if state.button_a { buttons.insert(Buttons::A) } if state.button_a {
if state.button_b { buttons.insert(Buttons::B) } buttons.insert(Buttons::A)
if state.button_c { buttons.insert(Buttons::C) } }
if state.button_d { buttons.insert(Buttons::D) } if state.button_b {
if state.button_select { buttons.insert(Buttons::SELECT) } buttons.insert(Buttons::B)
if state.button_start { buttons.insert(Buttons::START) } }
if state.button_c {
buttons.insert(Buttons::C)
}
if state.button_d {
buttons.insert(Buttons::D)
}
if state.button_select {
buttons.insert(Buttons::SELECT)
}
if state.button_start {
buttons.insert(Buttons::START)
}
// Calculate data for D-pad // Calculate data for D-pad
let mut dpad: u8 = 0x8; let mut dpad: u8 = 0x8;
if state.button_up { dpad = 0x0 } if state.button_up {
if state.button_down { dpad = 0x4 } dpad = 0x0
if state.button_left { dpad = 0x6 } }
if state.button_right { dpad = 0x2 } if state.button_down {
if state.button_up & state.button_left { dpad = 0x7 } dpad = 0x4
if state.button_up & state.button_right { dpad = 0x1 } }
if state.button_down & state.button_left { dpad = 0x5 } if state.button_left {
if state.button_down & state.button_right { dpad = 0x3 } 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 endpoint // Assemble data and send it to endpoint
let data = [0x1, brake, power, 0xFF, dpad, buttons.bits]; let data = [0x1, brake, power, 0xFF, dpad, buttons.bits];

View file

@ -1,18 +1,29 @@
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
use crate::controller::physical::ControllerState;
use bitflags::bitflags;
pub const DESCRIPTORS: [u8; 48] = [0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, pub const DESCRIPTORS: [u8; 48] = [
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x14,
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 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, bcd_device: 0x0102, 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 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]; const BRAKE_NOTCHES: [u8; 10] = [0x1C, 0x38, 0x54, 0x70, 0x8B, 0xA7, 0xC3, 0xDF, 0xDF, 0xFB];
@ -36,23 +47,51 @@ pub fn update_gadget(state: &mut ControllerState) {
// Calculate data for buttons // Calculate data for buttons
let mut buttons = Buttons::NONE; let mut buttons = Buttons::NONE;
if state.button_a { buttons.insert(Buttons::A) } if state.button_a {
if state.button_b { buttons.insert(Buttons::B) } buttons.insert(Buttons::A)
if state.button_c { buttons.insert(Buttons::C) } }
if state.button_d { buttons.insert(Buttons::D) } if state.button_b {
if state.button_select { buttons.insert(Buttons::SELECT) } buttons.insert(Buttons::B)
if state.button_start { buttons.insert(Buttons::START) } }
if state.button_c {
buttons.insert(Buttons::C)
}
if state.button_d {
buttons.insert(Buttons::D)
}
if state.button_select {
buttons.insert(Buttons::SELECT)
}
if state.button_start {
buttons.insert(Buttons::START)
}
// Calculate data for D-pad // Calculate data for D-pad
let mut dpad: u8 = 0x8; let mut dpad: u8 = 0x8;
if state.button_up { dpad = 0x0 } if state.button_up {
if state.button_down { dpad = 0x4 } dpad = 0x0
if state.button_left { dpad = 0x6 } }
if state.button_right { dpad = 0x2 } if state.button_down {
if state.button_up & state.button_left { dpad = 0x7 } dpad = 0x4
if state.button_up & state.button_right { dpad = 0x1 } }
if state.button_down & state.button_left { dpad = 0x5 } if state.button_left {
if state.button_down & state.button_right { dpad = 0x3 } 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 endpoint // Assemble data and send it to endpoint
let data = [brake, power, 0xFF, dpad, buttons.bits, 0x0]; let data = [brake, power, 0xFF, dpad, buttons.bits, 0x0];

View file

@ -1,52 +0,0 @@
use std::fs::File;
use std::io::{Write};
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1};
pub const DESCRIPTORS: [u8; 76] = [0x01, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00,
0x07, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00,
0x07, 0x05, 0x02, 0x02, 0x20, 0x00, 0x00,
0x07, 0x05, 0x81, 0x03, 0x08, 0x00, 0x01,
0x09, 0x04, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00,
0x07, 0x05, 0x82, 0x02, 0x20, 0x00, 0x00,
0x07, 0x05, 0x02, 0x02, 0x20, 0x00, 0x00,
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, 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"];
const BRAKE_NOTCHES: [&str; 10] = ["TSA50", "TSA45", "TSA35", "TSA25", "TSA15", "TSA05", "TSE99", "TSB40", "TSB30", "TSB20"];
const BUTTON_A: [&str; 2] = ["TSX00", "TSX99"];
const BUTTON_B: [&str; 2] = ["TSY00", "TSY99"];
const BUTTON_C: [&str; 2] = ["TSZ00", "TSZ99"];
const BUTTON_S: [&str; 2] = ["TSK00", "TSK99"];
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
let button_a = if state.button_a {BUTTON_A[1]} else {BUTTON_A[0]};
let button_b = if state.button_b {BUTTON_B[1]} else {BUTTON_B[0]};
let button_c = if state.button_c {BUTTON_C[1]} else {BUTTON_C[0]};
let button_s = if state.button_d {BUTTON_S[1]} else {BUTTON_S[0]};
if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(handle.as_bytes()).ok();
file.write(&[0xD]).ok();
file.write(button_a.as_bytes()).ok();
file.write(&[0xD]).ok();
file.write(button_b.as_bytes()).ok();
file.write(&[0xD]).ok();
file.write(button_c.as_bytes()).ok();
file.write(&[0xD]).ok();
file.write(button_s.as_bytes()).ok();
file.write(&[0xD]).ok();
}
}

View file

@ -1,68 +1,79 @@
use std::fs::File;
use std::io::{Write};
use bitflags::bitflags;
use crate::controller::physical::ControllerState;
use crate::controller::emulated::{DeviceDescriptor, ENDPOINT1}; use crate::controller::emulated::{DeviceDescriptor, 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, pub const DESCRIPTORS: [u8; 80] = [
0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x5E, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22,
0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x5E, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 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,
0x09, 0x04, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, 0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05,
0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x5E, 0x00, ];
0x07, 0x05, 0x02, 0x03, 0x40, 0x00, 0x05, pub const STRINGS: [u8; 16] = [
0x07, 0x05, 0x81, 0x03, 0x40, 0x00, 0x05]; 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, bcd_device: 0x0106, 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] = [ pub const HID_REPORT_DESCRIPTOR: [u8; 94] = [
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad) 0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application) 0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0) 0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1) 0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0) 0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1) 0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1) 0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14) 0x95, 0x0E, // Report Count (14)
0x05, 0x09, // Usage Page (Button) 0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01) 0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0E, // Usage Maximum (0x0E) 0x29, 0x0E, // Usage Maximum (0x0E)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x02, // Report Count (2) 0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls) 0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x25, 0x07, // Logical Maximum (7) 0x25, 0x07, // Logical Maximum (7)
0x46, 0x3B, 0x01, // Physical Maximum (315) 0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4) 0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1) 0x95, 0x01, // Report Count (1)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter) 0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x09, 0x39, // Usage (Hat switch) 0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State) 0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None) 0x65, 0x00, // Unit (None)
0x95, 0x01, // Report Count (1) 0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x26, 0xFF, 0x00, // Logical Maximum (255) 0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255) 0x46, 0xFF, 0x00, // Physical Maximum (255)
0x09, 0x30, // Usage (X) 0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y) 0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z) 0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz) 0x09, 0x35, // Usage (Rz)
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4) 0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1) 0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x0A, 0x4F, 0x48, // Usage (0x484F) 0x0A, 0x4F, 0x48, // Usage (0x484F)
0x75, 0x08, // Report Size (8) 0x75, 0x08, // Report Size (8)
0x95, 0x08, // Report Count (8) 0x95, 0x08, // Report Count (8)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xB1,
0x0A, 0x4F, 0x48, // Usage (0x484F) 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0x0A, 0x4F, 0x48, // Usage (0x484F)
0xC0, // End Collection 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 POWER_NOTCHES: [u8; 6] = [0x80, 0x9F, 0xB7, 0xCE, 0xE6, 0xFF];
@ -109,27 +120,66 @@ pub fn update_gadget(state: &mut ControllerState) {
buttons2.insert(Buttons2::HOME); buttons2.insert(Buttons2::HOME);
state.combo = true; state.combo = true;
} }
if state.button_a { buttons1.insert(Buttons1::Y) } if state.button_a {
if state.button_b { buttons1.insert(Buttons1::B) } buttons1.insert(Buttons1::Y)
if state.button_c { buttons1.insert(Buttons1::A) } }
if state.button_d { buttons1.insert(Buttons1::X) } if state.button_b {
if state.brake == 9 { buttons1.insert(Buttons1::ZL) } buttons1.insert(Buttons1::B)
if !state.combo && state.button_start { buttons2.insert(Buttons2::START) } }
if !state.combo && state.button_select_hold { buttons2.insert(Buttons2::SELECT) } 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.combo && state.button_start {
buttons2.insert(Buttons2::START)
}
if !state.combo && state.button_select_hold {
buttons2.insert(Buttons2::SELECT)
}
// Calculate data for D-pad // Calculate data for D-pad
let mut dpad: u8 = 0xF; let mut dpad: u8 = 0xF;
if state.button_up { dpad = 0x0 } if state.button_up {
if state.button_down { dpad = 0x4 } dpad = 0x0
if !state.combo && state.button_left { dpad = 0x6 } }
if !state.combo && state.button_right { dpad = 0x2 } if state.button_down {
if !state.combo && state.button_up & state.button_left { dpad = 0x7 } dpad = 0x4
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_left {
if !state.combo && state.button_down & state.button_right { dpad = 0x3 } 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 // Assemble data and send it to gadget
let data = [buttons1.bits, buttons2.bits, dpad, 0x80, handle, 0x80, 0x80, 0x00]; let data = [
buttons1.bits,
buttons2.bits,
dpad,
0x80,
handle,
0x80,
0x80,
0x00,
];
if let Ok(mut file) = File::create(ENDPOINT1) { if let Ok(mut file) = File::create(ENDPOINT1) {
file.write(&data).ok(); file.write(&data).ok();
} }

View file

@ -1,7 +1,7 @@
use std::fs::File; use std::fs::File;
use std::io::Write;
use std::io::Result; use std::io::Result;
use std::time::{Instant,Duration}; use std::io::Write;
use std::time::{Duration, Instant};
use evdev::Device; use evdev::Device;
use evdev::Key; use evdev::Key;
@ -30,9 +30,34 @@ pub struct ControllerState {
const HOLD_DELAY: Duration = Duration::from_millis(750); 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, const USED_KEYS: [Key; 26] = [
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_0,
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]; 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]> { pub fn init() -> Result<[Device; 2]> {
let d1 = Device::open("/dev/input/event1")?; let d1 = Device::open("/dev/input/event1")?;
@ -55,27 +80,90 @@ pub fn get_state(state: &mut ControllerState, dev: &[Device; 2]) {
fn read_input(controller: &mut ControllerState, key: Key, value: bool) { fn read_input(controller: &mut ControllerState, key: Key, value: bool) {
// Save input status to object for processing // Save input status to object for processing
match key { match key {
Key::KEY_0=>if value {controller.power = 0}, Key::KEY_0 => {
Key::KEY_1=>if value {controller.power = 1}, if value {
Key::KEY_2=>if value {controller.power = 2}, controller.power = 0
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_1 => {
Key::KEY_B=>if value {controller.brake = 0}, if value {
Key::KEY_C=>if value {controller.brake = 1}, controller.power = 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_2 => {
Key::KEY_G=>if value {controller.brake = 5}, if value {
Key::KEY_H=>if value {controller.brake = 6}, controller.power = 2
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_3 => {
Key::KEY_SPACE=> { 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 => {
if !controller.button_select && value { if !controller.button_select && value {
controller.button_select_time = Some(Instant::now()); controller.button_select_time = Some(Instant::now());
} } else if !value {
else if !value {
controller.button_select_time = None; controller.button_select_time = None;
controller.combo = false; controller.combo = false;
} }
@ -84,23 +172,23 @@ fn read_input(controller: &mut ControllerState, key: Key, value: bool) {
if let Some(time) = controller.button_select_time { if let Some(time) = controller.button_select_time {
controller.button_select_hold = time.elapsed() > HOLD_DELAY && !controller.combo; controller.button_select_hold = time.elapsed() > HOLD_DELAY && !controller.combo;
} }
}, }
Key::KEY_ENTER=>controller.button_start = value, Key::KEY_ENTER => controller.button_start = value,
Key::KEY_A=>controller.button_a = value, Key::KEY_A => controller.button_a = value,
Key::KEY_Z=>controller.button_b = value, Key::KEY_Z => controller.button_b = value,
Key::KEY_X=>controller.button_c = value, Key::KEY_X => controller.button_c = value,
Key::KEY_S=>controller.button_d = value, Key::KEY_S => controller.button_d = value,
Key::KEY_UP=>controller.button_up = value, Key::KEY_UP => controller.button_up = value,
Key::KEY_DOWN=>controller.button_down = value, Key::KEY_DOWN => controller.button_down = value,
Key::KEY_LEFT=>controller.button_left = value, Key::KEY_LEFT => controller.button_left = value,
Key::KEY_RIGHT=>controller.button_right = value, Key::KEY_RIGHT => controller.button_right = value,
_=>(), _ => (),
} }
} }
pub fn set_lamp(status: bool) { pub fn set_lamp(status: bool) {
if let Ok(mut out) = File::create("/sys/class/leds/led2/brightness") { if let Ok(mut out) = File::create("/sys/class/leds/led2/brightness") {
out.write(if status {b"1"} else {b"0"}).ok(); out.write(if status { b"1" } else { b"0" }).ok();
} }
/*else { /*else {
println!("WARNING: Could not set door lamp status!") println!("WARNING: Could not set door lamp status!")
@ -109,7 +197,7 @@ pub fn set_lamp(status: bool) {
pub fn set_rumble(status: bool) { pub fn set_rumble(status: bool) {
if let Ok(mut out) = File::create("/sys/class/leds/led1/brightness") { if let Ok(mut out) = File::create("/sys/class/leds/led1/brightness") {
out.write(if status {b"1"} else {b"0"}).ok(); out.write(if status { b"1" } else { b"0" }).ok();
} }
/*else { /*else {
println!("WARNING: Could not set rumble motor status!") println!("WARNING: Could not set rumble motor status!")

View file

@ -2,10 +2,10 @@ mod controller;
use std::io::Result; use std::io::Result;
use std::process::Command; use std::process::Command;
use std::time::Duration;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration;
use controller::physical::{set_lamp,set_rumble}; use controller::physical::{set_lamp, set_rumble};
fn main() -> Result<()> { fn main() -> Result<()> {
match controller::physical::init() { match controller::physical::init() {
@ -18,7 +18,6 @@ fn main() -> Result<()> {
// Check selected controller model // Check selected controller model
if let Some(controller_model) = controller::emulated::set_model(&controller_state) { if let Some(controller_model) = controller::emulated::set_model(&controller_state) {
// Stop main game // Stop main game
stop_game(); stop_game();
@ -43,12 +42,15 @@ fn main() -> Result<()> {
} }
} }
return Result::Ok(()); return Result::Ok(());
}, }
Err(_e) => println!("ddgo-pnp-controller: ERROR: Could not read input devices! Exiting."), Err(_e) => println!("ddgo-pnp-controller: ERROR: Could not read input devices! Exiting."),
} }
Ok(()) Ok(())
} }
fn stop_game() { fn stop_game() {
Command::new("/etc/init.d/S99dgtype3").arg("stop").output().ok(); Command::new("/etc/init.d/S99dgtype3")
.arg("stop")
.output()
.ok();
} }