use bitflags::bitflags;
use std::{
mem,
ops::{Deref, DerefMut},
};
bitflags! {
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Ds4Button: u16 {
const THUMB_RIGHT = 1 << 15;
const THUMB_LEFT = 1 << 14;
const OPTIONS = 1 << 13;
const SHARE = 1 << 12;
const TRIGGER_RIGHT = 1 << 11;
const TRIGGER_LEFT = 1 << 10;
const SHOULDER_RIGHT = 1 << 9;
const SHOULDER_LEFT = 1 << 8;
const TRIANGLE = 1 << 7;
const CIRCLE = 1 << 6;
const CROSS = 1 << 5;
const SQUARE = 1 << 4;
}
}
bitflags! {
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Ds4SpecialButton: u8 {
const PS = 1 << 0;
const TOUCHPAD = 1 << 1;
}
}
#[repr(u8)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Ds4Dpad {
North = 0,
NorthEast = 1,
East = 2,
SouthEast = 3,
South = 4,
SouthWest = 5,
West = 6,
NorthWest = 7,
#[default]
Neutral = 8,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Ds4Report {
pub thumb_lx: u8,
pub thumb_ly: u8,
pub thumb_rx: u8,
pub thumb_ry: u8,
pub buttons: u16,
pub special: u8,
pub trigger_l: u8,
pub trigger_r: u8,
}
impl Ds4Report {
#[inline]
pub fn set_dpad(&mut self, dpad: Ds4Dpad) {
const DPAD_MASK: u16 = 0x000F;
self.buttons = (self.buttons & !DPAD_MASK) | (dpad as u16);
}
}
impl Default for Ds4Report {
fn default() -> Self {
let mut report = Self {
thumb_lx: 128,
thumb_ly: 128,
thumb_rx: 128,
thumb_ry: 128,
buttons: 0,
special: 0,
trigger_l: 0,
trigger_r: 0,
};
report.set_dpad(Ds4Dpad::Neutral);
report
}
}
#[repr(C, packed)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Ds4Touch {
pub packet_counter: u8,
pub is_up_tracking_num_1: u8,
pub touch_data_1: [u8; 3],
pub is_up_tracking_num_2: u8,
pub touch_data_2: [u8; 3],
}
impl Ds4Touch {
#[inline]
fn pack_coords(buf: &mut [u8; 3], x: u16, y: u16) {
let x = x.min(1919);
let y = y.min(942);
buf[0] = (x & 0xFF) as u8;
buf[1] = (((x >> 8) & 0x0F) | ((y & 0x0F) << 4)) as u8;
buf[2] = ((y >> 4) & 0xFF) as u8;
}
#[inline]
fn unpack_coords(buf: &[u8; 3]) -> (u16, u16) {
let x = (buf[0] as u16) | (((buf[1] & 0x0F) as u16) << 8);
let y = (((buf[1] & 0xF0) as u16) >> 4) | ((buf[2] as u16) << 4);
(x, y)
}
#[inline]
pub fn set_touch_1(&mut self, is_down: bool, tracking_num: u8, x: u16, y: u16) {
let up_bit = if is_down { 0 } else { 1 << 7 };
self.is_up_tracking_num_1 = up_bit | (tracking_num & 0x7F);
Self::pack_coords(&mut self.touch_data_1, x, y);
}
#[inline]
pub fn set_touch_2(&mut self, is_down: bool, tracking_num: u8, x: u16, y: u16) {
let up_bit = if is_down { 0 } else { 1 << 7 };
self.is_up_tracking_num_2 = up_bit | (tracking_num & 0x7F);
Self::pack_coords(&mut self.touch_data_2, x, y);
}
#[inline]
pub fn get_packet_counter(&self) -> u8 {
self.packet_counter
}
#[inline]
pub fn get_is_down_1(&self) -> bool {
(self.is_up_tracking_num_1 & 0x80) == 0
}
#[inline]
pub fn get_tracking_num_1(&self) -> u8 {
self.is_up_tracking_num_1 & 0x7F
}
#[inline]
pub fn get_coords_1(&self) -> (u16, u16) {
Self::unpack_coords(&self.touch_data_1)
}
#[inline]
pub fn get_is_down_2(&self) -> bool {
(self.is_up_tracking_num_2 & 0x80) == 0
}
#[inline]
pub fn get_tracking_num_2(&self) -> u8 {
self.is_up_tracking_num_2 & 0x7F
}
#[inline]
pub fn get_coords_2(&self) -> (u16, u16) {
Self::unpack_coords(&self.touch_data_2)
}
}
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct Ds4ReportExData {
pub thumb_lx: u8,
pub thumb_ly: u8,
pub thumb_rx: u8,
pub thumb_ry: u8,
pub buttons: u16,
pub special: u8,
pub trigger_l: u8,
pub trigger_r: u8,
pub timestamp: u16,
pub battery_lvl: u8,
pub gyro_x: i16,
pub gyro_y: i16,
pub gyro_z: i16,
pub accel_x: i16,
pub accel_y: i16,
pub accel_z: i16,
pub _unknown1: [u8; 5],
pub battery_lvl_special: u8,
pub _unknown2: [u8; 2],
pub touch_packets_n: u8,
pub current_touch: Ds4Touch,
pub previous_touch: [Ds4Touch; 2],
}
impl Ds4ReportExData {
#[inline]
pub fn as_report(&self) -> &Ds4Report {
unsafe { &*(self as *const _ as *const Ds4Report) }
}
#[inline]
pub fn as_report_mut(&mut self) -> &mut Ds4Report {
unsafe { &mut *(self as *mut _ as *mut Ds4Report) }
}
pub fn set_dpad(&mut self, dpad: Ds4Dpad) {
self.as_report_mut().set_dpad(dpad);
}
}
impl Default for Ds4ReportExData {
fn default() -> Self {
let mut report: Self = unsafe { mem::zeroed() };
let base = Ds4Report::default();
report.thumb_lx = base.thumb_lx;
report.thumb_ly = base.thumb_ly;
report.thumb_rx = base.thumb_rx;
report.thumb_ry = base.thumb_ry;
report.buttons = base.buttons;
report.special = base.special;
report.trigger_l = base.trigger_l;
report.trigger_r = base.trigger_r;
report
}
}
#[repr(C, packed)]
pub union Ds4ReportEx {
pub report: Ds4ReportExData,
pub report_buffer: [u8; 63],
}
impl Deref for Ds4ReportEx {
type Target = Ds4ReportExData;
fn deref(&self) -> &Self::Target {
unsafe { &self.report }
}
}
impl DerefMut for Ds4ReportEx {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut self.report }
}
}
impl Clone for Ds4ReportEx {
fn clone(&self) -> Self {
*self
}
}
impl Copy for Ds4ReportEx {}
impl Default for Ds4ReportEx {
fn default() -> Self {
Self {
report: Ds4ReportExData::default(),
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub(crate) struct Ds4SubmitReport {
pub size: u32,
pub serial_no: u32,
pub report: Ds4Report,
}
#[repr(C, packed)]
#[derive(Clone, Copy, Default)]
pub(crate) struct Ds4SubmitReportEx {
pub size: u32,
pub serial_no: u32,
pub report: Ds4ReportEx,
}
const _: () = {
assert!(
mem::size_of::<Ds4ReportExData>() == 60,
"Ds4ReportExData must be 60 bytes!"
);
assert!(
mem::size_of::<Ds4ReportEx>() == 63,
"Ds4ReportEx union must be 63 bytes!"
);
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Ds4LightbarColor {
pub red: u8,
pub green: u8,
pub blue: u8,
}
impl Ds4LightbarColor {
#[inline]
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self {
red: r,
green: g,
blue: b,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Ds4Notification {
pub large_motor: u8,
pub small_motor: u8,
pub lightbar: Ds4LightbarColor,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Ds4OutputBuffer {
pub buf: [u8; 64],
}