From 2919aeeaaba0d1d54e03f9132269c5277d414543 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Fri, 4 Dec 2009 01:06:26 +0000
Subject: [PATCH] Fixed HID Parser not distributing the Usage Min and Usage Max
 values across an array of report items.

Added new HID_ALIGN_DATA() macro to return the pre-retrieved value of a HID report item, left-aligned to a given datatype.

Added new PreviousValue to the HID Report Parser report item structure, for easy monitoring of previous report item values.
---
 .../JoystickHostWithParser.c                  |  2 +-
 .../MouseHostWithParser/MouseHostWithParser.c |  2 +-
 LUFA/Drivers/USB/Class/Host/HIDParser.c       | 26 ++++++++++++++-----
 LUFA/Drivers/USB/Class/Host/HIDParser.h       | 21 +++++++++++++--
 LUFA/ManPages/ChangeLog.txt                   |  3 +++
 LUFA/ManPages/MigrationInformation.txt        |  3 +++
 Projects/AVRISP/Lib/ISPProtocol.h             |  2 +-
 Projects/AVRISP/Lib/ISPTarget.h               |  2 +-
 Projects/AVRISP/Lib/PDIProtocol.h             |  2 +-
 Projects/AVRISP/Lib/PDITarget.c               |  2 +-
 Projects/AVRISP/Lib/PDITarget.h               |  2 +-
 Projects/AVRISP/Lib/V2Protocol.h              |  2 +-
 12 files changed, 52 insertions(+), 17 deletions(-)

diff --git a/Demos/Host/LowLevel/JoystickHostWithParser/JoystickHostWithParser.c b/Demos/Host/LowLevel/JoystickHostWithParser/JoystickHostWithParser.c
index eee9343d3..04f4d2476 100644
--- a/Demos/Host/LowLevel/JoystickHostWithParser/JoystickHostWithParser.c
+++ b/Demos/Host/LowLevel/JoystickHostWithParser/JoystickHostWithParser.c
@@ -282,7 +282,7 @@ void ProcessJoystickReport(uint8_t* JoystickReport)
 			if (!(FoundData))
 			  continue;
 			  
-			int16_t DeltaMovement = (int16_t)(ReportItem->Value << (16 - ReportItem->Attributes.BitSize));
+			int16_t DeltaMovement = HID_ALIGN_DATA(ReportItem, int16_t);
 			
 			/* Determine if the report is for the X or Y delta movement */
 			if (ReportItem->Attributes.Usage.Usage == USAGE_X)
diff --git a/Demos/Host/LowLevel/MouseHostWithParser/MouseHostWithParser.c b/Demos/Host/LowLevel/MouseHostWithParser/MouseHostWithParser.c
index d84e2d3ce..c29d4debd 100644
--- a/Demos/Host/LowLevel/MouseHostWithParser/MouseHostWithParser.c
+++ b/Demos/Host/LowLevel/MouseHostWithParser/MouseHostWithParser.c
@@ -280,7 +280,7 @@ void ProcessMouseReport(uint8_t* MouseReport)
 			if (!(USB_GetHIDReportItemInfo(MouseReport, ReportItem)))
 			  continue;							  
 
-			int16_t WheelDelta = (int16_t)(ReportItem->Value << (16 - ReportItem->Attributes.BitSize));
+			int16_t WheelDelta = HID_ALIGN_DATA(ReportItem, int16_t);
 			
 			if (WheelDelta)
 			  LEDMask = (LEDS_LED1 | LEDS_LED2 | ((WheelDelta > 0) ? LEDS_LED3 : LEDS_LED4));
diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.c b/LUFA/Drivers/USB/Class/Host/HIDParser.c
index 81062b1c8..71598b036 100644
--- a/LUFA/Drivers/USB/Class/Host/HIDParser.c
+++ b/LUFA/Drivers/USB/Class/Host/HIDParser.c
@@ -40,7 +40,8 @@ uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID
 	HID_CollectionPath_t* CurrCollectionPath      = NULL;
 	HID_ReportSizeInfo_t* CurrReportIDInfo        = &ParserData->ReportIDSizes[0];			
 	uint16_t              UsageList[HID_USAGE_STACK_DEPTH];
