forked
Embed:
(wiki syntax)
Show/hide line numbers
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)
Generated on Tue Jul 12 2022 16:02:33 by 1.7.2