a

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UARTSerial_mio.cpp Source File

UARTSerial_mio.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 "UARTSerial_mio.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_mio::UARTSerial_mio(PinName tx, PinName rx, int baud) :
00032     SerialBase(tx, rx, baud),
00033     _blocking(true),
00034     _tx_irq_enabled(false),
00035     _rx_irq_enabled(false),
00036     _tx_enabled(true),
00037     _rx_enabled(true),
00038     _dcd_irq(NULL)
00039 {
00040     /* Attatch IRQ routines to the serial device. */
00041     enable_rx_irq();
00042 }
00043 
00044 UARTSerial_mio::~UARTSerial_mio()
00045 {
00046     delete _dcd_irq;
00047 }
00048 
00049 void UARTSerial_mio::dcd_irq()
00050 {
00051     wake();
00052 }
00053 
00054 void UARTSerial_mio::set_baud(int baud)
00055 {
00056     SerialBase::baud(baud);
00057 }
00058 
00059 void UARTSerial_mio::set_format(int bits, Parity parity, int stop_bits)
00060 {
00061     api_lock();
00062     SerialBase::format(bits, parity, stop_bits);
00063     api_unlock();
00064 }
00065 
00066 #if DEVICE_SERIAL_FC
00067 void UARTSerial_mio::set_flow_control(Flow type, PinName flow1, PinName flow2)
00068 {
00069     api_lock();
00070     SerialBase::set_flow_control(type, flow1, flow2);
00071     api_unlock();
00072 }
00073 #endif
00074 
00075 int UARTSerial_mio::close(){return 0;}
00076 
00077 int UARTSerial_mio::isatty(){return 1;}
00078 
00079 
00080 off_t UARTSerial_mio::seek(off_t offset, int whence)
00081 {
00082     /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
00083      * buffer system (from an interrupt context) */
00084     return -ESPIPE;
00085 }
00086 
00087 int UARTSerial_mio::sync()
00088 {
00089     api_lock();
00090     while (!_txbuf.empty()) {
00091         api_unlock();
00092         // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
00093         wait_us(500);
00094         api_lock();
00095     }
00096     
00097     api_unlock();
00098 
00099     return 0;
00100 }
00101 
00102 int UARTSerial_mio::flush()
00103 {
00104     api_lock();
00105     char c;
00106 
00107     while (!_rxbuf.empty()) {
00108         api_unlock();
00109         // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
00110         wait_us(500);
00111         _rxbuf.pop(c);
00112         api_lock();
00113     }
00114 
00115     api_unlock();
00116 
00117     return 0;
00118 }
00119 
00120 void UARTSerial_mio::sigio(Callback<void()> func)
00121 {
00122     core_util_critical_section_enter();
00123     _sigio_cb = func;
00124     if (_sigio_cb) {
00125         short current_events = poll(0x7FFF);
00126         if (current_events) {
00127             _sigio_cb();
00128         }
00129     }
00130     core_util_critical_section_exit();
00131 }
00132 
00133 /* Special synchronous write designed to work from critical section, such
00134  * as in mbed_error_vprintf.
00135  */
00136 ssize_t UARTSerial_mio::write_unbuffered(const char *buf_ptr, size_t length)
00137 {
00138     while (!_txbuf.empty()) {
00139         tx_irq();
00140     }
00141 
00142     for (size_t data_written = 0; data_written < length; data_written++) {
00143         SerialBase::_base_putc(*buf_ptr++);
00144     }
00145 
00146     return length;
00147 }
00148 
00149 ssize_t UARTSerial_mio::write(const void *buffer, size_t length)
00150 {
00151     size_t data_written = 0;
00152     const char *buf_ptr = static_cast<const char *>(buffer);
00153 
00154     if (length == 0) {
00155         return 0;
00156     }
00157 
00158     if (core_util_in_critical_section()) {
00159         return write_unbuffered(buf_ptr, length);
00160     }
00161 
00162     api_lock();
00163 
00164     // Unlike read, we should write the whole thing if blocking. POSIX only
00165     // allows partial as a side-effect of signal handling; it normally tries to
00166     // write everything if blocking. Without signals we can always write all.
00167     while (data_written < length) {
00168 
00169         if (_txbuf.full()) {
00170             if (!_blocking) {
00171                 break;
00172             }
00173             do {
00174                 api_unlock();
00175                 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
00176                 api_lock();
00177             } while (_txbuf.full());
00178         }
00179 
00180         while (data_written < length && !_txbuf.full()) {
00181             _txbuf.push(*buf_ptr++);
00182             data_written++;
00183         }
00184 
00185         core_util_critical_section_enter();
00186         if (_tx_enabled && !_tx_irq_enabled) {
00187             UARTSerial_mio::tx_irq();                // only write to hardware in one place
00188             if (!_txbuf.empty()) {
00189                 enable_tx_irq();
00190             }
00191         }
00192         core_util_critical_section_exit();
00193     }
00194 
00195     api_unlock();
00196 
00197     return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN;
00198 }
00199 
00200 ssize_t UARTSerial_mio::read(void *buffer, size_t length)
00201 {
00202     size_t data_read = 0;
00203     
00204     float timeout = 1.0; //ms
00205     float tm = 0.0;
00206 
00207     char *ptr = static_cast<char *>(buffer);
00208 
00209     if (length == 0) {
00210         return 0;
00211     }
00212 
00213     api_lock();
00214 
00215     while (_rxbuf.size()!=length && tm <= timeout) {
00216         if (!_blocking) {
00217             api_unlock();
00218             return -EAGAIN;
00219         }
00220         api_unlock();
00221         wait_us(10);  // XXX todo - proper wait, WFE for non-rtos ?
00222         api_lock();
00223         tm = tm + 0.01; //10/1000
00224     }
00225 
00226     while (data_read < length && !_rxbuf.empty()) {
00227         _rxbuf.pop(*ptr++);
00228         data_read++;
00229     }
00230 
00231     core_util_critical_section_enter();
00232     if (_rx_enabled && !_rx_irq_enabled) {
00233         UARTSerial_mio::rx_irq();               // only read from hardware in one place
00234         if (!_rxbuf.full()) {
00235             enable_rx_irq();
00236         }
00237     }
00238     core_util_critical_section_exit();
00239 
00240     api_unlock();
00241 
00242     return data_read;
00243 }
00244 
00245 ssize_t UARTSerial_mio::read_timeout(void *buffer, size_t length, double _timeOut)
00246 {
00247     size_t data_read = 0;
00248     
00249     double timeout = _timeOut; //ms
00250     double tm = 0.0;
00251 
00252     char *ptr = static_cast<char *>(buffer);
00253 
00254     if (length == 0) {
00255         return 0;
00256     }
00257 
00258     api_lock();
00259 
00260     while (_rxbuf.size()!=length && tm<=timeout) {
00261         if (!_blocking) {
00262             api_unlock();
00263             return -EAGAIN;
00264         }
00265         api_unlock();
00266         wait_us(1);  // XXX todo - proper wait, WFE for non-rtos ?
00267         api_lock();
00268         tm = tm + 0.001; //10/1000
00269         
00270     }
00271     
00272     //printf("tm: %f\r\n",tm);
00273     tm = 0.0;
00274     while (data_read < length && !_rxbuf.empty()  && tm<=timeout) {
00275         _rxbuf.pop(*ptr++);
00276         data_read++;
00277         tm = tm + 0.001; //10/1000
00278     }
00279 
00280     core_util_critical_section_enter();
00281     if (_rx_enabled && !_rx_irq_enabled) {
00282         UARTSerial_mio::rx_irq();               // only read from hardware in one place
00283         if (!_rxbuf.full()) {
00284             enable_rx_irq();
00285         }
00286     }
00287     core_util_critical_section_exit();
00288 
00289     api_unlock();
00290 
00291     return data_read;
00292 }
00293 
00294 bool UARTSerial_mio::hup() const
00295 {
00296     return _dcd_irq && _dcd_irq->read() != 0;
00297 }
00298 
00299 void UARTSerial_mio::wake()
00300 {
00301     if (_sigio_cb) {
00302         _sigio_cb();
00303     }
00304 }
00305 
00306 short UARTSerial_mio::poll(short events) const
00307 {
00308 
00309     short revents = 0;
00310     /* Check the Circular Buffer if space available for writing out */
00311 
00312 
00313     if (!_rxbuf.empty()) {
00314         revents |= POLLIN;
00315     }
00316 
00317     /* POLLHUP and POLLOUT are mutually exclusive */
00318     if (hup()) {
00319         revents |= POLLHUP;
00320     } else if (!_txbuf.full()) {
00321         revents |= POLLOUT;
00322     }
00323 
00324     /*TODO Handle other event types */
00325 
00326     return revents;
00327 }
00328 
00329 void UARTSerial_mio::lock()
00330 {
00331     // This is the override for SerialBase.
00332     // No lock required as we only use SerialBase from interrupt or from
00333     // inside our own critical section.
00334 }
00335 
00336 void UARTSerial_mio::unlock()
00337 {
00338     // This is the override for SerialBase.
00339 }
00340 
00341 void UARTSerial_mio::api_lock(void)
00342 {
00343     //_mutex.lock();
00344 }
00345 
00346 void UARTSerial_mio::api_unlock(void)
00347 {
00348     //_mutex.unlock();
00349 }
00350 
00351 void UARTSerial_mio::rx_irq(void)
00352 {
00353     bool was_empty = _rxbuf.empty();
00354 
00355     /* Fill in the receive buffer if the peripheral is readable
00356      * and receive buffer is not full. */
00357     while (!_rxbuf.full() && SerialBase::readable()) {
00358         char data = SerialBase::_base_getc();
00359         _rxbuf.push(data);
00360     }
00361 
00362     if (_rx_irq_enabled && _rxbuf.full()) {
00363         disable_rx_irq();
00364     }
00365 
00366     /* Report the File handler that data is ready to be read from the buffer. */
00367     if (was_empty && !_rxbuf.empty()) {
00368         wake();
00369     }
00370 }
00371 
00372 // Also called from write to start transfer
00373 void UARTSerial_mio::tx_irq(void)
00374 {
00375     bool was_full = _txbuf.full();
00376     char data;
00377 
00378     /* Write to the peripheral if there is something to write
00379      * and if the peripheral is available to write. */
00380     while (SerialBase::writeable() && _txbuf.pop(data)) {
00381         SerialBase::_base_putc(data);
00382     }
00383 
00384     if (_tx_irq_enabled && _txbuf.empty()) {
00385         disable_tx_irq();
00386     }
00387 
00388     /* Report the File handler that data can be written to peripheral. */
00389     if (was_full && !_txbuf.full() && !hup()) {
00390         wake();
00391     }
00392 }
00393 
00394 /* These are all called from critical section */
00395 void UARTSerial_mio::enable_rx_irq()
00396 {
00397     SerialBase::attach(callback(this, &UARTSerial_mio::rx_irq), RxIrq);
00398     _rx_irq_enabled = true;
00399 }
00400 
00401 void UARTSerial_mio::disable_rx_irq()
00402 {
00403     SerialBase::attach(NULL, RxIrq);
00404     _rx_irq_enabled = false;
00405 }
00406 
00407 void UARTSerial_mio::enable_tx_irq()
00408 {
00409     SerialBase::attach(callback(this, &UARTSerial_mio::tx_irq), TxIrq);
00410     _tx_irq_enabled = true;
00411 }
00412 
00413 void UARTSerial_mio::disable_tx_irq()
00414 {
00415     SerialBase::attach(NULL, TxIrq);
00416     _tx_irq_enabled = false;
00417 }
00418 
00419 int UARTSerial_mio::enable_input(bool enabled)
00420 {
00421     core_util_critical_section_enter();
00422     if (_rx_enabled != enabled) {
00423         if (enabled) {
00424             UARTSerial_mio::rx_irq();
00425             if (!_rxbuf.full()) {
00426                 enable_rx_irq();
00427             }
00428         } else {
00429             disable_rx_irq();
00430         }
00431         _rx_enabled = enabled;
00432     }
00433     core_util_critical_section_exit();
00434 
00435     return 0;
00436 }
00437 
00438 int UARTSerial_mio::enable_output(bool enabled)
00439 {
00440     core_util_critical_section_enter();
00441     if (_tx_enabled != enabled) {
00442         if (enabled) {
00443             UARTSerial_mio::tx_irq();
00444             if (!_txbuf.empty()) {
00445                 enable_tx_irq();
00446             }
00447         } else {
00448             disable_tx_irq();
00449         }
00450         _tx_enabled = enabled;
00451     }
00452     core_util_critical_section_exit();
00453 
00454     return 0;
00455 }
00456 
00457 void UARTSerial_mio::wait_ms(uint32_t millisec)
00458 {
00459     /* wait_ms implementation for RTOS spins until exact microseconds - we
00460      * want to just sleep until next tick.
00461      */
00462 #if MBED_CONF_RTOS_PRESENT
00463     rtos::ThisThread::sleep_for(millisec);
00464 #else
00465     ::wait_ms(millisec);
00466 #endif
00467 }
00468 
00469 void UARTSerial_mio::wait_us(uint32_t microseconds)
00470 {
00471     /* wait_ms implementation for RTOS spins until exact microseconds - we
00472      * want to just sleep until next tick.
00473      */
00474 #if MBED_CONF_RTOS_PRESENT
00475     rtos::ThisThread::sleep_for(microseconds/1000);
00476 #else
00477     ::wait_us(microseconds);
00478 #endif
00479 }
00480 } //namespace mbed
00481 
00482 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)