3      Copyright (C) Dean Camera, 2010. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2010  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 uint8_t RequestInProgress 
= 0; 
  58 /** Stream callback abort flag for bulk IN data */ 
  59 bool IsTMCBulkINReset 
= false; 
  61 /** Stream callback abort flag for bulk OUT data */ 
  62 bool IsTMCBulkOUTReset 
= false; 
  64 /** Last used tag value for data transfers */ 
  65 uint8_t CurrentTransferTag 
= 0; 
  68 /** Main program entry point. This routine contains the overall program flow, including initial 
  69  *  setup of all components and the main program loop. 
  75         LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
); 
  85 /** Configures the board hardware and chip peripherals for the demo's functionality. */ 
  86 void SetupHardware(void) 
  88         /* Disable watchdog if enabled by bootloader/fuses */ 
  89         MCUSR 
&= ~(1 << WDRF
); 
  92         /* Disable clock division */ 
  93         clock_prescale_set(clock_div_1
); 
  95         /* Hardware Initialization */ 
 100 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and 
 101  *  starts the library USB task to begin the enumeration and USB management process. 
 103 void EVENT_USB_Device_Connect(void) 
 105         LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING
); 
 108 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via 
 109  *  the status LEDs and stops the USB management and CDC management tasks. 
 111 void EVENT_USB_Device_Disconnect(void) 
 113         LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY
); 
 116 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host set the current configuration 
 117  *  of the USB device after enumeration - the device endpoints are configured and the CDC management task started. 
 119 void EVENT_USB_Device_ConfigurationChanged(void) 
 121         bool ConfigSuccess 
= true; 
 123         /* Setup TMC In, Out and Notification Endpoints */ 
 124         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_NOTIFICATION_EPNUM
, EP_TYPE_INTERRUPT
, ENDPOINT_DIR_IN
, 
 125                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 126         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_IN_EPNUM
,  EP_TYPE_BULK
, ENDPOINT_DIR_IN
, 
 127                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 128         ConfigSuccess 
&= Endpoint_ConfigureEndpoint(TMC_OUT_EPNUM
, EP_TYPE_BULK
, ENDPOINT_DIR_OUT
, 
 129                                                     TMC_IO_EPSIZE
, ENDPOINT_BANK_SINGLE
); 
 131         /* Indicate endpoint configuration success or failure */ 
 132         LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY 
: LEDMASK_USB_ERROR
); 
 135 /** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific 
 136  *  control requests that are not handled internally by the USB library (including the CDC control commands, 
 137  *  which are all issued via the control endpoint), so that they can be handled appropriately for the application. 
 139 void EVENT_USB_Device_UnhandledControlRequest(void) 
 141         uint8_t TMCRequestStatus 
= TMC_STATUS_SUCCESS
; 
 143         /* Process TMC specific control requests */ 
 144         switch (USB_ControlRequest
.bRequest
) 
 146                 case Req_InitiateAbortBulkOut
: 
 147                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 149                                 /* Check that no split transaction is already in progress and the data transfer tag is valid */ 
 150                                 if (RequestInProgress 
!= 0) 
 152                                         TMCRequestStatus 
= TMC_STATUS_SPLIT_IN_PROGRESS
; 
 154                                 else if (USB_ControlRequest
.wValue 
!= CurrentTransferTag
) 
 156                                         TMCRequestStatus 
= TMC_STATUS_TRANSFER_NOT_IN_PROGRESS
; 
 160                                         /* Indicate that all in-progress/pending data OUT requests should be aborted */ 
 161                                         IsTMCBulkOUTReset 
= true; 
 163                                         /* Save the split request for later checking when a new request is received */ 
 164                                         RequestInProgress 
= Req_InitiateAbortBulkOut
; 
 167                                 Endpoint_ClearSETUP(); 
 169                                 /* Write the request response byte */ 
 170                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 173                                 Endpoint_ClearStatusStage(); 
 177                 case Req_CheckAbortBulkOutStatus
: 
 178                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 180                                 /* Check that an ABORT BULK OUT transaction has been requested and that the request has completed */ 
 181                                 if (RequestInProgress 
!= Req_InitiateAbortBulkOut
) 
 182                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
;                           
 183                                 else if (IsTMCBulkOUTReset
) 
 184                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 186                                   RequestInProgress 
