Skip to content

Commit

Permalink
WIP: dualsense
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Apr 9, 2024
1 parent 6fd65d4 commit 0f0d4be
Show file tree
Hide file tree
Showing 7 changed files with 1,035 additions and 239 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@
"keyboard",
"gamepad",
"xb360",
"deck"
"deck",
"ds5",
"ds5-usb",
"ds5-bt",
"ds5-edge",
"ds5-edge-usb",
"ds5-edge-bt"
]
}
}
Expand Down
20 changes: 14 additions & 6 deletions src/drivers/dualsense/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,33 @@ pub const DS5_VERSION: u16 = 0x8111;
pub const DS5_VID: u16 = 0x054C;
pub const DS5_PID: u16 = 0x0ce6;

pub const FEATURE_REPORT_PAIRING_IFO: u8 = 0x09;
pub const FEATURE_REPORT_PAIRING_INFO: u8 = 0x09;
pub const FEATURE_REPORT_PAIRING_INFO_SIZE: u8 = 20;
pub const FEATURE_REPORT_FIRMWARE_INFO: u8 = 0x20;
pub const FEATURE_REPORT_FIRMWARE_INFO_SIZE: u8 = 64;
pub const FEATURE_REPORT_CALIBRATION: u8 = 0x05;
pub const FEATURE_REPORT_CALIBRATION_SIZE: u8 = 41;

pub const INPUT_REPORT_USB: u8 = 0x01;
pub const INPUT_REPORT_USB_SIZE: u8 = 64;
pub const INPUT_REPORT_USB_SIZE: usize = 64;
pub const INPUT_REPORT_BT: u8 = 0x31;
pub const INPUT_REPORT_BT_SIZE: u8 = 78;
pub const INPUT_REPORT_BT_SIZE: usize = 78;
pub const OUTPUT_REPORT_USB: u8 = 0x02;
pub const OUTPUT_REPORT_USB_SIZE: u8 = 63;
pub const OUTPUT_REPORT_USB_SIZE: usize = 63;
pub const OUTPUT_REPORT_BT: u8 = 0x31;
pub const OUTPUT_REPORT_BT_SIZE: u8 = 78;
pub const OUTPUT_REPORT_BT_SIZE: usize = 78;

pub const OUTPUT_VALID_FLAG0_HAPTICS_SELECT: u8 = 0x02;
pub const OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2: u8 = 0x04;
pub const OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION: u8 = 0x01;
pub const OUTPUT_VALID_FLAG1_LIGHTBAR_CONTROL_ENABLE: u8 = 0x04;

//#define DS5_SPEC_DELTA_TIME 4096.0f
// Input report axis ranges
pub const STICK_X_MIN: f64 = u8::MIN as f64;
pub const STICK_X_MAX: f64 = u8::MAX as f64;
pub const STICK_Y_MIN: f64 = u8::MIN as f64;
pub const STICK_Y_MAX: f64 = u8::MAX as f64;
pub const TRIGGER_MAX: f64 = u8::MAX as f64;

//#define DS5_SPEC_DELTA_TIME 4096.0f

239 changes: 218 additions & 21 deletions src/drivers/dualsense/hid_report.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,247 @@
use packed_struct::{prelude::*, types::SizedInteger, PackedStruct};
use packed_struct::prelude::*;

use super::driver::*;

pub trait PackedInputDataReport: PackedStruct + Copy + Clone + PartialEq
{
fn new() -> Self;
#[derive(Debug, Copy, Clone)]
pub enum PackedInputDataReport {
Usb(USBPackedInputDataReport),
Bluetooth(BluetoothPackedInputDataReport),
}

fn set_frame_number(&mut self, num: u8);
}
impl PackedInputDataReport {
pub fn set_frame_number(&mut self, num: u8) {
match self {
PackedInputDataReport::Usb(_) => (),
PackedInputDataReport::Bluetooth(_) => (),
}
}
}

