~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/hid/tests/test_sony.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0
  3 # -*- coding: utf-8 -*-
  4 #
  5 # Copyright (c) 2020 Benjamin Tissoires <benjamin.tissoires@gmail.com>
  6 # Copyright (c) 2020 Red Hat, Inc.
  7 #
  8 
  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,
 18 )
 19 from hidtools.util import BusType
 20 
 21 import libevdev
 22 import logging
 23 import pytest
 24 
 25 logger = logging.getLogger("hidtools.test.sony")
 26 
 27 PS3_MODULE = ("sony", "hid_sony")
 28 PS4_MODULE = ("playstation", "hid_playstation")
 29 PS5_MODULE = ("playstation", "hid_playstation")
 30 
 31 
 32 class SonyBaseTest:
 33     class SonyTest(BaseTest.TestGamepad):
 34         pass
 35 
 36     class SonyPS4ControllerTest(SonyTest):
 37         kernel_modules = [PS4_MODULE]
 38 
 39         def test_accelerometer(self):
 40             uhdev = self.uhdev
 41             evdev = uhdev.get_evdev("Accelerometer")
 42 
 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)
 47 
 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
 53 
 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)
 58 
 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
 62 
 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)
 67 
 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
 71 
 72         def test_gyroscope(self):
 73             uhdev = self.uhdev
 74             evdev = uhdev.get_evdev("Accelerometer")
 75 
 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)
 80 
 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
 86 
 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)
 91 
 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
 95 
 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)
100 
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
104 
105         def test_battery(self):
106             uhdev = self.uhdev
107 
108             assert uhdev.power_supply_class is not None
109 
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
116 
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"
123 
124             uhdev.battery.cable_connected = True
125             uhdev.battery.capacity = 5
126             uhdev.event()
127             assert uhdev.power_supply_class.status == "Charging"
128 
129             uhdev.battery.capacity = 100
130             uhdev.event()
131             assert uhdev.power_supply_class.status == "Charging"
132 
133             uhdev.battery.full = True
134             uhdev.event()
135             assert uhdev.power_supply_class.status == "Full"
136 
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")
142 
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)
147 
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
152 
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
159 
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
164 
165             Note: PTP will send here BTN_DOUBLETAP emulation"""
166             uhdev = self.uhdev
167             evdev = uhdev.get_evdev("Touch Pad")
168 
169             t0 = PSTouchPoint(1, 50, 100)
170             t1 = PSTouchPoint(2, 150, 200)
171 
172             r = uhdev.event(touch=[t0])
173             events = uhdev.next_sync_events("Touch Pad")
174             self.debug_reports(r, uhdev, events)
175 
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
182 
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
190             )
191             assert (
192                 libevdev.InputEvent(libevdev.EV_ABS.ABS_MT_POSITION_Y, 10) not in events
193             )
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
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
209 
210             t1.tipswitch = False
211             r = uhdev.event(touch=[t1])
212 
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
217 
218 
219 class TestPS3Controller(SonyBaseTest.SonyTest):
220     kernel_modules = [PS3_MODULE]
221 
222     def create_device(self):
223         controller = PS3Controller()
224         controller.application_matches = application_matches
225         return controller
226 
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)
231 
232         # drain any remaining udev events
233         while self.uhdev.dispatch(10):
234             pass
235 
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}")
240 
241                 idx = int(k[-1]) - 1
242                 assert self.uhdev.hw_leds.get_led(idx)[0] == bool(v.brightness)
243 
244                 v.brightness = 0
245                 self.uhdev.dispatch(10)
246                 assert self.uhdev.hw_leds.get_led(idx)[0] is False
247 
248                 v.brightness = v.max_brightness
249                 self.uhdev.dispatch(10)
250                 assert self.uhdev.hw_leds.get_led(idx)[0]
251 
252 
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'.
259     #
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},
267     }
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},
272     }
273 
274 
275 class CalibratedPS4ControllerBluetooth(CalibratedPS4Controller, PS4ControllerBluetooth):
276     pass
277 
278 
279 class TestPS4ControllerBluetooth(SonyBaseTest.SonyPS4ControllerTest):
280     def create_device(self):
281         controller = CalibratedPS4ControllerBluetooth()
282         controller.application_matches = application_matches
283         return controller
284 
285 
286 class CalibratedPS4ControllerUSB(CalibratedPS4Controller, PS4ControllerUSB):
287     pass
288 
289 
290 class TestPS4ControllerUSB(SonyBaseTest.SonyPS4ControllerTest):
291     def create_device(self):
292         controller = CalibratedPS4ControllerUSB()
293         controller.application_matches = application_matches
294         return controller
295 
296 
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'.
303     #
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},
311     }
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},
316     }
317 
318 
319 class CalibratedPS5ControllerBluetooth(CalibratedPS5Controller, PS5ControllerBluetooth):
320     pass
321 
322 
323 class TestPS5ControllerBluetooth(SonyBaseTest.SonyPS4ControllerTest):
324     kernel_modules = [PS5_MODULE]
325 
326     def create_device(self):
327         controller = CalibratedPS5ControllerBluetooth()
328         controller.application_matches = application_matches
329         return controller
330 
331 
332 class CalibratedPS5ControllerUSB(CalibratedPS5Controller, PS5ControllerUSB):
333     pass
334 
335 
336 class TestPS5ControllerUSB(SonyBaseTest.SonyPS4ControllerTest):
337     kernel_modules = [PS5_MODULE]
338 
339     def create_device(self):
340         controller = CalibratedPS5ControllerUSB()
341         controller.application_matches = application_matches
342         return controller

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php