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

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

commit fcff5d43b7ac6be973a885b7cf1af165b1e49729
Author: Tiago Medicci Serrano <[email protected]>
AuthorDate: Fri Nov 10 09:39:21 2023 -0300

    drivers/rmt: Implement an upper-half RMT character driver
    
    The RMT (Remote Control) character driver allows to use the RMT
    peripheral (usually, a one-wire peripheral dedicated to driving
    IR remote control) as a character driver.
    
    Please note that this perpiheral depends on the lower-half specific
    driver implementation.
---
 drivers/Kconfig                                    |   1 +
 drivers/Makefile                                   |   1 +
 drivers/rmt/CMakeLists.txt                         |  29 ++
 drivers/rmt/Kconfig                                |  36 +++
 drivers/rmt/Make.defs                              |  30 ++
 drivers/rmt/rmtchar.c                              | 339 +++++++++++++++++++++
 include/nuttx/mm/circbuf.h                         |   2 +-
 .../include/esp32_rmt.h => include/nuttx/rmt/rmt.h |  59 +++-
 .../esp32_rmt.h => include/nuttx/rmt/rmtchar.h     |  49 ++-
 9 files changed, 518 insertions(+), 28 deletions(-)

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 11991ae59a..77031932d2 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -36,6 +36,7 @@ source "drivers/note/Kconfig"
 source "drivers/pipes/Kconfig"
 source "drivers/power/Kconfig"
 source "drivers/regmap/Kconfig"
+source "drivers/rmt/Kconfig"
 source "drivers/rptun/Kconfig"
 source "drivers/sensors/Kconfig"
 source "drivers/serial/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index d9d3244f61..e553af04d3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -55,6 +55,7 @@ include note/Make.defs
 include pipes/Make.defs
 include power/Make.defs
 include regmap/Make.defs
+include rmt/Make.defs
 include rptun/Make.defs
 include sensors/Make.defs
 include serial/Make.defs
