3      Copyright (C) Dean Camera, 2009. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, and distribute this software 
  13   and its documentation for any purpose and without fee is hereby 
  14   granted, provided that the above copyright notice appear in all 
  15   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 "HIDParser.h" 
  33 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData
, uint16_t ReportSize
, HID_ReportInfo_t
* const ParserData
) 
  35         HID_StateTable_t  StateTable
[HID_STATETABLE_STACK_DEPTH
]; 
  36         HID_StateTable_t
* CurrStateTable               
= &StateTable
[0]; 
  37         uint16_t          UsageStack
[HID_USAGE_STACK_DEPTH
]; 
  38         uint8_t           UsageStackSize               
= 0; 
  39         uint16_t          BitOffsetIn                  
= 0; 
  40         uint16_t          BitOffsetOut                 
= 0; 
  41 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
  42         uint16_t          BitOffsetFeature             
= 0; 
  44         HID_CollectionPath_t
* CurrCollectionPath       
= NULL
; 
  46         memset((void*)ParserData
, 0x00, sizeof(HID_ReportInfo_t
)); 
  47         memset((void*)StateTable
, 0x00, sizeof(StateTable
)); 
  51                 uint32_t ReportItemData 
= 0; 
  53                 switch (*ReportData 
& DATA_SIZE_MASK
) 
  56                                 ReportItemData 
= *((uint32_t*)(ReportData 
+ 1)); 
  59                                 ReportItemData 
= *((uint16_t*)(ReportData 
+ 1)); 
  62                                 ReportItemData 
= *((uint8_t*)(ReportData 
+ 1)); 
  66                 switch (*ReportData 
& (TYPE_MASK 
| TAG_MASK
)) 
  68                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  69                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH
]) 
  70                                   return HID_PARSE_HIDStackOverflow
; 
  72                                 memcpy((CurrStateTable 
- 1), 
  74                                        sizeof(HID_ReportItem_t
)); 
  78                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  79                                 if (CurrStateTable 
== &StateTable
[0]) 
  80                                   return HID_PARSE_HIDStackUnderflow
; 
  84                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  85                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
  87                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
  88                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
  90                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
  91                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
  93                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
  94                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
  96                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
  97                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
  99                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 100                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 102                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 103                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 105                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 106                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 108                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 109                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 111                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 112                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 114                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 115                                 if (UsageStackSize 
== HID_USAGE_STACK_DEPTH
) 
 116                                   return HID_PARSE_UsageStackOverflow
; 
 118                                 UsageStack
[UsageStackSize
++] = ReportItemData
; 
 120                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 121                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= ReportItemData
; 
 123                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 124                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= ReportItemData
; 
 126                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 127                                 if (CurrCollectionPath 
== NULL
) 
 129                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 133                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 135                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 137                                         while (CurrCollectionPath
->Parent 
!= NULL
); 
 139                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS
]) 
 140                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 142                                                 CurrCollectionPath
++; 
 145                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 148                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 149                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 153                                         CurrCollectionPath
->Usage
.Usage 
= UsageStack
[0]; 
 155                                         for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 156                                           UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 162                                         CurrCollectionPath
->Usage
.Usage 
= 0; 
 166                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 167                                 if (CurrCollectionPath 
== NULL
) 
 168                                   return HID_PARSE_UnexpectedEndCollection
; 
 170                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 173                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 174                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 175 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
 176                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 178                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 180                                         HID_ReportItem_t
* CurrReportItem 
= &ParserData
->ReportItems
[ParserData
->TotalReportItems
]; 
 182                                         if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 183                                           return HID_PARSE_InsufficientReportItems
; 
 185                                         memcpy(&CurrReportItem
->Attributes
, 
 186                                                &CurrStateTable
->Attributes
, 
 187                                                sizeof(HID_ReportItem_Attributes_t
)); 
 189                                         CurrReportItem
->ItemFlags      
= ReportItemData
; 
 190                                         CurrReportItem
->CollectionPath 
= CurrCollectionPath
; 
 191                                         CurrReportItem
->ReportID       
= CurrStateTable
->ReportID
; 
 195                                                 CurrReportItem
->Attributes
.Usage
.Usage 
= UsageStack
[0]; 
 197                                                 for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 198                                                   UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 204                                                 CurrReportItem
->Attributes
.Usage
.Usage 
= 0; 
 207                                         switch (*ReportData 
& TAG_MASK
) 
 210                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_In
; 
 211                                                         CurrReportItem
->BitOffset 
= BitOffsetIn
; 
 213                                                         BitOffsetIn 
+= CurrStateTable
->Attributes
.BitSize
; 
 216                                                 case TAG_MAIN_OUTPUT
: 
 217                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_Out
; 
 218                                                         CurrReportItem
->BitOffset 
= BitOffsetOut
; 
 220                                                         BitOffsetOut 
+= CurrStateTable
->Attributes
.BitSize
; 
 223 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
 224                                                 case TAG_MAIN_FEATURE
: 
 225                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_Feature
;                                            
 226                                                         CurrReportItem
->BitOffset 
= BitOffsetFeature
; 
 228                                                         BitOffsetFeature 
+= CurrStateTable
->Attributes
.BitSize
;          
 234 #if !defined(HID_INCLUDE_CONSTANT_DATA_ITEMS) 
 235                                         if (!(ReportItemData 
& IOF_CONSTANT
)) 
 236                                           ParserData
->TotalReportItems
++; 
 238                                         ParserData
->TotalReportItems
++; 
 247                 if ((*ReportData 
& TYPE_MASK
) == TYPE_MAIN
) 
 249                         CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= 0; 
 250                         CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= 0; 
 254                 switch (*ReportData 
& DATA_SIZE_MASK
) 
 275         return HID_PARSE_Successful
; 
 278 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 280         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 281         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 282         uint32_t BitMask      
= (1 << 0); 
 284         ReportItem
->Value 
= 0; 
 286         if (ReportItem
->ReportID
) 
 288                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 294         while (DataBitsRem
--) 
 296                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 297                   ReportItem
->Value 
|= BitMask
; 
 306 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, const HID_ReportItem_t
* ReportItem
) 
 308         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 309         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 310         uint32_t BitMask      
= (1 << 0); 
 312         if (ReportItem
->ReportID
) 
 314                 ReportData
[0] = ReportItem
->ReportID
; 
 318         while (DataBitsRem
--) 
 320                 if (ReportItem
->Value 
& (1 << (CurrentBit 
% 8))) 
 321                   ReportData
[CurrentBit 
/ 8] |= BitMask
;