This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new bb14b94f112 drivers/rpmsg/rpmsg_port_uart: add optional LZF compression
bb14b94f112 is described below

commit bb14b94f112f93e6153cdc8c06f13285c2ef5d9c
Author: wangshaoxin <[email protected]>
AuthorDate: Fri Oct 30 18:35:56 2026 +0800

    drivers/rpmsg/rpmsg_port_uart: add optional LZF compression
    
    Add CONFIG_RPMSG_PORT_UART_COMPRESSION. When it is enabled, the TX path
    compresses the frame payload with lzf_compress() before byte escaping
    and sends it with the CMD_LZF flag; the RX path decompresses LZF frames
    in rpmsg_port_uart_process_rx_data() into a reserved rx queue buffer.
    Payloads that do not compress are sent as is.
    
    This reduces the UART bandwidth used by compressible rpmsg traffic.
    Both sides of the link must enable the option.
    
    Signed-off-by: wangshaoxin <[email protected]>
---
 drivers/rpmsg/Kconfig           |   9 ++++
 drivers/rpmsg/rpmsg_port_uart.c | 112 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 117 insertions(+), 4 deletions(-)

diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index f21d908a552..2939850e1af 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -112,6 +112,15 @@ config RPMSG_PORT_UART_CRC
        bool "Rpmsg UART Port CRC Enable"
        default n
 
+config RPMSG_PORT_UART_COMPRESSION
+       bool "Rpmsg UART Port LZF Compression"
+       default n
+       depends on LIBC_LZF
+       ---help---
+               Enable LZF compression for rpmsg port uart data frames.
+               Compresses payload before byte-escaping to reduce UART
+               bandwidth usage. Both TX and RX sides must enable this.
+
 config RPMSG_PORT_UART_DEBUG
        bool "Rpmsg UART DEBUG Enable"
        default n
diff --git a/drivers/rpmsg/rpmsg_port_uart.c b/drivers/rpmsg/rpmsg_port_uart.c
index a19bf749548..d9557a2af90 100644
--- a/drivers/rpmsg/rpmsg_port_uart.c
+++ b/drivers/rpmsg/rpmsg_port_uart.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <execinfo.h>
 #include <fcntl.h>
+#include <lzf.h>
 #include <stdint.h>
 #include <stdio.h>
 
@@ -48,6 +49,9 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define RPMSG_PORT_UART_CMD_NORMAL         0x00
+#define RPMSG_PORT_UART_CMD_LZF            0x01
+
 #define RPMSG_PORT_UART_START              0x7f
 #define RPMSG_PORT_UART_CONNREQ            0x7e
 #define RPMSG_PORT_UART_CONNACK            0x7d
@@ -121,6 +125,11 @@ struct rpmsg_port_uart_s
   struct pm_wakelock_s            tx_wakelock;
   struct pm_wakelock_s            rx_wakelock;
 #endif
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+  FAR struct rpmsg_port_header_s *tx_lzfhdr;  /* Buffer for LZF compression 
output */
+  FAR struct rpmsg_port_header_s *rx_lzfhdr;  /* Pre-reserved rxq buffer for 
decompression */
+  lzf_state_t                     tx_lzfhtab; /* LZF compression hash table */
+#endif
 };
 
 /****************************************************************************
@@ -374,12 +383,52 @@ static void rpmsg_port_uart_send_frame(FAR struct 
rpmsg_port_uart_s *rpuart,
 static void rpmsg_port_uart_send_data(FAR struct rpmsg_port_uart_s *rpuart,
                                       FAR struct rpmsg_port_header_s *hdr)
 {
-  rpmsgdbg("Send data len: %" PRIu16 "\n", hdr->len);
+  uint16_t len = hdr->len - sizeof(*hdr);
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+  FAR struct rpmsg_port_header_s *lzfhdr = rpuart->tx_lzfhdr;
+  FAR struct lzf_header_s *reshdr;
+  size_t lzflen;
+
+  /* Try LZF compression: compress hdr->buf payload into lzfhdr->buf.
+   * out_len is set to len so compression only succeeds (TYPE1) when
+   * the result is strictly smaller than the original data.
+   *
+   * Side effects of lzf_compress:
+   *  - TYPE1 (compressed): writes a 7-byte LZF file header at
+   *    lzfhdr->buf - 7, clobbering lzfhdr's port header fields.
+   *    We rebuild them below before sending.
+   *  - TYPE0 (incompressible fallback): writes a 5-byte header at
+   *    hdr->buf - 5, clobbering hdr->cmd, hdr->avail, and hdr->len.
+   *    The else branch restores all three fields.
+   */
+
+  lzflen = lzf_compress(hdr->buf, len, lzfhdr->buf, len,
+                        rpuart->tx_lzfhtab, &reshdr);
+  if (reshdr->lzf_type == LZF_TYPE1_HDR)
+    {
+      /* Compression successful (TYPE1).  The compressed payload sits
+       * at lzfhdr->buf with length = lzflen - LZF_TYPE1_HDR_SIZE.
+       * Copy the original port header to lzfhdr (restoring fields
+       * clobbered by the LZF file header), then override cmd and len
+       * for the compressed frame.  Finally redirect hdr to lzfhdr
+       * so the common CRC + send path below uses the compressed frame.
+       */
+
+      memcpy(lzfhdr, hdr, sizeof(*lzfhdr));
+      lzfhdr->cmd = RPMSG_PORT_UART_CMD_LZF;
+      lzfhdr->len = sizeof(*lzfhdr) + lzflen - LZF_TYPE1_HDR_SIZE;
+      hdr = lzfhdr;
+    }
+  else
+#endif
+    {
+      hdr->cmd = RPMSG_PORT_UART_CMD_NORMAL;
+      hdr->len = sizeof(*hdr) + len;
+    }
 