diff --git a/drivers/rmt/CMakeLists.txt b/drivers/rmt/CMakeLists.txt
new file mode 100644
index 0000000000..95d89bece4
--- /dev/null
+++ b/drivers/rmt/CMakeLists.txt
@@ -0,0 +1,29 @@
+# 
##############################################################################
+# drivers/rmt/CMakeLists.txt
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor
+# license agreements.  See the NOTICE file distributed with this work for
+# additional information regarding copyright ownership.  The ASF licenses this
+# file to you under the Apache License, Version 2.0 (the "License"); you may 
not
+# use this file except in compliance with the License.  You may obtain a copy 
of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# 
##############################################################################
+
+if(CONFIG_RMT)
+  set(SRCS)
+
+  if(CONFIG_RMTCHAR)
+    list(APPEND SRCS rmtchar.c)
+  endif()
+
+  target_sources(drivers PRIVATE ${SRCS})
+endif()
diff --git a/drivers/rmt/Kconfig b/drivers/rmt/Kconfig
new file mode 100644
index 0000000000..0e8de76d75
--- /dev/null
+++ b/drivers/rmt/Kconfig
@@ -0,0 +1,36 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig RMT
+       bool "RMT (Remote Control) Driver Support"
+       default n
+       ---help---
+               This option selects common RMT (Remote Control) options and 
should be
+               enabled by the platforms that implement a Remote Control 
Peripheral.
+
+if RMT
+
+config RMTCHAR
+       bool "RMT character driver (for testing only)"
+       default n
+       ---help---
+               The RMT character driver is a simple character driver that 
supports
+               RMT transfers via read() and write(). This driver is primarily
+               intended to support RMT testing. It is not suitable for use in 
any
+               real driver application in its current form because its buffer
+               management heuristics are dependent on the lower half driver
+               (device-specific). Applications that use the RMT peripheral to
+               implement protocols such as NEC (for Remote Control), or use 
this
+               driver to implement other 1-wire protocols such as WS2812 LED 
must
+               provide their specific driver implementation.
+
+config RMT_DEFAULT_RX_BUFFER_SIZE
+       int "Default RX buffer size"
+       default 100
+       ---help---
+               The RMT RX default buffer size. This is the expected buffer size
+               that should be returned on a `read()` operation.
+
+endif # RMT
diff --git a/drivers/rmt/Make.defs b/drivers/rmt/Make.defs
new file mode 100644
index 0000000000..93e20c8048
--- /dev/null
+++ b/drivers/rmt/Make.defs
@@ -0,0 +1,30 @@
+############################################################################
+# drivers/rmt/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifeq ($(CONFIG_RMT),y)
+
+ifeq ($(CONFIG_RMTCHAR),y)
+CSRCS += rmtchar.c
+endif
+
+DEPPATH += --dep-path rmt
+VPATH += :rmt
+
+endif
diff --git a/drivers/rmt/rmtchar.c b/drivers/rmt/rmtchar.c
new file mode 100644
index 0000000000..2c22e8d1c0
--- /dev/null
+++ b/drivers/rmt/rmtchar.c
@@ -0,0 +1,339 @@
+/****************************************************************************
+ * drivers/rmt/rmtchar.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mm/circbuf.h>
+#include <nuttx/mutex.h>
+#include <nuttx/rmt/rmt.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define DEVNAME_FMT    "/dev/rmt%d"
+#define DEVNAME_FMTLEN (8 + 3 + 1)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rmt_driver_s
+{
+  /* The lower half RMT driver */
+
+  FAR struct rmt_dev_s *rmt;
+
+  /* The minor identification of the driver. It's provided by the lower half
+   * driver and it can represent the channel being used.
+   */
+
+  int minor;
+
+  mutex_t lock;               /* Assures mutually exclusive access */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rmt_open(FAR struct file *filep);
+static int rmt_close(FAR struct file *filep);
+static ssize_t rmt_read(FAR struct file *filep, FAR char *buffer,
+                        size_t buflen);
+static ssize_t rmt_write(FAR struct file *filep, FAR const char *buffer,
+                         size_t buflen);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_rmt_channel_fops =
+{
+  rmt_open,     /* open  */
+  rmt_close,    /* close */
+  rmt_read,     /* read  */
+  rmt_write,    /* write */
+  NULL,         /* seek  */
+  NULL,         /* ioctl */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rmt_open
+ *
+ * Description:
+ *   Prepare the RMT peripheral for use. This method just calls the lower
+ *   half `open` routine if it exists.
+ *
+ * Input Parameters:
+ *   filep - Pointer system file data
+ *
+ * Returned Value:
+ *   The return code of the lower half `open` routine if it exists.
+ *   Please check device-specific driver for more information.
+ *
+ ****************************************************************************/
+
+static int rmt_open(FAR struct file *filep)
+{
+  FAR struct inode *inode;
+  FAR struct rmt_driver_s *priv;
+  int ret = OK;
+
+  /* Get our private data structure */
+
+  inode = filep->f_inode;
+
+  priv = inode->i_private;
+  DEBUGASSERT(priv);
+
+  if (priv->rmt->ops->open)
+    {
+      ret = priv->rmt->ops->open(priv->rmt);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rmt_close
+ *
+ * Description:
+ *   Close the RMT peripheral after use. This method just calls the lower
+ *   half `close` routine if it exists.
+ *
+ * Input Parameters:
+ *   filep - Pointer system file data
+ *
+ * Returned Value:
+ *   The return code of the lower half `close` routine if it exists.
+ *   Please check device-specific driver for more information.
+ *
+ ****************************************************************************/
+
+static int rmt_close(FAR struct file *filep)
+{
+  FAR struct inode *inode;
+  FAR struct rmt_driver_s *priv;
+  int ret = OK;
+
+  /* Get our private data structure */
+
+  inode = filep->f_inode;
+
+  priv = inode->i_private;
+  DEBUGASSERT(priv);
+
+  if (priv->rmt->ops->close)
+    {
+      ret = priv->rmt->ops->close(priv->rmt);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: rmt_read
+ *
+ * Description:
+ *   This function reads data from the RMT device into the provided buffer.
+ *   The read operation is performed by the read function pointer in the
+ *   RMT device's operations structure, if it exists.
+ *
+ * Input Parameters:
+ *   filep   - Pointer to the file structure.
+ *   buffer  - Pointer to the buffer where the read data should be stored.
+ *   buflen  - The maximum amount of data to be read.
+ *
+ * Returned Value:
+ *   Returns the number of bytes read from the RMT device; a negated errno
+ *   value is returned on any failure.
+ *
+ ****************************************************************************/
+
+static ssize_t rmt_read(FAR struct file *filep, FAR char *buffer,
+                        size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct rmt_driver_s *priv;
+  ssize_t nread = 0;
+
+  /* Get our private data structure */
+
+  inode = filep->f_inode;
+
+  priv = inode->i_private;
+  DEBUGASSERT(priv);
+
+  if (priv->rmt->ops->read)
+    {
+      int ret = priv->rmt->ops->read(priv->rmt, buffer, buflen);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      for (; ; )
+        {
+          nread = circbuf_read(priv->rmt->circbuf , buffer, buflen);
+          if (nread != 0 || (filep->f_oflags & O_NONBLOCK))
+            {
+              break;
+            }
+
+          while (circbuf_is_empty(priv->rmt->circbuf))
+            {
+              nxsem_wait_uninterruptible(priv->rmt->recvsem);
+            }
+        }
+    }
+
+  return nread;
+}
+
+/****************************************************************************
+ * Name: rmt_write
+ *
+ * Description:
+ *   Write to the RMT peripheral. This method just calls the lower half
+ *   `write` routine if it exists.
+ *
+ * Input Parameters:
+ *   filep  - Pointer system file data
+ *   buffer - Data to write to the RMT device
+ *   buflen - Number of bytes requested to write
+ *
+ * Returned Value:
+ *   Number of bytes that has been successfully written, or 0 when no
+ *   bytes could be written for any reason.
+ *
+ ****************************************************************************/
+
+static ssize_t rmt_write(FAR struct file *filep, FAR const char *buffer,
+                         size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct rmt_driver_s *priv;
+  ssize_t nwritten = 0;
+
+  /* Get our private data structure */
+
+  inode = filep->f_inode;
+
+  priv = inode->i_private;
+  DEBUGASSERT(priv);
+
+  if (priv->rmt->ops->write)
+    {
+      nwritten = priv->rmt->ops->write(priv->rmt, buffer, buflen);
+    }
+
+  return nwritten;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rmtchar_register
+ *
+ * Description:
+ *   Create and register the RMT character driver.
+ *
+ *   The RMT character driver is a simple character driver that supports RMT
+ *   transfers via read() and write(). This driver is primarily intended to
+ *   support RMT testing. It is not suitable for use in any real driver
+ *   application in its current form because its buffer management heuristics
+ *   are dependent on the lower half driver (device-specific).
+ *
+ * Input Parameters:
+ *   rmt - An instance of the lower half RMT driver
+ *
+ * Returned Value:
+ *   OK if the driver was successfully registered; A negated errno value is
+ *   returned on any failure.
+ *
+ ****************************************************************************/
+
+int rmtchar_register(FAR struct rmt_dev_s *rmt)
+{
+  FAR struct rmt_driver_s *priv;
+  char devname[DEVNAME_FMTLEN];
+  size_t dev_size = sizeof(struct rmt_driver_s);
+  int ret;
+
+  /* Sanity check */
+
+  DEBUGASSERT(rmt != NULL && (unsigned)rmt->minor < 1000);
+
+  /* Allocate a RMT character device structure */
+
+  priv = kmm_zalloc(dev_size);
+  if (priv)
+    {
+      /* Initialize the RMT character device structure */
+
+      priv->rmt = rmt;
+      priv->minor = rmt->minor;
+      nxmutex_init(&priv->lock);
+
+      /* Create the character device name */
+
+      snprintf(devname, DEVNAME_FMTLEN, DEVNAME_FMT, priv->minor);
+      ret = register_driver(devname, &g_rmt_channel_fops, 0666, priv);
+      if (ret < 0)
+        {
+          /* Free the device structure if we failed to create the character
+           * device.
+           */
+
+          nxmutex_destroy(&priv->lock);
+          kmm_free(priv);
+          return ret;
+        }
+
+      /* Return the result of the registration */
+
+      return ret;
+    }
+
+  return -ENOMEM;
+}
diff --git a/include/nuttx/mm/circbuf.h b/include/nuttx/mm/circbuf.h
index 94bd8791af..e856d3b5e2 100644
--- a/include/nuttx/mm/circbuf.h
+++ b/include/nuttx/mm/circbuf.h
@@ -202,7 +202,7 @@ size_t circbuf_space(FAR struct circbuf_s *circ);
  * Name: circbuf_peekat
  *
  * Description:
- *   Get data speicified position from the circular buffer without removing
+ *   Get data specified position from the circular buffer without removing
  *
  * Note :
  *   That with only one concurrent reader and one concurrent writer,
diff --git a/boards/xtensa/esp32/common/include/esp32_rmt.h 
b/include/nuttx/rmt/rmt.h
similarity index 62%
copy from boards/xtensa/esp32/common/include/esp32_rmt.h
copy to include/nuttx/rmt/rmt.h
index 560c64f29f..1f2b1b216c 100644
--- a/boards/xtensa/esp32/common/include/esp32_rmt.h
+++ b/include/nuttx/rmt/rmt.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/xtensa/esp32/common/include/esp32_rmt.h
+ * include/nuttx/rmt/rmt.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H
-#define __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H
+#ifndef __INCLUDE_NUTTX_RMT_RMT_H
+#define __INCLUDE_NUTTX_RMT_RMT_H
 
 /****************************************************************************
  * Included Files
@@ -27,23 +27,55 @@
 
 #include <nuttx/config.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef CONFIG_RMT
 
 /****************************************************************************
- * Type Definitions
+ * Pre-processor Definitions
  ****************************************************************************/
 
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
+struct rmt_dev_s;
+
+/* The RMT peripheral vtable */
+
+struct rmt_ops_s
+{
+  CODE int      (*open)(FAR struct rmt_dev_s *dev);
+  CODE int      (*close)(FAR struct rmt_dev_s *dev);
+  CODE ssize_t  (*write)(FAR struct rmt_dev_s *dev,
+                         FAR const char *buffer,
+                         size_t buflen);
+  CODE ssize_t  (*read)(FAR struct rmt_dev_s *dev,
+                        FAR char *buffer,
+                        size_t buflen);
+};
+
+/* RMT private data.  This structure only defines the initial fields of the
+ * structure visible to the RMT client.  The specific implementation may
+ * add additional, device-specific fields.
+ */
+
+struct rmt_dev_s
+{
+  FAR const struct rmt_ops_s *ops;
+  FAR struct circbuf_s       *circbuf;
+  sem_t                      *recvsem;
+  int                         minor;
+};
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
 
-#ifdef __cplusplus
+#undef EXTERN
+#if defined(__cplusplus)
 #define EXTERN extern "C"
 extern "C"
 {
@@ -52,16 +84,13 @@ extern "C"
 #endif
 
 /****************************************************************************
- * Inline Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Public Function Prototypes
+ * Public Functions Prototypes
  ****************************************************************************/
 
 #undef EXTERN
-#ifdef __cplusplus
+#if defined(__cplusplus)
 }
 #endif
 
-#endif /* __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H */
+#endif /* CONFIG_RMT */
+#endif /* __INCLUDE_NUTTX_RMT_RMT_H */
diff --git a/boards/xtensa/esp32/common/include/esp32_rmt.h 
b/include/nuttx/rmt/rmtchar.h
similarity index 65%
rename from boards/xtensa/esp32/common/include/esp32_rmt.h
rename to include/nuttx/rmt/rmtchar.h
index 560c64f29f..6337e6ca8d 100644
--- a/boards/xtensa/esp32/common/include/esp32_rmt.h
+++ b/include/nuttx/rmt/rmtchar.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/xtensa/esp32/common/include/esp32_rmt.h
+ * include/nuttx/rmt/rmtchar.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +18,8 @@
  *
  ****************************************************************************/
 
-#ifndef __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H
-#define __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H
+#ifndef __INCLUDE_NUTTX_RMT_RMTCHAR_H
+#define __INCLUDE_NUTTX_RMT_RMTCHAR_H
 
 /****************************************************************************
  * Included Files
@@ -27,12 +27,16 @@
 
 #include <nuttx/config.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <nuttx/rmt/rmt.h>
+
+#ifdef CONFIG_RMTCHAR
 
 /****************************************************************************
- * Type Definitions
+ * Pre-processor Definitions
  ****************************************************************************/
 
 /****************************************************************************
@@ -43,7 +47,8 @@
  * Public Data
  ****************************************************************************/
 
-#ifdef __cplusplus
+#undef EXTERN
+#if defined(__cplusplus)
 #define EXTERN extern "C"
 extern "C"
 {
@@ -52,16 +57,36 @@ extern "C"
 #endif
 
 /****************************************************************************
- * Inline Functions
+ * Public Functions Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Public Function Prototypes
+ * Name: rmtchar_register
+ *
+ * Description:
+ *   Create and register the RMT character driver.
+ *
+ *   The RMT character driver is a simple character driver that supports RMT
+ *   transfers via read() and write(). This driver is primarily intended to
+ *   support RMT testing. It is not suitable for use in any real driver
+ *   application in its current form because its buffer management heuristics
+ *   are dependent on the lower half driver (device-specific).
+ *
+ * Input Parameters:
+ *   rmt - An instance of the lower half RMT driver
+ *
+ * Returned Value:
+ *   OK if the driver was successfully registered; A negated errno value is
+ *   returned on any failure.
+ *
  ****************************************************************************/
 
+int rmtchar_register(FAR struct rmt_dev_s *rmt);
+
 #undef EXTERN
-#ifdef __cplusplus
+#if defined(__cplusplus)
 }
 #endif
 
-#endif /* __BOARDS_XTENSA_ESP32_COMMON_INCLUDE_ESP32_RMT_H */
+#endif /* CONFIG_RMT */
+#endif /* __INCLUDE_NUTTX_RMT_RMTCHAR_H */

Reply via email to