Lee Shen / FTHR_USB_serial_qSPI
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 
00017 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN)
00018 
00019 #include <errno.h>
00020 #include "UARTSerial.h"
00021 #include "platform/mbed_poll.h"
00022 
00023 #if MBED_CONF_RTOS_PRESENT
00024 #include "rtos/Thread.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         _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 int UARTSerial::close()
00072 {
00073     /* Does not let us pass a file descriptor. So how to close ?
00074      * Also, does it make sense to close a device type file descriptor*/
00075     return 0;
00076 }
00077 
00078 int UARTSerial::isatty()
00079 {
00080     return 1;
00081 
00082 }
00083 
00084 off_t UARTSerial::seek(off_t offset, int whence)
00085 {
00086     /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking
00087      * buffer system (from an interrupt context) */
00088     return -ESPIPE;
00089 }
00090 
00091 int UARTSerial::sync()
00092 {
00093     api_lock();
00094 
00095     while (!_txbuf.empty()) {
00096         api_unlock();
00097         // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it?
00098         wait_ms(1);
00099         api_lock();
00100     }
00101 
00102     api_unlock();
00103 
00104     return 0;
00105 }
00106 
00107 void UARTSerial::sigio(Callback<void()> func) {
00108     core_util_critical_section_enter();
00109     _sigio_cb = func;
00110     if (_sigio_cb) {
00111         short current_events = poll(0x7FFF);
00112         if (current_events) {
00113             _sigio_cb();
00114         }
00115     }
00116     core_util_critical_section_exit();
00117 }
00118 
00119 ssize_t UARTSerial::write(const void* buffer, size_t length)
00120 {
00121     size_t data_written = 0;
00122     const char *buf_ptr = static_cast<const char *>(buffer);
00123 
00124     api_lock();
00125 
00126     while (_txbuf.full()) {
00127         if (!_blocking) {
00128             api_unlock();
00129             return -EAGAIN;
00130         }
00131         api_unlock();
00132         wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ?
00133         api_lock();
00134     }
00135 
00136     while (data_written < length && !_txbuf.full()) {
00137         _txbuf.push(*buf_ptr++);
00138         data_written++;
00139     }
00140 
00141     core_util_critical_section_enter();
00142     if (!_tx_irq_enabled) {
00143         UARTSerial::tx_irq();                // only write to hardware in one place
00144         if (!_txbuf.empty()) {
00145             SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq);
00146             _tx_irq_enabled = true;
00147         }
00148     }
00149     core_util_critical_section_exit();
00150 
00151     api_unlock();
00152 
00153     return data_written;
00154 }
00155 
00156 ssize_t UARTSerial::read(void* buffer, size_t length)
00157 {
00158     size_t data_read = 0;
00159 
00160     char *ptr = static_cast<char *>(buffer);
00161 
00162     api_lock();
00163 
00164     while (_rxbuf.empty()) {
00165         if (!_blocking) {
00166             api_unlock();
00167             return -EAGAIN;
00168         }
00169         api_unlock();
00170         wait_ms(1);  // XXX todo - proper wait, WFE for non-rtos ?
00171         api_lock();
00172     }
00173 
00174     while (data_read < length && !_rxbuf.empty()) {
00175         _rxbuf.pop(*ptr++);
00176         data_read++;
00177     }
00178 
00179     api_unlock();
00180 
00181     return data_read;
00182 }
00183 
00184 bool UARTSerial::hup() const
00185 {
00186     return _dcd_irq && _dcd_irq->read() != 0;
00187 }
00188 
00189 void UARTSerial::wake()
00190 {
00191     if (_sigio_cb) {
00192         _sigio_cb();
00193     }
00194 }
00195 
00196 short UARTSerial::poll(short events) const {
00197 
00198     short revents = 0;
00199     /* Check the Circular Buffer if space available for writing out */
00200 
00201 
00202     if (!_rxbuf.empty()) {
00203         revents |= POLLIN;
00204     }
00205 
00206     /* POLLHUP and POLLOUT are mutually exclusive */
00207     if (hup()) {
00208         revents |= POLLHUP;
00209     } else if (!_txbuf.full()) {
00210         revents |= POLLOUT;
00211     }
00212 
00213     /*TODO Handle other event types */
00214 
00215     return revents;
00216 }
00217 
00218 void UARTSerial::lock()
00219 {
00220     // This is the override for SerialBase.
00221     // No lock required as we only use SerialBase from interrupt or from
00222     // inside our own critical section.
00223 }
00224 
00225 void UARTSerial::unlock()
00226 {
00227     // This is the override for SerialBase.
00228 }
00229 
00230 void UARTSerial::api_lock(void)
00231 {
00232     _mutex.lock();
00233 }
00234 
00235 void UARTSerial::api_unlock(void)
00236 {
00237     _mutex.unlock();
00238 }
00239 
00240 void UARTSerial::rx_irq(void)
00241 {
00242     bool was_empty = _rxbuf.empty();
00243 
00244     /* Fill in the receive buffer if the peripheral is readable
00245      * and receive buffer is not full. */
00246     while (SerialBase::readable()) {
00247         char data = SerialBase::_base_getc();
00248         if (!_rxbuf.full()) {
00249             _rxbuf.push(data);
00250         } else {
00251             /* Drop - can we report in some way? */
00252         }
00253     }
00254 
00255     /* Report the File handler that data is ready to be read from the buffer. */
00256     if (was_empty && !_rxbuf.empty()) {
00257         wake();
00258     }
00259 }
00260 
00261 // Also called from write to start transfer
00262 void UARTSerial::tx_irq(void)
00263 {
00264     bool was_full = _txbuf.full();
00265 
00266     /* Write to the peripheral if there is something to write
00267      * and if the peripheral is available to write. */
00268     while (!_txbuf.empty() && SerialBase::writeable()) {
00269         char data;
00270         _txbuf.pop(data);
00271         SerialBase::_base_putc(data);
00272     }
00273 
00274     if (_tx_irq_enabled && _txbuf.empty()) {
00275         SerialBase::attach(NULL, TxIrq);
00276         _tx_irq_enabled = false;
00277     }
00278 
00279     /* Report the File handler that data can be written to peripheral. */
00280     if (was_full && !_txbuf.full() && !hup()) {
00281         wake();
00282     }
00283 }
00284 
00285 void UARTSerial::wait_ms(uint32_t millisec)
00286 {
00287     /* wait_ms implementation for RTOS spins until exact microseconds - we
00288      * want to just sleep until next tick.
00289      */
00290 #if MBED_CONF_RTOS_PRESENT
00291     rtos::Thread::wait(millisec);
00292 #else
00293     ::wait_ms(millisec);
00294 #endif
00295 }
00296 } //namespace mbed
00297 
00298 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)