ricreato il link mancante
RoboClaw/UARTserial_mio/UARTSerial_mio.cpp
- Committer:
- marcodesilva
- Date:
- 2022-01-10
- Revision:
- 4:31695331ce17
File content as of revision 4:31695331ce17:
/* mbed Microcontroller Library * Copyright (c) 2006-2017 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "UARTSerial_mio.h" #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) #include "platform/mbed_poll.h" #if MBED_CONF_RTOS_PRESENT #include "rtos/ThisThread.h" #else #include "platform/mbed_wait_api.h" #endif namespace mbed { UARTSerial_mio::UARTSerial_mio(PinName tx, PinName rx, int baud) : SerialBase(tx, rx, baud), _blocking(true), _tx_irq_enabled(false), _rx_irq_enabled(false), _tx_enabled(true), _rx_enabled(true), _dcd_irq(NULL) { /* Attatch IRQ routines to the serial device. */ enable_rx_irq(); } UARTSerial_mio::~UARTSerial_mio() { delete _dcd_irq; } void UARTSerial_mio::dcd_irq() { wake(); } void UARTSerial_mio::set_baud(int baud) { SerialBase::baud(baud); } void UARTSerial_mio::set_format(int bits, Parity parity, int stop_bits) { api_lock(); SerialBase::format(bits, parity, stop_bits); api_unlock(); } #if DEVICE_SERIAL_FC void UARTSerial_mio::set_flow_control(Flow type, PinName flow1, PinName flow2) { api_lock(); SerialBase::set_flow_control(type, flow1, flow2); api_unlock(); } #endif int UARTSerial_mio::close(){return 0;} int UARTSerial_mio::isatty(){return 1;} off_t UARTSerial_mio::seek(off_t offset, int whence) { /*XXX lseek can be done theoratically, but is it sane to mark positions on a dynamically growing/shrinking * buffer system (from an interrupt context) */ return -ESPIPE; } int UARTSerial_mio::sync() { api_lock(); while (!_txbuf.empty()) { api_unlock(); // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? wait_us(500); api_lock(); } api_unlock(); return 0; } int UARTSerial_mio::flush() { api_lock(); char c; while (!_rxbuf.empty()) { api_unlock(); // Doing better than wait would require TxIRQ to also do wake() when becoming empty. Worth it? wait_us(500); _rxbuf.pop(c); api_lock(); } api_unlock(); return 0; } void UARTSerial_mio::sigio(Callback<void()> func) { core_util_critical_section_enter(); _sigio_cb = func; if (_sigio_cb) { short current_events = poll(0x7FFF); if (current_events) { _sigio_cb(); } } core_util_critical_section_exit(); } /* Special synchronous write designed to work from critical section, such * as in mbed_error_vprintf. */ ssize_t UARTSerial_mio::write_unbuffered(const char *buf_ptr, size_t length) { while (!_txbuf.empty()) { tx_irq(); } for (size_t data_written = 0; data_written < length; data_written++) { SerialBase::_base_putc(*buf_ptr++); } return length; } ssize_t UARTSerial_mio::write(const void *buffer, size_t length) { size_t data_written = 0; const char *buf_ptr = static_cast<const char *>(buffer); if (length == 0) { return 0; } if (core_util_in_critical_section()) { return write_unbuffered(buf_ptr, length); } api_lock(); // Unlike read, we should write the whole thing if blocking. POSIX only // allows partial as a side-effect of signal handling; it normally tries to // write everything if blocking. Without signals we can always write all. while (data_written < length) { if (_txbuf.full()) { if (!_blocking) { break; } do { api_unlock(); wait_ms(1); // XXX todo - proper wait, WFE for non-rtos ? api_lock(); } while (_txbuf.full()); } while (data_written < length && !_txbuf.full()) { _txbuf.push(*buf_ptr++); data_written++; } core_util_critical_section_enter(); if (_tx_enabled && !_tx_irq_enabled) { UARTSerial_mio::tx_irq(); // only write to hardware in one place if (!_txbuf.empty()) { enable_tx_irq(); } } core_util_critical_section_exit(); } api_unlock(); return data_written != 0 ? (ssize_t) data_written : (ssize_t) - EAGAIN; } ssize_t UARTSerial_mio::read(void *buffer, size_t length) { size_t data_read = 0; float timeout = 1.0; //ms float tm = 0.0; char *ptr = static_cast<char *>(buffer); if (length == 0) { return 0; } api_lock(); while (_rxbuf.size()!=length && tm <= timeout) { if (!_blocking) { api_unlock(); return -EAGAIN; } api_unlock(); wait_us(10); // XXX todo - proper wait, WFE for non-rtos ? api_lock(); tm = tm + 0.01; //10/1000 } while (data_read < length && !_rxbuf.empty()) { _rxbuf.pop(*ptr++); data_read++; } core_util_critical_section_enter(); if (_rx_enabled && !_rx_irq_enabled) { UARTSerial_mio::rx_irq(); // only read from hardware in one place if (!_rxbuf.full()) { enable_rx_irq(); } } core_util_critical_section_exit(); api_unlock(); return data_read; } ssize_t UARTSerial_mio::read_timeout(void *buffer, size_t length, double _timeOut) { size_t data_read = 0; double timeout = _timeOut; //ms double tm = 0.0; char *ptr = static_cast<char *>(buffer); if (length == 0) { return 0; } api_lock(); while (_rxbuf.size()!=length && tm<=timeout) { if (!_blocking) { api_unlock(); return -EAGAIN; } api_unlock(); wait_us(1); // XXX todo - proper wait, WFE for non-rtos ? api_lock(); tm = tm + 0.001; //10/1000 } //printf("tm: %f\r\n",tm); tm = 0.0; while (data_read < length && !_rxbuf.empty() && tm<=timeout) { _rxbuf.pop(*ptr++); data_read++; tm = tm + 0.001; //10/1000 } core_util_critical_section_enter(); if (_rx_enabled && !_rx_irq_enabled) { UARTSerial_mio::rx_irq(); // only read from hardware in one place if (!_rxbuf.full()) { enable_rx_irq(); } } core_util_critical_section_exit(); api_unlock(); return data_read; } bool UARTSerial_mio::hup() const { return _dcd_irq && _dcd_irq->read() != 0; } void UARTSerial_mio::wake() { if (_sigio_cb) { _sigio_cb(); } } short UARTSerial_mio::poll(short events) const { short revents = 0; /* Check the Circular Buffer if space available for writing out */ if (!_rxbuf.empty()) { revents |= POLLIN; } /* POLLHUP and POLLOUT are mutually exclusive */ if (hup()) { revents |= POLLHUP; } else if (!_txbuf.full()) { revents |= POLLOUT; } /*TODO Handle other event types */ return revents; } void UARTSerial_mio::lock() { // This is the override for SerialBase. // No lock required as we only use SerialBase from interrupt or from // inside our own critical section. } void UARTSerial_mio::unlock() { // This is the override for SerialBase. } void UARTSerial_mio::api_lock(void) { //_mutex.lock(); } void UARTSerial_mio::api_unlock(void) { //_mutex.unlock(); } void UARTSerial_mio::rx_irq(void) { bool was_empty = _rxbuf.empty(); /* Fill in the receive buffer if the peripheral is readable * and receive buffer is not full. */ while (!_rxbuf.full() && SerialBase::readable()) { char data = SerialBase::_base_getc(); _rxbuf.push(data); } if (_rx_irq_enabled && _rxbuf.full()) { disable_rx_irq(); } /* Report the File handler that data is ready to be read from the buffer. */ if (was_empty && !_rxbuf.empty()) { wake(); } } // Also called from write to start transfer void UARTSerial_mio::tx_irq(void) { bool was_full = _txbuf.full(); char data; /* Write to the peripheral if there is something to write * and if the peripheral is available to write. */ while (SerialBase::writeable() && _txbuf.pop(data)) { SerialBase::_base_putc(data); } if (_tx_irq_enabled && _txbuf.empty()) { disable_tx_irq(); } /* Report the File handler that data can be written to peripheral. */ if (was_full && !_txbuf.full() && !hup()) { wake(); } } /* These are all called from critical section */ void UARTSerial_mio::enable_rx_irq() { SerialBase::attach(callback(this, &UARTSerial_mio::rx_irq), RxIrq); _rx_irq_enabled = true; } void UARTSerial_mio::disable_rx_irq() { SerialBase::attach(NULL, RxIrq); _rx_irq_enabled = false; } void UARTSerial_mio::enable_tx_irq() { SerialBase::attach(callback(this, &UARTSerial_mio::tx_irq), TxIrq); _tx_irq_enabled = true; } void UARTSerial_mio::disable_tx_irq() { SerialBase::attach(NULL, TxIrq); _tx_irq_enabled = false; } int UARTSerial_mio::enable_input(bool enabled) { core_util_critical_section_enter(); if (_rx_enabled != enabled) { if (enabled) { UARTSerial_mio::rx_irq(); if (!_rxbuf.full()) { enable_rx_irq(); } } else { disable_rx_irq(); } _rx_enabled = enabled; } core_util_critical_section_exit(); return 0; } int UARTSerial_mio::enable_output(bool enabled) { core_util_critical_section_enter(); if (_tx_enabled != enabled) { if (enabled) { UARTSerial_mio::tx_irq(); if (!_txbuf.empty()) { enable_tx_irq(); } } else { disable_tx_irq(); } _tx_enabled = enabled; } core_util_critical_section_exit(); return 0; } void UARTSerial_mio::wait_ms(uint32_t millisec) { /* wait_ms implementation for RTOS spins until exact microseconds - we * want to just sleep until next tick. */ #if MBED_CONF_RTOS_PRESENT rtos::ThisThread::sleep_for(millisec); #else ::wait_ms(millisec); #endif } void UARTSerial_mio::wait_us(uint32_t microseconds) { /* wait_ms implementation for RTOS spins until exact microseconds - we * want to just sleep until next tick. */ #if MBED_CONF_RTOS_PRESENT rtos::ThisThread::sleep_for(microseconds/1000); #else ::wait_us(microseconds); #endif } } //namespace mbed #endif //(DEVICE_SERIAL && DEVICE_INTERRUPTIN)