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         HID_CollectionPath_t
* CurrCollectionPath      
= NULL
; 
  41         HID_ReportSizeInfo_t
* CurrReportIDInfo        
= &ParserData
->ReportIDSizes
[0];                   
  42         uint16_t              UsageStack
[HID_USAGE_STACK_DEPTH
]; 
  43         uint8_t               UsageStackSize          
= 0; 
  45         memset(ParserData
,       0x00, sizeof(HID_ReportInfo_t
)); 
  46         memset(CurrStateTable
,   0x00, sizeof(HID_StateTable_t
)); 
  47         memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
  49         ParserData
->TotalDeviceReports 
= 1;      
  53                 uint8_t  HIDReportItem  
= *ReportData
; 
  54                 uint32_t ReportItemData 
= 0; 
  59                 switch (HIDReportItem 
& DATA_SIZE_MASK
) 
  62                                 ReportItemData  
= *((uint32_t*)ReportData
); 
  67                                 ReportItemData  
= *((uint16_t*)ReportData
); 
  72                                 ReportItemData  
= *((uint8_t*)ReportData
); 
  78                 switch (HIDReportItem 
& (TYPE_MASK 
| TAG_MASK
)) 
  80                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  81                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH 
- 1]) 
  82                                   return HID_PARSE_HIDStackOverflow
; 
  84                                 memcpy((CurrStateTable 
+ 1), 
  86                                        sizeof(HID_ReportItem_t
)); 
  90                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  91                                 if (CurrStateTable 
== &StateTable
[0]) 
  92                                   return HID_PARSE_HIDStackUnderflow
; 
  96                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  97                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
  99                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
 100                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
 102                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
 103                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
 105                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
 106                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
 108                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
 109                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 111                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 112                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 114                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 115                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 117                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 118                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 120                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 121                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 123                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 124                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 126                                 if (ParserData
->UsingReportIDs
) 
 128                                         CurrReportIDInfo 
= NULL
; 
 130                                         for (uint8_t i 
= 0; i 
< ParserData
->TotalDeviceReports
; i
++) 
 132                                                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== CurrStateTable
->ReportID
) 
 134                                                         CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[i
]; 
 139                                         if (CurrReportIDInfo 
== NULL
) 
 141                                                 if (ParserData
->TotalDeviceReports
++ > HID_MAX_REPORT_IDS
) 
 142                                                   return HID_PARSE_InsufficientReportIDItems
; 
 144                                                 CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports 
- 1]; 
 145                                                 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
 149                                 ParserData
->UsingReportIDs 
= true;                               
 151                                 CurrReportIDInfo
->ReportID     
= CurrStateTable
->ReportID
; 
 153                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 154                                 if (UsageStackSize 
== HID_USAGE_STACK_DEPTH
) 
 155                                   return HID_PARSE_UsageStackOverflow
; 
 157                                 UsageStack
[UsageStackSize
++] = ReportItemData
; 
 159                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 160                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= ReportItemData
; 
 162                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 163                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= ReportItemData
; 
 165                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 166                                 if (CurrCollectionPath 
== NULL
) 
 168                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 172                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 174                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 176                                         while (CurrCollectionPath
->Parent 
!= NULL
) 
 178                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS 
- 1]) 
 179                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 181                                                 CurrCollectionPath
++; 
 184                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 187                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 188                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 192                                         CurrCollectionPath
->Usage
.Usage 
= UsageStack
[0]; 
 194                                         for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 195                                           UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 201                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 202                                 if (CurrCollectionPath 
== NULL
) 
 203                                   return HID_PARSE_UnexpectedEndCollection
; 
 205                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 207                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 208                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 209                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 210                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 212                                         HID_ReportItem_t NewReportItem
; 
 214                                         memcpy(&NewReportItem
.Attributes
, 
 215                                                &CurrStateTable
->Attributes
, 
 216                                                sizeof(HID_ReportItem_Attributes_t
)); 
 218                                         NewReportItem
.ItemFlags      
= ReportItemData
; 
 219                                         NewReportItem
.CollectionPath 
= CurrCollectionPath
; 
 220                                         NewReportItem
.ReportID       
= CurrStateTable
->ReportID
; 
 224                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageStack
[0]; 
 226                                                 for (uint8_t i 
= 0; i 
< UsageStackSize
; i
++) 
 227                                                   UsageStack
[i
] = UsageStack
[i 
+ 1]; 
 232                                         switch (HIDReportItem 
& TAG_MASK
) 
 235                                                         NewReportItem
.ItemType  
= REPORT_ITEM_TYPE_In
; 
 237                                                 case TAG_MAIN_OUTPUT
: 
 238                                                         NewReportItem
.ItemType  
= REPORT_ITEM_TYPE_Out
; 
 240                                                 case TAG_MAIN_FEATURE
: 
 241                                                         NewReportItem
.ItemType  
= REPORT_ITEM_TYPE_Feature
;                                              
 245                                         NewReportItem
.BitOffset 
= CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]; 
 247                                         CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
] += CurrStateTable
->Attributes
.BitSize
; 
 249                                         if (ParserData
->LargestReportSizeBits 
< NewReportItem
.BitOffset
) 
 250                                           ParserData
->LargestReportSizeBits 
= NewReportItem
.BitOffset
; 
 252                                         if (!(ReportItemData 
& IOF_CONSTANT
) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem
)) 
 254                                                 if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 255                                                   return HID_PARSE_InsufficientReportItems
; 
 257                                                 memcpy(&ParserData
->ReportItems
[ParserData
->TotalReportItems
], 
 258                                                        &NewReportItem
, sizeof(HID_ReportItem_t
)); 
 260                                                 ParserData
->TotalReportItems
++; 
 267                 if ((HIDReportItem 
& TYPE_MASK
) == TYPE_MAIN
) 
 269                         CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= 0; 
 270                         CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= 0; 
 275         if (!(ParserData
->TotalReportItems
)) 
 276           return HID_PARSE_NoUnfilteredReportItems
; 
 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
; 
 331 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t
* const ParserData
, const uint8_t ReportID
, const uint8_t ReportType
) 
 333         for (uint8_t i 
= 0; i 
< HID_MAX_REPORT_IDS
; i
++) 
 335                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== ReportID
) 
 336                   return ParserData
->ReportIDSizes
[i
].ReportSizeBits
[ReportType
];