Skip to content

Workaround for legacy joystick calibration using jscal in SDL2.

License

Notifications You must be signed in to change notification settings

m-kostrzewa/sdl2-joystick-calib

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SDL2 Joystick Calib

Python script that man-in-the-middles joystick events and applies legacy jscal calibration.

It works by intercepting messages sent to /dev/input/event* and publishing calibrated versions to a virtual device.

The problem

I wanted to play Freespace 2 using my old Saitek Cyborg 3D Gold joystick. I had to calibrate it. Using standard tools like jscal worked, but not in game. Turns out, SDL is the culprit.

SDL1.2 defaulted to using event API (/dev/input/event*) over /dev/input/js*. You could workaround this by setting environment variable export SDL_JOYSTICK_DEVICE=/dev/input/js0. See this answer for more info. Well, it didn't work for me.

Turns out, SDL2 abandoned /dev/input/js* input method in favor of /dev/input/event* API completely (source). And of course Freespace 2 now uses SDL2. Sad thing is, SDL is supposed to handle calibrating the joystick, but it doesn't work.

Requirements

  • Python3
  • jstest, jscal
  • Evdev Python3 wrapper, e.g.:
sudo dnf install python3-evdev.x86_64 # or your distro equivalent

Usage

  1. Use jstest to see if the joystick needs recalibration. If moving the joystick to min/max positions doesn't yield values close to +-32 thousand, it needs to be recalibrated. (Note: path to device may be different for you, especially if you have multiple joysticks).

    jstest /dev/input/js0
    
  2. If calibration is needed, use jscal:

    jscal -c /dev/input/js0
    
  3. Verify the calibration. Moving joystick to min/max positions should yield values close to +-32 thousand.

    jstest /dev/input/js0
    
  4. Ensure that SDL2 is the culprit. Use sdl-jstest. If it seems like it contradicts jstest's results, then keep reading. Otherwise, you probably have a different issue.

    ./sdl2-jstest --list
    ./sdl2-jstest --test 0
    
  5. Dump calibration data to a file:

    jscal -p /dev/input/js0 > cal.txt
    
  6. Use evtest to see which /dev/input/event* device to intercept:

    $ sudo evtest
    No device specified, trying to scan all of /dev/input/event*
    Available devices:
    ...
    /dev/input/event28:	SAITEK CYBORG 3D USB
    Select the device event number [0-30]: 30^C
    
  7. Run the script as root in verbose mode:

    sudo ./sdl2-joystick-calib.py --calib cal.txt --input "/dev/input/event28" --verbose
    
  8. Aside from some info logs, you should see different events. If val is different from Adjusted value, then the calibration from jscal is being applied.

    DEBUG:root:event at 1535842389.423851, code 05, type 03, val 85	-> Adjusted value: 468
    
  9. Are you using the same joystick as me (Saitek Cybork 3D Gold)? If not, you will probably need to reconfigure the script a little bit. See configuring.

  10. Use evtest to verify if our device has come up. Look for 'Calibrated' prefix:

    $ sudo evtest
    No device specified, trying to scan all of /dev/input/event*
    Available devices:
    ...
    /dev/input/event28:	SAITEK CYBORG 3D USB
    ...
    /dev/input/event30:	Calibrated SAITEK CYBORG 3D USB
    Select the device event number [0-30]: 30^C
    
  11. Use sdl2-jstest to verify if everything is sane.

    ./sdl2-jstest --list
    ./sdl2-jstest --test 1
    
  12. You should be good to go. Enjoy!

Configuring

I have only one joystick, so I just hard-coded configuration data inside the script. Sorry, too lazy for now. You may have to modify it. PRs welcome :)

It is likely that you will have to modify MOVED_EVENT constant and MAP_EVENT_CODE_TO_AXIS_IDX dictionary.

MOVED_EVENT

Your joystick may send many types of messages. Use evtest to peek what yours sends. For me, the interesting output is

Event: time 1535842968.567306, -------------- SYN_REPORT ------------
Event: time 1535842968.583313, type 3 (EV_ABS), code 0 (ABS_X), value 93

It carries the value data, which changes as I move the joystick. Set MOVED_EVENT to value of type from these kinds of messages.

MAP_EVENT_CODE_TO_AXIS_IDX

My Joystick has 6 axis. Each one has its own corresponding message code. E.g. left-right movement is code 0, throttle is 6, etc. We need to associate these codes with output of jscal tool, which doesn't contain such information.

Use verbose and filter_evcode parameters to try to find correspondence between the order in which axis appear in jscal calibration file and message codes. Overwrite MAP_EVENT_CODE_TO_AXIS_IDX dict with this information.

References

About

Workaround for legacy joystick calibration using jscal in SDL2.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages