Commit 958a1b4e authored by Dean Camera's avatar Dean Camera
Browse files

Fixed Mouse and Keyboard device demos not acting in accordance with the HID...

Fixed Mouse and Keyboard device demos not acting in accordance with the HID specification for idle periods (thanks to Brian Dickman).

Removed support for endpoint/pipe non-control interrupts; these did not act in the way users expected, and had many subtle issues.
parent ea743970
...@@ -43,9 +43,7 @@ TASK_LIST ...@@ -43,9 +43,7 @@ TASK_LIST
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP }, { .Task = USB_USBTask , .TaskStatus = TASK_STOP },
#endif #endif
#if !defined(INTERRUPT_DATA_ENDPOINT)
{ .Task = USB_HID_Report , .TaskStatus = TASK_STOP }, { .Task = USB_HID_Report , .TaskStatus = TASK_STOP },
#endif
}; };
/** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */ /** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */
...@@ -112,9 +110,7 @@ EVENT_HANDLER(USB_Connect) ...@@ -112,9 +110,7 @@ EVENT_HANDLER(USB_Connect)
EVENT_HANDLER(USB_Disconnect) EVENT_HANDLER(USB_Disconnect)
{ {
/* Stop running HID reporting and USB management tasks */ /* Stop running HID reporting and USB management tasks */
#if !defined(INTERRUPT_DATA_ENDPOINT)
Scheduler_SetTaskMode(USB_HID_Report, TASK_STOP); Scheduler_SetTaskMode(USB_HID_Report, TASK_STOP);
#endif
#if !defined(INTERRUPT_CONTROL_ENDPOINT) #if !defined(INTERRUPT_CONTROL_ENDPOINT)
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
...@@ -134,21 +130,11 @@ EVENT_HANDLER(USB_ConfigurationChanged) ...@@ -134,21 +130,11 @@ EVENT_HANDLER(USB_ConfigurationChanged)
ENDPOINT_DIR_IN, GENERIC_EPSIZE, ENDPOINT_DIR_IN, GENERIC_EPSIZE,
ENDPOINT_BANK_SINGLE); ENDPOINT_BANK_SINGLE);
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Enable the endpoint IN interrupt ISR for the report endpoint */
USB_INT_Enable(ENDPOINT_INT_IN);
#endif
/* Setup Generic OUT Report Endpoint */ /* Setup Generic OUT Report Endpoint */
Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT, Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT,
ENDPOINT_DIR_OUT, GENERIC_EPSIZE, ENDPOINT_DIR_OUT, GENERIC_EPSIZE,
ENDPOINT_BANK_SINGLE); ENDPOINT_BANK_SINGLE);
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Enable the endpoint OUT interrupt ISR for the report endpoint */
USB_INT_Enable(ENDPOINT_INT_OUT);
#endif
/* Indicate USB connected and ready */ /* Indicate USB connected and ready */
UpdateStatus(Status_USBReady); UpdateStatus(Status_USBReady);
} }
...@@ -266,7 +252,6 @@ void CreateGenericHIDReport(uint8_t* DataArray) ...@@ -266,7 +252,6 @@ void CreateGenericHIDReport(uint8_t* DataArray)
DataArray[i] = LastReceived[i]; DataArray[i] = LastReceived[i];
} }
#if !defined(INTERRUPT_DATA_ENDPOINT)
TASK(USB_HID_Report) TASK(USB_HID_Report)
{ {
/* Check if the USB system is connected to a host */ /* Check if the USB system is connected to a host */
...@@ -313,8 +298,8 @@ TASK(USB_HID_Report) ...@@ -313,8 +298,8 @@ TASK(USB_HID_Report)
} }
} }
} }
#endif
#if defined(INTERRUPT_CONTROL_ENDPOINT)
/** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as
* a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send
* HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB
...@@ -325,7 +310,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) ...@@ -325,7 +310,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
/* Save previously selected endpoint before selecting a new endpoint */ /* Save previously selected endpoint before selecting a new endpoint */
uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint(); uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();
#if defined(INTERRUPT_CONTROL_ENDPOINT)
/* Check if the control endpoint has received a request */ /* Check if the control endpoint has received a request */
if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP))
{ {
...@@ -338,60 +322,8 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) ...@@ -338,60 +322,8 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
/* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */
USB_INT_Clear(ENDPOINT_INT_SETUP); USB_INT_Clear(ENDPOINT_INT_SETUP);
} }
#endif
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Check if Generic IN endpoint has interrupted */
if (Endpoint_HasEndpointInterrupted(GENERIC_IN_EPNUM))
{
/* Select the Generic IN Report Endpoint */
Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);
/* Clear the endpoint IN interrupt flag */
USB_INT_Clear(ENDPOINT_INT_IN);
/* Clear the Generic IN Report endpoint interrupt and select the endpoint */
Endpoint_ClearEndpointInterrupt(GENERIC_IN_EPNUM);
/* Create a temporary buffer to hold the report to send to the host */
uint8_t GenericData[GENERIC_REPORT_SIZE];
/* Create Generic Report Data */
CreateGenericHIDReport(GenericData);
/* Write Generic Report Data */
Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData));
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN();
}
/* Check if Generic OUT endpoint has interrupted */
if (Endpoint_HasEndpointInterrupted(GENERIC_OUT_EPNUM))
{
/* Select the Generic OUT Report Endpoint */
Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM);
/* Clear the endpoint OUT Interrupt flag */
USB_INT_Clear(ENDPOINT_INT_OUT);
/* Clear the Generic OUT Report endpoint interrupt and select the endpoint */
Endpoint_ClearEndpointInterrupt(GENERIC_OUT_EPNUM);
/* Create a temporary buffer to hold the read in report from the host */
uint8_t GenericData[GENERIC_REPORT_SIZE];
/* Read Generic Report Data */
Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData));
/* Process Generic Report Data */
ProcessGenericHIDReport(GenericData);
/* Finalize the stream transfer to send the last packet */
Endpoint_ClearOUT();
}
#endif
/* Restore previously selected endpoint */ /* Restore previously selected endpoint */
Endpoint_SelectEndpoint(PrevSelectedEndpoint); Endpoint_SelectEndpoint(PrevSelectedEndpoint);
} }
#endif
...@@ -67,12 +67,5 @@ ...@@ -67,12 +67,5 @@
* which services control requests from the host. If not defined, the control endpoint * which services control requests from the host. If not defined, the control endpoint
* is serviced via polling using the task scheduler.</td> * is serviced via polling using the task scheduler.</td>
* </tr> * </tr>
* <tr>
* <td>INTERRUPT_DATA_ENDPOINT</td>
* <td>Makefile CDEFS</td>
* <td>When defined, this causes the demo to enable interrupts for the data endpoints,
* which services incoming LED reports and outgoing key status reports to and from the host.
* If not defined, the data endpoints are serviced via polling using the task scheduler.</td>
* </tr>
* </table> * </table>
*/ */
...@@ -56,9 +56,9 @@ TASK_LIST ...@@ -56,9 +56,9 @@ TASK_LIST
bool UsingReportProtocol = true; bool UsingReportProtocol = true;
/** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
* for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse). * for either the entire idle duration, or until the report status changes (e.g. the user presses a key).
*/ */
uint8_t IdleCount = 0; uint16_t IdleCount = 500;
/** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
* milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request * milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
...@@ -140,9 +140,7 @@ EVENT_HANDLER(USB_Reset) ...@@ -140,9 +140,7 @@ EVENT_HANDLER(USB_Reset)
EVENT_HANDLER(USB_Disconnect) EVENT_HANDLER(USB_Disconnect)
{ {
/* Stop running keyboard reporting and USB management tasks */ /* Stop running keyboard reporting and USB management tasks */
#if !defined(INTERRUPT_DATA_ENDPOINT)
Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP); Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP);
#endif
#if !defined(INTERRUPT_CONTROL_ENDPOINT) #if !defined(INTERRUPT_CONTROL_ENDPOINT)
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
...@@ -162,28 +160,16 @@ EVENT_HANDLER(USB_ConfigurationChanged) ...@@ -162,28 +160,16 @@ EVENT_HANDLER(USB_ConfigurationChanged)
ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, ENDPOINT_DIR_IN, KEYBOARD_EPSIZE,
ENDPOINT_BANK_SINGLE); ENDPOINT_BANK_SINGLE);
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Enable the endpoint IN interrupt ISR for the report endpoint */
USB_INT_Enable(ENDPOINT_INT_IN);
#endif
/* Setup Keyboard LED Report Endpoint */ /* Setup Keyboard LED Report Endpoint */
Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT, Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT,
ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE, ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE,
ENDPOINT_BANK_SINGLE); ENDPOINT_BANK_SINGLE);
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Enable the endpoint OUT interrupt ISR for the LED report endpoint */
USB_INT_Enable(ENDPOINT_INT_OUT);
#endif
/* Indicate USB connected and ready */ /* Indicate USB connected and ready */
UpdateStatus(Status_USBReady); UpdateStatus(Status_USBReady);
#if !defined(INTERRUPT_DATA_ENDPOINT)
/* Start running keyboard reporting task */ /* Start running keyboard reporting task */
Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN); Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN);
#endif
} }
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
...@@ -358,7 +344,7 @@ void ProcessLEDReport(uint8_t LEDReport) ...@@ -358,7 +344,7 @@ void ProcessLEDReport(uint8_t LEDReport)
} }
/** Sends the next HID report to the host, via the keyboard data endpoint. */ /** Sends the next HID report to the host, via the keyboard data endpoint. */
static inline void SendNextReport(void) void SendNextReport(void)
{ {
static USB_KeyboardReport_Data_t PrevKeyboardReportData; static USB_KeyboardReport_Data_t PrevKeyboardReportData;
USB_KeyboardReport_Data_t KeyboardReportData; USB_KeyboardReport_Data_t KeyboardReportData;
...@@ -367,41 +353,38 @@ static inline void SendNextReport(void) ...@@ -367,41 +353,38 @@ static inline void SendNextReport(void)
/* Create the next keyboard report for transmission to the host */ /* Create the next keyboard report for transmission to the host */
CreateKeyboardReport(&KeyboardReportData); CreateKeyboardReport(&KeyboardReportData);
/* Check if the idle period is set */ /* Check to see if the report data has changed - if so a report MUST be sent */
if (IdleCount) SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);
{
/* Check if idle period has elapsed */
if (!(IdleMSRemaining))
{
/* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */
IdleMSRemaining = (IdleCount << 2);
}
else
{
/* Idle period not elapsed, indicate that a report must not be sent unless the report has changed */
SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);
}
}
/* Save the current report data for later comparison to check for changes */ /* Save the current report data for later comparison to check for changes */
PrevKeyboardReportData = KeyboardReportData; PrevKeyboardReportData = KeyboardReportData;
/* Check if the idle period is set and has elapsed */
if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))
{
/* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */
IdleMSRemaining = (IdleCount << 2);
/* Idle period is set and has elapsed, must send a report to the host */
SendReport = true;
}
/* Select the Keyboard Report Endpoint */ /* Select the Keyboard Report Endpoint */
Endpoint_SelectEndpoint(KEYBOARD_EPNUM); Endpoint_SelectEndpoint(KEYBOARD_EPNUM);
/* Check if Keyboard Endpoint Ready for Read/Write, and if we should send a report */ /* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */
if (Endpoint_IsReadWriteAllowed() && SendReport) if (Endpoint_IsReadWriteAllowed() && SendReport)
{ {
/* Write Keyboard Report Data */ /* Write Keyboard Report Data */
Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData)); Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));
/* Finalize the stream transfer to send the last packet */ /* Finalize the stream transfer to send the last packet */
Endpoint_ClearIN(); Endpoint_ClearIN();
} }
} }
/** Reads the next LED status report from the host from the LED data endpoint, if one has been sent. */ /** Reads the next LED status report from the host from the LED data endpoint, if one has been sent. */
static inline void ReceiveNextReport(void) void ReceiveNextReport(void)
{ {
/* Select the Keyboard LED Report Endpoint */ /* Select the Keyboard LED Report Endpoint */
Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM); Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM);
...@@ -451,7 +434,6 @@ void UpdateStatus(uint8_t CurrentStatus) ...@@ -451,7 +434,6 @@ void UpdateStatus(uint8_t CurrentStatus)
LEDs_SetAllLEDs(LEDMask); LEDs_SetAllLEDs(LEDMask);
} }
#if !defined(INTERRUPT_DATA_ENDPOINT)
/** Function to manage HID report generation and transmission to the host, when in report mode. */ /** Function to manage HID report generation and transmission to the host, when in report mode. */
TASK(USB_Keyboard_Report) TASK(USB_Keyboard_Report)
{ {
...@@ -465,8 +447,8 @@ TASK(USB_Keyboard_Report) ...@@ -465,8 +447,8 @@ TASK(USB_Keyboard_Report)
ReceiveNextReport(); ReceiveNextReport();
} }
} }
#endif
#if defined(INTERRUPT_CONTROL_ENDPOINT)
/** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as
* a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send
* HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB
...@@ -475,52 +457,20 @@ TASK(USB_Keyboard_Report) ...@@ -475,52 +457,20 @@ TASK(USB_Keyboard_Report)
*/ */
ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
{ {
#if defined(INTERRUPT_CONTROL_ENDPOINT) /* Save previously selected endpoint before selecting a new endpoint */
uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();
/* Check if the control endpoint has received a request */ /* Check if the control endpoint has received a request */
if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP))
{ {
/* Clear the endpoint interrupt */
Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP);
/* Process the control request */ /* Process the control request */
USB_USBTask(); USB_USBTask();
/* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */ /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */
USB_INT_Clear(ENDPOINT_INT_SETUP); USB_INT_Clear(ENDPOINT_INT_SETUP);
} }
#endif
/* Restore previously selected endpoint */
#if defined(INTERRUPT_DATA_ENDPOINT) Endpoint_SelectEndpoint(PrevSelectedEndpoint);
/* Check if keyboard endpoint has interrupted */
if (Endpoint_HasEndpointInterrupted(KEYBOARD_EPNUM))
{
/* Select the Keyboard Report Endpoint */
Endpoint_SelectEndpoint(KEYBOARD_EPNUM);
/* Clear the endpoint IN interrupt flag */
USB_INT_Clear(ENDPOINT_INT_IN);
/* Clear the Keyboard Report endpoint interrupt */
Endpoint_ClearEndpointInterrupt(KEYBOARD_EPNUM);
/* Send the next keypress report to the host */
SendNextReport();
}
/* Check if Keyboard LED status Endpoint has interrupted */
if (Endpoint_HasEndpointInterrupted(KEYBOARD_LEDS_EPNUM))
{
/* Select the Keyboard LED Report Endpoint */
Endpoint_SelectEndpoint(KEYBOARD_LEDS_EPNUM);
/* Clear the endpoint OUT interrupt flag */
USB_INT_Clear(ENDPOINT_INT_OUT);
/* Clear the Keyboard LED Report endpoint interrupt */
Endpoint_ClearEndpointInterrupt(KEYBOARD_LEDS_EPNUM);
/* Process the LED report sent from the host */
ReceiveNextReport();
}
#endif
} }
#endif
...@@ -54,6 +54,9 @@ ...@@ -54,6 +54,9 @@
#include <LUFA/Drivers/Board/LEDs.h> // LEDs driver #include <LUFA/Drivers/Board/LEDs.h> // LEDs driver
/* Macros: */ /* Macros: */
/** Idle period indicating that reports should be sent only when the inputs have changed */
#define HID_IDLE_CHANGESONLY 0
/** HID Class specific request to get the next HID report from the device. */ /** HID Class specific request to get the next HID report from the device. */
#define REQ_GetReport 0x01 #define REQ_GetReport 0x01
...@@ -114,8 +117,8 @@ ...@@ -114,8 +117,8 @@
/* Function Prototypes: */ /* Function Prototypes: */
void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData); void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData);
void ProcessLEDReport(uint8_t LEDReport); void ProcessLEDReport(uint8_t LEDReport);
static inline void SendNextReport(void); void SendNextReport(void);
static inline void ReceiveNextReport(void); void ReceiveNextReport(void);
void UpdateStatus(uint8_t CurrentStatus); void UpdateStatus(uint8_t CurrentStatus);
#endif #endif
...@@ -63,12 +63,5 @@ ...@@ -63,12 +63,5 @@
* which services control requests from the host. If not defined, the control endpoint * which services control requests from the host. If not defined, the control endpoint
* is serviced via polling using the task scheduler.</td> * is serviced via polling using the task scheduler.</td>
* </tr> * </tr>
* <tr>
* <td>INTERRUPT_DATA_ENDPOINT</td>
* <td>Makefile CDEFS</td>
* <td>When defined, this causes the demo to enable interrupts for the data endpoints,
* which services incoming LED reports and outgoing key status reports to and from the host.
* If not defined, the data endpoints are serviced via polling using the task scheduler.</td>
* </tr>
* </table> * </table>
*/ */
...@@ -387,9 +387,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK) ...@@ -387,9 +387,6 @@ ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
/* Check if the control endpoint has received a request */ /* Check if the control endpoint has received a request */
if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP)) if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP))
{ {
/* Clear the endpoint interrupt */
Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP);
/* Process the control request */ /* Process the control request */
USB_USBTask(); USB_USBTask();
......
...@@ -43,9 +43,7 @@ TASK_LIST ...@@ -43,9 +43,7 @@ TASK_LIST
{ .Task = USB_USBTask , .TaskStatus = TASK_STOP }, { .Task = USB_USBTask , .TaskStatus = TASK_STOP },
#endif #endif
#if !defined(INTERRUPT_DATA_ENDPOINT)
{ .Task = USB_Mouse_Report , .TaskStatus = TASK_STOP }, { .Task = USB_Mouse_Report , .TaskStatus = TASK_STOP },
#endif
}; };
/* Global Variables */ /* Global Variables */
...@@ -57,7 +55,7 @@ bool UsingReportProtocol = true; ...@@ -57,7 +55,7 @@ bool UsingReportProtocol = true;
/** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
* for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse). * for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse).
*/ */
uint8_t IdleCount = 0; uint16_t IdleCount = HID_IDLE_CHANGESONLY;
/** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
* milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request * milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
...@@ -140,9 +138,7 @@ EVENT_HANDLER(USB_Reset) ...@@ -140,9 +138,7 @@ EVENT_HANDLER(USB_Reset)
EVENT_HANDLER(USB_Disconnect) EVENT_HANDLER(USB_Disconnect)
{ {
/* Stop running mouse reporting and USB management tasks */ /* Stop running mouse reporting and USB management tasks */
#if !defined(INTERRUPT_DATA_ENDPOINT)
Scheduler_SetTaskMode(USB_Mouse_Report, TASK_STOP); Scheduler_SetTaskMode(USB_Mouse_Report, TASK_STOP);
#endif
#if !defined(INTERRUPT_CONTROL_ENDPOINT) #if !defined(INTERRUPT_CONTROL_ENDPOINT)
Scheduler_SetTaskMode(USB_USBTask, TASK_STOP); Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
...@@ -162,18 +158,11 @@ EVENT_HANDLER(USB_ConfigurationChanged) ...@@ -162,18 +158,11 @@ EVENT_HANDLER(USB_ConfigurationChanged)
ENDPOINT_DIR_IN, MOUSE_EPSIZE, ENDPOINT_DIR_IN, MOUSE_EPSIZE,
ENDPOINT_BANK_SINGLE); ENDPOINT_BANK_SINGLE);
#if defined(INTERRUPT_DATA_ENDPOINT)
/* Enable the endpoint IN interrupt ISR for the report endpoint */
USB_INT_Enable(ENDPOINT_INT_IN);
#endif
/* Indicate USB connected and ready */ /* Indicate USB connected and ready */
UpdateStatus(Status_USBReady); UpdateStatus(Status_USBReady);
#if !defined(INTERRUPT_DATA_ENDPOINT)
/* Start running mouse reporting task */ /* Start running mouse reporting task */
Scheduler_SetTaskMode(USB_Mouse_Report, TASK_RUN); Scheduler_SetTaskMode(USB_Mouse_Report, TASK_RUN);
#endif
} }
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
...@@ -311,34 +300,36 @@ void CreateMouseReport(USB_MouseReport_Data_t* ReportData) ...@@ -311,34 +300,36 @@ void CreateMouseReport(USB_MouseReport_Data_t* ReportData)
} }
/** Sends the next HID report to the host, via the keyboard data endpoint. */ /** Sends the next HID report to the host, via the keyboard data endpoint. */
static inline void SendNextReport(void) void SendNextReport(void)
{ {
static USB_MouseReport_Data_t PrevMouseReportData; static USB_MouseReport_Data_t PrevMouseReportData;
USB_MouseReport_Data_t MouseReportData; USB_MouseReport_Data_t MouseReportData;
bool SendReport = true; bool SendReport;
/* Create the next mouse report for transmission to the host */ /* Create the next mouse report for transmission to the host */
CreateMouseReport(&MouseReportData); CreateMouseReport(&MouseReportData);
/* Check if the idle period is set*/ /* Check to see if the report data has changed - if so a report MUST be sent */
if (IdleCount) SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0);
{
/* Determine if the idle period has elapsed */ /* Override the check if the Y or X values are non-zero - we want continuous movement while the joystick
if (!(IdleMSRemaining)) * is being held down (via continuous reports), otherwise the cursor will only move once per joystick toggle */
{ if ((MouseReportData.Y != 0) || (MouseReportData.X != 0))
/* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */ SendReport = true;
IdleMSRemaining = (IdleCount << 2);
}
else
{
/* Idle period not elapsed, indicate that a report must not be sent unless the report has changed */
SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0);
}
}
/* Save the current report data for later comparison to check for changes */ /* Save the current report data for later comparison to check for changes */
PrevMouseReportData = MouseReportData; PrevMouseReportData = MouseReportData;
/* Check if the idle period is set and has elapsed */
if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))