Serial Upper Half: Add watermarks to RX flow control logic

This commit is contained in:
Gregory Nutt
2014-12-27 07:43:06 -06:00
parent 1c39b67e32
commit aefde565d3
6 changed files with 133 additions and 23 deletions
+1 -1
View File
@@ -4443,7 +4443,7 @@ void board_led_off(int led);
<code>void rxint(FAR struct uart_dev_s *dev, bool enable);</code><br>
<code>bool rxavailable(FAR struct uart_dev_s *dev);</code><br>
<code>#ifdef CONFIG_SERIAL_IFLOWCONTROL</code><br>
<code>bool rxflowcontrol(FAR struct uart_dev_s *dev);</code><br>
<code>bool rxflowcontrol(FAR struct uart_dev_s *dev, unsigned int nbuffered, bool upper);</code><br>
<code>#endif</code><br>
<code>void send(FAR struct uart_dev_s *dev, int ch);</code><br>
<code>void txint(FAR struct uart_dev_s *dev, bool enable);</code><br>
+8 -4
View File
@@ -327,7 +327,8 @@ static void up_rxint(struct uart_dev_s *dev, bool enable);
static bool up_rxavailable(struct uart_dev_s *dev);
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool up_rxflowcontrol(struct uart_dev_s *dev);
static bool up_rxflowcontrol(struct uart_dev_s *dev, unsigned int nbuffered,
bool upper);
#endif
static void up_send(struct uart_dev_s *dev, int ch);
static void up_txint(struct uart_dev_s *dev, bool enable);
@@ -2134,13 +2135,16 @@ static bool up_rxavailable(struct uart_dev_s *dev)
* Name: up_rxflowcontrol
*
* Description:
* Called when Rx buffer is full. Return true if the Rx interrupt was
* disabled.
* Called when Rx buffer is full (or exceeds configured watermark levels
* if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
* Return true if UART activated RX flow control to block more incoming
* data
*
****************************************************************************/
#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool up_rxflowcontrol(struct uart_dev_s *dev)
static bool up_rxflowcontrol(struct uart_dev_s *dev,
unsigned int nbuffered, bool upper)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
uint16_t ie;
+42 -8
View File
@@ -523,6 +523,48 @@ config SERIAL_NPOLLWAITERS
Maximum number of threads than can be waiting for POLL events.
Default: 2
config SERIAL_IFLOWCONTROL
bool
default n
config SERIAL_OFLOWCONTROL
bool
default n
config SERIAL_IFLOWCONTROL_WATERMARKS
bool "RX flow control watermarks"
default n
depends on SERIAL_IFLOWCONTROL
---help---
Call the "lower half" rxflowcontrol method whenever the number of
characters in the serial RX buffer falls above an upper water mark
level or below a lower watermark level. The default behavior is to
call the rxflowcontrol method only when the RX buffer is full.
if SERIAL_IFLOWCONTROL_WATERMARKS
config SERIAL_IFLOWCONTROL_LOWER_WATERMARK
int "RX lower Watermark (percent)"
default 10
range 0 100
---help---
Call the rxflowcontrol method then there are this amount (or or less)
data buffered in the serial drivers RX buffer. This is expressed
as a percentage of the total size of the RX buffer which may vary
from instance-to-instance.
config SERIAL_IFLOWCONTROL_UPPER_WATERMARK
int "RX upper Watermark (percent)"
default 90
range 0 100
---help---
Call the rxflowcontrol method then there are this amount (or more)
data buffered in the serial drivers RX buffer. This is expressed
as a percentage of the total size of the RX buffer which may vary
from instance-to-instance.
endif # SERIAL_IFLOWCONTROL_WATERMARKS
config SERIAL_TIOCSERGSTRUCT
bool "Support TIOCSERGSTRUCT"
default n
@@ -1843,11 +1885,3 @@ config SCI1_2STOP
1=Two stop bits
endmenu # SCI1 Configuration
config SERIAL_IFLOWCONTROL
bool
default n
config SERIAL_OFLOWCONTROL
bool
default n
+30 -1
View File
@@ -522,6 +522,10 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
{
FAR struct inode *inode = filep->f_inode;
FAR uart_dev_t *dev = inode->i_private;
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
unsigned int nbuffered;
unsigned int watermark;
#endif
irqstate_t flags;
ssize_t recvd = 0;
int16_t tail;
@@ -565,7 +569,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
#endif
/* Check if there is more data to return in the circular buffer.
* NOTE: Rx interrupt handling logic may aynchronously increment
* NOTE: Rx interrupt handling logic may asynchronously increment
* the head index but must not modify the tail index. The tail
* index is only modified in this function. Therefore, no
* special handshaking is required here.
@@ -774,6 +778,30 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
}
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
/* How many bytes are now buffered */
if (buf->head >= buf->tail)
{
nbuffered = buf->head - buf->tail;
}
else
{
nbuffered = buf->size - buf->tail + buf->head;
}
/* Is the level now below the watermark level that we need to report? */
watermark = (CONFIG_SERIAL_IFLOWCONTROL_LOWER_WATERMARK * buf->size) / 100
if (nbuffered <= watermark)
{
/* Let the lower level driver know that the watermark level has been
* crossed.
*/
(void)uart_rxflowcontrol(dev, nubuffered, false))
}
#else
if (dev->recv.head == dev->recv.tail)
{
/* We might leave Rx interrupt disabled if full recv buffer was read
@@ -782,6 +810,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
uart_enablerxint(dev);
}
#endif
#endif
uart_givesem(&dev->recv.sem);
+45 -5
View File
@@ -138,6 +138,9 @@ void uart_xmitchars(FAR uart_dev_t *dev)
void uart_recvchars(FAR uart_dev_t *dev)
{
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
unsigned int watermark;
#endif
unsigned int status;
int nexthead = dev->recv.head + 1;
uint16_t nbytes = 0;
@@ -147,6 +150,12 @@ void uart_recvchars(FAR uart_dev_t *dev)
nexthead = 0;
}
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
/* Pre-calcuate the watermark level that we will need to test against. */
watermark = (CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK * buf->size) / 100
#endif
/* Loop putting characters into the receive buffer until there are no further
* characters to available.
*/
@@ -157,19 +166,50 @@ void uart_recvchars(FAR uart_dev_t *dev)
char ch;
#ifdef CONFIG_SERIAL_IFLOWCONTROL
/* Check if RX buffer is full and allow serial low-level driver to pause
* processing. This allows proper utilization of hardware flow control.
*/
unsigned int nbuffered;
if (is_full)
/* How many bytes are buffered */
if (buf->head >= buf->tail)
{
if (uart_rxflowcontrol(dev))
nbuffered = buf->head - buf->tail;
}
else
{
nbuffered = buf->size - buf->tail + buf->head;
}
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
/* Is the level now above the watermark level that we need to report? */
if (nbuffered >= watermark)
{
/* Let the lower level driver know that the watermark level has been
* crossed.
*/
if (uart_rxflowcontrol(dev, nubuffered, true))
{
/* Low-level driver activated RX flow control, exit loop now. */
break;
}
}
#else
/* Check if RX buffer is full and allow serial low-level driver to pause
* processing. This allows proper utilization of hardware flow control.
*/
if (is_full)
{
if (uart_rxflowcontrol(dev, nbuffered, true))
{
/* Low-level driver activated RX flow control, exit loop now. */
break;
}
}
#endif
#endif
ch = uart_receive(dev, &status);
+7 -4
View File
@@ -79,8 +79,8 @@
#define uart_receive(dev,s) dev->ops->receive(dev,s)
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#define uart_rxflowcontrol(dev) \
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev))
#define uart_rxflowcontrol(dev,n,u) \
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev,n,u))
#endif
/************************************************************************************
@@ -165,9 +165,12 @@ struct uart_ops_s
CODE bool (*rxavailable)(FAR struct uart_dev_s *dev);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
/* Return true if UART activated RX flow control to block more incoming data. */
/* Return true if UART activated RX flow control to block more incoming
* data.
*/
CODE bool (*rxflowcontrol)(FAR struct uart_dev_s *dev);
CODE bool (*rxflowcontrol)(FAR struct uart_dev_s *dev,
unsigned int nbuffered, bool upper);
#endif
/* This method will send one byte on the UART */