= 0;         
 188                                 Endpoint_ClearSETUP(); 
 190                                 /* Write the request response bytes */ 
 191                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 192                                 Endpoint_Write_Word_LE(0); 
 193                                 Endpoint_Write_DWord_LE(0); // TODO - Last transfer length 
 196                                 Endpoint_ClearStatusStage();                             
 200                 case Req_InitiateAbortBulkIn
: 
 201                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 203                                 /* Check that no split transaction is already in progress and the data transfer tag is valid */ 
 204                                 if (RequestInProgress 
!= 0) 
 206                                         TMCRequestStatus 
= TMC_STATUS_SPLIT_IN_PROGRESS
;                                 
 208                                 else if (USB_ControlRequest
.wValue 
!= CurrentTransferTag
) 
 210                                         TMCRequestStatus 
= TMC_STATUS_TRANSFER_NOT_IN_PROGRESS
; 
 214                                         /* Indicate that all in-progress/pending data IN requests should be aborted */ 
 215                                         IsTMCBulkINReset 
= true; 
 217                                         /* Save the split request for later checking when a new request is received */ 
 218                                         RequestInProgress 
= Req_InitiateAbortBulkIn
; 
 221                                 Endpoint_ClearSETUP(); 
 223                                 /* Write the request response bytes */ 
 224                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 225                                 Endpoint_Write_Byte(CurrentTransferTag
); 
 228                                 Endpoint_ClearStatusStage(); 
 232                 case Req_CheckAbortBulkInStatus
: 
 233                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_ENDPOINT
)) 
 235                                 /* Check that an ABORT BULK IN transaction has been requested and that the request has completed */ 
 236                                 if (RequestInProgress 
!= Req_InitiateAbortBulkIn
) 
 237                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
; 
 238                                 else if (IsTMCBulkINReset
) 
 239                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 241                                   RequestInProgress 
= 0; 
 243                                 Endpoint_ClearSETUP(); 
 245                                 /* Write the request response bytes */ 
 246                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 247                                 Endpoint_Write_Word_LE(0); 
 248                                 Endpoint_Write_DWord_LE(0); // TODO - Last transfer length 
 251                                 Endpoint_ClearStatusStage(); 
 255                 case Req_InitiateClear
: 
 256                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 258                                 /* Check that no split transaction is already in progress */ 
 259                                 if (RequestInProgress 
!= 0) 
 261                                         Endpoint_Write_Byte(TMC_STATUS_SPLIT_IN_PROGRESS
);                               
 265                                         /* Indicate that all in-progress/pending data IN and OUT requests should be aborted */ 
 266                                         IsTMCBulkINReset  
= true; 
 267                                         IsTMCBulkOUTReset 
= true; 
 269                                         /* Save the split request for later checking when a new request is received */ 
 270                                         RequestInProgress 
= Req_InitiateClear
; 
 273                                 Endpoint_ClearSETUP(); 
 275                                 /* Write the request response byte */ 
 276                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 279                                 Endpoint_ClearStatusStage(); 
 283                 case Req_CheckClearStatus
: 
 284                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 286                                 /* Check that a CLEAR transaction has been requested and that the request has completed */ 
 287                                 if (RequestInProgress 
!= Req_InitiateClear
) 
 288                                   TMCRequestStatus 
= TMC_STATUS_SPLIT_NOT_IN_PROGRESS
;                           
 289                                 else if (IsTMCBulkINReset 
|| IsTMCBulkOUTReset
) 
 290                                   TMCRequestStatus 
= TMC_STATUS_PENDING
; 
 292                                   RequestInProgress 
= 0; 
 294                                 Endpoint_ClearSETUP(); 
 296                                 /* Write the request response bytes */ 
 297                                 Endpoint_Write_Byte(TMCRequestStatus
); 
 298                                 Endpoint_Write_Byte(0); 
 301                                 Endpoint_ClearStatusStage();                             
 305                 case Req_GetCapabilities
: 
 306                         if (USB_ControlRequest
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
)) 
 308                                 Endpoint_ClearSETUP(); 
 310                                 /* Write the device capabilities to the control endpoint */ 
 311                                 Endpoint_Write_Control_Stream_LE(&Capabilities
, sizeof(TMC_Capabilities_t
));                             
 319 /** Function to manage TMC data transmission and reception to and from the host. */ 
 322         /* Device must be connected and configured for the task to run */ 
 323         if (USB_DeviceState 
!= DEVICE_STATE_Configured
) 
 326         TMC_MessageHeader_t MessageHeader
