Add LUFA-side channel open/close routines, add signalling handlers for the creation...
[pub/USBasp.git] / Demos / Device / LowLevel / KeyboardMouse / KeyboardMouse.c
index 25d633e..e41b709 100644 (file)
@@ -1,22 +1,22 @@
 /*\r
              LUFA Library\r
 /*\r
              LUFA Library\r
-     Copyright (C) Dean Camera, 2009.\r
+     Copyright (C) Dean Camera, 2010.\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
               \r
   dean [at] fourwalledcubicle [dot] com\r
       www.fourwalledcubicle.com\r
 */\r
 \r
 /*\r
-  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-  Copyright 2009  Denver Gingerich (denver [at] ossguy [dot] com)\r
+  Copyright 2010  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
+  Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)\r
          \r
          \r
-  Permission to use, copy, modify, and distribute this software\r
-  and its documentation for any purpose and without fee is hereby\r
-  granted, provided that the above copyright notice appear in all\r
-  copies and that both that the copyright notice and this\r
-  permission notice and warranty disclaimer appear in supporting\r
-  documentation, and that the name of the author not be used in\r
-  advertising or publicity pertaining to distribution of the\r
+  Permission to use, copy, modify, distribute, and sell this \r
+  software and its documentation for any purpose is hereby granted\r
+  without fee, provided that the above copyright notice appear in \r
+  all copies and that both that the copyright notice and this\r
+  permission notice and warranty disclaimer appear in supporting \r
+  documentation, and that the name of the author not be used in \r
+  advertising or publicity pertaining to distribution of the \r
   software without specific, written prior permission.\r
 \r
   The author disclaim all warranties with regard to this\r
   software without specific, written prior permission.\r
 \r
   The author disclaim all warranties with regard to this\r
  \r
 #include "KeyboardMouse.h"\r
 \r
  \r
 #include "KeyboardMouse.h"\r
 \r
-/* Scheduler Task List */\r
-TASK_LIST\r
-{\r
-       { .Task = USB_USBTask               , .TaskStatus = TASK_STOP },\r
-       { .Task = USB_Mouse                 , .TaskStatus = TASK_RUN  },\r
-       { .Task = USB_Keyboard              , .TaskStatus = TASK_RUN  },\r
-};\r
-\r
-/* Global Variables */\r
 /** Global structure to hold the current keyboard interface HID report, for transmission to the host */\r
 USB_KeyboardReport_Data_t KeyboardReportData;\r
 \r
 /** Global structure to hold the current mouse interface HID report, for transmission to the host */\r
 USB_MouseReport_Data_t    MouseReportData;\r
 \r
 /** Global structure to hold the current keyboard interface HID report, for transmission to the host */\r
 USB_KeyboardReport_Data_t KeyboardReportData;\r
 \r
 /** Global structure to hold the current mouse interface HID report, for transmission to the host */\r
 USB_MouseReport_Data_t    MouseReportData;\r
 \r
+\r
 /** Main program entry point. This routine configures the hardware required by the application, then\r
 /** Main program entry point. This routine configures the hardware required by the application, then\r
- *  starts the scheduler to run the USB management task.\r
+ *  enters a loop to run the application tasks in sequence.\r
  */\r
 int main(void)\r
 {\r
  */\r
 int main(void)\r
 {\r
+       SetupHardware();\r
+       \r
+       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
+\r
+       for (;;)\r
+       {\r
+               Keyboard_HID_Task();\r
+               Mouse_HID_Task();\r
+               USB_USBTask();\r
+       }\r
+}\r
+\r
+/** Configures the board hardware and chip peripherals for the demo's functionality. */\r
+void SetupHardware(void)\r
+{\r
        /* Disable watchdog if enabled by bootloader/fuses */\r
        MCUSR &= ~(1 << WDRF);\r
        wdt_disable();\r
        /* Disable watchdog if enabled by bootloader/fuses */\r
        MCUSR &= ~(1 << WDRF);\r
        wdt_disable();\r
@@ -67,73 +74,65 @@ int main(void)
        /* Hardware Initialization */\r
        Joystick_Init();\r
        LEDs_Init();\r
        /* Hardware Initialization */\r
        Joystick_Init();\r
        LEDs_Init();\r
-       \r
-       /* Indicate USB not ready */\r
-       UpdateStatus(Status_USBNotReady);\r
-       \r
-       /* Initialize Scheduler so that it can be used */\r
-       Scheduler_Init();\r
-\r
-       /* Initialize USB Subsystem */\r
        USB_Init();\r
        USB_Init();\r
-       \r
-       /* Scheduling - routine never returns, so put this last in the main function */\r
-       Scheduler_Start();\r
 }\r
 \r
 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and\r
  *  starts the library USB task to begin the enumeration and USB management process.\r
  */\r
 }\r
 \r
 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and\r
  *  starts the library USB task to begin the enumeration and USB management process.\r
  */\r
