Platform drivers for Mbed.

Dependents:   EVAL-CN0535-FMCZ EVAL-CN0535-FMCZ EVAL-AD568x-AD569x EVAL-AD7606 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers uart.cpp Source File

uart.cpp

Go to the documentation of this file.
00001 /***************************************************************************//**
00002  * @file  uart.cpp
00003  * @brief Implementation of UART Mbed platform driver interfaces
00004 ********************************************************************************
00005  * Copyright (c) 2021 Analog Devices, Inc.
00006  * All rights reserved.
00007  *
00008  * This software is proprietary to Analog Devices, Inc. and its licensors.
00009  * By using this software you agree to the terms of the associated
00010  * Analog Devices Software License Agreement.
00011 *******************************************************************************/
00012 
00013 /******************************************************************************/
00014 /***************************** Include Files **********************************/
00015 /******************************************************************************/
00016 #include <stdio.h>
00017 #include <mbed.h>
00018 #include <USBCDC.h>
00019 
00020 // Platform drivers needs to be C-compatible to work with other drivers
00021 #ifdef __cplusplus
00022 extern "C"
00023 {
00024 #endif //  _cplusplus
00025 
00026 #include "error.h"
00027 #include "delay.h"
00028 #include "uart.h"
00029 #include "uart_extra.h"
00030 
00031 /******************************************************************************/
00032 /************************ Macros/Constants ************************************/
00033 /******************************************************************************/
00034 
00035 /* Max size for USB CDC packet during transmit/receive */
00036 #define USB_CDC_MAX_PACKET_SIZE     (64)
00037 
00038 /* Max allowed length of USB serial number in characters */
00039 #define USB_SERIAL_NUM_MAX_LENGTH   (100)
00040 
00041 /******************************************************************************/
00042 /*************************** Types Declarations *******************************/
00043 /******************************************************************************/
00044 
00045 /* Derived USBCDC class to access protected members of USBCDC class */
00046 class platform_usbcdc :public USBCDC
00047 {
00048 private:
00049     uint8_t usb_iserial_descriptor[(USB_SERIAL_NUM_MAX_LENGTH * 2) + 2];
00050 
00051 public :
00052     /* Call parent class (USBCDC) constructor explicitly */
00053     platform_usbcdc(bool connect_blocking, uint16_t vendor_id, uint16_t product_id,
00054             const char *serial_number)
00055         : USBCDC(connect_blocking, vendor_id, product_id)
00056     {
00057         uint8_t usb_iserial_len;    // USB serial number length
00058         uint8_t i, j = 0;
00059 
00060         usb_iserial_len = strlen(serial_number);
00061         if (usb_iserial_len > USB_SERIAL_NUM_MAX_LENGTH) {
00062             usb_iserial_len = USB_SERIAL_NUM_MAX_LENGTH;
00063         }
00064 
00065         this->usb_iserial_descriptor[j++] = (usb_iserial_len * 2) + 2;  /* bLength */
00066         this->usb_iserial_descriptor[j++] = STRING_DESCRIPTOR;          /* bDescriptorType */
00067 
00068         /* bString iSerial */
00069         for (i = 0; i < usb_iserial_len; i++) {
00070             this->usb_iserial_descriptor[j++] = serial_number[i];
00071             this->usb_iserial_descriptor[j++] = 0;
00072         }
00073     }
00074 
00075     /* Override the virtual function that sets the USB serial number
00076      * The custom (user provided) USB serial number is passed through this function */
00077     virtual const uint8_t *string_iserial_desc()
00078     {
00079         return this->usb_iserial_descriptor;
00080     }
00081 
00082     void change_terminal_connection(bool connect_status);
00083     bool data_received(uint32_t rx_size);
00084     bool data_transmited(void);
00085 };
00086 
00087 /******************************************************************************/
00088 /************************ Functions Definitions *******************************/
00089 /******************************************************************************/
00090 
00091 /**
00092  * @brief Change the terminal connection status (for non-terminal) based USB interface
00093  * @param connect_status- new connection status
00094  * @note  This functions is used to change the terminal connection status of USB client
00095  *        interface which is different than the 'console terminal'. The console terminals acknowledge
00096  *        back to USB host when USB connection is opened on the console terminal and Mbed USBCDC
00097  *        class automatically changes the '_terminal_connected' status accordingly. However, for
00098  *        custom PC applications (non terminal), the terminal connection status needs to be changed
00099  *        manually. The '_terminal_connected' is protected member of USBCDC parent class and thus can
00100  *        be accessed through 'platform_usbcdc' derived class using below function.
00101  */
00102 void platform_usbcdc::change_terminal_connection(bool connect_status)
00103 {
00104     _terminal_connected = connect_status;
00105 }
00106 
00107 
00108 /**
00109  * @brief   Check if new USB data is received/available
00110  * @param   bytes[in] - Number of expected bytes to be received
00111  * @return  true if expected number of bytes received, else false
00112  */
00113 bool platform_usbcdc::data_received(uint32_t bytes)
00114 {
00115     volatile static uint32_t *rx_size = &_rx_size;
00116 
00117     if (*rx_size >= bytes) {
00118         return true;
00119     } else {
00120         return false;
00121     }
00122 }
00123 
00124 
00125 /**
00126  * @brief  Check if old USB data was transmitted
00127  * @return true if transmit not in progress, else false
00128  */
00129 bool platform_usbcdc::data_transmited(void)
00130 {
00131     volatile static bool *tx_in_progress = &_tx_in_progress;
00132 
00133     if (*tx_in_progress) {
00134         return false;
00135     } else {
00136         return true;
00137     }
00138 }
00139 
00140 
00141 /**
00142  * @brief Read data from UART device.
00143  * @param desc - Instance of UART.
00144  * @param data - Pointer to buffer containing data.
00145  * @param bytes_number - Number of bytes to read.
00146  * @return SUCCESS in case of success, FAILURE otherwise.
00147  */
00148 int32_t uart_read(struct uart_desc *desc, uint8_t *data, uint32_t bytes_number)
00149 {
00150     uint8_t cnt;
00151     mbed::UnbufferedSerial *uart;   // pointer to UnbufferedSerial/UART instance
00152     platform_usbcdc *usb_cdc_dev;   // Pointer to usb cdc device class instance
00153     uint32_t size_rd;
00154 
00155     if (desc && data) {
00156         if (((mbed_uart_desc *)(desc->extra))->uart_port) {
00157             if (((mbed_uart_desc *)desc->extra)->virtual_com_enable) {
00158                 usb_cdc_dev = (platform_usbcdc *)((mbed_uart_desc *)(
00159                         desc->extra))->uart_port;
00160 
00161                 while (!usb_cdc_dev->data_received(bytes_number)) {
00162                     /* Wait until new data is available */
00163                 }
00164 
00165                 /* Change terminal connection status manually */
00166                 usb_cdc_dev->change_terminal_connection(true);
00167 
00168                 usb_cdc_dev->receive_nb(data, bytes_number, &size_rd);
00169             } else {
00170                 uart = (UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port);
00171 
00172                 for (cnt = 0; cnt < bytes_number; cnt++) {
00173                     uart->read(data + cnt, 1);
00174                 }
00175             }
00176 
00177             return bytes_number;
00178         }
00179     }
00180 
00181     return FAILURE;
00182 }
00183 
00184 
00185 /**
00186  * @brief Write data to UART device.
00187  * @param desc - Instance of UART.
00188  * @param data - Pointer to buffer containing data.
00189  * @param bytes_number - Number of bytes to read.
00190  * @return SUCCESS in case of success, FAILURE otherwise.
00191  */
00192 int32_t uart_write(struct uart_desc *desc, const uint8_t *data,
00193            uint32_t bytes_number)
00194 {
00195     mbed::UnbufferedSerial *uart;   // pointer to UnbufferedSerial/UART instance
00196     platform_usbcdc *usb_cdc_dev;   // Pointer to usb cdc device class instance
00197     uint32_t d_sz;
00198     uint32_t indx = 0;
00199 
00200     if (desc && data) {
00201         if (((mbed_uart_desc *)(desc->extra))->uart_port) {
00202             if (((mbed_uart_desc *)desc->extra)->virtual_com_enable) {
00203                 usb_cdc_dev = (platform_usbcdc *)((mbed_uart_desc *)(
00204                         desc->extra))->uart_port;
00205 
00206                 while (bytes_number) {
00207                     while (!usb_cdc_dev->data_transmited()) {
00208                         /* Wait until old data is transmitted */
00209                     }
00210 
00211                     /* Make sure packet size is less than max CDC packet size during data transmit */
00212                     d_sz = (bytes_number > (USB_CDC_MAX_PACKET_SIZE - 1)) ?
00213                            (USB_CDC_MAX_PACKET_SIZE - 1) :
00214                            bytes_number;
00215 
00216                     /* Change terminal connection status manually */
00217                     usb_cdc_dev->change_terminal_connection(true);
00218 
00219                     usb_cdc_dev->send_nb((uint8_t *)&data[indx], d_sz, &d_sz);
00220 
00221                     bytes_number -= d_sz;
00222                     indx += d_sz;
00223                 }
00224 
00225                 return bytes_number;
00226             } else {
00227                 uart = (UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port);
00228                 return uart->write(data, bytes_number);
00229             }
00230         }
00231     }
00232 
00233     return FAILURE;
00234 }
00235 
00236 
00237 /**
00238  * @brief Submit reading buffer to the UART driver.
00239  *
00240  * Buffer is used until bytes_number bytes are read.
00241  * @param desc: Descriptor of the UART device
00242  * @param data: Buffer where data will be read
00243  * @param bytes_number: Number of bytes to be read.
00244  * @return \ref SUCCESS in case of success, \ref FAILURE otherwise.
00245  */
00246 int32_t uart_read_nonblocking(struct uart_desc *desc,
00247                   uint8_t *data,
00248                   uint32_t bytes_number)
00249 {
00250     mbed::UnbufferedSerial *uart;       // pointer to UnbufferedSerial/UART instance
00251 
00252     if (desc) {
00253         if (((mbed_uart_desc *)(desc->extra))->uart_port) {
00254             uart = (UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port);
00255 
00256             if (data) {
00257                 for (size_t i = 0; i < bytes_number; i++) {
00258                     if (uart->readable() > 0) {
00259                         uart->read(&data[i], 1);
00260                     }
00261                 }
00262 
00263                 return bytes_number;
00264             }
00265         }
00266     }
00267 
00268     return FAILURE;
00269 }
00270 
00271 
00272 /**
00273  * @brief Submit writting buffer to the UART driver.
00274  *
00275  * Data from the buffer is sent over the UART, the function returns imediatly.
00276  * @param desc: Descriptor of the UART device
00277  * @param data: Buffer where data will be written
00278  * @param bytes_number: Number of bytes to be written.
00279  * @return \ref SUCCESS in case of success, \ref FAILURE otherwise.
00280  */
00281 int32_t uart_write_nonblocking(struct uart_desc *desc,
00282                    const uint8_t *data,
00283                    uint32_t bytes_number)
00284 {
00285     mbed::UnbufferedSerial *uart;       // pointer to UnbufferedSerial/UART instance
00286 
00287     if (desc) {
00288         if (((mbed_uart_desc *)(desc->extra))->uart_port) {
00289             uart = (UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port);
00290 
00291             if (data) {
00292                 for (size_t i = 0; i < bytes_number; i++) {
00293                     uart->write(&data[i], 1);
00294                 }
00295 
00296                 return bytes_number;
00297             }
00298         }
00299     }
00300 
00301     return FAILURE;
00302 }
00303 
00304 
00305 /**
00306  * @brief Initialize the UART communication peripheral.
00307  * @param desc - The UART descriptor.
00308  * @param param - The structure that contains the UART parameters.
00309  * @return SUCCESS in case of success, FAILURE otherwise.
00310  */
00311 int32_t uart_init(struct uart_desc **desc, struct uart_init_param *param)
00312 {
00313     mbed::UnbufferedSerial *uart;   // Pointer to new UnbufferedSerial/UART instance
00314     platform_usbcdc *usb_cdc_dev;   // Pointer to usb cdc device class instance
00315     mbed_uart_desc *mbed_desc;      // Pointer to mbed uart descriptor
00316     uart_desc *new_desc;            // UART new descriptor
00317 
00318     if (desc && param && param->extra) {
00319         // Create the UART description object for the device
00320         new_desc = (uart_desc *)malloc(sizeof(uart_desc));
00321         if (!new_desc) {
00322             goto err_new_desc;
00323         }
00324 
00325         new_desc->baud_rate = param->baud_rate;
00326 
00327         if (((mbed_uart_init_param *)param->extra)->virtual_com_enable) {
00328             // Create a new instance of platform_usbcdc class
00329             usb_cdc_dev = new platform_usbcdc(false,
00330                               ((mbed_uart_init_param *)param->extra)->vendor_id,
00331                               ((mbed_uart_init_param *)param->extra)->product_id,
00332                               ((mbed_uart_init_param *)param->extra)->serial_number);
00333             if (!usb_cdc_dev) {
00334                 goto err_usb_cdc_dev;
00335             }
00336         } else {
00337             // Create and configure a new instance of UnbufferedSerial/UART port
00338             uart = new UnbufferedSerial(
00339                 (PinName)(((mbed_uart_init_param *)param->extra)->uart_tx_pin),
00340                 (PinName)(((mbed_uart_init_param *)param->extra)->uart_rx_pin),
00341                 (int)param->baud_rate);
00342 
00343             if (!uart) {
00344                 goto err_uart;
00345             }
00346         }
00347 
00348         // Create a new mbed descriptor to store new UART instances
00349         mbed_desc = (mbed_uart_desc *)malloc(sizeof(mbed_uart_desc));
00350         if (!mbed_desc) {
00351             goto err_mbed_desc;
00352         }
00353 
00354         if (((mbed_uart_init_param *)param->extra)->virtual_com_enable) {
00355             mbed_desc->uart_port = (platform_usbcdc *)usb_cdc_dev;
00356 
00357             /* Establish connection with the USB CDC communication port */
00358             usb_cdc_dev->connect();
00359             mdelay(2000);
00360         } else {
00361             mbed_desc->uart_port = (UnbufferedSerial *)uart;
00362         }
00363 
00364         mbed_desc->virtual_com_enable = ((mbed_uart_init_param *)
00365                          param->extra)->virtual_com_enable;
00366         new_desc->extra = (mbed_uart_desc *)mbed_desc;
00367         *desc = new_desc;
00368 
00369         return SUCCESS;
00370     }
00371 
00372 err_mbed_desc:
00373     if (uart) {
00374         free(uart);
00375     }
00376     if (usb_cdc_dev) {
00377         free(usb_cdc_dev);
00378     }
00379 err_uart:
00380 err_usb_cdc_dev:
00381     free(new_desc);
00382 err_new_desc:
00383     // Nothing to free
00384 
00385     return FAILURE;
00386 }
00387 
00388 
00389 /**
00390  * @brief Free the resources allocated by uart_init().
00391  * @param desc - The UART descriptor.
00392  * @return SUCCESS in case of success, FAILURE otherwise.
00393  */
00394 int32_t uart_remove(struct uart_desc *desc)
00395 {
00396     if (desc) {
00397         // Free the UART port object
00398         if (((mbed_uart_desc *)desc->extra)->virtual_com_enable) {
00399             if ((platform_usbcdc *)((mbed_uart_desc *)desc->extra)->uart_port)
00400                 delete((platform_usbcdc *)(platform_usbcdc *)((mbed_uart_desc *)
00401                         desc->extra)->uart_port);
00402         } else {
00403             if ((UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port)) {
00404                 delete((UnbufferedSerial *)(((mbed_uart_desc *)(desc->extra))->uart_port));
00405             }
00406         }
00407 
00408         // Free the UART extra descriptor object
00409         if ((mbed_uart_desc *)(desc->extra)) {
00410             free((mbed_uart_desc *)(desc->extra));
00411         }
00412 
00413         // Free the UART descriptor object
00414         free(desc);
00415 
00416         return SUCCESS;
00417     }
00418 
00419     return FAILURE;
00420 }
00421 
00422 
00423 /**
00424  * @brief Get number of UART errors.
00425  * @param desc - The UART descriptor.
00426  * @return number of errors.
00427  */
00428 uint32_t uart_get_errors(struct uart_desc *desc)
00429 {
00430     if (desc) {
00431         // Unused variable - fix compiler warning
00432     }
00433 
00434     return SUCCESS;
00435 }
00436 
00437 #ifdef __cplusplus  // Closing extern c
00438 }
00439 #endif //  _cplusplus