-	uint8_t               UsageListSize          = 0;
+	uint8_t               UsageListSize           = 0;
+	HID_MinMax_t          UsageMinMax             = {0, 0};
 
 	memset(ParserData,       0x00, sizeof(HID_ReportInfo_t));
 	memset(CurrStateTable,   0x00, sizeof(HID_StateTable_t));
@@ -157,10 +158,10 @@ uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID
 				UsageList[UsageListSize++] = ReportItemData;
 				break;
 			case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
-				CurrStateTable->Attributes.Usage.MinMax.Minimum = ReportItemData;
+				UsageMinMax.Minimum = ReportItemData;
 				break;
 			case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
-				CurrStateTable->Attributes.Usage.MinMax.Maximum = ReportItemData;
+				UsageMinMax.Maximum = ReportItemData;
 				break;
 			case (TYPE_MAIN | TAG_MAIN_COLLECTION):
 				if (CurrCollectionPath == NULL)
@@ -196,6 +197,10 @@ uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID
 					  
 					UsageListSize--;
 				}
+				else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
+				{
+					CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
+				}
 				
 				break;
 			case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
@@ -228,7 +233,11 @@ uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID
 						  
 						UsageListSize--;
 					}
-
+					else if (UsageMinMax.Minimum <= UsageMinMax.Maximum)
+					{
+						CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++;
+					}
+				
 					uint8_t ItemTag = (HIDReportItem & TAG_MASK);
 
 					if (ItemTag == TAG_MAIN_INPUT)
@@ -262,9 +271,9 @@ uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, uint16_t ReportSize, HID
 	  
 		if ((HIDReportItem & TYPE_MASK) == TYPE_MAIN)
 		{
-			CurrStateTable->Attributes.Usage.MinMax.Minimum = 0;
-			CurrStateTable->Attributes.Usage.MinMax.Maximum = 0;
-			UsageListSize = 0;
+			UsageMinMax.Minimum = 0;
+			UsageMinMax.Maximum = 0;
+			UsageListSize   = 0;
 		}
 	}
 	
@@ -280,6 +289,7 @@ bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, HID_ReportItem_t* const
 	uint16_t CurrentBit   = ReportItem->BitOffset;
 	uint32_t BitMask      = (1 << 0);
 
+	ReportItem->PreviousValue = ReportItem->Value;
 	ReportItem->Value = 0;
 	
 	if (ReportItem->ReportID)
@@ -314,6 +324,8 @@ void USB_SetHIDReportItemInfo(uint8_t* ReportData, const HID_ReportItem_t* Repor
 		ReportData++;
 	}
 
