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.
This commit is contained in:
Tiago Medicci Serrano 2023-11-10 09:39:21 -03:00 committed by Xiang Xiao
parent dec6ec1138
commit fcff5d43b7
9 changed files with 570 additions and 13 deletions

View File

@ -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"

View File

@ -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

View File

@ -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()

36
drivers/rmt/Kconfig Normal file
View File

@ -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

30
drivers/rmt/Make.defs Normal file
View File

@ -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

339
drivers/rmt/rmtchar.c Normal file
View File

@ -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;
}

View File

@ -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,

96
include/nuttx/rmt/rmt.h Normal file
View File

@ -0,0 +1,96 @@
/****************************************************************************
* 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
* 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.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_RMT_RMT_H
#define __INCLUDE_NUTTX_RMT_RMT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef CONFIG_RMT
/****************************************************************************
* 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
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Functions Prototypes
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* CONFIG_RMT */
#endif /* __INCLUDE_NUTTX_RMT_RMT_H */

View File

@ -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 */