chrippa/ds4drv

Rumble support

Opened this issue ยท 23 comments

Ape commented

We can send rumble events to the physical controller just fine, but we are not currently supporting rumble features in the evdev end so games cannot actually use rumble.

Do you have any links explaining why evdev doesn't support rumble? Is there any way around this you've seen?

Ape commented

Evdev itself would allow rumble (force feedback) support. See this for information about it. However, python-evdev doesn't seem to support rumble, or at least it didn't in the past. Here is an old pull request discussing that.

Hi! This is my code for send vibration in gamepad in python (works with xbox 360 controller, dualshock 4, wii remote).

import fcntl, struct, array, time

EVIOCRMFF = 0x40044581
EVIOCSFF = 0x40304580
LOG_CLASS_ON = False
TIME_DELTA = 250

class Vibrate:

    def __init__(self, file):
        self.ff_joy = open(file, "r+")

    def close(self):
        self.ff_joy.close()

    def new_effect(self, strong, weak, length):
        effect = struct.pack('HhHHHHHxHH', 0x50, -1, 0, 0, 0, length, 0, int(strong * 0xFFFF), int(weak * 0xFFFF))
        a = array.array('h', effect)
        fcntl.ioctl(self.ff_joy, EVIOCSFF, a, True)
        return a[1]
        id = a[1]
        return (ev_play, ev_stop)

    def play_efect(self, id):
        if type(id) == tuple or type(id) == list:
            ev_play = ''
            for i in id:
                ev_play = ev_play + struct.pack('LLHHi', 0, 0, 0x15, i, 1)
        else:
            ev_play = struct.pack('LLHHi', 0, 0, 0x15, id, 1)
        self.ff_joy.write(ev_play)
        self.ff_joy.flush()

    def stop_effect(self, id):
        if type(id) == tuple or type(id) == list:
            ev_stop = ''
            for i in id:
                ev_stop = ev_stop + struct.pack('LLHHi', 0, 0, 0x15, i, 0)
        else:
            ev_stop = struct.pack('LLHHi', 0, 0, 0x15, id, 0)
        self.ff_joy.write(ev_stop)
        self.ff_joy.flush()

    def forget_effect(self, id):
        if type(id) == tuple or type(id) == list:
            for i in id:
                fcntl.ioctl(self.ff_joy, EVIOCRMFF, i)
        else:
            fcntl.ioctl(self.ff_joy, EVIOCRMFF, id)

f = Vibrate("/dev/input/event14")
p = f.new_effect(1.0, 1.0, TIME_DELTA )
f.play_efect((p))
time.sleep(TIME_DELTA / 1000.0)
f.stop_effect((p))
f.forget_effect((p))

@kharlashkin Hi. Are you saying you are able to get rumble to work with this code? If so, what file is this that you have provided? I would like to add it to get rumble to work if possible. Thanks!

@Millsionaire Hi! You must write only correct "/dev/input/event14" for testing this code. Sorry for my english.

Hi,

for me the ds4drv correctly creates /dev/input/event0 (raspberry pi 3).
However, fftest cannot play any rumble effects ("Error: function not implemented").

The code posted above does not work ("invalid argument").

How can I make the controller rumble? Any working c code/program is appreciated.

Can't this be done through libinput?

@kharlashkin

with your code:

โ””โ”€โ”€โ”€โ•ผ  ds4drv                                                                                                                                                                                                                                                                                                                 
[info][controller 1] Created devices /dev/input/js0 (joystick) /dev/input/event7 (evdev)                                                                                                                                                                                                                                      
[info][bluetooth] Scanning for devices                                                                                                                                                                                                                                                                                        
[info][bluetooth] Found device 00:01:6C:8D:29:C5                                                                                                                                                                                                                                                                              
[info][controller 1] Connected to Bluetooth Controller (00:01:6C:8D:29:C5)                                                                                                                                                                                                                                                    
[info][bluetooth] Scanning for devices                                                                                                                                                                                                                                                                                        
[info][controller 1] Battery: Fully charged  
โ””โ”€โ”€โ”€โ•ผ  python rumble.py 
Traceback (most recent call last):
  File "rumble.py", line 51, in <module>
    f = Vibrate("/dev/input/event7")
  File "rumble.py", line 11, in __init__
    self.ff_joy = open(file, "r+")
io.UnsupportedOperation: File or stream is not seekable.

any hint?

is a DualShock 4 20th anniversary edition

In first you must find your gamepad in "/dev/input/eventXX" and insert true event. For testing vibration in terminal try:
fftest /dev/input/eventXX

I think autofind true event try make with glob.glob('/dev/input/event[A-Za-z]*'). Sorry for my english.

you mean like this?

[1036906.183060] input: Sony Computer Entertainment Wireless Controller as /devices/virtual/input/input119

from dmesg

note: using python-evdev 0.6.4

I don't have any dualshock for testing, but I'm sure - when dualshock 4 connect with cable to PC - its has vibrate from fftest /dev/input/eventXX. One of my friend test this.

then only works with USB? not working through BT?

On occasion, I will ask him about BT.

other question, what version of python-evdev is used? ff branch?

On my example I dont use any python-evdev. Documentation for writing this test program Im getting in Linux Kernel.

ok. tested with fftest from linuxconsole package

only works throught USB cable

fails with BT due unimplemented function

โ””โ”€โ”€โ”€โ•ผ  fftest /dev/input/event7
Force feedback test program.
HOLD FIRMLY YOUR WHEEL OR JOYSTICK TO PREVENT DAMAGES

Device /dev/input/event7 opened
Features:
  * Absolute axes: X, Y, Z, RX, RY, RZ, Throttle, Rudder, Wheel, Hat 0 X, Hat 0 Y, Distance, Tilt X, Tilt Y, 
    [FF 01 03 0E 00 00 00 00 ]
  * Relative axes: 
    [00 00 ]
  * Force feedback effects types: 
    Force feedback periodic effects: 
    [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
  * Number of simultaneous effects: 0

Uploading effect #0 (Periodic sinusoidal) ... Error:: Function not implemented
Uploading effect #1 (Constant) ... Error: Function not implemented
Uploading effect #2 (Spring) ... Error: Function not implemented
Uploading effect #3 (Damper) ... Error: Function not implemented
Uploading effect #4 (Strong rumble, with heavy motor) ... Error: Function not implemented
Uploading effect #5 (Weak rumble, with light motor) ... Error: Function not implemented
Enter effect number, -1 to exit
-1
Stopping effects

same output with ds4drv --hidraw (with USB cable) (/dev/input/event25)

EDIT: oh, is a python2 (fails with python3) script..... ok. now works.

fails in BT mode throught ds4drv (plain bluez)

works in BT mode without ds4drv

Yes. I posted my script with idea to developers added vibration in ds4drv.

you can add python3 support in you script?

Yes, I can add python3 support, but now I dont have a gamepad for testing.

For anyone looking for Python 3 support:
Just change line 11 to this:

self.ff_joy = open(file, "r+b", buffering=0)

Thanks for the Vibrate Class Kharlashkin

This is my output on Fedora:

  File "rumble.py", line 53, in <module>
    p = f.new_effect(1.0, 1.0, TIME_DELTA )
  File "rumble.py", line 20, in new_effect
    fcntl.ioctl(self.ff_joy, EVIOCSFF, a, True)
OSError: [Errno 38] Function not implemented

@kharlashkin do you still need some testing for this? I can be a tester for this feature ;)

Hi there, anyone figured this out yet?