UARTSerial: add flow control and format APIs

Add passthrough APIs to enable the flow control and format methods from
SerialBase to be accessed.

Modify the RX data pump so it stops reading data and disables the IRQ
when the buffer is full, to allow UART automatic flow control to work.

In principle it would also be possible as a future enhancement to
provide XON/XOFF flow control, or manual RTS/CTS control using GPIO, but
this commit at least restores the functionality present in Serial,
SerialBase and RawSerial that was missing in UARTSerial.
pull/5088/head
Kevin Bracey 2017-07-06 13:27:01 +03:00
parent 7b428916f5
commit c262a035f6
2 changed files with 71 additions and 6 deletions

View File

@ -27,6 +27,7 @@ UARTSerial::UARTSerial(PinName tx, PinName rx, int baud) :
SerialBase(tx, rx, baud),
_blocking(true),
_tx_irq_enabled(false),
_rx_irq_enabled(true),
_dcd_irq(NULL)
{
/* Attatch IRQ routines to the serial device. */
@ -63,6 +64,22 @@ void UARTSerial::set_data_carrier_detect(PinName dcd_pin, bool active_high)
}
}
void UARTSerial::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::set_flow_control(Flow type, PinName flow1, PinName flow2)
{
api_lock();
SerialBase::set_flow_control(type, flow1, flow2);
api_unlock();
}
#endif
int UARTSerial::close()
{
/* Does not let us pass a file descriptor. So how to close ?
@ -171,6 +188,16 @@ ssize_t UARTSerial::read(void* buffer, size_t length)
data_read++;
}
core_util_critical_section_enter();
if (!_rx_irq_enabled) {
UARTSerial::rx_irq(); // only read from hardware in one place
if (!_rxbuf.full()) {
SerialBase::attach(callback(this, &UARTSerial::rx_irq), RxIrq);
_rx_irq_enabled = true;
}
}
core_util_critical_section_exit();
api_unlock();
return data_read;
@ -238,13 +265,14 @@ void UARTSerial::rx_irq(void)
/* Fill in the receive buffer if the peripheral is readable
* and receive buffer is not full. */
while (SerialBase::readable()) {
while (!_rxbuf.full() && SerialBase::readable()) {
char data = SerialBase::_base_getc();
if (!_rxbuf.full()) {
_rxbuf.push(data);
} else {
/* Drop - can we report in some way? */
}
_rxbuf.push(data);
}
if (_rx_irq_enabled && _rxbuf.full()) {
SerialBase::attach(NULL, RxIrq);
_rx_irq_enabled = false;
}
/* Report the File handler that data is ready to be read from the buffer. */

View File

@ -158,6 +158,42 @@ public:
*/
void set_baud(int baud);
// Expose private SerialBase::Parity as UARTSerial::Parity
using SerialBase::Parity;
// In C++11, we wouldn't need to also have using directives for each value
using SerialBase::None;
using SerialBase::Odd;
using SerialBase::Even;
using SerialBase::Forced1;
using SerialBase::Forced0;
/** Set the transmission format used by the serial port
*
* @param bits The number of bits in a word (5-8; default = 8)
* @param parity The parity used (None, Odd, Even, Forced1, Forced0; default = None)
* @param stop_bits The number of stop bits (1 or 2; default = 1)
*/
void set_format(int bits=8, Parity parity=UARTSerial::None, int stop_bits=1);
#if DEVICE_SERIAL_FC
// For now use the base enum - but in future we may have extra options
// such as XON/XOFF or manual GPIO RTSCTS.
using SerialBase::Flow;
// In C++11, we wouldn't need to also have using directives for each value
using SerialBase::Disabled;
using SerialBase::RTS;
using SerialBase::CTS;
using SerialBase::RTSCTS;
/** Set the flow control type on the serial port
*
* @param type the flow control type (Disabled, RTS, CTS, RTSCTS)
* @param flow1 the first flow control pin (RTS for RTS or RTSCTS, CTS for CTS)
* @param flow2 the second flow control pin (CTS for RTSCTS)
*/
void set_flow_control(Flow type, PinName flow1=NC, PinName flow2=NC);
#endif
private:
/** SerialBase lock override */
@ -184,6 +220,7 @@ private:
bool _blocking;
bool _tx_irq_enabled;
bool _rx_irq_enabled;
InterruptIn *_dcd_irq;
/** Device Hanged up