// https://github.com/nondebug/dualsense
#[derive(PackedStruct, Debug, Copy, Clone, PartialEq)]
#[packed_struct(bit_numbering = "msb0", size_bytes = "64")]
pub struct USBPackedInputDataReport {
// byte 0
#[packed_field(bytes = "0")]
pub input_report: u8,
pub report_id: u8, // Report ID (always 0x01)

// byte 1-7
#[packed_field(bytes = "1")]
pub joystick_l_x: u8,
pub joystick_l_x: u8, // left stick X axis
#[packed_field(bytes = "2")]
pub joystick_l_y: u8,
pub joystick_l_y: u8, // left stick Y axis
#[packed_field(bytes = "3")]
pub joystick_r_x: u8,
pub joystick_r_x: u8, // right stick X axis
#[packed_field(bytes = "4")]
pub joystick_r_y: u8,
pub joystick_r_y: u8, // right stick Y axis
#[packed_field(bytes = "5")]
pub l2_trigger: u8, // L2 trigger axis
#[packed_field(bytes = "6")]
pub r2_trigger: u8, // R2 trigger axis
#[packed_field(bytes = "7")]
pub _vendor_defined_0: u8, // Vendor defined

// byte 8
#[packed_field(bits = "64")]
pub down: bool, // Directional buttons
#[packed_field(bits = "65")]
pub left: bool,
#[packed_field(bits = "66")]
pub right: bool,
#[packed_field(bits = "67")]
pub up: bool,
#[packed_field(bits = "68")]
pub square: bool, // Button cluster, x, ◯, □, ∆
#[packed_field(bits = "69")]
pub cross: bool,
#[packed_field(bits = "70")]
pub circle: bool,
#[packed_field(bits = "71")]
pub triangle: bool,

// byte 9
#[packed_field(bits = "72")]
pub l1: bool, // Triggers
#[packed_field(bits = "73")]
pub r1: bool,
#[packed_field(bits = "74")]
pub l2: bool,
#[packed_field(bits = "75")]
pub r2: bool,
#[packed_field(bits = "76")]
pub create: bool, // Create button ⚟
#[packed_field(bits = "77")]
pub options: bool, // Options button ☰
#[packed_field(bits = "78")]
pub l3: bool,
#[packed_field(bits = "79")]
pub r3: bool,

// byte 10
#[packed_field(bits = "80")]
pub ps: bool, // PS button
#[packed_field(bits = "81")]
pub touchpad: bool, // Touchpad button
#[packed_field(bits = "82")]
pub mute: bool, // Mute button 🔇
#[packed_field(bits = "83..=95")]
pub _vendor_defined_1: [u8; 13],

// byte 12-64
#[packed_field(bytes = "12..=64")]
pub _vendor_defined_2: [u8; 52],
}

