mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
UARTSerial.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 "drivers/UARTSerial.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::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 { 00126 core_util_critical_section_enter(); 00127 _sigio_cb = func; 00128 if (_sigio_cb) { 00129 short current_events = poll(0x7FFF); 00130 if (current_events) { 00131 _sigio_cb(); 00132 } 00133 } 00134 core_util_critical_section_exit(); 00135 } 00136 00137 /* Special synchronous write designed to work from critical section, such 00138 * as in mbed_error_vprintf. 00139 */ 00140 ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length) 00141 { 00142 while (!_txbuf.empty()) { 00143 tx_irq(); 00144 } 00145 00146 for (size_t data_written = 0; data_written < length; data_written++) { 00147 SerialBase::_base_putc(*buf_ptr++); 00148 data_written++; 00149 } 00150 00151 return length; 00152 } 00153 00154 ssize_t UARTSerial::write(const void *buffer, size_t length) 00155 { 00156 size_t data_written = 0; 00157 const char *buf_ptr = static_cast<const char *>(buffer); 00158 00159 if (length == 0) { 00160 return 0; 00161 } 00162 00163 if (core_util_in_critical_section()) { 00164 return write_unbuffered(buf_ptr, length); 00165 } 00166 00167 api_lock(); 00168 00169 // Unlike read, we should write the whole thing if blocking. POSIX only 00170 // allows partial as a side-effect of signal handling; it normally tries to 00171 // write everything if blocking. Without signals we can always write all. 00172 while (data_written < length) { 00173 00174 if (_txbuf.full()) { 00175 if (!_blocking) { 00176 break; 00177 } 00178 do { 00179 api_unlock(); 00180 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00181 api_lock(); 00182 } while (_txbuf.full()); 00183 } 00184 00185 while (data_written < length && !_txbuf.full()) { 00186 _txbuf.push(*buf_ptr++); 00187 data_written++; 00188 } 00189 00190 core_util_critical_section_enter(); 00191 if (!_tx_irq_enabled) { 00192 UARTSerial::tx_irq(); // only write to hardware in one place 00193 if (!_txbuf.empty()) { 00194 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); 00195 _tx_irq_enabled = true; 00196 } 00197 } 00198 core_util_critical_section_exit(); 00199 } 00200 00201 api_unlock(); 00202 00203 return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN; 00204 } 00205 00206 ssize_t UARTSerial::read(void *buffer, size_t length) 00207 { 00208 size_t data_read = 0; 00209 00210 char *ptr = static_cast<char *>(buffer); 00211 00212 if (length == 0) { 00213 return 0; 00214 } 00215 00216 api_lock(); 00217 00218 while (_rxbuf.empty()) { 00219 if (!_blocking) { 00220 api_unlock(); 00221 return -EAGAIN; 00222 } 00223 api_unlock(); 00224 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00225 api_lock(); 00226 } 00227 00228 while (data_read < length && !_rxbuf.empty()) { 00229 _rxbuf.pop(*ptr++); 00230 data_read++; 00231 } 00232 00233 core_util_critical_section_enter(); 00234 if (!_rx_irq_enabled) { 00235 UARTSerial::rx_irq(); // only read from hardware in one place 00236 if (!_rxbuf.full()) { 00237 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); 00238 _rx_irq_enabled = true; 00239 } 00240 } 00241 core_util_critical_section_exit(); 00242 00243 api_unlock(); 00244 00245 return data_read; 00246 } 00247 00248 bool UARTSerial::hup() const 00249 { 00250 return _dcd_irq && _dcd_irq->read() != 0; 00251 } 00252 00253 void UARTSerial::wake() 00254 { 00255 if (_sigio_cb) { 00256 _sigio_cb(); 00257 } 00258 } 00259 00260 short UARTSerial::poll(short events) const 00261 { 00262 00263 short revents = 0; 00264 /* Check the Circular Buffer if space available for writing out */ 00265 00266 00267 if (!_rxbuf.empty()) { 00268 revents |= POLLIN; 00269 } 00270 00271 /* POLLHUP and POLLOUT are mutually exclusive */ 00272 if (hup()) { 00273 revents |= POLLHUP; 00274 } else if (!_txbuf.full()) { 00275 revents |= POLLOUT; 00276 } 00277 00278 /*TODO Handle other event types */ 00279 00280 return revents; 00281 } 00282 00283 void UARTSerial::lock() 00284 { 00285 // This is the override for SerialBase. 00286 // No lock required as we only use SerialBase from interrupt or from 00287 // inside our own critical section. 00288 } 00289 00290 void UARTSerial::unlock() 00291 { 00292 // This is the override for SerialBase. 00293 } 00294 00295 void UARTSerial::api_lock(void) 00296 { 00297 _mutex.lock(); 00298 } 00299 00300 void UARTSerial::api_unlock(void) 00301 { 00302 _mutex.unlock(); 00303 } 00304 00305 void UARTSerial::rx_irq(void) 00306 { 00307 bool was_empty = _rxbuf.empty(); 00308 00309 /* Fill in the receive buffer if the peripheral is readable 00310 * and receive buffer is not full. */ 00311 while (!_rxbuf.full() && SerialBase::readable()) { 00312 char data = SerialBase::_base_getc(); 00313 _rxbuf.push(data); 00314 } 00315 00316 if (_rx_irq_enabled && _rxbuf.full()) { 00317 SerialBase::attach(NULL, RxIrq); 00318 _rx_irq_enabled = false; 00319 } 00320 00321 /* Report the File handler that data is ready to be read from the buffer. */ 00322 if (was_empty && !_rxbuf.empty()) { 00323 wake(); 00324 } 00325 } 00326 00327 // Also called from write to start transfer 00328 void UARTSerial::tx_irq(void) 00329 { 00330 bool was_full = _txbuf.full(); 00331 char data; 00332 00333 /* Write to the peripheral if there is something to write 00334 * and if the peripheral is available to write. */ 00335 while (SerialBase::writeable() && _txbuf.pop(data)) { 00336 SerialBase::_base_putc(data); 00337 } 00338 00339 if (_tx_irq_enabled && _txbuf.empty()) { 00340 SerialBase::attach(NULL, TxIrq); 00341 _tx_irq_enabled = false; 00342 } 00343 00344 /* Report the File handler that data can be written to peripheral. */ 00345 if (was_full && !_txbuf.full() && !hup()) { 00346 wake(); 00347 } 00348 } 00349 00350 void UARTSerial::wait_ms(uint32_t millisec) 00351 { 00352 /* wait_ms implementation for RTOS spins until exact microseconds - we 00353 * want to just sleep until next tick. 00354 */ 00355 #if MBED_CONF_RTOS_PRESENT 00356 rtos::ThisThread::sleep_for(millisec); 00357 #else 00358 ::wait_ms(millisec); 00359 #endif 00360 } 00361 } //namespace mbed 00362 00363 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
Generated on Tue Jul 12 2022 20:41:16 by 1.7.2