-void EVENT_USB_Connect(void)\r
+void EVENT_USB_Device_Connect(void)\r
 {\r
 {\r
-       /* Start USB management task */\r
-       Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);\r
-\r
        /* Indicate USB enumerating */\r
        /* Indicate USB enumerating */\r
-       UpdateStatus(Status_USBEnumerating);\r
+       LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);\r
 }\r
 \r
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via\r
  *  the status LEDs and stops the USB management task.\r
  */\r
 }\r
 \r
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via\r
  *  the status LEDs and stops the USB management task.\r
  */\r
-void EVENT_USB_Disconnect(void)\r
+void EVENT_USB_Device_Disconnect(void)\r
 {\r
 {\r
-       /* Stop running HID reporting and USB management tasks */\r
-       Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);\r
-\r
        /* Indicate USB not ready */\r
        /* Indicate USB not ready */\r
-       UpdateStatus(Status_USBNotReady);\r
+       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
 }\r
 \r
 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration\r
  *  of the USB device after enumeration, and configures the keyboard and mouse device endpoints.\r
  */\r
 }\r
 \r
 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration\r
  *  of the USB device after enumeration, and configures the keyboard and mouse device endpoints.\r
  */\r
-void EVENT_USB_ConfigurationChanged(void)\r
+void EVENT_USB_Device_ConfigurationChanged(void)\r
 {\r
 {\r
-       /* Setup Keyboard Report Endpoint */\r
-       Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT,\r
-                                      ENDPOINT_DIR_IN, HID_EPSIZE,\r
-                                  ENDPOINT_BANK_SINGLE);\r
+       /* Indicate USB connected and ready */\r
+       LEDs_SetAllLEDs(LEDMASK_USB_READY);\r
 \r
 \r
+       /* Setup Keyboard Report Endpoint */\r
+       if (!(Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT,\r
+                                            ENDPOINT_DIR_IN, HID_EPSIZE,\r
+                                        ENDPOINT_BANK_SINGLE)))\r
+       {\r
+               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+       }\r
+       \r
        /* Setup Keyboard LED Report Endpoint */\r
        /* Setup Keyboard LED Report Endpoint */\r
-       Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT,\r
-                                      ENDPOINT_DIR_OUT, HID_EPSIZE,\r
-                                  ENDPOINT_BANK_SINGLE);\r
+       if (!(Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT,\r
+                                            ENDPOINT_DIR_OUT, HID_EPSIZE,\r
+                                        ENDPOINT_BANK_SINGLE)))\r
+       {\r
+               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+       }\r
 \r
        /* Setup Mouse Report Endpoint */\r
 \r
        /* Setup Mouse Report Endpoint */\r
-       Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT,\r
-                                      ENDPOINT_DIR_IN, HID_EPSIZE,\r
-                                  ENDPOINT_BANK_SINGLE);\r
-\r
-       /* Indicate USB connected and ready */\r
-       UpdateStatus(Status_USBReady);\r
+       if (!(Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT,\r
+                                            ENDPOINT_DIR_IN, HID_EPSIZE,\r
+                                        ENDPOINT_BANK_SINGLE)))\r
+       {\r
+               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+       }\r
 }\r
 \r
 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific\r
  *  control requests that are not handled internally by the USB library (including the HID commands, which are\r
  *  all issued via the control endpoint), so that they can be handled appropriately for the application.\r
  */\r
 }\r
 \r
 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific\r
  *  control requests that are not handled internally by the USB library (including the HID commands, which are\r
  *  all issued via the control endpoint), so that they can be handled appropriately for the application.\r
  */\r
