Make board specific and device peripheral specific drivers' file documentation copy...
[pub/USBasp.git] / Demos / Device / LowLevel / Keyboard / Keyboard.c
index 6abd193..28a3d40 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  Denver Gingerich (denver [at] ossguy [dot] com)\r
+  Copyright 2010  Denver Gingerich (denver [at] ossguy [dot] com)\r
       Based on code by Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
 \r
       Based on code by Dean Camera (dean [at] fourwalledcubicle [dot] com)\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 "Keyboard.h"\r
 \r
  \r
 #include "Keyboard.h"\r
 \r
-/* Scheduler Task List */\r
-TASK_LIST\r
-{\r
-       { .Task = USB_USBTask          , .TaskStatus = TASK_STOP },     \r
-       { .Task = USB_Keyboard_Report  , .TaskStatus = TASK_STOP },\r
-};\r
-\r
-/* Global Variables */\r
 /** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot\r
  *  protocol reporting mode.\r
  */\r
 /** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot\r
  *  protocol reporting mode.\r
  */\r
@@ -63,10 +55,24 @@ uint16_t IdleMSRemaining = 0;
 \r
 \r
 /** Main program entry point. This routine configures the hardware required by the application, then\r
 \r
 \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
+               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
@@ -77,36 +83,17 @@ int main(void)
        /* Hardware Initialization */\r
        Joystick_Init();\r
        LEDs_Init();\r
        /* Hardware Initialization */\r
        Joystick_Init();\r
        LEDs_Init();\r
-       \r
-       /* Millisecond timer initialization, with output compare interrupt enabled for the idle timing */\r
-       OCR0A  = 0x7D;\r
-       TCCR0A = (1 << WGM01);\r
-       TCCR0B = ((1 << CS01) | (1 << CS00));\r
-       TIMSK0 = (1 << OCIE0A);\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
+       Buttons_Init();\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
        /* Default to report protocol on connect */\r
        UsingReportProtocol = true;\r
 \r
        /* Default to report protocol on connect */\r
        UsingReportProtocol = true;\r
@@ -115,43 +102,44 @@ void EVENT_USB_Connect(void)
 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via\r
  *  the status LEDs.\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.\r
  */\r
-void EVENT_USB_Disconnect(void)\r
+void EVENT_USB_Device_Disconnect(void)\r
 {\r
 {\r
-       /* Stop running keyboard reporting and USB management tasks */\r
-       Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_STOP);\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 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 device endpoints.\r
  */\r
-void EVENT_USB_ConfigurationChanged(void)\r
-{\r
-       /* Setup Keyboard Keycode Report Endpoint */\r
-       Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT,\r
-                                      ENDPOINT_DIR_IN, KEYBOARD_EPSIZE,\r
-                                  ENDPOINT_BANK_SINGLE);\r
-\r
-       /* Setup Keyboard LED Report Endpoint */\r
-       Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT,\r
-                                      ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE,\r
-                                  ENDPOINT_BANK_SINGLE);\r
-\r
+void EVENT_USB_Device_ConfigurationChanged(void)\r
+{      \r
        /* Indicate USB connected and ready */\r
        /* Indicate USB connected and ready */\r
-       UpdateStatus(Status_USBReady);\r
+       LEDs_SetAllLEDs(LEDMASK_USB_READY);\r
 \r
 \r
-       /* Start running keyboard reporting task */\r
-       Scheduler_SetTaskMode(USB_Keyboard_Report, TASK_RUN);\r
+       /* Setup Keyboard Keycode Report Endpoint */\r
+       if (!(Endpoint_ConfigureEndpoint(KEYBOARD_EPNUM, EP_TYPE_INTERRUPT,\r
+                                            ENDPOINT_DIR_IN, KEYBOARD_EPSIZE,\r
+                                        ENDPOINT_BANK_SINGLE)))\r
+       {\r
+               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+       }\r
+       \r
+       /* Setup Keyboard LED Report Endpoint */\r
+       if (!(Endpoint_ConfigureEndpoint(KEYBOARD_LEDS_EPNUM, EP_TYPE_INTERRUPT,\r
+                                            ENDPOINT_DIR_OUT, KEYBOARD_EPSIZE,\r
+                                        ENDPOINT_BANK_SINGLE)))\r
+       {\r
+               LEDs_SetAllLEDs(LEDMASK_USB_ERROR);\r
+       }\r
+       \r
+       USB_Device_EnableSOFEvents();\r
 }\r
 \r
 }\r
 \r
