New HID report item macros (with HID_RI_ prefix) to allow for easy creation and editi...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Common / HIDParser.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2011.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
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.
20
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
28 this software.
29 */
30
31 #define __INCLUDE_FROM_USB_DRIVER
32 #define __INCLUDE_FROM_HID_DRIVER
33 #include "HIDParser.h"
34
35 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,
36 uint16_t ReportSize,
37 HID_ReportInfo_t* const ParserData)
38 {
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};
46
47 memset(ParserData, 0x00, sizeof(HID_ReportInfo_t));
48 memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t));
49 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
50
51 ParserData->TotalDeviceReports = 1;
52
53 while (ReportSize)
54 {
55 uint8_t HIDReportItem = *ReportData;
56 uint32_t ReportItemData = 0;
57
58 ReportData++;
59 ReportSize--;
60
61 switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)
62 {
63 case HID_RI_DATA_BITS_32:
64 ReportItemData = *((uint32_t*)ReportData);
65 ReportSize -= 4;
66 ReportData += 4;
67 break;
68 case HID_RI_DATA_BITS_16:
69 ReportItemData = *((uint16_t*)ReportData);
70 ReportSize -= 2;
71 ReportData += 2;
72 break;
73 case HID_RI_DATA_BITS_8:
74 ReportItemData = *((uint8_t*)ReportData);
75 ReportSize -= 1;
76 ReportData += 1;
77 break;
78 }
79
80 switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))
81 {
82 case HID_RI_PUSH(0):
83 if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
84 return HID_PARSE_HIDStackOverflow;
85
86 memcpy((CurrStateTable + 1),
87 CurrStateTable,
88 sizeof(HID_ReportItem_t));
89
90 CurrStateTable++;
91 break;
92 case HID_RI_POP(0):
93 if (CurrStateTable == &StateTable[0])
94 return HID_PARSE_HIDStackUnderflow;
95
96 CurrStateTable--;
97 break;
98 case HID_RI_USAGE_PAGE(0):
99 CurrStateTable->Attributes.Usage.Page = ReportItemData;
100 break;
101 case HID_RI_LOGICAL_MINIMUM(0):
102 CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
103 break;
104 case HID_RI_LOGICAL_MAXIMUM(0):
105 CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
106 break;
107 case HID_RI_PHYSICAL_MINIMUM(0):
108 CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
109 break;
110 case HID_RI_PHYSICAL_MAXIMUM(0):
111 CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
112 break;
113 case HID_RI_UNIT_EXPONENT(0):
114 CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
115 break;
116 case HID_RI_UNIT(0):
117 CurrStateTable->Attributes.Unit.Type = ReportItemData;
118 break;
119 case HID_RI_REPORT_SIZE(0):
120 CurrStateTable->Attributes.BitSize = ReportItemData;
121 break;
122 case HID_RI_REPORT_COUNT(0):
123 CurrStateTable->ReportCount = ReportItemData;
124 break;
125 case HID_RI_REPORT_ID(0):
126 CurrStateTable->ReportID = ReportItemData;
127
128 if (ParserData->UsingReportIDs)
129 {
130 CurrReportIDInfo = NULL;
131
132 for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
133 {
134 if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
135 {
136 CurrReportIDInfo = &ParserData->ReportIDSizes[i];
137 break;
138 }
139 }
140
141 if (CurrReportIDInfo == NULL)
142 {
143 if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
144 return HID_PARSE_InsufficientReportIDItems;
145
146 CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
147 memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
148 }
149 }
150
151 ParserData->UsingReportIDs = true;
152
153 CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
154 break;
155 case HID_RI_USAGE(0):
156 if (UsageListSize == HID_USAGE_STACK_DEPTH)
157 return HID_PARSE_UsageListOverflow;
158
159 UsageList[UsageListSize++] = ReportItemData;
160 break;
161 case HID_RI_USAGE_MINIMUM(0):
162 UsageMinMax.Minimum = ReportItemData;
163 break;
164 case HID_RI_USAGE_MAXIMUM(0):
165 UsageMinMax.Maximum = ReportItemData;
166 break;
167 case HID_RI_COLLECTION(0):
168 if (CurrCollectionPath == NULL)
169 {
170 CurrCollectionPath = &ParserData->CollectionPaths[0];
171 }
172 else
173 {
174 HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
175
176 CurrCollectionPath = &ParserData->CollectionPaths[1];
177
178 while (CurrCollectionPath->Parent != NULL)
179 {
180 if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
181 return HID_PARSE_InsufficientCollectionPaths;
182
183 CurrCollectionPath++;
184 }
185
186 CurrCollectionPath->Parent = ParentCollectionPath;
187 }
188
189 CurrCollectionPath->Type = ReportItemData;
190 CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
191
192 if (UsageListSize)
193 {
194 CurrCollectionPath->Usage.Usage = UsageList[0];
195
196 for (uint8_t i = 0; i < UsageListSize; i++)
197 UsageList[i] = UsageList[i + 1];
198
199 UsageListSize--;
200 }
201 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
202 {
203 CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
204 }
205
206 break;
207 case HID_RI_END_COLLECTION(0):
208 if (CurrCollectionPath == NULL)
209 return HID_PARSE_UnexpectedEndCollection;
210
211 CurrCollectionPath = CurrCollectionPath->Parent;
212 break;
213 case HID_RI_INPUT(0):
214 case HID_RI_OUTPUT(0):
215 case HID_RI_FEATURE(0):
216 for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
217 {
218 HID_ReportItem_t NewReportItem;
219
220 memcpy(&NewReportItem.Attributes,
221 &CurrStateTable->Attributes,
222 sizeof(HID_ReportItem_Attributes_t));
223
224 NewReportItem.ItemFlags = ReportItemData;
225 NewReportItem.CollectionPath = CurrCollectionPath;
226 NewReportItem.ReportID = CurrStateTable->ReportID;
227
228 if (UsageListSize)
229 {
230 NewReportItem.Attributes.Usage.Usage = UsageList[0];
231
232 for (uint8_t i = 0; i < UsageListSize; i++)
233 UsageList[i] = UsageList[i + 1];
234
235 UsageListSize--;
236 }
237 else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
238 {
239 NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
240 }
241
242 uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
243
244 if (ItemTypeTag == HID_RI_INPUT(0))
245 NewReportItem.ItemType = HID_REPORT_ITEM_In;
246 else if (ItemTypeTag == HID_RI_OUTPUT(0))
247 NewReportItem.ItemType = HID_REPORT_ITEM_Out;
248 else
249 NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
250
251 NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
252
253 CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
254
255 if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
256 ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
257
258 if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
259 {
260 if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
261 return HID_PARSE_InsufficientReportItems;
262
263 memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
264 &NewReportItem, sizeof(HID_ReportItem_t));
265
266 ParserData->TotalReportItems++;
267 }
268 }
269
270 break;
271 }
272
273 if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
274 {
275 UsageMinMax.Minimum = 0;
276 UsageMinMax.Maximum = 0;
277 UsageListSize = 0;
278 }
279 }
280
281 if (!(ParserData->TotalReportItems))
282 return HID_PARSE_NoUnfilteredReportItems;
283
284 return HID_PARSE_Successful;
285 }
286
287 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
288 HID_ReportItem_t* const ReportItem)
289 {
290 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
291 uint16_t CurrentBit = ReportItem->BitOffset;
292 uint32_t BitMask = (1 << 0);
293
294 if (ReportItem->ReportID)
295 {
296 if (ReportItem->ReportID != ReportData[0])
297 return false;
298
299 ReportData++;
300 }
301
302 ReportItem->PreviousValue = ReportItem->Value;
303 ReportItem->Value = 0;
304
305 while (DataBitsRem--)
306 {
307 if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
308 ReportItem->Value |= BitMask;
309
310 CurrentBit++;
311 BitMask <<= 1;
312 }
313
314 return true;
315 }
316
317 void USB_SetHIDReportItemInfo(uint8_t* ReportData,
318 HID_ReportItem_t* const ReportItem)
319 {
320 uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
321 uint16_t CurrentBit = ReportItem->BitOffset;
322 uint32_t BitMask = (1 << 0);
323
324 if (ReportItem->ReportID)
325 {
326 ReportData[0] = ReportItem->ReportID;
327 ReportData++;
328 }
329
330 ReportItem->PreviousValue = ReportItem->Value;
331
332 while (DataBitsRem--)
333 {
334 if (ReportItem->Value & (1 << (CurrentBit % 8)))
335 ReportData[CurrentBit / 8] |= BitMask;
336
337 CurrentBit++;
338 BitMask <<= 1;
339 }
340 }
341
342 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
343 const uint8_t ReportID,
344 const uint8_t ReportType)
345 {
346 for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
347 {
348 uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
349
350 if (ParserData->ReportIDSizes[i].ReportID == ReportID)
351 return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));
352 }
353
354 return 0;
355 }