-void EVENT_USB_UnhandledControlPacket(void)\r
+void EVENT_USB_Device_UnhandledControlRequest(void)\r
 {\r
        uint8_t* ReportData;\r
        uint8_t  ReportSize;\r
 {\r
        uint8_t* ReportData;\r
        uint8_t  ReportSize;\r
@@ -175,60 +174,44 @@ void EVENT_USB_UnhandledControlPacket(void)
                                Endpoint_ClearSETUP();\r
                                \r
                                /* Wait until the LED report has been sent by the host */\r
                                Endpoint_ClearSETUP();\r
                                \r
                                /* Wait until the LED report has been sent by the host */\r
-                               while (!(Endpoint_IsOUTReceived()));\r
-\r
-                               /* Read in the LED report from the host */\r
-                               uint8_t LEDStatus = Endpoint_Read_Byte();\r
-                               uint8_t LEDMask   = LEDS_LED2;\r
-                               \r
-                               if (LEDStatus & 0x01) // NUM Lock\r
-                                 LEDMask |= LEDS_LED1;\r
-                               \r
-                               if (LEDStatus & 0x02) // CAPS Lock\r
-                                 LEDMask |= LEDS_LED3;\r
-\r
-                               if (LEDStatus & 0x04) // SCROLL Lock\r
-                                 LEDMask |= LEDS_LED4;\r
+                               while (!(Endpoint_IsOUTReceived()))\r
+                               {\r
+                                       if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                         return;\r
+                               }\r
 \r
 \r
-                               /* Set the status LEDs to the current HID LED status */\r
-                               LEDs_SetAllLEDs(LEDMask);\r
+                               /* Read in and process the LED report from the host */\r
+                               Keyboard_ProcessLEDReport(Endpoint_Read_Byte());\r
 \r
                                /* Clear the endpoint data */\r
                                Endpoint_ClearOUT();\r
 \r
 \r
                                /* Clear the endpoint data */\r
                                Endpoint_ClearOUT();\r
 \r
-                               /* Acknowledge status stage */\r
-                               while (!(Endpoint_IsINReady()));\r
-                               Endpoint_ClearIN();\r
+                               Endpoint_ClearStatusStage();\r
                        }\r
                        \r
                        break;\r
        }\r
 }\r
 \r
                        }\r
                        \r
                        break;\r
        }\r
 }\r
 \r
-/** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to\r
- *  log to a serial port, or anything else that is suitable for status updates.\r
- *\r
- *  \param CurrentStatus  Current status of the system, from the KeyboardMouse_StatusCodes_t enum\r
+/** Processes a given Keyboard LED report from the host, and sets the board LEDs to match. Since the Keyboard\r
+ *  LED report can be sent through either the control endpoint (via a HID SetReport request) or the HID OUT\r
+ *  endpoint, the processing code is placed here to avoid duplicating it and potentially having different\r
+ *  behaviour depending on the method used to sent it.\r
  */\r
  */\r
-void UpdateStatus(uint8_t CurrentStatus)\r
+void Keyboard_ProcessLEDReport(const uint8_t LEDStatus)\r
 {\r
 {\r
-       uint8_t LEDMask = LEDS_NO_LEDS;\r
+       uint8_t LEDMask = LEDS_LED2;\r
        \r
        \r
-       /* Set the LED mask to the appropriate LED mask based on the given status code */\r
-       switch (CurrentStatus)\r
-       {\r
-               case Status_USBNotReady:\r
-                       LEDMask = (LEDS_LED1);\r
-                       break;\r
-               case Status_USBEnumerating:\r
-                       LEDMask = (LEDS_LED1 | LEDS_LED2);\r
-                       break;\r
-               case Status_USBReady:\r
-                       LEDMask = (LEDS_LED2 | LEDS_LED4);\r
-                       break;\r
-       }\r
+       if (LEDStatus & KEYBOARD_LED_NUMLOCK)\r
+         LEDMask |= LEDS_LED1;\r
        \r
        \r
-       /* Set the board LEDs to the new LED mask */\r
+       if (LEDStatus & KEYBOARD_LED_CAPSLOCK)\r
+         LEDMask |= LEDS_LED3;\r
+\r
+       if (LEDStatus & KEYBOARD_LED_SCROLLLOCK)\r
+         LEDMask |= LEDS_LED4;\r
+\r
+       /* Set the status LEDs to the current Keyboard LED status */\r
        LEDs_SetAllLEDs(LEDMask);\r
 }\r
 \r
        LEDs_SetAllLEDs(LEDMask);\r
 }\r
 \r
