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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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)
Generated on Tue Jul 12 2022 13:55:01 by
