3      Copyright (C) Dean Camera, 2010. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, distribute, and sell this  
  13   software and its documentation for any purpose is hereby granted 
  14   without fee, provided that the above copyright notice appear in  
  15   all copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting  
  17   documentation, and that the name of the author not be used in  
  18   advertising or publicity pertaining to distribution of the  
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  31 #include "../../HighLevel/USBMode.h" 
  32 #if defined(USB_CAN_BE_HOST) 
  34 #include "HIDParser.h" 
  36 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData
, uint16_t ReportSize
, HID_ReportInfo_t
* const ParserData
) 
  38         HID_StateTable_t      StateTable
[HID_STATETABLE_STACK_DEPTH
]; 
  39         HID_StateTable_t
*     CurrStateTable          
= &StateTable
[0]; 
  40         HID_CollectionPath_t
* CurrCollectionPath      
= NULL
; 
  41         HID_ReportSizeInfo_t
* CurrReportIDInfo        
= &ParserData
->ReportIDSizes
[0];                   
  42         uint16_t              UsageList
[HID_USAGE_STACK_DEPTH
]; 
  43         uint8_t               UsageListSize           
= 0; 
  44         HID_MinMax_t          UsageMinMax             
= {0, 0}; 
  46         memset(ParserData
,       0x00, sizeof(HID_ReportInfo_t
)); 
  47         memset(CurrStateTable
,   0x00, sizeof(HID_StateTable_t
)); 
  48         memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
  50         ParserData
->TotalDeviceReports 
= 1;      
  54                 uint8_t  HIDReportItem  
= *ReportData
; 
  55                 uint32_t ReportItemData 
= 0; 
  60                 switch (HIDReportItem 
& DATA_SIZE_MASK
) 
  63                                 ReportItemData  
= *((uint32_t*)ReportData
); 
  68                                 ReportItemData  
= *((uint16_t*)ReportData
); 
  73                                 ReportItemData  
= *((uint8_t*)ReportData
); 
  79                 switch (HIDReportItem 
& (TYPE_MASK 
| TAG_MASK
)) 
  81                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  82                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH 
- 1]) 
  83                                   return HID_PARSE_HIDStackOverflow
; 
  85                                 memcpy((CurrStateTable 
+ 1), 
  87                                        sizeof(HID_ReportItem_t
)); 
  91                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  92                                 if (CurrStateTable 
== &StateTable
[0]) 
  93                                   return HID_PARSE_HIDStackUnderflow
; 
  97                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  98                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
 100                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
 101                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
 103                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
 104                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
 106                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
 107                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
 109                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
 110                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 112                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 113                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 115                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 116                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 118                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 119                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 121                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 122                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 124                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 125                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 127                                 if (ParserData
->UsingReportIDs
) 
 129                                         CurrReportIDInfo 
= NULL
; 
 131                                         for (uint8_t i 
= 0; i 
< ParserData
->TotalDeviceReports
; i
++) 
 133                                                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== CurrStateTable
->ReportID
) 
 135                                                         CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[i
]; 
 140                                         if (CurrReportIDInfo 
== NULL
) 
 142                                                 if (ParserData
->TotalDeviceReports 
== HID_MAX_REPORT_IDS
) 
 143                                                   return HID_PARSE_InsufficientReportIDItems
; 
 145                                                 CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports
++]; 
 146                                                 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
 150                                 ParserData
->UsingReportIDs 
= true;                               
 152                                 CurrReportIDInfo
->ReportID 
= CurrStateTable
->ReportID
; 
 154                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 155                                 if (UsageListSize 
== HID_USAGE_STACK_DEPTH
) 
 156                                   return HID_PARSE_UsageListOverflow
; 
 158                                 UsageList
[UsageListSize
++] = ReportItemData
; 
 160                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 161                                 UsageMinMax
.Minimum 
= ReportItemData
; 
 163                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 164                                 UsageMinMax
.Maximum 
= ReportItemData
; 
 166                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 167                                 if (CurrCollectionPath 
== NULL
) 
 169                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 173                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 175                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 177                                         while (CurrCollectionPath
->Parent 
!= NULL
) 
 179                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS 
