Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / hid / tests / test_sony.py
blob7e52c28e59c5c210e081579f7047a368c16063ce
1 #!/bin/env python3
2 # SPDX-License-Identifier: GPL-2.0
3 # -*- coding: utf-8 -*-
5 # Copyright (c) 2020 Benjamin Tissoires <benjamin.tissoires@gmail.com>
6 # Copyright (c) 2020 Red Hat, Inc.
9 from .base import application_matches
10 from .test_gamepad import BaseTest
11 from hidtools.device.sony_gamepad import (
12 PS3Controller,
13 PS4ControllerBluetooth,
14 PS4ControllerUSB,
15 PS5ControllerBluetooth,
16 PS5ControllerUSB,
17 PSTouchPoint,
19 from hidtools.util import BusType
21 import libevdev
22 import logging
23 import pytest
25 logger = logging.getLogger("hidtools.test.sony")
27 PS3_MODULE = ("sony", "hid_sony")
28 PS4_MODULE = ("playstation", "hid_playstation")
29 PS5_MODULE = ("playstation", "hid_playstation")
32 class SonyBaseTest:
33 class SonyTest(BaseTest.TestGamepad):
34 pass
36 class SonyPS4ControllerTest(SonyTest):
37 kernel_modules = [PS4_MODULE]
39 def test_accelerometer(self):
40 uhdev = self.uhdev
41 evdev = uhdev.get_evdev("Accelerometer")
43 for x in range(-32000, 32000, 4000):
44 r = uhdev.event(accel=(x, None, None))
45 events = uhdev.next_sync_events("Accelerometer")
46 self.debug_reports(r, uhdev, events)
48 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X) in events
49 value = evdev.value[libevdev.EV_ABS.ABS_X]
50 # Check against range due to small loss in precision due
51 # to inverse calibration, followed by calibration by hid-sony.
52 assert x - 1 <= value <= x + 1
54 for y in range(-32000, 32000, 4000):
55 r = uhdev.event(accel=(None, y, None))
56 events = uhdev.next_sync_events("Accelerometer")
57 self.debug_reports(r, uhdev, events)
59 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y) in events
60 value = evdev.value[libevdev.EV_ABS.ABS_Y]
61 assert y - 1 <= value <= y + 1
63 for z in range(-32000, 32000, 4000):
64 r = uhdev.event(accel=(None, None, z))
65 events = uhdev.next_sync_events("Accelerometer")
66 self.debug_reports(r, uhdev, events)
68 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Z) in events
69 value = evdev.value[libevdev.EV_ABS.ABS_Z]
70 assert z - 1 <= value <= z + 1
72 def test_gyroscope(self):
73 uhdev = self.uhdev
74 evdev = uhdev.get_evdev("Accelerometer")
76 for rx in range(-2000000, 2000000, 200000):
77 r = uhdev.event(gyro=(rx, None, None))
78 events = uhdev.next_sync_events("Accelerometer")
79 self.debug_reports(r, uhdev, events)
81 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_RX) in events
82 value = evdev.value[libevdev.EV_ABS.ABS_RX]
83 # Sensor internal value is 16-bit, but calibrated is 22-bit, so
84 # 6-bit (64) difference, so allow a range of +/- 64.
85 assert rx - 64 <= value <= rx + 64
87 for ry in range(-2000000, 2000000, 200000):
88 r = uhdev.event(gyro=(None, ry, None))
89 events = uhdev.next_sync_events("Accelerometer")
90 self.debug_reports(r, uhdev, events)
92 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_RY) in events
93 value = evdev.value[libevdev.EV_ABS.ABS_RY]
94 assert ry - 64 <= value <= ry + 64
96 for rz in range(-2000000, 2000000, 200000):
97 r = uhdev.event(gyro=(None, None, rz))
98 events = uhdev.next_sync_events("Accelerometer")
99 self.debug_reports(r, uhdev, events)
101 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_RZ) in events
102 value = evdev.value[libevdev.EV_ABS.ABS_RZ]
103 assert rz - 64 <= value <= rz + 64
105 def test_battery(self):
106 uhdev = self.uhdev
108 assert uhdev.power_supply_class is not None
110 # DS4 capacity levels are in increments of 10.
111 # Battery is never below 5%.
112 for i in range(5, 105, 10):
113 uhdev.battery.capacity = i
114 uhdev.event()
115 assert uhdev.power_supply_class.capacity == i
117 # Discharging tests only make sense for BlueTooth.
118 if uhdev.bus == BusType.BLUETOOTH:
119 uhdev.battery.cable_connected = False
120 uhdev.battery.capacity = 45
121 uhdev.event()
122 assert uhdev.power_supply_class.status == "Discharging"
124 uhdev.battery.cable_connected = True
125 uhdev.battery.capacity = 5
126 uhdev.event()
127 assert uhdev.power_supply_class.status == "Charging"
129 uhdev.battery.capacity = 100
130 uhdev.event()
131 assert uhdev.power_supply_class.status == "Charging"
133 uhdev.battery.full = True
134 uhdev.event()
135 assert uhdev.power_supply_class.status == "Full"
137 def test_mt_single_touch(self):
138 """send a single touch in the first slot of the device,
139 and release it."""
140 uhdev = self.uhdev
141 evdev = uhdev.get_evdev("Touch Pad")
143 t0 = PSTouchPoint(1, 50, 100)
144 r = uhdev.event(touch=[t0])
145 events = uhdev.next_sync_events("Touch Pad")
146 self.debug_reports(r, uhdev, events)
148 assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
149 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
150 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
151 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
153 t0.tipswitch = False
154 r = uhdev.event(touch=[t0])
155 events = uhdev.next_sync_events("Touch Pad")
156 self.debug_reports(r, uhdev, events)
157 assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
158 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
160 def test_mt_dual_touch(self):
161 """Send 2 touches in the first 2 slots.
162 Make sure the kernel sees this as a dual touch.
163 Release and check
165 Note: PTP will send here BTN_DOUBLETAP emulation"""
166 uhdev = self.uhdev
167 evdev = uhdev.get_evdev("Touch Pad")
169 t0 = PSTouchPoint(1, 50, 100)
170 t1 = PSTouchPoint(2, 150, 200)
172 r = uhdev.event(touch=[t0])
173 events = uhdev.next_sync_events("Touch Pad")
174 self.debug_reports(r, uhdev, events)
176 assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
177 assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
178 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
179 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
180 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
181 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
183 r = uhdev.event(touch=[t0, t1])
184 events = uhdev.next_sync_events("Touch Pad")
185 self.debug_reports(r, uhdev, events)
186 assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH) not in events
187 assert evdev.value[libevdev.EV_KEY.BTN_TOUCH] == 1
188 assert (
189 libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_X, 5) not in events
191 assert (
192 libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_Y, 10) not in events
194 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 0
195 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_X] == 50
196 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 100
197 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
198 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_POSITION_X] == 150
199 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_POSITION_Y] == 200
201 t0.tipswitch = False
202 r = uhdev.event(touch=[t0, t1])
203 events = uhdev.next_sync_events("Touch Pad")
204 self.debug_reports(r, uhdev, events)
205 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
206 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == 1
207 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_X) not in events
208 assert libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_Y) not in events
210 t1.tipswitch = False
211 r = uhdev.event(touch=[t1])
213 events = uhdev.next_sync_events("Touch Pad")
214 self.debug_reports(r, uhdev, events)
215 assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
216 assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1
219 class TestPS3Controller(SonyBaseTest.SonyTest):
220 kernel_modules = [PS3_MODULE]
222 def create_device(self):
223 controller = PS3Controller()
224 controller.application_matches = application_matches
225 return controller
227 @pytest.fixture(autouse=True)
228 def start_controller(self):
229 # emulate a 'PS' button press to tell the kernel we are ready to accept events
230 self.assert_button(17)
232 # drain any remaining udev events
233 while self.uhdev.dispatch(10):
234 pass
236 def test_led(self):
237 for k, v in self.uhdev.led_classes.items():
238 # the kernel might have set a LED for us
239 logger.info(f"{k}: {v.brightness}")
241 idx = int(k[-1]) - 1
242 assert self.uhdev.hw_leds.get_led(idx)[0] == bool(v.brightness)
244 v.brightness = 0
245 self.uhdev.dispatch(10)
246 assert self.uhdev.hw_leds.get_led(idx)[0] is False
248 v.brightness = v.max_brightness
249 self.uhdev.dispatch(10)
250 assert self.uhdev.hw_leds.get_led(idx)[0]
253 class CalibratedPS4Controller(object):
254 # DS4 reports uncalibrated sensor data. Calibration coefficients
255 # can be retrieved using a feature report (0x2 USB / 0x5 BT).
256 # The values below are the processed calibration values for the
257 # DS4s matching the feature reports of PS4ControllerBluetooth/USB
258 # as dumped from hid-sony 'ds4_get_calibration_data'.
260 # Note we duplicate those values here in case the kernel changes them
261 # so we can have tests passing even if hid-tools doesn't have the
262 # correct values.
263 accelerometer_calibration_data = {
264 "x": {"bias": -73, "numer": 16384, "denom": 16472},
265 "y": {"bias": -352, "numer": 16384, "denom": 16344},
266 "z": {"bias": 81, "numer": 16384, "denom": 16319},
268 gyroscope_calibration_data = {
269 "x": {"bias": 0, "numer": 1105920, "denom": 17827},
270 "y": {"bias": 0, "numer": 1105920, "denom": 17777},
271 "z": {"bias": 0, "numer": 1105920, "denom": 17748},
275 class CalibratedPS4ControllerBluetooth(CalibratedPS4Controller, PS4ControllerBluetooth):
276 pass
279 class TestPS4ControllerBluetooth(SonyBaseTest.SonyPS4ControllerTest):
280 def create_device(self):
281 controller = CalibratedPS4ControllerBluetooth()
282 controller.application_matches = application_matches
283 return controller
286 class CalibratedPS4ControllerUSB(CalibratedPS4Controller, PS4ControllerUSB):
287 pass
290 class TestPS4ControllerUSB(SonyBaseTest.SonyPS4ControllerTest):
291 def create_device(self):
292 controller = CalibratedPS4ControllerUSB()
293 controller.application_matches = application_matches
294 return controller
297 class CalibratedPS5Controller(object):
298 # DualSense reports uncalibrated sensor data. Calibration coefficients
299 # can be retrieved using feature report 0x09.
300 # The values below are the processed calibration values for the
301 # DualSene matching the feature reports of PS5ControllerBluetooth/USB
302 # as dumped from hid-playstation 'dualsense_get_calibration_data'.
304 # Note we duplicate those values here in case the kernel changes them
305 # so we can have tests passing even if hid-tools doesn't have the
306 # correct values.
307 accelerometer_calibration_data = {
308 "x": {"bias": 0, "numer": 16384, "denom": 16374},
309 "y": {"bias": -114, "numer": 16384, "denom": 16362},
310 "z": {"bias": 2, "numer": 16384, "denom": 16395},
312 gyroscope_calibration_data = {
313 "x": {"bias": 0, "numer": 1105920, "denom": 17727},
314 "y": {"bias": 0, "numer": 1105920, "denom": 17728},
315 "z": {"bias": 0, "numer": 1105920, "denom": 17769},
319 class CalibratedPS5ControllerBluetooth(CalibratedPS5Controller, PS5ControllerBluetooth):
320 pass
323 class TestPS5ControllerBluetooth(SonyBaseTest.SonyPS4ControllerTest):
324 kernel_modules = [PS5_MODULE]
326 def create_device(self):
327 controller = CalibratedPS5ControllerBluetooth()
328 controller.application_matches = application_matches
329 return controller
332 class CalibratedPS5ControllerUSB(CalibratedPS5Controller, PS5ControllerUSB):
333 pass
336 class TestPS5ControllerUSB(SonyBaseTest.SonyPS4ControllerTest):
337 kernel_modules = [PS5_MODULE]
339 def create_device(self):
340 controller = CalibratedPS5ControllerUSB()
341 controller.application_matches = application_matches
342 return controller