Analog sticks deadzone fix
Closed this issue · 7 comments
Knulli build version
40-dev-d3b520f949 2024/07/21 02:18
Your architecture
RG35XX H
Issue description
We now can fix issies with analog sticks using modded kernel from this repo
https://github.com/TheGammaSqueeze/40xx-kernel-decomp/releases
Detailed reproduction steps
- Dump, repack and reflash kernel. Linux PC needed
1.1 If your sdcard is /dev/sdb then
sudo dd if=/dev/sdb1 bs=4M of=path/to/kerneldump.img
1.2 Repack it with modded kernel
abootimg -x kerneldump.img
abootimg --create newboot.img -f bootimg.cfg -k RG35XXH-kernel.modded -r initrd.img
1.3 Flash it back.
sudo dd if=newboot.img of=/dev/sdb1 bs=4M - Sticks will work, but they will be uncalibrated, To resolve this proble I've used script from this repo.
https://github.com/m-kostrzewa/sdl2-joystick-calib with some modifications
After this point everything should be done with ssh or scp on runnig console
2.1 create /opt/sdl2_jscal/sdl2-joystick-calib.py
#!/usr/bin/python3
import argparse
import logging as log
from select import select
from evdev import InputDevice, UInput, UInputError
MOVED_EVENT = 3 #event type 3 is input from sticks and arrowkeys
MAP_EVENT_CODE_TO_AXIS_IDX = {
1: 0, # left X (ABS_Z)
2: 1, # left Y (ABS_Y)
4: 2, # right X (ABS_RZ)
5: 3, # right Y (ABS_RY)
16: 4, #arrowkeys left\right
17: 5 #arrowkeys up\down
}
class Calibration(object):
def __init__(self, a, b, c, d):
self.a = a
self.b = b
self.c = c
self.d = d
def apply(self, real_pos):
# y = sign*multiplier(deadzone-real_pos)
x = real_pos
y = 0
if x < self.a:
y = -self.c * (self.a - x) / 100000
elif x > self.b:
y = self.d * (x - self.b) / 100000
return round(y)
def __str__(self):
return "a: {}, b: {}, c: {}, d: {}". format(self.a, self.b, self.c, self.d)
def parse_params():
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('--input_dev', type=str, default='/dev/input/event1',
help='input event device')
parser.add_argument('--calib_file', type=str, default='cal.txt',
help='jcal calibration file')
parser.add_argument('--verbose', action='store_true',
help='print verbose debugging output')
parser.add_argument('--filter_evcode', type=int, default=-1,
help='prints events only for speficic evcode')
parser.add_argument('--dry_run', action='store_true',
help='do not apply calibration, just pass through')
args = parser.parse_args()
return args
def setup_logging(is_verbose):
if is_verbose:
log.basicConfig(level=log.DEBUG)
else:
log.basicConfig(level=log.INFO)
def load_calibrations(calib_path):
calibrations = {}
with open(calib_path, "r") as f:
line = f.readline()
_, _, lotsa_numbers, _ = line.split(" ")
calibs = lotsa_numbers.split(",")
num_axis = int(calibs[0])
current_axis = 0
for i in range(1, len(calibs), 6):
_, _, a, b, c, d = map(int, calibs[i:i+6])
calibrations[current_axis] = Calibration(a, b, c, d)
current_axis += 1
assert(len(calibrations) == num_axis)
log.info("Loaded calibration for axis:")
for i in range(num_axis):
log.info("- axis {}: {}".format(i, calibrations[i]))
return calibrations
def setup_devices(original_path):
raw = InputDevice(original_path)
target_dev = '/dev/uinput'
try:
fixed = UInput.from_device(raw, devnode=target_dev, name="Calibrated {}".format(raw.name))
except UInputError as e:
raise PermissionError("You should run this command as root") from e
log.info("Redirecting fixed stream to {}".format(target_dev))
return raw, fixed
def write_event(device, event):
device.write_event(event)
device.syn()
def redirect(from_dev, to_dev, calib, dry_run, filter_evcode):
while True:
r, _, _ = select([from_dev], [], [])
for event in from_dev.read():
if event.type != MOVED_EVENT:
write_event(to_dev, event)
continue
axis = MAP_EVENT_CODE_TO_AXIS_IDX[event.code]
old_val = event.value
new_val = calib[axis].apply(old_val) if not dry_run else old_val
if filter_evcode == -1 or event.code == filter_evcode:
log.debug('{}\t-> Adjusted value: {}'.format(event, new_val))
event.value = new_val
write_event(to_dev, event)
def main():
args = parse_params()
setup_logging(args.verbose)
calib = load_calibrations(args.calib_file)
from_dev, to_dev = setup_devices(args.input_dev)
redirect(from_dev, to_dev, calib, args.dry_run, args.filter_evcode)
if __name__ == "__main__":
main()
chmod +x /opt/sdl2_jscal/sdl2-joystick-calib.py
2.2 and /opt/sdl2_jscal/cal.txt
jscal -s 6,0,0,-300,800,145000,170000,0,0,-300,500,150000,180000,1,0,-600,400,170000,160000,1,0,-600,400,205000,135000,1,0,0,0,2147483647,2147483647,1,0,0,0,2147483647,2147483647 /dev/input/js0
- Modify /etc/profile to add new env at the beginning of file
export SDL_GAMECONTROLLERCONFIG="19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
"
- add new script /etc/init.d/S99sdljscal to run new srvice at boot
#!/bin/sh
workfolder=/opt/sdl2_jscal
mkdir /inputmirror
mount -o bind /dev/input /inputmirror
"$workfolder"/sdl2-joystick-calib.py --calib "$workfolder"/cal.txt --input "/inputmirror/event1" &
counter=30
while [ ! -e /dev/input/event3 ]&&[ $counter -gt 0 ]; do sleep 1; counter=$(($counter-1)); done
mount -o bind /inputmirror/event3 /dev/input/event1
chmod +x /etc/init.d/S99sdljscal
this script will replace real hradware gamepad with virtual one with corrected inputs
5. fix changes in firmware
batocera-save-overlay
sync
reboot
Details of any attempts to fix this yourself
Lots of different attempts. One of them worked
Details of any modifications you have made to Knulli.
New kernel flashed. New service created
Logs and data
No response
On my RG35XXH this messed up the button mappings. I now had select and start as "up" and "down", L1 as "select", and R1 as "start". East and North moved 3 lines down and up respectively. Nothing else worked... Removing the start-up script brought it back to normal.
On my RG35XXH this messed up the button mappings. I now had select and start as "up" and "down", L1 as "select", and R1 as "start". East and North moved 3 lines down and up respectively. Nothing else worked... Removing the start-up script brought it back to normal.
Seems that third paraghraph (/etc/profile modification) did not worked for you. We set button mappings for new virtual gamepad through SDL_GAMECONTROLLERCONFIG environment variable
What is your output of sdl2-jstest --list ? Should be:
[root@KNULLI /userdata/system]# sdl2-jstest --list
Found 1 joystick(s)
Joystick Name: 'Calibrated Deeplay-keys'
Joystick Path: '/dev/input/event1'
Joystick GUID: 03000000010000000100000001000000
Joystick Number: 0
Number of Axes: 4
Number of Buttons: 17
Number of Hats: 1
Number of Balls: 0
GameControllerConfig:
Name: 'odroidgo2 joypad'
Mapping: '03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,'
Axis code 0: 1
Axis code 1: 2
Axis code 2: 4
Axis code 3: 5
Button code 0: 1
Button code 1: 114
Button code 2: 115
Button code 3: 304
Button code 4: 305
Button code 5: 306
Button code 6: 307
Button code 7: 308
Button code 8: 309
Button code 9: 310
Button code 10: 311
Button code 11: 312
Button code 12: 313
Button code 13: 314
Button code 14: 315
Button code 15: 316
Button code 16: 354
Hat code 0: -1
Seems to be the same, apart from the GUID:
bash-5.2# sdl2-jstest --list
Found 1 joystick(s)
Joystick Name: 'Deeplay-keys'
Joystick Path: '/dev/input/event1'
Joystick GUID: 19000000010000000100000000010000
Joystick Number: 0
Number of Axes: 4
Number of Buttons: 17
Number of Hats: 1
Number of Balls: 0
GameControllerConfig:
Name: 'odroidgo2 joypad'
Mapping: '19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,'
Axis code 0: 1
Axis code 1: 2
Axis code 2: 4
Axis code 3: 5
Button code 0: 1
Button code 1: 114
Button code 2: 115
Button code 3: 304
Button code 4: 305
Button code 5: 306
Button code 6: 307
Button code 7: 308
Button code 8: 309
Button code 9: 310
Button code 10: 311
Button code 11: 312
Button code 12: 313
Button code 13: 314
Button code 14: 315
Button code 15: 316
Button code 16: 354
Hat code 0: -1
Seems to be the same, apart from the GUID:
You did not restore startup script before doing this, right?
The idea of this hack is like:
- Create mirror of /dev/input ( mkdir /inputmirror and mount -o bind /dev/input /inputmirror commands)
- Run special script, which reads events from HW one (from /inputmirror/event1) and creates new virtual gamepad with calibrated input(/opt/sdl2_jscal/sdl2-joystick-calib.py --calib /opt/sdl2_jscal/cal.txt --input "/inputmirror/event1" & command)
- Mount new virtual gamepad (/dev/input/event3) on top of HW one to hide HW gamepad from system and inrtercept all readings (mount -o bind /inputmirror/event3 /dev/input/event1 command)
Unfortunately, there is no default key mappings for our virtual gamepad, so we provide it through SDL_GAMECONTROLLERCONFIG environment variable.
So, you should check your SDL_GAMECONTROLLERCONFIG variable
echo $SDL_GAMECONTROLLERCONFIG
Output should be:
[root@KNULLI /userdata/system]# echo $SDL_GAMECONTROLLERCONFIG
19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, 03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
And also check your /etc/profile
Should be like:
export SDL_GAMECONTROLLERCONFIG="19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
"
if [ "$PS1" ]; then
if [ "`id -u`" -eq 0 ]; then
export PS1='# '
else
export PS1='$ '
fi
fi
export EDITOR='/bin/vi'
# Source configuration files from /etc/profile.d
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
. $i
fi
done
unset i
Also dowble check, that all files, which you modified or created now have linux line-ending (Windows OS uses combination of CR and LF as line end, MacOS uses CR only and Linux uses only LF)
After that reatore all scripts and try again
[root@KNULLI /userdata/system]# echo $SDL_GAMECONTROLLERCONFIG
19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, 03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
[root@KNULLI /userdata/system]# cat /etc/profile
export PATH="/bin:/sbin:/usr/bin:/usr/sbin"
if [ "$PS1" ]; then
if [ "`id -u`" -eq 0 ]; then
export PS1='# '
else
export PS1='$ '
fi
fi
export EDITOR='/bin/vi'
# Source configuration files from /etc/profile.d
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
. $i
fi
done
unset i
export SDL_GAMECONTROLLERCONFIG="19000000010000000100000000010000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
03000000010000000100000001000000,odroidgo2 joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
"
Everything was done on the terminal, with vim, so it should have a LF line ending only.
I see that /etc/profile I've put the "export SDL_GAMECONTROLLERCONFIG" line at the end, I'll move it to the beginning
export SDL_GAMECONTROLLERCONFIG" line at the end
I think it should not make any difference, but try it. If nothing works - I will publish all files from my installation
Closing as gammas fix is included in Knulli builds now.