-/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific\r
+/** Event handler for the USB_UnhandledControlRequest 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
  *  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
        /* Handle HID Class specific requests */\r
        switch (USB_ControlRequest.bRequest)\r
 {\r
        /* Handle HID Class specific requests */\r
        switch (USB_ControlRequest.bRequest)\r
@@ -180,7 +168,11 @@ 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
+                               while (!(Endpoint_IsOUTReceived()))\r
+                               {\r
+                                       if (USB_DeviceState == DEVICE_STATE_Unattached)\r
+                                         return;\r
+                               }\r
 \r
                                /* Read in the LED report from the host */\r
                                uint8_t LEDStatus = Endpoint_Read_Byte();\r
 \r
                                /* Read in the LED report from the host */\r
                                uint8_t LEDStatus = Endpoint_Read_Byte();\r
@@ -191,9 +183,7 @@ void EVENT_USB_UnhandledControlPacket(void)
                                /* Clear the endpoint data */\r
                                Endpoint_ClearOUT();\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
                        break;\r
@@ -208,9 +198,7 @@ void EVENT_USB_UnhandledControlPacket(void)
                                /* Send the flag to the host */\r
                                Endpoint_ClearIN();\r
 \r
                                /* Send the flag to the host */\r
                                Endpoint_ClearIN();\r
 \r
-                               /* Acknowledge status stage */\r
-                               while (!(Endpoint_IsOUTReceived()));\r
-                               Endpoint_ClearOUT();\r
+                               Endpoint_ClearStatusStage();\r
                        }\r
                        \r
                        break;\r
                        }\r
                        \r
                        break;\r
@@ -222,9 +210,7 @@ void EVENT_USB_UnhandledControlPacket(void)
                                /* Set or clear the flag depending on what the host indicates that the current Protocol should be */\r
                                UsingReportProtocol = (USB_ControlRequest.wValue != 0);\r
 \r
                                /* Set or clear the flag depending on what the host indicates that the current Protocol should be */\r
                                UsingReportProtocol = (USB_ControlRequest.wValue != 0);\r
 \r
-                               /* Acknowledge status stage */\r
-                               while (!(Endpoint_IsINReady()));\r
-                               Endpoint_ClearIN();\r
+                               Endpoint_ClearStatusStage();\r
                        }\r
                        \r
                        break;\r
                        }\r
                        \r
                        break;\r
@@ -233,12 +219,10 @@ void EVENT_USB_UnhandledControlPacket(void)
                        {\r
                                Endpoint_ClearSETUP();\r
                                \r
                        {\r
                                Endpoint_ClearSETUP();\r
                                \r
-                               /* Get idle period in MSB */\r
-                               IdleCount = (USB_ControlRequest.wValue >> 8);\r
+                               /* Get idle period in MSB, IdleCount must be multiplied by 4 to get number of milliseconds */\r
+                               IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6);\r
                                \r
                                \r
-                               /* Acknowledge status stage */\r
-                               while (!(Endpoint_IsINReady()));\r
-                               Endpoint_ClearIN();\r
+                               Endpoint_ClearStatusStage();\r
                        }\r
                        \r
                        break;\r
                        }\r
                        \r
                        break;\r
