3      Copyright (C) Dean Camera, 2012. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, distribute, and sell this 
  13   software and its documentation for any purpose is hereby granted 
  14   without fee, provided that the above copyright notice appear in 
  15   all copies and that both that the copyright notice and this 
  16   permission notice and warranty disclaimer appear in supporting 
  17   documentation, and that the name of the author not be used in 
  18   advertising or publicity pertaining to distribution of the 
  19   software without specific, written prior permission. 
  21   The author disclaim all warranties with regard to this 
  22   software, including all implied warranties of merchantability 
  23   and fitness.  In no event shall the author be liable for any 
  24   special, indirect or consequential damages or any damages 
  25   whatsoever resulting from loss of use, data or profits, whether 
  26   in an action of contract, negligence or other tortious action, 
  27   arising out of or in connection with the use or performance of 
  31 #include "TestAndMeasurement.h" 
  33 /** Contains the (usually static) capabilities of the TMC device. This table is requested by the 
  34  *  host upon enumeration to give it information on what features of the Test and Measurement USB 
  35  *  Class the device supports. 
  37 TMC_Capabilities_t Capabilities 
= 
  39                 .Status     
= TMC_STATUS_SUCCESS
, 
  40                 .TMCVersion 
= VERSION_BCD(1.00), 
  46                                 .PulseIndicateSupported 
= false, 
  51                                 .SupportsAbortINOnMatch 
= false, 
  55 /** Current TMC control request that is being processed */ 
  56 static uint8_t RequestInProgress 
= 0; 
  58 /** Stream callback abort flag for bulk IN data */ 
  59 static bool IsTMCBulkINReset 
= false; 
  61 /** Stream callback abort flag for bulk OUT data */ 
  62 static bool IsTMCBulkOUTReset 
= false; 
  64 /** Last used tag value for data transfers */ 
  65 static uint8_t CurrentTransferTag 
= 0; 
  67 /** Length of last data transfer, for reporting to the host in case an in-progress transfer is aborted */ 
  68 static uint16_t LastTransferLength 
= 0; 
  70 /** Buffer to hold the next message to sent to the TMC host */ 
  71 static uint8_t NextResponseBuffer
[64]; 
  73 /** Indicates the length of the next response to send */ 
  74 static uint8_t NextReponseLen
; 
  76 /** Main program entry point. This routine contains the overall program flow, including initial 
  77  *  setup of all components and the main program loop. 
  83         LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
); 
  93 /** Configures the board hardware and chip peripherals for the demo's functionality. */ 
  94 void SetupHardware(void) 
  96         /* Disable watchdog if enabled by bootloader/fuses */ 
  97         MCUSR 
&= ~(1 << WDRF
); 
 100         /* Disable clock division */ 
 101         clock_prescale_set(clock_div_1
); 
 103         /* Hardware Initialization */ 
 108 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and 
 109  *  starts the library USB task to begin the enumeration and USB management process. 
 111 void EVENT_USB_Device_Connect(void) 
 113         LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING
); 
 116 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via 
 117  *  the status LEDs and stops the USB management and CDC management tasks. 
 119 void EVENT_USB_Device_Disconnect(void) 
 121         LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
); 
 124 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration 
 125  *  of the USB device after enumeration - the device endpoints are configured and the CDC management task started. 
 127 void EVENT_USB_Device_ConfigurationChanged(void) 
 129         bool ConfigSuccess 
= true; 
 131         /* Setup TMC In, Out and Notification Endpoints */ 
 132         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_NOTIFICATION_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
, 
 133                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 134         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_IN_EPNUM
,  EP_TYPE_BULK
, ENDPOINT_DIR_IN
, 
 135                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 136         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_OUT_EPNUM
, EP_TYPE_BULK
, ENDPOINT_DIR_OUT
, 
 137                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 139         /* Indicate endpoint configuration success or failure */ 
 140         LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY 
: LEDMASK_USB_ERROR
); 
 143 /** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to 
 144  *  the device from the USB host before passing along unhandled control requests to the library for processing 
 147 void EVENT_USB_Device_ControlRequest(void) 
 149         uint8_t TMCRequestStatus 
= TMC_STATUS_SUCCESS
; 
 151         /* Process TMC specific control requests */ 
 152         switch (USB_ControlRequest
.bRequest
) 
 154                 case Req_InitiateAbortBulkOut
: 
 155                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 157                                 /* Check that no split transaction is already in progress and the data transfer tag is valid */ 
 158                                 if (RequestInProgress 
!= 0) 
 160                                         TMCRequestStatus 
= TMC_STATUS_SPLIT_IN_PROGRESS
; 
 162                                 else if (USB_ControlRequest
.wValue 
!= CurrentTransferTag
) 
 164                                         TMCRequestStatus 
= TMC_STATUS_TRANSFER_NOT_IN_PROGRESS
; 
 168                                         /* Indicate that all in-progress/pending data OUT requests should be aborted */ 
 169                                         IsTMCBulkOUTReset 
= true; 
 171                                         /* Save the split request for later checking when a new request is received */ 
 172                                         RequestInProgress 
