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"""USB echo gadget module.
6
7This gadget has pairs of IN/OUT endpoints that echo packets back to the host.
8"""
9
10import math
11import struct
12import uuid
13
14import gadget
15import usb_constants
16import usb_descriptors
17
18
19class EchoGadget(gadget.Gadget):
20  """Echo gadget.
21  """
22
23  def __init__(self):
24    """Create an echo gadget.
25    """
26    device_desc = usb_descriptors.DeviceDescriptor(
27        idVendor=usb_constants.VendorID.GOOGLE,
28        idProduct=usb_constants.ProductID.GOOGLE_ECHO_GADGET,
29        bcdUSB=0x0200,
30        iManufacturer=1,
31        iProduct=2,
32        iSerialNumber=3,
33        bcdDevice=0x0100)
34
35    fs_config_desc = usb_descriptors.ConfigurationDescriptor(
36        bmAttributes=0x80,
37        MaxPower=50)
38    fs_intr_interface_desc = usb_descriptors.InterfaceDescriptor(
39        bInterfaceNumber=0,
40        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
41        bInterfaceSubClass=0,
42        bInterfaceProtocol=0,
43        iInterface=4,
44    )
45    fs_intr_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
46        bEndpointAddress=0x01,
47        bmAttributes=usb_constants.TransferType.INTERRUPT,
48        wMaxPacketSize=64,
49        bInterval=1  # 1ms
50    ))
51    fs_intr_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
52        bEndpointAddress=0x81,
53        bmAttributes=usb_constants.TransferType.INTERRUPT,
54        wMaxPacketSize=64,
55        bInterval=1  # 1ms
56    ))
57    fs_config_desc.AddInterface(fs_intr_interface_desc)
58
59    fs_bulk_interface_desc = usb_descriptors.InterfaceDescriptor(
60        bInterfaceNumber=1,
61        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
62        bInterfaceSubClass=0,
63        bInterfaceProtocol=0,
64        iInterface=5
65    )
66    fs_bulk_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
67        bEndpointAddress=0x02,
68        bmAttributes=usb_constants.TransferType.BULK,
69        wMaxPacketSize=64,
70        bInterval=0
71    ))
72    fs_bulk_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
73        bEndpointAddress=0x82,
74        bmAttributes=usb_constants.TransferType.BULK,
75        wMaxPacketSize=64,
76        bInterval=0
77    ))
78    fs_config_desc.AddInterface(fs_bulk_interface_desc)
79
80    fs_config_desc.AddInterface(usb_descriptors.InterfaceDescriptor(
81        bInterfaceNumber=2,
82        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
83        bInterfaceSubClass=0,
84        bInterfaceProtocol=0,
85        iInterface=6
86    ))
87    fs_isoc_interface_desc = usb_descriptors.InterfaceDescriptor(
88        bInterfaceNumber=2,
89        bAlternateSetting=1,
90        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
91        bInterfaceSubClass=0,
92        bInterfaceProtocol=0,
93        iInterface=6
94    )
95    fs_isoc_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
96        bEndpointAddress=0x03,
97        bmAttributes=usb_constants.TransferType.ISOCHRONOUS,
98        wMaxPacketSize=1023,
99        bInterval=1  # 1ms
100    ))
101    fs_isoc_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
102        bEndpointAddress=0x83,
103        bmAttributes=usb_constants.TransferType.ISOCHRONOUS,
104        wMaxPacketSize=1023,
105        bInterval=1  # 1ms
106    ))
107    fs_config_desc.AddInterface(fs_isoc_interface_desc)
108
109    hs_config_desc = usb_descriptors.ConfigurationDescriptor(
110        bmAttributes=0x80,
111        MaxPower=50)
112
113    hs_intr_interface_desc = usb_descriptors.InterfaceDescriptor(
114        bInterfaceNumber=0,
115        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
116        bInterfaceSubClass=0,
117        bInterfaceProtocol=0,
118        iInterface=4
119    )
120    hs_intr_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
121        bEndpointAddress=0x01,
122        bmAttributes=usb_constants.TransferType.INTERRUPT,
123        wMaxPacketSize=64,
124        bInterval=4  # 1ms
125    ))
126    hs_intr_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
127        bEndpointAddress=0x81,
128        bmAttributes=usb_constants.TransferType.INTERRUPT,
129        wMaxPacketSize=64,
130        bInterval=4  # 1ms
131    ))
132    hs_config_desc.AddInterface(hs_intr_interface_desc)
133
134    hs_bulk_interface_desc = usb_descriptors.InterfaceDescriptor(
135        bInterfaceNumber=1,
136        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
137        bInterfaceSubClass=0,
138        bInterfaceProtocol=0,
139        iInterface=5
140    )
141    hs_bulk_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
142        bEndpointAddress=0x02,
143        bmAttributes=usb_constants.TransferType.BULK,
144        wMaxPacketSize=512,
145        bInterval=0
146    ))
147    hs_bulk_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
148        bEndpointAddress=0x82,
149        bmAttributes=usb_constants.TransferType.BULK,
150        wMaxPacketSize=512,
151        bInterval=0
152    ))
153    hs_config_desc.AddInterface(hs_bulk_interface_desc)
154
155    hs_config_desc.AddInterface(usb_descriptors.InterfaceDescriptor(
156        bInterfaceNumber=2,
157        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
158        bInterfaceSubClass=0,
159        bInterfaceProtocol=0,
160        iInterface=6
161    ))
162    hs_isoc_interface_desc = usb_descriptors.InterfaceDescriptor(
163        bInterfaceNumber=2,
164        bAlternateSetting=1,
165        bInterfaceClass=usb_constants.DeviceClass.VENDOR,
166        bInterfaceSubClass=0,
167        bInterfaceProtocol=0,
168        iInterface=6
169    )
170    hs_isoc_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
171        bEndpointAddress=0x03,
172        bmAttributes=usb_constants.TransferType.ISOCHRONOUS,
173        wMaxPacketSize=1024,
174        bInterval=4  # 1ms
175    ))
176    hs_isoc_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
177        bEndpointAddress=0x83,
178        bmAttributes=usb_constants.TransferType.ISOCHRONOUS,
179        wMaxPacketSize=1024,
180        bInterval=4  # 1ms
181    ))
182    hs_config_desc.AddInterface(hs_isoc_interface_desc)
183
184    super(EchoGadget, self).__init__(
185        device_desc, fs_config_desc, hs_config_desc)
186    self.AddStringDescriptor(1, 'Google Inc.')
187    self.AddStringDescriptor(2, 'Echo Gadget')
188    self.AddStringDescriptor(3, '{:06X}'.format(uuid.getnode()))
189    self.AddStringDescriptor(4, 'Interrupt Echo')
190    self.AddStringDescriptor(5, 'Bulk Echo')
191    self.AddStringDescriptor(6, 'Isochronous Echo')
192
193  def ReceivePacket(self, endpoint, data):
194    """Echo a packet back to the host.
195
196    Args:
197      endpoint: Incoming endpoint (must be an OUT pipe).
198      data: Packet data.
199    """
200    assert endpoint & usb_constants.Dir.IN == 0
201
202    self.SendPacket(endpoint | usb_constants.Dir.IN, data)
203
204def RegisterHandlers():
205  """Registers web request handlers with the application server."""
206
207  import server
208  from tornado import web
209
210  class WebConfigureHandler(web.RequestHandler):
211
212    def post(self):
213      server.SwitchGadget(EchoGadget())
214
215  server.app.add_handlers('.*$', [
216      (r'/echo/configure', WebConfigureHandler),
217  ])
218