88 split_bmRequestType ,
99 EP_IN_FLAG ,
1010 STAGE_SETUP ,
11+ STAGE_DATA ,
1112 REQ_TYPE_STANDARD ,
1213 REQ_TYPE_CLASS ,
1314)
@@ -43,6 +44,7 @@ def __init__(
4344 self ,
4445 report_descriptor ,
4546 extra_descriptors = [],
47+ set_report_buf = None ,
4648 protocol = _INTERFACE_PROTOCOL_NONE ,
4749 interface_str = None ,
4850 ):
@@ -57,17 +59,34 @@ def __init__(
5759 # descriptors, to append after the mandatory report descriptor. Most
5860 # HID devices do not use these.
5961 #
62+ # - set_report_buf is an optional writable buffer object (i.e.
63+ # bytearray), where SET_REPORT requests from the host can be
64+ # written. Only necessary if the report_descriptor contains Output
65+ # entries. If set, the size must be at least the size of the largest
66+ # Output entry.
67+ #
6068 # - protocol can be set to a specific value as per HID v1.11 section 4.3 Protocols, p9.
6169 #
6270 # - interface_str is an optional string descriptor to associate with the HID USB interface.
6371 super ().__init__ (_INTERFACE_CLASS , _INTERFACE_SUBCLASS_NONE , protocol , interface_str )
6472 self .extra_descriptors = extra_descriptors
6573 self .report_descriptor = report_descriptor
74+ self ._set_report_buf = set_report_buf
6675 self ._int_ep = None # set during enumeration
6776
6877 def get_report (self ):
6978 return False
7079
80+ def handle_set_report (self , report_data , report_id , report_type ):
81+ # Override this function in order to handle SET REPORT requests from the host,
82+ # where it sends data to the HID device.
83+ #
84+ # This function will only be called if the Report descriptor contains at least one Output entry,
85+ # and the set_report_buf argument is provided to the constructor.
86+ #
87+ # Return True to complete the control transfer normally, False to abort it.
88+ return True
89+
7190 def send_report (self , report_data ):
7291 # Helper function to send a HID report in the typical USB interrupt
7392 # endpoint associated with a HID interface. return
@@ -115,36 +134,63 @@ def get_hid_descriptor(self):
115134
116135 def handle_interface_control_xfer (self , stage , request ):
117136 # Handle standard and class-specific interface control transfers for HID devices.
118- bmRequestType , bRequest , wValue , _ , _ = request
137+ bmRequestType , bRequest , wValue , _ , wLength = request
119138
120139 recipient , req_type , _ = split_bmRequestType (bmRequestType )
121140
122- if stage != STAGE_SETUP :
123- return True # allow request DATA/ACK stages to complete normally
124-
125- if req_type == REQ_TYPE_STANDARD :
126- # HID Spec p48: 7.1 Standard Requests
127- if bRequest == _REQ_CONTROL_GET_DESCRIPTOR :
128- desc_type = wValue >> 8
129- if desc_type == _DESC_HID_TYPE :
130- return self .get_hid_descriptor ()
131- if desc_type == _DESC_REPORT_TYPE :
132- return self .report_descriptor
133- elif req_type == REQ_TYPE_CLASS :
134- # HID Spec p50: 7.2 Class-Specific Requests
135- if bRequest == _REQ_CONTROL_GET_REPORT :
136- return False # Unsupported for now
137- if bRequest == _REQ_CONTROL_GET_IDLE :
138- return bytes ([self .idle_rate ])
139- if bRequest == _REQ_CONTROL_GET_PROTOCOL :
140- return bytes ([self .protocol ])
141- if bRequest == _REQ_CONTROL_SET_IDLE :
142- self .idle_rate = wValue >> 8
143- return b""
144- if bRequest == _REQ_CONTROL_SET_PROTOCOL :
145- self .protocol = wValue
146- return b""
147- return False # Unsupported
141+ if stage == STAGE_SETUP :
142+ if req_type == REQ_TYPE_STANDARD :
143+ # HID Spec p48: 7.1 Standard Requests
144+ if bRequest == _REQ_CONTROL_GET_DESCRIPTOR :
145+ desc_type = wValue >> 8
146+ if desc_type == _DESC_HID_TYPE :
147+ return self .get_hid_descriptor ()
148+ if desc_type == _DESC_REPORT_TYPE :
149+ return self .report_descriptor
150+ elif req_type == REQ_TYPE_CLASS :
151+ # HID Spec p50: 7.2 Class-Specific Requests
152+ if bRequest == _REQ_CONTROL_GET_REPORT :
153+ print ("GET_REPORT?" )
154+ return False # Unsupported for now
155+ if bRequest == _REQ_CONTROL_GET_IDLE :
156+ return bytes ([self .idle_rate ])
157+ if bRequest == _REQ_CONTROL_GET_PROTOCOL :
158+ return bytes ([self .protocol ])
159+ if bRequest == _REQ_CONTROL_SET_IDLE :
160+ self .idle_rate = wValue >> 8
161+ return b""
162+ if bRequest == _REQ_CONTROL_SET_PROTOCOL :
163+ self .protocol = wValue
164+ return b""
165+ if bRequest == _REQ_CONTROL_SET_REPORT :
166+ # Return the _set_report_buf to be filled with the
167+ # report data
168+ if not self ._set_report_buf :
169+ return False
170+ elif wLength >= len (self ._set_report_buf ):
171+ # Saves an allocation if the size is exactly right (or will be a short read)
172+ return self ._set_report_buf
173+ else :
174+ # Otherwise, need to wrap the buffer in a memoryview of the correct length
175+ #
176+ # TODO: check this is correct, maybe TinyUSB won't mind if we ask for more
177+ # bytes than the host has offered us.
178+ return memoryview (self ._set_report_buf )[:wLength ]
179+ return False # Unsupported
180+
181+ if stage == STAGE_DATA :
182+ if req_type == REQ_TYPE_CLASS :
183+ if bRequest == _REQ_CONTROL_SET_REPORT and self ._set_report_buf :
184+ report_id = wValue & 0xFF
185+ report_type = wValue >> 8
186+ report_data = self ._set_report_buf
187+ if wLength < len (report_data ):
188+ # as above, need to truncate the buffer if we read less
189+ # bytes than what was provided
190+ report_data = memoryview (self ._set_report_buf )[:wLength ]
191+ self .handle_set_report (report_data , report_id , report_type )
192+
193+ return True # allow DATA/ACK stages to complete normally
148194
149195
150196# Basic 3-button mouse HID Report Descriptor.
0 commit comments