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 #include "platform/mbed_wait_api.h" 00023 00024 namespace mbed { 00025 00026 UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) : 00027 SerialBase(tx, rx, baud), 00028 _blocking(true), 00029 _tx_irq_enabled(false), 00030 _dcd_irq(NULL) 00031 { 00032 /* Attatch IRQ routines to the serial device. */ 00033 SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq); 00034 } 00035 00036 UARTSerial::~UARTSerial() 00037 { 00038 delete _dcd_irq; 00039 } 00040 00041 void UARTSerial::dcd_irq() 00042 { 00043 wake(); 00044 } 00045 00046 void UARTSerial::set_baud(int baud) 00047 { 00048 SerialBase::baud(baud); 00049 } 00050 00051 void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high) 00052 { 00053 delete _dcd_irq; 00054 _dcd_irq = NULL; 00055 00056 if (dcd_pin != NC) { 00057 _dcd_irq = new InterruptIn(dcd_pin); 00058 if (active_high) { 00059 _dcd_irq->fall(callback(this, &UARTSerial::dcd_irq)); 00060 } else { 00061 _dcd_irq->rise(callback(this, &UARTSerial::dcd_irq)); 00062 } 00063 } 00064 } 00065 00066 int UARTSerial::close() 00067 { 00068 /* Does not let us pass a file descriptor. So how to close ? 00069 * Also, does it make sense to close a device type file descriptor*/ 00070 return 0; 00071 } 00072 00073 int UARTSerial::isatty() 00074 { 00075 return 1; 00076 00077 } 00078 00079 off_t UARTSerial::seek(off_t offset, int whence) 00080 { 00081 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking 00082 * buffer system (from an interrupt context) */ 00083 return -ESPIPE; 00084 } 00085 00086 int UARTSerial::sync() 00087 { 00088 api_lock(); 00089 00090 while (!_txbuf.empty()) { 00091 api_unlock(); 00092 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? 00093 wait_ms(1); 00094 api_lock(); 00095 } 00096 00097 api_unlock(); 00098 00099 return 0; 00100 } 00101 00102 void UARTSerial::sigio(Callback<void()> func) { 00103 core_util_critical_section_enter(); 00104 _sigio_cb = func; 00105 if (_sigio_cb) { 00106 short current_events = poll(0x7FFF); 00107 if (current_events) { 00108 _sigio_cb(); 00109 } 00110 } 00111 core_util_critical_section_exit(); 00112 } 00113 00114 ssize_t UARTSerial::write(const void* buffer, size_t length) 00115 { 00116 size_t data_written = 0; 00117 const char *buf_ptr = static_cast<const char *>(buffer); 00118 00119 api_lock(); 00120 00121 while (_txbuf.full()) { 00122 if (!_blocking) { 00123 api_unlock(); 00124 return -EAGAIN; 00125 } 00126 api_unlock(); 00127 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00128 api_lock(); 00129 } 00130 00131 while (data_written < length && !_txbuf.full()) { 00132 _txbuf.push(*buf_ptr++); 00133 data_written++; 00134 } 00135 00136 core_util_critical_section_enter(); 00137 if (!_tx_irq_enabled) { 00138 UARTSerial::tx_irq(); // only write to hardware in one place 00139 if (!_txbuf.empty()) { 00140 SerialBase::attach(callback(this, &UARTSerial::tx_irq), TxIrq); 00141 _tx_irq_enabled = true; 00142 } 00143 } 00144 core_util_critical_section_exit(); 00145 00146 api_unlock(); 00147 00148 return data_written; 00149 } 00150 00151 ssize_t UARTSerial::read(void* buffer, size_t length) 00152 { 00153 size_t data_read = 0; 00154 00155 char *ptr = static_cast<char *>(buffer); 00156 00157 api_lock(); 00158 00159 while (_rxbuf.empty()) { 00160 if (!_blocking) { 00161 api_unlock(); 00162 return -EAGAIN; 00163 } 00164 api_unlock(); 00165 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00166 api_lock(); 00167 } 00168 00169 while (data_read < length && !_rxbuf.empty()) { 00170 _rxbuf.pop(*ptr++); 00171 data_read++; 00172 } 00173 00174 api_unlock(); 00175 00176 return data_read; 00177 } 00178 00179 bool UARTSerial::hup() const 00180 { 00181 return _dcd_irq && _dcd_irq->read() != 0; 00182 } 00183 00184 void UARTSerial::wake() 00185 { 00186 if (_sigio_cb) { 00187 _sigio_cb(); 00188 } 00189 } 00190 00191 short UARTSerial::poll(short events) const { 00192 00193 short revents = 0; 00194 /* Check the Circular Buffer if space available for writing out */ 00195 00196 00197 if (!_rxbuf.empty()) { 00198 revents |= POLLIN; 00199 } 00200 00201 /* POLLHUP and POLLOUT are mutually exclusive */ 00202 if (hup()) { 00203 revents |= POLLHUP; 00204 } else if (!_txbuf.full()) { 00205 revents |= POLLOUT; 00206 } 00207 00208 /*TODO Handle other event types */ 00209 00210 return revents; 00211 } 00212 00213 void UARTSerial::lock() 00214 { 00215 // This is the override for SerialBase. 00216 // No lock required as we only use SerialBase from interrupt or from 00217 // inside our own critical section. 00218 } 00219 00220 void UARTSerial::unlock() 00221 { 00222 // This is the override for SerialBase. 00223 } 00224 00225 void UARTSerial::api_lock(void) 00226 { 00227 _mutex.lock(); 00228 } 00229 00230 void UARTSerial::api_unlock(void) 00231 { 00232 _mutex.unlock(); 00233 } 00234 00235 void UARTSerial::rx_irq(void) 00236 { 00237 bool was_empty = _rxbuf.empty(); 00238 00239 /* Fill in the receive buffer if the peripheral is readable 00240 * and receive buffer is not full. */ 00241 while (SerialBase::readable()) { 00242 char data = SerialBase::_base_getc(); 00243 if (!_rxbuf.full()) { 00244 _rxbuf.push(data); 00245 } else { 00246 /* Drop - can we report in some way? */ 00247 } 00248 } 00249 00250 /* Report the File handler that data is ready to be read from the buffer. */ 00251 if (was_empty && !_rxbuf.empty()) { 00252 wake(); 00253 } 00254 } 00255 00256 // Also called from write to start transfer 00257 void UARTSerial::tx_irq(void) 00258 { 00259 bool was_full = _txbuf.full(); 00260 00261 /* Write to the peripheral if there is something to write 00262 * and if the peripheral is available to write. */ 00263 while (!_txbuf.empty() && SerialBase::writeable()) { 00264 char data; 00265 _txbuf.pop(data); 00266 SerialBase::_base_putc(data); 00267 } 00268 00269 if (_tx_irq_enabled && _txbuf.empty()) { 00270 SerialBase::attach(NULL, TxIrq); 00271 _tx_irq_enabled = false; 00272 } 00273 00274 /* Report the File handler that data can be written to peripheral. */ 00275 if (was_full && !_txbuf.full() && !hup()) { 00276 wake(); 00277 } 00278 } 00279 00280 } //namespace mbed 00281 00282 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN) 00283
Generated on Thu Jun 15 2023 06:56:49 by
