SAMV71 Xplained Ultra Software Package 1.5

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