-  hdr->cmd = 0;
+  rpmsgdbg("Send data len: %" PRIu16 "\n", hdr->len);
   hdr->avail = 0;
   hdr->crc = rpmsg_port_uart_crc16(hdr);
-
   rpmsg_port_uart_send_frame(rpuart, hdr, hdr->len);
 }
 
@@ -625,6 +674,37 @@ rpmsg_port_uart_process_rx_data(FAR struct 
rpmsg_port_uart_s *rpuart)
   while ((hdr = rpmsg_port_queue_get_buffer(rxq, false)) != NULL)
     {
       rpmsgdbg("Received data hdr=%p len=%u\n", hdr, hdr->len);
+
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+      if (hdr->cmd == RPMSG_PORT_UART_CMD_LZF)
+        {
+          FAR struct rpmsg_port_header_s *rxhdr = rpuart->rx_lzfhdr;
+          uint16_t rxlen = hdr->len - sizeof(*hdr);
+
+          /* Decompress hdr->buf (compressed payload) into the
+           * pre-reserved rxhdr buffer.  On success, copy the port
+           * header from hdr to rxhdr, fix up rxhdr->len with the
+           * decompressed size, then swap: rxhdr goes to rx_cb and
+           * the consumed hdr becomes the new rx_lzfhdr.
+           */
+
+          rxlen = lzf_decompress(hdr->buf, rxlen, rxhdr->buf,
+                                 rxq->len - sizeof(*rxhdr));
+          if (rxlen > 0)
+            {
+              memcpy(rxhdr, hdr, sizeof(*rxhdr));
+              rxhdr->len = sizeof(*rxhdr) + rxlen;
+              rpuart->rx_lzfhdr = hdr;
+              hdr = rxhdr;
+            }
+          else
+            {
+              rpmsgerr("LZF decompress failed\n");
+              PANIC();
+            }
+        }
+#endif
+
       rpuart->rx_cb(&rpuart->port, hdr);
     }
 }
@@ -886,13 +966,21 @@ int rpmsg_port_uart_initialize(FAR const struct 
rpmsg_port_config_s *cfg,
   int ret;
   int rx;
 
-  rpuart = kmm_zalloc(sizeof(*rpuart));
+  rpuart = kmm_malloc(sizeof(*rpuart)
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+                      + cfg->txlen
+#endif
+                    );
   if (rpuart == NULL)
     {
       rpmsgerr("Malloc rptun uart failed\n");
       return -ENOMEM;
     }
 
+  memset(rpuart, 0, sizeof(*rpuart));
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+  rpuart->tx_lzfhdr = (FAR struct rpmsg_port_header_s *)(rpuart + 1);
+#endif
   rpuart->rx_state = RPMSG_PORT_UART_RX_WAIT_START;
   rpuart->tx_staywake = RPMSG_PORT_UART_STAYWAKE1;
   nxevent_init(&rpuart->event, 0);
@@ -918,6 +1006,17 @@ int rpmsg_port_uart_initialize(FAR const struct 
rpmsg_port_config_s *cfg,
       goto err_rpmsg_port;
     }
 
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+  rpuart->rx_lzfhdr = rpmsg_port_queue_get_available_buffer(
+                        &rpuart->port.rxq, false);
+  if (rpuart->rx_lzfhdr == NULL)
+    {
+      rpmsgerr("Get LZF rx queue buffer failed\n");
+      ret = -ENOMEM;
+      goto err_lzf;
+    }
+#endif
+
 #ifdef CONFIG_PM
   snprintf(arg1, sizeof(arg1), "rpmsg-uart-rx-%s", cfg->remotecpu);
   pm_wakelock_init(&rpuart->rx_wakelock, arg1, PM_IDLE_DOMAIN, PM_IDLE);
@@ -964,6 +1063,11 @@ err_rx_thread:
 #ifdef CONFIG_PM
   pm_wakelock_uninit(&rpuart->tx_wakelock);
   pm_wakelock_uninit(&rpuart->rx_wakelock);
+#endif
+#ifdef CONFIG_RPMSG_PORT_UART_COMPRESSION
+  rpmsg_port_queue_return_buffer(&rpuart->port.rxq,
+                                 rpuart->rx_lzfhdr);
+err_lzf:
 #endif
   rpmsg_port_uninitialize(&rpuart->port);
 err_rpmsg_port:

Reply via email to