Forked to make modifications to bring the USBHID into USB compliance and add additional features.

Dependents:   HW4_AudioControl

Fork of USBDevice by mbed official

As of Revision 18 everything in the USBHID specification is now implemented, except Multi-reports.

Revision comments for changelist 18

USBHID.cpp

  • Added SET_PROTOCOL support
  • Added GET_PROTOCOL support
  • protocolSate is set to 1 by default to match USB HID specification. This variable should be checked to determine which format theinput report should have. 1 - Use the user specified report format. 0 - Use the BOOT protocol report format.

Revision comments for changelist 16

  • HID_REPORT transformed from structure to class. This was done for several reasons.
  1. When multiple reports are used the 64 byte size for every report becomes a problem.
  2. The length value should always remain the same for a report, Make the constructor set the vale at the same time it allocates memory for the DATA area.
  • By default the data will be an array of MAX_HID_REPORT_SIZE like the structure,
  • When given a length argument, the hid_report.length will be set, and hid_report.data will be an array of the size given.
  • Length zero causes data to be NULL
  • Mostly backwards compatible. The definition of a destructor caused a compiler error in USBMouse::update and USBMousekeyboard::update. This error was caused by instatiation of HID_REPORT in the middle of an IF logic statement. These files have been modified. The error complained that the logic skipped object initialization. The HID_REPORT has been moved to the class definition. Since both ABSOLUTE and RELATIVE modes used the HID_REPORT, this seems to make more sense. Previously the hid_report would be instatiated in <class>::mousesend and <class>::update.

Revision comments for changelist 14

USBdevice.cpp

  • Modified USB device state to change from Configure when disconnect is called.
  • Modified the call back function for when the suspend state changes. This should be used to turn off peripherals to conserve power.

Revision comments for changelist 13

USBdevice.cpp

  • ) Changed DEBUG messages to be more descriptive for string descriptor
  • ) Bug fix: Control Transfers did not actually transfer the data from Buffer to transfer->ptr

USBHIDTypes.h

  • ) Added ALL CLASS request to KEYWORD list
  • ) Added KEYWORDS for report type

USBHID.h

  • ) Added a new constructor to specify size of feature report
  • ) Added HID_REPORT inputReport and featureReport
  • ) Added data structures to support IDLE rate
  • ) Added data structures to support callback functions

USBHID.cpp

  • ) Changed constructor to initialize new feature data structures
  • ) Implemented Set_IDLE/GET_IDLE and the periodic resend of non-changed data
  • ) Implemented HID specification required control transfer GET_REPORT
  • ) Fixed issue where Intreput transfers and control transfers did not access the same data structures.
  • ) Implemented Feature reports
  • ) Implemented Callback Hooks for get_report/set_report actions.
  • ) Added callback hooks for interupt actions in the new functions.
  • ) interupt transfer can now write to outputReport
  • ) Modified SET_REPORT code to function for multiple types.
  • ) Refactored some code in preperation to add multi report support
Test NumberTest DescriptionTest ResultNotes
1Use USBmouse to verify backward compatibility of constructor and methodsPass
2Test SET_REPORT can set a feature reportPass
3Test GET_REPORT can retrieve a feature reportPass
4Test SET_IDLE sets up a reoccuring triggerPassIOCTL_SET_POLL_FREQUENCY_MSEC does not function for the windows HID driver. A Special test program is used to rearm the IDLE rate after windows sets it to zero
5Test SET_IDLE disables a triggerPassWindows automatically sends this command to a HID device when it is inserted.
6Enabled DEBUG in USBDevice.cpp and generated str descriptor requests.Pass
7Test SET_REPORT can set an output reportPass
8Test GET_REPORT can retrieve an output reportPass
9ReadFile, accesses the input_reportPass
10WriteFile accesses the output_report, via interupt transfer when ep1_out is used.Pass
11WriteFile accesses the output_report, via control transfer when ep1_out is NOT used.Not Tested
12Callback hooks trigger independently for each type of set_report/get_reportPass
13New constructor sets feature_report sizePass
14Control transfer SET_REPORT and writeFile access the same data structureBUGThe same data structure is accessed, but the data transfer size is different. The writeFile strips the leading byte which is the report ID, The Control transfer keeps the byte.
15Control transfer GET_REPORT and readFile access the same data structureBUGThe same dtat structure is accessed, but the data transfer size is different. The readFile strips the leading byte which is the report ID, The Control transfer keeps the byte.
16Test GET_IDLE retrieves the IDLE rateUnknownWindows HID driver does not implement IOCTL_HID_GET_POLL_FREQUENCY_MSEC

