HIDParser.c 10.4 KB
Newer Older
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
17
18
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
19
20
21
22
23
24
25
26
27
28
29
30
31
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

#define  __INCLUDE_FROM_USB_DRIVER
32
#define  __INCLUDE_FROM_HID_DRIVER
33
34
#include "HIDParser.h"

35
36
37
uint8_t USB_ProcessHIDReport(const uint8_t* ReportData,
                             uint16_t ReportSize,
                             HID_ReportInfo_t* const ParserData)
38
39
40
41
{
	HID_StateTable_t      StateTable[HID_STATETABLE_STACK_DEPTH];
	HID_StateTable_t*     CurrStateTable          = &StateTable[0];
	HID_CollectionPath_t* CurrCollectionPath      = NULL;
42
	HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];
43
44
45
46
47
48
49
50
	uint16_t              UsageList[HID_USAGE_STACK_DEPTH];
	uint8_t               UsageListSize           = 0;
	HID_MinMax_t          UsageMinMax             = {0, 0};

	memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));
	memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));
	memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));

51
	ParserData->TotalDeviceReports = 1;
52
53
54
55
56

	while (ReportSize)
	{
		uint8_t  HIDReportItem  = *ReportData;
		uint32_t ReportItemData = 0;
57

58
59
		ReportData++;
		ReportSize--;
60

61
		switch (HIDReportItem & HID_RI_DATA_SIZE_MASK)
62
		{
63
			case HID_RI_DATA_BITS_32:
64
				ReportItemData  = le32_to_cpu(*((uint32_t*)ReportData));
65
66
67
				ReportSize     -= 4;
				ReportData     += 4;
				break;
68
			case HID_RI_DATA_BITS_16:
69
				ReportItemData  = le16_to_cpu(*((uint16_t*)ReportData));
70
71
72
				ReportSize     -= 2;
				ReportData     += 2;
				break;
73
			case HID_RI_DATA_BITS_8:
74
75
76
77
78
79
				ReportItemData  = *((uint8_t*)ReportData);
				ReportSize     -= 1;
				ReportData     += 1;
				break;
		}

80
		switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK))
81
		{
82
			case HID_RI_PUSH(0):
83
84
				if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1])
				  return HID_PARSE_HIDStackOverflow;
85

86
87
88
89
90
91
				memcpy((CurrStateTable + 1),
				       CurrStateTable,
				       sizeof(HID_ReportItem_t));

				CurrStateTable++;
				break;
92
			case HID_RI_POP(0):
93
94
				if (CurrStateTable == &StateTable[0])
				  return HID_PARSE_HIDStackUnderflow;
95

96
97
				CurrStateTable--;
				break;
98
			case HID_RI_USAGE_PAGE(0):
99
100
101
				if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32)
				  CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16);
				
102
103
				CurrStateTable->Attributes.Usage.Page       = ReportItemData;
				break;
104
			case HID_RI_LOGICAL_MINIMUM(0):
105
106
				CurrStateTable->Attributes.Logical.Minimum  = ReportItemData;
				break;
107
			case HID_RI_LOGICAL_MAXIMUM(0):
108
109
				CurrStateTable->Attributes.Logical.Maximum  = ReportItemData;
				break;
110
			case HID_RI_PHYSICAL_MINIMUM(0):
111
112
				CurrStateTable->Attributes.Physical.Minimum = ReportItemData;
				break;
113
			case HID_RI_PHYSICAL_MAXIMUM(0):
114
115
				CurrStateTable->Attributes.Physical.Maximum = ReportItemData;
				break;
116
			case HID_RI_UNIT_EXPONENT(0):
117
118
				CurrStateTable->Attributes.Unit.Exponent    = ReportItemData;
				break;
119
			case HID_RI_UNIT(0):
120
121
				CurrStateTable->Attributes.Unit.Type        = ReportItemData;
				break;
122
			case HID_RI_REPORT_SIZE(0):
123
124
				CurrStateTable->Attributes.BitSize          = ReportItemData;
				break;
125
			case HID_RI_REPORT_COUNT(0):
126
127
				CurrStateTable->ReportCount                 = ReportItemData;
				break;
128
			case HID_RI_REPORT_ID(0):
129
130
131
132
133
134
135
136
137
138
139
140
141
142
				CurrStateTable->ReportID                    = ReportItemData;

				if (ParserData->UsingReportIDs)
				{
					CurrReportIDInfo = NULL;

					for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++)
					{
						if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID)
						{
							CurrReportIDInfo = &ParserData->ReportIDSizes[i];
							break;
						}
					}
143

144
145
146
147
					if (CurrReportIDInfo == NULL)
					{
						if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS)
						  return HID_PARSE_InsufficientReportIDItems;
148

149
150
151
152
						CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++];
						memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t));
					}
				}
153

Dean Camera's avatar
Dean Camera committed
154
				ParserData->UsingReportIDs = true;
155

156
157
				CurrReportIDInfo->ReportID = CurrStateTable->ReportID;
				break;
158
			case HID_RI_USAGE(0):
159
160
				if (UsageListSize == HID_USAGE_STACK_DEPTH)
				  return HID_PARSE_UsageListOverflow;
161

162
163
				UsageList[UsageListSize++] = ReportItemData;
				break;
164
			case HID_RI_USAGE_MINIMUM(0):
165
166
				UsageMinMax.Minimum = ReportItemData;
				break;
167
			case HID_RI_USAGE_MAXIMUM(0):
168
169
				UsageMinMax.Maximum = ReportItemData;
				break;
170
			case HID_RI_COLLECTION(0):
