SAMV71 Xplained Ultra Software Package 1.4

CDCDSerialPort.c

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