SAMV71 Xplained Ultra Software Package 1.3

uhi_cdc.c

Go to the documentation of this file.
00001 /**
00002  * \file
00003  *
00004  * \brief USB host Communication Device Class interface.
00005  *
00006  * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
00007  *
00008  * \asf_license_start
00009  *
00010  * \page License
00011  *
00012  * Redistribution and use in source and binary forms, with or without
00013  * modification, are permitted provided that the following conditions are met:
00014  *
00015  * 1. Redistributions of source code must retain the above copyright notice,
00016  *    this list of conditions and the following disclaimer.
00017  *
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  *
00022  * 3. The name of Atmel may not be used to endorse or promote products derived
00023  *    from this software without specific prior written permission.
00024  *
00025  * 4. This software may only be redistributed and used in connection with an
00026  *    Atmel microcontroller product.
00027  *
00028  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
00029  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00030  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00031  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
00032  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00033  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00034  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00035  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00036  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00037  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00038  * POSSIBILITY OF SUCH DAMAGE.
00039  *
00040  * \asf_license_stop
00041  *
00042  */
00043 /*
00044  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
00045  */
00046 
00047 #include "conf_usb_host.h"
00048 #include "USBHDriver.h"
00049 #include "USBDescriptors.h"
00050 #include "USBH.h"
00051 #include "CDCDescriptors.h"
00052 #include "uhi_cdc.h"
00053 #include <string.h>
00054 
00055 #ifdef USB_HOST_HUB_SUPPORT
00056 #  error USB HUB support is not implemented on UHI CDC
00057 #endif
00058 
00059 #ifndef UHI_CDC_RX_NOTIFY
00060 #  define UHI_CDC_RX_NOTIFY()
00061 #endif
00062 
00063 //! Define the minimum internal buffer size
00064 #ifdef UHI_CDC_LOW_RATE
00065 #  define UHI_CDC_BUFFER_SIZE  (1*64)
00066 #else
00067 #  define UHI_CDC_BUFFER_SIZE  (5*64)
00068 #endif
00069 
00070 /**
00071  * \ingroup uhi_cdc_group
00072  * \defgroup uhi_cdc_group_internal Implementation of UHI Communication Device Class
00073  *
00074  * Class internal implementation 
00075  * @{
00076  */
00077 
00078 /**
00079  * \name Internal defines and variables to manage CDC device
00080  */
00081 //@{
00082 
00083 //! Internal buffer information
00084 typedef struct {
00085     //! Position of consumer in this buffer
00086     uint16_t pos;
00087     //! Number of data available in buffer
00088     uint16_t nb;
00089     //! Pointer on internal buffer
00090     uint8_t* ptr;
00091 } uhi_cdc_buf_t;
00092 
00093 //! Communication line information
00094 typedef struct {
00095     //! Bulk endpoint number used to transfer data
00096     USBHS_Ep_t ep_data;
00097     //! True, if a transfer is on-going on endpoint
00098     bool b_trans_ongoing;
00099     //! Frame number of last transfer
00100     uint16_t sof;
00101     //! Current internal buffer used to store data
00102     volatile uint8_t buf_sel;
00103     //! Size of internal buffer (unit Byte)
00104     uint16_t buffer_size;
00105     //! Internal buffer information
00106     uhi_cdc_buf_t buffer[2];
00107 } uhi_cdc_line_t;
00108 
00109 //! Communication port information
00110 typedef struct {
00111     //! Current port configuration (baudrate,...)
00112     CDCLineCoding conf;
00113     //! USB CDC-COMM interface number
00114     uint8_t  iface_comm;
00115     //! USB CDC-DATA interface number
00116     uint8_t  iface_data;
00117     //! Interrupt IN endpoint from CDC-COMM interface
00118     USBHS_Ep_t ep_comm_in;
00119     //! RX line information
00120     uhi_cdc_line_t line_rx;
00121     //! TX line information
00122     uhi_cdc_line_t line_tx;
00123 } uhi_cdc_port_t;
00124 
00125 //! USB CDC device information
00126 typedef struct {
00127     //! Pointer on USB Device information
00128     USBH_device_t *dev;
00129     //! True, if a CDC Device has been enumerated
00130     bool b_enabled;
00131     //! Pointer on communication port(s) information
00132     uhi_cdc_port_t *port;
00133     //! Number of port available on this USB device
00134     uint8_t nb_port;
00135 } uhi_cdc_dev_t;
00136 
00137 //! Information about the enumerated USB CDC device
00138 static uhi_cdc_dev_t uhi_cdc_dev = {
00139     .dev = NULL,
00140     .nb_port = 0,
00141 };
00142 //@}
00143 
00144 /**
00145  * \name Internal routines
00146  */
00147 //@{
00148 
00149 /**
00150  * \brief Free all CDC device structures
00151  */
00152 static void uhi_cdc_free_device(void);
00153 
00154 /**
00155  * \brief Returns a port structure information
00156  *
00157  * \param port_num  Number of port
00158  *
00159  * \return pointer on port structure
00160  */
00161 static uhi_cdc_port_t* uhi_cdc_get_port(uint8_t port_num);
00162 
00163 /**
00164  * \brief Changes the port configuration
00165  *
00166  * \param port_num       Number of port
00167  * \param configuration  Pointer on new configuration
00168  *
00169  * \return True, if success
00170  */
00171 static bool uhi_cdc_set_conf(uint8_t port, CDCLineCoding *configuration);
00172 
00173 /**
00174  * \brief Sends a control line command on the port
00175  *
00176  * \param port_num       Number of port
00177  * \param wValue         USB CDC control line word
00178  *
00179  * \return True, if success
00180  */
00181 static bool uhi_cdc_set_ctrl_line(uint8_t port, uint16_t wValue);
00182 
00183 /**
00184  * \brief Update the transfer endpoint IN (RX)
00185  * Valid the reception of the previous transfer.
00186  * Start a new transfer on endpoint IN, if a RX buffer is free
00187  * and a new USB frame is occurred since last transfer.
00188  *
00189  * \param line        RX communication line to manage
00190  *
00191  * \return True, if a new transfer has been started
00192  */
00193 static bool uhi_cdc_rx_update(uhi_cdc_line_t *line);
00194 
00195 /**
00196  * \brief Manage the end of RX transfer.
00197  * Registered by USBH_HAL_RunEndpoint()
00198  * Callback called by USB interrupt after data transfer or abort (reset,...).
00199  *
00200  * \param add            USB address used by the transfer
00201  * \param status         Transfer status
00202  * \param nb_transferred Number of data transfered
00203  */
00204 static void uhi_cdc_rx_received(USBHS_Add_t add, USBHS_Ep_t ep,
00205         USBH_XfrStatus_t status, uint32_t nb_transferred);
00206 
00207 /**
00208  * \brief Update the transfer endpoint OUT (TX)
00209  * Start a new transfer on endpoint OUT, if a data must be send
00210  * and a new USB frame is occurred since last transfer.
00211  *
00212  * \param line        TX communication line to manage
00213  *
00214  * \return True, if a new transfer has been started
00215  */
00216 static bool uhi_cdc_tx_update(uhi_cdc_line_t *line);
00217 
00218 /**
00219  * \brief Manage the end of TX transfer.
00220  * Registered by USBH_HAL_RunEndpoint()
00221  * Callback called by USB interrupt after data transfer or abort (reset,...).
00222  *
00223  * \param add            USB address used by the transfer
00224  * \param status         Transfer status
00225  * \param nb_transferred Number of data transfered
00226  */
00227 static void uhi_cdc_tx_send(USBHS_Add_t add, USBHS_Ep_t ep,
00228         USBH_XfrStatus_t status, uint32_t nb_transferred);
00229 //@}
00230 
00231 //@}
00232 
00233 
00234 /**
00235  * \name Interface used by UHC module
00236  */
00237 //@{
00238 
00239 USBH_enum_status_t uhi_cdc_install(USBH_device_t* dev)
00240 {
00241     bool b_iface_comm, b_iface_data;
00242     uint16_t conf_desc_lgt;
00243     uint8_t port_num, i;
00244     USBInterfaceDescriptor *ptr_iface;
00245     uhi_cdc_port_t *ptr_port = NULL;
00246     uhi_cdc_line_t *ptr_line;
00247 
00248     if (uhi_cdc_dev.dev != NULL) {
00249         return UHC_ENUM_SOFTWARE_LIMIT; // Device already allocated
00250     }
00251 
00252     // Compute the number of port
00253     conf_desc_lgt = (dev->conf_desc->wTotalLength);
00254     ptr_iface = (USBInterfaceDescriptor*)dev->conf_desc;
00255     uhi_cdc_dev.nb_port = 0;
00256     while (conf_desc_lgt) {
00257         if ((ptr_iface->bDescriptorType == USBGenericDescriptor_INTERFACE)
00258                 && (ptr_iface->bInterfaceClass == CDCCommunicationInterfaceDescriptor_CLASS)
00259                 && (ptr_iface->bInterfaceSubClass == CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL)
00260                 && (ptr_iface->bInterfaceProtocol <= CDCCommunicationInterfaceDescriptor_NOPROTOCOL)) {
00261             // New COM port has been found
00262             uhi_cdc_dev.nb_port++;
00263         }
00264         assert(conf_desc_lgt>=ptr_iface->bLength);
00265         conf_desc_lgt -= ptr_iface->bLength;
00266         ptr_iface = (USBInterfaceDescriptor*)((uint8_t*)ptr_iface + ptr_iface->bLength);
00267     }
00268     if (uhi_cdc_dev.nb_port == 0) {
00269         return UHC_ENUM_UNSUPPORTED; // No interface supported
00270     }
00271 
00272     // Alloc port structures
00273     uhi_cdc_dev.port = malloc(uhi_cdc_dev.nb_port * sizeof(uhi_cdc_port_t));
00274     if (uhi_cdc_dev.port == NULL) {
00275         assert(false);
00276         return UHC_ENUM_SOFTWARE_LIMIT;
00277     }
00278     // Initialize structure
00279     for (i = 0; i<uhi_cdc_dev.nb_port; i++) {
00280         uhi_cdc_dev.port[i].ep_comm_in = 0;
00281         uhi_cdc_dev.port[i].iface_data = 0xFF;
00282         uhi_cdc_dev.port[i].line_rx.ep_data = 0;
00283         uhi_cdc_dev.port[i].line_rx.buffer[0].ptr = NULL;
00284         uhi_cdc_dev.port[i].line_rx.buffer[1].ptr = NULL;
00285         uhi_cdc_dev.port[i].line_tx.ep_data = 0;
00286         uhi_cdc_dev.port[i].line_tx.buffer[0].ptr = NULL;
00287         uhi_cdc_dev.port[i].line_tx.buffer[1].ptr = NULL;
00288     }
00289 
00290     // Fill port structures
00291     conf_desc_lgt = (dev->conf_desc->wTotalLength);
00292     ptr_iface = (USBInterfaceDescriptor*)dev->conf_desc;
00293     b_iface_comm = false;
00294     b_iface_data = false;
00295     port_num = 0;
00296     while (conf_desc_lgt) {
00297         switch (ptr_iface->bDescriptorType) {
00298 
00299         case USBGenericDescriptor_INTERFACE:
00300             if ((ptr_iface->bInterfaceClass == CDCCommunicationInterfaceDescriptor_CLASS)
00301                     && (ptr_iface->bInterfaceSubClass == CDCCommunicationInterfaceDescriptor_ABSTRACTCONTROLMODEL)
00302                     && (ptr_iface->bInterfaceProtocol <= CDCCommunicationInterfaceDescriptor_NOPROTOCOL) )
00303               {
00304                 // New Communication Class COM port has been found
00305                 b_iface_comm = true;
00306                 ptr_port = &uhi_cdc_dev.port[port_num++];
00307                 ptr_port->iface_comm = ptr_iface->bInterfaceNumber;
00308             } else {
00309                 // Stop allocation endpoint(s)
00310                 b_iface_comm = false;
00311             }
00312             if ((ptr_iface->bInterfaceClass == CDCDataInterfaceDescriptor_CLASS)
00313                     && (ptr_iface->bInterfaceSubClass == 0)
00314                     && (ptr_iface->bInterfaceProtocol == 0) ) {
00315                 for (i = 0; i<uhi_cdc_dev.nb_port; i++) {
00316                     ptr_port = &uhi_cdc_dev.port[i];
00317                     //if (ptr_port->iface_data == 0xFF) {
00318                         b_iface_data = true;
00319                         break;
00320                     //}
00321                     //else
00322                         if (ptr_port->iface_data == ptr_iface->bInterfaceNumber) {
00323                         // New CDC DATA Class has been found
00324                         // and correspond at a CDC COMM Class
00325                         b_iface_data = true;
00326                         break;
00327                     }
00328                 }
00329             } else {
00330                 // Stop allocation endpoint(s)
00331                 b_iface_data = false;
00332             }
00333             break;
00334 
00335         case CDCGenericDescriptor_INTERFACE:
00336             if (!b_iface_comm) {
00337                 break;
00338             }
00339             if (((CDCCallManagementDescriptor*)ptr_iface)->bDescriptorSubtype == CDCGenericDescriptor_CALLMANAGEMENT) {
00340                 ptr_port->iface_data = ((CDCCallManagementDescriptor*)ptr_iface)->bDataInterface;
00341             }
00342             break;
00343 
00344         case USBGenericDescriptor_ENDPOINT:
00345             //  Allocation of the endpoint
00346             if (b_iface_comm) {
00347                 assert (((USBEndpointDescriptor *)ptr_iface)->bmAttributes == USBEndpointDescriptor_INTERRUPT);
00348                 assert(((USBEndpointDescriptor*)ptr_iface)->bEndpointAddress & USB_EP_DIR_IN);
00349                 if (!USBH_HAL_ConfigurePipe(dev->address, (USBEndpointDescriptor*)ptr_iface)) {
00350                     uhi_cdc_free_device();
00351                     return UHC_ENUM_HARDWARE_LIMIT; // Endpoint allocation fail
00352                 }
00353                 ptr_port->ep_comm_in = ((USBEndpointDescriptor*)ptr_iface)->bEndpointAddress;
00354             }
00355             if (b_iface_data) {
00356                 assert (((USBEndpointDescriptor*)ptr_iface)->bmAttributes == USBEndpointDescriptor_BULK);
00357                 if (!USBH_HAL_ConfigurePipe(dev->address, (USBEndpointDescriptor*)ptr_iface)) {
00358                     uhi_cdc_free_device();
00359                     return UHC_ENUM_HARDWARE_LIMIT; // Endpoint allocation fail
00360                 }
00361 
00362                 if (((USBEndpointDescriptor*)ptr_iface)->bEndpointAddress & USB_EP_DIR_IN) {
00363                     ptr_line = &ptr_port->line_rx;
00364                 } else {
00365                     ptr_line = &ptr_port->line_tx;
00366                 }
00367                 ptr_line->ep_data = ((USBEndpointDescriptor*)ptr_iface)->bEndpointAddress;
00368                 ptr_line->b_trans_ongoing = false;
00369                 ptr_line->buf_sel = 0;
00370 
00371                 // Allocate and initialize buffers
00372                 uint16_t buf_size = Max( (
00373                         ((USBEndpointDescriptor*)ptr_iface)->wMaxPacketSize),
00374                         UHI_CDC_BUFFER_SIZE );
00375                 ptr_line->buffer_size = buf_size;
00376                 ptr_line->buffer[0].pos = 0;
00377                 ptr_line->buffer[0].nb = 0;
00378                 ptr_line->buffer[0].ptr = malloc(buf_size);
00379                 if (ptr_line->buffer[0].ptr == NULL) {
00380                     assert(false);
00381                     uhi_cdc_free_device();
00382                     return UHC_ENUM_SOFTWARE_LIMIT;
00383                 }
00384                 ptr_line->buffer[1].pos = 0;
00385                 ptr_line->buffer[1].nb = 0;
00386                 ptr_line->buffer[1].ptr = malloc(buf_size);
00387                 if (ptr_line->buffer[1].ptr == NULL) {
00388                     assert(false);
00389                     uhi_cdc_free_device();
00390                     return UHC_ENUM_SOFTWARE_LIMIT;
00391                 }
00392 
00393             }
00394             break;
00395 
00396         }
00397         assert(conf_desc_lgt >= ptr_iface->bLength);
00398         conf_desc_lgt -= ptr_iface->bLength;
00399         ptr_iface = (USBInterfaceDescriptor*)((uint8_t*)ptr_iface + ptr_iface->bLength);
00400     }
00401 
00402     // Check installed ports
00403     for (i = 0; i<uhi_cdc_dev.nb_port; i++) {
00404         if ((uhi_cdc_dev.port[i].ep_comm_in == 0)
00405                 || (uhi_cdc_dev.port[i].line_rx.ep_data == 0)
00406                 || (uhi_cdc_dev.port[i].line_tx.ep_data == 0)) {
00407             // Install is not complete
00408             uhi_cdc_free_device();
00409             return UHC_ENUM_UNSUPPORTED;
00410         }
00411     }
00412     uhi_cdc_dev.b_enabled = false;
00413     uhi_cdc_dev.dev = dev;
00414     return UHC_ENUM_SUCCESS;
00415 }
00416 
00417 void uhi_cdc_enable(USBH_device_t* dev)
00418 {
00419     if (uhi_cdc_dev.dev != dev) {
00420         return; // No interface to enable
00421     }
00422     uhi_cdc_dev.b_enabled = true;
00423 
00424     // Start all data transfers
00425     uhi_cdc_sof(false);
00426     UHI_CDC_CHANGE(dev,true);
00427 }
00428 
00429 void uhi_cdc_uninstall(USBH_device_t* dev)
00430 {
00431     if (uhi_cdc_dev.dev != dev) {
00432         return; // Device not enabled in this interface
00433     }
00434     uhi_cdc_dev.dev = NULL;
00435     uhi_cdc_free_device();
00436     UHI_CDC_CHANGE(dev,false);
00437 }
00438 
00439 void uhi_cdc_sof(bool b_micro)
00440 {
00441     uint8_t port = 0;
00442     uhi_cdc_port_t *ptr_port;
00443     UNUSED(b_micro);
00444 
00445     if (uhi_cdc_dev.dev == NULL) {
00446         return; // No interface to installed
00447     }
00448     if (!uhi_cdc_dev.b_enabled) {
00449         return; // Interface not enabled
00450     }
00451 
00452     // Update transfers on each port
00453     while (1) {
00454         ptr_port = uhi_cdc_get_port(port++);
00455         if (ptr_port == NULL) {
00456             break;
00457         }
00458         uhi_cdc_rx_update(&ptr_port->line_rx);
00459         uhi_cdc_tx_update(&ptr_port->line_tx);
00460     }
00461 }
00462 //@}
00463 
00464 
00465 /**
00466  * \name Internal routines
00467  */
00468 //@{
00469 
00470 static void uhi_cdc_free_device(void)
00471 {
00472     if (uhi_cdc_dev.port == NULL) {
00473         return;
00474     }
00475     
00476     uint8_t i;
00477     for ( i=0;i<uhi_cdc_dev.nb_port; i++) {
00478         if (uhi_cdc_dev.port[i].line_rx.buffer[0].ptr) {
00479             free(uhi_cdc_dev.port[i].line_rx.buffer[0].ptr);
00480         }
00481         if (uhi_cdc_dev.port[i].line_rx.buffer[1].ptr) {
00482             free(uhi_cdc_dev.port[i].line_rx.buffer[1].ptr);
00483         }
00484         if (uhi_cdc_dev.port[i].line_tx.buffer[0].ptr) {
00485             free(uhi_cdc_dev.port[i].line_tx.buffer[0].ptr);
00486         }
00487         if (uhi_cdc_dev.port[i].line_tx.buffer[1].ptr) {
00488             free(uhi_cdc_dev.port[i].line_tx.buffer[1].ptr);
00489         }
00490     }
00491     free(uhi_cdc_dev.port);
00492 }
00493 
00494 static uhi_cdc_port_t* uhi_cdc_get_port(uint8_t port_num)
00495 {
00496     if (uhi_cdc_dev.dev == NULL) {
00497         return NULL;
00498     }
00499     if (port_num >= uhi_cdc_dev.nb_port) {
00500         return NULL;
00501     }
00502     return &uhi_cdc_dev.port[port_num];
00503 }
00504 
00505 static bool uhi_cdc_set_conf(uint8_t port, CDCLineCoding *configuration)
00506 {
00507     uhi_cdc_port_t *ptr_port;
00508     USBGenericRequest req;
00509 
00510     // Select port
00511     ptr_port = uhi_cdc_get_port(port);
00512     if (ptr_port == NULL) {
00513         return false;
00514     }
00515     memcpy(&ptr_port->conf, configuration, sizeof(CDCLineCoding));
00516 
00517     // Enable configuration
00518     req.bmRequestType = USB_REQ_RECIP_INTERFACE | USB_REQ_TYPE_CLASS | USB_REQ_DIR_OUT;
00519     req.bRequest = CDCGenericRequest_SETLINECODING;
00520     req.wValue = 0;
00521     req.wIndex = ptr_port->iface_comm;
00522     req.wLength = sizeof(CDCLineCoding);
00523     if (!USBH_HAL_SetupReq(uhi_cdc_dev.dev->address,
00524             &req,
00525             (uint8_t *) &ptr_port->conf,
00526             sizeof(CDCLineCoding),
00527             NULL, NULL)) {
00528         return false;
00529     }
00530     return true;
00531 }
00532 
00533 static bool uhi_cdc_set_ctrl_line(uint8_t port, uint16_t wValue)
00534 {
00535     uhi_cdc_port_t *ptr_port;
00536     USBGenericRequest req;
00537 
00538     // Select port
00539     ptr_port = uhi_cdc_get_port(port);
00540     if (ptr_port == NULL) {
00541         return false;
00542     }
00543 
00544     // Enable configuration
00545     req.bmRequestType = USB_REQ_RECIP_INTERFACE | USB_REQ_TYPE_CLASS | USB_REQ_DIR_OUT;
00546     req.bRequest = CDCGenericRequest_SETCONTROLLINESTATE;
00547     req.wValue = wValue;
00548     req.wIndex = ptr_port->iface_comm;
00549     req.wLength = 0;
00550     if (!USBH_HAL_SetupReq(uhi_cdc_dev.dev->address,
00551             &req,
00552             NULL,
00553             0,
00554             NULL, NULL)) {
00555         return false;
00556     }
00557     return true;
00558 }
00559 
00560 static bool uhi_cdc_rx_update(uhi_cdc_line_t *line)
00561 {
00562     irqflags_t flags;
00563     uhi_cdc_buf_t *buf_nosel;
00564     uhi_cdc_buf_t *buf_sel;
00565 
00566     flags = cpu_irq_save();
00567     // Check if transfer is already on-going
00568     if (line->b_trans_ongoing) {
00569         cpu_irq_restore(flags);
00570         return false;
00571     }
00572 
00573     // Search a empty buffer to start a transfer
00574     buf_sel = &line->buffer[line->buf_sel];
00575     buf_nosel = &line->buffer[(line->buf_sel == 0)? 1 : 0];
00576     if (buf_sel->pos >= buf_sel->nb) {
00577         // The current buffer has been read
00578         // then reset it
00579         buf_sel->pos = 0;
00580         buf_sel->nb = 0;
00581     }
00582     if (!buf_sel->nb && buf_nosel->nb) {
00583         // New data available then change current buffer
00584         line->buf_sel = (line->buf_sel == 0)? 1 : 0;
00585         buf_nosel = buf_sel;
00586         UHI_CDC_RX_NOTIFY();
00587     }
00588 
00589     if (buf_nosel->nb) {
00590         // No empty buffer available to start a transfer
00591         cpu_irq_restore(flags);
00592         return false;
00593     }
00594 
00595     // Check if transfer must be delayed after the next SOF
00596     if (uhi_cdc_dev.dev->speed == UHD_SPEED_HIGH) {
00597         if (line->sof == USBH_HAL_GetMicroFrameNum()) {
00598             cpu_irq_restore(flags);
00599             return false;
00600         }
00601     } else {
00602         if (line->sof == USBH_HAL_GetFrameNum()) {
00603             cpu_irq_restore(flags);
00604             return false;
00605         }
00606     }
00607 
00608     // Start transfer on empty buffer
00609     line->b_trans_ongoing = true;
00610     cpu_irq_restore(flags);
00611 
00612     return USBH_HAL_RunEndpoint(
00613         uhi_cdc_dev.dev->address,
00614         line->ep_data,
00615         true,
00616         buf_nosel->ptr,
00617         line->buffer_size,
00618         10,
00619         uhi_cdc_rx_received);
00620 }
00621 
00622 static void uhi_cdc_rx_received(
00623         USBHS_Add_t add,
00624         USBHS_Ep_t ep,
00625         USBH_XfrStatus_t status,
00626         uint32_t nb_transferred)
00627 {
00628     uint8_t port = 0;
00629     uhi_cdc_port_t *ptr_port;
00630     uhi_cdc_line_t *line;
00631     uhi_cdc_buf_t *buf;
00632     UNUSED(add);
00633 
00634     // Search port corresponding at endpoint
00635     while (1) {
00636         ptr_port = uhi_cdc_get_port(port++);
00637         if (ptr_port == NULL) {
00638             return;
00639         }
00640         line = &ptr_port->line_rx;
00641         if (ep == line->ep_data) {
00642             break; // Port found
00643         }
00644     }
00645 
00646   if (UHD_TRANS_NOERROR != status) {
00647         // Abort transfer
00648         line->b_trans_ongoing  = false;
00649         return;
00650     }
00651 
00652     // Update SOF tag, if it is a short packet
00653     if (nb_transferred != line->buffer_size) {
00654         if (uhi_cdc_dev.dev->speed == UHD_SPEED_HIGH) {
00655             line->sof = USBH_HAL_GetMicroFrameNum();
00656         } else {
00657             line->sof = USBH_HAL_GetFrameNum();
00658         }
00659     }
00660 
00661     // Update buffer structure
00662     buf = &line->buffer[(line->buf_sel == 0) ? 1 : 0];
00663     buf->pos = 0;
00664     buf->nb = nb_transferred;
00665     line->b_trans_ongoing  = false;
00666 
00667     // Manage new transfer
00668     uhi_cdc_rx_update(line);
00669 }
00670 
00671 
00672 static bool uhi_cdc_tx_update(uhi_cdc_line_t *line)
00673 {
00674     irqflags_t flags;
00675     uhi_cdc_buf_t *buf;
00676 
00677     flags = cpu_irq_save();
00678     // Check if transfer is already on-going
00679     if (line->b_trans_ongoing) {
00680         cpu_irq_restore(flags);
00681         return false;
00682     }
00683     // Check if transfer must be delayed after the next SOF
00684     if (uhi_cdc_dev.dev->speed == UHD_SPEED_HIGH) {
00685         if (line->sof == USBH_HAL_GetMicroFrameNum()) {
00686             cpu_irq_restore(flags);
00687             return false;
00688         }
00689     } else {
00690         if (line->sof == USBH_HAL_GetFrameNum()) {
00691             cpu_irq_restore(flags);
00692             return false;
00693         }
00694     }
00695 
00696     // Send the current buffer if not empty
00697     buf = &line->buffer[line->buf_sel];
00698     if (buf->nb == 0) {
00699         cpu_irq_restore(flags);
00700         return false;
00701     }
00702 
00703     // Change current buffer to next buffer
00704     line->buf_sel = (line->buf_sel == 0)? 1 : 0;
00705 
00706     // Start transfer
00707     line->b_trans_ongoing = true;
00708     cpu_irq_restore(flags);
00709 
00710     return USBH_HAL_RunEndpoint(
00711         uhi_cdc_dev.dev->address,
00712         line->ep_data,
00713         true,
00714         buf->ptr,
00715         buf->nb,
00716         1000,
00717         uhi_cdc_tx_send);
00718 }
00719 
00720 
00721 static void uhi_cdc_tx_send(
00722         USBHS_Add_t add,
00723         USBHS_Ep_t ep,
00724         USBH_XfrStatus_t status,
00725         uint32_t nb_transferred)
00726 {
00727     uint8_t port = 0;
00728     uhi_cdc_port_t *ptr_port;
00729     uhi_cdc_line_t *line;
00730     uhi_cdc_buf_t *buf;
00731     irqflags_t flags;
00732     UNUSED(add);
00733 
00734     flags = cpu_irq_save();
00735 
00736     // Search port corresponding at endpoint
00737     while (1) {
00738         ptr_port = uhi_cdc_get_port(port++);
00739         if (ptr_port == NULL) {
00740             cpu_irq_restore(flags);
00741             return;
00742         }
00743         line = &ptr_port->line_tx;
00744         if (ep == line->ep_data) {
00745             break; // Port found
00746         }
00747     }
00748 
00749     if (UHD_TRANS_NOERROR != status) {
00750         // Abort transfer
00751         line->b_trans_ongoing  = false;
00752         cpu_irq_restore(flags);
00753         return;
00754     }
00755 
00756     // Update SOF tag, if it is a short packet
00757     if (nb_transferred != line->buffer_size) {
00758         if (uhi_cdc_dev.dev->speed == UHD_SPEED_HIGH) {
00759             line->sof = USBH_HAL_GetMicroFrameNum();
00760         } else {
00761             line->sof = USBH_HAL_GetFrameNum();
00762         }
00763     }
00764 
00765     // Update buffer structure
00766     buf = &line->buffer[(line->buf_sel == 0) ? 1 : 0 ];
00767     buf->nb = 0;
00768     line->b_trans_ongoing  = false;
00769     cpu_irq_restore(flags);
00770 
00771     // Manage new transfer
00772     uhi_cdc_tx_update(line);
00773 }
00774 //@}
00775 
00776 
00777 bool uhi_cdc_open(uint8_t port, CDCLineCoding *configuration)
00778 {
00779     // Send configuration
00780     if (!uhi_cdc_set_conf(port, configuration)) {
00781         return false;
00782     }
00783     // Send DTR
00784     if (!uhi_cdc_set_ctrl_line(port, CDCControlLineState_DTE_PRESENT)) {
00785         return false;
00786     }
00787     return true;
00788 }
00789 
00790 void uhi_cdc_close(uint8_t port)
00791 {
00792     // Clear DTR
00793     uhi_cdc_set_ctrl_line(port, 0);
00794 }
00795 
00796 bool uhi_cdc_is_rx_ready(uint8_t port)
00797 {
00798     return (0 != uhi_cdc_get_nb_received(port));
00799 }
00800 
00801 uint32_t uhi_cdc_get_nb_received(uint8_t port)
00802 {
00803     uhi_cdc_port_t *ptr_port;
00804     uhi_cdc_buf_t *buf;
00805 
00806     // Select port
00807     ptr_port = uhi_cdc_get_port(port);
00808     if (ptr_port == NULL) {
00809         return false;
00810     }
00811 
00812     // Check available data
00813     buf = &ptr_port->line_rx.buffer[ ptr_port->line_rx.buf_sel ];
00814     return (buf->nb - buf->pos);
00815 }
00816 
00817 int uhi_cdc_getc(uint8_t port)
00818 {
00819     uhi_cdc_port_t *ptr_port;
00820     uhi_cdc_line_t *line;
00821     uhi_cdc_buf_t *buf;
00822     int rx_data = 0;
00823     bool b_databit_9;
00824 
00825     // Select port
00826     ptr_port = uhi_cdc_get_port(port);
00827     if (ptr_port == NULL) {
00828         return false;
00829     }
00830     line = &ptr_port->line_rx;
00831 
00832     b_databit_9 = (9 == ptr_port->conf.bDataBits);
00833 
00834 uhi_cdc_getc_process_one_byte:
00835     // Check available data
00836     buf = &line->buffer[line->buf_sel];
00837     while (buf->pos >= buf->nb) {
00838         if (NULL == uhi_cdc_get_port(port)) {
00839             return 0;
00840         }
00841         uhi_cdc_rx_update(line);
00842         goto uhi_cdc_getc_process_one_byte;
00843     }
00844 
00845     // Read data
00846     rx_data |= buf->ptr[buf->pos];
00847     buf->pos++;
00848 
00849     uhi_cdc_rx_update(line);
00850 
00851     if (b_databit_9) {
00852         // Receive MSB
00853         b_databit_9 = false;
00854         rx_data = rx_data << 8;
00855         goto uhi_cdc_getc_process_one_byte;
00856     }
00857     return rx_data;
00858 }
00859 
00860 uint32_t uhi_cdc_read_buf(uint8_t port, void* buf, uint32_t size)
00861 {
00862     uhi_cdc_port_t *ptr_port;
00863     uhi_cdc_line_t *line;
00864     uhi_cdc_buf_t *cdc_buf;
00865     uint32_t copy_nb;
00866 
00867     // Select port
00868     ptr_port = uhi_cdc_get_port(port);
00869     if (ptr_port == NULL) {
00870         return false;
00871     }
00872     line = &ptr_port->line_rx;
00873 
00874 
00875 uhi_cdc_read_buf_loop_wait:
00876     // Check available data
00877     cdc_buf = &line->buffer[line->buf_sel];
00878     while (cdc_buf->pos >= cdc_buf->nb) {
00879         if (NULL == uhi_cdc_get_port(port)) {
00880             return 0;
00881         }
00882         uhi_cdc_rx_update(line);
00883         goto uhi_cdc_read_buf_loop_wait;
00884     }
00885 
00886     // Read data
00887     copy_nb = cdc_buf->nb - cdc_buf->pos;
00888     if (copy_nb > size) {
00889         copy_nb = size;
00890     }
00891     memcpy(buf, &cdc_buf->ptr[cdc_buf->pos], copy_nb);
00892     cdc_buf->pos += copy_nb;
00893     buf = (uint8_t*)buf + copy_nb;
00894     size -= copy_nb;
00895 
00896     uhi_cdc_rx_update(line);
00897 
00898     if (size) {
00899         goto uhi_cdc_read_buf_loop_wait;
00900     }
00901     return 0;
00902 }
00903 
00904 
00905 bool uhi_cdc_is_tx_ready(uint8_t port)
00906 {
00907     uhi_cdc_port_t *ptr_port;
00908     uhi_cdc_line_t *line;
00909 
00910     ptr_port = uhi_cdc_get_port(port);
00911     if (ptr_port == NULL) {
00912         return false;
00913     }
00914     line = &ptr_port->line_tx;
00915 
00916     return (line->buffer_size != line->buffer[line->buf_sel].nb);
00917 }
00918 
00919 
00920 int uhi_cdc_putc(uint8_t port, int value)
00921 {
00922     irqflags_t flags;
00923     uhi_cdc_port_t *ptr_port;
00924     uhi_cdc_line_t *line;
00925     uhi_cdc_buf_t *buf;
00926     bool b_databit_9;
00927 
00928     // Select port
00929     ptr_port = uhi_cdc_get_port(port);
00930     if (ptr_port == NULL) {
00931         return false;
00932     }
00933     line = &ptr_port->line_tx;
00934 
00935     b_databit_9 = (9 == ptr_port->conf.bDataBits);
00936 
00937 uhi_cdc_putc_process_one_byte:
00938     // Check available space
00939     buf = &line->buffer[line->buf_sel];
00940     while (line->buffer_size == buf->nb) {
00941         if (NULL == uhi_cdc_get_port(port)) {
00942             return false;
00943         }
00944         goto uhi_cdc_putc_process_one_byte;
00945     }
00946 
00947     // Write value
00948     flags = cpu_irq_save();
00949     buf = &line->buffer[line->buf_sel];
00950     buf->ptr[buf->nb++] = value;
00951     cpu_irq_restore(flags);
00952 
00953     if (b_databit_9) {
00954         // Send MSB
00955         b_databit_9 = false;
00956         value = value >> 8;
00957         goto uhi_cdc_putc_process_one_byte;
00958     }
00959     return true;
00960 }
00961 
00962 uint32_t uhi_cdc_write_buf(uint8_t port, const void* buf, uint32_t size)
00963 {
00964     irqflags_t flags;
00965     uhi_cdc_port_t *ptr_port;
00966     uhi_cdc_line_t *line;
00967     uhi_cdc_buf_t *cdc_buf;
00968     uint32_t copy_nb;
00969 
00970     // Select port
00971     ptr_port = uhi_cdc_get_port(port);
00972     if (ptr_port == NULL) {
00973         return false;
00974     }
00975     line = &ptr_port->line_tx;
00976 
00977     if (9 == ptr_port->conf.bDataBits) {
00978         size *=2;
00979     }
00980 
00981 uhi_cdc_write_buf_loop_wait:
00982     // Check available space
00983     cdc_buf = &line->buffer[line->buf_sel];
00984     while (line->buffer_size == cdc_buf->nb) {
00985         if (NULL == uhi_cdc_get_port(port)) {
00986             return 0;
00987         }
00988         goto uhi_cdc_write_buf_loop_wait;
00989     }
00990 
00991     // Write value
00992     flags = cpu_irq_save();
00993     cdc_buf = &line->buffer[line->buf_sel];
00994     copy_nb = line->buffer_size - cdc_buf->nb;
00995     if (copy_nb>size) {
00996         copy_nb = size;
00997     }
00998     memcpy(&cdc_buf->ptr[cdc_buf->nb], buf, copy_nb);
00999     cdc_buf->nb += copy_nb;
01000     cpu_irq_restore(flags);
01001 
01002     // Update buffer pointer
01003     buf = (uint8_t*)buf + copy_nb;
01004     size -= copy_nb;
01005 
01006     if (size) {
01007         goto uhi_cdc_write_buf_loop_wait;
01008     }
01009 
01010     return 0;
01011 }
01012 
01013 //@}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines