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"""A HID-class echo device.
6
7This module provides a HID feature and HID device that can be used as an
8echo test for HID drivers. The device exposes vendor-specific input, output
9and feature usages that transmit 8 bytes of data. Data written sent as an
10output report is echoed as an input report. The value of the feature report
11can be written and read with control transfers.
12"""
13
14import struct
15
16import hid_constants
17import hid_descriptors
18import hid_gadget
19import usb_constants
20
21
22class EchoFeature(hid_gadget.HidFeature):
23
24  REPORT_DESC = hid_descriptors.ReportDescriptor(
25      hid_descriptors.UsagePage(0xFF00),  # Vendor Defined
26      hid_descriptors.Usage(0),
27      hid_descriptors.Collection(
28          hid_constants.CollectionType.APPLICATION,
29          hid_descriptors.LogicalMinimum(0, force_length=1),
30          hid_descriptors.LogicalMaximum(255, force_length=2),
31          hid_descriptors.ReportSize(8),
32          hid_descriptors.ReportCount(8),
33          hid_descriptors.Usage(0),
34          hid_descriptors.Input(hid_descriptors.Data,
35                                hid_descriptors.Variable,
36                                hid_descriptors.Absolute),
37          hid_descriptors.Usage(0),
38          hid_descriptors.Output(hid_descriptors.Data,
39                                 hid_descriptors.Variable,
40                                 hid_descriptors.Absolute),
41          hid_descriptors.Usage(0),
42          hid_descriptors.Feature(hid_descriptors.Data,
43                                  hid_descriptors.Variable,
44                                  hid_descriptors.Absolute)
45      )
46  )
47
48  def __init__(self):
49    super(EchoFeature, self).__init__()
50    self._input_output_report = 0
51    self._feature_report = 0
52
53  def SetInputReport(self, data):
54    self._input_output_report, = struct.unpack('<Q', data)
55    self.SendReport(struct.pack('<Q', self._input_output_report))
56    return True
57
58  def SetOutputReport(self, data):
59    self._input_output_report, = struct.unpack('<Q', data)
60    self.SendReport(struct.pack('<Q', self._input_output_report))
61    return True
62
63  def SetFeatureReport(self, data):
64    self._feature_report, = struct.unpack('<Q', data)
65    return True
66
67  def GetInputReport(self):
68    return struct.pack('<Q', self._input_output_report)
69
70  def GetOutputReport(self):
71    return struct.pack('<Q', self._input_output_report)
72
73  def GetFeatureReport(self):
74    return struct.pack('<Q', self._feature_report)
75
76
77class EchoGadget(hid_gadget.HidGadget):
78
79  def __init__(self):
80    self._feature = EchoFeature()
81    super(EchoGadget, self).__init__(
82        report_desc=EchoFeature.REPORT_DESC,
83        features={0: self._feature},
84        packet_size=8,
85        interval_ms=1,
86        out_endpoint=True,
87        vendor_id=usb_constants.VendorID.GOOGLE,
88        product_id=usb_constants.ProductID.GOOGLE_HID_ECHO_GADGET,
89        device_version=0x0100)
90    self.AddStringDescriptor(1, 'Google Inc.')
91    self.AddStringDescriptor(2, 'HID Echo Gadget')
92
93
94def RegisterHandlers():
95  from tornado import web
96
97  class WebConfigureHandler(web.RequestHandler):
98
99    def post(self):
100      server.SwitchGadget(EchoGadget())
101
102  import server
103  server.app.add_handlers('.*$', [
104      (r'/hid_echo/configure', WebConfigureHandler),
105  ])
106