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