55
66import ctypes
77import logging
8+ import os
89import sys
910from typing import TYPE_CHECKING
1011
12+ from usb1 import USBDeviceHandle
13+
1114from scc .constants import STICK_PAD_MAX , STICK_PAD_MIN , ControllerFlags , SCButtons
15+ from scc .controller import Controller
1216from scc .drivers .evdevdrv import (
1317 HAVE_EVDEV ,
1418 EvdevController ,
2832 HIDController ,
2933 HIDDecoder ,
3034 _lib ,
35+ button_to_bit ,
3136 hiddrv_test ,
3237)
33- from scc .drivers .usb import register_hotplug_device
38+ from scc .drivers .usb import USBDevice , register_hotplug_device
39+ from scc .lib .hidraw import HIDRaw
3440from scc .tools import init_logging , set_logging_level
3541
3642if TYPE_CHECKING :
4551DS4_V1_PRODUCT_ID = 0x05C4
4652
4753
48- class DS4Controller (HIDController ):
54+ class DS4Controller (Controller ):
4955 # Most of axes are the same
5056 BUTTON_MAP = (
5157 SCButtons .X ,
@@ -73,6 +79,11 @@ class DS4Controller(HIDController):
7379 )
7480
7581
82+ def __init__ (self , daemon : "SCCDaemon" ) -> None :
83+ self .daemon = daemon
84+ Controller .__init__ (self )
85+
86+
7687 def _load_hid_descriptor (self , config , max_size , vid , pid , test_mode ):
7788 # Overrided and hardcoded
7889 self ._decoder = HIDDecoder ()
@@ -143,9 +154,8 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode):
143154 for x in range (BUTTON_COUNT ):
144155 self ._decoder .buttons .button_map [x ] = 64
145156 for x , sc in enumerate (DS4Controller .BUTTON_MAP ):
146- self ._decoder .buttons .button_map [x ] = self . button_to_bit (sc )
157+ self ._decoder .buttons .button_map [x ] = button_to_bit (sc )
147158
148- self ._packet_size = 64
149159
150160# TODO: Which commit made data switch from bytes to bytearray?
151161 def input (self , endpoint : int , data : bytearray ) -> None :
@@ -192,6 +202,82 @@ def _generate_id(self) -> str:
192202 return id
193203
194204
205+ class DS4HIDController (DS4Controller , HIDController ):
206+ def __init__ (self , device : "USBDevice" , daemon : "SCCDaemon" , handle : "USBDeviceHandle" , config_file , config , test_mode = False ):
207+ DS4Controller .__init__ (self , daemon )
208+ HIDController .__init__ (self , device , daemon , handle , config_file , config , test_mode )
209+
210+
211+ class DS4HIDRawController (DS4Controller , Controller ):
212+ def __init__ (self , driver : "DS4HIDRawDriver" , syspath , hidrawdev : "HIDRaw" , vid , pid ) -> None :
213+ self .driver = driver
214+ self .syspath = syspath
215+
216+ DS4Controller .__init__ (self , driver .daemon )
217+
218+ self ._device_name = hidrawdev .getName ()
219+ self ._hidrawdev = hidrawdev
220+ self ._fileno = hidrawdev ._device .fileno ()
221+ self ._id = self ._generate_id () if driver else "-"
222+
223+ self ._packet_size = 78
224+ self ._load_hid_descriptor (driver .config , self ._packet_size , vid , pid , None )
225+
226+ # self._set_operational()
227+ self .read_serial ()
228+ self ._poller = self .daemon .get_poller ()
229+ if self ._poller :
230+ self ._poller .register (self ._fileno , self ._poller .POLLIN , self ._input )
231+ # self.daemon.get_device_monitor().add_remove_callback(syspath, self.close)
232+ self .daemon .add_controller (self )
233+
234+ def read_serial (self ):
235+ self ._serial = (self ._hidrawdev
236+ .getPhysicalAddress ().replace (b":" , b"" ))
237+
238+ def _input (self , * args ):
239+ data = self ._hidrawdev .read (self ._packet_size )
240+ if data [0 ] != 0x11 :
241+ return
242+ self .input (self ._fileno , data [2 :])
243+
244+ def close (self ):
245+ if self ._poller :
246+ self ._poller .unregister (self ._fileno )
247+
248+ self .daemon .remove_controller (self )
249+ self ._hidrawdev ._device .close ()
250+
251+
252+ class DS4HIDRawDriver :
253+ def __init__ (self , daemon : "SCCDaemon" , config : dict ):
254+ self .config = config
255+ self .daemon = daemon
256+ daemon .get_device_monitor ().add_callback ("bluetooth" , VENDOR_ID , PRODUCT_ID , self .make_bt_hidraw_callback , None )
257+ daemon .get_device_monitor ().add_callback ("bluetooth" , VENDOR_ID , DS4_V1_PRODUCT_ID , self .make_bt_hidraw_callback , None )
258+
259+ def retry (self , syspath : str ):
260+ pass
261+
262+ def make_bt_hidraw_callback (self , syspath : str , vid , pid , * whatever ):
263+ hidrawname = self .daemon .get_device_monitor ().get_hidraw (syspath )
264+ if hidrawname is None :
265+ return None
266+ try :
267+ dev = HIDRaw (open (os .path .join ("/dev/" , hidrawname ), "w+b" ))
268+ return DS4HIDRawController (self , syspath , dev , vid , pid )
269+ except Exception as e :
270+ log .exception (e )
271+ return None
272+
273+ def get_device_name (self ):
274+ return "Dualshock 4 over Bluetooth HIDRaw"
275+
276+ def get_type (self ):
277+ return "ds4bt_hidraw"
278+
279+
280+
195281class DS4EvdevController (EvdevController ):
196282 TOUCH_FACTOR_X = STICK_PAD_MAX / 940.0
197283 TOUCH_FACTOR_Y = STICK_PAD_MAX / 470.0
@@ -381,8 +467,8 @@ def _generate_id(self) -> str:
381467def init (daemon : "SCCDaemon" , config : dict ) -> bool :
382468 """Register hotplug callback for DS4 device."""
383469
384- def hid_callback (device , handle ) -> DS4Controller :
385- return DS4Controller (device , daemon , handle , None , None )
470+ def hid_callback (device , handle ) -> DS4HIDController :
471+ return DS4HIDController (device , daemon , handle , None , None )
386472
387473 def make_evdev_device (sys_dev_path : str , * whatever ):
388474 devices = get_evdev_devices_from_syspath (sys_dev_path )
@@ -435,7 +521,10 @@ def fail_cb(syspath: str, vid: int, pid: int) -> None:
435521 register_hotplug_device (hid_callback , VENDOR_ID , PRODUCT_ID , on_failure = fail_cb )
436522 # DS4 v.1
437523 register_hotplug_device (hid_callback , VENDOR_ID , DS4_V1_PRODUCT_ID , on_failure = fail_cb )
438- if HAVE_EVDEV and config ["drivers" ].get ("evdevdrv" ):
524+ if config ["drivers" ].get ("hiddrv" ):
525+ # Only enable HIDRaw support for BT connections if hiddrv is enabled
526+ _drv = DS4HIDRawDriver (daemon , config )
527+ elif HAVE_EVDEV and config ["drivers" ].get ("evdevdrv" ):
439528 # DS4 v.2
440529 daemon .get_device_monitor ().add_callback ("bluetooth" , VENDOR_ID , PRODUCT_ID , make_evdev_device , None )
441530 # DS4 v.1
@@ -449,4 +538,4 @@ def fail_cb(syspath: str, vid: int, pid: int) -> None:
449538 """ Called when executed as script """
450539 init_logging ()
451540 set_logging_level (True , True )
452- sys .exit (hiddrv_test (DS4Controller , [ "054c:09cc" ]))
541+ sys .exit (hiddrv_test (DS4HIDController , [ "054c:09cc" ]))
0 commit comments