3      Copyright (C) Dean Camera, 2018. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2018  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 disclaims 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 #define  __INCLUDE_FROM_USB_DRIVER 
  32 #define  __INCLUDE_FROM_HID_DRIVER 
  33 #include "HIDParser.h" 
  35 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData
, 
  37                              HID_ReportInfo_t
* const ParserData
) 
  39         HID_StateTable_t      StateTable
[HID_STATETABLE_STACK_DEPTH
]; 
  40         HID_StateTable_t
*     CurrStateTable     
= &StateTable
[0]; 
  41         HID_CollectionPath_t
* CurrCollectionPath 
= NULL
; 
  42         HID_ReportSizeInfo_t
* CurrReportIDInfo   
= &ParserData
->ReportIDSizes
[0]; 
  43         uint16_t              UsageList
[HID_USAGE_STACK_DEPTH
]; 
  44         uint8_t               UsageListSize      
= 0; 
  45         HID_MinMax_t          UsageMinMax        
= {0, 0}; 
  47         memset(ParserData
,       0x00, sizeof(HID_ReportInfo_t
)); 
  48         memset(CurrStateTable
,   0x00, sizeof(HID_StateTable_t
)); 
  49         memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
  51         ParserData
->TotalDeviceReports 
= 1; 
  55                 uint8_t  HIDReportItem  
= *ReportData
; 
  56                 uint32_t ReportItemData
; 
  61                 switch (HIDReportItem 
& HID_RI_DATA_SIZE_MASK
) 
  63                         case HID_RI_DATA_BITS_32
: 
  64                                 ReportItemData  
= (((uint32_t)ReportData
[3] << 24) | ((uint32_t)ReportData
[2] << 16) | 
  65                                                ((uint16_t)ReportData
[1] << 8)  | ReportData
[0]); 
  70                         case HID_RI_DATA_BITS_16
: 
  71                                 ReportItemData  
= (((uint16_t)ReportData
[1] << 8) | (ReportData
[0])); 
  76                         case HID_RI_DATA_BITS_8
: 
  77                                 ReportItemData  
= ReportData
[0]; 
  87                 switch (HIDReportItem 
& (HID_RI_TYPE_MASK 
| HID_RI_TAG_MASK
)) 
  90                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH 
- 1]) 
  91                                   return HID_PARSE_HIDStackOverflow
; 
  93                                 memcpy((CurrStateTable 
+ 1), 
  95                                        sizeof(HID_StateTable_t
)); 
 101                                 if (CurrStateTable 
== &StateTable
[0]) 
 102                                   return HID_PARSE_HIDStackUnderflow
; 
 107                         case HID_RI_USAGE_PAGE(0): 
 108                                 if ((HIDReportItem 
& HID_RI_DATA_SIZE_MASK
) == HID_RI_DATA_BITS_32
) 
 109                                   CurrStateTable
->Attributes
.Usage
.Page 
= (ReportItemData 
>> 16); 
 111                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
 114                         case HID_RI_LOGICAL_MINIMUM(0): 
 115                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
 118                         case HID_RI_LOGICAL_MAXIMUM(0): 
 119                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
 122                         case HID_RI_PHYSICAL_MINIMUM(0): 
 123                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
 126                         case HID_RI_PHYSICAL_MAXIMUM(0): 
 127                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 130                         case HID_RI_UNIT_EXPONENT(0): 
 131                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 135                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 138                         case HID_RI_REPORT_SIZE(0): 
 139                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 142                         case HID_RI_REPORT_COUNT(0): 
 143                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 146                         case HID_RI_REPORT_ID(0): 
 147                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 149                                 if (ParserData
->UsingReportIDs
) 
 151                                         CurrReportIDInfo 
= NULL
; 
 153                                         for (uint8_t i 
= 0; i 
< ParserData
->TotalDeviceReports
; i
++) 
 155                                                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== CurrStateTable
->ReportID
) 
 157                                                         CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[i
]; 
 162                                         if (CurrReportIDInfo 
== NULL
) 
 164                                                 if (ParserData
->TotalDeviceReports 
== HID_MAX_REPORT_IDS
) 
 165                                                   return HID_PARSE_InsufficientReportIDItems
; 
 167                                                 CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports
++]; 
 168                                                 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
 172                                 ParserData
->UsingReportIDs 
= true; 
 174                                 CurrReportIDInfo
->ReportID 
= CurrStateTable
->ReportID
; 
 177                         case HID_RI_USAGE(0): 
 178                                 if (UsageListSize 
== HID_USAGE_STACK_DEPTH
) 
 179                                   return HID_PARSE_UsageListOverflow
; 
 181                                 UsageList
[UsageListSize
++] = ReportItemData
; 
 184                         case HID_RI_USAGE_MINIMUM(0): 
 185                                 UsageMinMax
.Minimum 
= ReportItemData
; 
 188                         case HID_RI_USAGE_MAXIMUM(0): 
 189                                 UsageMinMax
.Maximum 
= ReportItemData
; 
 192                         case HID_RI_COLLECTION(0): 
 193                                 if (CurrCollectionPath 
== NULL
) 
 195                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 199                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 201                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 203                                         while (CurrCollectionPath
->Parent 
!= NULL
) 
 205                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS 
