I built a test package that was tested by Edu with his Driving Force GT wheel. We discovered a few issues that I was able to fix.
Since the DFGT wheel supports adjusting the wheel range, I decided to add support for the wheel range change command (which is an extended command in the Logitech protocol). I also added support for the set rpm leds command.
I made the FFB support generic in GNU/Linux. The following wheels should be supported:
- Driving Force GT
- Momo Racing Force Feedback (tested)
- Momo Force
- Driving Force Pro
- Logitech Speed Force Wireless
- Formula Force GP (tested, the only working effect is vibration)
My current task is to make the code generic on Windows.
As explained in status 1, GIMX has to convert the FFB report stream so that it can be transmitted to a wheel that cannot handle reports as fast as a G29 (my Momo racing wheel can handle one report each 8ms, and the G29 one report each 4ms). I wrote some code that handles this task the following way:
- on reception, decode the report according to the protocol specification (published by Logitech here), and only handle “download and play” and “stop” commands
- store the status of the effect into a slot (there are up to 4 effects), and push the effect id into a fifo
- if no write is pending:
- if multiple effects have to be stopped, build a report to stop them, and remove the effects from the fifo
- otherwise, get the next effect to update from the fifo (if any), and build a report
- finally, if a report has to be written, write it (this is non-blocking)
- when writing is complete (this is notified asynchronously), execute step 3
And that’s it, I made my Momo Racing wheel work with my PS4, including force-feedback!
My last task will be to make the code more generic so that other Logitech wheels can be used.
While searching for some HID parser code to parse HID input reports from Logitech wheels, I found an interesting driver that can do this job: UHID. It was written to allow connecting a userspace-managed device to the HID core driver of Linux. My first idea was to create a device with UHID, logically connected to the USB bus, with the same name and USB ids, and the fixed HID report from the Linux kernel. But using the same bus and the same USB ids makes the HID core driver load specific drivers (hid-lg, hid-lg4ff). The userspace-managed device I want to create is an input device only, since I’m already managing the HID OUT interrupt endpoint with libusb. The solution is to connect the device to the virtual bus. The last thing to care about is to set the same calibration parameters as the kernel does.
Some people may have noticed the presence of two new firmwares since GIMX 4.0: EMUG27PS3 and EMUT300RSPS4. There is also another new firmware in the git repository: EMUG29PS4. These firmwares can be used with the DIY USB adapter. Many thanks to tps and InhexSTER for helping me implement these firmwares!
As it may not be obvious, these firmwares have the following purposes:
- EMUG27PS3: emulate a Logitech G27 wheel to use with a PS3
- EMUT300RSPS4: emulate a Thrustmaster T300RS wheel to use with a PS4
- EMUG29PS4: emulate a Logitech G29 wheel to use with a PS4.
For now, only controls can be used. But force feedback support is coming! This is possible thanks to the following findings:
- the DS4 can be used as an authentication source for PS4 wheels
- the PS3 and the PS4 send FFB data to the Logitech wheel using the FFB protocol that Logitech published here
This means that it is possible to forward FFB data to almost any Logitech wheel including my old Momo racing wheel 🙂
My current work is to make a communication layer to manage Logitech wheels, that are standard HID devices. One key feature of this communication layer is to support asynchronous transfers, which allows to initiate transfers without waiting (blocking) for the results. This is the only way to efficiently process inputs from multiple devices at the same time (one thread per device is not efficient to me). This communication layer also has to be cross-platform (Linux and Windows). GIMX already talks to HID devices using the hidapi library, but this library does not support asynchronous transfers (this is the reason why GIMX does not support rumble with GPP/Cronus/Titan devices). After realizing that no library was providing this, I decided to write my own one, that uses overlapped IO in Windows, and the hidraw interface in Linux. It turned out that the hidraw interface does not support asynchronous writes, which forced me to use the libusb library instead. When using the libusb library, the kernel drivers are detached (unloaded), including the driver that parses HID input packets and translates them into input events (i.e. joystick buttons and axes). This means that GIMX has to do this job, which may be a time consuming development considering each Logitech wheel can have a different HID input format.
There is another non-trivial task that I’ll have to work on. I was thinking that the bInterval value for a USB interrupt out endpoint would restrict the USB host from sending more than one transfer each bInterval period on this endpoint. But in fact a USB device can accept more than that: the G29 has a bInterval of 5ms for its interrupt out endpoint, but it can take at least one out report each 4ms; the Momo racing has a bInterval of 10ms for its interrupt out endpoint, but it can take at least one out report each 8ms. Therefore, changing the bInterval for the interrupt out endpoint of the EMUG29PS4 firmware would not allow to work-around the mismatch of the out report period (I tried it before realizing that fact, and it made my PS4 randomly crash!). This means that I can’t forward all interrupt out transfers to my Momo racing wheel: I have to drop or combine some transfers without altering the FFB effects.
Last sunday I went to a bric-a-brac sale. I was looking for a steering wheel to adapt to my emulator. I bought a Wingman Formula Force GP for 5€:
This wheel is quite old – it was released in 2002 – but it still has a force feedback and a usb connector (older steering wheels have a gameport connector). It is probably outdated but I bet I can’t find better for that price.
I committed some code that enables the use of this controller with the sixaxis emulator. It uses the joystick API of the SDL library. The code is not well designed and has some limitations (only one joystick plugged to the PC, mappings are hardcoded…), but it is for now a proof of concept. It can be activated by modifying the Makefile: remove the # character from the line “#CFLAGS+=-DJOYSTICK”, and perform a make clean and a make.
Note that your joystick may be wrapped by default to a mouse and/or a keyboard by your linux distro. This is annoying because it generates extra mouse/keyboard events that interfere with real mouse and keyboard events in the emulator. This behavior can be configured/removed with the xinput command line utility. For more info on that command, type “xinput –help”.