Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* MAX3421E USB Host controller configuration descriptor parser */ |
2 | #include <Spi.h> |
||
3 | #include <Max3421e.h> |
||
4 | #include <Usb.h> |
||
5 | #include "descriptor_parser.h" |
||
6 | |||
7 | #define LOBYTE(x) ((char*)(&(x)))[0] |
||
8 | #define HIBYTE(x) ((char*)(&(x)))[1] |
||
9 | #define BUFSIZE 256 //buffer size |
||
10 | #define DEVADDR 1 |
||
11 | |||
12 | #define getReportDescr( addr, ep, nbytes, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, parse_func, nak_limit ) |
||
13 | #define getReport( addr, ep, nbytes, interface, report_type, report_id, parse_func, nak_limit ) ctrlXfer( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, parse_func, nak_limit ) |
||
14 | |||
15 | /* Foeward declarations */ |
||
16 | void setup(); |
||
17 | void loop(); |
||
18 | byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit ); |
||
19 | void HIDreport_parse( uint8_t* buf, uint8_t* head, uint8_t* tail); |
||
20 | |||
21 | typedef struct { |
||
22 | uint8_t bDescriptorType; |
||
23 | uint16_t wDescriptorLength; |
||
24 | } HID_CLASS_DESCRIPTOR; |
||
25 | |||
26 | |||
27 | //typedef void (*PARSE)( int8_t*, int8_t*, int8_t ); |
||
28 | |||
29 | MAX3421E Max; |
||
30 | USB Usb; |
||
31 | |||
32 | void setup() |
||
33 | { |
||
34 | Serial.begin( 115200 ); |
||
35 | printProgStr(PSTR("\r\nStart")); |
||
36 | Max.powerOn(); |
||
37 | delay( 200 ); |
||
38 | } |
||
39 | |||
40 | void loop() |
||
41 | { |
||
42 | uint8_t rcode; |
||
43 | uint8_t tmpbyte = 0; |
||
44 | //PARSE pf = &HIDreport_parse; |
||
45 | /**/ |
||
46 | Max.Task(); |
||
47 | Usb.Task(); |
||
48 | if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) { //state configuring or higher |
||
49 | /* printing device descriptor */ |
||
50 | printProgStr(PSTR("\r\nDevice addressed... ")); |
||
51 | printProgStr(PSTR("Requesting device descriptor.")); |
||
52 | tmpbyte = getdevdescr( DEVADDR ); //number of configurations, 0 if error |
||
53 | if( tmpbyte == 0 ) { |
||
54 | printProgStr(PSTR("\r\nDevice descriptor cannot be retrieved. Program Halted\r\n")); |
||
55 | while( 1 ); //stop |
||
56 | }//if( tmpbyte |
||
57 | /* print configuration descriptors for all configurations */ |
||
58 | for( uint8_t i = 0; i < tmpbyte; i++ ) { |
||
59 | getconfdescr( DEVADDR, i ); |
||
60 | } |
||
61 | /* Stop */ |
||
62 | while( 1 ); //stop |
||
63 | } |
||
64 | } |
||
65 | |||
66 | /* Prints device descriptor. Returns number of configurations or zero if request error occured */ |
||
67 | byte getdevdescr( byte addr ) |
||
68 | { |
||
69 | USB_DEVICE_DESCRIPTOR buf; |
||
70 | byte rcode; |
||
71 | //Max.toggle( BPNT_0 ); |
||
72 | rcode = Usb.getDevDescr( addr, 0, 0x12, ( char *)&buf ); |
||
73 | if( rcode ) { |
||
74 | printProgStr( rcode_error_msg ); |
||
75 | print_hex( rcode, 8 ); |
||
76 | return( 0 ); |
||
77 | } |
||
78 | printProgStr(PSTR("\r\nDevice descriptor: \r\n")); |
||
79 | //Descriptor length |
||
80 | printProgStr( descr_len ); |
||
81 | print_hex( buf.bLength, 8 ); |
||
82 | //Descriptor type |
||
83 | // printProgStr( descr_type ); |
||
84 | // print_hex( buf.bDescriptorType, 8 ); |
||
85 | // printProgStr( descrtype_parse( buf.bDescriptorType )); |
||
86 | //USB Version |
||
87 | printProgStr(PSTR("\r\nUSB version:\t\t")); |
||
88 | Serial.print(( HIBYTE( buf.bcdUSB )), HEX ); |
||
89 | Serial.print("."); |
||
90 | Serial.print(( LOBYTE( buf.bcdUSB )), HEX ); |
||
91 | //Device class |
||
92 | printProgStr( class_str ); |
||
93 | print_hex( buf.bDeviceClass, 8 ); |
||
94 | printProgStr( classname_parse( buf.bDeviceClass )); |
||
95 | //Device Subclass |
||
96 | printProgStr( subclass_str ); |
||
97 | print_hex( buf.bDeviceSubClass, 8 ); |
||
98 | //Device Protocol |
||
99 | printProgStr( protocol_str ); |
||
100 | print_hex( buf.bDeviceProtocol, 8 ); |
||
101 | //Max.packet size |
||
102 | printProgStr( maxpktsize_str ); |
||
103 | print_hex( buf.bMaxPacketSize0, 8 ); |
||
104 | //VID |
||
105 | printProgStr(PSTR("\r\nVendor ID:\t\t")); |
||
106 | print_hex( buf.idVendor, 16 ); |
||
107 | //PID |
||
108 | printProgStr(PSTR("\r\nProduct ID:\t\t")); |
||
109 | print_hex( buf.idProduct, 16 ); |
||
110 | //Revision |
||
111 | printProgStr(PSTR("\r\nRevision ID:\t\t")); |
||
112 | print_hex( buf.bcdDevice, 16 ); |
||
113 | //Mfg.string |
||
114 | printProgStr (PSTR("\r\nMfg.string index:\t")); |
||
115 | print_hex( buf.iManufacturer, 8 ); |
||
116 | getstrdescr( addr, buf.iManufacturer ); |
||
117 | //Prod.string |
||
118 | printProgStr(PSTR("\r\nProd.string index:\t")); |
||
119 | print_hex( buf.iProduct, 8 ); |
||
120 | //printProgStr( str_cont ); |
||
121 | getstrdescr( addr, buf.iProduct ); |
||
122 | //Serial number string |
||
123 | printProgStr(PSTR("\r\nSerial number index:\t")); |
||
124 | print_hex( buf.iSerialNumber, 8 ); |
||
125 | //printProgStr( str_cont ); |
||
126 | getstrdescr( addr, buf.iSerialNumber ); |
||
127 | //Number of configurations |
||
128 | printProgStr(PSTR("\r\nNumber of conf.:\t")); |
||
129 | print_hex( buf.bNumConfigurations, 8 ); |
||
130 | return( buf.bNumConfigurations ); |
||
131 | } |
||
132 | /* Get string descriptor. Takes device address and string index */ |
||
133 | byte getstrdescr( byte addr, byte idx ) |
||
134 | { |
||
135 | char buf[ BUFSIZE ]; |
||
136 | byte rcode; |
||
137 | byte length; |
||
138 | byte i; |
||
139 | unsigned int langid; |
||
140 | if( idx == 0 ) { //don't try to get index zero |
||
141 | return( 0 ); |
||
142 | } |
||
143 | rcode = Usb.getStrDescr( addr, 0, 1, 0, 0, buf ); //get language table length |
||
144 | if( rcode ) { |
||
145 | printProgStr(PSTR("\r\nError retrieving LangID table length")); |
||
146 | return( rcode ); |
||
147 | } |
||
148 | length = buf[ 0 ]; //length is the first byte |
||
149 | rcode = Usb.getStrDescr( addr, 0, length, 0, 0, buf ); //get language table |
||
150 | if( rcode ) { |
||
151 | printProgStr(PSTR("\r\nError retrieving LangID table")); |
||
152 | return( rcode ); |
||
153 | } |
||
154 | HIBYTE( langid ) = buf[ 3 ]; //get first langid |
||
155 | LOBYTE( langid ) = buf[ 2 ]; //bytes are swapped to account for endiannes |
||
156 | //printProgStr(PSTR("\r\nLanguage ID: ")); |
||
157 | //print_hex( langid, 16 ); |
||
158 | rcode = Usb.getStrDescr( addr, 0, 1, idx, langid, buf ); |
||
159 | if( rcode ) { |
||
160 | printProgStr(PSTR("\r\nError retrieving string length")); |
||
161 | return( rcode ); |
||
162 | } |
||
163 | length = ( buf[ 0 ] < 254 ? buf[ 0 ] : 254 ); |
||
164 | printProgStr(PSTR(" Length: ")); |
||
165 | Serial.print( length, DEC ); |
||
166 | rcode = Usb.getStrDescr( addr, 0, length, idx, langid, buf ); |
||
167 | if( rcode ) { |
||
168 | printProgStr(PSTR("\r\nError retrieveing string")); |
||
169 | return( rcode ); |
||
170 | } |
||
171 | printProgStr(PSTR(" Contents: ")); |
||
172 | for( i = 2; i < length; i+=2 ) { |
||
173 | Serial.print( buf[ i ] ); |
||
174 | } |
||
175 | return( idx ); |
||
176 | } |
||
177 | /* Returns string to class name */ |
||
178 | const char* classname_parse( byte class_number ) |
||
179 | { |
||
180 | switch( class_number ) { |
||
181 | case 0x00: |
||
182 | return PSTR(" Use class information in the Interface Descriptor"); |
||
183 | case 0x01: |
||
184 | return PSTR(" Audio"); |
||
185 | case 0x02: |
||
186 | return PSTR(" Communications and CDC Control"); |
||
187 | case 0x03: |
||
188 | return PSTR(" HID (Human Interface Device)"); |
||
189 | case 0x05: |
||
190 | return PSTR(" Physical"); |
||
191 | case 0x06: |
||
192 | return PSTR(" Image"); |
||
193 | case 0x07: |
||
194 | return PSTR(" Printer"); |
||
195 | case 0x08: |
||
196 | return PSTR(" Mass Storage"); |
||
197 | case 0x09: |
||
198 | return PSTR(" Hub"); |
||
199 | case 0x0a: |
||
200 | return PSTR(" CDC-Data"); |
||
201 | case 0x0b: |
||
202 | return PSTR(" Smart Card"); |
||
203 | case 0x0d: |
||
204 | return PSTR(" Content Security"); |
||
205 | case 0x0e: |
||
206 | return PSTR(" Video"); |
||
207 | case 0x0f: |
||
208 | return PSTR(" Personal Healthcare"); |
||
209 | case 0xdc: |
||
210 | return PSTR("Diagnostic Device"); |
||
211 | case 0xe0: |
||
212 | return PSTR(" Wireless Controller"); |
||
213 | case 0xef: |
||
214 | return PSTR(" Miscellaneous"); |
||
215 | case 0xfe: |
||
216 | return PSTR(" Application Specific"); |
||
217 | case 0xff: |
||
218 | return PSTR(" Vendor Specific"); |
||
219 | default: |
||
220 | return unk_msg; |
||
221 | }//switch( class_number |
||
222 | } |
||
223 | /* Getting configuration descriptor */ |
||
224 | byte getconfdescr( byte addr, byte conf ) |
||
225 | { |
||
226 | char buf[ BUFSIZE ]; |
||
227 | char* buf_ptr = buf; |
||
228 | byte rcode; |
||
229 | byte descr_length; |
||
230 | byte descr_type; |
||
231 | unsigned int total_length; |
||
232 | printProgStr(PSTR("\r\n\nConfiguration number ")); |
||
233 | Serial.print( conf, HEX ); |
||
234 | rcode = Usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length |
||
235 | if( rcode ) { |
||
236 | printProgStr(PSTR("Error retrieving configuration length. Error code ")); |
||
237 | Serial.println( rcode, HEX ); |
||
238 | return( 0 ); |
||
239 | }//if( rcode |
||
240 | LOBYTE( total_length ) = buf[ 2 ]; |
||
241 | HIBYTE( total_length ) = buf[ 3 ]; |
||
242 | printProgStr(PSTR("\r\nTotal configuration length: ")); |
||
243 | Serial.print( total_length, DEC ); |
||
244 | printProgStr(PSTR(" bytes")); |
||
245 | if( total_length > BUFSIZE ) { //check if total length is larger than buffer |
||
246 | printProgStr(PSTR("Total length truncated to ")); |
||
247 | Serial.print( BUFSIZE, DEC); |
||
248 | printProgStr(PSTR("bytes")); |
||
249 | total_length = BUFSIZE; |
||
250 | } |
||
251 | rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor |
||
252 | while( buf_ptr < buf + total_length ) { //parsing descriptors |
||
253 | descr_length = *( buf_ptr ); |
||
254 | descr_type = *( buf_ptr + 1 ); |
||
255 | switch( descr_type ) { |
||
256 | case( USB_DESCRIPTOR_CONFIGURATION ): |
||
257 | printconfdescr( buf_ptr ); |
||
258 | break; |
||
259 | case( USB_DESCRIPTOR_INTERFACE ): |
||
260 | printintfdescr( buf_ptr ); |
||
261 | break; |
||
262 | case( USB_DESCRIPTOR_ENDPOINT ): |
||
263 | printepdescr( buf_ptr ); |
||
264 | break; |
||
265 | case( HID_DESCRIPTOR_HID ): |
||
266 | printhid_descr( buf_ptr ); |
||
267 | break; |
||
268 | default: |
||
269 | printunkdescr( buf_ptr ); |
||
270 | break; |
||
271 | }//switch( descr_type |
||
272 | Serial.println(""); |
||
273 | buf_ptr = ( buf_ptr + descr_length ); //advance buffer pointer |
||
274 | }//while( buf_ptr <=... |
||
275 | return( 0 ); |
||
276 | } |
||
277 | /* function to print configuration descriptor */ |
||
278 | void printconfdescr( char* descr_ptr ) |
||
279 | { |
||
280 | USB_CONFIGURATION_DESCRIPTOR* conf_ptr = ( USB_CONFIGURATION_DESCRIPTOR* )descr_ptr; |
||
281 | uint8_t tmpbyte; |
||
282 | printProgStr(PSTR("\r\n\nConfiguration descriptor:")); |
||
283 | printProgStr(PSTR("\r\nTotal length:\t\t")); |
||
284 | print_hex( conf_ptr->wTotalLength, 16 ); |
||
285 | printProgStr(PSTR("\r\nNumber of interfaces:\t")); |
||
286 | print_hex( conf_ptr->bNumInterfaces, 8 ); |
||
287 | printProgStr(PSTR("\r\nConfiguration value:\t")); |
||
288 | print_hex( conf_ptr->bConfigurationValue, 8 ); |
||
289 | printProgStr(PSTR("\r\nConfiguration string:\t")); |
||
290 | tmpbyte = conf_ptr->iConfiguration; |
||
291 | print_hex( tmpbyte, 8 ); |
||
292 | getstrdescr( DEVADDR, tmpbyte ); |
||
293 | printProgStr(PSTR("\r\nAttributes:\t\t")); |
||
294 | tmpbyte = conf_ptr->bmAttributes; |
||
295 | print_hex( tmpbyte, 8 ); |
||
296 | if( tmpbyte & 0x40 ) { //D6 |
||
297 | printProgStr(PSTR(" Self-powered")); |
||
298 | } |
||
299 | if( tmpbyte & 0x20 ) { //D5 |
||
300 | printProgStr(PSTR(" Remote Wakeup")); |
||
301 | } |
||
302 | printProgStr(PSTR("\r\nMax.power:\t\t")); |
||
303 | tmpbyte = conf_ptr->bMaxPower; |
||
304 | print_hex( tmpbyte, 8 ); |
||
305 | printProgStr(PSTR(" ")); |
||
306 | Serial.print(( tmpbyte * 2 ), DEC); |
||
307 | printProgStr(PSTR("ma")); |
||
308 | return; |
||
309 | } |
||
310 | /* function to print interface descriptor */ |
||
311 | void printintfdescr( char* descr_ptr ) |
||
312 | { |
||
313 | USB_INTERFACE_DESCRIPTOR* intf_ptr = ( USB_INTERFACE_DESCRIPTOR* )descr_ptr; |
||
314 | uint8_t tmpbyte; |
||
315 | printProgStr(PSTR("\r\nInterface descriptor:")); |
||
316 | printProgStr(PSTR("\r\nInterface number:\t")); |
||
317 | print_hex( intf_ptr->bInterfaceNumber, 8 ); |
||
318 | printProgStr(PSTR("\r\nAlternate setting:\t")); |
||
319 | print_hex( intf_ptr->bAlternateSetting, 8 ); |
||
320 | printProgStr(PSTR("\r\nEndpoints:\t\t")); |
||
321 | print_hex( intf_ptr->bNumEndpoints, 8 ); |
||
322 | printProgStr( class_str ); |
||
323 | tmpbyte = intf_ptr->bInterfaceClass; |
||
324 | print_hex( tmpbyte, 8 ); |
||
325 | printProgStr(classname_parse( tmpbyte )); |
||
326 | printProgStr( subclass_str ); |
||
327 | print_hex( intf_ptr->bInterfaceSubClass, 8 ); |
||
328 | printProgStr( protocol_str ); |
||
329 | print_hex( intf_ptr->bInterfaceProtocol, 8 ); |
||
330 | printProgStr(PSTR("\r\nInterface string:\t")); |
||
331 | tmpbyte = intf_ptr->iInterface; |
||
332 | print_hex( tmpbyte, 8 ); |
||
333 | getstrdescr( DEVADDR, tmpbyte ); |
||
334 | return; |
||
335 | } |
||
336 | /* function to print endpoint descriptor */ |
||
337 | void printepdescr( char* descr_ptr ) |
||
338 | { |
||
339 | USB_ENDPOINT_DESCRIPTOR* ep_ptr = ( USB_ENDPOINT_DESCRIPTOR* )descr_ptr; |
||
340 | uint8_t tmpbyte; |
||
341 | printProgStr(PSTR("\r\nEndpoint descriptor:")); |
||
342 | printProgStr(PSTR("\r\nEndpoint address:\t")); |
||
343 | tmpbyte = ep_ptr->bEndpointAddress; |
||
344 | print_hex( tmpbyte & 0x0f, 8 ); |
||
345 | printProgStr(PSTR(" Direction: ")); |
||
346 | ( tmpbyte & 0x80 ) ? printProgStr(PSTR("IN")) : printProgStr(PSTR("OUT")); |
||
347 | printProgStr(PSTR("\r\nAttributes:\t\t")); |
||
348 | tmpbyte = ep_ptr->bmAttributes; |
||
349 | print_hex( tmpbyte, 8 ); |
||
350 | printProgStr(PSTR(" Transfer type: ")); |
||
351 | printProgStr((char*)pgm_read_word(&transfer_types[(tmpbyte & 0x03)])); |
||
352 | if(( tmpbyte & 0x03 ) == 1 ) { //Isochronous Transfer |
||
353 | printProgStr(PSTR(", Sync Type: ")); |
||
354 | printProgStr((char*)pgm_read_word(&sync_types[(tmpbyte & 0x0c)])); |
||
355 | printProgStr(PSTR(", Usage Type: ")); |
||
356 | printProgStr((char*)pgm_read_word(&usage_types[(tmpbyte & 0x30)])); |
||
357 | }//if( tmpbyte & 0x01 |
||
358 | printProgStr( maxpktsize_str ); |
||
359 | print_hex( ep_ptr->wMaxPacketSize, 16 ); |
||
360 | printProgStr(PSTR("\r\nPolling interval:\t")); |
||
361 | tmpbyte = ep_ptr->bInterval; |
||
362 | print_hex( tmpbyte, 8 ); |
||
363 | printProgStr(PSTR(" ")); |
||
364 | Serial.print( tmpbyte, DEC ); |
||
365 | printProgStr(PSTR(" ms")); |
||
366 | return; |
||
367 | } |
||
368 | /* function to print HID descriptor */ |
||
369 | void printhid_descr( char* descr_ptr ) |
||
370 | { |
||
371 | PARSE pf = &HIDreport_parse; |
||
372 | USB_HID_DESCRIPTOR* hid_ptr = ( USB_HID_DESCRIPTOR* )descr_ptr; |
||
373 | uint8_t tmpbyte; |
||
374 | /**/ |
||
375 | printProgStr(PSTR("\r\nHID descriptor:")); |
||
376 | printProgStr(PSTR("\r\nDescriptor length:\t")); |
||
377 | tmpbyte = hid_ptr->bLength; |
||
378 | print_hex( tmpbyte, 8 ); |
||
379 | printProgStr(PSTR(" ")); |
||
380 | Serial.print( tmpbyte, DEC ); |
||
381 | printProgStr(PSTR(" bytes")); |
||
382 | printProgStr(PSTR("\r\nHID version:\t\t")); |
||
383 | Serial.print(( HIBYTE( hid_ptr->bcdHID )), HEX ); |
||
384 | Serial.print("."); |
||
385 | Serial.print(( LOBYTE( hid_ptr->bcdHID )), HEX ); |
||
386 | tmpbyte = hid_ptr->bCountryCode; |
||
387 | printProgStr(PSTR("\r\nCountry Code:\t\t")); |
||
388 | Serial.print( tmpbyte, DEC ); |
||
389 | printProgStr(PSTR(" ")); |
||
390 | ( tmpbyte > 35 ) ? printProgStr(PSTR("Reserved")) : printProgStr((char*)pgm_read_word(&HID_Country_Codes[ tmpbyte ])); |
||
391 | tmpbyte = hid_ptr->bNumDescriptors; |
||
392 | printProgStr(PSTR("\r\nClass Descriptors:\t")); |
||
393 | Serial.print( tmpbyte, DEC ); |
||
394 | //Printing class descriptors |
||
395 | descr_ptr += 6; //advance buffer pointer |
||
396 | for( uint8_t i = 0; i < tmpbyte; i++ ) { |
||
397 | uint8_t tmpdata; |
||
398 | HID_CLASS_DESCRIPTOR* hidclass_ptr = ( HID_CLASS_DESCRIPTOR* )descr_ptr; |
||
399 | tmpdata = hidclass_ptr->bDescriptorType; |
||
400 | printProgStr(PSTR("\r\nClass Descriptor Type:\t")); |
||
401 | Serial.print( tmpdata, HEX ); |
||
402 | if(( tmpdata < 0x21 ) || ( tmpdata > 0x2f )) { |
||
403 | printProgStr(PSTR(" Invalid")); |
||
404 | } |
||
405 | switch( tmpdata ) { |
||
406 | case 0x21: |
||
407 | printProgStr(PSTR(" HID")); |
||
408 | break; |
||
409 | case 0x22: |
||
410 | printProgStr(PSTR(" Report")); |
||
411 | break; |
||
412 | case 0x23: |
||
413 | printProgStr(PSTR(" Physical")); |
||
414 | break; |
||
415 | default: |
||
416 | printProgStr(PSTR(" Reserved")); |
||
417 | break; |
||
418 | }//switch( tmpdata |
||
419 | printProgStr(PSTR("\r\nClass Descriptor Length:")); |
||
420 | Serial.print( hidclass_ptr->wDescriptorLength ); |
||
421 | printProgStr(PSTR(" bytes")); |
||
422 | printProgStr(PSTR("\r\n\nHID report descriptor:\r\n")); |
||
423 | getReportDescr( DEVADDR, 0 , hidclass_ptr->wDescriptorLength, pf, USB_NAK_LIMIT ); |
||
424 | descr_ptr += 3; //advance to the next record |
||
425 | }//for( uint8_t i=... |
||
426 | return; |
||
427 | } |
||
428 | /*function to print unknown descriptor */ |
||
429 | void printunkdescr( char* descr_ptr ) |
||
430 | { |
||
431 | byte length = *descr_ptr; |
||
432 | byte i; |
||
433 | printProgStr(PSTR("\r\nUnknown descriptor:")); |
||
434 | printProgStr(PSTR("Length:\t\t")); |
||
435 | print_hex( *descr_ptr, 8 ); |
||
436 | printProgStr(PSTR("\r\nType:\t\t")); |
||
437 | print_hex( *(descr_ptr + 1 ), 8 ); |
||
438 | printProgStr(PSTR("\r\nContents:\t")); |
||
439 | descr_ptr += 2; |
||
440 | for( i = 0; i < length; i++ ) { |
||
441 | print_hex( *descr_ptr, 8 ); |
||
442 | descr_ptr++; |
||
443 | } |
||
444 | } |
||
445 | /* Control-IN transfer with callback. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer */ |
||
446 | /* Control, data, and setup stages combined from standard USB library to be able to read large data blocks. Restricted to control-IN transfers with data stage */ |
||
447 | /* data read and MAX3421E RECV FIFO buffer release shall be performed by parse_func callback */ |
||
448 | /* return codes: */ |
||
449 | /* 00 = success */ |
||
450 | /* 01-0f = non-zero HRSLT */ |
||
451 | byte ctrlXfer( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, uint16_t nbytes, PARSE parse_func, uint16_t nak_limit = USB_NAK_LIMIT ) |
||
452 | { |
||
453 | byte rcode; |
||
454 | SETUP_PKT sp; |
||
455 | EP_RECORD* ep_rec = Usb.getDevTableEntry( addr, ep ); |
||
456 | byte pktsize; |
||
457 | byte maxpktsize = ep_rec->MaxPktSize; |
||
458 | unsigned int xfrlen = 0; |
||
459 | /**/ |
||
460 | Max.regWr( rPERADDR, addr ); //set peripheral address |
||
461 | /* fill in setup packet */ |
||
462 | sp.ReqType_u.bmRequestType = bmReqType; |
||
463 | sp.bRequest = bRequest; |
||
464 | sp.wVal_u.wValueLo = wValLo; |
||
465 | sp.wVal_u.wValueHi = wValHi; |
||
466 | sp.wIndex = wInd; |
||
467 | sp.wLength = nbytes; |
||
468 | Max.bytesWr( rSUDFIFO, 8, ( char *)&sp ); //transfer to setup packet FIFO |
||
469 | rcode = Usb.dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet |
||
470 | //Serial.println("Setup packet"); //DEBUG |
||
471 | if( rcode ) { //return HRSLT if not zero |
||
472 | printProgStr(PSTR("\r\nSetup packet error: ")); |
||
473 | Serial.print( rcode, HEX ); |
||
474 | return( rcode ); |
||
475 | } |
||
476 | /* Data stage */ |
||
477 | //ep_rec->rcvToggle = bmRCVTOG1; |
||
478 | Max.regWr( rHCTL, bmRCVTOG1 ); //set toggle |
||
479 | while( 1 ) { //exited by break |
||
480 | /* request data */ |
||
481 | rcode = Usb.dispatchPkt( tokIN, ep, nak_limit ); |
||
482 | if( rcode ) { |
||
483 | printProgStr(PSTR("\r\nData Stage Error: ")); |
||
484 | Serial.print( rcode, HEX ); |
||
485 | return( rcode ); |
||
486 | } |
||
487 | /* check for RCVDAVIRQ and generate error if not present */ |
||
488 | /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ |
||
489 | if(( Max.regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { |
||
490 | printProgStr(PSTR("\r\nData Toggle error.")); |
||
491 | return ( 0xf0 ); |
||
492 | } |
||
493 | pktsize = Max.regRd( rRCVBC ); //get received bytes count |
||
494 | parse_func( pktsize ); //call parse function. Parse is expected to read the FIFO completely |
||
495 | Max.regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer |
||
496 | xfrlen += pktsize; // add this packet's byte count to total transfer length |
||
497 | /* The transfer is complete under two conditions: */ |
||
498 | /* 1. The device sent a short packet (L.T. maxPacketSize) */ |
||
499 | /* 2. 'nbytes' have been transferred. */ |
||
500 | if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? |
||
501 | break; |
||
502 | } |
||
503 | }//while( 1 ) |
||
504 | rcode = Usb.dispatchPkt( tokOUTHS, ep, nak_limit ); |
||
505 | if( rcode ) { //return error |
||
506 | printProgStr(PSTR("Status packet error: ")); |
||
507 | Serial.print( rcode, HEX ); |
||
508 | } |
||
509 | return( rcode ); |
||
510 | } |
||
511 | /* Parses bitfields in main items */ |
||
512 | void print_mainbitfield( uint8_t byte_toparse ) |
||
513 | { |
||
514 | ( byte_toparse & 0x01 ) ? printProgStr(PSTR("Constant,")) : printProgStr(PSTR("Data,")); //bit 0 |
||
515 | ( byte_toparse & 0x02 ) ? printProgStr(PSTR("Variable,")) : printProgStr(PSTR("Array,")); //bit 1 |
||
516 | ( byte_toparse & 0x04 ) ? printProgStr(PSTR("Relative,")) : printProgStr(PSTR("Absolute,")); //... |
||
517 | ( byte_toparse & 0x08 ) ? printProgStr(PSTR("Wrap,")) : printProgStr(PSTR("No Wrap,")); |
||
518 | ( byte_toparse & 0x10 ) ? printProgStr(PSTR("Non Linear,")) : printProgStr(PSTR("Linear,")); |
||
519 | ( byte_toparse & 0x20 ) ? printProgStr(PSTR("No preferred,")) : printProgStr(PSTR("Preferred State,")); |
||
520 | ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Null State,")) : printProgStr(PSTR("No Null Position,")); //bit 6 |
||
521 | ( byte_toparse & 0x40 ) ? printProgStr(PSTR("Volatile( ignore for Input),")) : printProgStr(PSTR("Non-volatile(Ignore for Input),")); //bit 7 |
||
522 | } |
||
523 | /* HID Report Desriptor Parser Callback */ |
||
524 | /* called repeatedly from Control transfer function */ |
||
525 | void HIDreport_parse( uint8_t pkt_size ) |
||
526 | { |
||
527 | #define B_SIZE 0x03 //bSize bitmask |
||
528 | #define B_TYPE 0x0c //bType bitmask |
||
529 | #define B_TAG 0xf0 //bTag bitmask |
||
530 | /* parser states */ |
||
531 | enum STATE { ITEM_START, DATA_PARSE }; |
||
532 | static STATE state = ITEM_START; |
||
533 | static uint8_t databytes_left = 0; |
||
534 | static uint8_t prefix; //item prefix - type and tag |
||
535 | uint8_t byte_toparse; |
||
536 | uint8_t bType; |
||
537 | uint8_t tmpbyte; |
||
538 | /**/ |
||
539 | while( 1 ) { |
||
540 | if( pkt_size ) { |
||
541 | byte_toparse = Max.regRd( rRCVFIFO ); //read a byte from FIFO |
||
542 | pkt_size--; |
||
543 | } |
||
544 | else { |
||
545 | return; //all bytes read |
||
546 | } |
||
547 | switch( state ) { |
||
548 | case ITEM_START: //start of the record |
||
549 | prefix = byte_toparse >>2; //store prefix for databyte parsing |
||
550 | tmpbyte = byte_toparse & B_SIZE; |
||
551 | /* get item length */ |
||
552 | ( tmpbyte == 0x03 ) ? databytes_left = 4 : databytes_left = tmpbyte; |
||
553 | if( databytes_left ) { |
||
554 | state = DATA_PARSE; //read bytes after prefix |
||
555 | } |
||
556 | printProgStr(PSTR("\r\nLength: ")); |
||
557 | Serial.print( databytes_left, DEC ); |
||
558 | /* get item type */ |
||
559 | bType = ( byte_toparse & B_TYPE ) >>2; |
||
560 | printProgStr(PSTR(" Type: ")); |
||
561 | printProgStr((char*)pgm_read_word(&btypes[ bType ])); |
||
562 | /* get item tag */ |
||
563 | printProgStr(PSTR("\t\tTag: ")); |
||
564 | tmpbyte = ( byte_toparse & B_TAG ) >>4 ; |
||
565 | switch( bType ) { |
||
566 | case 0: //Main |
||
567 | if( tmpbyte < 0x08 ) { |
||
568 | printProgStr(PSTR("Invalid Tag")); |
||
569 | } |
||
570 | else if( tmpbyte > 0x0c ) { |
||
571 | printProgStr( reserved_msg ); |
||
572 | } |
||
573 | else { |
||
574 | printProgStr((char*)pgm_read_word(&maintags[ tmpbyte - 8 /* & 0x03 */])); |
||
575 | //Serial.print("Byte: "); |
||
576 | //Serial.println( tmpbyte, HEX ); |
||
577 | } |
||
578 | break;//case 0 Main |
||
579 | case 1: //Global |
||
580 | ( tmpbyte > 0x0b ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&globaltags[ tmpbyte ])); |
||
581 | break;//case 1 Global |
||
582 | case 2: //Local |
||
583 | ( tmpbyte > 0x0a ) ? printProgStr( reserved_msg ) : printProgStr((char*)pgm_read_word(&localtags[ tmpbyte ])); |
||
584 | break;//case 2 Local |
||
585 | default: |
||
586 | break; |
||
587 | }//switch( bType... |
||
588 | break;//case ITEM_START |
||
589 | case DATA_PARSE: |
||
590 | switch( prefix ) { |
||
591 | case 0x20: //Main Input |
||
592 | case 0x24: //Main Output |
||
593 | case 0x2c: //Main Feature |
||
594 | /* todo: add parsing 8th bit */ |
||
595 | print_mainbitfield( byte_toparse ); |
||
596 | break; |
||
597 | case 0x28: //Main Collection |
||
598 | if(( byte_toparse > 0x06 ) && ( byte_toparse < 0x80 )) { |
||
599 | printProgStr( reserved_msg ); |
||
600 | } |
||
601 | else if(( byte_toparse > 0x7f ) && ( byte_toparse <= 0xff )) { |
||
602 | printProgStr(PSTR("Vendor-defined")); |
||
603 | } |
||
604 | else { |
||
605 | printProgStr((char*)pgm_read_word(&collections[ byte_toparse ])); |
||
606 | } |
||
607 | break;//case 0x28 Main Collection |
||
608 | //case 0x30: //Main End Collection |
||
609 | case 0x01: //Global Usage Page |
||
610 | switch( byte_toparse ) { //see HID Usage Tables doc v.1.12 page 14 |
||
611 | case 0x00: |
||
612 | case 0x01: |
||
613 | case 0x02: |
||
614 | case 0x03: |
||
615 | case 0x04: |
||
616 | case 0x05: |
||
617 | case 0x06: |
||
618 | case 0x07: |
||
619 | case 0x08: |
||
620 | case 0x09: |
||
621 | case 0x0a: |
||
622 | case 0x0b: |
||
623 | case 0x0c: |
||
624 | case 0x0d: |
||
625 | case 0x0e: |
||
626 | case 0x0f: |
||
627 | case 0x10: |
||
628 | printProgStr((char*)pgm_read_word(&usage_pages[ byte_toparse ])); |
||
629 | break; |
||
630 | case 0x14: |
||
631 | printProgStr(PSTR("Alphanumeric Display")); |
||
632 | break; |
||
633 | case 0x40: |
||
634 | printProgStr(PSTR("Medical Instruments")); |
||
635 | break; |
||
636 | case 0x80: |
||
637 | case 0x81: |
||
638 | case 0x82: |
||
639 | case 0x83: |
||
640 | printProgStr(PSTR("Monitor page")); |
||
641 | break; |
||
642 | case 0x84: |
||
643 | case 0x85: |
||
644 | case 0x86: |
||
645 | case 0x87: |
||
646 | printProgStr(PSTR("Power page")); |
||
647 | break; |
||
648 | case 0x8c: |
||
649 | printProgStr(PSTR("Bar Code Scanner page")); |
||
650 | break; |
||
651 | case 0x8d: |
||
652 | printProgStr(PSTR("Scale page")); |
||
653 | break; |
||
654 | case 0x8e: |
||
655 | printProgStr(PSTR("Magnetic Stripe Reading (MSR) Devices")); |
||
656 | break; |
||
657 | case 0x8f: |
||
658 | printProgStr(PSTR("Reserved Point of Sale pages")); |
||
659 | break; |
||
660 | case 0x90: |
||
661 | printProgStr(PSTR("Camera Control Page")); |
||
662 | break; |
||
663 | case 0x91: |
||
664 | printProgStr(PSTR("Arcade Page")); |
||
665 | break; |
||
666 | default: |
||
667 | // printProgStr(PSTR("Data: ")); |
||
668 | // print_hex( byte_toparse, 8 ); |
||
669 | //databytes_left--; |
||
670 | break; |
||
671 | }//switch case 0x01: //Global Usage Page |
||
672 | }//switch( prefix ... |
||
673 | printProgStr(PSTR(" Data: ")); |
||
674 | print_hex( byte_toparse, 8 ); |
||
675 | databytes_left--; |
||
676 | if( !databytes_left ) { |
||
677 | state = ITEM_START; |
||
678 | } |
||
679 | break; |
||
680 | }//switch( state... |
||
681 | }//while( 1 ... |
||
682 | } |
||
683 | /* prints hex numbers with leading zeroes */ |
||
684 | // copyright, Peter H Anderson, Baltimore, MD, Nov, '07 |
||
685 | // source: http://www.phanderson.com/arduino/arduino_display.html |
||
686 | void print_hex(int v, int num_places) |
||
687 | { |
||
688 | int mask=0, n, num_nibbles, digit; |
||
689 | |||
690 | for (n=1; n<=num_places; n++) { |
||
691 | mask = (mask << 1) | 0x0001; |
||
692 | } |
||
693 | v = v & mask; // truncate v to specified number of places |
||
694 | |||
695 | num_nibbles = num_places / 4; |
||
696 | if ((num_places % 4) != 0) { |
||
697 | ++num_nibbles; |
||
698 | } |
||
699 | do { |
||
700 | digit = ((v >> (num_nibbles-1) * 4)) & 0x0f; |
||
701 | Serial.print(digit, HEX); |
||
702 | } |
||
703 | while(--num_nibbles); |
||
704 | } |
||
705 | |||
706 | /* given a PROGMEM string, use Serial.print() to send it out */ |
||
707 | /* Some non-intuitive casting necessary: */ |
||
708 | /* printProgStr(PSTR("Func.Mode:\t0x")); */ |
||
709 | /* printProgStr((char*)pgm_read_word(&mtpopNames[(op & 0xFF)])); */ |
||
710 | void printProgStr(const char* str) |
||
711 | { |
||
712 | if(!str) { |
||
713 | return; |
||
714 | } |
||
715 | char c; |
||
716 | while((c = pgm_read_byte(str++))) { |
||
717 | Serial.print(c,BYTE); |
||
718 | } |
||
719 | return; |
||
720 | } |