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 _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 int UARTSerial::close() 00072 { 00073 /* Does not let us pass a file descriptor. So how to close ? 00074 * Also, does it make sense to close a device type file descriptor*/ 00075 return 0; 00076 } 00077 00078 int UARTSerial::isatty() 00079 { 00080 return 1; 00081 00082 } 00083 00084 off_t UARTSerial::seek(off_t offset, int whence) 00085 { 00086 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking 00087 * buffer system (from an interrupt context) */ 00088 return -ESPIPE; 00089 } 00090 00091 int UARTSerial::sync() 00092 { 00093 api_lock(); 00094 00095 while (!_txbuf.empty()) { 00096 api_unlock(); 00097 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? 00098 wait_ms(1); 00099 api_lock(); 00100 } 00101 00102 api_unlock(); 00103 00104 return 0; 00105 } 00106 00107 void UARTSerial::sigio(Callback<void()> func) { 00108 core_util_critical_section_enter(); 00109 _sigio_cb = func; 00110 if (_sigio_cb) { 00111 short current_events = poll(0x7FFF); 00112 if (current_events) { 00113 _sigio_cb(); 00114 } 00115 } 00116 core_util_critical_section_exit(); 00117 } 00118 00119 ssize_t UARTSerial::write(const void* buffer, size_t length) 00120 { 00121 size_t data_written = 0; 00122 const char *buf_ptr = static_cast<const char *>(buffer); 00123 00124 api_lock(); 00125 00126 while (_txbuf.full()) { 00127 if (!_blocking) { 00128 api_unlock(); 00129 return -EAGAIN; 00130 } 00131 api_unlock(); 00132 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00133 api_lock(); 00134 } 00135 00136 while (data_written < length && !_txbuf.full()) { 00137 _txbuf.push(*buf_ptr++); 00138 data_written++; 00139 } 00140 00141 core_util_critical_section_enter(); 00142 if (!_tx_irq_enabled) { 00143 UARTSerial::tx_irq(); // only write to hardware in one place 00144 if (!_txbuf.empty()) { 00145 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); 00146 _tx_irq_enabled = true; 00147 } 00148 } 00149 core_util_critical_section_exit(); 00150 00151 api_unlock(); 00152 00153 return data_written; 00154 } 00155 00156 ssize_t UARTSerial::read(void* buffer, size_t length) 00157 { 00158 size_t data_read = 0; 00159 00160 char *ptr = static_cast<char *>(buffer); 00161 00162 api_lock(); 00163 00164 while (_rxbuf.empty()) { 00165 if (!_blocking) { 00166 api_unlock(); 00167 return -EAGAIN; 00168 } 00169 api_unlock(); 00170 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00171 api_lock(); 00172 } 00173 00174 while (data_read < length && !_rxbuf.empty()) { 00175 _rxbuf.pop(*ptr++); 00176 data_read++; 00177 } 00178 00179 api_unlock(); 00180 00181 return data_read; 00182 } 00183 00184 bool UARTSerial::hup() const 00185 { 00186 return _dcd_irq && _dcd_irq->read() != 0; 00187 } 00188 00189 void UARTSerial::wake() 00190 { 00191 if (_sigio_cb) { 00192 _sigio_cb(); 00193 } 00194 } 00195 00196 short UARTSerial::poll(short events) const { 00197 00198 short revents = 0; 00199 /* Check the Circular Buffer if space available for writing out */ 00200 00201 00202 if (!_rxbuf.empty()) { 00203 revents |= POLLIN; 00204 } 00205 00206 /* POLLHUP and POLLOUT are mutually exclusive */ 00207 if (hup()) { 00208 revents |= POLLHUP; 00209 } else if (!_txbuf.full()) { 00210 revents |= POLLOUT; 00211 } 00212 00213 /*TODO Handle other event types */ 00214 00215 return revents; 00216 } 00217 00218 void UARTSerial::lock() 00219 { 00220 // This is the override for SerialBase. 00221 // No lock required as we only use SerialBase from interrupt or from 00222 // inside our own critical section. 00223 } 00224 00225 void UARTSerial::unlock() 00226 { 00227 // This is the override for SerialBase. 00228 } 00229 00230 void UARTSerial::api_lock(void) 00231 { 00232 _mutex.lock(); 00233 } 00234 00235 void UARTSerial::api_unlock(void) 00236 { 00237 _mutex.unlock(); 00238 } 00239 00240 void UARTSerial::rx_irq(void) 00241 { 00242 bool was_empty = _rxbuf.empty(); 00243 00244 /* Fill in the receive buffer if the peripheral is readable 00245 * and receive buffer is not full. */ 00246 while (SerialBase::readable()) { 00247 char data = SerialBase::_base_getc(); 00248 if (!_rxbuf.full()) { 00249 _rxbuf.push(data); 00250 } else { 00251 /* Drop - can we report in some way? */ 00252 } 00253 } 00254 00255 /* Report the File handler that data is ready to be read from the buffer. */ 00256 if (was_empty && !_rxbuf.empty()) { 00257 wake(); 00258 } 00259 } 00260 00261 // Also called from write to start transfer 00262 void UARTSerial::tx_irq(void) 00263 { 00264 bool was_full = _txbuf.full(); 00265 00266 /* Write to the peripheral if there is something to write 00267 * and if the peripheral is available to write. */ 00268 while (!_txbuf.empty() && SerialBase::writeable()) { 00269 char data; 00270 _txbuf.pop(data); 00271 SerialBase::_base_putc(data); 00272 } 00273 00274 if (_tx_irq_enabled && _txbuf.empty()) { 00275 SerialBase::attach(NULL, TxIrq); 00276 _tx_irq_enabled = false; 00277 } 00278 00279 /* Report the File handler that data can be written to peripheral. */ 00280 if (was_full && !_txbuf.full() && !hup()) { 00281 wake(); 00282 } 00283 } 00284 00285 void UARTSerial::wait_ms(uint32_t millisec) 00286 { 00287 /* wait_ms implementation for RTOS spins until exact microseconds - we 00288 * want to just sleep until next tick. 00289 */ 00290 #if MBED_CONF_RTOS_PRESENT 00291 rtos::Thread::wait(millisec); 00292 #else 00293 ::wait_ms(millisec); 00294 #endif 00295 } 00296 } //namespace mbed 00297 00298 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
Generated on Tue Jul 12 2022 20:03:25 by
