From 7ef58eef7a57c46ab53ed8a26805b58dcffd7010 Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Fri, 20 Nov 2009 04:39:41 +0000
Subject: [PATCH] Fixed LowLevel Keyboard demo not saving the issued report
 only after it has been written to the endpoint.

Added support for multiple keyboard keycodes in a single report to the LowLevel and ClassDriver Keyboard demos.
---
 Demos/Device/ClassDriver/Keyboard/Keyboard.c  | 24 +++++++++----
 .../Device/ClassDriver/Keyboard/Keyboard.txt  | 11 +++---
 Demos/Device/LowLevel/Keyboard/Keyboard.c     | 36 +++++++++++++------
 Demos/Device/LowLevel/Keyboard/Keyboard.h     |  1 +
 Demos/Device/LowLevel/Keyboard/Keyboard.txt   | 11 +++---
 Demos/Device/LowLevel/Mouse/Mouse.c           |  8 ++---
 .../JoystickHostWithParser.c                  |  2 +-
 .../MouseHostWithParser/MouseHostWithParser.c |  2 +-
 .../RNDISEthernetHost/RNDISEthernetHost.c     |  2 +-
 LUFA/ManPages/ChangeLog.txt                   |  2 ++
 LUFA/ManPages/FutureChanges.txt               |  3 +-
 .../StandaloneProgrammer.c                    |  2 +-
 12 files changed, 68 insertions(+), 36 deletions(-)

diff --git a/Demos/Device/ClassDriver/Keyboard/Keyboard.c b/Demos/Device/ClassDriver/Keyboard/Keyboard.c
index ea373a802..2918f5a67 100644
--- a/Demos/Device/ClassDriver/Keyboard/Keyboard.c
+++ b/Demos/Device/ClassDriver/Keyboard/Keyboard.c
@@ -144,22 +144,34 @@ bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDIn
 	uint8_t JoyStatus_LCL    = Joystick_GetStatus();
 	uint8_t ButtonStatus_LCL = Buttons_GetStatus();
 
+	static uint8_t PrevUsedKeyCodes;
+	uint8_t UsedKeyCodes = 0;
+	
 	if (JoyStatus_LCL & JOY_UP)
-	  KeyboardReport->KeyCode[0] = 0x04; // A
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x04; // A
 	else if (JoyStatus_LCL & JOY_DOWN)
-	  KeyboardReport->KeyCode[0] = 0x05; // B
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x05; // B
 
 	if (JoyStatus_LCL & JOY_LEFT)
-	  KeyboardReport->KeyCode[0] = 0x06; // C
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x06; // C
 	else if (JoyStatus_LCL & JOY_RIGHT)
-	  KeyboardReport->KeyCode[0] = 0x07; // D
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x07; // D
 
 	if (JoyStatus_LCL & JOY_PRESS)
-	  KeyboardReport->KeyCode[0] = 0x08; // E
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x08; // E
 	  
 	if (ButtonStatus_LCL & BUTTONS_BUTTON1)
-	  KeyboardReport->KeyCode[0] = 0x09; // F
+	  KeyboardReport->KeyCode[UsedKeyCodes++] = 0x09; // F
 	
+	/* The host will ignore the device if we add a new keycode to the report while another keycode is currently
+	 * being sent (i.e. the user has pressed another key while a key is already being pressed) - we need to intersperse
+	 * the two reports with a zeroed report to force the host to accept the additional keys */
+	if (UsedKeyCodes != PrevUsedKeyCodes)
+	{
+		memset(KeyboardReport, sizeof(USB_KeyboardReport_Data_t), 0x00);
+		PrevUsedKeyCodes = UsedKeyCodes;
+	}
+
 	*ReportSize = sizeof(USB_KeyboardReport_Data_t);
 	return false;
 }
diff --git a/Demos/Device/ClassDriver/Keyboard/Keyboard.txt b/Demos/Device/ClassDriver/Keyboard/Keyboard.txt
index b1f5c2b53..89dde8305 100644
--- a/Demos/Device/ClassDriver/Keyboard/Keyboard.txt
+++ b/Demos/Device/ClassDriver/Keyboard/Keyboard.txt
@@ -49,11 +49,12 @@
  *  OSes (i.e. no special drivers required). It is boot protocol compatible, and thus
  *  works under compatible BIOS as if it was a native keyboard (e.g. PS/2).
  *  
- *  On start-up the system will automatically enumerate and function
- *  as a keyboard when the USB connection to a host is present. To use
- *  the keyboard example, manipulate the joystick to send the letters
- *  a, b, c, d and e. See the USB HID documentation for more information
- *  on sending keyboard event and key presses.
+ *  On start-up the system will automatically enumerate and function as a keyboard 
+ *  when the USB connection to a host is present. To use the keyboard example,
+ *  manipulate the joystick to send the letters a, b, c, d and e. See the USB HID
+ *  documentation for more information on sending keyboard event and key presses. Unlike
+ *  other LUFA Keyboard demos, this example shows explicitly how to send multiple keypresses
+ *  inside the same report to the host.
  *
  *  \section SSec_Options Project Options
  *  
diff --git a/Demos/Device/LowLevel/Keyboard/Keyboard.c b/Demos/Device/LowLevel/Keyboard/Keyboard.c
index 32765af3d..33a6d840a 100644
--- a/Demos/Device/LowLevel/Keyboard/Keyboard.c
+++ b/Demos/Device/LowLevel/Keyboard/Keyboard.c
@@ -84,6 +84,7 @@ void SetupHardware(void)
 	Joystick_Init();
 	LEDs_Init();
 	USB_Init();
+	Buttons_Init();
 }
 
 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
@@ -257,23 +258,38 @@ void EVENT_USB_Device_StartOfFrame(void)
  */
 void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData)
 {
-	uint8_t JoyStatus_LCL = Joystick_GetStatus();
+	static uint8_t PrevUsedKeyCodes;
+	uint8_t UsedKeyCodes      = 0;
+	uint8_t JoyStatus_LCL     = Joystick_GetStatus();
+	uint8_t ButtonStatus_LCL  = Buttons_GetStatus();
 
 	/* Clear the report contents */
 	memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t));
-
+	
 	if (JoyStatus_LCL & JOY_UP)
-	  ReportData->KeyCode[0] = 0x04; // A
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x04; // A
 	else if (JoyStatus_LCL & JOY_DOWN)
-	  ReportData->KeyCode[0] = 0x05; // B
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x05; // B
 
 	if (JoyStatus_LCL & JOY_LEFT)
-	  ReportData->KeyCode[0] = 0x06; // C
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x06; // C
 	else if (JoyStatus_LCL & JOY_RIGHT)
-	  ReportData->KeyCode[0] = 0x07; // D
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x07; // D
 
 	if (JoyStatus_LCL & JOY_PRESS)
-	  ReportData->KeyCode[0] = 0x08; // E
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x08; // E
+	  
+	if (ButtonStatus_LCL & BUTTONS_BUTTON1)
+	  ReportData->KeyCode[UsedKeyCodes++] = 0x09; // F
+	
+	/* The host will ignore the device if we add a new keycode to the report while another keycode is currently
+	 * being sent (i.e. the user has pressed another key while a key is already being pressed) - we need to intersperse
+	 * the two reports with a zeroed report to force the host to accept the additional keys */
+	if (UsedKeyCodes != PrevUsedKeyCodes)
+	{
+		memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t));
+		PrevUsedKeyCodes = UsedKeyCodes;
+	}
 }
 
 /** Processes a received LED report, and updates the board LEDs states to match.
@@ -310,9 +326,6 @@ void SendNextReport(void)
 	/* Check to see if the report data has changed - if so a report MUST be sent */
 	SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);
 	
-	/* Save the current report data for later comparison to check for changes */
-	PrevKeyboardReportData = KeyboardReportData;
-	
 	/* Check if the idle period is set and has elapsed */
 	if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))
 	{
@@ -329,6 +342,9 @@ void SendNextReport(void)
 	/* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */
 	if (Endpoint_IsReadWriteAllowed() && SendReport)
 	{
+		/* Save the current report data for later comparison to check for changes */
+		PrevKeyboardReportData = KeyboardReportData;
+	
 		/* Write Keyboard Report Data */
 		Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));
 		
diff --git a/Demos/Device/LowLevel/Keyboard/Keyboard.h b/Demos/Device/LowLevel/Keyboard/Keyboard.h
index f319ab73b..576e08030 100644
--- a/Demos/Device/LowLevel/Keyboard/Keyboard.h
+++ b/Demos/Device/LowLevel/Keyboard/Keyboard.h
@@ -49,6 +49,7 @@
 		#include <LUFA/Version.h>
 		#include <LUFA/Drivers/USB/USB.h>
 		#include <LUFA/Drivers/Board/Joystick.h>
+		#include <LUFA/Drivers/Board/Buttons.h>
 		#include <LUFA/Drivers/Board/LEDs.h>
 
 	/* Macros: */
diff --git a/Demos/Device/LowLevel/Keyboard/Keyboard.txt b/Demos/Device/LowLevel/Keyboard/Keyboard.txt
index 1aa1675ab..2bdaa6cc3 100644
--- a/Demos/Device/LowLevel/Keyboard/Keyboard.txt
+++ b/Demos/Device/LowLevel/Keyboard/Keyboard.txt
@@ -49,11 +49,12 @@
  *  OSes (i.e. no special drivers required). It is boot protocol compatible, and thus
  *  works under compatible BIOS as if it was a native keyboard (e.g. PS/2).
  *  
- *  On start-up the system will automatically enumerate and function
- *  as a keyboard when the USB connection to a host is present. To use
- *  the keyboard example, manipulate the joystick to send the letters
- *  a, b, c, d and e. See the USB HID documentation for more information
- *  on sending keyboard event and key presses.
+ *  On start-up the system will automatically enumerate and function as a keyboard 
+ *  when the USB connection to a host is present. To use the keyboard example,
+ *  manipulate the joystick to send the letters a, b, c, d and e. See the USB HID
+ *  documentation for more information on sending keyboard event and key presses. Unlike
+ *  other LUFA Keyboard demos, this example shows explicitly how to send multiple keypresses
+ *  inside the same report to the host.
  *
  *  \section SSec_Options Project Options
  *  
diff --git a/Demos/Device/LowLevel/Mouse/Mouse.c b/Demos/Device/LowLevel/Mouse/Mouse.c
index 4b318e30c..ff54c6544 100644
--- a/Demos/Device/LowLevel/Mouse/Mouse.c
+++ b/Demos/Device/LowLevel/Mouse/Mouse.c
@@ -268,9 +268,6 @@ void SendNextReport(void)
 	if ((MouseReportData.Y != 0) || (MouseReportData.X != 0))
 	  SendReport = true;
 	
-	/* Save the current report data for later comparison to check for changes */
-	PrevMouseReportData = MouseReportData;
-	
 	/* Check if the idle period is set and has elapsed */
 	if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))
 	{
@@ -286,7 +283,10 @@ void SendNextReport(void)
 
 	/* Check if Mouse Endpoint Ready for Read/Write and if we should send a new report */
 	if (Endpoint_IsReadWriteAllowed() && SendReport)
-	{
+	{	
+		/* Save the current report data for later comparison to check for changes */
+		PrevMouseReportData = MouseReportData;
+
 		/* Write Mouse Report Data */
 		Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));
 		
diff --git a/Demos/Host/ClassDriver/JoystickHostWithParser/JoystickHostWithParser.c b/Demos/Host/ClassDriver/JoystickHostWithParser/JoystickHostWithParser.c
index 037f72237..c620702ff 100644
--- a/Demos/Host/ClassDriver/JoystickHostWithParser/JoystickHostWithParser.c
+++ b/Demos/Host/ClassDriver/JoystickHostWithParser/JoystickHostWithParser.c
@@ -263,7 +263,7 @@ bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* CurrentItem)
 
 	/* Iterate through the item's collection path, until either the root collection node or a collection with the
 	 * Joystick Usage is found - this prevents Mice, which use identical descriptors except for the Joystick usage
-	 * parent node, from being erroneously treated as a joystick
+	 * parent node, from being erroneously treated as a joystick by the demo
 	 */
 	for (HID_CollectionPath_t* CurrPath = CurrentItem->CollectionPath; CurrPath != NULL; CurrPath = CurrPath->Parent)
 	{
diff --git a/Demos/Host/ClassDriver/MouseHostWithParser/MouseHostWithParser.c b/Demos/Host/ClassDriver/MouseHostWithParser/MouseHostWithParser.c
index 289a323f5..938dc26d5 100644
--- a/Demos/Host/ClassDriver/MouseHostWithParser/MouseHostWithParser.c
+++ b/Demos/Host/ClassDriver/MouseHostWithParser/MouseHostWithParser.c
@@ -278,7 +278,7 @@ bool CALLBACK_HIDParser_FilterHIDReportItem(HID_ReportItem_t* CurrentItem)
 
 	/* Iterate through the item's collection path, until either the root collection node or a collection with the
 	 * Mouse Usage is found - this prevents Joysticks, which use identical descriptors except for the Joystick usage
-	 * parent node, from being erroneously treated as a mouse
+	 * parent node, from being erroneously treated as a mouse by the demo
 	 */
 	for (HID_CollectionPath_t* CurrPath = CurrentItem->CollectionPath; CurrPath != NULL; CurrPath = CurrPath->Parent)
 	{
diff --git a/Demos/Host/Incomplete/RNDISEthernetHost/RNDISEthernetHost.c b/Demos/Host/Incomplete/RNDISEthernetHost/RNDISEthernetHost.c
index f3252cd87..237d94dfe 100644
--- a/Demos/Host/Incomplete/RNDISEthernetHost/RNDISEthernetHost.c
+++ b/Demos/Host/Incomplete/RNDISEthernetHost/RNDISEthernetHost.c
@@ -263,7 +263,7 @@ void RNDIS_Host_Task(void)
 			}
 			
 			if (RetrievedPacketFilter != PacketFilter)
-				printf("ERROR: Retrieved Packet Filter %08lx != Set Packet Filter %08lx!\r\n", RetrievedPacketFilter, PacketFilter);
+				printf("ERROR: Retrieved Packet Filter 0x%08lx != Set Packet Filter 0x%08lx!\r\n", RetrievedPacketFilter, PacketFilter);
 
 			uint32_t VendorID;
 			if ((ErrorCode = RNDIS_QueryRNDISProperty(OID_GEN_VENDOR_ID,
diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index 84fa2a617..8390fde2c 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -34,6 +34,7 @@
   *  - Changed MouseHostWithParser demos to check that the report items have a Mouse usage collection as a parent at some point,
   *    to prevent Joysticks from enumerating with the demo
   *  - Corrected the name of the misnamed USB_GetDeviceConfigDescriptor() function to USB_Host_GetDeviceConfigDescriptor().
+  *  - Keyboard LowLevel/ClassDriver demos now support multiple simultaneous keypresses (up to 6) per report
   *
   *  <b>Fixed:</b>
   *  - Fixed PrinterHost demo returning invalid Device ID data when the attached device does not have a
@@ -49,6 +50,7 @@
   *  - Fixed HID report parser collection paths invalid due to misplaced semicolon in the free path item search loop
   *  - Fixed HID host Class driver report send/receive report broken when issued through the control pipe
   *  - Fixed HOST_STATE_AS_GPIOR compile time option being ignored when in host mode (thanks to David Lyons)
+  *  - Fixed LowLevel Keyboard demo not saving the issues report only after it has been sent to the host
   *
   *  \section Sec_ChangeLog090924 Version 090924
   *
diff --git a/LUFA/ManPages/FutureChanges.txt b/LUFA/ManPages/FutureChanges.txt
index 20caca016..f58b09cda 100644
--- a/LUFA/ManPages/FutureChanges.txt
+++ b/LUFA/ManPages/FutureChanges.txt
@@ -21,9 +21,7 @@
   *  - Add detailed overviews of how each demo works
   *  - Master LUFA include file rather than per-module includes
   *  - Change makefiles to allow for absolute LUFA location to be used
-  *  - Add unit testing to APIs
   *  - Add board overviews
-  *  - Add resume interrupt support
   *  - Correct mishandling of error cases in Mass Storage demo
   *  - Add RNDIS Host Class driver
   *  - Make new demos
@@ -34,4 +32,5 @@
   *      -# AVR32 UC3B series microcontrollers
   *      -# Atmel ARM7 series microcontrollers
   *      -# Other (commercial) C compilers
+  *  - Write LUFA tutorials
   */
diff --git a/Projects/Incomplete/StandaloneProgrammer/StandaloneProgrammer.c b/Projects/Incomplete/StandaloneProgrammer/StandaloneProgrammer.c
index 655d13a51..afe3b3a36 100644
--- a/Projects/Incomplete/StandaloneProgrammer/StandaloneProgrammer.c
+++ b/Projects/Incomplete/StandaloneProgrammer/StandaloneProgrammer.c
@@ -96,7 +96,7 @@ FATFS DataflashData;
 
 
 /** Stream character fetching routine for the FAT driver so that characters from the currently open file can be
- *  readin sequence when applied to a stdio stream.
+ *  read in sequence when applied to a stdio stream.
  */
 static int Dataflash_getchar(FILE* Stream)
 {
-- 
GitLab