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.
Dependents: STM32L452_Nucleo_ticker
Fork of mbed-dev by
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 12:52:26 by
