8
8
split_bmRequestType ,
9
9
EP_IN_FLAG ,
10
10
STAGE_SETUP ,
11
+ STAGE_DATA ,
11
12
REQ_TYPE_STANDARD ,
12
13
REQ_TYPE_CLASS ,
13
14
)
@@ -43,6 +44,7 @@ def __init__(
43
44
self ,
44
45
report_descriptor ,
45
46
extra_descriptors = [],
47
+ set_report_buf = None ,
46
48
protocol = _INTERFACE_PROTOCOL_NONE ,
47
49
interface_str = None ,
48
50
):
@@ -57,17 +59,34 @@ def __init__(
57
59
# descriptors, to append after the mandatory report descriptor. Most
58
60
# HID devices do not use these.
59
61
#
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
+ #
60
68
# - protocol can be set to a specific value as per HID v1.11 section 4.3 Protocols, p9.
61
69
#
62
70
# - interface_str is an optional string descriptor to associate with the HID USB interface.
63
71
super ().__init__ (_INTERFACE_CLASS , _INTERFACE_SUBCLASS_NONE , protocol , interface_str )
64
72
self .extra_descriptors = extra_descriptors
65
73
self .report_descriptor = report_descriptor
74
+ self ._set_report_buf = set_report_buf
66
75
self ._int_ep = None # set during enumeration
67
76
68
77
def get_report (self ):
69
78
return False
70
79
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
+
71
90
def send_report (self , report_data ):
72
91
# Helper function to send a HID report in the typical USB interrupt
73
92
# endpoint associated with a HID interface. return
@@ -115,36 +134,63 @@ def get_hid_descriptor(self):
115
134
116
135
def handle_interface_control_xfer (self , stage , request ):
117
136
# Handle standard and class-specific interface control transfers for HID devices.
118
- bmRequestType , bRequest , wValue , _ , _ = request
137
+ bmRequestType , bRequest , wValue , _ , wLength = request
119
138
120
139
recipient , req_type , _ = split_bmRequestType (bmRequestType )
121
140
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
148
194
149
195
150
196
# Basic 3-button mouse HID Report Descriptor.
0 commit comments