Add missing SVN eol-style property to files where it was missing.
[pub/USBasp.git] / Demos / Device / Incomplete / TestAndMeasurement / TestAndMeasurement.c
index 0767127..15d0a6d 100644 (file)
-/*\r
-             LUFA Library\r
-     Copyright (C) Dean Camera, 2011.\r
-              \r
-  dean [at] fourwalledcubicle [dot] com\r
-           www.lufa-lib.org\r
-*/\r
-\r
-/*\r
-  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
-\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, including all implied warranties of merchantability\r
-  and fitness.  In no event shall the author be liable for any\r
-  special, indirect or consequential damages or any damages\r
-  whatsoever resulting from loss of use, data or profits, whether\r
-  in an action of contract, negligence or other tortious action,\r
-  arising out of or in connection with the use or performance of\r
-  this software.\r
-*/\r
-\r
-#include "TestAndMeasurement.h"\r
-\r
-/** Contains the (usually static) capabilities of the TMC device. This table is requested by the\r
- *  host upon enumeration to give it information on what features of the Test and Measurement USB\r
- *  Class the device supports.\r
- */\r
-TMC_Capabilities_t Capabilities =\r
-       {\r
-               .Status     = TMC_STATUS_SUCCESS,\r
-               .TMCVersion = VERSION_BCD(1.00),\r
-               \r
-               .Interface  =\r
-                       {\r
-                               .ListenOnly             = false,\r
-                               .TalkOnly               = false,\r
-                               .PulseIndicateSupported = false,\r
-                       },\r
-\r
-               .Device     =\r
-                       {\r
-                               .SupportsAbortINOnMatch = false,\r
-                       },\r
-       };\r
-\r
-/** Current TMC control request that is being processed */\r
-static uint8_t RequestInProgress = 0;\r
-\r
-/** Stream callback abort flag for bulk IN data */\r
-static bool IsTMCBulkINReset = false;\r
-\r
-/** Stream callback abort flag for bulk OUT data */\r
-static bool IsTMCBulkOUTReset = false;\r
-\r
-/** Last used tag value for data transfers */\r
-static uint8_t CurrentTransferTag = 0;\r
-\r
-/** Length of last data transfer, for reporting to the host in case an in-progress transfer is aborted */\r
-static uint32_t LastTransferLength = 0;\r
-\r
-/** Main program entry point. This routine contains the overall program flow, including initial\r
- *  setup of all components and the main program loop.\r
- */\r
-int main(void)\r
-{\r
-       SetupHardware();\r
-\r
-       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
-       sei();\r
-       \r
-       for (;;)\r
-       {\r
-               TMC_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
-\r
-       /* Disable clock division */\r
-       clock_prescale_set(clock_div_1);\r
-       \r
-       /* Hardware Initialization */\r
-       LEDs_Init();\r
-       USB_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
-void EVENT_USB_Device_Connect(void)\r
-{\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 and CDC management tasks.\r
- */\r
-void EVENT_USB_Device_Disconnect(void)\r
-{\r
-       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);\r
-}\r
-\r
-/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration\r
- *  of the USB device after enumeration - the device endpoints are configured and the CDC management task started.\r
- */\r
-void EVENT_USB_Device_ConfigurationChanged(void)\r
-{\r
-       bool ConfigSuccess = true;\r
-\r
-       /* Setup TMC In, Out and Notification Endpoints */\r
-       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,\r
-                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);\r
-       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_IN_EPNUM,  EP_TYPE_BULK, ENDPOINT_DIR_IN,\r
-                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);\r
-       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_OUT_EPNUM, EP_TYPE_BULK, ENDPOINT_DIR_OUT,\r
-                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);\r
-\r
-       /* Indicate endpoint configuration success or failure */\r
-       LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);\r
-}\r
-\r
-/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to\r
- *  the device from the USB host before passing along unhandled control requests to the library for processing\r
- *  internally.\r
- */\r
-void EVENT_USB_Device_ControlRequest(void)\r
-{\r
-       uint8_t TMCRequestStatus = TMC_STATUS_SUCCESS;\r
-\r
-       /* Process TMC specific control requests */\r
-       switch (USB_ControlRequest.bRequest)\r
-       {\r
-               case Req_InitiateAbortBulkOut:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))\r
-                       {\r
-                               /* Check that no split transaction is already in progress and the data transfer tag is valid */\r
-                               if (RequestInProgress != 0)\r
-                               {\r
-                                       TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;\r
-                               }\r
-                               else if (USB_ControlRequest.wValue != CurrentTransferTag)\r
-                               {\r
-                                       TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* Indicate that all in-progress/pending data OUT requests should be aborted */\r
-                                       IsTMCBulkOUTReset = true;\r
-                                       \r
-                                       /* Save the split request for later checking when a new request is received */\r
-                                       RequestInProgress = Req_InitiateAbortBulkOut;\r
-                               }\r
-\r
-                               Endpoint_ClearSETUP();\r
-                               \r
-                               /* Write the request response byte */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-\r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();\r
-                       }\r
-                       \r
-                       break;\r
-               case Req_CheckAbortBulkOutStatus:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))\r
-                       {\r
-                               /* Check that an ABORT BULK OUT transaction has been requested and that the request has completed */\r
-                               if (RequestInProgress != Req_InitiateAbortBulkOut)\r
-                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;                          \r
-                               else if (IsTMCBulkOUTReset)\r
-                                 TMCRequestStatus = TMC_STATUS_PENDING;\r
-                               else\r
-                                 RequestInProgress = 0;        \r
-\r
-                               Endpoint_ClearSETUP();\r
-                                                               \r
-                               /* Write the request response bytes */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-                               Endpoint_Write_16_LE(0);\r
-                               Endpoint_Write_32_LE(LastTransferLength);\r
-\r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();                            \r
-                       }\r
-                       \r
-                       break;\r
-               case Req_InitiateAbortBulkIn:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))\r
-                       {\r
-                               /* Check that no split transaction is already in progress and the data transfer tag is valid */\r
-                               if (RequestInProgress != 0)\r
-                               {\r
-                                       TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;                                \r
-                               }\r
-                               else if (USB_ControlRequest.wValue != CurrentTransferTag)\r
-                               {\r
-                                       TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* Indicate that all in-progress/pending data IN requests should be aborted */\r
-                                       IsTMCBulkINReset = true;\r
-                                       \r
-                                       /* Save the split request for later checking when a new request is received */\r
-                                       RequestInProgress = Req_InitiateAbortBulkIn;\r
-                               }\r
-\r
-                               Endpoint_ClearSETUP();\r
-                               \r
-                               /* Write the request response bytes */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-                               Endpoint_Write_8(CurrentTransferTag);\r
-\r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();\r
-                       }\r
-                       \r
-                       break;\r
-               case Req_CheckAbortBulkInStatus:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))\r
-                       {\r
-                               /* Check that an ABORT BULK IN transaction has been requested and that the request has completed */\r
-                               if (RequestInProgress != Req_InitiateAbortBulkIn)\r
-                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;\r
-                               else if (IsTMCBulkINReset)\r
-                                 TMCRequestStatus = TMC_STATUS_PENDING;\r
-                               else\r
-                                 RequestInProgress = 0;\r
-\r
-                               Endpoint_ClearSETUP();\r
-                                                               \r
-                               /* Write the request response bytes */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-                               Endpoint_Write_16_LE(0);\r
-                               Endpoint_Write_32_LE(LastTransferLength);\r
-\r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();\r
-                       }\r
-                       \r
-                       break;\r
-               case Req_InitiateClear:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))\r
-                       {\r
-                               /* Check that no split transaction is already in progress */\r
-                               if (RequestInProgress != 0)\r
-                               {\r
-                                       Endpoint_Write_8(TMC_STATUS_SPLIT_IN_PROGRESS);                         \r
-                               }\r
-                               else\r
-                               {\r
-                                       /* Indicate that all in-progress/pending data IN and OUT requests should be aborted */\r
-                                       IsTMCBulkINReset  = true;\r
-                                       IsTMCBulkOUTReset = true;\r
-                                       \r
-                                       /* Save the split request for later checking when a new request is received */\r
-                                       RequestInProgress = Req_InitiateClear;\r
-                               }\r
-\r
-                               Endpoint_ClearSETUP();\r
-                               \r
-                               /* Write the request response byte */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-\r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();\r
-                       }\r
-                       \r
-                       break;\r
-               case Req_CheckClearStatus:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))\r
-                       {\r
-                               /* Check that a CLEAR transaction has been requested and that the request has completed */\r
-                               if (RequestInProgress != Req_InitiateClear)\r
-                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;                          \r
-                               else if (IsTMCBulkINReset || IsTMCBulkOUTReset)\r
-                                 TMCRequestStatus = TMC_STATUS_PENDING;\r
-                               else\r
-                                 RequestInProgress = 0;\r
-\r
-                               Endpoint_ClearSETUP();\r
-\r
-                               /* Write the request response bytes */\r
-                               Endpoint_Write_8(TMCRequestStatus);\r
-                               Endpoint_Write_8(0);\r
-                               \r
-                               Endpoint_ClearIN();\r
-                               Endpoint_ClearStatusStage();                            \r
-                       }\r
-                       \r
-                       break;\r
-               case Req_GetCapabilities:\r
-                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))\r
-                       {\r
-                               Endpoint_ClearSETUP();\r
-                                       \r
-                               /* Write the device capabilities to the control endpoint */\r
-                               Endpoint_Write_Control_Stream_LE(&Capabilities, sizeof(TMC_Capabilities_t));                            \r
-                               Endpoint_ClearOUT();\r
-                       }\r
-                       \r
-                       break;\r
-       }\r
-}\r
-\r
-/** Function to manage TMC data transmission and reception to and from the host. */\r
-void TMC_Task(void)\r
-{\r
-       /* Device must be connected and configured for the task to run */\r
-       if (USB_DeviceState != DEVICE_STATE_Configured)\r
-         return;\r
-       \r
-       TMC_MessageHeader_t MessageHeader;\r
-       uint16_t            BytesTransferred;\r
-       \r
-       /* Try to read in a TMC message from the interface, process if one is available */\r
-       if (ReadTMCHeader(&MessageHeader))\r
-       {\r
-               /* Indicate busy */\r
-               LEDs_SetAllLEDs(LEDMASK_USB_BUSY);\r
-               \r
-               switch (MessageHeader.MessageID)\r
-               {\r
-                       case TMC_MESSAGEID_DEV_DEP_MSG_OUT:\r
-                               BytesTransferred = 0;\r
-                               while (Endpoint_Discard_Stream(MessageHeader.TransferSize, &BytesTransferred) ==\r
-                                      ENDPOINT_RWSTREAM_IncompleteTransfer)\r
-                               {\r
-                                       if (IsTMCBulkOUTReset)\r
-                                         break;\r
-                               }\r
-                               LastTransferLength = BytesTransferred;\r
-                               \r
-                               Endpoint_ClearOUT();\r
-                               break;\r
-                       case TMC_MESSAGEID_DEV_DEP_MSG_IN:\r
-                               Endpoint_ClearOUT();\r
-\r
-                               MessageHeader.TransferSize = 3;\r
-                               MessageHeader.MessageIDSpecific.DeviceOUT.LastMessageTransaction = true;\r
-                               WriteTMCHeader(&MessageHeader);\r
-\r
-                               BytesTransferred = 0;\r
-                               while (Endpoint_Write_Stream_LE("TMC", MessageHeader.TransferSize, &BytesTransferred) ==\r
-                                      ENDPOINT_RWSTREAM_IncompleteTransfer)\r
-                               {\r
-                                       if (IsTMCBulkINReset)\r
-                                         break;\r
-                               }\r
-                               LastTransferLength = BytesTransferred;\r
-\r
-                               Endpoint_ClearIN();\r
-                               break;\r
-                       default:\r
-                               Endpoint_StallTransaction();\r
-                               break;\r
-               }\r
-\r
-               LEDs_SetAllLEDs(LEDMASK_USB_READY);\r
-       }\r
-       \r
-       /* All pending data has been processed - reset the data abort flags */\r
-       IsTMCBulkINReset  = false;\r
-       IsTMCBulkOUTReset = false;\r
-}\r
-\r
-/** Attempts to read in the TMC message header from the TMC interface.\r
- *\r
- *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored\r
- *\r
- *  \return Boolean true if a header was read, false otherwise\r
- */\r
-bool ReadTMCHeader(TMC_MessageHeader_t* const MessageHeader)\r
-{\r
-       uint16_t BytesTransferred;\r
-\r
-       /* Select the Data Out endpoint */\r
-       Endpoint_SelectEndpoint(TMC_OUT_EPNUM);\r
-       \r
-       /* Abort if no command has been sent from the host */\r
-       if (!(Endpoint_IsOUTReceived()))\r
-         return false;\r
-       \r
-       /* Read in the header of the command from the host */\r
-       BytesTransferred = 0;\r
-       while (Endpoint_Read_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==\r
-              ENDPOINT_RWSTREAM_IncompleteTransfer)\r
-       {\r
-               if (IsTMCBulkOUTReset)\r
-                 break;\r
-       }\r
-\r
-       /* Store the new command tag value for later use */\r
-       CurrentTransferTag = MessageHeader->Tag;\r
-       \r
-       /* Indicate if the command has been aborted or not */\r
-       return !(IsTMCBulkOUTReset);\r
-}\r
-\r
-bool WriteTMCHeader(TMC_MessageHeader_t* const MessageHeader)\r
-{\r
-       uint16_t BytesTransferred;\r
-\r
-       /* Set the message tag of the command header */\r
-       MessageHeader->Tag        =  CurrentTransferTag;\r
-       MessageHeader->InverseTag = ~CurrentTransferTag;\r
-\r
-       /* Select the Data In endpoint */\r
-       Endpoint_SelectEndpoint(TMC_IN_EPNUM);\r
-\r
-       /* Send the command header to the host */\r
-       BytesTransferred = 0;\r
-       while (Endpoint_Write_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==\r
-              ENDPOINT_RWSTREAM_IncompleteTransfer)\r
-       {\r
-               if (IsTMCBulkINReset)\r
-                 break;\r
-       }\r
-\r
-       /* Indicate if the command has been aborted or not */\r
-       return !(IsTMCBulkINReset);\r
-}\r
+/*
+             LUFA Library
+     Copyright (C) Dean Camera, 2011.
+              
+  dean [at] fourwalledcubicle [dot] com
+           www.lufa-lib.org
+*/
+
+/*
+  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+
+  Permission to use, copy, modify, distribute, and sell this 
+  software and its documentation for any purpose is hereby granted
+  without fee, provided that the above copyright notice appear in 
+  all copies and that both that the copyright notice and this
+  permission notice and warranty disclaimer appear in supporting 
+  documentation, and that the name of the author not be used in 
+  advertising or publicity pertaining to distribution of the 
+  software without specific, written prior permission.
+
+  The author disclaim all warranties with regard to this
+  software, including all implied warranties of merchantability
+  and fitness.  In no event shall the author be liable for any
+  special, indirect or consequential damages or any damages
+  whatsoever resulting from loss of use, data or profits, whether
+  in an action of contract, negligence or other tortious action,
+  arising out of or in connection with the use or performance of
+  this software.
+*/
+
+#include "TestAndMeasurement.h"
+
+/** Contains the (usually static) capabilities of the TMC device. This table is requested by the
+ *  host upon enumeration to give it information on what features of the Test and Measurement USB
+ *  Class the device supports.
+ */
+TMC_Capabilities_t Capabilities =
+       {
+               .Status     = TMC_STATUS_SUCCESS,
+               .TMCVersion = VERSION_BCD(1.00),
+               
+               .Interface  =
+                       {
+                               .ListenOnly             = false,
+                               .TalkOnly               = false,
+                               .PulseIndicateSupported = false,
+                       },
+
+               .Device     =
+                       {
+                               .SupportsAbortINOnMatch = false,
+                       },
+       };
+
+/** Current TMC control request that is being processed */
+static uint8_t RequestInProgress = 0;
+
+/** Stream callback abort flag for bulk IN data */
+static bool IsTMCBulkINReset = false;
+
+/** Stream callback abort flag for bulk OUT data */
+static bool IsTMCBulkOUTReset = false;
+
+/** Last used tag value for data transfers */
+static uint8_t CurrentTransferTag = 0;
+
+/** Length of last data transfer, for reporting to the host in case an in-progress transfer is aborted */
+static uint32_t LastTransferLength = 0;
+
+/** Main program entry point. This routine contains the overall program flow, including initial
+ *  setup of all components and the main program loop.
+ */
+int main(void)
+{
+       SetupHardware();
+
+       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+       sei();
+       
+       for (;;)
+       {
+               TMC_Task();
+               USB_USBTask();
+       }
+}
+
+/** Configures the board hardware and chip peripherals for the demo's functionality. */
+void SetupHardware(void)
+{
+       /* Disable watchdog if enabled by bootloader/fuses */
+       MCUSR &= ~(1 << WDRF);
+       wdt_disable();
+
+       /* Disable clock division */
+       clock_prescale_set(clock_div_1);
+       
+       /* Hardware Initialization */
+       LEDs_Init();
+       USB_Init();
+}
+
+/** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
+ *  starts the library USB task to begin the enumeration and USB management process.
+ */
+void EVENT_USB_Device_Connect(void)
+{
+       LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
+}
+
+/** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
+ *  the status LEDs and stops the USB management and CDC management tasks.
+ */
+void EVENT_USB_Device_Disconnect(void)
+{
+       LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
+}
+
+/** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration
+ *  of the USB device after enumeration - the device endpoints are configured and the CDC management task started.
+ */
+void EVENT_USB_Device_ConfigurationChanged(void)
+{
+       bool ConfigSuccess = true;
+
+       /* Setup TMC In, Out and Notification Endpoints */
+       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_NOTIFICATION_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
+                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
+       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_IN_EPNUM,  EP_TYPE_BULK, ENDPOINT_DIR_IN,
+                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
+       ConfigSuccess &= Endpoint_ConfigureEndpoint(TMC_OUT_EPNUM, EP_TYPE_BULK, ENDPOINT_DIR_OUT,
+                                                   TMC_IO_EPSIZE, ENDPOINT_BANK_SINGLE);
+
+       /* Indicate endpoint configuration success or failure */
+       LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
+}
+
+/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to
+ *  the device from the USB host before passing along unhandled control requests to the library for processing
+ *  internally.
+ */
+void EVENT_USB_Device_ControlRequest(void)
+{
+       uint8_t TMCRequestStatus = TMC_STATUS_SUCCESS;
+
+       /* Process TMC specific control requests */
+       switch (USB_ControlRequest.bRequest)
+       {
+               case Req_InitiateAbortBulkOut:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Check that no split transaction is already in progress and the data transfer tag is valid */
+                               if (RequestInProgress != 0)
+                               {
+                                       TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;
+                               }
+                               else if (USB_ControlRequest.wValue != CurrentTransferTag)
+                               {
+                                       TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
+                               }
+                               else
+                               {
+                                       /* Indicate that all in-progress/pending data OUT requests should be aborted */
+                                       IsTMCBulkOUTReset = true;
+                                       
+                                       /* Save the split request for later checking when a new request is received */
+                                       RequestInProgress = Req_InitiateAbortBulkOut;
+                               }
+
+                               Endpoint_ClearSETUP();
+                               
+                               /* Write the request response byte */
+                               Endpoint_Write_8(TMCRequestStatus);
+
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();
+                       }
+                       
+                       break;
+               case Req_CheckAbortBulkOutStatus:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Check that an ABORT BULK OUT transaction has been requested and that the request has completed */
+                               if (RequestInProgress != Req_InitiateAbortBulkOut)
+                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;                          
+                               else if (IsTMCBulkOUTReset)
+                                 TMCRequestStatus = TMC_STATUS_PENDING;
+                               else
+                                 RequestInProgress = 0;        
+
+                               Endpoint_ClearSETUP();
+                                                               
+                               /* Write the request response bytes */
+                               Endpoint_Write_8(TMCRequestStatus);
+                               Endpoint_Write_16_LE(0);
+                               Endpoint_Write_32_LE(LastTransferLength);
+
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();                            
+                       }
+                       
+                       break;
+               case Req_InitiateAbortBulkIn:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Check that no split transaction is already in progress and the data transfer tag is valid */
+                               if (RequestInProgress != 0)
+                               {
+                                       TMCRequestStatus = TMC_STATUS_SPLIT_IN_PROGRESS;                                
+                               }
+                               else if (USB_ControlRequest.wValue != CurrentTransferTag)
+                               {
+                                       TMCRequestStatus = TMC_STATUS_TRANSFER_NOT_IN_PROGRESS;
+                               }
+                               else
+                               {
+                                       /* Indicate that all in-progress/pending data IN requests should be aborted */
+                                       IsTMCBulkINReset = true;
+                                       
+                                       /* Save the split request for later checking when a new request is received */
+                                       RequestInProgress = Req_InitiateAbortBulkIn;
+                               }
+
+                               Endpoint_ClearSETUP();
+                               
+                               /* Write the request response bytes */
+                               Endpoint_Write_8(TMCRequestStatus);
+                               Endpoint_Write_8(CurrentTransferTag);
+
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();
+                       }
+                       
+                       break;
+               case Req_CheckAbortBulkInStatus:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_ENDPOINT))
+                       {
+                               /* Check that an ABORT BULK IN transaction has been requested and that the request has completed */
+                               if (RequestInProgress != Req_InitiateAbortBulkIn)
+                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;
+                               else if (IsTMCBulkINReset)
+                                 TMCRequestStatus = TMC_STATUS_PENDING;
+                               else
+                                 RequestInProgress = 0;
+
+                               Endpoint_ClearSETUP();
+                                                               
+                               /* Write the request response bytes */
+                               Endpoint_Write_8(TMCRequestStatus);
+                               Endpoint_Write_16_LE(0);
+                               Endpoint_Write_32_LE(LastTransferLength);
+
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();
+                       }
+                       
+                       break;
+               case Req_InitiateClear:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+                       {
+                               /* Check that no split transaction is already in progress */
+                               if (RequestInProgress != 0)
+                               {
+                                       Endpoint_Write_8(TMC_STATUS_SPLIT_IN_PROGRESS);                         
+                               }
+                               else
+                               {
+                                       /* Indicate that all in-progress/pending data IN and OUT requests should be aborted */
+                                       IsTMCBulkINReset  = true;
+                                       IsTMCBulkOUTReset = true;
+                                       
+                                       /* Save the split request for later checking when a new request is received */
+                                       RequestInProgress = Req_InitiateClear;
+                               }
+
+                               Endpoint_ClearSETUP();
+                               
+                               /* Write the request response byte */
+                               Endpoint_Write_8(TMCRequestStatus);
+
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();
+                       }
+                       
+                       break;
+               case Req_CheckClearStatus:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+                       {
+                               /* Check that a CLEAR transaction has been requested and that the request has completed */
+                               if (RequestInProgress != Req_InitiateClear)
+                                 TMCRequestStatus = TMC_STATUS_SPLIT_NOT_IN_PROGRESS;                          
+                               else if (IsTMCBulkINReset || IsTMCBulkOUTReset)
+                                 TMCRequestStatus = TMC_STATUS_PENDING;
+                               else
+                                 RequestInProgress = 0;
+
+                               Endpoint_ClearSETUP();
+
+                               /* Write the request response bytes */
+                               Endpoint_Write_8(TMCRequestStatus);
+                               Endpoint_Write_8(0);
+                               
+                               Endpoint_ClearIN();
+                               Endpoint_ClearStatusStage();                            
+                       }
+                       
+                       break;
+               case Req_GetCapabilities:
+                       if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
+                       {
+                               Endpoint_ClearSETUP();
+                                       
+                               /* Write the device capabilities to the control endpoint */
+                               Endpoint_Write_Control_Stream_LE(&Capabilities, sizeof(TMC_Capabilities_t));                            
+                               Endpoint_ClearOUT();
+                       }
+                       
+                       break;
+       }
+}
+
+/** Function to manage TMC data transmission and reception to and from the host. */
+void TMC_Task(void)
+{
+       /* Device must be connected and configured for the task to run */
+       if (USB_DeviceState != DEVICE_STATE_Configured)
+         return;
+       
+       TMC_MessageHeader_t MessageHeader;
+       uint16_t            BytesTransferred;
+       
+       /* Try to read in a TMC message from the interface, process if one is available */
+       if (ReadTMCHeader(&MessageHeader))
+       {
+               /* Indicate busy */
+               LEDs_SetAllLEDs(LEDMASK_USB_BUSY);
+               
+               switch (MessageHeader.MessageID)
+               {
+                       case TMC_MESSAGEID_DEV_DEP_MSG_OUT:
+                               BytesTransferred = 0;
+                               while (Endpoint_Discard_Stream(MessageHeader.TransferSize, &BytesTransferred) ==
+                                      ENDPOINT_RWSTREAM_IncompleteTransfer)
+                               {
+                                       if (IsTMCBulkOUTReset)
+                                         break;
+                               }
+                               LastTransferLength = BytesTransferred;
+                               
+                               Endpoint_ClearOUT();
+                               break;
+                       case TMC_MESSAGEID_DEV_DEP_MSG_IN:
+                               Endpoint_ClearOUT();
+
+                               MessageHeader.TransferSize = 3;
+                               MessageHeader.MessageIDSpecific.DeviceOUT.LastMessageTransaction = true;
+                               WriteTMCHeader(&MessageHeader);
+
+                               BytesTransferred = 0;
+                               while (Endpoint_Write_Stream_LE("TMC", MessageHeader.TransferSize, &BytesTransferred) ==
+                                      ENDPOINT_RWSTREAM_IncompleteTransfer)
+                               {
+                                       if (IsTMCBulkINReset)
+                                         break;
+                               }
+                               LastTransferLength = BytesTransferred;
+
+                               Endpoint_ClearIN();
+                               break;
+                       default:
+                               Endpoint_StallTransaction();
+                               break;
+               }
+
+               LEDs_SetAllLEDs(LEDMASK_USB_READY);
+       }
+       
+       /* All pending data has been processed - reset the data abort flags */
+       IsTMCBulkINReset  = false;
+       IsTMCBulkOUTReset = false;
+}
+
+/** Attempts to read in the TMC message header from the TMC interface.
+ *
+ *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored
+ *
+ *  \return Boolean true if a header was read, false otherwise
+ */
+bool ReadTMCHeader(TMC_MessageHeader_t* const MessageHeader)
+{
+       uint16_t BytesTransferred;
+
+       /* Select the Data Out endpoint */
+       Endpoint_SelectEndpoint(TMC_OUT_EPNUM);
+       
+       /* Abort if no command has been sent from the host */
+       if (!(Endpoint_IsOUTReceived()))
+         return false;
+       
+       /* Read in the header of the command from the host */
+       BytesTransferred = 0;
+       while (Endpoint_Read_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==
+              ENDPOINT_RWSTREAM_IncompleteTransfer)
+       {
+               if (IsTMCBulkOUTReset)
+                 break;
+       }
+
+       /* Store the new command tag value for later use */
+       CurrentTransferTag = MessageHeader->Tag;
+       
+       /* Indicate if the command has been aborted or not */
+       return !(IsTMCBulkOUTReset);
+}
+
+bool WriteTMCHeader(TMC_MessageHeader_t* const MessageHeader)
+{
+       uint16_t BytesTransferred;
+
+       /* Set the message tag of the command header */
+       MessageHeader->Tag        =  CurrentTransferTag;
+       MessageHeader->InverseTag = ~CurrentTransferTag;
+
+       /* Select the Data In endpoint */
+       Endpoint_SelectEndpoint(TMC_IN_EPNUM);
+
+       /* Send the command header to the host */
+       BytesTransferred = 0;
+       while (Endpoint_Write_Stream_LE(MessageHeader, sizeof(TMC_MessageHeader_t), &BytesTransferred) ==
+              ENDPOINT_RWSTREAM_IncompleteTransfer)
+       {
+               if (IsTMCBulkINReset)
+                 break;
+       }
+
+       /* Indicate if the command has been aborted or not */
+       return !(IsTMCBulkINReset);
+}