impl PackedInputDataReport for USBPackedInputDataReport {
impl USBPackedInputDataReport {
/// Return a new empty input data report
fn new() -> Self {
pub fn new() -> Self {
Self {
input_report: INPUT_REPORT_USB,
joystick_l_x : 127,
joystick_l_y : 127,
joystick_r_x : 127,
joystick_r_y : 127,
report_id: INPUT_REPORT_USB,
joystick_l_x: 127,
joystick_l_y: 127,
joystick_r_x: 127,
joystick_r_y: 127,
l2_trigger: 0,
r2_trigger: 0,
_vendor_defined_0: 0,
down: false,
left: false,
right: false,
up: false,
square: false,
cross: false,
circle: false,
triangle: false,
l1: false,
r1: false,
l2: false,
r2: false,
create: false,
options: false,
l3: false,
r3: false,
ps: false,
touchpad: false,
mute: false,
_vendor_defined_1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
_vendor_defined_2: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
}
}
}

impl Default for USBPackedInputDataReport {
fn default() -> Self {
Self::new()
}
}

fn set_frame_number(&mut self, num: u8) {
#[derive(PackedStruct, Debug, Copy, Clone, PartialEq)]
#[packed_struct(bit_numbering = "msb0", size_bytes = "10")]
pub struct BluetoothPackedInputDataReport {
// byte 0
#[packed_field(bytes = "0")]
pub report_id: u8, // Report ID (always 0x01)

// byte 1-4
#[packed_field(bytes = "1")]
pub joystick_l_x: u8, // left stick X axis
#[packed_field(bytes = "2")]
pub joystick_l_y: u8, // left stick Y axis
#[packed_field(bytes = "3")]
pub joystick_r_x: u8, // right stick X axis
#[packed_field(bytes = "4")]
pub joystick_r_y: u8, // right stick Y axis

// byte 5
#[packed_field(bits = "40")]
pub down: bool, // Directional buttons
#[packed_field(bits = "41")]
pub left: bool,
#[packed_field(bits = "42")]
pub right: bool,
#[packed_field(bits = "43")]
pub up: bool,
#[packed_field(bits = "44")]
pub square: bool, // Button cluster, x, ◯, □, ∆
#[packed_field(bits = "45")]
pub cross: bool,
#[packed_field(bits = "46")]
pub circle: bool,
#[packed_field(bits = "47")]
pub triangle: bool,

// byte 6
#[packed_field(bits = "48")]
pub l1: bool, // Triggers
#[packed_field(bits = "49")]
pub r1: bool,
#[packed_field(bits = "50")]
pub l2: bool,
#[packed_field(bits = "51")]
pub r2: bool,
#[packed_field(bits = "52")]
pub create: bool, // Create button ⚟
#[packed_field(bits = "53")]
pub options: bool, // Options button ☰
#[packed_field(bits = "54")]
pub l3: bool,
#[packed_field(bits = "55")]
pub r3: bool,

// byte 7
#[packed_field(bits = "56")]
pub ps: bool, // PS button
#[packed_field(bits = "57")]
pub touchpad: bool, // Touchpad button
#[packed_field(bits = "58..=63")]
pub _vendor_defined_0: [u8; 6],

// byte 8-9
#[packed_field(bytes = "8")]
pub l2_trigger: u8, // L2 trigger axis
#[packed_field(bytes = "9")]
pub r2_trigger: u8, // R2 trigger axis
}

impl BluetoothPackedInputDataReport {
/// Return a new empty input data report
pub fn new() -> Self {
Self {
report_id: INPUT_REPORT_BT,
joystick_l_x: 127,
joystick_l_y: 127,
joystick_r_x: 127,
joystick_r_y: 127,
l2_trigger: 0,
r2_trigger: 0,
_vendor_defined_0: [0, 0, 0, 0, 0, 0],
down: false,
left: false,
right: false,
up: false,
square: false,
cross: false,
circle: false,
triangle: false,
l1: false,
r1: false,
l2: false,
r2: false,
create: false,
options: false,
l3: false,
r3: false,
ps: false,
touchpad: false,
}
}
}

impl Default for USBPackedInputDataReport {
impl Default for BluetoothPackedInputDataReport {
fn default() -> Self {
Self::new()
}
}
}
2 changes: 1 addition & 1 deletion src/drivers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod bmi_imu;
pub mod dualsense;
pub mod lego;
pub mod steam_deck;
pub mod dualsense;
37 changes: 37 additions & 0 deletions src/input/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ use crate::input::composite_device::CompositeDevice;
use crate::input::source;
use crate::input::source::hidraw;
use crate::input::target::dbus::DBusDevice;
use crate::input::target::dualsense;
use crate::input::target::dualsense::DualSenseDevice;
use crate::input::target::dualsense::DualSenseHardware;
use crate::input::target::gamepad::GenericGamepad;
use crate::input::target::keyboard::KeyboardDevice;
use crate::input::target::mouse::MouseDevice;
Expand Down Expand Up @@ -301,6 +304,27 @@ impl Manager {
let device = match kind {
"gamepad" => TargetDeviceType::GenericGamepad(GenericGamepad::new(self.dbus.clone())),
"deck" => TargetDeviceType::SteamDeck(SteamDeckDevice::new(self.dbus.clone())),
"ds5" | "ds5-usb" | "ds5-bt" | "ds5-edge" | "ds5-edge-usb" | "ds5-edge-bt" => {
let hw = match kind {
"ds5" | "ds5-usb" => DualSenseHardware::new(
dualsense::ModelType::Normal,
dualsense::BusType::Usb,
),
"ds5-bt" => DualSenseHardware::new(
dualsense::ModelType::Normal,
dualsense::BusType::Bluetooth,
),
"ds5-edge" | "ds5-edge-usb" => {
DualSenseHardware::new(dualsense::ModelType::Edge, dualsense::BusType::Usb)
}
"ds5-edge-bt" => DualSenseHardware::new(
dualsense::ModelType::Edge,
dualsense::BusType::Bluetooth,
),
_ => DualSenseHardware::default(),
};
TargetDeviceType::DualSense(DualSenseDevice::new(self.dbus.clone(), hw))
}
"xb360" => TargetDeviceType::XBox360(XBox360Controller::new()),
"dbus" => TargetDeviceType::DBus(DBusDevice::new(self.dbus.clone())),
"mouse" => TargetDeviceType::Mouse(MouseDevice::new(self.dbus.clone())),
Expand Down Expand Up @@ -386,6 +410,19 @@ impl Manager {
log::debug!("Target steam deck device closed");
});
}
TargetDeviceType::DualSense(mut device) => {
let path = self.next_target_path("gamepad")?;
let event_tx = device.transmitter();
target_devices.insert(path.clone(), event_tx.clone());
self.target_devices.insert(path.clone(), event_tx.clone());
device.listen_on_dbus(path).await?;
tokio::spawn(async move {
if let Err(e) = device.run().await {
log::error!("Failed to run target dualsense device: {:?}", e);
}
log::debug!("Target dualsense device closed");
});
}
TargetDeviceType::XBox360(_) => todo!(),
}
}
Expand Down
Loading

0 comments on commit 0f0d4be

Please sign in to comment.