= Req_InitiateAbortBulkOut
; 
 175                                 Endpoint_ClearSETUP(); 
 177                                 /* Write the request response byte */ 
 178                                 Endpoint_Write_8(TMCRequestStatus
); 
 181                                 Endpoint_ClearStatusStage(); 
 185                 case Req_CheckAbortBulkOutStatus
: 
 186                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 188                                 /* Check that an ABORT BULK OUT transaction has been requested and that the request has completed */ 
 189                                 if (RequestInProgress 
!= Req_InitiateAbortBulkOut
) 
 190                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
; 
 191                                 else if (IsTMCBulkOUTReset
) 
 192                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 194                                   RequestInProgress 
= 0; 
 196                                 Endpoint_ClearSETUP(); 
 198                                 /* Write the request response bytes */ 
 199                                 Endpoint_Write_8(TMCRequestStatus
); 
 200                                 Endpoint_Write_16_LE(0); 
 201                                 Endpoint_Write_32_LE(LastTransferLength
); 
 204                                 Endpoint_ClearStatusStage(); 
 208                 case Req_InitiateAbortBulkIn
: 
 209                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 211                                 /* Check that no split transaction is already in progress and the data transfer tag is valid */ 
 212                                 if (RequestInProgress 
!= 0) 
 214                                         TMCRequestStatus 
= TMC_STATUS_SPLIT_IN_PROGRESS
; 
 216                                 else if (USB_ControlRequest
.wValue 
!= CurrentTransferTag
) 
 218                                         TMCRequestStatus 
= TMC_STATUS_TRANSFER_NOT_IN_PROGRESS
; 
 222                                         /* Indicate that all in-progress/pending data IN requests should be aborted */ 
 223                                         IsTMCBulkINReset 
= true; 
 225                                         /* Save the split request for later checking when a new request is received */ 
 226                                         RequestInProgress 
= Req_InitiateAbortBulkIn
; 
 229                                 Endpoint_ClearSETUP(); 
 231                                 /* Write the request response bytes */ 
 232                                 Endpoint_Write_8(TMCRequestStatus
); 
 233                                 Endpoint_Write_8(CurrentTransferTag
); 
 236                                 Endpoint_ClearStatusStage(); 
 240                 case Req_CheckAbortBulkInStatus
: 
 241                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 243                                 /* Check that an ABORT BULK IN transaction has been requested and that the request has completed */ 
 244                                 if (RequestInProgress 
!= Req_InitiateAbortBulkIn
) 
 245                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
; 
 246                                 else if (IsTMCBulkINReset
) 
 247                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 249                                   RequestInProgress 
= 0; 
 251                                 Endpoint_ClearSETUP(); 
 253                                 /* Write the request response bytes */ 
 254                                 Endpoint_Write_8(TMCRequestStatus
); 
 255                                 Endpoint_Write_16_LE(0); 
 256                                 Endpoint_Write_32_LE(LastTransferLength
); 
 259                                 Endpoint_ClearStatusStage(); 
 263                 case Req_InitiateClear
: 
 264                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 266                                 /* Check that no split transaction is already in progress */ 
 267                                 if (RequestInProgress 
!= 0) 
 269                                         Endpoint_Write_8(TMC_STATUS_SPLIT_IN_PROGRESS
); 
 273                                         /* Indicate that all in-progress/pending data IN and OUT requests should be aborted */ 
 274                                         IsTMCBulkINReset  
= true; 
 275                                         IsTMCBulkOUTReset 
= true; 
 277                                         /* Save the split request for later checking when a new request is received */ 
 278                                         RequestInProgress 
= Req_InitiateClear
; 
 281                                 Endpoint_ClearSETUP(); 
 283                                 /* Write the request response byte */ 
 284                                 Endpoint_Write_8(TMCRequestStatus
); 
 287                                 Endpoint_ClearStatusStage(); 
 291                 case Req_CheckClearStatus
: 
 292                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 294                                 /* Check that a CLEAR transaction has been requested and that the request has completed */ 
 295                                 if (RequestInProgress 
!= Req_InitiateClear
) 
 296                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
; 
 297                                 else if (IsTMCBulkINReset 
|| IsTMCBulkOUTReset
) 
 298                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 300                                   RequestInProgress 
= 0; 
 302                                 Endpoint_ClearSETUP(); 
 304                                 /* Write the request response bytes */ 
 305                                 Endpoint_Write_8(TMCRequestStatus
); 
 309                                 Endpoint_ClearStatusStage(); 
 313                 case Req_GetCapabilities
: 
 314                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 316                                 Endpoint_ClearSETUP(); 
 318                                 /* Write the device capabilities to the control endpoint */ 
 319                                 Endpoint_Write_Control_Stream_LE(&Capabilities
, sizeof(TMC_Capabilities_t
)); 
 327 void ProcessSentMessage(uint8_t* const Data
, const uint8_t Length
) 
 329         if (strncmp((char*)Data
, "*IDN?", 5) == 0) 
 330           strcpy((char*)NextResponseBuffer
, "LUFA TMC DEMO"); 
 332         NextReponseLen 
