Example #1
0
#include "descriptor.h"


/*******************************************************************************
 * 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),
Example #2
0
#include "Descriptors.h"

/** HID class report descriptor. This is a special descriptor constructed with values from the
 *  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 HIDReport[] =
{
	HID_RI_USAGE_PAGE(16, 0xFFDC), /* Vendor Page 0xDC */
	HID_RI_USAGE(8, 0xFB), /* Vendor Usage 0xFB */
	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(16, (sizeof(uint16_t) + SPM_PAGESIZE)),		
	    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 DeviceDescriptor =
{
	.Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
Example #3
0
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;
}
Example #4
0
	HID_RI_COLLECTION(8, 0x01), /* Application */
		HID_RI_USAGE(8, 0xB0), /* Play */
		HID_RI_USAGE(8, 0xB1), /* Pause */
		HID_RI_USAGE(8, 0xB3), /* Fast Forward */
		HID_RI_USAGE(8, 0xB4), /* Rewind */
		HID_RI_USAGE(8, 0xB5), /* Next Track */
		HID_RI_USAGE(8, 0xB6), /* Previous Track */
		HID_RI_USAGE(8, 0xB7), /* Stop */
		HID_RI_USAGE(16, 0x09CD), /* Play/Pause (toggle) */
		HID_RI_USAGE(8, 0xE2), /* Mute */
		HID_RI_USAGE(8, 0xE9), /* Volume Up */
		HID_RI_USAGE(8, 0xEA), /* Volume Down */
		HID_RI_REPORT_SIZE(8, 0x01),
		HID_RI_REPORT_COUNT(8, 0x0B),
		HID_RI_LOGICAL_MINIMUM(8, 0),
		HID_RI_LOGICAL_MAXIMUM(8, 1),
		HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
		HID_RI_REPORT_COUNT(8, 0x05),
		HID_RI_INPUT(8, HID_IOF_CONSTANT),
	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 =
{
	.Header                 = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
Example #5
0
 *  This descriptor describes the multiple possible reports of the HID interface's report structure.
 */
const USB_Descriptor_HIDReport_Datatype_t PROGMEM HIDReport[] =
{
	/* Mouse Report */
	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
	HID_RI_USAGE(8, 0x02), /* Mouse */
	HID_RI_COLLECTION(8, 0x01), /* Application */
		HID_RI_REPORT_ID(8, HID_REPORTID_MouseReport),
	    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),
Example #6
0
	 *   Min physical X/Y/Z Axis values (used to determine resolution): -1
	 *   Max physical X/Y/Z Axis values (used to determine resolution):  1
	 *   Buttons: 2
	 */
	//HID_DESCRIPTOR_JOYSTICK(-100, 100, -1, 1, 2)
	//HID_DESCRIPTOR_JOYSTICK(MinAxisVal, MaxAxisVal, MinPhysicalVal, MaxPhysicalVal, Buttons)
	HID_RI_USAGE_PAGE(8, 0x01),
	HID_RI_USAGE(8, 0x04),
	HID_RI_COLLECTION(8, 0x01),
	HID_RI_USAGE(8, 0x01),
	HID_RI_COLLECTION(8, 0x00),
	HID_RI_USAGE(8, 0x30),
	HID_RI_USAGE(8, 0x31),
	HID_RI_USAGE(8, 0x32),
	HID_RI_LOGICAL_MINIMUM(16, -16384),
	HID_RI_LOGICAL_MAXIMUM(16, 16384),
	HID_RI_PHYSICAL_MINIMUM(16, -1),
	HID_RI_PHYSICAL_MAXIMUM(16, 1),
	HID_RI_REPORT_COUNT(8, 4),
	HID_RI_REPORT_SIZE(8, 16),
	HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
	HID_RI_END_COLLECTION(0),
	HID_RI_USAGE_PAGE(8, 0x09),
	HID_RI_USAGE_MINIMUM(8, 0x01),
	HID_RI_USAGE_MAXIMUM(8, 4),
	HID_RI_LOGICAL_MINIMUM(8, 0x00),
	HID_RI_LOGICAL_MAXIMUM(8, 0x01),
	HID_RI_REPORT_SIZE(8, 0x01),
	HID_RI_REPORT_COUNT(8, 4),
	HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
	HID_RI_REPORT_SIZE(8, 1),
 *  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 JoystickReport[] =
{
	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
	HID_RI_USAGE(8, 0x04), /* Joystick */
	HID_RI_COLLECTION(8, 0x01), /* Application */
	    HID_RI_USAGE(8, 0x01), /* Pointer */
	    HID_RI_COLLECTION(8, 0x00), /* Physical */
	        HID_RI_USAGE(8, 0x30), /* Usage X */
	        HID_RI_USAGE(8, 0x31), /* Usage Y */
	        HID_RI_LOGICAL_MINIMUM(8, -100),
	        HID_RI_LOGICAL_MAXIMUM(8, 100),
	        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_ABSOLUTE),
	    HID_RI_END_COLLECTION(0),
	    HID_RI_USAGE_PAGE(8, 0x09), /* Button */
	    HID_RI_USAGE_MINIMUM(8, 0x01),
	    HID_RI_USAGE_MAXIMUM(8, 0x02),
	    HID_RI_LOGICAL_MINIMUM(8, 0x00),
	    HID_RI_LOGICAL_MAXIMUM(8, 0x01),
	    HID_RI_REPORT_SIZE(8, 0x01),
	    HID_RI_REPORT_COUNT(8, 0x02),
	    HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
	    HID_RI_REPORT_SIZE(8, 0x06),
Example #8
0
    MakeStringDescriptor(kDescriptor, "Mouse Imposter");
    *outDescriptor = &kDescriptor;
    return pgm_read_byte(&kDescriptor.Header.Size);
}

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),
Example #9
0
const USB_Descriptor_HIDReport_Datatype_t PROGMEM HIDReport[] =
{

	/* Joystick Report */
	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
	HID_RI_USAGE(8, 0x04), /* Joystick */
	HID_RI_COLLECTION(8, 0x01), /* Application */
		HID_RI_REPORT_ID(8, HID_REPORTID_JoystickReport),
	    HID_RI_USAGE(8, 0x01), /* Pointer */
	    HID_RI_COLLECTION(8, 0x00), /* Physical */
	        HID_RI_USAGE(8, 0x30), /* Usage X */
	        HID_RI_USAGE(8, 0x31), /* Usage Y */
	        HID_RI_USAGE(8, 0x32), /* Usage X */  //JW added - can add more as 34, 35 etc
	        HID_RI_USAGE(8, 0x33), /* Usage Y */
	        HID_RI_LOGICAL_MINIMUM(8, -128),
	        HID_RI_LOGICAL_MAXIMUM(8, 127),
	        HID_RI_PHYSICAL_MINIMUM(8, -1),
	        HID_RI_PHYSICAL_MAXIMUM(8, 1),
	        //HID_RI_REPORT_COUNT(8, 0x02),  //increase axis from 2 to 4
	        HID_RI_REPORT_COUNT(8, 0x04),
	        HID_RI_REPORT_SIZE(8, 0x08),
	        HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
	    HID_RI_END_COLLECTION(0),
		
		//Hat Switch Start (Working)
		HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
        0x09, 0x39,             //     USAGE (Hat switch)
        0x95, 0x01,             //     REPORT_COUNT (1)
        0x75, 0x04,             //     REPORT_SIZE (4)
        0x15, 0x00,             //     LOGICAL_MINIMUM (0)
        0x25, 0x07,             //     LOGICAL_MAXIMUM (7)
Example #10
0
 *  This descriptor describes the multiple possible reports of the HID interface's report structure.
 */

//Keyboard and media report
const USB_Descriptor_HIDReport_Datatype_t PROGMEM KeyboardReport[] =
{
	/* Keyboard Report */
	HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
	HID_RI_USAGE(8, 0x06), /* Keyboard */
	HID_RI_COLLECTION(8, 0x01), /* Application */
	HID_RI_REPORT_ID(8, KEYBOARD_REPORTID_KeyboardReport),
	    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),