mirror of
https://github.com/apache/nuttx.git
synced 2026-06-03 22:20:31 +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>void rxint(FAR struct uart_dev_s *dev, bool enable);</code><br>
|
||||||
<code>bool rxavailable(FAR struct uart_dev_s *dev);</code><br>
|
<code>bool rxavailable(FAR struct uart_dev_s *dev);</code><br>
|
||||||
<code>#ifdef CONFIG_SERIAL_IFLOWCONTROL</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>#endif</code><br>
|
||||||
<code>void send(FAR struct uart_dev_s *dev, int ch);</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>
|
<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);
|
static bool up_rxavailable(struct uart_dev_s *dev);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#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
|
#endif
|
||||||
static void up_send(struct uart_dev_s *dev, int ch);
|
static void up_send(struct uart_dev_s *dev, int ch);
|
||||||
static void up_txint(struct uart_dev_s *dev, bool enable);
|
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
|
* Name: up_rxflowcontrol
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Called when Rx buffer is full. Return true if the Rx interrupt was
|
* Called when Rx buffer is full (or exceeds configured watermark levels
|
||||||
* disabled.
|
* if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
|
||||||
|
* Return true if UART activated RX flow control to block more incoming
|
||||||
|
* data
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#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;
|
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
|
||||||
uint16_t ie;
|
uint16_t ie;
|
||||||
|
|||||||
+42
-8
@@ -523,6 +523,48 @@ config SERIAL_NPOLLWAITERS
|
|||||||
Maximum number of threads than can be waiting for POLL events.
|
Maximum number of threads than can be waiting for POLL events.
|
||||||
Default: 2
|
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
|
config SERIAL_TIOCSERGSTRUCT
|
||||||
bool "Support TIOCSERGSTRUCT"
|
bool "Support TIOCSERGSTRUCT"
|
||||||
default n
|
default n
|
||||||
@@ -1843,11 +1885,3 @@ config SCI1_2STOP
|
|||||||
1=Two stop bits
|
1=Two stop bits
|
||||||
|
|
||||||
endmenu # SCI1 Configuration
|
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 struct inode *inode = filep->f_inode;
|
||||||
FAR uart_dev_t *dev = inode->i_private;
|
FAR uart_dev_t *dev = inode->i_private;
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
unsigned int nbuffered;
|
||||||
|
unsigned int watermark;
|
||||||
|
#endif
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
ssize_t recvd = 0;
|
ssize_t recvd = 0;
|
||||||
int16_t tail;
|
int16_t tail;
|
||||||
@@ -565,7 +569,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check if there is more data to return in the circular buffer.
|
/* 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
|
* the head index but must not modify the tail index. The tail
|
||||||
* index is only modified in this function. Therefore, no
|
* index is only modified in this function. Therefore, no
|
||||||
* special handshaking is required here.
|
* 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
|
||||||
|
#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)
|
if (dev->recv.head == dev->recv.tail)
|
||||||
{
|
{
|
||||||
/* We might leave Rx interrupt disabled if full recv buffer was read
|
/* 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);
|
uart_enablerxint(dev);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uart_givesem(&dev->recv.sem);
|
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)
|
void uart_recvchars(FAR uart_dev_t *dev)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
unsigned int watermark;
|
||||||
|
#endif
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
int nexthead = dev->recv.head + 1;
|
int nexthead = dev->recv.head + 1;
|
||||||
uint16_t nbytes = 0;
|
uint16_t nbytes = 0;
|
||||||
@@ -147,6 +150,12 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
nexthead = 0;
|
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
|
/* Loop putting characters into the receive buffer until there are no further
|
||||||
* characters to available.
|
* characters to available.
|
||||||
*/
|
*/
|
||||||
@@ -157,19 +166,50 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
/* Check if RX buffer is full and allow serial low-level driver to pause
|
unsigned int nbuffered;
|
||||||
* processing. This allows proper utilization of hardware flow control.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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. */
|
/* Low-level driver activated RX flow control, exit loop now. */
|
||||||
|
|
||||||
break;
|
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
|
#endif
|
||||||
|
|
||||||
ch = uart_receive(dev, &status);
|
ch = uart_receive(dev, &status);
|
||||||
|
|||||||
@@ -79,8 +79,8 @@
|
|||||||
#define uart_receive(dev,s) dev->ops->receive(dev,s)
|
#define uart_receive(dev,s) dev->ops->receive(dev,s)
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
#define uart_rxflowcontrol(dev) \
|
#define uart_rxflowcontrol(dev,n,u) \
|
||||||
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev))
|
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev,n,u))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@@ -165,9 +165,12 @@ struct uart_ops_s
|
|||||||
CODE bool (*rxavailable)(FAR struct uart_dev_s *dev);
|
CODE bool (*rxavailable)(FAR struct uart_dev_s *dev);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#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
|
#endif
|
||||||
|
|
||||||
/* This method will send one byte on the UART */
|
/* This method will send one byte on the UART */
|
||||||
|
|||||||
Reference in New Issue
Block a user