LPCOpen Platform
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
HIDParser.c
Go to the documentation of this file.
1 /*
2  * @brief USB Human Interface Device (HID) Class report descriptor parser
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * Copyright(C) Dean Camera, 2011, 2012
7  * All rights reserved.
8  *
9  * @par
10  * Software that is described herein is for illustrative purposes only
11  * which provides customers with programming information regarding the
12  * LPC products. This software is supplied "AS IS" without any warranties of
13  * any kind, and NXP Semiconductors and its licensor disclaim any and
14  * all warranties, express or implied, including all implied warranties of
15  * merchantability, fitness for a particular purpose and non-infringement of
16  * intellectual property rights. NXP Semiconductors assumes no responsibility
17  * or liability for the use of the software, conveys no license or rights under any
18  * patent, copyright, mask work right, or any other intellectual property rights in
19  * or to any products. NXP Semiconductors reserves the right to make changes
20  * in the software without notification. NXP Semiconductors also makes no
21  * representation or warranty that such application will be suitable for the
22  * specified use without further testing or modification.
23  *
24  * @par
25  * Permission to use, copy, modify, and distribute this software and its
26  * documentation is hereby granted, under NXP Semiconductors' and its
27  * licensor's relevant copyrights in the software, without fee, provided that it
28  * is used in conjunction with NXP Semiconductors microcontrollers. This
29  * copyright, permission, and disclaimer notice must appear in all copies of
30  * this code.
31  */
32 
33 
34 #define __INCLUDE_FROM_USB_DRIVER
35 #define __INCLUDE_FROM_HID_DRIVER
36 #include "HIDParser.h"
37 
38 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,
39  uint16_t ReportSize,
40  HID_ReportInfo_t* const ParserData)
41 {
42  HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH];
43  HID_StateTable_t* CurrStateTable = &StateTable[0];
44  HID_CollectionPath_t* CurrCollectionPath = NULL;
45  HID_ReportSizeInfo_t* CurrReportIDInfo = &ParserData->ReportIDSizes[0];
46  uint16_t UsageList[HID_USAGE_STACK_DEPTH];
47  uint8_t UsageListSize = 0;
48  HID_MinMax_t UsageMinMax = {0, 0};
49 
50  memset(ParserData, 0x00, sizeof(HID_ReportInfo_t));
51  memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t));
52  memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
53 
54  ParserData->TotalDeviceReports = 1;
55 
56  while (ReportSize)
57  {
58  uint8_t HIDReportItem = *ReportData;
59  uint32_t ReportItemData = 0;
60 
61  ReportData++;
62  ReportSize--;
63 
64  switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)
65  {
66  case HID_RI_DATA_BITS_32:
67  ReportItemData = le32_to_cpu(*((uint32_t*)ReportData));
68  ReportSize -= 4;
69  ReportData += 4;
70  break;
71  case HID_RI_DATA_BITS_16:
72  ReportItemData = le16_to_cpu(*((uint16_t*)ReportData));
73  ReportSize -= 2;
74  ReportData += 2;
75  break;
76  case HID_RI_DATA_BITS_8:
77  ReportItemData = *((uint8_t*)ReportData);
78  ReportSize -= 1;
79  ReportData += 1;
80  break;
81  }
82 
83  switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))
84  {
85  case HID_RI_PUSH(0):
86  if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
88 
89  memcpy((CurrStateTable + 1),
90  CurrStateTable,
91  sizeof(HID_ReportItem_t));
92 
93  CurrStateTable++;
94  break;
95  case HID_RI_POP(0):
96  if (CurrStateTable == &StateTable[0])
98 
99  CurrStateTable--;
100  break;
101  case HID_RI_USAGE_PAGE(0):
102  if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
103  CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
104 
105  CurrStateTable->Attributes.Usage.Page = ReportItemData;
106  break;
107  case HID_RI_LOGICAL_MINIMUM(0):
108  CurrStateTable->Attributes.Logical.Minimum = ReportItemData;
109  break;
110  case HID_RI_LOGICAL_MAXIMUM(0):
111  CurrStateTable->Attributes.Logical.Maximum = ReportItemData;
112  break;
113  case HID_RI_PHYSICAL_MINIMUM(0):
114  CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
115  break;
116  case HID_RI_PHYSICAL_MAXIMUM(0):
117  CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
118  break;
119  case HID_RI_UNIT_EXPONENT(0):
120  CurrStateTable->Attributes.Unit.Exponent = ReportItemData;
121  break;
122  case HID_RI_UNIT(0):
123  CurrStateTable->Attributes.Unit.Type = ReportItemData;
124  break;
125  case HID_RI_REPORT_SIZE(0):
126  CurrStateTable->Attributes.BitSize = ReportItemData;
127  break;
128  case HID_RI_REPORT_COUNT(0):
129  CurrStateTable->ReportCount = ReportItemData;
130  break;
131  case HID_RI_REPORT_ID(0):
132  CurrStateTable->ReportID = ReportItemData;
133 
134  if (ParserData->UsingReportIDs)
135  {
136  CurrReportIDInfo = NULL;
137 
138  for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
139  {
140  if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
141  {
142  CurrReportIDInfo = &ParserData->ReportIDSizes[i];
143  break;
144  }
145  }
146 
147  if (CurrReportIDInfo == NULL)
148  {
149  if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
151 
152  CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
153  memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
154  }
155  }
156 
157  ParserData->UsingReportIDs = true;
158 
159  CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
160  break;
161  case HID_RI_USAGE(0):
162  if (UsageListSize == HID_USAGE_STACK_DEPTH)
164 
165  UsageList[UsageListSize++] = ReportItemData;
166  break;
167  case HID_RI_USAGE_MINIMUM(0):
168  UsageMinMax.Minimum = ReportItemData;
169  break;
170  case HID_RI_USAGE_MAXIMUM(0):
171  UsageMinMax.Maximum = ReportItemData;
172  break;
173  case HID_RI_COLLECTION(0):
174  if (CurrCollectionPath == NULL)
175  {
176  CurrCollectionPath = &ParserData->CollectionPaths[0];
177  }
178  else
179  {
180  HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
181 
182  CurrCollectionPath = &ParserData->CollectionPaths[1];
183 
184  while (CurrCollectionPath->Parent != NULL)
185  {
186  if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
188 
189  CurrCollectionPath++;
190  }
191 
192  CurrCollectionPath->Parent = ParentCollectionPath;
193  }
194 
195  CurrCollectionPath->Type = ReportItemData;
196  CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
197 
198  if (UsageListSize)
199  {
200  CurrCollectionPath->Usage.Usage = UsageList[0];
201 
202  for (uint8_t i = 0; i < UsageListSize; i++)
203  UsageList[i] = UsageList[i + 1];
204 
205  UsageListSize--;
206  }
207  else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
208  {
209  CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
210  }
211 
212  break;
213  case HID_RI_END_COLLECTION(0):
214  if (CurrCollectionPath == NULL)
216 
217  CurrCollectionPath = CurrCollectionPath->Parent;
218  break;
219  case HID_RI_INPUT(0):
220  case HID_RI_OUTPUT(0):
221  case HID_RI_FEATURE(0):
222  for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
223  {
224  HID_ReportItem_t NewReportItem;
225 
226  memcpy(&NewReportItem.Attributes,
227  &CurrStateTable->Attributes,
229 
230  NewReportItem.ItemFlags = ReportItemData;
231  NewReportItem.CollectionPath = CurrCollectionPath;
232  NewReportItem.ReportID = CurrStateTable->ReportID;
233 
234  if (UsageListSize)
235  {
236  NewReportItem.Attributes.Usage.Usage = UsageList[0];
237 
238  for (uint8_t i = 0; i < UsageListSize; i++)
239  UsageList[i] = UsageList[i + 1];
240 
241  UsageListSize--;
242  }
243  else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
244  {
245  NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
246  }
247 
248  uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
249 
250  if (ItemTypeTag == HID_RI_INPUT(0))
251  NewReportItem.ItemType = HID_REPORT_ITEM_In;
252  else if (ItemTypeTag == HID_RI_OUTPUT(0))
253  NewReportItem.ItemType = HID_REPORT_ITEM_Out;
254  else
255  NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
256 
257  NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
258 
259  CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
260 
261  if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
262  ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
263 
264  if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
266 
267  memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
268  &NewReportItem, sizeof(HID_ReportItem_t));
269 
270  if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
271  ParserData->TotalReportItems++;
272  }
273 
274  break;
275  }
276 
277  if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
278  {
279  UsageMinMax.Minimum = 0;
280  UsageMinMax.Maximum = 0;
281  UsageListSize = 0;
282  }
283  }
284 
285  if (!(ParserData->TotalReportItems))
287 
288  return HID_PARSE_Successful;
289 }
290 
291 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
292  HID_ReportItem_t* const ReportItem)
293 {
294  if (ReportItem == NULL)
295  return false;
296 
297  uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
298  uint16_t CurrentBit = ReportItem->BitOffset;
299  uint32_t BitMask = (1 << 0);
300 
301  if (ReportItem->ReportID)
302  {
303  if (ReportItem->ReportID != ReportData[0])
304  return false;
305 
306  ReportData++;
307  }
308 
309  ReportItem->PreviousValue = ReportItem->Value;
310  ReportItem->Value = 0;
311 
312  while (DataBitsRem--)
313  {
314  if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
315  ReportItem->Value |= BitMask;
316 
317  CurrentBit++;
318  BitMask <<= 1;
319  }
320 
321  return true;
322 }
323 
324 void USB_SetHIDReportItemInfo(uint8_t* ReportData,
325  HID_ReportItem_t* const ReportItem)
326 {
327  if (ReportItem == NULL)
328  return;
329 
330  uint16_t DataBitsRem = ReportItem->Attributes.BitSize;
331  uint16_t CurrentBit = ReportItem->BitOffset;
332  uint32_t BitMask = (1 << 0);
333 
334  if (ReportItem->ReportID)
335  {
336  ReportData[0] = ReportItem->ReportID;
337  ReportData++;
338  }
339 
340  ReportItem->PreviousValue = ReportItem->Value;
341 
342  while (DataBitsRem--)
343  {
344  if (ReportItem->Value & (1 << (CurrentBit % 8)))
345  ReportData[CurrentBit / 8] |= BitMask;
346 
347  CurrentBit++;
348  BitMask <<= 1;
349  }
350 }
351 
352 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
353  const uint8_t ReportID,
354  const uint8_t ReportType)
355 {
356  for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
357  {
358  uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
359 
360  if (ParserData->ReportIDSizes[i].ReportID == ReportID)
361  return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0);
362  }
363 
364  return 0;
365 }