- 1]) 
 180                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 182                                                 CurrCollectionPath
++; 
 185                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 188                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 189                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 193                                         CurrCollectionPath
->Usage
.Usage 
= UsageList
[0]; 
 195                                         for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 196                                           UsageList
[i
] = UsageList
[i 
+ 1]; 
 200                                 else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 202                                         CurrCollectionPath
->Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 206                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 207                                 if (CurrCollectionPath 
== NULL
) 
 208                                   return HID_PARSE_UnexpectedEndCollection
; 
 210                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 212                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 213                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 214                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 215                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 217                                         HID_ReportItem_t NewReportItem
; 
 219                                         memcpy(&NewReportItem
.Attributes
, 
 220                                                &CurrStateTable
->Attributes
, 
 221                                                sizeof(HID_ReportItem_Attributes_t
)); 
 223                                         NewReportItem
.ItemFlags      
= ReportItemData
; 
 224                                         NewReportItem
.CollectionPath 
= CurrCollectionPath
; 
 225                                         NewReportItem
.ReportID       
= CurrStateTable
->ReportID
; 
 229                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageList
[0]; 
 231                                                 for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 232                                                   UsageList
[i
] = UsageList
[i 
+ 1]; 
 236                                         else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 238                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 241                                         uint8_t ItemTag 
= (HIDReportItem 
& TAG_MASK
); 
 243                                         if (ItemTag 
== TAG_MAIN_INPUT
) 
 244                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_In
; 
 245                                         else if (ItemTag 
== TAG_MAIN_OUTPUT
) 
 246                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Out
; 
 248                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Feature
; 
 250                                         NewReportItem
.BitOffset 
= CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]; 
 252                                         CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
] += CurrStateTable
->Attributes
.BitSize
; 
 254                                         if (ParserData
->LargestReportSizeBits 
< NewReportItem
.BitOffset
) 
 255                                           ParserData
->LargestReportSizeBits 
= NewReportItem
.BitOffset
; 
 257                                         if (!(ReportItemData 
& IOF_CONSTANT
) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem
)) 
 259                                                 if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 260                                                   return HID_PARSE_InsufficientReportItems
; 
 262                                                 memcpy(&ParserData
->ReportItems
[ParserData
->TotalReportItems
], 
 263                                                        &NewReportItem
, sizeof(HID_ReportItem_t
)); 
 265                                                 ParserData
->TotalReportItems
++; 
 272                 if ((HIDReportItem 
& TYPE_MASK
) == TYPE_MAIN
) 
 274                         UsageMinMax
.Minimum 
= 0; 
 275                         UsageMinMax
.Maximum 
= 0; 
 280         if (!(ParserData
->TotalReportItems
)) 
 281           return HID_PARSE_NoUnfilteredReportItems
; 
 283         return HID_PARSE_Successful
; 
 286 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 288         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 289         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 290         uint32_t BitMask      
= (1 << 0); 
 292         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 293         ReportItem
->Value 
= 0; 
 295         if (ReportItem
->ReportID
) 
 297                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 303         while (DataBitsRem
--) 
 305                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 306                   ReportItem
->Value 
|= BitMask
; 
 315 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 317         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 318         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 319         uint32_t BitMask      
= (1 << 0); 
 321         if (ReportItem
->ReportID
) 
 323                 ReportData
[0] = ReportItem
->ReportID
; 
 327         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 329         while (DataBitsRem
--) 
 331                 if (ReportItem
->Value 
& (1 << (CurrentBit 
% 8))) 
 332                   ReportData
[CurrentBit 
/ 8] |= BitMask
; 
 339 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t
* const ParserData
, const uint8_t ReportID
, const uint8_t ReportType
) 
 341         for (uint8_t i 
= 0; i 
< HID_MAX_REPORT_IDS
; i
++) 
 343                 uint16_t ReportSizeBits 
= ParserData
->ReportIDSizes
[i
].ReportSizeBits
[ReportType
]; 
 345                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== ReportID
) 
 346                   return ((ReportSizeBits 
>> 3) + ((ReportSizeBits 
& 0x07) ? 
1 : 0));