= strlen((char*)NextResponseBuffer
); 
 335 uint8_t GetNextMessage(uint8_t* const Data
) 
 337           strcpy((char*)NextResponseBuffer
, "LUFA TMC DEMO"); 
 339         NextReponseLen 
= strlen((char*)NextResponseBuffer
); 
 341         uint8_t DataLen 
= MIN(NextReponseLen
, 64); 
 343         strlcpy((char*)Data
, (char*)NextResponseBuffer
, DataLen
); 
 348 /** Function to manage TMC data transmission and reception to and from the host. */ 
 351         /* Device must be connected and configured for the task to run */ 
 352         if (USB_DeviceState 
!= DEVICE_STATE_Configured
) 
 355         TMC_MessageHeader_t MessageHeader
; 
 356         uint8_t             MessagePayload
[128]; 
 358         /* Try to read in a TMC message from the interface, process if one is available */ 
 359         if (ReadTMCHeader(&MessageHeader
)) 
 362                 LEDs_SetAllLEDs(LEDMASK_USB_BUSY
); 
 364                 switch (MessageHeader
.MessageID
) 
 366                         case TMC_MESSAGEID_DEV_DEP_MSG_OUT
: 
 367                                 LastTransferLength 
= 0; 
 368                                 while (Endpoint_Read_Stream_LE(MessagePayload
, MIN(MessageHeader
.TransferSize
, sizeof(MessagePayload
)), &LastTransferLength
) == 
 369                                        ENDPOINT_RWSTREAM_IncompleteTransfer
) 
 371                                         if (IsTMCBulkOUTReset
) 
 377                                 ProcessSentMessage(MessagePayload
, LastTransferLength
); 
 379                         case TMC_MESSAGEID_DEV_DEP_MSG_IN
: 
 382                                 MessageHeader
.TransferSize 
= GetNextMessage(MessagePayload
); 
 383                                 MessageHeader
.MessageIDSpecific
.DeviceOUT
.LastMessageTransaction 
= true; 
 384                                 WriteTMCHeader(&MessageHeader
); 
 386                                 LastTransferLength 
= 0; 
 387                                 while (Endpoint_Write_Stream_LE(MessagePayload
, MessageHeader
.TransferSize
, &LastTransferLength
) == 
 388                                        ENDPOINT_RWSTREAM_IncompleteTransfer
) 
 390                                         if (IsTMCBulkINReset
) 
 397                                 Endpoint_StallTransaction(); 
 401                 LEDs_SetAllLEDs(LEDMASK_USB_READY
); 
 404         /* All pending data has been processed - reset the data abort flags */ 
 405         IsTMCBulkINReset  
= false; 
 406         IsTMCBulkOUTReset 
= false; 
 409 /** Attempts to read in the TMC message header from the TMC interface. 
 411  *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored 
 413  *  \return Boolean true if a header was read, false otherwise 
 415 bool ReadTMCHeader(TMC_MessageHeader_t
* const MessageHeader
) 
 417         uint16_t BytesTransferred
; 
 420         /* Select the Data Out endpoint */ 
 421         Endpoint_SelectEndpoint(TMC_OUT_EPNUM
); 
 423         /* Abort if no command has been sent from the host */ 
 424         if (!(Endpoint_IsOUTReceived())) 
 427         /* Read in the header of the command from the host */ 
 428         BytesTransferred 
= 0; 
 429         while ((ErrorCode 
= Endpoint_Read_Stream_LE(MessageHeader
, sizeof(TMC_MessageHeader_t
), &BytesTransferred
)) == 
 430                ENDPOINT_RWSTREAM_IncompleteTransfer
) 
 432                 if (IsTMCBulkOUTReset
) 
 436         /* Store the new command tag value for later use */ 
 437         CurrentTransferTag 
= MessageHeader
->Tag
; 
 439         /* Indicate if the command has been aborted or not */ 
 440         return (!(IsTMCBulkOUTReset
) && (ErrorCode 
== ENDPOINT_RWSTREAM_NoError
)); 
 443 bool WriteTMCHeader(TMC_MessageHeader_t
* const MessageHeader
) 
 445         uint16_t BytesTransferred
; 
 448         /* Set the message tag of the command header */ 
 449         MessageHeader
->Tag        
=  CurrentTransferTag
; 
 450         MessageHeader
->InverseTag 
= ~CurrentTransferTag
; 
 452         /* Select the Data In endpoint */ 
 453         Endpoint_SelectEndpoint(TMC_IN_EPNUM
); 
 455         /* Send the command header to the host */ 
 456         BytesTransferred 
= 0; 
 457         while ((ErrorCode 
= Endpoint_Write_Stream_LE(MessageHeader
, sizeof(TMC_MessageHeader_t
), &BytesTransferred
)) == 
 458                ENDPOINT_RWSTREAM_IncompleteTransfer
) 
 460                 if (IsTMCBulkINReset
) 
 464         /* Indicate if the command has been aborted or not */ 
 465         return (!(IsTMCBulkINReset
) && (ErrorCode 
== ENDPOINT_RWSTREAM_NoError
));