summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-12-27 07:43:06 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-12-27 07:43:06 -0600
commitbd2e37d615f8a029263b8e4fad3bae504809943a (patch)
treed5b5e39781bcb9a6db5e134d60fb86ade737e6b2
parent351eeaf474338872c4e07c215ab12ca45e0b82bb (diff)
downloadpx4-nuttx-bd2e37d615f8a029263b8e4fad3bae504809943a.tar.gz
px4-nuttx-bd2e37d615f8a029263b8e4fad3bae504809943a.tar.bz2
px4-nuttx-bd2e37d615f8a029263b8e4fad3bae504809943a.zip
Serial Upper Half: Add watermarks to RX flow control logic
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html2
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_serial.c12
-rw-r--r--nuttx/drivers/serial/Kconfig50
-rw-r--r--nuttx/drivers/serial/serial.c31
-rw-r--r--nuttx/drivers/serial/serialirq.c42
-rw-r--r--nuttx/include/nuttx/serial/serial.h11
6 files changed, 129 insertions, 19 deletions
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html
index 7aebea676..f685d92ab 100644
--- a/nuttx/Documentation/NuttxPortingGuide.html
+++ b/nuttx/Documentation/NuttxPortingGuide.html
@@ -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>
diff --git a/nuttx/arch/arm/src/stm32/stm32_serial.c b/nuttx/arch/arm/src/stm32/stm32_serial.c
index 8a7ed0964..698568bd7 100644
--- a/nuttx/arch/arm/src/stm32/stm32_serial.c
+++ b/nuttx/arch/arm/src/stm32/stm32_serial.c
@@ -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;
diff --git a/nuttx/drivers/serial/Kconfig b/nuttx/drivers/serial/Kconfig
index 80956c798..e3c7856b5 100644
--- a/nuttx/drivers/serial/Kconfig
+++ b/nuttx/drivers/serial/Kconfig
@@ -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
diff --git a/nuttx/drivers/serial/serial.c b/nuttx/drivers/serial/serial.c
index 4d40527fe..9b9b82669 100644
--- a/nuttx/drivers/serial/serial.c
+++ b/nuttx/drivers/serial/serial.c
@@ -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
@@ -783,6 +811,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);
return recvd;
diff --git a/nuttx/drivers/serial/serialirq.c b/nuttx/drivers/serial/serialirq.c
index 1c76dfe5e..203677354 100644
--- a/nuttx/drivers/serial/serialirq.c
+++ b/nuttx/drivers/serial/serialirq.c
@@ -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,13 +166,43 @@ void uart_recvchars(FAR uart_dev_t *dev)
char ch;
#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ unsigned int nbuffered;
+
+ /* How many bytes are buffered */
+
+ if (buf->head >= buf->tail)
+ {
+ 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))
+ if (uart_rxflowcontrol(dev, nbuffered, true))
{
/* Low-level driver activated RX flow control, exit loop now. */
@@ -171,6 +210,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
}
}
#endif
+#endif
ch = uart_receive(dev, &status);
diff --git a/nuttx/include/nuttx/serial/serial.h b/nuttx/include/nuttx/serial/serial.h
index 2a32e416b..34eb1cc6d 100644
--- a/nuttx/include/nuttx/serial/serial.h
+++ b/nuttx/include/nuttx/serial/serial.h
@@ -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 */