/******************************************************************************* * HID Report Descriptors ******************************************************************************/ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = { HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x06), /* Keyboard */ HID_RI_COLLECTION(8, 0x01), /* Application */ HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */ HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */ HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0x01), HID_RI_REPORT_COUNT(8, 0x08), HID_RI_REPORT_SIZE(8, 0x01), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_RI_REPORT_COUNT(8, 0x01), HID_RI_REPORT_SIZE(8, 0x08), HID_RI_INPUT(8, HID_IOF_CONSTANT), /* reserved */ HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */ HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */ HID_RI_REPORT_COUNT(8, 0x05), HID_RI_REPORT_SIZE(8, 0x01), HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), HID_RI_REPORT_COUNT(8, 0x01), HID_RI_REPORT_SIZE(8, 0x03), HID_RI_OUTPUT(8, HID_IOF_CONSTANT),
uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID_ReportInfo_t* const ParserData) { HID_StateTable_t StateTable[HID_STATETABLE_STACK_DEPTH]; HID_StateTable_t* CurrStateTable = &StateTable[0]; HID_CollectionPath_t* CurrCollectionPath = NULL; HID_ReportSizeInfo_t* CurrReportIDInfo = &ParserData->ReportIDSizes[0]; 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)); ParserData->TotalDeviceReports = 1; while (ReportSize) { uint8_t HIDReportItem = *ReportData; uint32_t ReportItemData = 0; ReportData++; ReportSize--; switch (HIDReportItem & HID_RI_DATA_SIZE_MASK) { case HID_RI_DATA_BITS_32: ReportItemData = le32_to_cpu(*((uint32_t*)ReportData)); ReportSize -= 4; ReportData += 4; break; case HID_RI_DATA_BITS_16: ReportItemData = le16_to_cpu(*((uint16_t*)ReportData)); ReportSize -= 2; ReportData += 2; break; case HID_RI_DATA_BITS_8: ReportItemData = *((uint8_t*)ReportData); ReportSize -= 1; ReportData += 1; break; } switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK)) { case HID_RI_PUSH(0): if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1]) return HID_PARSE_HIDStackOverflow; memcpy((CurrStateTable + 1), CurrStateTable, sizeof(HID_ReportItem_t)); CurrStateTable++; break; case HID_RI_POP(0): if (CurrStateTable == &StateTable[0]) return HID_PARSE_HIDStackUnderflow; CurrStateTable--; break; case HID_RI_USAGE_PAGE(0): if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32) CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16); CurrStateTable->Attributes.Usage.Page = ReportItemData; break; case HID_RI_LOGICAL_MINIMUM(0): CurrStateTable->Attributes.Logical.Minimum = ReportItemData; break; case HID_RI_LOGICAL_MAXIMUM(0): CurrStateTable->Attributes.Logical.Maximum = ReportItemData; break; case HID_RI_PHYSICAL_MINIMUM(0): CurrStateTable->Attributes.Physical.Minimum = ReportItemData; break; case HID_RI_PHYSICAL_MAXIMUM(0): CurrStateTable->Attributes.Physical.Maximum = ReportItemData; break; case HID_RI_UNIT_EXPONENT(0): CurrStateTable->Attributes.Unit.Exponent = ReportItemData; break; case HID_RI_UNIT(0): CurrStateTable->Attributes.Unit.Type = ReportItemData; break; case HID_RI_REPORT_SIZE(0): CurrStateTable->Attributes.BitSize = ReportItemData; break; case HID_RI_REPORT_COUNT(0): CurrStateTable->ReportCount = ReportItemData; break; case HID_RI_REPORT_ID(0): 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; } } if (CurrReportIDInfo == NULL) { if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS) return HID_PARSE_InsufficientReportIDItems; CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++]; memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t)); } } ParserData->UsingReportIDs = true; CurrReportIDInfo->ReportID = CurrStateTable->ReportID; break; case HID_RI_USAGE(0): if (UsageListSize == HID_USAGE_STACK_DEPTH) return HID_PARSE_UsageListOverflow; UsageList[UsageListSize++] = ReportItemData; break; case HID_RI_USAGE_MINIMUM(0): UsageMinMax.Minimum = ReportItemData; break; case HID_RI_USAGE_MAXIMUM(0): UsageMinMax.Maximum = ReportItemData; break; case HID_RI_COLLECTION(0): if (CurrCollectionPath == NULL) { CurrCollectionPath = &ParserData->CollectionPaths[0]; } else { HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath; CurrCollectionPath = &ParserData->CollectionPaths[1]; while (CurrCollectionPath->Parent != NULL) { if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1]) return HID_PARSE_InsufficientCollectionPaths; CurrCollectionPath++; } CurrCollectionPath->Parent = ParentCollectionPath; } CurrCollectionPath->Type = ReportItemData; CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page; if (UsageListSize) { CurrCollectionPath->Usage.Usage = UsageList[0]; for (uint8_t i = 0; i < UsageListSize; i++) UsageList[i] = UsageList[i + 1]; UsageListSize--; } else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) { CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++; } break; case HID_RI_END_COLLECTION(0): if (CurrCollectionPath == NULL) return HID_PARSE_UnexpectedEndCollection; CurrCollectionPath = CurrCollectionPath->Parent; break; case HID_RI_INPUT(0): case HID_RI_OUTPUT(0): case HID_RI_FEATURE(0): for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++) { HID_ReportItem_t NewReportItem; memcpy(&NewReportItem.Attributes, &CurrStateTable->Attributes, sizeof(HID_ReportItem_Attributes_t)); NewReportItem.ItemFlags = ReportItemData; NewReportItem.CollectionPath = CurrCollectionPath; NewReportItem.ReportID = CurrStateTable->ReportID; if (UsageListSize) { NewReportItem.Attributes.Usage.Usage = UsageList[0]; for (uint8_t i = 0; i < UsageListSize; i++) UsageList[i] = UsageList[i + 1]; UsageListSize--; } else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) { NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++; } uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK)); if (ItemTypeTag == HID_RI_INPUT(0)) NewReportItem.ItemType = HID_REPORT_ITEM_In; else if (ItemTypeTag == HID_RI_OUTPUT(0)) NewReportItem.ItemType = HID_REPORT_ITEM_Out; else NewReportItem.ItemType = HID_REPORT_ITEM_Feature; NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]; CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize; ParserData->LargestReportSizeBits = MAX(ParserData->LargestReportSizeBits, CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]); if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS) return HID_PARSE_InsufficientReportItems; memcpy(&ParserData->ReportItems[ParserData->TotalReportItems], &NewReportItem, sizeof(HID_ReportItem_t)); if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem)) ParserData->TotalReportItems++; } break; } if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN) { UsageMinMax.Minimum = 0; UsageMinMax.Maximum = 0; UsageListSize = 0; } } if (!(ParserData->TotalReportItems)) return HID_PARSE_NoUnfilteredReportItems; return HID_PARSE_Successful; }
* USBIF HID class specification to describe the reports and capabilities of the HID device. This * descriptor is parsed by the host and its contents used to determine what data (and in what encoding) * the device will send, and what it may be sent back from the host. Refer to the HID specification for * more details on HID report descriptors. */ const USB_Descriptor_HIDReport_Datatype_t PROGMEM GenericReport[] = { HID_RI_USAGE_PAGE(16, 0xFF00), /* Vendor Page 0 */ HID_RI_USAGE(8, 0x01), /* Vendor Usage 1 */ HID_RI_COLLECTION(8, 0x01), /* Vendor Usage 1 */ HID_RI_USAGE(8, 0x02), /* Vendor Usage 2 */ HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0xFF), HID_RI_REPORT_SIZE(8, 0x08), HID_RI_REPORT_COUNT(8, GENERIC_REPORT_SIZE), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_RI_USAGE(8, 0x03), /* Vendor Usage 3 */ HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0xFF), HID_RI_REPORT_SIZE(8, 0x08), HID_RI_REPORT_COUNT(8, GENERIC_REPORT_SIZE), HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), HID_RI_END_COLLECTION(0), }; /** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall * device characteristics, including the supported USB version, control endpoint size and the * number of device configurations. The descriptor is read out by the USB host when the enumeration * process begins. */ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
*/ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] = { HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x02), /* Mouse */ HID_RI_COLLECTION(8, 0x01), /* Application */ HID_RI_USAGE(8, 0x01), /* Pointer */ HID_RI_COLLECTION(8, 0x00), /* Physical */ HID_RI_USAGE_PAGE(8, 0x09), /* Button */ HID_RI_USAGE_MINIMUM(8, 0x01), HID_RI_USAGE_MAXIMUM(8, 0x03), HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0x01), HID_RI_REPORT_COUNT(8, 0x03), HID_RI_REPORT_SIZE(8, 0x01), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_RI_REPORT_COUNT(8, 0x01), HID_RI_REPORT_SIZE(8, 0x05), HID_RI_INPUT(8, HID_IOF_CONSTANT), HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x30), /* Usage X */ HID_RI_USAGE(8, 0x31), /* Usage Y */ HID_RI_LOGICAL_MINIMUM(8, -1), HID_RI_LOGICAL_MAXIMUM(8, 1), HID_RI_PHYSICAL_MINIMUM(8, -1), HID_RI_PHYSICAL_MAXIMUM(8, 1), HID_RI_REPORT_COUNT(8, 0x02), HID_RI_REPORT_SIZE(8, 0x08), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), HID_RI_END_COLLECTION(0), HID_RI_END_COLLECTION(0),
* the device will send, and what it may be sent back from the host. Refer to the HID specification for * more details on HID report descriptors. */ const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] = { HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */ HID_RI_USAGE(8, 0x06), /* Keyboard */ HID_RI_COLLECTION(8, 0x01), /* Application */ HID_RI_USAGE_PAGE(8, 0x07), /* Key Codes */ HID_RI_USAGE_MINIMUM(8, 0xE0), /* Keyboard Left Control */ HID_RI_USAGE_MAXIMUM(8, 0xE7), /* Keyboard Right GUI */ HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0x01), HID_RI_REPORT_SIZE(8, 0x01), HID_RI_REPORT_COUNT(8, 0x08), HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), HID_RI_REPORT_COUNT(8, 0x01), HID_RI_REPORT_SIZE(8, 0x08), HID_RI_INPUT(8, HID_IOF_CONSTANT), HID_RI_USAGE_PAGE(8, 0x08), /* LEDs */ HID_RI_USAGE_MINIMUM(8, 0x01), /* Num Lock */ HID_RI_USAGE_MAXIMUM(8, 0x05), /* Kana */ HID_RI_REPORT_COUNT(8, 0x05), HID_RI_REPORT_SIZE(8, 0x01), HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), HID_RI_REPORT_COUNT(8, 0x01), HID_RI_REPORT_SIZE(8, 0x03), HID_RI_OUTPUT(8, HID_IOF_CONSTANT), HID_RI_LOGICAL_MINIMUM(8, 0x00), HID_RI_LOGICAL_MAXIMUM(8, 0x65), HID_RI_USAGE_PAGE(8, 0x07), /* Keyboard */
} static uint8_t const PROGMEM kMouseReportDescriptor[] = { HID_RI_USAGE_PAGE(8, 1), // 1 = Generic Desktop HID_RI_USAGE(8, 2), // 2 = Mouse HID_RI_COLLECTION(8, 1), // 1 = Application HID_RI_USAGE(8, 1), // 1 = Pointer HID_RI_COLLECTION(8, 0), // 0 = Physical HID_RI_USAGE_PAGE(8, 9), // 9 = Buttons HID_RI_USAGE_MINIMUM(8, 1), // 1 = first button number HID_RI_USAGE_MAXIMUM(8, 3), // 3 = last button number HID_RI_LOGICAL_MINIMUM(8, 0), // 0 = application value for bit value 0 HID_RI_LOGICAL_MAXIMUM(8, 1), // 1 = application value for bit value 1 HID_RI_REPORT_COUNT(8, 3), // 3 = number of buttons HID_RI_REPORT_SIZE(8, 1), // 1 = bits reported per button HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), // Define the button fields HID_RI_REPORT_COUNT(8, 1), // 1 = number of padding fields HID_RI_REPORT_SIZE(8, 5), // 5 = number of bits in padding field HID_RI_INPUT(8, HID_IOF_CONSTANT), // Define the padding field HID_RI_USAGE_PAGE(8, 1), // 1 = Generic Desktop HID_RI_USAGE(8, 0x30), // 0x30 = X axis HID_RI_USAGE(8, 0x31), // 0x31 = Y axis, HID_RI_LOGICAL_MINIMUM(8, -127), // -127 = minimum report value HID_RI_LOGICAL_MAXIMUM(8, 127), // 127 = maximum report value HID_RI_REPORT_SIZE(8, 8), // 8 = bits per axis HID_RI_REPORT_COUNT(8, 2), // 2 = number of axes HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE), // Define the axis fields HID_RI_END_COLLECTION(0), HID_RI_END_COLLECTION(0) };