1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5
6"""Utility functions for constructing HID report descriptors.
7"""
8
9import struct
10
11import hid_constants
12
13
14def ReportDescriptor(*items):
15  return ''.join(items)
16
17
18def _PackItem(tag, typ, value=0, force_length=0):
19  """Pack a multibyte value.
20
21  See Device Class Definition for Human Interface Devices (HID) Version 1.11
22  section 5.8.
23
24  Args:
25    tag: Item tag.
26    typ: Item type.
27    value: Item value.
28    force_length: Force packing to a specific width.
29
30  Returns:
31    Packed string.
32  """
33  if value == 0 and force_length <= 0:
34    return struct.pack('<B', tag << 4 | typ << 2 | 0)
35  elif value <= 0xff and force_length <= 1:
36    return struct.pack('<BB', tag << 4 | typ << 2 | 1, value)
37  elif value <= 0xffff and force_length <= 2:
38    return struct.pack('<BH', tag << 4 | typ << 2 | 2, value)
39  elif value <= 0xffffffff and force_length <= 4:
40    return struct.pack('<BI', tag << 4 | typ << 2 | 3, value)
41  else:
42    raise NotImplementedError('Long items are not implemented.')
43
44
45def _DefineItem(name, tag, typ):
46  """Create a function which encodes a HID item.
47
48  Args:
49    name: Function name.
50    tag: Item tag.
51    typ: Item type.
52
53  Returns:
54    A function which encodes a HID item of the given type.
55  """
56  assert tag >= 0 and tag <= 0xF
57  assert typ >= 0 and typ <= 3
58
59  def EncodeItem(value=0, force_length=0):
60    return _PackItem(tag, typ, value, force_length)
61
62  EncodeItem.__name__ = name
63  return EncodeItem
64
65
66def _DefineMainItem(name, tag):
67  """Create a function which encodes a HID Main item.
68
69  See Device Class Definition for Human Interface Devices (HID) Version 1.11
70  section 6.2.2.4.
71
72  Args:
73    name: Function name.
74    tag: Item tag.
75
76  Returns:
77    A function which encodes a HID item of the given type.
78
79  Raises:
80    ValueError: If the tag value is out of range.
81  """
82  assert tag >= 0 and tag <= 0xF
83
84  def EncodeMainItem(*properties):
85    value = 0
86    for bit, is_set in properties:
87      if is_set:
88        value |= 1 << bit
89    return _PackItem(tag, hid_constants.Scope.MAIN, value, force_length=1)
90
91  EncodeMainItem.__name__ = name
92  return EncodeMainItem
93
94Input = _DefineMainItem('Input', 8)
95Output = _DefineMainItem('Output', 9)
96Feature = _DefineMainItem('Feature', 11)
97
98# Input, Output and Feature Item Properties
99#
100# See Device Class Definition for Human Interface Devices (HID) Version 1.11
101# section 6.2.2.5.
102Data = (0, False)
103Constant = (0, True)
104Array = (1, False)
105Variable = (1, True)
106Absolute = (2, False)
107Relative = (2, True)
108NoWrap = (3, False)
109Wrap = (3, True)
110Linear = (4, False)
111NonLinear = (4, True)
112PreferredState = (5, False)
113NoPreferred = (5, True)
114NoNullPosition = (6, False)
115NullState = (6, True)
116NonVolatile = (7, False)
117Volatile = (7, True)
118BitField = (8, False)
119BufferedBytes = (8, True)
120
121
122def Collection(typ, *items):
123  start = struct.pack('<BB', 0xA1, typ)
124  end = struct.pack('<B', 0xC0)
125  return start + ''.join(items) + end
126
127# Global Items
128#
129# See Device Class Definition for Human Interface Devices (HID) Version 1.11
130# section 6.2.2.7.
131UsagePage = _DefineItem('UsagePage', 0, hid_constants.Scope.GLOBAL)
132LogicalMinimum = _DefineItem('LogicalMinimum', 1, hid_constants.Scope.GLOBAL)
133LogicalMaximum = _DefineItem('LogicalMaximum', 2, hid_constants.Scope.GLOBAL)
134PhysicalMinimum = _DefineItem('PhysicalMinimum', 3, hid_constants.Scope.GLOBAL)
135PhysicalMaximum = _DefineItem('PhysicalMaximum', 4, hid_constants.Scope.GLOBAL)
136UnitExponent = _DefineItem('UnitExponent', 5, hid_constants.Scope.GLOBAL)
137Unit = _DefineItem('Unit', 6, hid_constants.Scope.GLOBAL)
138ReportSize = _DefineItem('ReportSize', 7, hid_constants.Scope.GLOBAL)
139ReportID = _DefineItem('ReportID', 8, hid_constants.Scope.GLOBAL)
140ReportCount = _DefineItem('ReportCount', 9, hid_constants.Scope.GLOBAL)
141Push = _DefineItem('Push', 10, hid_constants.Scope.GLOBAL)
142Pop = _DefineItem('Pop', 11, hid_constants.Scope.GLOBAL)
143
144# Local Items
145#
146# See Device Class Definition for Human Interface Devices (HID) Version 1.11
147# section 6.2.2.8.
148Usage = _DefineItem('Usage', 0, hid_constants.Scope.LOCAL)
149UsageMinimum = _DefineItem('UsageMinimum', 1, hid_constants.Scope.LOCAL)
150UsageMaximum = _DefineItem('UsageMaximum', 2, hid_constants.Scope.LOCAL)
151DesignatorIndex = _DefineItem('DesignatorIndex', 3, hid_constants.Scope.LOCAL)
152DesignatorMinimum = _DefineItem('DesignatorMinimum', 4,
153                                hid_constants.Scope.LOCAL)
154DesignatorMaximum = _DefineItem('DesignatorMaximum', 5,
155                                hid_constants.Scope.LOCAL)
156StringIndex = _DefineItem('StringIndex', 7, hid_constants.Scope.LOCAL)
157StringMinimum = _DefineItem('StringMinimum', 8, hid_constants.Scope.LOCAL)
158StringMaximum = _DefineItem('StringMaximum', 9, hid_constants.Scope.LOCAL)
159Delimiter = _DefineItem('Delimiter', 10, hid_constants.Scope.LOCAL)
160