@@ -247,25 +231,21 @@ void EVENT_USB_UnhandledControlPacket(void)
                        {               \r
                                Endpoint_ClearSETUP();\r
                                \r
                        {               \r
                                Endpoint_ClearSETUP();\r
                                \r
-                               /* Write the current idle duration to the host */\r
-                               Endpoint_Write_Byte(IdleCount);\r
+                               /* Write the current idle duration to the host, must be divided by 4 before sent to host */\r
+                               Endpoint_Write_Byte(IdleCount >> 2);\r
                                \r
                                /* Send the flag to the host */\r
                                Endpoint_ClearIN();\r
 \r
                                \r
                                /* Send the flag to the host */\r
                                Endpoint_ClearIN();\r
 \r
-                               /* Acknowledge status stage */\r
-                               while (!(Endpoint_IsOUTReceived()));\r
-                               Endpoint_ClearOUT();\r
+                               Endpoint_ClearStatusStage();\r
                        }\r
 \r
                        break;\r
        }\r
 }\r
 \r
                        }\r
 \r
                        break;\r
        }\r
 }\r
 \r
-/** ISR for the timer 0 compare vector. This ISR fires once each millisecond, and increments the\r
- *  scheduler elapsed idle period counter when the host has set an idle period.\r
- */\r
-ISR(TIMER0_COMPA_vect, ISR_BLOCK)\r
+/** Event handler for the USB device Start Of Frame event. */\r
+void EVENT_USB_Device_StartOfFrame(void)\r
 {\r
        /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */\r
        if (IdleMSRemaining)\r
 {\r
        /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */\r
        if (IdleMSRemaining)\r
@@ -274,32 +254,38 @@ ISR(TIMER0_COMPA_vect, ISR_BLOCK)
 \r
 /** Fills the given HID report data structure with the next HID report to send to the host.\r
  *\r
 \r
 /** Fills the given HID report data structure with the next HID report to send to the host.\r
  *\r
- *  \param ReportData  Pointer to a HID report data structure to be filled\r
+ *  \param[out] ReportData  Pointer to a HID report data structure to be filled\r
  */\r
 void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData)\r
 {\r
  */\r
 void CreateKeyboardReport(USB_KeyboardReport_Data_t* ReportData)\r
 {\r
-       uint8_t JoyStatus_LCL = Joystick_GetStatus();\r
+       uint8_t JoyStatus_LCL     = Joystick_GetStatus();\r
+       uint8_t ButtonStatus_LCL  = Buttons_GetStatus();\r
+\r
+       uint8_t UsedKeyCodes      = 0;\r
 \r
        /* Clear the report contents */\r
        memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t));\r
 \r
        /* Clear the report contents */\r
        memset(ReportData, 0, sizeof(USB_KeyboardReport_Data_t));\r
-\r
+       \r
        if (JoyStatus_LCL & JOY_UP)\r
        if (JoyStatus_LCL & JOY_UP)\r
-         ReportData->KeyCode[0] = 0x04; // A\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x04; // A\r
        else if (JoyStatus_LCL & JOY_DOWN)\r
        else if (JoyStatus_LCL & JOY_DOWN)\r
-         ReportData->KeyCode[0] = 0x05; // B\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x05; // B\r
 \r
        if (JoyStatus_LCL & JOY_LEFT)\r
 \r
        if (JoyStatus_LCL & JOY_LEFT)\r
-         ReportData->KeyCode[0] = 0x06; // C\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x06; // C\r
        else if (JoyStatus_LCL & JOY_RIGHT)\r
        else if (JoyStatus_LCL & JOY_RIGHT)\r
-         ReportData->KeyCode[0] = 0x07; // D\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x07; // D\r
 \r
        if (JoyStatus_LCL & JOY_PRESS)\r
 \r
        if (JoyStatus_LCL & JOY_PRESS)\r
-         ReportData->KeyCode[0] = 0x08; // E\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x08; // E\r
+         \r
+       if (ButtonStatus_LCL & BUTTONS_BUTTON1)\r
+         ReportData->KeyCode[UsedKeyCodes++] = 0x09; // F\r
 }\r
 \r
 /** Processes a received LED report, and updates the board LEDs states to match.\r
  *\r
 }\r
 \r
 /** Processes a received LED report, and updates the board LEDs states to match.\r
  *\r
- *  \param LEDReport  LED status report from the host\r
+ *  \param[in] LEDReport  LED status report from the host\r
  */\r
 void ProcessLEDReport(uint8_t LEDReport)\r
 {\r
  */\r
 void ProcessLEDReport(uint8_t LEDReport)\r
 {\r
@@ -331,14 +317,11 @@ void SendNextReport(void)
        /* Check to see if the report data has changed - if so a report MUST be sent */\r
        SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);\r
        \r
        /* Check to see if the report data has changed - if so a report MUST be sent */\r
        SendReport = (memcmp(&PrevKeyboardReportData, &KeyboardReportData, sizeof(USB_KeyboardReport_Data_t)) != 0);\r
        \r
-       /* Save the current report data for later comparison to check for changes */\r
-       PrevKeyboardReportData = KeyboardReportData;\r
-       \r
        /* Check if the idle period is set and has elapsed */\r
        if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))\r
        {\r
        /* Check if the idle period is set and has elapsed */\r
        if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))\r
        {\r
-               /* Reset the idle time remaining counter, must multiply by 4 to get the duration in milliseconds */\r
-               IdleMSRemaining = (IdleCount << 2);\r
+               /* Reset the idle time remaining counter */\r
+               IdleMSRemaining = IdleCount;\r
                \r
                /* Idle period is set and has elapsed, must send a report to the host */\r
                SendReport = true;\r
                \r
                /* Idle period is set and has elapsed, must send a report to the host */\r
                SendReport = true;\r
@@ -350,6 +333,9 @@ void SendNextReport(void)
        /* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */\r
        if (Endpoint_IsReadWriteAllowed() && SendReport)\r
        {\r
        /* Check if Keyboard Endpoint Ready for Read/Write and if we should send a new report */\r
        if (Endpoint_IsReadWriteAllowed() && SendReport)\r
        {\r
+               /* Save the current report data for later comparison to check for changes */\r
+               PrevKeyboardReportData = KeyboardReportData;\r
+       \r
                /* Write Keyboard Report Data */\r
                Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));\r
                \r
                /* Write Keyboard Report Data */\r
                Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));\r
                \r
