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