3 Copyright (C) Dean Camera, 2013.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2013 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_ReportItem_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
& (1 << (CurrentBit
% 8)))
368 ReportData
[CurrentBit
/ 8] |= BitMask
;
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);