; 
 328         /* Try to read in a TMC message from the interface, process if one is available */ 
 329         if (ReadTMCHeader(&MessageHeader
)) 
 332                 LEDs_SetAllLEDs(LEDMASK_USB_BUSY
); 
 334                 switch (MessageHeader
.MessageID
) 
 336                         case TMC_MESSAGEID_DEV_DEP_MSG_OUT
: 
 337                                 Endpoint_Discard_Stream(MessageHeader
.TransferSize
, StreamCallback_AbortOUTOnRequest
); 
 340                         case TMC_MESSAGEID_DEV_DEP_MSG_IN
: 
 343                                 MessageHeader
.TransferSize 
= 3; 
 344                                 WriteTMCHeader(&MessageHeader
); 
 346                                 Endpoint_Write_Stream_LE("TMC", 3, StreamCallback_AbortINOnRequest
); 
 350                                 Endpoint_StallTransaction(); 
 354                 LEDs_SetAllLEDs(LEDMASK_USB_READY
); 
 357         /* All pending data has been processed - reset the data abort flags */ 
 358         IsTMCBulkINReset  
= false; 
 359         IsTMCBulkOUTReset 
= false; 
 362 /** Attempts to read in the TMC message header from the TMC interface. 
 364  *  \param[out] MessageHeader  Pointer to a location where the read header (if any) should be stored 
 366  *  \return Boolean true if a header was read, false otherwise 
 368 bool ReadTMCHeader(TMC_MessageHeader_t
* const MessageHeader
) 
 370         /* Select the Data Out endpoint */ 
 371         Endpoint_SelectEndpoint(TMC_OUT_EPNUM
); 
 373         /* Abort if no command has been sent from the host */ 
 374         if (!(Endpoint_IsOUTReceived())) 
 377         /* Read in the header of the command from the host */ 
 378         Endpoint_Read_Stream_LE(MessageHeader
, sizeof(TMC_MessageHeader_t
), StreamCallback_AbortOUTOnRequest
); 
 380         /* Store the new command tag value for later use */ 
 381         CurrentTransferTag 
= MessageHeader
->Tag
; 
 383         /* Indicate if the command has been aborted or not */ 
 384         return !(IsTMCBulkOUTReset
); 
 387 bool WriteTMCHeader(TMC_MessageHeader_t
* const MessageHeader
) 
 389         /* Compute the next transfer tag value, must be between 1 and 254 */ 
 390         if (++CurrentTransferTag 
== 0xFF) 
 391           CurrentTransferTag 
= 1; 
 393         /* Set the message tag of the command header */ 
 394         MessageHeader
->Tag        
=  CurrentTransferTag
; 
 395         MessageHeader
->InverseTag 
= ~CurrentTransferTag
; 
 397         /* Select the Data In endpoint */ 
 398         Endpoint_SelectEndpoint(TMC_IN_EPNUM
); 
 400         /* Send the command header to the host */ 
 401         Endpoint_Write_Stream_LE(MessageHeader
, sizeof(TMC_MessageHeader_t
), StreamCallback_AbortINOnRequest
); 
 403         /* Indicate if the command has been aborted or not */ 
 404         return !(IsTMCBulkINReset
); 
 407 /** Stream callback function for the Endpoint stream write functions. This callback will abort the current stream transfer 
 408  *  if a TMC Abort Bulk IN request has been issued to the control endpoint. 
 410 uint8_t StreamCallback_AbortINOnRequest(void) 
 412         /* Abort if a TMC Bulk Data IN abort was received */ 
 413         if (IsTMCBulkINReset
) 
 414           return STREAMCALLBACK_Abort
; 
 416         /* Continue with the current stream operation */ 
 417         return STREAMCALLBACK_Continue
; 
 420 /** Stream callback function for the Endpoint stream read functions. This callback will abort the current stream transfer 
 421  *  if a TMC Abort Bulk OUT request has been issued to the control endpoint. 
 423 uint8_t StreamCallback_AbortOUTOnRequest(void) 
 425         /* Abort if a TMC Bulk Data IN abort was received */ 
 426         if (IsTMCBulkOUTReset
) 
 427           return STREAMCALLBACK_Abort
; 
 429         /* Continue with the current stream operation */ 
 430         return STREAMCALLBACK_Continue
;