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