极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 6983|回复: 2

Arduino 控制USB设备(4)解析描述符

[复制链接]
发表于 2015-7-30 13:45:39 | 显示全部楼层 |阅读模式
前面一篇介绍了如何获得USB Descriptor,更麻烦的是这个数据的解读。在【参考1】给出了一个直接解析 Descriptor的例子。美中不足的是,这个例子只能在老版本的Arduino上工作(我估计是 0.22),在新版本 1.6.x 的IDE上会出现很多报错。

经过努力修改,终于可以编译通过(需要选择 Arduno Uno),程序如下:

  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. #define LOBYTE(x) ((char*)(&(x)))[0]
  7. #define HIBYTE(x) ((char*)(&(x)))[1]
  8. #define BUFSIZE 256    //buffer size
  9. #define DEVADDR 1

  10. #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 )
  11. #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 )

  12. /* Foeward declarations */
  13. void setup();
  14. void loop();
  15. 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 );
  16. void HIDreport_parse( uint8_t* buf, uint8_t* head, uint8_t* tail);

  17. typedef struct {
  18.   uint8_t bDescriptorType;
  19.   uint16_t wDescriptorLength;
  20. } HID_CLASS_DESCRIPTOR;


  21. //typedef void (*PARSE)( int8_t*, int8_t*, int8_t );

  22. MAX3421E Max;
  23. USB Usb;

  24. void setup()
  25. {
  26.   Serial.begin( 115200 );
  27.   printProgStr(PSTR("\r\nStart"));
  28.   Max.powerOn();
  29.   delay( 200 );
  30. }

  31. void loop()
  32. {
  33.   uint8_t rcode;
  34.   uint8_t tmpbyte = 0;

  35.   //PARSE pf = &HIDreport_parse;
  36.   /**/
  37.   Max.Task();
  38.   Usb.Task();
  39.   if( Usb.getUsbTaskState() >= USB_STATE_CONFIGURING ) {  //state configuring or higher
  40.   /* printing device descriptor */
  41.     printProgStr(PSTR("\r\nDevice addressed... "));
  42.     printProgStr(PSTR("Requesting device descriptor."));
  43.     tmpbyte = getdevdescr( DEVADDR );                           //number of configurations, 0 if error   
  44.     if( tmpbyte == 0 ) {
  45.       printProgStr(PSTR("\r\nDevice descriptor cannot be retrieved. Program Halted\r\n"));
  46.       while( 1 );           //stop
  47.      }//if( tmpbyte
  48.      /* print configuration descriptors for all configurations */
  49.      for( uint8_t i = 0; i < tmpbyte; i++ ) {
  50.        getconfdescr( DEVADDR, i );
  51.      }   
  52.   /* Stop */
  53.       while( 1 );                          //stop
  54.   }   
  55. }

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

  679.   for (n=1; n<=num_places; n++) {
  680.     mask = (mask << 1) | 0x0001;
  681.   }
  682.   v = v & mask; // truncate v to specified number of places

  683.   num_nibbles = num_places / 4;
  684.   if ((num_places % 4) != 0) {
  685.     ++num_nibbles;
  686.   }
  687.   do {
  688.     digit = ((v >> (num_nibbles-1) * 4)) & 0x0f;
  689.     Serial.print(digit, HEX);
  690.   }
  691.   while(--num_nibbles);
  692. }

  693. /* given a PROGMEM string, use Serial.print() to send it out       */
  694. /* Some non-intuitive casting necessary:                           */
  695. /* printProgStr(PSTR("Func.Mode:\t0x"));                           */
  696. /* printProgStr((char*)pgm_read_word(&mtpopNames[(op & 0xFF)]));   */
  697. void printProgStr(const char* str)
  698. {
  699.   if(!str) {
  700.     return;
  701.   }
  702.   char c;
  703.   while((c = pgm_read_byte(str++))) {
  704.     Serial.write(c);
  705.   }
  706.   return;
  707. }
复制代码


工作的照片:

我用USB Shield挂接了一个USB小键盘,获得的结果如下:

Start
Device addressed... Requesting device descriptor.
Device descriptor:

Descriptor Length:        12
USB version:        1.10
Class:        00 Use class information in the Interface Descriptor
Subclass:        00
Protocol:        00
Max.packet size:        08
Vendor ID:        13BA
Product ID:        0001
Revision ID:        0100
Mfg.string index:        00
Prod.string index:        00
Serial number index:        00
Number of conf.:        01

Configuration number 0
Total configuration length: 34 bytes

Configuration descriptor:
Total length:        0022
Number of interfaces:        01
Configuration value:        01
Configuration string:        00
Attributes:        A0 Remote Wakeup
Max.power:        32 100ma

Interface descriptor:
Interface number:        00
Alternate setting:        00
Endpoints:        01
Class:        03 HID (Human Interface Device)
Subclass:        01
Protocol:        01
Interface string:        00

HID descriptor:
Descriptor length:        09 9 bytes
HID version:        1.10
Country Code:        0 Not Supported
Class Descriptors:        1
Class Descriptor Type:        22 Report
Class Descriptor Length:54 bytes

HID report descriptor:

Length: 1 Type: Global        Tag: Usage Page        Generic Desktop Controls Data: 01
Length: 1 Type: Local        Tag: Usage        Data: 06
Length: 1 Type: Main        Tag: Collection        Application (mouse, keyboard) Data: 01
Length: 1 Type: Global        Tag: Usage Page        LEDs Data: 08
Length: 1 Type: Local        Tag: Usage Minimum        Data: 01
Length: 1 Type: Local        Tag: Usage Maximum        Data: 03
Length: 1 Type: Global        Tag: Logical Minimum        Data: 00
Length: 1 Type: Global        Tag: Logical Maximum        Data: 01
Length: 1 Type: Global        Tag: Report Size        Data: 01
Length: 1 Type: Global        Tag: Report Count        Data: 03
Length: 1 Type: Main        Tag: Output        Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 02
Length: 1 Type: Global        Tag: Report Count        Data: 05
Length: 1 Type: Main        Tag: Output        Constant,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 01
Length: 1 Type: Global        Tag: Usage Page        Keyboard/Keypad Data: 07
Length: 1 Type: Local        Tag: Usage Minimum        Data: E0
Length: 1 Type: Local        Tag: Usage Maximum        Data: E7
Length: 1 Type: Global        Tag: Report Count        Data: 08
Length: 1 Type: Main        Tag: Input        Data,Variable,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 02
Length: 1 Type: Global        Tag: Report Size        Data: 08
Length: 1 Type: Global        Tag: Report Count        Data: 01
Length: 1 Type: Main        Tag: Input        Constant,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 01
Length: 1 Type: Local        Tag: Usage Minimum        Data: 00
Length: 1 Type: Local        Tag: Usage Maximum        Data: 91
Length: 2 Type: Global        Tag: Logical Maximum        Data: FF Data: 00
Length: 1 Type: Global        Tag: Report Count        Data: 06
Length: 1 Type: Main        Tag: Input        Data,Array,Absolute,No Wrap,Linear,Preferred State,No Null Position,Non-volatile(Ignore for Input), Data: 00
Length: 0 Type: Main        Tag: End Collection

Endpoint descriptor:
Endpoint address:        01 Direction: IN
Attributes:        03 Transfer type: Interrupt
Max.packet size:        0008
Polling interval:        0A 10 ms

修改后的可以正常编译的代码下载



参考:

1. https://github.com/felis/USB_Hos ... s/descriptor_parser USB_Host_Shield/examples/descriptor_parser/

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2015-7-30 16:16:46 | 显示全部楼层
很厉害啊,看起来很麻烦!
回复 支持 反对

使用道具 举报

发表于 2015-7-30 17:26:56 | 显示全部楼层
精华啊,正在找这个呢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-5-3 07:59 , Processed in 0.041240 second(s), 20 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表