Files at this revision

API Documentation at this revision

Comitter:
jakowisp
Date:
Thu Jul 25 00:38:09 2013 +0000
Parent:
11:822c905d22e7
Child:
13:9f652add7891
Commit message:
New features added and modifications made to make library USB HID compliant.

Changed in this revision

USBDevice/USBDevice.cpp Show annotated file Show diff for this revision Revisions of this file
USBHID/USBHID.cpp Show annotated file Show diff for this revision Revisions of this file
USBHID/USBHID.h Show annotated file Show diff for this revision Revisions of this file
USBHID/USBHID_Types.h Show annotated file Show diff for this revision Revisions of this file
--- a/USBDevice/USBDevice.cpp	Wed Jul 24 17:24:49 2013 +0000
+++ b/USBDevice/USBDevice.cpp	Thu Jul 25 00:38:09 2013 +0000
@@ -91,7 +91,7 @@
             {
                             case STRING_OFFSET_LANGID:
 #ifdef DEBUG
-                                printf("1\r\n");
+                                printf("%d:LANGID\r\n",STRING_OFFSET_LANGID);
 #endif
                                 transfer.remaining = stringLangidDesc()[0];
                                 transfer.ptr = stringLangidDesc();
@@ -100,7 +100,7 @@
                                 break;
                             case STRING_OFFSET_IMANUFACTURER:
 #ifdef DEBUG
-                                printf("2\r\n");
+                                printf("%d:MANUFACTURE\r\n",STRING_OFFSET_IMANUFACTURER);
 #endif
                                 transfer.remaining =  stringImanufacturerDesc()[0];
                                 transfer.ptr = stringImanufacturerDesc();
@@ -109,7 +109,7 @@
                                 break;       
                             case STRING_OFFSET_IPRODUCT:
 #ifdef DEBUG
-                                printf("3\r\n");
+                                printf("%d:PRODUCT\r\n",STRING_OFFSET_IPRODUCT);
 #endif
                                 transfer.remaining = stringIproductDesc()[0];
                                 transfer.ptr = stringIproductDesc();
@@ -118,7 +118,7 @@
                                 break;            
                             case STRING_OFFSET_ISERIAL:
 #ifdef DEBUG
-                                printf("4\r\n");
+                                printf("%d:SERIAL\r\n",STRING_OFFSET_ISERIAL);
 #endif
                                 transfer.remaining = stringIserialDesc()[0];
                                 transfer.ptr = stringIserialDesc();
@@ -127,7 +127,7 @@
                                 break;        
                             case STRING_OFFSET_ICONFIGURATION:
 #ifdef DEBUG
-                                printf("5\r\n");
+                                printf("%d:CONFIGURATION\r\n",STRING_OFFSET_ICONFIGURATION);
 #endif
                                 transfer.remaining = stringIConfigurationDesc()[0];
                                 transfer.ptr = stringIConfigurationDesc();
@@ -136,13 +136,18 @@
                                 break; 
                             case STRING_OFFSET_IINTERFACE:
 #ifdef DEBUG
-                                printf("6\r\n");
+                                printf("%d:INTERFACE\r\n",STRING_OFFSET_IINTERFACE);
 #endif
                                 transfer.remaining = stringIinterfaceDesc()[0];
                                 transfer.ptr = stringIinterfaceDesc();
                                 transfer.direction = DEVICE_TO_HOST;
                                 success = true;
                                 break; 
+                             default:
+                             #ifdef DEBUG
+                                printf("Default:%x\r\n",DESCRIPTOR_INDEX(transfer.setup.wValue));
+                             #endif
+                             break;
             }
             break;
         case INTERFACE_DESCRIPTOR:
@@ -155,6 +160,11 @@
 #endif
             /* TODO: Support is optional, not implemented here */
             break;
+        case QUALIFIER_DESCRIPTOR:
+#ifdef DEBUG
+            printf("qualifier descr\r\n");
+            break;
+#endif        
         default:
 #ifdef DEBUG
             printf("ERROR\r\n");
@@ -199,6 +209,8 @@
         /* Too big */
         return false;
     }
+    for(int i=0; i<packetSize;i++)
+      transfer.ptr[i] = buffer[i];
 
     /* Update transfer */
     transfer.ptr += packetSize;
