-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17935 from dp1/ir_nec
drivers/ir_nec: NEC remote receiver implementation
- Loading branch information
Showing
12 changed files
with
361 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
*/ | ||
|
||
#ifndef IR_NEC_H | ||
#define IR_NEC_H | ||
|
||
#include <stdint.h> | ||
|
||
#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 */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
FEATURES_REQUIRED += periph_gpio | ||
FEATURES_REQUIRED += periph_gpio_irq | ||
USEMODULE += isrpipe | ||
USEMODULE += ztimer_usec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
USEMODULE_INCLUDES_ir_nec := $(LAST_MAKEFILEDIR)/include | ||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_ir_nec) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
*/ | ||
|
||
#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 */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
*/ | ||
|
||
#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 */ | ||
/** @} */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include "ir_nec.h" | ||
#include "ir_nec_constants.h" | ||
#include "ir_nec_params.h" | ||
|
||
#include <stdlib.h> | ||
#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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
include ../Makefile.tests_common | ||
|
||
# required modules | ||
USEMODULE += ir_nec | ||
|
||
# Setup pin for ir-receiver | ||
# Any interrupt capable GPIO pin should work fine | ||
ifneq (,$(filter b-l475e-iot01a,$(BOARD))) | ||
# This is the pin marked D7 on b-l475e-iot01a | ||
IR_PIN ?= GPIO_PIN(PORT_A,4) | ||
endif | ||
|
||
# fallback: set some default for compile test | ||
IR_PIN ?= GPIO_PIN(0,0) | ||
|
||
CFLAGS += -D'IR_NEC_PARAM_PIN=$(IR_PIN)' | ||
|
||
include $(RIOTBASE)/Makefile.include |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
driver_ir_nec | ||
============= | ||
|
||
This is a manual test application for the ir_nec driver. | ||
|
||
Usage | ||
===== | ||
|
||
The application continuously reads packets from the IR remote and prints them. | ||
It should print one line for every keypress. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* 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 tests | ||
* @{ | ||
* | ||
* @file | ||
* @brief Test application for the ir_nec driver | ||
* | ||
* @author Dario Petrillo <[email protected]> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include "ir_nec.h" | ||
#include "ir_nec_params.h" | ||
|
||
ir_nec_t remote; | ||
ir_nec_cmd_t cmd; | ||
|
||
int main(void) | ||
{ | ||
ir_nec_init(&remote, &ir_nec_params[0]); | ||
|
||
for (;;) { | ||
if (ir_nec_read(&remote, &cmd)) { | ||
puts("Error reading packet"); | ||
return -1; | ||
} | ||
printf("Received packet with addr = 0x%X, cmd = 0x%X\n", cmd.addr, cmd.cmd); | ||
} | ||
} |