SAMV71 Xplained Ultra Software Package 1.5

CDCDSerialPort.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /**\file
00031  *  Implementation of the CDCDSerialPort class methods.
00032  */
00033 
00034 /** \addtogroup usbd_cdc
00035  *@{
00036  */
00037 
00038 /*------------------------------------------------------------------------------
00039  *         Headers
00040  *------------------------------------------------------------------------------*/
00041 
00042 #include <CDCDSerialPort.h>
00043 #include <CDCDescriptors.h>
00044 #include <USBLib_Trace.h>
00045 #include <chip.h>
00046 /*------------------------------------------------------------------------------
00047  *         Types
00048  *------------------------------------------------------------------------------*/
00049 
00050 /** Parse data extention for descriptor parsing  */
00051 typedef struct _CDCDParseData {
00052     /** Pointer to CDCDSerialPort instance */
00053     CDCDSerialPort *pCdcd;
00054     /** Pointer to found interface descriptor */
00055     USBInterfaceDescriptor *pIfDesc;
00056 
00057 } CDCDParseData;
00058 
00059 /*------------------------------------------------------------------------------
00060  *         Internal variables
00061  *------------------------------------------------------------------------------*/
00062 
00063 /** Line coding values */
00064 static CDCLineCoding lineCoding;
00065 /*------------------------------------------------------------------------------
00066  *         Internal functions
00067  *------------------------------------------------------------------------------*/
00068 
00069 /**
00070  * Parse descriptors: Interface, Bulk IN/OUT, Interrupt IN.
00071  * \param desc Pointer to descriptor list.
00072  * \param arg  Argument, pointer to AUDDParseData instance.
00073  */
00074 static uint32_t _Interfaces_Parse(USBGenericDescriptor *pDesc,
00075                                   CDCDParseData *pArg)
00076 {
00077     CDCDSerialPort *pCdcd = pArg->pCdcd;
00078 
00079     /* Not a valid descriptor */
00080     if (pDesc->bLength == 0)
00081         return USBRC_PARAM_ERR;
00082 
00083     /* Find interface descriptor */
00084     if (pDesc->bDescriptorType == USBGenericDescriptor_INTERFACE) {
00085         USBInterfaceDescriptor *pIf = (USBInterfaceDescriptor *)pDesc;
00086 
00087         /* Obtain interface from descriptor */
00088         if (pCdcd->bInterfaceNdx == 0xFF) {
00089             /* First interface is communication */
00090             if (pIf->bInterfaceClass ==
00091                 CDCCommunicationInterfaceDescriptor_CLASS) {
00092                 pCdcd->bInterfaceNdx = pIf->bInterfaceNumber;
00093                 pCdcd->bNumInterface = 2;
00094             }
00095             /* Only data interface */
00096             else if (pIf->bInterfaceClass == CDCDataInterfaceDescriptor_CLASS) {
00097                 pCdcd->bInterfaceNdx = pIf->bInterfaceNumber;
00098                 pCdcd->bNumInterface = 1;
00099             }
00100 
00101             pArg->pIfDesc = pIf;
00102         } else if (pCdcd->bInterfaceNdx <= pIf->bInterfaceNumber
00103                 && pCdcd->bInterfaceNdx + pCdcd->bNumInterface
00104                     > pIf->bInterfaceNumber)
00105             pArg->pIfDesc = pIf;
00106     }
00107 
00108     /* Parse valid interfaces */
00109     if (pArg->pIfDesc == 0)
00110         return 0;
00111 
00112     /* Find endpoint descriptors */
00113     if (pDesc->bDescriptorType == USBGenericDescriptor_ENDPOINT) {
00114         USBEndpointDescriptor *pEp = (USBEndpointDescriptor *)pDesc;
00115 
00116         switch (pEp->bmAttributes & 0x3) {
00117         case USBEndpointDescriptor_INTERRUPT:
00118             if (pEp->bEndpointAddress & 0x80)
00119                 pCdcd->bIntInPIPE = pEp->bEndpointAddress & 0x7F;
00120 
00121             break;
00122 
00123         case USBEndpointDescriptor_BULK:
00124             if (pEp->bEndpointAddress & 0x80)
00125                 pCdcd->bBulkInPIPE = pEp->bEndpointAddress & 0x7F;
00126             else
00127                 pCdcd->bBulkOutPIPE = pEp->bEndpointAddress;
00128         }
00129     }
00130 
00131     if (pCdcd->bInterfaceNdx != 0xFF
00132             && pCdcd->bBulkInPIPE != 0
00133             && pCdcd->bBulkOutPIPE != 0)
00134         return USBRC_FINISHED;
00135 
00136     return 0;
00137 }
00138 
00139 /**
00140  * Callback function which should be invoked after the data of a
00141  * SetLineCoding request has been retrieved. Sends a zero-length packet
00142  * to the host for acknowledging the request.
00143  * \param pCdcd Pointer to CDCDSerialPort instance.
00144  */
00145 static void _SetLineCodingCallback(CDCDSerialPort *pCdcd)
00146 {
00147     uint32_t exec = 1;
00148 
00149     if (pCdcd->fEventHandler) {
00150         uint32_t rc = pCdcd->fEventHandler(
00151                           CDCDSerialPortEvent_SETLINECODING,
00152                           (uint32_t)(&lineCoding),
00153                           pCdcd->pEventArg);
00154 
00155         if (rc == USBD_STATUS_SUCCESS) {
00156             pCdcd->lineCoding.dwDTERate   = lineCoding.dwDTERate;
00157             pCdcd->lineCoding.bCharFormat = lineCoding.bCharFormat;
00158             pCdcd->lineCoding.bParityType = lineCoding.bParityType;
00159             pCdcd->lineCoding.bDataBits   = lineCoding.bDataBits;
00160         } else
00161             exec = 0;
00162     }
00163 
00164     if (exec)
00165         USBD_Write(0, 0, 0, 0, 0);
00166     else
00167         USBD_Stall(0);
00168 }
00169 
00170 /**
00171  * Receives new line coding information from the USB host.
00172  * \param pCdcd Pointer to CDCDSerialPort instance.
00173  */
00174 static void _SetLineCoding(CDCDSerialPort *pCdcd)
00175 {
00176     TRACE_INFO_WP("sLineCoding ");
00177 
00178     USBD_Read(0,
00179               (void *) & (lineCoding),
00180               sizeof(CDCLineCoding),
00181               (TransferCallback)_SetLineCodingCallback,
00182               (void *)pCdcd);
00183 }
00184 
00185 /**
00186  * Sends the current line coding information to the host through Control
00187  * endpoint 0.
00188  * \param pCdcd Pointer to CDCDSerialPort instance.
00189  */
00190 static void _GetLineCoding(CDCDSerialPort *pCdcd)
00191 {
00192     TRACE_INFO_WP("gLineCoding ");
00193 
00194     USBD_Write(0,
00195             (void *)&(pCdcd->lineCoding),
00196             sizeof(CDCLineCoding),
00197             0,
00198             0);
00199 }
00200 
00201 /**
00202  * Changes the state of the serial driver according to the information
00203  * sent by the host via a SetControlLineState request, and acknowledges
00204  * the request with a zero-length packet.
00205  * \param pCdcd Pointer to CDCDSerialPort instance.
00206  * \param request Pointer to a USBGenericRequest instance.
00207  */
00208 static void _SetControlLineState(
00209     CDCDSerialPort *pCdcd,
00210     const USBGenericRequest *request)
00211 {
00212 #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
00213     uint8_t DTR, RTS;
00214 
00215     DTR = ((request->wValue & CDCControlLineState_DTR) > 0);
00216     RTS = ((request->wValue & CDCControlLineState_RTS) > 0);
00217     TRACE_INFO_WP("sControlLineState(%d, %d) ", DTR, RTS);
00218 #endif
00219 
00220     pCdcd->bControlLineState = (uint8_t)request->wValue;
00221     USBD_Write(0, 0, 0, 0, 0);
00222 
00223     if (pCdcd->fEventHandler)
00224         pCdcd->fEventHandler(CDCDSerialPortEvent_SETCONTROLLINESTATE,
00225                              (uint32_t)pCdcd->bControlLineState,
00226                              pCdcd->pEventArg);
00227 }
00228 
00229 /*------------------------------------------------------------------------------
00230  *         Exported functions
00231  *------------------------------------------------------------------------------*/
00232 
00233 /**
00234  * Initializes the USB Device CDC serial port function.
00235  * \param pCdcd Pointer to CDCDSerialPort instance.
00236  * \param pUsbd Pointer to USBDDriver instance.
00237  * \param fEventHandler Pointer to event handler function.
00238  * \param firstInterface First interface index for the function
00239  *                       (0xFF to parse from descriptors).
00240  * \param numInterface   Number of interfaces for the function.
00241  */
00242 void CDCDSerialPort_Initialize(CDCDSerialPort *pCdcd,
00243                 USBDDriver *pUsbd,
00244                 CDCDSerialPortEventHandler fEventHandler,
00245                 void *pArg,
00246                 uint8_t firstInterface, uint8_t numInterface)
00247 {
00248     TRACE_INFO("CDCDSerialPort_Initialize\n\r");
00249 
00250     /* Initialize event handler */
00251     pCdcd->fEventHandler = fEventHandler;
00252     pCdcd->pEventArg = pArg;
00253 
00254     /* Initialize transfer callback */
00255     pCdcd->fTransCLK = 0;
00256     pCdcd->pTansArg = 0;
00257 
00258     /* Initialize USB Device Driver interface */
00259     pCdcd->pUsbd = pUsbd;
00260     pCdcd->bInterfaceNdx = firstInterface;
00261     pCdcd->bNumInterface = numInterface;
00262     pCdcd->bIntInPIPE = 0;
00263     pCdcd->bBulkInPIPE  = 0;
00264     pCdcd->bBulkOutPIPE = 0;
00265 
00266     /* Initialize Abstract Control Model attributes */
00267     pCdcd->bControlLineState = 0;
00268     pCdcd->wSerialState = 0;
00269     CDCLineCoding_Initialize(&(pCdcd->lineCoding),
00270                              115200,
00271                              CDCLineCoding_ONESTOPBIT,
00272                              CDCLineCoding_NOPARITY,
00273                              8);
00274 }
00275 
00276 /**
00277  * Parse CDC Serial Port information for CDCDSerialPort instance.
00278  * Accepted interfaces:
00279  * - Communication Interface + Data Interface
00280  * - Data Interface ONLY
00281  * \param pCdcd        Pointer to CDCDSerialPort instance.
00282  * \param pDescriptors Pointer to descriptor list.
00283  * \param dwLength     Descriptor list size in bytes.
00284  */
00285 USBGenericDescriptor *CDCDSerialPort_ParseInterfaces(
00286     CDCDSerialPort *pCdcd,
00287     USBGenericDescriptor *pDescriptors,
00288     uint32_t dwLength)
00289 {
00290     CDCDParseData parseData;
00291 
00292     parseData.pCdcd   = pCdcd;
00293     parseData.pIfDesc = 0;
00294 
00295     return USBGenericDescriptor_Parse(
00296             pDescriptors, dwLength,
00297             (USBDescriptorParseFunction)_Interfaces_Parse,
00298             &parseData);
00299 }
00300 
00301 
00302 /**
00303  * Handles CDC-specific SETUP requests. Should be called from a
00304  * re-implementation of USBDCallbacks_RequestReceived() method.
00305  * \param pCdcd Pointer to CDCDSerialPort instance.
00306  * \param request Pointer to a USBGenericRequest instance.
00307  * \return USBRC_SUCCESS if request handled, otherwise error.
00308  */
00309 uint32_t CDCDSerialPort_RequestHandler(
00310     CDCDSerialPort *pCdcd,
00311     const USBGenericRequest *request)
00312 {
00313     if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS)
00314         return USBRC_PARAM_ERR;
00315 
00316     TRACE_INFO_WP("Cdcs ");
00317 
00318     /* Validate interface */
00319     if (request->wIndex >= pCdcd->bInterfaceNdx &&
00320         request->wIndex < pCdcd->bInterfaceNdx + pCdcd->bNumInterface) {
00321     } else
00322         return USBRC_PARAM_ERR;
00323 
00324     /* Handle the request */
00325     switch (USBGenericRequest_GetRequest(request)) {
00326 
00327     case CDCGenericRequest_SETLINECODING:
00328 
00329         _SetLineCoding(pCdcd);
00330         break;
00331 
00332     case CDCGenericRequest_GETLINECODING:
00333 
00334         _GetLineCoding(pCdcd);
00335         break;
00336 
00337     case CDCGenericRequest_SETCONTROLLINESTATE:
00338 
00339         _SetControlLineState(pCdcd, request);
00340         break;
00341 
00342     default:
00343 
00344         return USBRC_PARAM_ERR;
00345     }
00346 
00347     return USBRC_SUCCESS;
00348 }
00349 
00350 /**
00351  * Receives data from the host through the virtual COM port created by
00352  * the CDC device serial driver. This function behaves like USBD_Read.
00353  * \param pCdcd  Pointer to CDCDSerialPort instance.
00354  * \param pData  Pointer to the data buffer to put received data.
00355  * \param dwSize Size of the data buffer in bytes.
00356  * \param fCallback Optional callback function to invoke when the transfer
00357  *                  finishes.
00358  * \param pArg      Optional argument to the callback function.
00359  * \return USBD_STATUS_SUCCESS if the read operation has been started normally;
00360  *         otherwise, the corresponding error code.
00361  */
00362 uint32_t CDCDSerialPort_Read(const CDCDSerialPort *pCdcd,
00363                              void *pData, uint32_t dwSize,
00364                              TransferCallback fCallback, void *pArg)
00365 {
00366     if (pCdcd->bBulkOutPIPE == 0)
00367         return USBRC_PARAM_ERR;
00368 
00369     return USBD_Read(pCdcd->bBulkOutPIPE,
00370                      pData, dwSize,
00371                      fCallback, pArg);
00372 }
00373 
00374 
00375 /**
00376  * Callback function for USBD_Write to send a zero-length packet.
00377  *
00378  */
00379 static void _UsbDataSent_ZLP(CDCDSerialPort *pCdcd)
00380 {
00381     USBD_Write(pCdcd->bBulkInPIPE, 0, 0, pCdcd->fTransCLK, pCdcd->pTansArg);
00382 }
00383 
00384 /**
00385  * Sends a data buffer through the virtual COM port created by the CDC
00386  * device serial driver. This function behaves exactly like USBD_Write.
00387  * \param pCdcd  Pointer to CDCDSerialPort instance.
00388  * \param pData  Pointer to the data buffer to send.
00389  * \param dwSize Size of the data buffer in bytes.
00390  * \param fCallback Optional callback function to invoke when the transfer
00391  *                  finishes.
00392  * \param pArg      Optional argument to the callback function.
00393  * \return USBD_STATUS_SUCCESS if the read operation has been started normally;
00394  *         otherwise, the corresponding error code.
00395  * \note The user can ensure finishing transmission before next transmission
00396  * through a flag in fCallback in application layer.
00397  */
00398 uint32_t CDCDSerialPort_Write(CDCDSerialPort *pCdcd,
00399                               void *pData, uint32_t dwSize,
00400                               TransferCallback fCallback, void *pArg)
00401 {
00402     uint32_t result;
00403     Usbhs *pUdp = USBHS;
00404     uint32_t endpointSize;
00405 
00406     if (pCdcd->bBulkInPIPE == 0)
00407         return USBRC_PARAM_ERR;
00408 
00409     endpointSize = USBHS_GetEpSize(pUdp, pCdcd->bBulkInPIPE);
00410 
00411     if (dwSize % endpointSize == 0) {
00412         pCdcd->fTransCLK = fCallback;
00413         pCdcd->pTansArg  = pArg;
00414         result = USBD_Write(pCdcd->bBulkInPIPE,
00415                             pData, dwSize,
00416                             (TransferCallback)_UsbDataSent_ZLP, (void *)pCdcd);
00417     } else {
00418         result = USBD_Write(pCdcd->bBulkInPIPE,
00419                             pData, dwSize,
00420                             fCallback, pArg);
00421 
00422     }
00423 
00424     return result;
00425 }
00426 
00427 /**
00428  * Returns the current control line state of the RS-232 line.
00429  * \param pCdcd  Pointer to CDCDSerialPort instance.
00430  */
00431 uint8_t CDCDSerialPort_GetControlLineState(const CDCDSerialPort *pCdcd)
00432 {
00433     return pCdcd->bControlLineState;
00434 }
00435 
00436 /**
00437  * Copy current line coding settings to appointed space.
00438  * \param pCdcd  Pointer to CDCDSerialPort instance.
00439  * \param pLineCoding Pointer to CDCLineCoding instance.
00440  */
00441 void CDCDSerialPort_GetLineCoding(const CDCDSerialPort *pCdcd,
00442                                   CDCLineCoding *pLineCoding)
00443 {
00444     if (pLineCoding) {
00445         pLineCoding->dwDTERate   = pCdcd->lineCoding.dwDTERate;
00446         pLineCoding->bCharFormat = pCdcd->lineCoding.bCharFormat;
00447         pLineCoding->bParityType = pCdcd->lineCoding.bParityType;
00448         pLineCoding->bDataBits   = pCdcd->lineCoding.bDataBits;
00449     }
00450 }
00451 
00452 /**
00453  * Returns the current status of the RS-232 line.
00454  * \param pCdcd  Pointer to CDCDSerialPort instance.
00455  */
00456 uint16_t CDCDSerialPort_GetSerialState(const CDCDSerialPort *pCdcd)
00457 {
00458     return pCdcd->wSerialState;
00459 }
00460 
00461 /**
00462  * Sets the current serial state of the device to the given value.
00463  * \param pCdcd  Pointer to CDCDSerialPort instance.
00464  * \param wSerialState  New device state.
00465  */
00466 void CDCDSerialPort_SetSerialState(CDCDSerialPort *pCdcd,
00467                                    uint16_t wSerialState)
00468 {
00469     if (pCdcd->bIntInPIPE == 0)
00470         return;
00471 
00472     /* If new state is different from previous one, send a notification to the
00473        host */
00474     if (pCdcd->wSerialState != wSerialState) {
00475 
00476         pCdcd->wSerialState = wSerialState;
00477         USBD_Write(pCdcd->bIntInPIPE,
00478                 &(pCdcd->wSerialState),
00479                 2,
00480                 0,
00481                 0);
00482 
00483         /* Reset one-time flags */
00484         pCdcd->wSerialState &= ~(CDCSerialState_OVERRUN
00485                         | CDCSerialState_PARITY
00486                         | CDCSerialState_FRAMING
00487                         | CDCSerialState_RINGSIGNAL
00488                         | CDCSerialState_BREAK);
00489     }
00490 }
00491 
00492 /**@}*/
00493 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines