Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usb_hid.py Source File

usb_hid.py

00001 #
00002 # DAPLink Interface Firmware
00003 # Copyright (c) 2016-2016, ARM Limited, All Rights Reserved
00004 # SPDX-License-Identifier: Apache-2.0
00005 #
00006 # Licensed under the Apache License, Version 2.0 (the "License"); you may
00007 # not use this file except in compliance with the License.
00008 # You may obtain a copy of the License at
00009 #
00010 # http://www.apache.org/licenses/LICENSE-2.0
00011 #
00012 # Unless required by applicable law or agreed to in writing, software
00013 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00014 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 # See the License for the specific language governing permissions and
00016 # limitations under the License.
00017 #
00018 
00019 import usb.util
00020 
00021 
00022 class USBHid (object):
00023     """Wrapper class for a HID usb device"""
00024 
00025     # HID commands documented in
00026     # Device Class Definition for Human Interface Devices (HID)
00027 
00028     CLASS_HID = 0x3
00029 
00030     DESC_TYPE_HID = 0x21
00031     DESC_TYPE_REPORT = 0x22
00032     DESC_TYPE_PHYSICAL = 0x23
00033 
00034     REPORT_TYPE_INPUT = 1
00035     REPORT_TYPE_OUTPUT = 2
00036     REPORT_TYPE_FEATURE = 3
00037 
00038     def __init__(self, device):
00039         self._dev  = device
00040         self._if  = None
00041         self.ep_in  = None
00042         self.ep_out  = None
00043         self._locked  = False
00044         self.timeout  = 10 * 1000
00045 
00046         # Find interface
00047         for interface in device.get_active_configuration():
00048             if interface.bInterfaceClass == USBHid.CLASS_HID:
00049                 assert self._if  is None
00050                 self._if  = interface
00051         assert self._if  is not None
00052 
00053         # Find endpoints
00054         for endpoint in self._if :
00055             if endpoint.bEndpointAddress & 0x80:
00056                 assert self.ep_in  is None
00057                 self.ep_in  = endpoint
00058             else:
00059                 assert self.ep_out  is None
00060                 self.ep_out  = endpoint
00061         assert self.ep_in  is not None
00062         # Endpoint out can be None
00063 
00064     def lock (self):
00065         """Acquire exclisive access to HID"""
00066         assert not self._locked 
00067 
00068         num = self._if .bInterfaceNumber
00069         try:
00070             if self._dev .is_kernel_driver_active(num):
00071                 self._dev .detach_kernel_driver(num)
00072         except NotImplementedError:
00073             pass
00074         except usb.core.USBError:
00075             pass
00076         usb.util.claim_interface(self._dev , num)
00077         self._locked  = True
00078 
00079     def unlock (self):
00080         """Release exclusive access to HID"""
00081         assert self._locked 
00082 
00083         num = self._if .bInterfaceNumber
00084         usb.util.release_interface(self._dev , num)
00085         try:
00086             self._dev .attach_kernel_driver(num)
00087         except NotImplementedError:
00088             pass
00089         except usb.core.USBError:
00090             pass
00091         self._locked  = False
00092 
00093     def set_idle (self, report_id=0, duration=0):
00094         """Send a HID Set_Idle request"""
00095         assert self._locked 
00096         assert report_id & ~0xFF == 0
00097         assert duration & ~0xFF == 0
00098 
00099         request_type = 0x21
00100         request = 0x0A                                  # SET_IDLE
00101         value = ((duration << 8) | (report_id << 0))    # Report and duration
00102         index = self._if .bInterfaceNumber       # HID interface
00103         self._dev .ctrl_transfer(request_type, request, value, index, None)
00104 
00105     def get_descriptor (self, desc_type, index):
00106         """Get the given descriptor"""
00107         assert self._locked 
00108         assert desc_type & ~0xFF == 0
00109         assert index & ~0xFF == 0
00110 
00111         request_type = 0x81
00112         request = 0x6                             # GET_DESCRIPTOR
00113         value = (((index & 0xFF) << (0 * 8)) |
00114                  ((desc_type & 0xFF) << (1 * 8)))  # Descriptor type and index
00115         index = self._if .bInterfaceNumber          # HID interface
00116         return self._dev .ctrl_transfer(request_type, request,
00117                                        value, index, 256)
00118 
00119     def set_report_req (self, data, report_type=REPORT_TYPE_OUTPUT,
00120                        report_id=0):
00121         """Set a report of the given type"""
00122         assert self._locked 
00123         assert report_type & ~0xFF == 0
00124         assert report_id & ~0xFF == 0
00125 
00126         request_type = 0x21
00127         request = 0x09                          # SET_REPORT
00128         value = ((report_type << 8) |
00129                  (report_id << 0))              # Report and duration
00130         index = self._if .bInterfaceNumber       # HID interface
00131         self._dev .ctrl_transfer(request_type, request, value, index, data,
00132                                 self.timeout )
00133 
00134     def get_report_req (self, data_size, report_type=REPORT_TYPE_INPUT,
00135                        report_id=0):
00136         """Set a report of the given type"""
00137         assert self._locked 
00138         assert report_type & ~0xFF == 0
00139         assert report_id & ~0xFF == 0
00140 
00141         request_type = 0xA1
00142         request = 0x01                          # SET_REPORT
00143         value = ((report_type << 8) |
00144                  (report_id << 0))              # Report and duration
00145         index = self._if .bInterfaceNumber       # HID interface
00146         return self._dev .ctrl_transfer(request_type, request, value, index,
00147                                        data_size, self.timeout )
00148 
00149     def set_report (self, data):
00150         """Send report to the device"""
00151         assert self._locked 
00152 
00153         if self.ep_out  is None:
00154             self.set_report_req (data)
00155         else:
00156             self.ep_out .write(data, 10 * 1000)
00157 
00158     def get_report (self, size):
00159         """Read report from the device"""
00160         assert self._locked 
00161 
00162         return self.ep_in .read(size, 10 * 1000)