a
Embed:
(wiki syntax)
Show/hide line numbers
UARTSerial_mio.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2017 ARM Limited 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #include "UARTSerial_mio.h" 00018 00019 #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) 00020 00021 #include "platform/mbed_poll.h" 00022 00023 #if MBED_CONF_RTOS_PRESENT 00024 #include "rtos/ThisThread.h" 00025 #else 00026 #include "platform/mbed_wait_api.h" 00027 #endif 00028 00029 namespace mbed { 00030 00031 UARTSerial_mio::UARTSerial_mio(PinName tx, PinName rx, int baud) : 00032 SerialBase(tx, rx, baud), 00033 _blocking(true), 00034 _tx_irq_enabled(false), 00035 _rx_irq_enabled(false), 00036 _tx_enabled(true), 00037 _rx_enabled(true), 00038 _dcd_irq(NULL) 00039 { 00040 /* Attatch IRQ routines to the serial device. */ 00041 enable_rx_irq(); 00042 } 00043 00044 UARTSerial_mio::~UARTSerial_mio() 00045 { 00046 delete _dcd_irq; 00047 } 00048 00049 void UARTSerial_mio::dcd_irq() 00050 { 00051 wake(); 00052 } 00053 00054 void UARTSerial_mio::set_baud(int baud) 00055 { 00056 SerialBase::baud(baud); 00057 } 00058 00059 void UARTSerial_mio::set_format(int bits, Parity parity, int stop_bits) 00060 { 00061 api_lock(); 00062 SerialBase::format(bits, parity, stop_bits); 00063 api_unlock(); 00064 } 00065 00066 #if DEVICE_SERIAL_FC 00067 void UARTSerial_mio::set_flow_control(Flow type, PinName flow1, PinName flow2) 00068 { 00069 api_lock(); 00070 SerialBase::set_flow_control(type, flow1, flow2); 00071 api_unlock(); 00072 } 00073 #endif 00074 00075 int UARTSerial_mio::close(){return 0;} 00076 00077 int UARTSerial_mio::isatty(){return 1;} 00078 00079 00080 off_t UARTSerial_mio::seek(off_t offset, int whence) 00081 { 00082 /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking 00083 * buffer system (from an interrupt context) */ 00084 return -ESPIPE; 00085 } 00086 00087 int UARTSerial_mio::sync() 00088 { 00089 api_lock(); 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_us(500); 00094 api_lock(); 00095 } 00096 00097 api_unlock(); 00098 00099 return 0; 00100 } 00101 00102 int UARTSerial_mio::flush() 00103 { 00104 api_lock(); 00105 char c; 00106 00107 while (!_rxbuf.empty()) { 00108 api_unlock(); 00109 // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? 00110 wait_us(500); 00111 _rxbuf.pop(c); 00112 api_lock(); 00113 } 00114 00115 api_unlock(); 00116 00117 return 0; 00118 } 00119 00120 void UARTSerial_mio::sigio(Callback<void()> func) 00121 { 00122 core_util_critical_section_enter(); 00123 _sigio_cb = func; 00124 if (_sigio_cb) { 00125 short current_events = poll(0x7FFF); 00126 if (current_events) { 00127 _sigio_cb(); 00128 } 00129 } 00130 core_util_critical_section_exit(); 00131 } 00132 00133 /* Special synchronous write designed to work from critical section, such 00134 * as in mbed_error_vprintf. 00135 */ 00136 ssize_t UARTSerial_mio::write_unbuffered(const char *buf_ptr, size_t length) 00137 { 00138 while (!_txbuf.empty()) { 00139 tx_irq(); 00140 } 00141 00142 for (size_t data_written = 0; data_written < length; data_written++) { 00143 SerialBase::_base_putc(*buf_ptr++); 00144 } 00145 00146 return length; 00147 } 00148 00149 ssize_t UARTSerial_mio::write(const void *buffer, size_t length) 00150 { 00151 size_t data_written = 0; 00152 const char *buf_ptr = static_cast<const char *>(buffer); 00153 00154 if (length == 0) { 00155 return 0; 00156 } 00157 00158 if (core_util_in_critical_section()) { 00159 return write_unbuffered(buf_ptr, length); 00160 } 00161 00162 api_lock(); 00163 00164 // Unlike read, we should write the whole thing if blocking. POSIX only 00165 // allows partial as a side-effect of signal handling; it normally tries to 00166 // write everything if blocking. Without signals we can always write all. 00167 while (data_written < length) { 00168 00169 if (_txbuf.full()) { 00170 if (!_blocking) { 00171 break; 00172 } 00173 do { 00174 api_unlock(); 00175 wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? 00176 api_lock(); 00177 } while (_txbuf.full()); 00178 } 00179 00180 while (data_written < length && !_txbuf.full()) { 00181 _txbuf.push(*buf_ptr++); 00182 data_written++; 00183 } 00184 00185 core_util_critical_section_enter(); 00186 if (_tx_enabled && !_tx_irq_enabled) { 00187 UARTSerial_mio::tx_irq(); // only write to hardware in one place 00188 if (!_txbuf.empty()) { 00189 enable_tx_irq(); 00190 } 00191 } 00192 core_util_critical_section_exit(); 00193 } 00194 00195 api_unlock(); 00196 00197 return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN; 00198 } 00199 00200 ssize_t UARTSerial_mio::read(void *buffer, size_t length) 00201 { 00202 size_t data_read = 0; 00203 00204 float timeout = 1.0; //ms 00205 float tm = 0.0; 00206 00207 char *ptr = static_cast<char *>(buffer); 00208 00209 if (length == 0) { 00210 return 0; 00211 } 00212 00213 api_lock(); 00214 00215 while (_rxbuf.size()!=length && tm <= timeout) { 00216 if (!_blocking) { 00217 api_unlock(); 00218 return -EAGAIN; 00219 } 00220 api_unlock(); 00221 wait_us(10); // XXX todo - proper wait, WFE for non-rtos ? 00222 api_lock(); 00223 tm = tm + 0.01; //10/1000 00224 } 00225 00226 while (data_read < length && !_rxbuf.empty()) { 00227 _rxbuf.pop(*ptr++); 00228 data_read++; 00229 } 00230 00231 core_util_critical_section_enter(); 00232 if (_rx_enabled && !_rx_irq_enabled) { 00233 UARTSerial_mio::rx_irq(); // only read from hardware in one place 00234 if (!_rxbuf.full()) { 00235 enable_rx_irq(); 00236 } 00237 } 00238 core_util_critical_section_exit(); 00239 00240 api_unlock(); 00241 00242 return data_read; 00243 } 00244 00245 ssize_t UARTSerial_mio::read_timeout(void *buffer, size_t length, double _timeOut) 00246 { 00247 size_t data_read = 0; 00248 00249 double timeout = _timeOut; //ms 00250 double tm = 0.0; 00251 00252 char *ptr = static_cast<char *>(buffer); 00253 00254 if (length == 0) { 00255 return 0; 00256 } 00257 00258 api_lock(); 00259 00260 while (_rxbuf.size()!=length && tm<=timeout) { 00261 if (!_blocking) { 00262 api_unlock(); 00263 return -EAGAIN; 00264 } 00265 api_unlock(); 00266 wait_us(1); // XXX todo - proper wait, WFE for non-rtos ? 00267 api_lock(); 00268 tm = tm + 0.001; //10/1000 00269 00270 } 00271 00272 //printf("tm: %f\r\n",tm); 00273 tm = 0.0; 00274 while (data_read < length && !_rxbuf.empty() && tm<=timeout) { 00275 _rxbuf.pop(*ptr++); 00276 data_read++; 00277 tm = tm + 0.001; //10/1000 00278 } 00279 00280 core_util_critical_section_enter(); 00281 if (_rx_enabled && !_rx_irq_enabled) { 00282 UARTSerial_mio::rx_irq(); // only read from hardware in one place 00283 if (!_rxbuf.full()) { 00284 enable_rx_irq(); 00285 } 00286 } 00287 core_util_critical_section_exit(); 00288 00289 api_unlock(); 00290 00291 return data_read; 00292 } 00293 00294 bool UARTSerial_mio::hup() const 00295 { 00296 return _dcd_irq && _dcd_irq->read() != 0; 00297 } 00298 00299 void UARTSerial_mio::wake() 00300 { 00301 if (_sigio_cb) { 00302 _sigio_cb(); 00303 } 00304 } 00305 00306 short UARTSerial_mio::poll(short events) const 00307 { 00308 00309 short revents = 0; 00310 /* Check the Circular Buffer if space available for writing out */ 00311 00312 00313 if (!_rxbuf.empty()) { 00314 revents |= POLLIN; 00315 } 00316 00317 /* POLLHUP and POLLOUT are mutually exclusive */ 00318 if (hup()) { 00319 revents |= POLLHUP; 00320 } else if (!_txbuf.full()) { 00321 revents |= POLLOUT; 00322 } 00323 00324 /*TODO Handle other event types */ 00325 00326 return revents; 00327 } 00328 00329 void UARTSerial_mio::lock() 00330 { 00331 // This is the override for SerialBase. 00332 // No lock required as we only use SerialBase from interrupt or from 00333 // inside our own critical section. 00334 } 00335 00336 void UARTSerial_mio::unlock() 00337 { 00338 // This is the override for SerialBase. 00339 } 00340 00341 void UARTSerial_mio::api_lock(void) 00342 { 00343 //_mutex.lock(); 00344 } 00345 00346 void UARTSerial_mio::api_unlock(void) 00347 { 00348 //_mutex.unlock(); 00349 } 00350 00351 void UARTSerial_mio::rx_irq(void) 00352 { 00353 bool was_empty = _rxbuf.empty(); 00354 00355 /* Fill in the receive buffer if the peripheral is readable 00356 * and receive buffer is not full. */ 00357 while (!_rxbuf.full() && SerialBase::readable()) { 00358 char data = SerialBase::_base_getc(); 00359 _rxbuf.push(data); 00360 } 00361 00362 if (_rx_irq_enabled && _rxbuf.full()) { 00363 disable_rx_irq(); 00364 } 00365 00366 /* Report the File handler that data is ready to be read from the buffer. */ 00367 if (was_empty && !_rxbuf.empty()) { 00368 wake(); 00369 } 00370 } 00371 00372 // Also called from write to start transfer 00373 void UARTSerial_mio::tx_irq(void) 00374 { 00375 bool was_full = _txbuf.full(); 00376 char data; 00377 00378 /* Write to the peripheral if there is something to write 00379 * and if the peripheral is available to write. */ 00380 while (SerialBase::writeable() && _txbuf.pop(data)) { 00381 SerialBase::_base_putc(data); 00382 } 00383 00384 if (_tx_irq_enabled && _txbuf.empty()) { 00385 disable_tx_irq(); 00386 } 00387 00388 /* Report the File handler that data can be written to peripheral. */ 00389 if (was_full && !_txbuf.full() && !hup()) { 00390 wake(); 00391 } 00392 } 00393 00394 /* These are all called from critical section */ 00395 void UARTSerial_mio::enable_rx_irq() 00396 { 00397 SerialBase::attach(callback(this, &UARTSerial_mio::rx_irq), RxIrq); 00398 _rx_irq_enabled = true; 00399 } 00400 00401 void UARTSerial_mio::disable_rx_irq() 00402 { 00403 SerialBase::attach(NULL, RxIrq); 00404 _rx_irq_enabled = false; 00405 } 00406 00407 void UARTSerial_mio::enable_tx_irq() 00408 { 00409 SerialBase::attach(callback(this, &UARTSerial_mio::tx_irq), TxIrq); 00410 _tx_irq_enabled = true; 00411 } 00412 00413 void UARTSerial_mio::disable_tx_irq() 00414 { 00415 SerialBase::attach(NULL, TxIrq); 00416 _tx_irq_enabled = false; 00417 } 00418 00419 int UARTSerial_mio::enable_input(bool enabled) 00420 { 00421 core_util_critical_section_enter(); 00422 if (_rx_enabled != enabled) { 00423 if (enabled) { 00424 UARTSerial_mio::rx_irq(); 00425 if (!_rxbuf.full()) { 00426 enable_rx_irq(); 00427 } 00428 } else { 00429 disable_rx_irq(); 00430 } 00431 _rx_enabled = enabled; 00432 } 00433 core_util_critical_section_exit(); 00434 00435 return 0; 00436 } 00437 00438 int UARTSerial_mio::enable_output(bool enabled) 00439 { 00440 core_util_critical_section_enter(); 00441 if (_tx_enabled != enabled) { 00442 if (enabled) { 00443 UARTSerial_mio::tx_irq(); 00444 if (!_txbuf.empty()) { 00445 enable_tx_irq(); 00446 } 00447 } else { 00448 disable_tx_irq(); 00449 } 00450 _tx_enabled = enabled; 00451 } 00452 core_util_critical_section_exit(); 00453 00454 return 0; 00455 } 00456 00457 void UARTSerial_mio::wait_ms(uint32_t millisec) 00458 { 00459 /* wait_ms implementation for RTOS spins until exact microseconds - we 00460 * want to just sleep until next tick. 00461 */ 00462 #if MBED_CONF_RTOS_PRESENT 00463 rtos::ThisThread::sleep_for(millisec); 00464 #else 00465 ::wait_ms(millisec); 00466 #endif 00467 } 00468 00469 void UARTSerial_mio::wait_us(uint32_t microseconds) 00470 { 00471 /* wait_ms implementation for RTOS spins until exact microseconds - we 00472 * want to just sleep until next tick. 00473 */ 00474 #if MBED_CONF_RTOS_PRESENT 00475 rtos::ThisThread::sleep_for(microseconds/1000); 00476 #else 00477 ::wait_us(microseconds); 00478 #endif 00479 } 00480 } //namespace mbed 00481 00482 #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)
Generated on Tue Aug 16 2022 09:44:47 by 1.7.2