diff --git a/dist/tools/doccheck/exclude_patterns b/dist/tools/doccheck/exclude_patterns index 16138cb027..0ce1ac9c14 100644 --- a/dist/tools/doccheck/exclude_patterns +++ b/dist/tools/doccheck/exclude_patterns @@ -10084,6 +10084,8 @@ drivers/io1_xplained/include/io1_xplained_internals\.h:[0-9]+: warning: Member I drivers/io1_xplained/include/io1_xplained_params\.h:[0-9]+: warning: Member IO1_XPLAINED_PARAMS \(macro definition\) of file io1_xplained_params\.h is not documented\. drivers/io1_xplained/include/io1_xplained_params\.h:[0-9]+: warning: Member IO1_XPLAINED_PARAM_ADDR \(macro definition\) of file io1_xplained_params\.h is not documented\. drivers/io1_xplained/include/io1_xplained_params\.h:[0-9]+: warning: Member IO1_XPLAINED_SAUL_INFO \(macro definition\) of file io1_xplained_params\.h is not documented\. +drivers/ir_nec/include/ir_nec_params\.h:35: warning: Member IR_NEC_PARAM_PIN \(macro definition\) of file ir_nec_params\.h is not documented\. +drivers/ir_nec/include/ir_nec_params\.h:39: warning: Member IR_NEC_PARAMS \(macro definition\) of file ir_nec_params\.h is not documented\. drivers/isl29020/include/isl29020\-internal\.h:[0-9]+: warning: Member ISL29020_CMD_EN \(macro definition\) of file isl29020\-internal\.h is not documented\. drivers/isl29020/include/isl29020\-internal\.h:[0-9]+: warning: Member ISL29020_CMD_LIGHT \(macro definition\) of file isl29020\-internal\.h is not documented\. drivers/isl29020/include/isl29020\-internal\.h:[0-9]+: warning: Member ISL29020_CMD_MODE \(macro definition\) of file isl29020\-internal\.h is not documented\. diff --git a/drivers/include/ir_nec.h b/drivers/include/ir_nec.h new file mode 100644 index 0000000000..ecfd21a872 --- /dev/null +++ b/drivers/include/ir_nec.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 Dario Petrillo + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_ir_nec IR NEC Remote receiver + * @ingroup drivers_misc + * @brief Receives commands from NEC IR remotes + * + * @{ + * + * @file + * + * @author Dario Petrillo + */ + +#ifndef IR_NEC_H +#define IR_NEC_H + +#include + +#include "isrpipe.h" +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief NEC command structure + */ +typedef struct { + uint8_t addr; /**< Address (usually 0, depends on the remote) */ + uint8_t cmd; /**< Command */ +} ir_nec_cmd_t; + +/** + * @brief Device initialization parameters + */ +typedef struct { + gpio_t pin; /**< Input pin */ +} ir_nec_params_t; + +/** + * @brief Device descriptor for the driver + */ +typedef struct { + gpio_t pin; /**< Input pin */ + isrpipe_t isrpipe; /**< Internal pipe for commands */ + + uint32_t last_rising; /**< Timestamp of the last rising edge */ + uint32_t data; /**< Data packet being received */ + uint8_t read_bits; /**< Number of bits read so far. 0xff if not currently reading */ + + uint8_t isrpipe_buf[2 * sizeof(ir_nec_cmd_t)]; /**< Buffer for the isrpipe */ +} ir_nec_t; + +/** + * @brief Initialize the given device + * + * @param[inout] dev Device descriptor of the driver + * @param[in] params Initialization parameters + * + * @return 0 on success + */ +int ir_nec_init(ir_nec_t *dev, const ir_nec_params_t *params); + +/** + * @brief Read a command packet. Blocks until one is received + * + * @param[inout] dev Device descriptor of the driver + * @param[out] command Structure to write the result into + * + * @retval 0 Success + * @retval -1 Isrpipe returned too few bytes. Should never happen + */ +int ir_nec_read(ir_nec_t *dev, ir_nec_cmd_t *command); + +#ifdef __cplusplus +} +#endif + +#endif /* IR_NEC_H */ +/** @} */ diff --git a/drivers/ir_nec/Kconfig b/drivers/ir_nec/Kconfig new file mode 100644 index 0000000000..f6165bab80 --- /dev/null +++ b/drivers/ir_nec/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2022 Dario Petrillo +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +config MODULE_IR_NEC + bool "IR NEC Remote receiver" + depends on TEST_KCONFIG + select MODULE_ISRPIPE + select MODULE_PERIPH_GPIO_IRQ + select MODULE_ZTIMER + select MODULE_ZTIMER_USEC diff --git a/drivers/ir_nec/Makefile b/drivers/ir_nec/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/ir_nec/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/ir_nec/Makefile.dep b/drivers/ir_nec/Makefile.dep new file mode 100644 index 0000000000..4f1eb0a801 --- /dev/null +++ b/drivers/ir_nec/Makefile.dep @@ -0,0 +1,4 @@ +FEATURES_REQUIRED += periph_gpio +FEATURES_REQUIRED += periph_gpio_irq +USEMODULE += isrpipe +USEMODULE += ztimer_usec diff --git a/drivers/ir_nec/Makefile.include b/drivers/ir_nec/Makefile.include new file mode 100644 index 0000000000..bd6f1d655a --- /dev/null +++ b/drivers/ir_nec/Makefile.include @@ -0,0 +1,2 @@ +USEMODULE_INCLUDES_ir_nec := $(LAST_MAKEFILEDIR)/include +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_ir_nec) diff --git a/drivers/ir_nec/include/ir_nec_constants.h b/drivers/ir_nec/include/ir_nec_constants.h new file mode 100644 index 0000000000..1682d2659c --- /dev/null +++ b/drivers/ir_nec/include/ir_nec_constants.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 Dario Petrillo + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ir_nec + * @{ + * + * @file + * @brief Internal addresses, registers and constants + * + * @author Dario Petrillo + */ + +#ifndef IR_NEC_CONSTANTS_H +#define IR_NEC_CONSTANTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define IR_NEC_START_US 4500 /**< Width of the start pulse, in microseconds */ +#define IR_NEC_ZERO_US 562 /**< Width of the zero pulse, in microseconds */ +#define IR_NEC_ONE_US 1687 /**< Width of the one pulse, in microseconds */ +#define IR_NEC_EPS_US 350 /**< Maximum timing deviation for value detection, in microseconds */ + +#ifdef __cplusplus +} +#endif + +#endif /* IR_NEC_CONSTANTS_H */ +/** @} */ diff --git a/drivers/ir_nec/include/ir_nec_params.h b/drivers/ir_nec/include/ir_nec_params.h new file mode 100644 index 0000000000..76a0facd1c --- /dev/null +++ b/drivers/ir_nec/include/ir_nec_params.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 Dario Petrillo + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ir_nec + * + * @{ + * @file + * @brief Default configuration + * + * @author Dario Petrillo + */ + +#ifndef IR_NEC_PARAMS_H +#define IR_NEC_PARAMS_H + +#include "board.h" +#include "ir_nec.h" +#include "ir_nec_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters + * @{ + */ +#ifndef IR_NEC_PARAM_PIN +#define IR_NEC_PARAM_PIN GPIO_UNDEF +#endif + +#ifndef IR_NEC_PARAMS +#define IR_NEC_PARAMS { .pin = IR_NEC_PARAM_PIN } +#endif +/**@}*/ + +/** + * @brief Configuration struct + */ +static const ir_nec_params_t ir_nec_params[] = +{ + IR_NEC_PARAMS +}; + +#ifdef __cplusplus +} +#endif + +#endif /* IR_NEC_PARAMS_H */ +/** @} */ diff --git a/drivers/ir_nec/ir_nec.c b/drivers/ir_nec/ir_nec.c new file mode 100644 index 0000000000..d313ca81b0 --- /dev/null +++ b/drivers/ir_nec/ir_nec.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 Dario Petrillo + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ir_nec + * @{ + * + * @file + * @brief Device driver implementation for the IR NEC Remote receiver + * + * @author Dario Petrillo + * + * @} + */ + +#include "ir_nec.h" +#include "ir_nec_constants.h" +#include "ir_nec_params.h" + +#include +#include "ztimer.h" + +#include "ir_nec.h" + +static void ir_nec_isr(void *arg) +{ + ir_nec_t *ir = (ir_nec_t *)arg; + + if (gpio_read(ir->pin) != 0) { // rising edge + ir->last_rising = ztimer_now(ZTIMER_USEC); + } + else { // falling edge + int length = ztimer_now(ZTIMER_USEC) - ir->last_rising; + + if (abs(length - IR_NEC_START_US) <= IR_NEC_EPS_US) { + ir->data = 0; + ir->read_bits = 0; + } + else if ((length - IR_NEC_ZERO_US) <= IR_NEC_EPS_US && ir->read_bits < 32) { + ir->data = (ir->data << 1); + ir->read_bits++; + } + else if (abs(length - IR_NEC_ONE_US) <= IR_NEC_EPS_US && ir->read_bits < 32) { + ir->data = (ir->data << 1) | 1; + ir->read_bits++; + } + else { // Interpacket delay + ir->read_bits = 0xff; + } + + if (ir->read_bits == 32) { + ir->read_bits = 0xff; + + uint8_t addr = (ir->data >> 24) & 0xff; + uint8_t addr_inv = (ir->data >> 16) & 0xff; + uint8_t cmd = (ir->data >> 8) & 0xff; + uint8_t cmd_inv = ir->data & 0xff; + + if ((addr ^ addr_inv) == 0xff && (cmd ^ cmd_inv) == 0xff) { + ir_nec_cmd_t command = { .addr = addr, .cmd = cmd }; + isrpipe_write(&ir->isrpipe, (void*)&command, sizeof(command)); + } + } + } +} + +int ir_nec_read(ir_nec_t *ir, ir_nec_cmd_t *command) +{ + int to_read = sizeof(ir_nec_cmd_t); + if (isrpipe_read(&ir->isrpipe, (void*)command, to_read) != to_read) { + return -1; + } + return 0; +} + +int ir_nec_init(ir_nec_t *ir, const ir_nec_params_t *params) +{ + ir->pin = params->pin; + ir->data = 0; + ir->last_rising = 0; + ir->read_bits = 0; + + isrpipe_init(&ir->isrpipe, ir->isrpipe_buf, sizeof(ir->isrpipe_buf)); + gpio_init_int(ir->pin, GPIO_IN, GPIO_BOTH, ir_nec_isr, ir); + + return 0; +}