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