mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UARTSerial.cpp Source File

UARTSerial.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2017 ARM Limited
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "drivers/UARTSerial.h"
00018 
00019 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
00020 
00021 #include "platform/mbed_poll.h"
00022 
00023 #if MBED_CONF_RTOS_PRESENT
00024 #include "rtos/ThisThread.h"
00025 #else
00026 #include "platform/mbed_wait_api.h"
00027 #endif
00028 
00029 namespace mbed {
00030 
00031 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
00032     SerialBase(tx, rx, baud),
00033     _blocking(true),
00034     _tx_irq_enabled(false),
00035     _rx_irq_enabled(true),
00036     _dcd_irq(NULL)
00037 {
00038     /* Attatch IRQ routines to the serial device. */
00039     SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
00040 }
00041 
00042 UARTSerial::~UARTSerial()
00043 {
00044     delete _dcd_irq;
00045 }
00046 
00047 void UARTSerial::dcd_irq()
00048 {
00049     wake();
00050 }
00051 
00052 void UARTSerial::set_baud(int baud)
00053 {
00054     SerialBase::baud(baud);
00055 }
00056 
00057 void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
00058 {
00059     delete _dcd_irq;
00060     _dcd_irq = NULL;
00061 
00062     if (dcd_pin != NC) {
00063         _dcd_irq = new InterruptIn(dcd_pin);
00064         if (active_high) {
00065             _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
00066         } else {
00067             _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
00068         }
00069     }
00070 }
00071 
00072 void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
00073 {
00074     api_lock();
00075     SerialBase::format(bits, parity, stop_bits);
00076     api_unlock();
00077 }
00078 
00079 #if DEVICE_SERIAL_FC
00080 void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
00081 {
00082     api_lock();
00083     SerialBase::set_flow_control(type, flow1, flow2);
00084     api_unlock();
00085 }
00086 #endif
00087 
00088 int UARTSerial::close()
00089 {
00090     /* Does not let us pass a file descriptor. So how to close ?
00091      * Also, does it make sense to close a device type file descriptor*/
00092     return 0;
00093 }
00094 
00095 int UARTSerial::isatty()
00096 {
00097     return 1;
00098 
00099 }
00100 
00101 off_t UARTSerial::seek(off_t offset, int whence)
00102 {
00103     /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
00104      * buffer system (from an interrupt context) */
00105     return -ESPIPE;
00106 }
00107 
00108 int UARTSerial::sync()
00109 {
00110     api_lock();
00111 
00112     while (!_txbuf.empty()) {
00113         api_unlock();
00114         // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
00115         wait_ms(1);
00116         api_lock();
00117     }
00118 
00119     api_unlock();
00120 
00121     return 0;
00122 }
00123 
00124 void UARTSerial::sigio(Callback<void()> func)
00125 {
00126     core_util_critical_section_enter();
00127     _sigio_cb = func;
00128     if (_sigio_cb) {
00129         short current_events = poll(0x7FFF);
00130         if (current_events) {
00131             _sigio_cb();
00132         }
00133     }
00134     core_util_critical_section_exit();
00135 }
00136 
00137 /* Special synchronous write designed to work from critical section, such
00138  * as in mbed_error_vprintf.
00139  */
00140 ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
00141 {
00142     while (!_txbuf.empty()) {
00143         tx_irq();
00144     }
00145 
00146     for (size_t data_written = 0; data_written < length; data_written++) {
00147         SerialBase::_base_putc(*buf_ptr++);
00148         data_written++;
00149     }
00150 
00151     return length;
00152 }
00153 
00154 ssize_t UARTSerial::write(const void *buffer, size_t length)
00155 {
00156     size_t data_written = 0;
00157     const char *buf_ptr = static_cast<const char *>(buffer);
00158 
00159     if (length == 0) {
00160         return 0;
00161     }
00162 
00163     if (core_util_in_critical_section()) {
00164         return write_unbuffered(buf_ptr, length);
00165     }
00166 
00167     api_lock();
00168 
00169     // Unlike read, we should write the whole thing if blocking. POSIX only
00170     // allows partial as a side-effect of signal handling; it normally tries to
00171     // write everything if blocking. Without signals we can always write all.
00172     while (data_written < length) {
00173 
00174         if (_txbuf.full()) {
00175             if (!_blocking) {
00176                 break;
00177             }
00178             do {
00179                 api_unlock();
00180                 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
00181                 api_lock();
00182             } while (_txbuf.full());
00183         }
00184 
00185         while (data_written < length && !_txbuf.full()) {
00186             _txbuf.push(*buf_ptr++);
00187             data_written++;
00188         }
00189 
00190         core_util_critical_section_enter();
00191         if (!_tx_irq_enabled) {
00192             UARTSerial::tx_irq();                // only write to hardware in one place
00193             if (!_txbuf.empty()) {
00194                 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
00195                 _tx_irq_enabled = true;
00196             }
00197         }
00198         core_util_critical_section_exit();
00199     }
00200 
00201     api_unlock();
00202 
00203     return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
00204 }
00205 
00206 ssize_t UARTSerial::read(void *buffer, size_t length)
00207 {
00208     size_t data_read = 0;
00209 
00210     char *ptr = static_cast<char *>(buffer);
00211 
00212     if (length == 0) {
00213         return 0;
00214     }
00215 
00216     api_lock();
00217 
00218     while (_rxbuf.empty()) {
00219         if (!_blocking) {
00220             api_unlock();
00221             return -EAGAIN;
00222         }
00223         api_unlock();
00224         wait_ms(1);  // XXX todo - proper wait, WFE for non-rtos ?
00225         api_lock();
00226     }
00227 
00228     while (data_read < length && !_rxbuf.empty()) {
00229         _rxbuf.pop(*ptr++);
00230         data_read++;
00231     }
00232 
00233     core_util_critical_section_enter();
00234     if (!_rx_irq_enabled) {
00235         UARTSerial::rx_irq();               // only read from hardware in one place
00236         if (!_rxbuf.full()) {
00237             SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
00238             _rx_irq_enabled = true;
00239         }
00240     }
00241     core_util_critical_section_exit();
00242 
00243     api_unlock();
00244 
00245     return data_read;
00246 }
00247 
00248 bool UARTSerial::hup() const
00249 {
00250     return _dcd_irq && _dcd_irq->read() != 0;
00251 }
00252 
00253 void UARTSerial::wake()
00254 {
00255     if (_sigio_cb) {
00256         _sigio_cb();
00257     }
00258 }
00259 
00260 short UARTSerial::poll(short events) const
00261 {
00262 
00263     short revents = 0;
00264     /* Check the Circular Buffer if space available for writing out */
00265 
00266 
00267     if (!_rxbuf.empty()) {
00268         revents |= POLLIN;
00269     }
00270 
00271     /* POLLHUP and POLLOUT are mutually exclusive */
00272     if (hup()) {
00273         revents |= POLLHUP;
00274     } else if (!_txbuf.full()) {
00275         revents |= POLLOUT;
00276     }
00277 
00278     /*TODO Handle other event types */
00279 
00280     return revents;
00281 }
00282 
00283 void UARTSerial::lock()
00284 {
00285     // This is the override for SerialBase.
00286     // No lock required as we only use SerialBase from interrupt or from
00287     // inside our own critical section.
00288 }
00289 
00290 void UARTSerial::unlock()
00291 {
00292     // This is the override for SerialBase.
00293 }
00294 
00295 void UARTSerial::api_lock(void)
00296 {
00297     _mutex.lock();
00298 }
00299 
00300 void UARTSerial::api_unlock(void)
00301 {
00302     _mutex.unlock();
00303 }
00304 
00305 void UARTSerial::rx_irq(void)
00306 {
00307     bool was_empty = _rxbuf.empty();
00308 
00309     /* Fill in the receive buffer if the peripheral is readable
00310      * and receive buffer is not full. */
00311     while (!_rxbuf.full() && SerialBase::readable()) {
00312         char data = SerialBase::_base_getc();
00313         _rxbuf.push(data);
00314     }
00315 
00316     if (_rx_irq_enabled && _rxbuf.full()) {
00317         SerialBase::attach(NULL, RxIrq);
00318         _rx_irq_enabled = false;
00319     }
00320 
00321     /* Report the File handler that data is ready to be read from the buffer. */
00322     if (was_empty && !_rxbuf.empty()) {
00323         wake();
00324     }
00325 }
00326 
00327 // Also called from write to start transfer
00328 void UARTSerial::tx_irq(void)
00329 {
00330     bool was_full = _txbuf.full();
00331     char data;
00332 
00333     /* Write to the peripheral if there is something to write
00334      * and if the peripheral is available to write. */
00335     while (SerialBase::writeable() && _txbuf.pop(data)) {
00336         SerialBase::_base_putc(data);
00337     }
00338 
00339     if (_tx_irq_enabled && _txbuf.empty()) {
00340         SerialBase::attach(NULL, TxIrq);
00341         _tx_irq_enabled = false;
00342     }
00343 
00344     /* Report the File handler that data can be written to peripheral. */
00345     if (was_full && !_txbuf.full() && !hup()) {
00346         wake();
00347     }
00348 }
00349 
00350 void UARTSerial::wait_ms(uint32_t millisec)
00351 {
00352     /* wait_ms implementation for RTOS spins until exact microseconds - we
00353      * want to just sleep until next tick.
00354      */
00355 #if MBED_CONF_RTOS_PRESENT
00356     rtos::ThisThread::sleep_for(millisec);
00357 #else
00358     ::wait_ms(millisec);
00359 #endif
00360 }
00361 } //namespace mbed
00362 
00363 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)