#!/bin/env python3
# SPDX-License-Identifier: GPL-2.0
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 Benjamin Tissoires <benjamin.tissoires@gmail.com>
# Copyright (c) 2017 Red Hat, Inc.
# Copyright (c) 2020 Wacom Technology Corp.
#
# Authors:
# Jason Gerecke <jason.gerecke@wacom.com>
"""
Tests for the Wacom driver generic codepath.
This module tests the function of the Wacom driver's generic codepath.
The generic codepath is used by devices which are not explicitly listed
in the driver's device table. It uses the device's HID descriptor to
decode reports sent by the device.
"""
from .descriptors_wacom import (
wacom_pth660_v145,
wacom_pth660_v150,
wacom_pth860_v145,
wacom_pth860_v150,
wacom_pth460_v105,
)
import attr
from collections import namedtuple
from enum import Enum
from hidtools.hut import HUT
from hidtools.hid import HidUnit
from . import base
from . import test_multitouch
import libevdev
import pytest
import logging
logger = logging.getLogger("hidtools.test.wacom")
KERNEL_MODULE = ("wacom", "wacom")
class ProximityState(Enum):
"""
Enumeration of allowed proximity states.
"""
# Tool is not able to be sensed by the device
OUT = 0
# Tool is close enough to be sensed, but some data may be invalid
# or inaccurate
IN_PROXIMITY = 1
# Tool is close enough to be sensed with high accuracy. All data
# valid.
IN_RANGE = 2
def fill(self, reportdata):
"""Fill a report with approrpiate HID properties/values."""
reportdata.inrange = self in [ProximityState.IN_RANGE]
reportdata.wacomsense = self in [
ProximityState.IN_PROXIMITY,
ProximityState.IN_RANGE,
]
class ReportData:
"""
Placeholder for HID report values.
"""
pass
@attr.s
class Buttons:
"""
Stylus button state.
Describes the state of each of the buttons / "side switches" that
may be present on a stylus. Buttons set to 'None' indicate the
state is "unchanged" since the previous event.
"""
primary = attr.ib(default=None)
secondary = attr.ib(default=None)
tertiary = attr.ib(default=None)
@staticmethod
def clear():
"""Button object with all states cleared."""
return Buttons(False, False, False)
def fill(self, reportdata):
"""Fill a report with approrpiate HID properties/values."""
reportdata.barrelswitch = int(self.primary or 0)
reportdata.secondarybarrelswitch = int(self.secondary or 0)
reportdata.b3 = int(self.tertiary or 0)
@attr.s
class ToolID:
"""
Stylus tool identifiers.
Contains values used to identify a specific stylus, e.g. its serial
number and tool-type identifier. Values of ``0`` may sometimes be
used for the out-of-range condition.
"""
serial = attr.ib()
tooltype = attr.ib()
@staticmethod
def clear():
"""ToolID object with all fields cleared."""
return ToolID(0, 0)
def fill(self, reportdata):
"""Fill a report with approrpiate HID properties/values."""
reportdata.transducerserialnumber = self.serial & 0xFFFFFFFF
reportdata.serialhi = (self.serial >> 32) & 0xFFFFFFFF
reportdata.tooltype = self.tooltype
@attr.s
class PhysRange:
"""
Range of HID physical values, with units.
"""
unit = attr.ib()
min_size = attr.ib()
max_size = attr.ib()
CENTIMETER = HidUnit.from_string("SILinear: cm")
DEGREE = HidUnit.from_string("EnglishRotation: deg")
def contains(self, field):
"""
Check if the physical size of the provided field is in range.
Compare the physical size described by the provided HID field
against the range of sizes described by this object. This is
an exclusive range comparison (e.g. 0 cm is not within the
range 0 cm - 5 cm) and exact unit comparison (e.g. 1 inch is
not within the range 0 cm - 5 cm).
"""
phys_size = (field.physical_max - field.physical_min) * 10 ** (field.unit_exp)
return (
field.unit == self.unit.value
and phys_size > self.min_size
and phys_size < self.max_size
)
class BaseTablet(base.UHIDTestDevice):
"""
Skeleton object for all kinds of tablet devices.
"""
def __init__(self, rdesc, name=None, info=None):
assert rdesc is no