mbedos senza corrente

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers UARTSerial_half.cpp Source File

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)