Kenji Arai / TYBLE16_mbedlized_os5_several_examples_1st

Dependencies:   nRF51_Vdd TextLCD BME280

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