espressif/rmt: replace rmtchar with arch-specific lirc adapter

Replace the ESP-specific rmtchar upper-half with arch-local esp_lirc
adapters for Xtensa and RISC-V.

 This moves the RMT upper-half out of drivers/rmt, registers LIRC
 devices from the ESP board bring-up paths, and removes the old common
 rmtchar driver and headers.

 Also update the ESP Kconfig and build wiring to build esp_lirc when
 ESP_RMT and DRIVERS_RC are enabled.

 Fixes discovered during hardware validation:
  - register TX as /dev/lirc1 so RX and TX do not collide
  - parse the RX worker thread argument from the correct argv slot
  - keep RX devices from advertising TX capability

Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
This commit is contained in:
Piyush Patle
2026-03-31 03:21:46 +05:30
committed by Alan C. Assis
parent 96005c6a7d
commit 7b590f9c43
36 changed files with 1124 additions and 699 deletions
+12 -1
View File
@@ -1288,13 +1288,24 @@ config ESPRESSIF_BROWNOUT_DET
config ESP_RMT
bool "Remote Control Module (RMT)"
default n
depends on RMT
select DRIVERS_RC
---help---
The RMT (Remote Control Transceiver) peripheral was designed to act as
an infrared transceiver. However, due to the flexibility of its data
format, RMT can be extended to a versatile and general-purpose
transceiver, transmitting or receiving many other types of signals.
if ESP_RMT
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 receive operation.
endif # ESP_RMT
config ESP_SDM
bool "Sigma-Delta Modulation (SDM) Module"
default n
@@ -94,6 +94,9 @@ endif
ifeq ($(CONFIG_ESP_RMT),y)
CHIP_CSRCS += esp_rmt.c
ifeq ($(CONFIG_DRIVERS_RC),y)
CHIP_CSRCS += esp_lirc.c
endif
ifeq ($(CONFIG_WS2812_NON_SPI_DRIVER),y)
CHIP_CSRCS += esp_ws2812.c
endif
+399
View File
@@ -0,0 +1,399 @@
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_lirc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <assert.h>
#include <debug.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <nuttx/circbuf.h>
#include <nuttx/kmalloc.h>
#include <nuttx/kthread.h>
#include <nuttx/lirc.h>
#include <nuttx/rc/lirc_dev.h>
#include <nuttx/semaphore.h>
#include "hal/rmt_types.h"
#include "esp_rmt.h"
#include "esp_lirc.h"
#if defined(CONFIG_ESP_RMT) && defined(CONFIG_DRIVERS_RC)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* RMT channel clock: 10 MHz → 1 tick = 0.1 µs */
#define RMT_TICK_TO_US(t) ((t) / 10)
#define RMT_US_TO_TICK(u) ((u) * 10)
/* DMA receive scratch buffer size (in bytes, must be multiple of 4) */
#define LIRC_RX_BUF_BYTES CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE
/* Stack size for the RX worker thread */
#define LIRC_RX_THREAD_STACK 2048
/****************************************************************************
* Private Types
****************************************************************************/
struct esp_lirc_dev_s
{
struct lirc_lowerhalf_s lower; /* Must be first — lirc upper-half iface */
FAR struct rmt_dev_s *rmt; /* ESP RMT lower-half */
volatile bool running; /* RX thread keep-alive flag */
pid_t rxpid; /* RX worker thread PID */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int esp_lirc_open(FAR struct lirc_lowerhalf_s *lower);
static void esp_lirc_close(FAR struct lirc_lowerhalf_s *lower);
static int esp_lirc_tx_ir(FAR struct lirc_lowerhalf_s *lower,
FAR unsigned int *txbuf, unsigned int n);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct lirc_ops_s g_esp_lirc_rx_ops =
{
.driver_type = LIRC_DRIVER_IR_RAW,
.open = esp_lirc_open,
.close = esp_lirc_close,
};
static const struct lirc_ops_s g_esp_lirc_tx_ops =
{
.driver_type = LIRC_DRIVER_IR_RAW_TX,
.open = esp_lirc_open,
.close = esp_lirc_close,
.tx_ir = esp_lirc_tx_ir,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_lirc_rx_thread
****************************************************************************/
static int esp_lirc_rx_thread(int argc, FAR char *argv[])
{
FAR struct esp_lirc_dev_s *priv;
FAR const char *arg;
FAR char *rxbuf;
FAR rmt_symbol_word_t *sym;
unsigned int sample;
int nbytes;
int nsyms;
int i;
DEBUGASSERT(argc >= 2 && argv[argc - 1] != NULL);
arg = argv[argc - 1];
priv = (FAR struct esp_lirc_dev_s *)(uintptr_t)strtoul(arg, NULL, 16);
rxbuf = kmm_malloc(LIRC_RX_BUF_BYTES);
if (rxbuf == NULL)
{
rcerr("ERROR: out of memory for RX buffer\n");
return -ENOMEM;
}
while (priv->running)
{
if (priv->rmt->ops->read)
{
priv->rmt->ops->read(priv->rmt, rxbuf, LIRC_RX_BUF_BYTES);
}
nxsem_wait_uninterruptible(priv->rmt->recvsem);
if (!priv->running)
{
break;
}
while ((nbytes = circbuf_read(priv->rmt->circbuf,
rxbuf, LIRC_RX_BUF_BYTES)) > 0)
{
nsyms = nbytes / sizeof(rmt_symbol_word_t);
sym = (FAR rmt_symbol_word_t *)rxbuf;
for (i = 0; i < nsyms; i++)
{
uint16_t dur0 = sym[i].duration0;
uint8_t lvl0 = sym[i].level0;
uint16_t dur1 = sym[i].duration1;
uint8_t lvl1 = sym[i].level1;
if (dur0 > 0)
{
sample = lvl0 ?
LIRC_PULSE(RMT_TICK_TO_US(dur0)) :
LIRC_SPACE(RMT_TICK_TO_US(dur0));
lirc_sample_event(&priv->lower, sample);
}
if (dur1 > 0)
{
sample = lvl1 ?
LIRC_PULSE(RMT_TICK_TO_US(dur1)) :
LIRC_SPACE(RMT_TICK_TO_US(dur1));
lirc_sample_event(&priv->lower, sample);
}
}
}
}
kmm_free(rxbuf);
return OK;
}
/****************************************************************************
* Name: esp_lirc_open
****************************************************************************/
static int esp_lirc_open(FAR struct lirc_lowerhalf_s *lower)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
FAR char *argv[3];
char addrstr[20];
int ret = OK;
if (priv->rxpid > 0)
{
return OK;
}
if (priv->rmt->recvsem != NULL)
{
priv->running = true;
snprintf(addrstr, sizeof(addrstr), "%lx",
(unsigned long)(uintptr_t)priv);
argv[0] = "esp_lirc_rx";
argv[1] = addrstr;
argv[2] = NULL;
ret = kthread_create("esp_lirc_rx", SCHED_PRIORITY_DEFAULT,
LIRC_RX_THREAD_STACK,
esp_lirc_rx_thread, argv);
if (ret < 0)
{
priv->running = false;
rcerr("ERROR: kthread_create failed: %d\n", ret);
return ret;
}
priv->rxpid = ret;
ret = OK;
}
return ret;
}
/****************************************************************************
* Name: esp_lirc_close
****************************************************************************/
static void esp_lirc_close(FAR struct lirc_lowerhalf_s *lower)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
if (priv->rxpid > 0)
{
priv->running = false;
if (priv->rmt->recvsem != NULL)
{
nxsem_post(priv->rmt->recvsem);
}
priv->rxpid = -1;
}
}
/****************************************************************************
* Name: esp_lirc_tx_ir
****************************************************************************/
static int esp_lirc_tx_ir(FAR struct lirc_lowerhalf_s *lower,
FAR unsigned int *txbuf, unsigned int n)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
FAR rmt_symbol_word_t *items;
unsigned int nwords;
unsigned int i;
int ret;
if (!priv->rmt->ops->write)
{
return -ENOSYS;
}
nwords = (n + 1) / 2;
items = kmm_zalloc(nwords * sizeof(rmt_symbol_word_t));
if (items == NULL)
{
return -ENOMEM;
}
for (i = 0; i < n; i++)
{
uint32_t us = LIRC_VALUE(txbuf[i]);
uint8_t lvl = LIRC_IS_PULSE(txbuf[i]) ? 1 : 0;
uint16_t tks = (uint16_t)RMT_US_TO_TICK(us);
if ((i & 1) == 0)
{
items[i / 2].duration0 = tks;
items[i / 2].level0 = lvl;
}
else
{
items[i / 2].duration1 = tks;
items[i / 2].level1 = lvl;
}
}
ret = priv->rmt->ops->write(priv->rmt,
(FAR const char *)items,
nwords * sizeof(rmt_symbol_word_t));
kmm_free(items);
return (ret < 0) ? ret : (int)n;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp_lirc_rx_initialize
*
* Description:
* Register a pre-initialized RMT RX channel as a LIRC raw IR device.
*
* Input Parameters:
* devno - The LIRC device number (e.g. 0 for /dev/lirc0)
* rmt - An already-initialized RMT RX lower-half handle
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int esp_lirc_rx_initialize(int devno, FAR struct rmt_dev_s *rmt)
{
FAR struct esp_lirc_dev_s *priv;
int ret;
DEBUGASSERT(rmt != NULL);
priv = kmm_zalloc(sizeof(struct esp_lirc_dev_s));
if (priv == NULL)
{
return -ENOMEM;
}
priv->lower.ops = &g_esp_lirc_rx_ops;
priv->lower.buffer_bytes = LIRC_RX_BUF_BYTES;
priv->lower.rx_resolution = 100; /* 0.1 µs = 100 ns */
priv->rmt = rmt;
priv->rxpid = -1;
ret = lirc_register(&priv->lower, devno);
if (ret < 0)
{
rcerr("ERROR: lirc_register failed: %d\n", ret);
kmm_free(priv);
return ret;
}
return OK;
}
/****************************************************************************
* Name: esp_lirc_tx_initialize
*
* Description:
* Register a pre-initialized RMT TX channel as a LIRC raw TX device.
*
* Input Parameters:
* devno - The LIRC device number (e.g. 0 for /dev/lirc0)
* rmt - An already-initialized RMT TX lower-half handle
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int esp_lirc_tx_initialize(int devno, FAR struct rmt_dev_s *rmt)
{
FAR struct esp_lirc_dev_s *priv;
int ret;
DEBUGASSERT(rmt != NULL);
priv = kmm_zalloc(sizeof(struct esp_lirc_dev_s));
if (priv == NULL)
{
return -ENOMEM;
}
priv->lower.ops = &g_esp_lirc_tx_ops;
priv->lower.tx_resolution = 100; /* 0.1 µs = 100 ns */
priv->rmt = rmt;
priv->rxpid = -1;
ret = lirc_register(&priv->lower, devno);
if (ret < 0)
{
rcerr("ERROR: lirc_register failed: %d\n", ret);
kmm_free(priv);
return ret;
}
return OK;
}
#endif /* CONFIG_ESP_RMT && CONFIG_DRIVERS_RC */
@@ -0,0 +1,48 @@
/****************************************************************************
* arch/risc-v/src/common/espressif/esp_lirc.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 __ARCH_RISC_V_SRC_COMMON_ESPRESSIF_ESP_LIRC_H
#define __ARCH_RISC_V_SRC_COMMON_ESPRESSIF_ESP_LIRC_H
#include <nuttx/config.h>
#include "esp_rmt.h"
#ifndef __ASSEMBLY__
#ifdef __cplusplus
extern "C"
{
#endif
#if defined(CONFIG_ESP_RMT) && defined(CONFIG_DRIVERS_RC)
int esp_lirc_rx_initialize(int devno, FAR struct rmt_dev_s *rmt);
int esp_lirc_tx_initialize(int devno, FAR struct rmt_dev_s *rmt);
#endif /* CONFIG_ESP_RMT && CONFIG_DRIVERS_RC */
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_RISC_V_SRC_COMMON_ESPRESSIF_ESP_LIRC_H */
@@ -39,7 +39,6 @@
#include <arch/board/board.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/rmt/rmt.h>
#include <nuttx/spinlock.h>
#include <nuttx/circbuf.h>
@@ -29,6 +29,10 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/circbuf.h>
#include <nuttx/spinlock.h>
/****************************************************************************
@@ -51,6 +55,34 @@
* Public Types
****************************************************************************/
/* The RMT peripheral vtable */
struct rmt_dev_s;
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 device structure — initial fields visible to upper-half drivers.
* The ESP lower-half extends this with hardware-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
****************************************************************************/
@@ -31,7 +31,6 @@
#include <nuttx/kmalloc.h>
#include <nuttx/signal.h>
#include <nuttx/leds/ws2812.h>
#include <nuttx/rmt/rmt.h>
#include "hal/rmt_types.h"
+12 -1
View File
@@ -71,13 +71,24 @@ endmenu # Interrupt Configuration
config ESP_RMT
bool "Remote Control Module (RMT)"
default n
depends on RMT
select DRIVERS_RC
---help---
The RMT (Remote Control Transceiver) peripheral was designed to act as
an infrared transceiver. However, due to the flexibility of its data
format, RMT can be extended to a versatile and general-purpose
transceiver, transmitting or receiving many other types of signals.
if ESP_RMT
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 receive operation.
endif # ESP_RMT
config ESP_MCPWM
bool "Motor Control PWM (MCPWM)"
default n
@@ -26,6 +26,9 @@ CFLAGS += -Wno-shadow -Wno-undef
ifeq ($(CONFIG_ESP_RMT),y)
CHIP_CSRCS += esp_rmt.c
ifeq ($(CONFIG_DRIVERS_RC),y)
CHIP_CSRCS += esp_lirc.c
endif
ifeq ($(CONFIG_WS2812_NON_SPI_DRIVER),y)
CHIP_CSRCS += esp_ws2812.c
endif
+441
View File
@@ -0,0 +1,441 @@
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_lirc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <assert.h>
#include <debug.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <nuttx/circbuf.h>
#include <nuttx/kmalloc.h>
#include <nuttx/kthread.h>
#include <nuttx/lirc.h>
#include <nuttx/rc/lirc_dev.h>
#include <nuttx/semaphore.h>
#include "hal/rmt_types.h"
#include "esp_rmt.h"
#include "esp_lirc.h"
#if defined(CONFIG_ESP_RMT) && defined(CONFIG_DRIVERS_RC)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* RMT channel clock: 10 MHz → 1 tick = 0.1 µs */
#define RMT_TICK_TO_US(t) ((t) / 10)
#define RMT_US_TO_TICK(u) ((u) * 10)
/* DMA receive scratch buffer size (in bytes, must be multiple of 4) */
#define LIRC_RX_BUF_BYTES CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE
/* Stack size for the RX worker thread */
#define LIRC_RX_THREAD_STACK 2048
/****************************************************************************
* Private Types
****************************************************************************/
struct esp_lirc_dev_s
{
struct lirc_lowerhalf_s lower; /* Must be first — lirc upper-half iface */
FAR struct rmt_dev_s *rmt; /* ESP RMT lower-half */
volatile bool running; /* RX thread keep-alive flag */
pid_t rxpid; /* RX worker thread PID */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int esp_lirc_open(FAR struct lirc_lowerhalf_s *lower);
static void esp_lirc_close(FAR struct lirc_lowerhalf_s *lower);
static int esp_lirc_tx_ir(FAR struct lirc_lowerhalf_s *lower,
FAR unsigned int *txbuf, unsigned int n);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct lirc_ops_s g_esp_lirc_rx_ops =
{
.driver_type = LIRC_DRIVER_IR_RAW,
.open = esp_lirc_open,
.close = esp_lirc_close,
};
static const struct lirc_ops_s g_esp_lirc_tx_ops =
{
.driver_type = LIRC_DRIVER_IR_RAW_TX,
.open = esp_lirc_open,
.close = esp_lirc_close,
.tx_ir = esp_lirc_tx_ir,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: esp_lirc_rx_thread
*
* Description:
* Kernel thread that continuously arms the RMT receiver, waits for
* received symbols, converts rmt_symbol_word_t items to LIRC pulse/space
* samples, and pushes them upstream via lirc_sample_event().
*
* RMT clock is 10 MHz → 1 tick = 0.1 µs.
* rmt_symbol_word_t layout:
* bits [0:14] duration0 (RMT ticks)
* bit [15] level0 (1 = pulse, 0 = space)
* bits [16:30] duration1 (RMT ticks)
* bit [31] level1
*
****************************************************************************/
static int esp_lirc_rx_thread(int argc, FAR char *argv[])
{
FAR struct esp_lirc_dev_s *priv;
FAR const char *arg;
FAR char *rxbuf;
FAR rmt_symbol_word_t *sym;
unsigned int sample;
int nbytes;
int nsyms;
int i;
DEBUGASSERT(argc >= 2 && argv[argc - 1] != NULL);
arg = argv[argc - 1];
priv = (FAR struct esp_lirc_dev_s *)(uintptr_t)strtoul(arg, NULL, 16);
rxbuf = kmm_malloc(LIRC_RX_BUF_BYTES);
if (rxbuf == NULL)
{
rcerr("ERROR: out of memory for RX buffer\n");
return -ENOMEM;
}
while (priv->running)
{
/* Arm the RMT receiver — uses rxbuf as DMA scratch buffer.
* The actual received symbols land in priv->rmt->circbuf via
* the rmt_rx_done_callback in esp_rmt.c.
*/
if (priv->rmt->ops->read)
{
priv->rmt->ops->read(priv->rmt, rxbuf, LIRC_RX_BUF_BYTES);
}
/* Wait until the callback posts the semaphore */
nxsem_wait_uninterruptible(priv->rmt->recvsem);
if (!priv->running)
{
break;
}
/* Drain the circular buffer */
while ((nbytes = circbuf_read(priv->rmt->circbuf,
rxbuf, LIRC_RX_BUF_BYTES)) > 0)
{
nsyms = nbytes / sizeof(rmt_symbol_word_t);
sym = (FAR rmt_symbol_word_t *)rxbuf;
for (i = 0; i < nsyms; i++)
{
uint16_t dur0 = sym[i].duration0;
uint8_t lvl0 = sym[i].level0;
uint16_t dur1 = sym[i].duration1;
uint8_t lvl1 = sym[i].level1;
/* First half-symbol */
if (dur0 > 0)
{
sample = lvl0 ?
LIRC_PULSE(RMT_TICK_TO_US(dur0)) :
LIRC_SPACE(RMT_TICK_TO_US(dur0));
lirc_sample_event(&priv->lower, sample);
}
/* Second half-symbol (duration1 == 0 marks end of burst) */
if (dur1 > 0)
{
sample = lvl1 ?
LIRC_PULSE(RMT_TICK_TO_US(dur1)) :
LIRC_SPACE(RMT_TICK_TO_US(dur1));
lirc_sample_event(&priv->lower, sample);
}
}
}
}
kmm_free(rxbuf);
return OK;
}
/****************************************************************************
* Name: esp_lirc_open
****************************************************************************/
static int esp_lirc_open(FAR struct lirc_lowerhalf_s *lower)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
FAR char *argv[3];
char addrstr[20];
int ret = OK;
if (priv->rxpid > 0)
{
return OK; /* Already open */
}
if (priv->rmt->recvsem != NULL)
{
/* RX-capable device: start the receiver thread */
priv->running = true;
snprintf(addrstr, sizeof(addrstr), "%lx",
(unsigned long)(uintptr_t)priv);
argv[0] = "esp_lirc_rx";
argv[1] = addrstr;
argv[2] = NULL;
ret = kthread_create("esp_lirc_rx", SCHED_PRIORITY_DEFAULT,
LIRC_RX_THREAD_STACK,
esp_lirc_rx_thread, argv);
if (ret < 0)
{
priv->running = false;
rcerr("ERROR: kthread_create failed: %d\n", ret);
return ret;
}
priv->rxpid = ret;
ret = OK;
}
return ret;
}
/****************************************************************************
* Name: esp_lirc_close
****************************************************************************/
static void esp_lirc_close(FAR struct lirc_lowerhalf_s *lower)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
if (priv->rxpid > 0)
{
priv->running = false;
/* Wake the blocked thread so it can exit */
if (priv->rmt->recvsem != NULL)
{
nxsem_post(priv->rmt->recvsem);
}
priv->rxpid = -1;
}
}
/****************************************************************************
* Name: esp_lirc_tx_ir
*
* Description:
* Transmit raw IR pulse/space data. Converts LIRC mode2 unsigned int
* samples (each a LIRC_PULSE or LIRC_SPACE with duration in µs) to pairs
* of rmt_symbol_word_t items and writes them to the RMT TX channel.
*
* The RMT clock is 10 MHz so 1 µs = 10 ticks.
*
****************************************************************************/
static int esp_lirc_tx_ir(FAR struct lirc_lowerhalf_s *lower,
FAR unsigned int *txbuf, unsigned int n)
{
FAR struct esp_lirc_dev_s *priv =
(FAR struct esp_lirc_dev_s *)lower;
FAR rmt_symbol_word_t *items;
unsigned int nwords;
unsigned int i;
int ret;
if (!priv->rmt->ops->write)
{
return -ENOSYS;
}
/* Each pair of LIRC samples (pulse + space) maps to one rmt_symbol_word_t.
* For an odd count we pad the last word with a zero second half-symbol.
*/
nwords = (n + 1) / 2;
items = kmm_zalloc(nwords * sizeof(rmt_symbol_word_t));
if (items == NULL)
{
return -ENOMEM;
}
for (i = 0; i < n; i++)
{
uint32_t us = LIRC_VALUE(txbuf[i]);
uint8_t lvl = LIRC_IS_PULSE(txbuf[i]) ? 1 : 0;
uint16_t tks = (uint16_t)RMT_US_TO_TICK(us);
if ((i & 1) == 0)
{
items[i / 2].duration0 = tks;
items[i / 2].level0 = lvl;
}
else
{
items[i / 2].duration1 = tks;
items[i / 2].level1 = lvl;
}
}
ret = priv->rmt->ops->write(priv->rmt,
(FAR const char *)items,
nwords * sizeof(rmt_symbol_word_t));
kmm_free(items);
return (ret < 0) ? ret : (int)n;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp_lirc_rx_initialize
*
* Description:
* Register a pre-initialized RMT RX channel as a LIRC raw IR device.
*
* Input Parameters:
* devno - The LIRC device number (e.g. 0 for /dev/lirc0)
* rmt - An already-initialized RMT RX lower-half handle
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int esp_lirc_rx_initialize(int devno, FAR struct rmt_dev_s *rmt)
{
FAR struct esp_lirc_dev_s *priv;
int ret;
DEBUGASSERT(rmt != NULL);
priv = kmm_zalloc(sizeof(struct esp_lirc_dev_s));
if (priv == NULL)
{
return -ENOMEM;
}
priv->lower.ops = &g_esp_lirc_rx_ops;
priv->lower.buffer_bytes = LIRC_RX_BUF_BYTES;
priv->lower.rx_resolution = 100; /* 0.1 µs = 100 ns */
priv->rmt = rmt;
priv->rxpid = -1;
ret = lirc_register(&priv->lower, devno);
if (ret < 0)
{
rcerr("ERROR: lirc_register failed: %d\n", ret);
kmm_free(priv);
return ret;
}
return OK;
}
/****************************************************************************
* Name: esp_lirc_tx_initialize
*
* Description:
* Register a pre-initialized RMT TX channel as a LIRC raw TX device.
*
* Input Parameters:
* devno - The LIRC device number (e.g. 0 for /dev/lirc0)
* rmt - An already-initialized RMT TX lower-half handle
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int esp_lirc_tx_initialize(int devno, FAR struct rmt_dev_s *rmt)
{
FAR struct esp_lirc_dev_s *priv;
int ret;
DEBUGASSERT(rmt != NULL);
priv = kmm_zalloc(sizeof(struct esp_lirc_dev_s));
if (priv == NULL)
{
return -ENOMEM;
}
priv->lower.ops = &g_esp_lirc_tx_ops;
priv->lower.tx_resolution = 100; /* 0.1 µs = 100 ns */
priv->rmt = rmt;
priv->rxpid = -1;
ret = lirc_register(&priv->lower, devno);
if (ret < 0)
{
rcerr("ERROR: lirc_register failed: %d\n", ret);
kmm_free(priv);
return ret;
}
return OK;
}
#endif /* CONFIG_ESP_RMT && CONFIG_DRIVERS_RC */
@@ -0,0 +1,56 @@
/****************************************************************************
* arch/xtensa/src/common/espressif/esp_lirc.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LIRC_H
#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LIRC_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include "esp_rmt.h"
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
extern "C"
{
#endif
#if defined(CONFIG_ESP_RMT) && defined(CONFIG_DRIVERS_RC)
int esp_lirc_rx_initialize(int devno, FAR struct rmt_dev_s *rmt);
int esp_lirc_tx_initialize(int devno, FAR struct rmt_dev_s *rmt);
#endif /* CONFIG_ESP_RMT && CONFIG_DRIVERS_RC */
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LIRC_H */
@@ -39,7 +39,6 @@
#include <arch/board/board.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/rmt/rmt.h>
#include <nuttx/spinlock.h>
#include <nuttx/circbuf.h>
@@ -29,6 +29,10 @@
#include <nuttx/config.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/circbuf.h>
#include <nuttx/spinlock.h>
/****************************************************************************
@@ -51,6 +55,34 @@
* Public Types
****************************************************************************/
/* The RMT peripheral vtable */
struct rmt_dev_s;
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 device structure — initial fields visible to upper-half drivers.
* The ESP lower-half extends this with hardware-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
****************************************************************************/
@@ -31,7 +31,6 @@
#include <nuttx/kmalloc.h>
#include <nuttx/signal.h>
#include <nuttx/leds/ws2812.h>
#include <nuttx/rmt/rmt.h>
#include "hal/rmt_types.h"
#include "soc/soc.h"
@@ -31,7 +31,7 @@
#include <stdio.h>
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -87,13 +87,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -129,10 +135,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -23,11 +23,8 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt2"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
@@ -42,9 +39,6 @@ CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=512
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
@@ -31,7 +31,7 @@
#include <stdio.h>
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -87,13 +87,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -129,10 +135,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -23,11 +23,8 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt2"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
@@ -42,9 +39,6 @@ CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=512
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
@@ -23,11 +23,8 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt2"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
@@ -42,9 +39,6 @@ CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=512
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
@@ -31,7 +31,7 @@
#include <stdio.h>
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -87,13 +87,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -129,10 +135,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -22,11 +22,8 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt2"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_IDLETHREAD_STACKSIZE=2048
@@ -41,9 +38,6 @@ CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=512
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
@@ -31,7 +31,7 @@
#include <stdio.h>
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -87,13 +87,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -129,10 +135,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -21,11 +21,8 @@ CONFIG_ARCH_RISCV=y
CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=15000
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt4"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_EXPERIMENTAL=y
CONFIG_FS_PROCFS=y
@@ -41,9 +38,6 @@ CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_NSH_STRERROR=y
CONFIG_PREALLOC_TIMERS=0
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=512
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_BACKTRACE=y
CONFIG_SCHED_WAITPID=y
@@ -33,7 +33,7 @@
#include "xtensa.h"
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -89,13 +89,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -125,17 +131,16 @@ int board_rmt_txinitialize(int pin)
#endif
rmt = esp_rmt_tx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_tx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -22,11 +22,9 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP32_UART0=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
@@ -44,9 +42,6 @@ CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=256
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
@@ -33,7 +33,7 @@
#include "xtensa.h"
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -98,10 +98,10 @@ int board_rmt_rxinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -137,10 +137,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -24,11 +24,9 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP32S2_UART0=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
@@ -45,9 +43,6 @@ CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=256
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
@@ -33,7 +33,7 @@
#include "xtensa.h"
#include <nuttx/kmalloc.h>
#include <nuttx/rmt/rmtchar.h>
#include "espressif/esp_lirc.h"
#ifdef CONFIG_WS2812_NON_SPI_DRIVER
#include <nuttx/leds/ws2812.h>
@@ -89,13 +89,19 @@
int board_rmt_rxinitialize(int pin)
{
int ret;
struct rmt_dev_s *rmt;
struct rmt_dev_s *rmt = esp_rmt_rx_init(pin);
rmt = esp_rmt_rx_init(pin);
if (rmt == NULL)
{
rmterr("ERROR: esp_rmt_rx_init failed\n");
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_rx_initialize(0, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_rx_initialize failed: %d\n", ret);
return ret;
}
@@ -131,10 +137,10 @@ int board_rmt_txinitialize(int pin)
return -ENODEV;
}
ret = rmtchar_register(rmt);
ret = esp_lirc_tx_initialize(1, rmt);
if (ret < 0)
{
rmterr("ERROR: rmtchar_register failed: %d\n", ret);
rmterr("ERROR: esp_lirc_tx_initialize failed: %d\n", ret);
return ret;
}
@@ -25,12 +25,9 @@ CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_DRIVERS_RC=y
CONFIG_ESP32S3_UART0=y
CONFIG_ESP_RMT=y
CONFIG_EXAMPLES_RMTCHAR=y
CONFIG_EXAMPLES_RMTCHAR_RX=y
CONFIG_EXAMPLES_RMTCHAR_RX_DEVPATH="/dev/rmt4"
CONFIG_EXAMPLES_RMTCHAR_TX=y
CONFIG_EXAMPLES_WS2812=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
@@ -47,9 +44,6 @@ CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=114688
CONFIG_RAM_START=0x20000000
CONFIG_RMT=y
CONFIG_RMTCHAR=y
CONFIG_RMT_DEFAULT_RX_BUFFER_SIZE=256
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_WAITPID=y
CONFIG_START_DAY=6
-1
View File
@@ -39,7 +39,6 @@ source "drivers/pinctrl/Kconfig"
source "drivers/pipes/Kconfig"
source "drivers/power/Kconfig"
source "drivers/regmap/Kconfig"
source "drivers/rmt/Kconfig"
source "drivers/rpmsg/Kconfig"
source "drivers/rptun/Kconfig"
source "drivers/sensors/Kconfig"
+1 -9
View File
@@ -20,12 +20,4 @@
#
# ##############################################################################
if(CONFIG_RMT)
set(SRCS)
if(CONFIG_RMTCHAR)
list(APPEND SRCS rmtchar.c)
endif()
target_sources(drivers PRIVATE ${SRCS})
endif()
# RMT character driver removed; RMT upper-half is now arch/espressif/esp_lirc.c
-43
View File
@@ -2,46 +2,3 @@
# 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.
config RMT_LOOP_TEST_MODE
bool "RMT character driver loopback test mode (for testing only)"
depends on EXPERIMENTAL
default n
---help---
This enables a lower-half driver-specific loopback test
mode that attaches the transmitter to the receiver, being
able to test the RMT peripheral without any external
connection. This feature depends on lower-half driver
implementation.
endif # RMT
-11
View File
@@ -19,14 +19,3 @@
# under the License.
#
############################################################################
ifeq ($(CONFIG_RMT),y)
ifeq ($(CONFIG_RMTCHAR),y)
CSRCS += rmtchar.c
endif
DEPPATH += --dep-path rmt
VPATH += :rmt
endif
-341
View File
@@ -1,341 +0,0 @@
/****************************************************************************
* drivers/rmt/rmtchar.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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/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, sizeof(devname), 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;
}
-98
View File
@@ -1,98 +0,0 @@
/****************************************************************************
* include/nuttx/rmt/rmt.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 */
-94
View File
@@ -1,94 +0,0 @@
/****************************************************************************
* include/nuttx/rmt/rmtchar.h
*
* SPDX-License-Identifier: Apache-2.0
*
* 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_RMTCHAR_H
#define __INCLUDE_NUTTX_RMT_RMTCHAR_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/rmt/rmt.h>
#ifdef CONFIG_RMTCHAR
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Functions 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
#if defined(__cplusplus)
}
#endif
#endif /* CONFIG_RMT */
#endif /* __INCLUDE_NUTTX_RMT_RMTCHAR_H */