Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 _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 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 api_lock(); 00142 00143 while (_txbuf.full()) { 00144 if (!_blocking) { 00145 api_unlock(); 00146 return -EAGAIN; 00147 } 00148 api_unlock(); 00149 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00150 api_lock(); 00151 } 00152 00153 while (data_written < length && !_txbuf.full()) { 00154 _txbuf.push(*buf_ptr++); 00155 data_written++; 00156 } 00157 00158 core_util_critical_section_enter(); 00159 if (!_tx_irq_enabled) { 00160 UARTSerial::tx_irq(); // only write to hardware in one place 00161 if (!_txbuf.empty()) { 00162 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); 00163 _tx_irq_enabled = true; 00164 } 00165 } 00166 core_util_critical_section_exit(); 00167 00168 api_unlock(); 00169 00170 return data_written; 00171 } 00172 00173 ssize_t UARTSerial::read(void* buffer, size_t length) 00174 { 00175 size_t data_read = 0; 00176 00177 char *ptr = static_cast<char *>(buffer); 00178 00179 api_lock(); 00180 00181 while (_rxbuf.empty()) { 00182 if (!_blocking) { 00183 api_unlock(); 00184 return -EAGAIN; 00185 } 00186 api_unlock(); 00187 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00188 api_lock(); 00189 } 00190 00191 while (data_read < length && !_rxbuf.empty()) { 00192 _rxbuf.pop(*ptr++); 00193 data_read++; 00194 } 00195 00196 core_util_critical_section_enter(); 00197 if (!_rx_irq_enabled) { 00198 UARTSerial::rx_irq(); // only read from hardware in one place 00199 if (!_rxbuf.full()) { 00200 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); 00201 _rx_irq_enabled = true; 00202 } 00203 } 00204 core_util_critical_section_exit(); 00205 00206 api_unlock(); 00207 00208 return data_read; 00209 } 00210 00211 bool UARTSerial::hup() const 00212 { 00213 return _dcd_irq && _dcd_irq->read() != 0; 00214 } 00215 00216 void UARTSerial::wake() 00217 { 00218 if (_sigio_cb) { 00219 _sigio_cb(); 00220 } 00221 } 00222 00223 short UARTSerial::poll(short events) const { 00224 00225 short revents = 0; 00226 /* Check the Circular Buffer if space available for writing out */ 00227 00228 00229 if (!_rxbuf.empty()) { 00230 revents |= POLLIN; 00231 } 00232 00233 /* POLLHUP and POLLOUT are mutually exclusive */ 00234 if (hup()) { 00235 revents |= POLLHUP; 00236 } else if (!_txbuf.full()) { 00237 revents |= POLLOUT; 00238 } 00239 00240 /*TODO Handle other event types */ 00241 00242 return revents; 00243 } 00244 00245 void UARTSerial::lock() 00246 { 00247 // This is the override for SerialBase. 00248 // No lock required as we only use SerialBase from interrupt or from 00249 // inside our own critical section. 00250 } 00251 00252 void UARTSerial::unlock() 00253 { 00254 // This is the override for SerialBase. 00255 } 00256 00257 void UARTSerial::api_lock(void) 00258 { 00259 _mutex.lock(); 00260 } 00261 00262 void UARTSerial::api_unlock(void) 00263 { 00264 _mutex.unlock(); 00265 } 00266 00267 void UARTSerial::rx_irq(void) 00268 { 00269 bool was_empty = _rxbuf.empty(); 00270 00271 /* Fill in the receive buffer if the peripheral is readable 00272 * and receive buffer is not full. */ 00273 while (!_rxbuf.full() && SerialBase::readable()) { 00274 char data = SerialBase::_base_getc(); 00275 _rxbuf.push(data); 00276 } 00277 00278 if (_rx_irq_enabled && _rxbuf.full()) { 00279 SerialBase::attach(NULL, RxIrq); 00280 _rx_irq_enabled = false; 00281 } 00282 00283 /* Report the File handler that data is ready to be read from the buffer. */ 00284 if (was_empty && !_rxbuf.empty()) { 00285 wake(); 00286 } 00287 } 00288 00289 // Also called from write to start transfer 00290 void UARTSerial::tx_irq(void) 00291 { 00292 bool was_full = _txbuf.full(); 00293 00294 /* Write to the peripheral if there is something to write 00295 * and if the peripheral is available to write. */ 00296 while (!_txbuf.empty() && SerialBase::writeable()) { 00297 char data; 00298 _txbuf.pop(data); 00299 SerialBase::_base_putc(data); 00300 } 00301 00302 if (_tx_irq_enabled && _txbuf.empty()) { 00303 SerialBase::attach(NULL, TxIrq); 00304 _tx_irq_enabled = false; 00305 } 00306 00307 /* Report the File handler that data can be written to peripheral. */ 00308 if (was_full && !_txbuf.full() && !hup()) { 00309 wake(); 00310 } 00311 } 00312 00313 void UARTSerial::wait_ms(uint32_t millisec) 00314 { 00315 /* wait_ms implementation for RTOS spins until exact microseconds - we 00316 * want to just sleep until next tick. 00317 */ 00318 #if MBED_CONF_RTOS_PRESENT 00319 rtos::Thread::wait(millisec); 00320 #else 00321 ::wait_ms(millisec); 00322 #endif 00323 } 00324 } //namespace mbed 00325 00326 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
Generated on Thu Jul 14 2022 14:36:23 by