171
172
173
174
175
176
177
				if (CurrCollectionPath == NULL)
				{
					CurrCollectionPath = &ParserData->CollectionPaths[0];
				}
				else
				{
					HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath;
178

179
					CurrCollectionPath = &ParserData->CollectionPaths[1];
180

181
182
183
184
					while (CurrCollectionPath->Parent != NULL)
					{
						if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1])
						  return HID_PARSE_InsufficientCollectionPaths;
185

186
187
						CurrCollectionPath++;
					}
188

189
190
					CurrCollectionPath->Parent = ParentCollectionPath;
				}
191

192
193
				CurrCollectionPath->Type = ReportItemData;
				CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page;
194

195
196
197
198
199
200
				if (UsageListSize)
				{
					CurrCollectionPath->Usage.Usage = UsageList[0];

					for (uint8_t i = 0; i < UsageListSize; i++)
					  UsageList[i] = UsageList[i + 1];
201

202
203
204
205
206
207
					UsageListSize--;
				}
				else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
				{
					CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
				}
208

209
				break;
210
			case HID_RI_END_COLLECTION(0):
211
212
				if (CurrCollectionPath == NULL)
				  return HID_PARSE_UnexpectedEndCollection;
213

214
215
				CurrCollectionPath = CurrCollectionPath->Parent;
				break;
216
217
218
			case HID_RI_INPUT(0):
			case HID_RI_OUTPUT(0):
			case HID_RI_FEATURE(0):
219
220
221
				for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++)
				{
					HID_ReportItem_t NewReportItem;
222

223
224
225
					memcpy(&NewReportItem.Attributes,
					       &CurrStateTable->Attributes,
					       sizeof(HID_ReportItem_Attributes_t));
226

227
228
229
					NewReportItem.ItemFlags      = ReportItemData;
					NewReportItem.CollectionPath = CurrCollectionPath;
					NewReportItem.ReportID       = CurrStateTable->ReportID;
230

231
232
233
					if (UsageListSize)
					{
						NewReportItem.Attributes.Usage.Usage = UsageList[0];
234

235
236
						for (uint8_t i = 0; i < UsageListSize; i++)
						  UsageList[i] = UsageList[i + 1];
237

238
239
240
241
242
243
						UsageListSize--;
					}
					else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
					{
						NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++;
					}
244

245
					uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK));
246

247
					if (ItemTypeTag == HID_RI_INPUT(0))
248
					  NewReportItem.ItemType = HID_REPORT_ITEM_In;
249
					else if (ItemTypeTag == HID_RI_OUTPUT(0))
250
					  NewReportItem.ItemType = HID_REPORT_ITEM_Out;
251
					else
252
					  NewReportItem.ItemType = HID_REPORT_ITEM_Feature;
253

254
					NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType];
255

256
					CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize;
257

258
259
					if (ParserData->LargestReportSizeBits < NewReportItem.BitOffset)
					  ParserData->LargestReportSizeBits = NewReportItem.BitOffset;
260

261
					if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem))
Dean Camera's avatar
Dean Camera committed
262
					{
263
264
						if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS)
						  return HID_PARSE_InsufficientReportItems;
265

266
267
						memcpy(&ParserData->ReportItems[ParserData->TotalReportItems],
						       &NewReportItem, sizeof(HID_ReportItem_t));
268

269
270
271
						ParserData->TotalReportItems++;
					}
				}
272

273
274
				break;
		}
275

276
		if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN)
277
278
279
		{
			UsageMinMax.Minimum = 0;
			UsageMinMax.Maximum = 0;
280
			UsageListSize       = 0;
281
282
		}
	}
283

284
285
	if (!(ParserData->TotalReportItems))
	  return HID_PARSE_NoUnfilteredReportItems;
286

287
288
289
	return HID_PARSE_Successful;
}

290
291
bool USB_GetHIDReportItemInfo(const uint8_t* ReportData,
                              HID_ReportItem_t* const ReportItem)
292
293
294
295
{
	uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
	uint16_t CurrentBit   = ReportItem->BitOffset;
	uint32_t BitMask      = (1 << 0);
296

297
298
299
300
	if (ReportItem->ReportID)
	{
		if (ReportItem->ReportID != ReportData[0])
		  return false;
301

302
303
		ReportData++;
	}
304

305
306
	ReportItem->PreviousValue = ReportItem->Value;
	ReportItem->Value = 0;
307

308
309
310
311
	while (DataBitsRem--)
	{
		if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8)))
		  ReportItem->Value |= BitMask;
312

313
314
315
		CurrentBit++;
		BitMask <<= 1;
	}
316

317
318
319
	return true;
}

320
321
void USB_SetHIDReportItemInfo(uint8_t* ReportData,
                              HID_ReportItem_t* const ReportItem)
322
323
324
325
{
	uint16_t DataBitsRem  = ReportItem->Attributes.BitSize;
	uint16_t CurrentBit   = ReportItem->BitOffset;
	uint32_t BitMask      = (1 << 0);
326

327
328
329
330
331
	if (ReportItem->ReportID)
	{
		ReportData[0] = ReportItem->ReportID;
		ReportData++;
	}
332

333
	ReportItem->PreviousValue = ReportItem->Value;
334

335
336
337
338
	while (DataBitsRem--)
	{
		if (ReportItem->Value & (1 << (CurrentBit % 8)))
		  ReportData[CurrentBit / 8] |= BitMask;
339

340
341
342
343
344
		CurrentBit++;
		BitMask <<= 1;
	}
}

345
346
347
uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData,
                              const uint8_t ReportID,
                              const uint8_t ReportType)
348
349
350
351
{
	for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++)
	{
		uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType];
352

353
354
355
356
357
358
		if (ParserData->ReportIDSizes[i].ReportID == ReportID)
		  return ((ReportSizeBits >> 3) + ((ReportSizeBits & 0x07) ? 1 : 0));
	}

	return 0;
}