1# Copyright (C) 2009-2014 Wander Lairson Costa
2#
3# The following terms apply to all files associated
4# with the software unless explicitly disclaimed in individual files.
5#
6# The authors hereby grant permission to use, copy, modify, distribute,
7# and license this software and its documentation for any purpose, provided
8# that existing copyright notices are retained in all copies and that this
9# notice is included verbatim in any distributions. No written agreement,
10# license, or royalty fee is required for any of the authorized uses.
11# Modifications to this software may be copyrighted by their authors
12# and need not follow the licensing terms described here, provided that
13# the new terms are clearly indicated on the first page of each file where
14# they apply.
15#
16# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
17# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
18# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
19# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
20# POSSIBILITY OF SUCH DAMAGE.
21#
22# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
23# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
24# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
25# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
26# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
27# MODIFICATIONS.
28
29import utils
30import unittest
31import devinfo
32import usb.util
33import usb.backend.libusb0 as libusb0
34import usb.backend.libusb1 as libusb1
35import usb.backend.openusb as openusb
36from usb._debug import methodtrace
37import time
38import sys
39
40class BackendTest(unittest.TestCase):
41    @methodtrace(utils.logger)
42    def __init__(self, backend):
43        unittest.TestCase.__init__(self)
44        self.backend = backend
45
46    @methodtrace(utils.logger)
47    def runTest(self):
48        try:
49            self.test_enumerate_devices()
50            self.test_get_device_descriptor()
51            self.test_get_configuration_descriptor()
52            self.test_get_interface_descriptor()
53            self.test_get_endpoint_descriptor()
54            self.test_open_device()
55            self.test_set_configuration()
56            self.test_claim_interface()
57            self.test_set_interface_altsetting()
58            self.test_clear_halt()
59            self.test_bulk_write_read()
60            self.test_intr_write_read()
61            self.test_iso_write_read()
62            self.test_ctrl_transfer()
63        except:
64            # do this to not influence other tests upon error
65            intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0)
66            self.backend.release_interface(self.handle, intf.bInterfaceNumber)
67            self.backend.close_device(self.handle)
68            raise
69        self.test_release_interface()
70        #self.test_reset_device()
71        self.test_close_device()
72        #utils.delay_after_reset()
73
74    @methodtrace(utils.logger)
75    def test_enumerate_devices(self):
76        for d in self.backend.enumerate_devices():
77            desc = self.backend.get_device_descriptor(d)
78            if desc.idVendor == devinfo.ID_VENDOR and desc.idProduct == devinfo.ID_PRODUCT:
79                self.dev = d
80                return
81        self.fail('PyUSB test device not found')
82
83    @methodtrace(utils.logger)
84    def test_get_device_descriptor(self):
85        dsc = self.backend.get_device_descriptor(self.dev)
86        self.assertEqual(dsc.bLength, 18)
87        self.assertEqual(dsc.bDescriptorType, usb.util.DESC_TYPE_DEVICE)
88        self.assertEqual(dsc.bcdUSB, 0x0200)
89        self.assertEqual(dsc.idVendor, devinfo.ID_VENDOR)
90        self.assertEqual(dsc.idProduct, devinfo.ID_PRODUCT)
91        self.assertEqual(dsc.bcdDevice, 0x0001)
92        self.assertEqual(dsc.iManufacturer, 0x01)
93        self.assertEqual(dsc.iProduct, 0x02)
94        self.assertEqual(dsc.iSerialNumber, 0x03)
95        self.assertEqual(dsc.bNumConfigurations, 0x01)
96        self.assertEqual(dsc.bMaxPacketSize0, 8)
97        self.assertEqual(dsc.bDeviceClass, 0x00)
98        self.assertEqual(dsc.bDeviceSubClass, 0x00)
99        self.assertEqual(dsc.bDeviceProtocol, 0x00)
100
101    @methodtrace(utils.logger)
102    def test_get_configuration_descriptor(self):
103        cfg = self.backend.get_configuration_descriptor(self.dev, 0)
104        self.assertEqual(cfg.bLength, 9)
105        self.assertEqual(cfg.bDescriptorType, usb.util.DESC_TYPE_CONFIG)
106        self.assertEqual(cfg.wTotalLength, 78)
107        self.assertEqual(cfg.bNumInterfaces, 0x01)
108        self.assertEqual(cfg.bConfigurationValue, 0x01)
109        self.assertEqual(cfg.iConfiguration, 0x00)
110        self.assertEqual(cfg.bmAttributes, 0xC0)
111        self.assertEqual(cfg.bMaxPower, 50)
112
113    @methodtrace(utils.logger)
114    def test_get_interface_descriptor(self):
115        intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0)
116        self.assertEqual(intf.bLength, 9)
117        self.assertEqual(intf.bDescriptorType, usb.util.DESC_TYPE_INTERFACE)
118        self.assertEqual(intf.bInterfaceNumber, 0)
119        self.assertEqual(intf.bAlternateSetting, 0)
120        self.assertEqual(intf.bNumEndpoints, 2)
121        self.assertEqual(intf.bInterfaceClass, 0x00)
122        self.assertEqual(intf.bInterfaceSubClass, 0x00)
123        self.assertEqual(intf.bInterfaceProtocol, 0x00)
124        self.assertEqual(intf.iInterface, 0x00)
125
126    @methodtrace(utils.logger)
127    def test_get_endpoint_descriptor(self):
128        ep = self.backend.get_endpoint_descriptor(self.dev, 0, 0, 0, 0)
129        self.assertEqual(ep.bLength, 7)
130        self.assertEqual(ep.bDescriptorType, usb.util.DESC_TYPE_ENDPOINT)
131        self.assertEqual(ep.bEndpointAddress, 0x01)
132        self.assertEqual(ep.bmAttributes, 0x02)
133        self.assertEqual(ep.wMaxPacketSize, 16)
134        self.assertEqual(ep.bInterval, 0)
135
136    @methodtrace(utils.logger)
137    def test_open_device(self):
138        self.handle = self.backend.open_device(self.dev)
139
140    @methodtrace(utils.logger)
141    def test_close_device(self):
142        self.backend.close_device(self.handle)
143
144    @methodtrace(utils.logger)
145    def test_set_configuration(self):
146        cfg = self.backend.get_configuration_descriptor(self.dev, 0)
147        self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
148
149    @methodtrace(utils.logger)
150    def test_set_interface_altsetting(self):
151        intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0)
152        self.backend.set_interface_altsetting(self.handle,
153                                              intf.bInterfaceNumber,
154                                              intf.bAlternateSetting)
155
156    @methodtrace(utils.logger)
157    def test_claim_interface(self):
158        intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0)
159        self.backend.claim_interface(self.handle, intf.bInterfaceNumber)
160
161    @methodtrace(utils.logger)
162    def test_release_interface(self):
163        intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0)
164        self.backend.release_interface(self.handle, intf.bInterfaceNumber)
165
166    @methodtrace(utils.logger)
167    def test_bulk_write_read(self):
168        self.backend.set_interface_altsetting(
169                self.handle,
170                0,
171                devinfo.INTF_BULK
172            )
173
174        self.__write_read(
175                self.backend.bulk_write,
176                self.backend.bulk_read,
177                devinfo.EP_BULK
178            )
179
180    @methodtrace(utils.logger)
181    def test_intr_write_read(self):
182        self.backend.set_interface_altsetting(
183                self.handle,
184                0,
185                devinfo.INTF_INTR
186            )
187
188        self.__write_read(
189                self.backend.intr_write,
190                self.backend.intr_read,
191                devinfo.EP_INTR
192            )
193
194    @methodtrace(utils.logger)
195    def test_iso_write_read(self):
196        if utils.is_iso_test_allowed():
197            self.backend.set_interface_altsetting(
198                self.handle,
199                0,
200                devinfo.INTF_ISO)
201
202            self.__write_read(
203                self.backend.iso_write,
204                self.backend.iso_read,
205                devinfo.EP_ISO,
206                64)
207
208    @methodtrace(utils.logger)
209    def test_clear_halt(self):
210        self.backend.clear_halt(self.handle, 0x01)
211        self.backend.clear_halt(self.handle, 0x81)
212
213    @methodtrace(utils.logger)
214    def test_ctrl_transfer(self):
215        for data in (utils.get_array_data1(), utils.get_array_data2()):
216            length = len(data) * data.itemsize
217            buff = usb.util.create_buffer(length)
218
219            ret = self.backend.ctrl_transfer(self.handle,
220                                             0x40,
221                                             devinfo.PICFW_SET_VENDOR_BUFFER,
222                                             0,
223                                             0,
224                                             data,
225                                             1000)
226            self.assertEqual(ret,
227                             length,
228                             'Failed to write data: ' + str(data) + ', ' + str(length) + ' != ' + str(ret))
229
230            ret = self.backend.ctrl_transfer(self.handle,
231                                             0xC0,
232                                             devinfo.PICFW_GET_VENDOR_BUFFER,
233                                             0,
234                                             0,
235                                             buff,
236                                             1000)
237
238            self.assertEqual(ret, length)
239
240            self.assertEqual(buff,
241                             data,
242                             'Failed to read data: ' + str(data) + ' != ' + str(ret))
243
244    @methodtrace(utils.logger)
245    def test_reset_device(self):
246        self.backend.reset_device(self.handle)
247
248    def __write_read(self, write_fn, read_fn, ep, length = 8):
249        intf = self.backend.get_interface_descriptor(self.dev, 0, 0, 0).bInterfaceNumber
250        for data in (utils.get_array_data1(length), utils.get_array_data2(length)):
251            length = len(data) * data.itemsize
252
253            try:
254                ret = write_fn(self.handle, ep, intf, data, 1000)
255            except NotImplementedError:
256                return
257
258            self.assertEqual(ret,
259                             length,
260                             'Failed to write data: ' + \
261                                str(data) + \
262                                ', in EP = ' + \
263                                str(ep))
264
265            buff = usb.util.create_buffer(length)
266
267            try:
268                ret = read_fn(self.handle, ep | usb.util.ENDPOINT_IN, intf, buff, 1000)
269            except NotImplementedError:
270                return
271
272            self.assertEqual(ret, length, str(ret) + ' != ' + str(length))
273
274            self.assertEqual(buff,
275                             data,
276                             'Failed to read data: ' + \
277                                str(data) + \
278                                ', in EP = ' + \
279                                str(ep))
280
281            if utils.is_windows():
282                time.sleep(0.5)
283
284def get_suite():
285    suite = unittest.TestSuite()
286    for m in (libusb1, libusb0, openusb):
287        b = m.get_backend()
288        if b is not None and utils.find_my_device(b):
289            utils.logger.info('Adding %s(%s) to test suite...', BackendTest.__name__, m.__name__)
290            suite.addTest(BackendTest(b))
291        else:
292            utils.logger.warning('%s(%s) is not available', BackendTest.__name__, m.__name__)
293    return suite
294
295if __name__ == '__main__':
296    utils.run_tests(get_suite())
297