@@ -211,7 +223,7 @@
         if (transfer.notify)
         {
             /* Notify class layer. */
-            USBCallback_requestCompleted(buffer, packetSize);
+            USBCallback_requestCompleted(transfer.ptr, packetSize);
             transfer.notify = false;
         }
         /* Status stage */
@@ -975,3 +987,4 @@
     };
     return stringIproductDescriptor;
 }
+
--- a/USBHID/USBHID.cpp	Wed Jul 24 17:24:49 2013 +0000
+++ b/USBHID/USBHID.cpp	Thu Jul 25 00:38:09 2013 +0000
@@ -20,28 +20,113 @@
 #include "USBHAL.h"
 #include "USBHID.h"
 
-
-USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
+/* new constructor
+  This constructor adds the ability toset the feature_report length.  This constructor is not the default constructor to maintain backward compatibility.
+*/
+USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length, uint8_t feature_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
 {
     output_length = output_report_length;
     input_length = input_report_length;
+    feature_length = feature_report_length;
+    inputReport.length=input_length;
+    outputReport.length=output_length;
+    featureReport.length=feature_length;
+    
+    callbackSetInputReport = &HID_callbackSetReport;
+    callbackGetInputReport = &HID_callbackGetReport;
+    callbackSetOutputReport = &HID_callbackSetReport;
+    callbackGetOutputReport = &HID_callbackGetReport;
+    callbackSetFeatureReport = &HID_callbackSetReport;
+    callbackGetFeatureReport = &HID_callbackGetReport;
+
+    reportIdleRateInt=0x0;
+    reportIdleRate=0.0;
+    
     if(connect) {
         USBDevice::connect();
     }
 }
 
+/*Original constructor 
+    The original constructor, modified to set the defautls for new features
+    Feature report will be disabled if the old/default constructor is used.
+*/
 
+USBHID::USBHID(uint8_t output_report_length, uint8_t input_report_length,  uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect): USBDevice(vendor_id, product_id, product_release)
+{
+    output_length = output_report_length;
+    input_length = input_report_length;
+    feature_length = 0;
+    inputReport.length=input_length;
+    outputReport.length=output_length;
+    featureReport.length=feature_length;
+    
+    callbackSetInputReport = &HID_callbackSetReport;
+    callbackGetInputReport = &HID_callbackGetReport;
+    callbackSetOutputReport = &HID_callbackSetReport;
+    callbackGetOutputReport = &HID_callbackGetReport;
+    callbackSetFeatureReport = &HID_callbackSetReport;
+    callbackGetFeatureReport = &HID_callbackGetReport;
+
+    reportIdleRateInt=0x0;
+    reportIdleRate=0.0;
+    
+    if(connect) {
+        USBDevice::connect();
+    }
+}
+
+/* IdlePeriodReSend is called when the IDLE rate is non-zero and the ticker period expires.
+   By default: Windows will issue a set-idle rate to Zero when a device is connected.
+   WARNING: The deviceIOcontrol commands for the poll rate get/set do not seem to be implemented in the windows hid driver.
+   When the set_idle rate is greater than zero an input report will be resent every idle period even if there is no change. If the input report 
+   changes via the FillReport command, the change is sent and the Ticker is reset.
+*/
+void USBHID::IdlePeriodReSend(void) { 
+      //Disable the Tickers during the function kicked off from the ticker. 
+     NVIC_DisableIRQ(TIMER3_IRQn);
+     SendReport();
+     NVIC_EnableIRQ(TIMER3_IRQn);    
+}
+
+/* ResetIdleTicker
+   Arms the ticker function in the idle period is greater than zero, otherwise the ticker is disarmed.
+   If a changed report is sent, this command is used to Arm the ticker agian before it has triggered, effectively reseting the countdown.
+*/
+void USBHID::ResetIdleTicker() {
+   if(  reportIdleRateInt > 0 )
+         countDownToReportTrigger.attach(this,&USBHID::IdlePeriodReSend,reportIdleRate);
+     else
+         countDownToReportTrigger.detach();
+}
+
+/* SetReportIdle handles the SET_IDLE controlTransfer.  The idle rate is a minimum of 4ms when enabled.
+   The float conversion to seconds is computerd and the Ticker is armed or disarmed.
+*/
+void USBHID::SetReportIdle(uint16_t wValue){
+     reportIdleRateInt=(wValue>>8);
+     reportIdleRate= reportIdleRateInt * 0.004;
+     
+     #ifdef DEBUG
+     printf("IDLE: %f\r\n",reportIdleRate);
+     #endif
+     ResetIdleTicker();
+}
+
+
+/* Legacy method --> No change */
 bool USBHID::send(HID_REPORT *report)
