mirror of
https://github.com/apache/nuttx.git
synced 2026-05-13 10:27:25 +08:00
Serial Upper Half: Add watermarks to RX flow control logic
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user