Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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-2019 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 #include "platform/mbed_thread.h"
00023 
00024 namespace mbed {
00025 
00026 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
00027     SerialBase(tx, rx, baud),
00028     _blocking(true),
00029     _tx_irq_enabled(false),
00030     _rx_irq_enabled(false),
00031     _tx_enabled(true),
00032     _rx_enabled(true),
00033     _dcd_irq(NULL)
00034 {
00035     /* Attatch IRQ routines to the serial device. */
00036     enable_rx_irq();
00037 }
00038 
00039 UARTSerial::UARTSerial(const serial_pinmap_t &static_pinmap, int baud) :
00040     SerialBase(static_pinmap, baud),
00041     _blocking(true),
00042     _tx_irq_enabled(false),
00043     _rx_irq_enabled(false),
00044     _tx_enabled(true),
00045     _rx_enabled(true),
00046     _dcd_irq(NULL)
00047 {
00048     /* Attatch IRQ routines to the serial device. */
00049     enable_rx_irq();
00050 }
00051 
00052 UARTSerial::~UARTSerial()
00053 {
00054     delete _dcd_irq;
00055 }
00056 
00057 void UARTSerial::dcd_irq()
00058 {
00059     wake();
00060 }
00061 
00062 void UARTSerial::set_baud(int baud)
00063 {
00064     SerialBase::baud(baud);
00065 }
00066 
00067 void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
00068 {
00069     delete _dcd_irq;
00070     _dcd_irq = NULL;
00071 
00072     if (dcd_pin != NC) {
00073         _dcd_irq = new InterruptIn(dcd_pin);
00074         if (active_high) {
00075             _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq));
00076         } else {
00077             _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq));
00078         }
00079     }
00080 }
00081 
00082 void UARTSerial::set_format(int bits, Parity parity, int stop_bits)
00083 {
00084     api_lock();
00085     SerialBase::format(bits, parity, stop_bits);
00086     api_unlock();
00087 }
00088 
00089 #if DEVICE_SERIAL_FC
00090 void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2)
00091 {
00092     api_lock();
00093     SerialBase::set_flow_control(type, flow1, flow2);
00094     api_unlock();
00095 }
00096 #endif
00097 
00098 int UARTSerial::close()
00099 {
00100     /* Does not let us pass a file descriptor. So how to close ?
00101      * Also, does it make sense to close a device type file descriptor*/
00102     return 0;
00103 }
00104 
00105 int UARTSerial::isatty()
00106 {
00107     return 1;
00108 
00109 }
00110 
00111 off_t UARTSerial::seek(off_t offset, int whence)
00112 {
00113     /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
00114      * buffer system (from an interrupt context) */
00115     return -ESPIPE;
00116 }
00117 
00118 int UARTSerial::sync()
00119 {
00120     api_lock();
00121 
00122     while (!_txbuf.empty()) {
00123         api_unlock();
00124         // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
00125         thread_sleep_for(1);
00126         api_lock();
00127     }
00128 
00129     api_unlock();
00130 
00131     return 0;
00132 }
00133 
00134 void UARTSerial::sigio(Callback<void()> func)
00135 {
00136     core_util_critical_section_enter();
00137     _sigio_cb = func;
00138     if (_sigio_cb) {
00139         short current_events = poll(0x7FFF);
00140         if (current_events) {
00141             _sigio_cb();
00142         }
00143     }
00144     core_util_critical_section_exit();
00145 }
00146 
00147 /* Special synchronous write designed to work from critical section, such
00148  * as in mbed_error_vprintf.
00149  */
00150 ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
00151 {
00152     while (!_txbuf.empty()) {
00153         tx_irq();
00154     }
00155 
00156     for (size_t data_written = 0; data_written < length; data_written++) {
00157         SerialBase::_base_putc(*buf_ptr++);
00158     }
00159 
00160     return length;
00161 }
00162 
00163 ssize_t UARTSerial::write(const void *buffer, size_t length)
00164 {
00165     size_t data_written = 0;
00166     const char *buf_ptr = static_cast<const char *>(buffer);
00167 
00168     if (length == 0) {
00169         return 0;
00170     }
00171 
00172     if (core_util_in_critical_section()) {
00173         return write_unbuffered(buf_ptr, length);
00174     }
00175 
00176     api_lock();
00177 
00178     // Unlike read, we should write the whole thing if blocking. POSIX only
00179     // allows partial as a side-effect of signal handling; it normally tries to
00180     // write everything if blocking. Without signals we can always write all.
00181     while (data_written < length) {
00182 
00183         if (_txbuf.full()) {
00184             if (!_blocking) {
00185                 break;
00186             }
00187             do {
00188                 api_unlock();
00189                 thread_sleep_for(1); // XXX todo - proper wait?
00190                 api_lock();
00191             } while (_txbuf.full());
00192         }
00193 
00194         while (data_written < length && !_txbuf.full()) {
00195             _txbuf.push(*buf_ptr++);
00196             data_written++;
00197         }
00198 
00199         core_util_critical_section_enter();
00200         if (_tx_enabled && !_tx_irq_enabled) {
00201             UARTSerial::tx_irq();                // only write to hardware in one place
00202             if (!_txbuf.empty()) {
00203                 enable_tx_irq();
00204             }
00205         }
00206         core_util_critical_section_exit();
00207     }
00208 
00209     api_unlock();
00210 
00211     return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
00212 }
00213 
00214 ssize_t UARTSerial::read(void *buffer, size_t length)
00215 {
00216     size_t data_read = 0;
00217 
00218     char *ptr = static_cast<char *>(buffer);
00219 
00220     if (length == 0) {
00221         return 0;
00222     }
00223 
00224     api_lock();
00225 
00226     while (_rxbuf.empty()) {
00227         if (!_blocking) {
00228             api_unlock();
00229             return -EAGAIN;
00230         }
00231         api_unlock();
00232         thread_sleep_for(1);  // XXX todo - proper wait?
00233         api_lock();
00234     }
00235 
00236     while (data_read < length && !_rxbuf.empty()) {
00237         _rxbuf.pop(*ptr++);
00238         data_read++;
00239     }
00240 
00241     core_util_critical_section_enter();
00242     if (_rx_enabled && !_rx_irq_enabled) {
00243         UARTSerial::rx_irq();               // only read from hardware in one place
00244         if (!_rxbuf.full()) {
00245             enable_rx_irq();
00246         }
00247     }
00248     core_util_critical_section_exit();
00249 
00250     api_unlock();
00251 
00252     return data_read;
00253 }
00254 
00255 bool UARTSerial::hup() const
00256 {
00257     return _dcd_irq && _dcd_irq->read() != 0;
00258 }
00259 
00260 void UARTSerial::wake()
00261 {
00262     if (_sigio_cb) {
00263         _sigio_cb();
00264     }
00265 }
00266 
00267 short UARTSerial::poll(short events) const
00268 {
00269 
00270     short revents = 0;
00271     /* Check the Circular Buffer if space available for writing out */
00272 
00273 
00274     if (!_rxbuf.empty()) {
00275         revents |= POLLIN;
00276     }
00277 
00278     /* POLLHUP and POLLOUT are mutually exclusive */
00279     if (hup()) {
00280         revents |= POLLHUP;
00281     } else if (!_txbuf.full()) {
00282         revents |= POLLOUT;
00283     }
00284 
00285     /*TODO Handle other event types */
00286 
00287     return revents;
00288 }
00289 
00290 void UARTSerial::lock()
00291 {
00292     // This is the override for SerialBase.
00293     // No lock required as we only use SerialBase from interrupt or from
00294     // inside our own critical section.
00295 }
00296 
00297 void UARTSerial::unlock()
00298 {
00299     // This is the override for SerialBase.
00300 }
00301 
00302 void UARTSerial::api_lock(void)
00303 {
00304     _mutex.lock();
00305 }
00306 
00307 void UARTSerial::api_unlock(void)
00308 {
00309     _mutex.unlock();
00310 }
00311 
00312 void UARTSerial::rx_irq(void)
00313 {
00314     bool was_empty = _rxbuf.empty();
00315 
00316     /* Fill in the receive buffer if the peripheral is readable
00317      * and receive buffer is not full. */
00318     while (!_rxbuf.full() && SerialBase::readable()) {
00319         char data = SerialBase::_base_getc();
00320         _rxbuf.push(data);
00321     }
00322 
00323     if (_rx_irq_enabled && _rxbuf.full()) {
00324         disable_rx_irq();
00325     }
00326 
00327     /* Report the File handler that data is ready to be read from the buffer. */
00328     if (was_empty && !_rxbuf.empty()) {
00329         wake();
00330     }
00331 }
00332 
00333 // Also called from write to start transfer
00334 void UARTSerial::tx_irq(void)
00335 {
00336     bool was_full = _txbuf.full();
00337     char data;
00338 
00339     /* Write to the peripheral if there is something to write
00340      * and if the peripheral is available to write. */
00341     while (SerialBase::writeable() && _txbuf.pop(data)) {
00342         SerialBase::_base_putc(data);
00343     }
00344 
00345     if (_tx_irq_enabled && _txbuf.empty()) {
00346         disable_tx_irq();
00347     }
00348 
00349     /* Report the File handler that data can be written to peripheral. */
00350     if (was_full && !_txbuf.full() && !hup()) {
00351         wake();
00352     }
00353 }
00354 
00355 /* These are all called from critical section */
00356 void UARTSerial::enable_rx_irq()
00357 {
00358     SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
00359     _rx_irq_enabled = true;
00360 }
00361 
00362 void UARTSerial::disable_rx_irq()
00363 {
00364     SerialBase::attach(NULL, RxIrq);
00365     _rx_irq_enabled = false;
00366 }
00367 
00368 void UARTSerial::enable_tx_irq()
00369 {
00370     SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
00371     _tx_irq_enabled = true;
00372 }
00373 
00374 void UARTSerial::disable_tx_irq()
00375 {
00376     SerialBase::attach(NULL, TxIrq);
00377     _tx_irq_enabled = false;
00378 }
00379 
00380 int UARTSerial::enable_input(bool enabled)
00381 {
00382     api_lock();
00383     SerialBase::enable_input(enabled);
00384     api_unlock();
00385 
00386     return 0;
00387 }
00388 
00389 int UARTSerial::enable_output(bool enabled)
00390 {
00391     api_lock();
00392     SerialBase::enable_output(enabled);
00393     api_unlock();
00394 
00395     return 0;
00396 }
00397 
00398 } //namespace mbed
00399 
00400 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)