-{
+{   
     return write(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
 }
 
+/* Legacy method --> No change */
 bool USBHID::sendNB(HID_REPORT *report)
 {
     return writeNB(EPINT_IN, report->data, report->length, MAX_HID_REPORT_SIZE);
 }
 
-
+/* Legacy method --> No change */
 bool USBHID::read(HID_REPORT *report)
 {
     uint32_t bytesRead = 0;
@@ -54,6 +139,7 @@
 }
 
 
+/* Legacy method --> No change */
 bool USBHID::readNB(HID_REPORT *report)
 {
     uint32_t bytesRead = 0;
@@ -65,24 +151,99 @@
     return result;
 }
 
+/* FillInputReport should be the main function that HID developers call. The develop sets a HID report with thier data. And pass it to FillInputReport
+  The procedure will 1) Copy the HID report data to the input_report 2) check to see if the data has changed.
+  Action #1 is important due to USB HID conformance.HID devices are required to implement the GET_REPORT control transfer. This transfer can be used to obtain the input report at any time.
+      With the legacy HID methods, GET_REPORT was not implemented and SET_REPORT always wrote into the output_report. this means the contents of input_report would not be read by a control transfer.
+  Action #2 is important for the IDLE RATE. Windows will set the IDLE rate to 0 for HID devices. Which means that reports should only be sent when the data changes.
+      With the legacy HID methods, A send would always send a HID_REPORT even if it had not changed.     
+*/
+bool USBHID::FillInputReport(HID_REPORT *report)
+{
+    bool changed=false;
+    
+    for(int i =0; i<input_length; i++)
+       if(inputReport.data[i] != report->data[i]) {
+          inputReport.data[i] = report->data[i];
+          changed=true;
+        }
+      
+    if (changed)    
+        return SendReport();
+    else
+        return true;
+}  
 
+
+bool USBHID::FillFeatureReport(HID_REPORT *report)
+{
+    for(int i =0; i<feature_length; i++)
+          featureReport.data[i] = report->data[i];
+    return true;
+}  
+/* SendReport is called by FillReport if the data has changed. It performs 3 action
+ *   1) Trigger an exposed CallBack  This call back is called if a control transfer or interrupt transfer wants to get a INPUT_REPORT
+ *       This functions may be useful to notify your device when a transfer of the input_report is executed. NOTE: The call back occurs BEFORE the actual transfer.
+ *   2) Reset the IDLE ticker. IF the IDEL rate is not zero, the tickerneeds to be reset since we are sending a changed report.
+ *   3) Send the Report via NB transfer on the interupt endpoint.
+*/
+bool USBHID::SendReport()
+{
+    bool result=false;
+ 
+    if ((*callbackGetInputReport)(&inputReport)) {
+        ResetIdleTicker();   
+        result=writeNB(EPINT_IN, inputReport.data, inputReport.length, MAX_HID_REPORT_SIZE);
+    }    
+    return result;
+}  
+
+
+
+/* Legacy method --> No change */
 uint16_t USBHID::reportDescLength() {
+//TODO: Is this a bug? reportDesc() is called and a value that isn't changed is returned.  Why execute the function
     reportDesc();
     return reportLength;
 }
 
+/* GetReportTargetPointer: HID class control transfers Set_report and Get_report require a pointer to the report to write and read data
+   The actual read and write logic is the same only the target report is different. Given the wvalue which  has a value of MSB(TYPE) LSB(reportID), a point to a report can be returned.
+   Multi report is not implemented in this release, but a small change in this function will allow support of multiple reports via control transfers.
+   
+   If a value of 0 for a report was entered when the HID class was instantiated, a NULL report pointer is return which will cause a E0STALL for get/set report action on that type.
+*/
+
+HID_REPORT * USBHID::GetReportTargetPointer(uint16_t wValue){
+   //TODO: Add support for multiple reports.
+    HID_REPORT *targetPtr=NULL;
+    switch(wValue>>8) {
+      case 0x01:  if (input_length >0)
+                     targetPtr=&inputReport;
+                   break;
+      case 0x03:  if (feature_length >0)
+                     targetPtr=&featureReport; 
+                   break;
+      case 0x02:  
+      default: if (output_length >0)
+                   targetPtr=&outputReport; 
+                break;
+    }
+   return targetPtr;
+}
 
 
 //
 //  Route callbacks from lower layers to class(es)
 //
 
-
 // Called in ISR context
 // Called by USBDevice on Endpoint0 request
 // This is used to handle extensions to standard requests
 // and class specific requests
 // Return true if class handles this request
+//Legacy method-->modified to include GET_REPORT, GET_IDLE, SET_IDLE transfers
+//               modified the function of SET_REPORT for multiple types(INPUT,OUTPUT,FEATURE)
 bool USBHID::USBCallback_request() {
     bool success = false;
     CONTROL_TRANSFER * transfer = getTransferPtr();
@@ -132,18 +293,77 @@
 
     if (transfer->setup.bmRequestType.Type == CLASS_TYPE)
     {
+        
+        HID_REPORT *targetPtr=NULL;
+        printf("ReportID: %x\r\n", transfer->setup.wValue & 0xff );
         switch (transfer->setup.bRequest)
         {
              case SET_REPORT:
+                targetPtr=GetReportTargetPointer(transfer->setup.wValue);
+                if (targetPtr==NULL)
+                    break;
                 // First byte will be used for report ID
-                outputReport.data[0] = transfer->setup.wValue & 0xff;
-                outputReport.length = transfer->setup.wLength + 1;
-
-                transfer->remaining = sizeof(outputReport.data) - 1;
-                transfer->ptr = &outputReport.data[1];
+                // BUG: In a control transfer the first byte is the reportid and deviceiocontrol does transmit this byte
+                //      But the interupt transfer strips the reportid byte
+                targetPtr->data[0] = transfer->setup.wValue & 0xff;
+                targetPtr->length = transfer->setup.wLength + 1;
+                if(transfer->remaining >= sizeof(targetPtr->data) - 1) 
+                   transfer->remaining = sizeof(targetPtr->data) - 1;
+                else
+                   transfer->remaining = transfer->setup.wLength;
+                transfer->ptr = &targetPtr->data[1];
                 transfer->direction = HOST_TO_DEVICE;
                 transfer->notify = true;
                 success = true;
+                break;
+             case GET_REPORT:
+                // Required by section 7.2 of the HID Device Class Definition: Mandatory implementation by all devices
+                targetPtr=GetReportTargetPointer(transfer->setup.wValue);
+                if (targetPtr==NULL)
+                    break;
+                // First byte will be used for report ID
+                // BUG: In a control transfer the first byte is the reportid and deviceiocontrol does transmit this byte
+                //      But the interupt transfer strips the reportid byte
+                transfer->setup.wLength = targetPtr->length  - 1;
+                if(transfer->remaining >= sizeof(targetPtr->data) - 1) 
+                   transfer->remaining = sizeof(targetPtr->data) - 1;
+                else
+                   transfer->remaining = transfer->setup.wLength;
+                transfer->ptr = &targetPtr->data[1];
+                transfer->direction = DEVICE_TO_HOST;
+                transfer->notify = true;
+                //Provide a hook for developers to provide thier own call back for Get_Report, prior to the report data is sentin response to a 
+                //   Control IN.
+                success =HIDCallback_GetReportHandler(targetPtr);
+                break;
+            
+            case SET_IDLE:
+               //SET_IDLE works very well, Microsoft is able to use this to set the IDLE rate to 0. Durring testing the default rate was set to 0x80. 
+               //   Normal default setting is zero.
+               //   The microsoft HID driver will throw an invlid function error when IOCTL_HID_GET_POLL_FREQUENCY_MSEC is used.
+               //   wValue {duration:ReportID}
+               //TODO:  To support multipe reports, a HID_REPORT Class should be defined. The ticker and idle methods and objects should be included.
+                SetReportIdle(transfer->setup.wValue);
+                transfer->setup.wLength = 0;
+                transfer->direction = HOST_TO_DEVICE;
+                transfer->remaining = transfer->setup.wLength;
+                transfer->notify = true;
+                success=true;
+            case GET_IDLE:
+                //This functionality has not been tested. The microsoft HID driver will throw an invlid function error when IOCTL_HID_GET_POLL_FREQUENCY_MSEC is used.
+                transfer->setup.wLength = 1;
+                transfer->remaining = transfer->setup.wLength;
+                transfer->ptr = getReportIdlePtr(transfer->setup.wValue & 0xff);
+                transfer->direction = DEVICE_TO_HOST;
+                transfer->notify = true;
+                success=true;
+                break;
+            case GET_PROTOCOL:
+               //TODO: Implement to support BOOT type HIDs
+               //wValue = 0
+            case SET_PROTOCOL:
+               //TODO: Implement to support BOOT type HIDs
+               //wValue = 0 or 1
             default:
                 break;
         }
@@ -152,6 +372,85 @@
     return success;
 }
 
+/* HIDCallback_GetReportHandler provides a useful  set of callbacks for the getting of each type in a report.
+   This can be used to generate the data on the fly(Useful for a feature report) or notification that a report was sent for the device.
+   NOTE: CALLBACKS happen before the actuall data for the report is transmitted.
+*/
+bool USBHID::HIDCallback_GetReportHandler(HID_REPORT *targetPtr) {
+      bool (*callbackGetReport)(HID_REPORT *report);
+      CONTROL_TRANSFER * transfer = getTransferPtr();
+      
+      switch(transfer->setup.wValue>>8) {
+      case HID_INPUT_REPORT_TYPE:
+           callbackGetReport=callbackGetInputReport;
+           break;
+      case HID_OUTPUT_REPORT_TYPE:
+           callbackGetReport=callbackGetOutputReport;
+           break;
+      case HID_FEATURE_REPORT_TYPE:
+           callbackGetReport=callbackGetFeatureReport;
+           break;
+      default:
+        return false;
+      }
+      return (*callbackGetReport)(targetPtr); 
+}
+
+/* HIDCallback_SetReportHandler provides a useful  set of callbacks for the setting of each type in a report.
+   This can be used to update displays after a value is change(Example:NUM lock LED change).
+   NOTE: CALLBACKS happen after the actuall data for the report is recieved.
+*/
+
+bool USBHID::HIDCallback_SetReportHandler(HID_REPORT *targetPtr) {
+      void (*callbackSetReport)(HID_REPORT *report);
+      CONTROL_TRANSFER * transfer = getTransferPtr();
+      
+      switch(transfer->setup.wValue>>8) {
+      case HID_INPUT_REPORT_TYPE:
+           callbackSetReport=callbackSetInputReport;
+           break;
+      case HID_OUTPUT_REPORT_TYPE:
+           callbackSetReport=callbackSetOutputReport;
+           break;
+      case HID_FEATURE_REPORT_TYPE:
+           callbackSetReport=callbackSetFeatureReport;
+           break;
+      default:
+           return false;
+      }
+      (*callbackSetReport)(targetPtr);
+      return true;
+       
+}
+
+/* USBCallback_requestCompleted To implement the set_report call back ability we need to override the requestCompleted function to provide the callback handler hook
+*/
+void USBHID::USBCallback_requestCompleted(uint8_t * buf, uint32_t length){
+     CONTROL_TRANSFER * transfer;
+     HID_REPORT *targetPtr;
+      
+     transfer = getTransferPtr();
+     targetPtr = GetReportTargetPointer(transfer->setup.wValue);
+     USBDevice::USBCallback_requestCompleted(buf, length);
+     //Provide a callback hook for developer use of set_report, called after the completion of the control transfer.
+     if(transfer->setup.bRequest==SET_REPORT) {
+        HIDCallback_SetReportHandler(targetPtr);
+     }      
+}
+
+/* To ensure that the output report is updated on a writeFile interupt transfer, the EP1_OUT_callback is overridden.
+ * additionally a callback for setOutputReport type is trigger
+*/
+bool USBHID::EP1_OUT_callback(){
+    uint32_t bytesRead = 0;
+    bool result;
+    //TODO: Is there a buffer over run issue here? 
+    result = endpointReadResult(EPINT_OUT, outputReport.data, &bytesRead);
+    outputReport.length = bytesRead;
+    (*callbackSetOutputReport)(&outputReport);
+    return result;
+}
+
 
 #define DEFAULT_CONFIGURATION (1)
 
@@ -193,23 +492,28 @@
 }
 
 
-
+/* legacy method .. Modified
+ *  1) Added feature report
+ *  2) Used KEYWORDS for added user readability.
+ */
 uint8_t * USBHID::reportDesc() {
     static uint8_t reportDescriptor[] = {
-        0x06, LSB(0xFFAB), MSB(0xFFAB),
-        0x0A, LSB(0x0200), MSB(0x0200),
-        0xA1, 0x01,         // Collection 0x01
-        0x75, 0x08,         // report size = 8 bits
-        0x15, 0x00,         // logical minimum = 0
-        0x26, 0xFF, 0x00,   // logical maximum = 255
-        0x95, input_length, // report count
-        0x09, 0x01,         // usage
-        0x81, 0x02,         // Input (array)
-        0x95, output_length,// report count
-        0x09, 0x02,         // usage
-        0x91, 0x02,         // Output (array)
-        0xC0                // end collection
-
+        USAGE_PAGE(2), LSB(0xFFAB), MSB(0xFFAB),
+        USAGE(2), LSB(0x0200), MSB(0x0200),
+        COLLECTION(1), 0x01,                     // Collection 0x01
+        REPORT_SIZE(1), 0x08,                    // report size = 8 bits
+        LOGICAL_MINIMUM(1), 0x00,                // logical minimum = 0
+        LOGICAL_MAXIMUM(2), 0xFF, 0x00,          // logical maximum = 255
+        REPORT_COUNT(1), input_length,           // report count
+        USAGE(1), 0x01,                          // usage
+        INPUT(1), 0x02,                          // Input (array)
+        REPORT_COUNT(1), output_length,          // report count
+        USAGE(1), 0x02,                          // usage
+        OUTPUT(1), 0x02,                         // Output (array)
+        REPORT_COUNT(1), feature_length,
+        USAGE(1), 0x03,
+        FEATURE(2), 0x02, 0x01,
+        END_COLLECTION(0)                        // end collection
     };
     reportLength = sizeof(reportDescriptor);
     return reportDescriptor;
--- a/USBHID/USBHID.h	Wed Jul 24 17:24:49 2013 +0000
+++ b/USBHID/USBHID.h	Thu Jul 25 00:38:09 2013 +0000
@@ -27,7 +27,6 @@
 #include "USBHID_Types.h"
 #include "USBDevice.h"
 
-
 /**
  * USBHID example
  * @code
@@ -51,15 +50,18 @@
 public:
 
     /**
-    * Constructor
+    * Constructors
     *
     * @param output_report_length Maximum length of a sent report (up to 64 bytes) (default: 64 bytes)
     * @param input_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
+    * @param report_report_length Maximum length of a received report (up to 64 bytes) (default: 64 bytes)
     * @param vendor_id Your vendor_id
     * @param product_id Your product_id
     * @param product_release Your preoduct_release
     * @param connect Connect the device
     */
+    USBHID(uint8_t output_report_length , uint8_t input_report_length , uint8_t feature_report_length , uint16_t vendor_id , uint16_t product_id , uint16_t product_release , bool connect );
+    /* default constructor to maintain backwards compatibility. */
     USBHID(uint8_t output_report_length = 64, uint8_t input_report_length = 64, uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0006, uint16_t product_release = 0x0001, bool connect = true);
 
 
@@ -95,6 +97,36 @@
     * @returns true if successful
     */
     bool readNB(HID_REPORT * report);
+    
+    /**
+    * Provide function to trigger default report transfer
+    *
+    * @param HID_REPORT
+    * @returns true if succsful
+    * The devloper should always use FillReport, The IDLE logic will send a report if the value has changed, or if the idle period expires.
+    */
+    bool FillInputReport(HID_REPORT *report);
+    bool FillFeatureReport(HID_REPORT *report);
+    
+    
+    /**
+    * Callback poiters to functions.
+    *
+    * @param report pointer to the report to fill
+    * These allow a user program to hook on get/set report control setup stages.
+    */
+    void (*callbackSetInputReport)(HID_REPORT *report);
+    bool (*callbackGetInputReport)(HID_REPORT *report);
+    void (*callbackSetOutputReport)(HID_REPORT *report);
+    bool (*callbackGetOutputReport)(HID_REPORT *report);
+    void (*callbackSetFeatureReport)(HID_REPORT *report);
+    bool (*callbackGetFeatureReport)(HID_REPORT *report);
+    
+    /* This function should be private, but is exposed to allow a developer to reenable IDLE values > zero after windows sets the value to zero. 
+        This is due to microsoft windows HID driver not implementing IOCTL_HID_SET_POLL_FREQUENCY_MSEC/IOCTL_HID_GET_POLL_FREQUENCY_MSEC
+    */
+    virtual void SetReportIdle(uint16_t wValue);
+    
 
 protected:
     uint16_t reportLength;
@@ -141,9 +173,16 @@
     *
     * @param report Data and length received
     */
-    virtual void HID_callbackSetReport(HID_REPORT *report){};
-
-
+    static void HID_callbackSetReport(HID_REPORT *report){};
+    
+    /*
+    * HID Report received by GET_REPORT request. Warning: Called in ISR context
+    * First byte of data will be the report ID
+    *
+    * @param report Data and length received
+    */
+    static bool HID_callbackGetReport(HID_REPORT *report){return true;};
+   
     /*
     * Called by USBDevice on Endpoint0 request. Warning: Called in ISR context
     * This is used to handle extensions to standard requests
@@ -152,21 +191,58 @@
     * @returns true if class handles this request
     */
     virtual bool USBCallback_request();
-
+    /*
+    * Called by USBDevice on Endpoint0 request completion
+    * if the 'notify' flag has been set to true. Warning: Called in ISR context
+    *
+    * In this case it is used to indicate that a HID report has
+    * been received from the host on endpoint 0
+    *
+    * @param buf buffer received on endpoint 0
+    * @param length length of this buffer
+    */
+    virtual void USBCallback_requestCompleted(uint8_t * buf, uint32_t length);
 
     /*
-    * Called by USBDevice layer. Set configuration of the device.
-    * For instance, you can add all endpoints that you need on this function.
-    *
-    * @param configuration Number of the configuration
-    * @returns true if class handles this request
+    * Called by USBDevice layer. to ensure that control transfers and interupt transfers work on the same reports.
+    */
+    virtual bool EP1_OUT_callback();
+    
+    /* Called by FillInputReport when data has changed, and transmits the data. */
+    bool SendReport(void);
+    
+    /*
+    * Called by USBDevice layer.to set configuration
     */
     virtual bool USBCallback_setConfiguration(uint8_t configuration);
-
+    
+    /* tells SET_IDLE/GET_IDLE where the IDE rate value is. */
+    
+    virtual uint8_t * getReportIdlePtr(uint8_t reportID){ return &reportIdleRateInt; };
+    
+    
 private:
+   // TODO: HID Reports should be dynamically malloced to save memory and prepare for multi-reports 
+    HID_REPORT inputReport;
     HID_REPORT outputReport;
+    HID_REPORT featureReport;
     uint8_t output_length;
     uint8_t input_length;
+    uint8_t feature_length;
+ 
+    //TODO: REPORT clsss should be created to handle MULTI-report
+    //Implementation items for IDLE rate (TICKER)
+    float reportIdleRate;
+    uint8_t reportIdleRateInt;
+    Ticker countDownToReportTrigger;
+    void ResetIdleTicker(void);
+    void IdlePeriodReSend(void);
+   
+    //Report REPORT data pointer retrieval.
+    HID_REPORT * GetReportTargetPointer(uint16_t wValue);
+    //Report Set/GET REPORT callback handlers
+    bool HIDCallback_GetReportHandler(HID_REPORT *targetPtr);
+    bool HIDCallback_SetReportHandler(HID_REPORT *targetPtr);
 };
 
 #endif
--- a/USBHID/USBHID_Types.h	Wed Jul 24 17:24:49 2013 +0000
+++ b/USBHID/USBHID_Types.h	Thu Jul 25 00:38:09 2013 +0000
@@ -35,10 +35,12 @@
 #define REPORT_DESCRIPTOR       (34)
 
 /* Class requests */
-#define GET_REPORT (0x1)
-#define GET_IDLE   (0x2)
-#define SET_REPORT (0x9)
-#define SET_IDLE   (0xa)
+#define GET_REPORT   (0x1)
+#define GET_IDLE     (0x2)
+#define GET_PROTOCOL (0x3)
+#define SET_REPORT   (0x9)
+#define SET_IDLE     (0xa)
+#define SET_PROTOCOL (0xb)
 
 /* HID Class Report Descriptor */
 /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes */
@@ -78,9 +80,13 @@
 #define DELIMITER(size)             (0xa8 | size)
 
 /* HID Report */
+/* Each report can have input,output, and feature type thetype codes are defined below*/
+#define HID_INPUT_REPORT_TYPE  (0x01)
+#define HID_OUTPUT_REPORT_TYPE  (0x02)
+#define HID_FEATURE_REPORT_TYPE  (0x03)
+
 /* Where report IDs are used the first byte of 'data' will be the */
 /* report ID and 'length' will include this report ID byte. */
-
 #define MAX_HID_REPORT_SIZE (64)
 
 typedef struct {