@@ -236,13 +219,20 @@ void UpdateStatus(uint8_t CurrentStatus)
  *  keyboard IN endpoint when the host is ready for more data. Additionally, it processes host LED status\r
  *  reports sent to the device via the keyboard OUT reporting endpoint.\r
  */\r
  *  keyboard IN endpoint when the host is ready for more data. Additionally, it processes host LED status\r
  *  reports sent to the device via the keyboard OUT reporting endpoint.\r
  */\r
-TASK(USB_Keyboard)\r
+void Keyboard_HID_Task(void)\r
 {\r
        uint8_t JoyStatus_LCL = Joystick_GetStatus();\r
 \r
 {\r
        uint8_t JoyStatus_LCL = Joystick_GetStatus();\r
 \r
+       /* Device must be connected and configured for the task to run */\r
+       if (USB_DeviceState != DEVICE_STATE_Configured)\r
+         return;\r
+\r
        /* Check if board button is not pressed, if so mouse mode enabled */\r
        if (!(Buttons_GetStatus() & BUTTONS_BUTTON1))\r
        {\r
        /* Check if board button is not pressed, if so mouse mode enabled */\r
        if (!(Buttons_GetStatus() & BUTTONS_BUTTON1))\r
        {\r
+               /* Make sent key uppercase by indicating that the left shift key is pressed */\r
+               KeyboardReportData.Modifier = KEYBOARD_MODIFER_LEFTSHIFT;\r
+\r
                if (JoyStatus_LCL & JOY_UP)\r
                  KeyboardReportData.KeyCode[0] = 0x04; // A\r
                else if (JoyStatus_LCL & JOY_DOWN)\r
                if (JoyStatus_LCL & JOY_UP)\r
                  KeyboardReportData.KeyCode[0] = 0x04; // A\r
                else if (JoyStatus_LCL & JOY_DOWN)\r
@@ -256,61 +246,48 @@ TASK(USB_Keyboard)
                if (JoyStatus_LCL & JOY_PRESS)\r
                  KeyboardReportData.KeyCode[0] = 0x08; // E\r
        }\r
                if (JoyStatus_LCL & JOY_PRESS)\r
                  KeyboardReportData.KeyCode[0] = 0x08; // E\r
        }\r
-       \r
-       /* Check if the USB system is connected to a host and report protocol mode is enabled */\r
-       if (USB_IsConnected)\r
+\r
+       /* Select the Keyboard Report Endpoint */\r
+       Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);\r
+\r
+       /* Check if Keyboard Endpoint Ready for Read/Write */\r
+       if (Endpoint_IsReadWriteAllowed())\r
        {\r
        {\r
-               /* Select the Keyboard Report Endpoint */\r
-               Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);\r
-\r
-               /* Check if Keyboard Endpoint Ready for Read/Write */\r
-               if (Endpoint_IsReadWriteAllowed())\r
-               {\r
-                       /* Write Keyboard Report Data */\r
-                       Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));\r
-\r
-                       /* Finalize the stream transfer to send the last packet */\r
-                       Endpoint_ClearIN();\r
-\r
-                       /* Clear the report data afterwards */\r
-                       memset(&KeyboardReportData, 0, sizeof(KeyboardReportData));\r
-               }\r
-\r
-               /* Select the Keyboard LED Report Endpoint */\r
-               Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM);\r
-\r
-               /* Check if Keyboard LED Endpoint Ready for Read/Write */\r
-               if (Endpoint_IsReadWriteAllowed())\r
-               {               \r
-                       /* Read in the LED report from the host */\r
-                       uint8_t LEDStatus = Endpoint_Read_Byte();\r
-                       uint8_t LEDMask   = LEDS_LED2;\r
-                       \r
-                       if (LEDStatus & 0x01) // NUM Lock\r
-                         LEDMask |= LEDS_LED1;\r
-                       \r
-                       if (LEDStatus & 0x02) // CAPS Lock\r
-                         LEDMask |= LEDS_LED3;\r
+               /* Write Keyboard Report Data */\r
+               Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));\r
+\r
+               /* Finalize the stream transfer to send the last packet */\r
+               Endpoint_ClearIN();\r
+\r
+               /* Clear the report data afterwards */\r
+               memset(&KeyboardReportData, 0, sizeof(KeyboardReportData));\r
+       }\r
 \r
 \r