- 1]) 
 206                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 208                                                 CurrCollectionPath
++; 
 211                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 214                                 CurrCollectionPath
->Type       
= ReportItemData
; 
 215                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 219                                         CurrCollectionPath
->Usage
.Usage 
= UsageList
[0]; 
 221                                         for (uint8_t i 
= 1; i 
< UsageListSize
; i
++) 
 222                                           UsageList
[i 
- 1] = UsageList
[i
]; 
 226                                 else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 228                                         CurrCollectionPath
->Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 233                         case HID_RI_END_COLLECTION(0): 
 234                                 if (CurrCollectionPath 
== NULL
) 
 235                                   return HID_PARSE_UnexpectedEndCollection
; 
 237                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 240                         case HID_RI_INPUT(0): 
 241                         case HID_RI_OUTPUT(0): 
 242                         case HID_RI_FEATURE(0): 
 243                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 245                                         HID_ReportItem_t NewReportItem
; 
 247                                         memcpy(&NewReportItem
.Attributes
, 
 248                                                &CurrStateTable
->Attributes
, 
 249                                                sizeof(HID_ReportItem_Attributes_t
)); 
 251                                         NewReportItem
.ItemFlags      
= ReportItemData
; 
 252                                         NewReportItem
.CollectionPath 
= CurrCollectionPath
; 
 253                                         NewReportItem
.ReportID       
= CurrStateTable
->ReportID
; 
 257                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageList
[0]; 
 259                                                 for (uint8_t i 
= 1; i 
< UsageListSize
; i
++) 
 260                                                   UsageList
[i 
- 1] = UsageList
[i
]; 
 264                                         else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 266                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 269                                         uint8_t ItemTypeTag 
= (HIDReportItem 
& (HID_RI_TYPE_MASK 
| HID_RI_TAG_MASK
)); 
 271                                         if (ItemTypeTag 
== HID_RI_INPUT(0)) 
 272                                           NewReportItem
.ItemType 
= HID_REPORT_ITEM_In
; 
 273                                         else if (ItemTypeTag 
== HID_RI_OUTPUT(0)) 
 274                                           NewReportItem
.ItemType 
= HID_REPORT_ITEM_Out
; 
 276                                           NewReportItem
.ItemType 
= HID_REPORT_ITEM_Feature
; 
 278                                         NewReportItem
.BitOffset 
= CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]; 
 280                                         CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
] += CurrStateTable
->Attributes
.BitSize
; 
 282                                         ParserData
->LargestReportSizeBits 
= MAX(ParserData
->LargestReportSizeBits
, CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]); 
 284                                         if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 285                                           return HID_PARSE_InsufficientReportItems
; 
 287                                         memcpy(&ParserData
->ReportItems
[ParserData
->TotalReportItems
], 
 288                                                &NewReportItem
, sizeof(HID_ReportItem_t
)); 
 290                                         if (!(ReportItemData 
& HID_IOF_CONSTANT
) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem
)) 
 291                                           ParserData
->TotalReportItems
++; 
 300                 if ((HIDReportItem 
& HID_RI_TYPE_MASK
) == HID_RI_TYPE_MAIN
) 
 302                         UsageMinMax
.Minimum 
= 0; 
 303                         UsageMinMax
.Maximum 
= 0; 
 308         if (!(ParserData
->TotalReportItems
)) 
 309           return HID_PARSE_NoUnfilteredReportItems
; 
 311         return HID_PARSE_Successful
; 
 314 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, 
 315                               HID_ReportItem_t
* const ReportItem
) 
 317         if (ReportItem 
== NULL
) 
 320         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 321         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 322         uint32_t BitMask      
= (1 << 0); 
 324         if (ReportItem
->ReportID
) 
 326                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 332         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 333         ReportItem
->Value 
= 0; 
 335         while (DataBitsRem
--) 
 337                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 338                   ReportItem
->Value 
|= BitMask
; 
 347 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, 
 348                               HID_ReportItem_t
* const ReportItem
) 
 350         if (ReportItem 
== NULL
) 
 353         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 354         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 355         uint32_t BitMask      
= (1 << 0); 
 357         if (ReportItem
->ReportID
) 
 359                 ReportData
[0] = ReportItem
->ReportID
; 
 363         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 365         while (DataBitsRem
--) 
 367                 if (ReportItem
->Value 
& BitMask
) 
 368                   ReportData
[CurrentBit 
/ 8] |= (1 << (CurrentBit 
% 8)); 
 375 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t
* const ParserData
, 
 376                               const uint8_t ReportID
, 
 377                               const uint8_t ReportType
) 
 379         for (uint8_t i 
= 0; i 
< HID_MAX_REPORT_IDS
; i
++) 
 381                 uint16_t ReportSizeBits 
= ParserData
->ReportIDSizes
[i
].ReportSizeBits
[ReportType
]; 
 383                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== ReportID
) 
 384                   return (ReportSizeBits 
/ 8) + ((ReportSizeBits 
% 8) ? 
1 : 0);