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 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 short revents = 0; 00241 /* Check the Circular Buffer if space available for writing out */ 00242 00243 00244 if (!_rxbuf.empty()) { 00245 revents |= POLLIN; 00246 } 00247 00248 /* POLLHUP and POLLOUT are mutually exclusive */ 00249 if (hup()) { 00250 revents |= POLLHUP; 00251 } else if (!_txbuf.full()) { 00252 revents |= POLLOUT; 00253 } 00254 00255 /*TODO Handle other event types */ 00256 00257 return revents; 00258 } 00259 00260 void UARTSerial::lock() 00261 { 00262 // This is the override for SerialBase. 00263 // No lock required as we only use SerialBase from interrupt or from 00264 // inside our own critical section. 00265 } 00266 00267 void UARTSerial::unlock() 00268 { 00269 // This is the override for SerialBase. 00270 } 00271 00272 void UARTSerial::api_lock(void) 00273 { 00274 _mutex.lock(); 00275 } 00276 00277 void UARTSerial::api_unlock(void) 00278 { 00279 _mutex.unlock(); 00280 } 00281 00282 void UARTSerial::rx_irq(void) 00283 { 00284 bool was_empty = _rxbuf.empty(); 00285 00286 /* Fill in the receive buffer if the peripheral is readable 00287 * and receive buffer is not full. */ 00288 while (!_rxbuf.full() && SerialBase::readable()) { 00289 char data = SerialBase::_base_getc(); 00290 _rxbuf.push(data); 00291 } 00292 00293 if (_rx_irq_enabled && _rxbuf.full()) { 00294 SerialBase::attach(NULL, RxIrq); 00295 _rx_irq_enabled = false; 00296 } 00297 00298 /* Report the File handler that data is ready to be read from the buffer. */ 00299 if (was_empty && !_rxbuf.empty()) { 00300 wake(); 00301 } 00302 } 00303 00304 // Also called from write to start transfer 00305 void UARTSerial::tx_irq(void) 00306 { 00307 bool was_full = _txbuf.full(); 00308 00309 /* Write to the peripheral if there is something to write 00310 * and if the peripheral is available to write. */ 00311 while (!_txbuf.empty() && SerialBase::writeable()) { 00312 char data; 00313 _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 13:31:48 by
