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 "../../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         uint16_t          UsageStack
[HID_USAGE_STACK_DEPTH
]; 
  41         uint8_t           UsageStackSize               
= 0; 
  42         uint16_t          BitOffsetIn                  
= 0; 
  43         uint16_t          BitOffsetOut                 
= 0; 
  44 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
  45         uint16_t          BitOffsetFeature             
= 0; 
  47         HID_CollectionPath_t
* CurrCollectionPath       
= NULL
; 
  49         memset((void*)ParserData
, 0x00, sizeof(HID_ReportInfo_t
)); 
  50         memset((void*)StateTable
, 0x00, sizeof(StateTable
)); 
  54                 uint32_t ReportItemData 
= 0; 
  56                 switch (*ReportData 
& DATA_SIZE_MASK
) 
  59                                 ReportItemData 
= *((uint32_t*)(ReportData 
+ 1)); 
  62                                 ReportItemData 
= *((uint16_t*)(ReportData 
+ 1)); 
  65                                 ReportItemData 
= *((uint8_t*)(ReportData 
+ 1)); 
  69                 switch (*ReportData 
& (TYPE_MASK 
| TAG_MASK
)) 
  71                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  72                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH
]) 
  73                                   return HID_PARSE_HIDStackOverflow
; 
  75                                 memcpy((CurrStateTable 
- 1), 
  77                                        sizeof(HID_ReportItem_t
)); 
  81                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  82                                 if (CurrStateTable 
== &StateTable
[0]) 
  83                                   return HID_PARSE_HIDStackUnderflow
; 
  87                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  88                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
  90                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
  91                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
  93                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
  94                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
  96                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
  97                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
  99                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
 100                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 102                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 103                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 105                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 106                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 108                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 109                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 111                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 112                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 114                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 115                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 117                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 118                                 if (UsageStackSize 
== HID_USAGE_STACK_DEPTH
) 
 119                                   return HID_PARSE_UsageStackOverflow
; 
 121                                 UsageStack
[UsageStackSize
++] = ReportItemData
; 
 123                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 124                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= ReportItemData
; 
 126                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 127                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= ReportItemData
; 
 129                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 130                                 if (CurrCollectionPath 
== NULL
) 
 132                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 136                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 138                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 140                                         while (CurrCollectionPath
->Parent 
!= NULL
); 
 142                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS
]) 
 143                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 145                                                 CurrCollectionPath
++; 
 148                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 151                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 152                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 156                                         CurrCollectionPath
->Usage
.Usage 
= UsageStack
[0]; 
 158                                         for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 159                                           UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 165                                         CurrCollectionPath
->Usage
.Usage 
= 0; 
 169                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 170                                 if (CurrCollectionPath 
== NULL
) 
 171                                   return HID_PARSE_UnexpectedEndCollection
; 
 173                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 176                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 177                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 178 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
 179                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 181                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 183                                         HID_ReportItem_t
* CurrReportItem 
= &ParserData
->ReportItems
[ParserData
->TotalReportItems
]; 
 185                                         if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 186                                           return HID_PARSE_InsufficientReportItems
; 
 188                                         memcpy(&CurrReportItem
->Attributes
, 
 189                                                &CurrStateTable
->Attributes
, 
 190                                                sizeof(HID_ReportItem_Attributes_t
)); 
 192                                         CurrReportItem
->ItemFlags      
= ReportItemData
; 
 193                                         CurrReportItem
->CollectionPath 
= CurrCollectionPath
; 
 194                                         CurrReportItem
->ReportID       
= CurrStateTable
->ReportID
; 
 198                                                 CurrReportItem
->Attributes
.Usage
.Usage 
= UsageStack
[0]; 
 200                                                 for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 201                                                   UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 207                                                 CurrReportItem
->Attributes
.Usage
.Usage 
= 0; 
 210                                         switch (*ReportData 
& TAG_MASK
) 
 213                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_In
; 
 214                                                         CurrReportItem
->BitOffset 
= BitOffsetIn
; 
 216                                                         BitOffsetIn 
+= CurrStateTable
->Attributes
.BitSize
; 
 219                                                 case TAG_MAIN_OUTPUT
: 
 220                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_Out
; 
 221                                                         CurrReportItem
->BitOffset 
= BitOffsetOut
; 
 223                                                         BitOffsetOut 
+= CurrStateTable
->Attributes
.BitSize
; 
 226 #if defined(HID_ENABLE_FEATURE_PROCESSING) 
 227                                                 case TAG_MAIN_FEATURE
: 
 228                                                         CurrReportItem
->ItemType  
= REPORT_ITEM_TYPE_Feature
;                                            
 229                                                         CurrReportItem
->BitOffset 
= BitOffsetFeature
; 
 231                                                         BitOffsetFeature 
+= CurrStateTable
->Attributes
.BitSize
;          
 237 #if !defined(HID_INCLUDE_CONSTANT_DATA_ITEMS) 
 238                                         if (!(ReportItemData 
& IOF_CONSTANT
)) 
 239                                           ParserData
->TotalReportItems
++; 
 241                                         ParserData
->TotalReportItems
++; 
 250                 if ((*ReportData 
& TYPE_MASK
) == TYPE_MAIN
) 
 252                         CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= 0; 
 253                         CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= 0; 
 257                 switch (*ReportData 
& DATA_SIZE_MASK
) 
 278         return HID_PARSE_Successful
; 
 281 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 283         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 284         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 285         uint32_t BitMask      
= (1 << 0); 
 287         ReportItem
->Value 
= 0; 
 289         if (ReportItem
->ReportID
) 
 291                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 297         while (DataBitsRem
--) 
 299                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 300                   ReportItem
->Value 
|= BitMask
; 
 309 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, const HID_ReportItem_t
* ReportItem
) 
 311         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 312         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 313         uint32_t BitMask      
= (1 << 0); 
 315         if (ReportItem
->ReportID
) 
 317                 ReportData
[0] = ReportItem
->ReportID
; 
 321         while (DataBitsRem
--) 
 323                 if (ReportItem
->Value 
& (1 << (CurrentBit 
% 8))) 
 324                   ReportData
[CurrentBit 
/ 8] |= BitMask
;