3 Copyright (C) Dean Camera, 2020.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2020 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 CurrStateTable
->Attributes
.Usage
.Page
= ReportItemData
;
111 case HID_RI_LOGICAL_MINIMUM(0):
112 CurrStateTable
->Attributes
.Logical
.Minimum
= ReportItemData
;
115 case HID_RI_LOGICAL_MAXIMUM(0):
116 CurrStateTable
->Attributes
.Logical
.Maximum
= ReportItemData
;
119 case HID_RI_PHYSICAL_MINIMUM(0):
120 CurrStateTable
->Attributes
.Physical
.Minimum
= ReportItemData
;
123 case HID_RI_PHYSICAL_MAXIMUM(0):
124 CurrStateTable
->Attributes
.Physical
.Maximum
= ReportItemData
;
127 case HID_RI_UNIT_EXPONENT(0):
128 CurrStateTable
->Attributes
.Unit
.Exponent
= ReportItemData
;
132 CurrStateTable
->Attributes
.Unit
.Type
= ReportItemData
;
135 case HID_RI_REPORT_SIZE(0):
136 CurrStateTable
->Attributes
.BitSize
= ReportItemData
;
139 case HID_RI_REPORT_COUNT(0):
140 CurrStateTable
->ReportCount
= ReportItemData
;
143 case HID_RI_REPORT_ID(0):
144 CurrStateTable
->ReportID
= ReportItemData
;
146 if (ParserData
->UsingReportIDs
)
148 CurrReportIDInfo
= NULL
;
150 for (uint8_t i
= 0; i
< ParserData
->TotalDeviceReports
; i
++)
152 if (ParserData
->ReportIDSizes
[i
].ReportID
== CurrStateTable
->ReportID
)
154 CurrReportIDInfo
= &ParserData
->ReportIDSizes
[i
];
159 if (CurrReportIDInfo
== NULL
)
161 if (ParserData
->TotalDeviceReports
== HID_MAX_REPORT_IDS
)
162 return HID_PARSE_InsufficientReportIDItems
;
164 CurrReportIDInfo
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports
++];
165 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
));
169 ParserData
->UsingReportIDs
= true;
171 CurrReportIDInfo
->ReportID
= CurrStateTable
->ReportID
;
174 case HID_RI_USAGE(0):
175 if (UsageListSize
== HID_USAGE_STACK_DEPTH
)
176 return HID_PARSE_UsageListOverflow
;
178 if ((HIDReportItem
& HID_RI_DATA_SIZE_MASK
) == HID_RI_DATA_BITS_32
)
179 CurrStateTable
->Attributes
.Usage
.Page
= (ReportItemData
>> 16);
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);