use std::{fmt, mem, ptr};
use std::borrow::Borrow;
use crate::*;
#[cfg(feature = "unstable_ds4")]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(C)]
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,
}
#[cfg(feature = "unstable_ds4")]
impl Default for DS4Report {
#[inline]
fn default() -> Self {
DS4Report {
thumb_lx: 0x80,
thumb_ly: 0x80,
thumb_rx: 0x80,
thumb_ry: 0x80,
buttons: 0x8,
special: 0,
trigger_l: 0,
trigger_r: 0,
}
}
}
pub struct DualShock4Wired<CL: Borrow<Client>> {
client: CL,
event: Event,
serial_no: u32,
id: TargetId,
}
impl<CL: Borrow<Client>> DualShock4Wired<CL> {
#[inline]
pub fn new(client: CL, id: TargetId) -> DualShock4Wired<CL> {
let event = Event::new(false, false);
DualShock4Wired { client, event, serial_no: 0, id }
}
#[inline]
pub fn is_attached(&self) -> bool {
self.serial_no != 0
}
#[inline]
pub fn id(&self) -> TargetId {
self.id
}
#[inline]
pub fn client(&self) -> &CL {
&self.client
}
#[inline]
pub fn drop(mut self) -> CL {
let _ = self.unplug();
unsafe {
let client = (&self.client as *const CL).read();
ptr::drop_in_place(&mut self.event);
mem::forget(self);
client
}
}
#[inline(never)]
pub fn plugin(&mut self) -> Result<(), Error> {
if self.is_attached() {
return Err(Error::AlreadyConnected);
}
self.serial_no = unsafe {
let mut plugin = bus::PluginTarget::ds4_wired(1, self.id.vendor, self.id.product);
let device = self.client.borrow().device;
while plugin.ioctl(device, self.event.handle).is_err() {
plugin.SerialNo += 1;
if plugin.SerialNo >= u16::MAX as u32 {
return Err(Error::NoFreeSlot);
}
}
plugin.SerialNo
};
Ok(())
}
#[inline(never)]
pub fn unplug(&mut self) -> Result<(), Error> {
if !self.is_attached() {
return Err(Error::NotPluggedIn);
}
unsafe {
let mut unplug = bus::UnplugTarget::new(self.serial_no);
let device = self.client.borrow().device;
unplug.ioctl(device, self.event.handle)?;
}
self.serial_no = 0;
Ok(())
}
#[inline(never)]
pub fn wait_ready(&mut self) -> Result<(), Error> {
if !self.is_attached() {
return Err(Error::NotPluggedIn);
}
unsafe {
let mut wait = bus::WaitDeviceReady::new(self.serial_no);
let device = self.client.borrow().device;
wait.ioctl(device, self.event.handle)?;
}
Ok(())
}
#[cfg(feature = "unstable_ds4")]
#[inline(never)]
pub fn update(&mut self, report: &DS4Report) -> Result<(), Error> {
if !self.is_attached() {
return Err(Error::NotPluggedIn);
}
unsafe {
let mut dsr = bus::DS4SubmitReport::new(self.serial_no, *report);
let device = self.client.borrow().device;
dsr.ioctl(device, self.event.handle)?;
}
Ok(())
}
}
impl<CL: Borrow<Client>> fmt::Debug for DualShock4Wired<CL> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("DualShock4Wired")
.field("serial_no", &self.serial_no)
.field("vendor_id", &self.id.vendor)
.field("product_id", &self.id.product)
.finish()
}
}
impl<CL: Borrow<Client>> Drop for DualShock4Wired<CL> {
#[inline]
fn drop(&mut self) {
let _ = self.unplug();
}
}