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 #include "drivers/UARTSerial.h" 00017 00018 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) 00019 00020 #include "platform/mbed_poll.h" 00021 00022 #if MBED_CONF_RTOS_PRESENT 00023 #include "rtos/Thread.h" 00024 #else 00025 #include "platform/mbed_wait_api.h" 00026 #endif 00027 00028 namespace mbed { 00029 00030 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) : 00031 SerialBase(tx, rx, baud), 00032 _blocking(true), 00033 _tx_irq_enabled(false), 00034 _rx_irq_enabled(true), 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 void UARTSerial::set_format(int bits, Parity parity, int stop_bits) 00072 { 00073 api_lock(); 00074 SerialBase::format(bits, parity, stop_bits); 00075 api_unlock(); 00076 } 00077 00078 #if DEVICE_SERIAL_FC 00079 void UARTSerial::set_flow_control(Flow type, PinName flow1, PinName flow2) 00080 { 00081 api_lock(); 00082 SerialBase::set_flow_control(type, flow1, flow2); 00083 api_unlock(); 00084 } 00085 #endif 00086 00087 int UARTSerial::close() 00088 { 00089 /* Does not let us pass a file descriptor. So how to close ? 00090 * Also, does it make sense to close a device type file descriptor*/ 00091 return 0; 00092 } 00093 00094 int UARTSerial::isatty() 00095 { 00096 return 1; 00097 00098 } 00099 00100 off_t UARTSerial::seek(off_t offset, int whence) 00101 { 00102 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking 00103 * buffer system (from an interrupt context) */ 00104 return -ESPIPE; 00105 } 00106 00107 int UARTSerial::sync() 00108 { 00109 api_lock(); 00110 00111 while (!_txbuf.empty()) { 00112 api_unlock(); 00113 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? 00114 wait_ms(1); 00115 api_lock(); 00116 } 00117 00118 api_unlock(); 00119 00120 return 0; 00121 } 00122 00123 void UARTSerial::sigio(Callback<void()> func) 00124 { 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 if (length == 0) { 00142 return 0; 00143 } 00144 00145 api_lock(); 00146 00147 // Unlike read, we should write the whole thing if blocking. POSIX only 00148 // allows partial as a side-effect of signal handling; it normally tries to 00149 // write everything if blocking. Without signals we can always write all. 00150 while (data_written < length) { 00151 00152 if (_txbuf.full()) { 00153 if (!_blocking) { 00154 break; 00155 } 00156 do { 00157 api_unlock(); 00158 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00159 api_lock(); 00160 } while (_txbuf.full()); 00161 } 00162 00163 while (data_written < length && !_txbuf.full()) { 00164 _txbuf.push(*buf_ptr++); 00165 data_written++; 00166 } 00167 00168 core_util_critical_section_enter(); 00169 if (!_tx_irq_enabled) { 00170 UARTSerial::tx_irq(); // only write to hardware in one place 00171 if (!_txbuf.empty()) { 00172 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); 00173 _tx_irq_enabled = true; 00174 } 00175 } 00176 core_util_critical_section_exit(); 00177 } 00178 00179 api_unlock(); 00180 00181 return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN; 00182 } 00183 00184 ssize_t UARTSerial::read(void *buffer, size_t length) 00185 { 00186 size_t data_read = 0; 00187 00188 char *ptr = static_cast<char *>(buffer); 00189 00190 if (length == 0) { 00191 return 0; 00192 } 00193 00194 api_lock(); 00195 00196 while (_rxbuf.empty()) { 00197 if (!_blocking) { 00198 api_unlock(); 00199 return -EAGAIN; 00200 } 00201 api_unlock(); 00202 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00203 api_lock(); 00204 } 00205 00206 while (data_read < length && !_rxbuf.empty()) { 00207 _rxbuf.pop(*ptr++); 00208 data_read++; 00209 } 00210 00211 core_util_critical_section_enter(); 00212 if (!_rx_irq_enabled) { 00213 UARTSerial::rx_irq(); // only read from hardware in one place 00214 if (!_rxbuf.full()) { 00215 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); 00216 _rx_irq_enabled = true; 00217 } 00218 } 00219 core_util_critical_section_exit(); 00220 00221 api_unlock(); 00222 00223 return data_read; 00224 } 00225 00226 bool UARTSerial::hup() const 00227 { 00228 return _dcd_irq && _dcd_irq->read() != 0; 00229 } 00230 00231 void UARTSerial::wake() 00232 { 00233 if (_sigio_cb) { 00234 _sigio_cb(); 00235 } 00236 } 00237 00238 short UARTSerial::poll(short events) const 00239 { 00240 00241 short revents = 0; 00242 /* Check the Circular Buffer if space available for writing out */ 00243 00244 00245 if (!_rxbuf.empty()) { 00246 revents |= POLLIN; 00247 } 00248 00249 /* POLLHUP and POLLOUT are mutually exclusive */ 00250 if (hup()) { 00251 revents |= POLLHUP; 00252 } else if (!_txbuf.full()) { 00253 revents |= POLLOUT; 00254 } 00255 00256 /*TODO Handle other event types */ 00257 00258 return revents; 00259 } 00260 00261 void UARTSerial::lock() 00262 { 00263 // This is the override for SerialBase. 00264 // No lock required as we only use SerialBase from interrupt or from 00265 // inside our own critical section. 00266 } 00267 00268 void UARTSerial::unlock() 00269 { 00270 // This is the override for SerialBase. 00271 } 00272 00273 void UARTSerial::api_lock(void) 00274 { 00275 _mutex.lock(); 00276 } 00277 00278 void UARTSerial::api_unlock(void) 00279 { 00280 _mutex.unlock(); 00281 } 00282 00283 void UARTSerial::rx_irq(void) 00284 { 00285 bool was_empty = _rxbuf.empty(); 00286 00287 /* Fill in the receive buffer if the peripheral is readable 00288 * and receive buffer is not full. */ 00289 while (!_rxbuf.full() && SerialBase::readable()) { 00290 char data = SerialBase::_base_getc(); 00291 _rxbuf.push(data); 00292 } 00293 00294 if (_rx_irq_enabled && _rxbuf.full()) { 00295 SerialBase::attach(NULL, RxIrq); 00296 _rx_irq_enabled = false; 00297 } 00298 00299 /* Report the File handler that data is ready to be read from the buffer. */ 00300 if (was_empty && !_rxbuf.empty()) { 00301 wake(); 00302 } 00303 } 00304 00305 // Also called from write to start transfer 00306 void UARTSerial::tx_irq(void) 00307 { 00308 bool was_full = _txbuf.full(); 00309 char data; 00310 00311 /* Write to the peripheral if there is something to write 00312 * and if the peripheral is available to write. */ 00313 while (SerialBase::writeable() && _txbuf.pop(data)) { 00314 SerialBase::_base_putc(data); 00315 } 00316 00317 if (_tx_irq_enabled && _txbuf.empty()) { 00318 SerialBase::attach(NULL, TxIrq); 00319 _tx_irq_enabled = false; 00320 } 00321 00322 /* Report the File handler that data can be written to peripheral. */ 00323 if (was_full && !_txbuf.full() && !hup()) { 00324 wake(); 00325 } 00326 } 00327 00328 void UARTSerial::wait_ms(uint32_t millisec) 00329 { 00330 /* wait_ms implementation for RTOS spins until exact microseconds - we 00331 * want to just sleep until next tick. 00332 */ 00333 #if MBED_CONF_RTOS_PRESENT 00334 rtos::Thread::wait(millisec); 00335 #else 00336 ::wait_ms(millisec); 00337 #endif 00338 } 00339 } //namespace mbed 00340 00341 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
Generated on Tue Jul 12 2022 20:53:02 by
1.7.2