+	ReportItem->PreviousValue = ReportItem->Value;
+
 	while (DataBitsRem--)
 	{
 		if (ReportItem->Value & (1 << (CurrentBit % 8)))
diff --git a/LUFA/Drivers/USB/Class/Host/HIDParser.h b/LUFA/Drivers/USB/Class/Host/HIDParser.h
index b04714739..e1f4cb3c2 100644
--- a/LUFA/Drivers/USB/Class/Host/HIDParser.h
+++ b/LUFA/Drivers/USB/Class/Host/HIDParser.h
@@ -71,7 +71,7 @@
 			extern "C" {
 		#endif
 
-	/* Preprocessor checks and defines: */
+	/* Macros: */
 		#if !defined(HID_STATETABLE_STACK_DEPTH) || defined(__DOXYGEN__)
 			/** Constant indicating the maximum stack depth of the state table. A larger state table
 			 *  allows for more PUSH/POP report items to be nested, but consumes more memory. By default
@@ -124,6 +124,17 @@
 			#define HID_MAX_REPORT_IDS            10
 		#endif
 
+		/** Returns the value a given HID report item (once its value has been fetched via \ref USB_GetHIDReportItemInfo())
+		 *  left-aligned to the given data type. This allows for signed data to be interpreted correctly, by shifting the data
+		 *  leftwards until the data's sign bit is in the correct position.
+		 *
+		 *  \param[in] reportitem  HID Report Item whose retrieved value is to be aligned
+		 *  \param[in] type  Data type to align the HID report item's value to
+		 *
+		 *  \return Left-aligned data of the given report item's pre-retrived value for the given datatype
+		 */
+		#define HID_ALIGN_DATA(reportitem, type) ((type)(reportitem->Value << (sizeof(type) - reportitem->Attributes.BitSize)))
+
 	/* Public Interface - May be used in end-application: */
 		/* Enums: */			
 			/** Enum for the possible error codes in the return value of the \ref USB_ProcessHIDReport() function */
@@ -160,7 +171,6 @@
 			{
 				uint16_t                     Page;   /**< Usage page of the report item. */
 				uint16_t                     Usage;  /**< Usage of the report item. */
-				HID_MinMax_t                 MinMax; /**< Usage minimum and maximum of the report item. */
 			} HID_Usage_t;
 
 			/** Type define for a COLLECTION object. Contains the collection attributes and a reference to the
@@ -196,6 +206,7 @@
 				HID_ReportItem_Attributes_t  Attributes;     /**< Report item attributes. */
 							
 				uint32_t                     Value;          /**< Current value of the report item. */
+				uint32_t                     PreviousValue;  /**< Previous value of the report item. */ 
 			} HID_ReportItem_t;
 			
 			/** Type define for a report item size information structure */
@@ -243,6 +254,9 @@
 			/** Extracts the given report item's value out of the given HID report and places it into the Value
 			 *  member of the report item's \ref HID_ReportItem_t structure.
 			 *
+			 *  When called, this copies the report item's Value element to it's PreviousValue element for easy
+			 *  checking to see if an item's value has changed before processing a report.
+			 *
 			 *  \param[in] ReportData  Buffer containing an IN or FEATURE report from an attached device
 			 *  \param[in,out] ReportItem  Pointer to the report item of interest in a \ref HID_ReportInfo_t ReportItem array
 			 *
@@ -256,6 +270,9 @@
 			 *  buffer. The report buffer is assumed to have the appropriate bits cleared before calling
 			 *  this function (i.e., the buffer should be explicitly cleared before report values are added).
 			 *
+			 *  When called, this copies the report item's Value element to it's PreviousValue element for easy
+			 *  checking to see if an item's value has changed before sending a report.
+			 *
 			 *  If the device has multiple HID reports, the first byte in the report is set to the report ID of the given item.
 			 *
 			 *  \param[out] ReportData  Buffer holding the current OUT or FEATURE report data
diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index f0d047894..4fc4424b5 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -19,6 +19,8 @@
   *  - Added PDI programming support for XMEGA devices to the AVRISP programmer project
   *  - Added support for the XPLAIN board Dataflash, with new XPLAIN_REV1 board target for the different dataflash used
   *    on the first revision boards compared to the one mounted on later revisions
+  *  - Added new HID_ALIGN_DATA() macro to return the pre-retrieved value of a HID report item, left-aligned to a given datatype
+  *  - Added new PreviousValue to the HID Report Parser report item structure, for easy monitoring of previous report item values
   *
   *  <b>Changed:</b>
   *  - Removed code in the Keyboard demos to send zeroed reports between two reports with differing numbers of keycodes
@@ -45,6 +47,7 @@
   *  - Fixed misnamed Pipe_SetPipeToken() macro for setting a pipe's direction
   *  - Fixed CDCHost failing on devices with bidirectional endpoints
   *  - Fixed USB driver failing to define the PLL prescaler mask for the ATMEGA8U2 and ATMEGA16U2
+  *  - Fixed HID Parser not distributing the Usage Min and Usage Max values across an array of report items
   *
   *  \section Sec_ChangeLog091122 Version 091122
   *
diff --git a/LUFA/ManPages/MigrationInformation.txt b/LUFA/ManPages/MigrationInformation.txt
index be0952f28..378744ee5 100644
--- a/LUFA/ManPages/MigrationInformation.txt
+++ b/LUFA/ManPages/MigrationInformation.txt
@@ -17,6 +17,9 @@
  *      now named \ref SImage_Host_USBTask() and \ref SImage_Host_ConfigurePipes() respectively.
  *    - The HOST_SENDCONTROL_DeviceDisconnect enum value has been renamed to \ref HOST_SENDCONTROL_DeviceDisconnected to be in
  *      line with the rest of the library error codes.
+ *    - The HID Parser item usages no longer contain seperate minimum and maximum values, as this was a violation of the HID
+ *      specification. Instead, the values are distributed evenly across each item as its usage value, to ensure that all items
+ *      can be distinguished from oneanother.
  *
  *  <b>Device Mode</b>
  *    - The CALLBACK_HID_Device_CreateHIDReport() HID Device Class driver callback now has a new ReportType parameter to
diff --git a/Projects/AVRISP/Lib/ISPProtocol.h b/Projects/AVRISP/Lib/ISPProtocol.h
index 247933e39..2f39b4446 100644
--- a/Projects/AVRISP/Lib/ISPProtocol.h
+++ b/Projects/AVRISP/Lib/ISPProtocol.h
@@ -42,7 +42,7 @@
 		#include "V2Protocol.h"
 		
 	/* Preprocessor Checks: */
-		#if BOARD == BOARD_XPLAIN
+		#if (BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)
 			#undef  ENABLE_ISP_PROTOCOL
 			
 			#if !defined(ENABLE_PDI_PROTOCOL)
diff --git a/Projects/AVRISP/Lib/ISPTarget.h b/Projects/AVRISP/Lib/ISPTarget.h
index da5bd30d1..bf884ae26 100644
--- a/Projects/AVRISP/Lib/ISPTarget.h
+++ b/Projects/AVRISP/Lib/ISPTarget.h
@@ -48,7 +48,7 @@
 		#include "V2ProtocolParams.h"
 
 	/* Preprocessor Checks: */
-		#if BOARD == BOARD_XPLAIN
+		#if (BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)
 			#undef  ENABLE_ISP_PROTOCOL
 			
 			#if !defined(ENABLE_PDI_PROTOCOL)
diff --git a/Projects/AVRISP/Lib/PDIProtocol.h b/Projects/AVRISP/Lib/PDIProtocol.h
index bbbfda50a..9511bc878 100644
--- a/Projects/AVRISP/Lib/PDIProtocol.h
+++ b/Projects/AVRISP/Lib/PDIProtocol.h
@@ -44,7 +44,7 @@
 		#include "PDITarget.h"
 
 	/* Preprocessor Checks: */
-		#if BOARD == BOARD_XPLAIN
+		#if (BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)
 			#undef  ENABLE_ISP_PROTOCOL
 			
 			#if !defined(ENABLE_PDI_PROTOCOL)
diff --git a/Projects/AVRISP/Lib/PDITarget.c b/Projects/AVRISP/Lib/PDITarget.c
index d1dfa1511..98d4bded4 100644
--- a/Projects/AVRISP/Lib/PDITarget.c
+++ b/Projects/AVRISP/Lib/PDITarget.c
@@ -41,7 +41,7 @@
 /** Writes a given byte to the attached XMEGA device, using a RS232 frame via software through the
  *  PDI interface.
  *
- *  \param Byte  Byte to send to the attached device
+ *  \param[in] Byte  Byte to send to the attached device
  */
 void PDITarget_SendByte(uint8_t Byte)
 {
diff --git a/Projects/AVRISP/Lib/PDITarget.h b/Projects/AVRISP/Lib/PDITarget.h
index 0ecc70a26..294d1a98b 100644
--- a/Projects/AVRISP/Lib/PDITarget.h
+++ b/Projects/AVRISP/Lib/PDITarget.h
@@ -43,7 +43,7 @@
 		#include <LUFA/Common/Common.h>
 	
 	/* Preprocessor Checks: */
-		#if BOARD == BOARD_XPLAIN
+		#if (BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)
 			#undef  ENABLE_ISP_PROTOCOL
 			
 			#if !defined(ENABLE_PDI_PROTOCOL)
diff --git a/Projects/AVRISP/Lib/V2Protocol.h b/Projects/AVRISP/Lib/V2Protocol.h
index 8a0ac2f7d..d40f951f9 100644
--- a/Projects/AVRISP/Lib/V2Protocol.h
+++ b/Projects/AVRISP/Lib/V2Protocol.h
@@ -47,7 +47,7 @@
 		#include "PDIProtocol.h"
 
 	/* Preprocessor Checks: */
-		#if BOARD == BOARD_XPLAIN
+		#if (BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1)
 			#undef  ENABLE_ISP_PROTOCOL
 			
 			#if !defined(ENABLE_PDI_PROTOCOL)
-- 
GitLab