@@ -382,43 +368,16 @@ void ReceiveNextReport(void)
        }\r
 }\r
 \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 Keyboard_StatusCodes_t enum\r
- */\r
-void UpdateStatus(uint8_t CurrentStatus)\r
-{\r
-       uint8_t LEDMask = LEDS_NO_LEDS;\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
-       \r
-       /* Set the board LEDs to the new LED mask */\r
-       LEDs_SetAllLEDs(LEDMask);\r
-}\r
-\r
 /** Function to manage HID report generation and transmission to the host, when in report mode. */\r
 /** Function to manage HID report generation and transmission to the host, when in report mode. */\r
-TASK(USB_Keyboard_Report)\r
+void HID_Task(void)\r
 {\r
 {\r
-       /* Check if the USB system is connected to a host */\r
-       if (USB_IsConnected)\r
-       {\r
-               /* Send the next keypress report to the host */\r
-               SendNextReport();\r
+       /* Device must be connected and configured for the task to run */\r
+       if (USB_DeviceState != DEVICE_STATE_Configured)\r
+         return;\r
+         \r
+       /* Send the next keypress report to the host */\r
+       SendNextReport();\r
                \r
                \r
-               /* Process the LED report sent from the host */\r
-               ReceiveNextReport();\r
-       }\r
+       /* Process the LED report sent from the host */\r
+       ReceiveNextReport();\r
 }\r
 }\r