-                       if (LEDStatus & 0x04) // SCROLL Lock\r
-                         LEDMask |= LEDS_LED4;\r
+       /* Select the Keyboard LED Report Endpoint */\r
+       Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM);\r
 \r
 \r
-                       /* Set the status LEDs to the current Keyboard LED status */\r
-                       LEDs_SetAllLEDs(LEDMask);\r
+       /* Check if Keyboard LED Endpoint Ready for Read/Write */\r
+       if (Endpoint_IsReadWriteAllowed())\r
+       {               \r
+               /* Read in and process the LED report from the host */\r
+               Keyboard_ProcessLEDReport(Endpoint_Read_Byte());\r
 \r
 \r
-                       /* Handshake the OUT Endpoint - clear endpoint and ready for next report */\r
-                       Endpoint_ClearOUT();\r
-               }\r
+               /* Handshake the OUT Endpoint - clear endpoint and ready for next report */\r
+               Endpoint_ClearOUT();\r
        }\r
 }\r
 \r
 /** Mouse task. This generates the next mouse HID report for the host, and transmits it via the\r
  *  mouse IN endpoint when the host is ready for more data.\r
  */\r
        }\r
 }\r
 \r
 /** Mouse task. This generates the next mouse HID report for the host, and transmits it via the\r
  *  mouse IN endpoint when the host is ready for more data.\r
  */\r
-TASK(USB_Mouse)\r
+void Mouse_HID_Task(void)\r
 {\r
        uint8_t JoyStatus_LCL = Joystick_GetStatus();\r
 \r
 {\r
        uint8_t JoyStatus_LCL = Joystick_GetStatus();\r
 \r
+       /* Device must be connected and configured for the task to run */\r
+       if (USB_DeviceState != DEVICE_STATE_Configured)\r
+         return;\r
+\r
        /* Check if board button is pressed, if so mouse mode enabled */\r
        if (Buttons_GetStatus() & BUTTONS_BUTTON1)\r
        {\r
        /* Check if board button is pressed, if so mouse mode enabled */\r
        if (Buttons_GetStatus() & BUTTONS_BUTTON1)\r
        {\r
@@ -328,23 +305,19 @@ TASK(USB_Mouse)
                  MouseReportData.Button  = (1 << 0);\r
        }\r
 \r
                  MouseReportData.Button  = (1 << 0);\r
        }\r
 \r
-       /* Check if the USB system is connected to a host and report protocol mode is enabled */\r
-       if (USB_IsConnected)\r
-       {\r
-               /* Select the Mouse Report Endpoint */\r
-               Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);\r
+       /* Select the Mouse Report Endpoint */\r
+       Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);\r
 \r
 \r
-               /* Check if Mouse Endpoint Ready for Read/Write */\r
-               if (Endpoint_IsReadWriteAllowed())\r
-               {\r
-                       /* Write Mouse Report Data */\r
-                       Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));\r
+       /* Check if Mouse Endpoint Ready for Read/Write */\r
+       if (Endpoint_IsReadWriteAllowed())\r
+       {\r
+               /* Write Mouse Report Data */\r
+               Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));\r
 \r
 \r
-                       /* Finalize the stream transfer to send the last packet */\r
-                       Endpoint_ClearIN();\r
+               /* Finalize the stream transfer to send the last packet */\r
+               Endpoint_ClearIN();\r
 \r
 \r
-                       /* Clear the report data afterwards */\r
-                       memset(&MouseReportData, 0, sizeof(MouseReportData));\r
-               }\r
+               /* Clear the report data afterwards */\r
+               memset(&MouseReportData, 0, sizeof(MouseReportData));\r
        }\r
 }\r
        }\r
 }\r