diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-12-27 07:43:06 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-12-27 07:43:06 -0600 |
commit | bd2e37d615f8a029263b8e4fad3bae504809943a (patch) | |
tree | d5b5e39781bcb9a6db5e134d60fb86ade737e6b2 | |
parent | 351eeaf474338872c4e07c215ab12ca45e0b82bb (diff) | |
download | px4-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.html | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_serial.c | 12 | ||||
-rw-r--r-- | nuttx/drivers/serial/Kconfig | 50 | ||||
-rw-r--r-- | nuttx/drivers/serial/serial.c | 31 | ||||
-rw-r--r-- | nuttx/drivers/serial/serialirq.c | 42 | ||||
-rw-r--r-- | nuttx/include/nuttx/serial/serial.h | 11 |
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 */ |