mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-02 06:38:47 +00:00
examples: Standardise naming of files, symbols, etc. in examples
* Use "example" in all example function & variable names, ie use i2c_example_xxx instead of i2c_xxx for example functions. Closes #198 https://github.com/espressif/esp-idf/issues/198 * Mark example functions, etc. static * Replace uses of "test" & "demo" with "example" * Split the UART example into two * Rename "main" example files to end with "_main.c" for disambiguation
This commit is contained in:
@@ -2,5 +2,7 @@
|
||||
|
||||
This example uses the remote control (RMT) peripheral to transmit and receive codes for the NEC infrared remote protocol.
|
||||
|
||||
Configuration (pin numbers, etc.) can be modified in top of the main/infrared_nec.c file.
|
||||
Configuration (pin numbers, etc.) can be modified in top of the main/infrared_nec_main.c file.
|
||||
|
||||
By default, this example runs a self test which assumes the TX and RX GPIO pins are connected together. To disable this, comment RMT_RX_SELF_TEST in infrared_nec_main.c.
|
||||
|
||||
|
@@ -1,358 +0,0 @@
|
||||
/* NEC remote infrared RMT example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "soc/rmt_reg.h"
|
||||
|
||||
static const char* NEC_TAG = "NEC";
|
||||
|
||||
//CHOOSE SELF TEST OR NORMAL TEST
|
||||
#define RMT_RX_SELF_TEST 1
|
||||
|
||||
/******************************************************/
|
||||
/***** SELF TEST: *****/
|
||||
/*Connect RMT_TX_GPIO_NUM with RMT_RX_GPIO_NUM */
|
||||
/*TX task will send NEC data with carrier disabled */
|
||||
/*RX task will print NEC data it receives. */
|
||||
/******************************************************/
|
||||
#if RMT_RX_SELF_TEST
|
||||
#define RMT_RX_ACTIVE_LEVEL 1 /*!< Data bit is active high for self test mode */
|
||||
#define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */
|
||||
#else
|
||||
//Test with infrared LED, we have to enable carrier for transmitter
|
||||
//When testing via IR led, the receiver waveform is usually active-low.
|
||||
#define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */
|
||||
#define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */
|
||||
#endif
|
||||
|
||||
#define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */
|
||||
#define RMT_TX_GPIO_NUM 16 /*!< GPIO number for transmitter signal */
|
||||
#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */
|
||||
#define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */
|
||||
#define RMT_CLK_DIV 100 /*!< RMT counter clock divider */
|
||||
#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */
|
||||
|
||||
#define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */
|
||||
#define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/
|
||||
#define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */
|
||||
#define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */
|
||||
#define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */
|
||||
#define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */
|
||||
#define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */
|
||||
#define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */
|
||||
|
||||
#define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */
|
||||
#define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */
|
||||
#define RMT_TX_DATA_NUM 100 /*!< NEC tx test data number */
|
||||
#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
|
||||
|
||||
/*
|
||||
* @brief Build register value of waveform for NEC one data bit
|
||||
*/
|
||||
inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us)
|
||||
{
|
||||
item->level0 = 1;
|
||||
item->duration0 = (high_us) / 10 * RMT_TICK_10_US;
|
||||
item->level1 = 0;
|
||||
item->duration1 = (low_us) / 10 * RMT_TICK_10_US;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC header value: active 9ms + negative 4.5ms
|
||||
*/
|
||||
static void nec_fill_item_header(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms
|
||||
*/
|
||||
static void nec_fill_item_bit_one(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms
|
||||
*/
|
||||
static void nec_fill_item_bit_zero(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC end signal: positive 0.56ms
|
||||
*/
|
||||
static void nec_fill_item_end(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_END, 0x7fff);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether duration is around target_us
|
||||
*/
|
||||
inline bool nec_check_in_range(int duration_ticks, int target_us, int margin_us)
|
||||
{
|
||||
if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us))
|
||||
&& ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC header
|
||||
*/
|
||||
static bool nec_header_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC data bit 1
|
||||
*/
|
||||
static bool nec_bit_one_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC data bit 0
|
||||
*/
|
||||
static bool nec_bit_zero_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Parse NEC 32 bit waveform to address and command.
|
||||
*/
|
||||
static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data)
|
||||
{
|
||||
int w_len = item_num;
|
||||
if(w_len < NEC_DATA_ITEM_NUM) {
|
||||
return -1;
|
||||
}
|
||||
int i = 0, j = 0;
|
||||
if(!nec_header_if(item++)) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t addr_t = 0;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(nec_bit_one_if(item)) {
|
||||
addr_t |= (1 << j);
|
||||
} else if(nec_bit_zero_if(item)) {
|
||||
addr_t |= (0 << j);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
}
|
||||
uint16_t data_t = 0;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(nec_bit_one_if(item)) {
|
||||
data_t |= (1 << j);
|
||||
} else if(nec_bit_zero_if(item)) {
|
||||
data_t |= (0 << j);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
}
|
||||
*addr = addr_t;
|
||||
*data = data_t;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Build NEC 32bit waveform.
|
||||
*/
|
||||
static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
if(item_num < NEC_DATA_ITEM_NUM) {
|
||||
return -1;
|
||||
}
|
||||
nec_fill_item_header(item++);
|
||||
i++;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(addr & 0x1) {
|
||||
nec_fill_item_bit_one(item);
|
||||
} else {
|
||||
nec_fill_item_bit_zero(item);
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
addr >>= 1;
|
||||
}
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(cmd_data & 0x1) {
|
||||
nec_fill_item_bit_one(item);
|
||||
} else {
|
||||
nec_fill_item_bit_zero(item);
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
cmd_data >>= 1;
|
||||
}
|
||||
nec_fill_item_end(item);
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief RMT transmitter initialization
|
||||
*/
|
||||
static void rmt_tx_init()
|
||||
{
|
||||
rmt_config_t rmt_tx;
|
||||
rmt_tx.channel = RMT_TX_CHANNEL;
|
||||
rmt_tx.gpio_num = RMT_TX_GPIO_NUM;
|
||||
rmt_tx.mem_block_num = 1;
|
||||
rmt_tx.clk_div = RMT_CLK_DIV;
|
||||
rmt_tx.tx_config.loop_en = false;
|
||||
rmt_tx.tx_config.carrier_duty_percent = 50;
|
||||
rmt_tx.tx_config.carrier_freq_hz = 38000;
|
||||
rmt_tx.tx_config.carrier_level = 1;
|
||||
rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
|
||||
rmt_tx.tx_config.idle_level = 0;
|
||||
rmt_tx.tx_config.idle_output_en = true;
|
||||
rmt_tx.rmt_mode = 0;
|
||||
rmt_config(&rmt_tx);
|
||||
rmt_driver_install(rmt_tx.channel, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief RMT receiver initialization
|
||||
*/
|
||||
void rmt_rx_init()
|
||||
{
|
||||
rmt_config_t rmt_rx;
|
||||
rmt_rx.channel = RMT_RX_CHANNEL;
|
||||
rmt_rx.gpio_num = RMT_RX_GPIO_NUM;
|
||||
rmt_rx.clk_div = RMT_CLK_DIV;
|
||||
rmt_rx.mem_block_num = 1;
|
||||
rmt_rx.rmt_mode = RMT_MODE_RX;
|
||||
rmt_rx.rx_config.filter_en = true;
|
||||
rmt_rx.rx_config.filter_ticks_thresh = 100;
|
||||
rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
|
||||
rmt_config(&rmt_rx);
|
||||
rmt_driver_install(rmt_rx.channel, 1000, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RMT receiver demo, this task will print each received NEC data.
|
||||
*
|
||||
*/
|
||||
void rmt_nec_rx_task()
|
||||
{
|
||||
int channel = RMT_RX_CHANNEL;
|
||||
rmt_rx_init();
|
||||
RingbufHandle_t rb = NULL;
|
||||
//get RMT RX ringbuffer
|
||||
rmt_get_ringbuf_handler(channel, &rb);
|
||||
rmt_rx_start(channel, 1);
|
||||
while(rb) {
|
||||
size_t rx_size = 0;
|
||||
//try to receive data from ringbuffer.
|
||||
//RMT driver will push all the data it receives to its ringbuffer.
|
||||
//We just need to parse the value and return the spaces of ringbuffer.
|
||||
rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000);
|
||||
if(item) {
|
||||
uint16_t rmt_addr;
|
||||
uint16_t rmt_cmd;
|
||||
int offset = 0;
|
||||
while(1) {
|
||||
//parse data value from ringbuffer.
|
||||
int res = nec_parse_items(item + offset, rx_size / 4 - offset, &rmt_addr, &rmt_cmd);
|
||||
if(res > 0) {
|
||||
offset += res + 1;
|
||||
ESP_LOGI(NEC_TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", rmt_addr, rmt_cmd);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//after parsing the data, return spaces to ringbuffer.
|
||||
vRingbufferReturnItem(rb, (void*) item);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.)
|
||||
*
|
||||
*/
|
||||
void rmt_nec_tx_task()
|
||||
{
|
||||
vTaskDelay(10);
|
||||
rmt_tx_init();
|
||||
esp_log_level_set(NEC_TAG, ESP_LOG_INFO);
|
||||
int channel = RMT_TX_CHANNEL;
|
||||
uint16_t cmd = 0x0;
|
||||
uint16_t addr = 0x11;
|
||||
int nec_tx_num = RMT_TX_DATA_NUM;
|
||||
for(;;) {
|
||||
ESP_LOGI(NEC_TAG, "RMT TX DATA");
|
||||
size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num);
|
||||
//each item represent a cycle of waveform.
|
||||
rmt_item32_t* item = (rmt_item32_t*) malloc(size);
|
||||
int item_num = NEC_DATA_ITEM_NUM * nec_tx_num;
|
||||
memset((void*) item, 0, size);
|
||||
int i, offset = 0;
|
||||
while(1) {
|
||||
//To build a series of waveforms.
|
||||
i = nec_build_items(channel, item + offset, item_num - offset, ((~addr) << 8) | addr, cmd);
|
||||
if(i < 0) {
|
||||
break;
|
||||
}
|
||||
cmd++;
|
||||
addr++;
|
||||
offset += i;
|
||||
}
|
||||
//To send data according to the waveform items.
|
||||
rmt_write_items(channel, item, item_num, true);
|
||||
//Wait until sending is done.
|
||||
rmt_wait_tx_done(channel);
|
||||
//before we free the data, make sure sending is already done.
|
||||
free(item);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
@@ -7,17 +7,358 @@
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
extern void rmt_nec_tx_task();
|
||||
extern void rmt_nec_rx_task();
|
||||
#include "soc/rmt_reg.h"
|
||||
|
||||
static const char* NEC_TAG = "NEC";
|
||||
|
||||
//CHOOSE SELF TEST OR NORMAL TEST
|
||||
#define RMT_RX_SELF_TEST 1
|
||||
|
||||
/******************************************************/
|
||||
/***** SELF TEST: *****/
|
||||
/*Connect RMT_TX_GPIO_NUM with RMT_RX_GPIO_NUM */
|
||||
/*TX task will send NEC data with carrier disabled */
|
||||
/*RX task will print NEC data it receives. */
|
||||
/******************************************************/
|
||||
#if RMT_RX_SELF_TEST
|
||||
#define RMT_RX_ACTIVE_LEVEL 1 /*!< Data bit is active high for self test mode */
|
||||
#define RMT_TX_CARRIER_EN 0 /*!< Disable carrier for self test mode */
|
||||
#else
|
||||
//Test with infrared LED, we have to enable carrier for transmitter
|
||||
//When testing via IR led, the receiver waveform is usually active-low.
|
||||
#define RMT_RX_ACTIVE_LEVEL 0 /*!< If we connect with a IR receiver, the data is active low */
|
||||
#define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */
|
||||
#endif
|
||||
|
||||
#define RMT_TX_CHANNEL 1 /*!< RMT channel for transmitter */
|
||||
#define RMT_TX_GPIO_NUM 16 /*!< GPIO number for transmitter signal */
|
||||
#define RMT_RX_CHANNEL 0 /*!< RMT channel for receiver */
|
||||
#define RMT_RX_GPIO_NUM 19 /*!< GPIO number for receiver */
|
||||
#define RMT_CLK_DIV 100 /*!< RMT counter clock divider */
|
||||
#define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */
|
||||
|
||||
#define NEC_HEADER_HIGH_US 9000 /*!< NEC protocol header: positive 9ms */
|
||||
#define NEC_HEADER_LOW_US 4500 /*!< NEC protocol header: negative 4.5ms*/
|
||||
#define NEC_BIT_ONE_HIGH_US 560 /*!< NEC protocol data bit 1: positive 0.56ms */
|
||||
#define NEC_BIT_ONE_LOW_US (2250-NEC_BIT_ONE_HIGH_US) /*!< NEC protocol data bit 1: negative 1.69ms */
|
||||
#define NEC_BIT_ZERO_HIGH_US 560 /*!< NEC protocol data bit 0: positive 0.56ms */
|
||||
#define NEC_BIT_ZERO_LOW_US (1120-NEC_BIT_ZERO_HIGH_US) /*!< NEC protocol data bit 0: negative 0.56ms */
|
||||
#define NEC_BIT_END 560 /*!< NEC protocol end: positive 0.56ms */
|
||||
#define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */
|
||||
|
||||
#define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */
|
||||
#define NEC_DATA_ITEM_NUM 34 /*!< NEC code item number: header + 32bit data + end */
|
||||
#define RMT_TX_DATA_NUM 100 /*!< NEC tx test data number */
|
||||
#define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */
|
||||
|
||||
/*
|
||||
* @brief Build register value of waveform for NEC one data bit
|
||||
*/
|
||||
static inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us)
|
||||
{
|
||||
item->level0 = 1;
|
||||
item->duration0 = (high_us) / 10 * RMT_TICK_10_US;
|
||||
item->level1 = 0;
|
||||
item->duration1 = (low_us) / 10 * RMT_TICK_10_US;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC header value: active 9ms + negative 4.5ms
|
||||
*/
|
||||
static void nec_fill_item_header(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC data bit 1: positive 0.56ms + negative 1.69ms
|
||||
*/
|
||||
static void nec_fill_item_bit_one(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC data bit 0: positive 0.56ms + negative 0.56ms
|
||||
*/
|
||||
static void nec_fill_item_bit_zero(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Generate NEC end signal: positive 0.56ms
|
||||
*/
|
||||
static void nec_fill_item_end(rmt_item32_t* item)
|
||||
{
|
||||
nec_fill_item_level(item, NEC_BIT_END, 0x7fff);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether duration is around target_us
|
||||
*/
|
||||
inline bool nec_check_in_range(int duration_ticks, int target_us, int margin_us)
|
||||
{
|
||||
if(( NEC_ITEM_DURATION(duration_ticks) < (target_us + margin_us))
|
||||
&& ( NEC_ITEM_DURATION(duration_ticks) > (target_us - margin_us))) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC header
|
||||
*/
|
||||
static bool nec_header_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_HEADER_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_HEADER_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC data bit 1
|
||||
*/
|
||||
static bool nec_bit_one_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_BIT_ONE_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_BIT_ONE_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Check whether this value represents an NEC data bit 0
|
||||
*/
|
||||
static bool nec_bit_zero_if(rmt_item32_t* item)
|
||||
{
|
||||
if((item->level0 == RMT_RX_ACTIVE_LEVEL && item->level1 != RMT_RX_ACTIVE_LEVEL)
|
||||
&& nec_check_in_range(item->duration0, NEC_BIT_ZERO_HIGH_US, NEC_BIT_MARGIN)
|
||||
&& nec_check_in_range(item->duration1, NEC_BIT_ZERO_LOW_US, NEC_BIT_MARGIN)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Parse NEC 32 bit waveform to address and command.
|
||||
*/
|
||||
static int nec_parse_items(rmt_item32_t* item, int item_num, uint16_t* addr, uint16_t* data)
|
||||
{
|
||||
int w_len = item_num;
|
||||
if(w_len < NEC_DATA_ITEM_NUM) {
|
||||
return -1;
|
||||
}
|
||||
int i = 0, j = 0;
|
||||
if(!nec_header_if(item++)) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t addr_t = 0;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(nec_bit_one_if(item)) {
|
||||
addr_t |= (1 << j);
|
||||
} else if(nec_bit_zero_if(item)) {
|
||||
addr_t |= (0 << j);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
}
|
||||
uint16_t data_t = 0;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(nec_bit_one_if(item)) {
|
||||
data_t |= (1 << j);
|
||||
} else if(nec_bit_zero_if(item)) {
|
||||
data_t |= (0 << j);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
}
|
||||
*addr = addr_t;
|
||||
*data = data_t;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Build NEC 32bit waveform.
|
||||
*/
|
||||
static int nec_build_items(int channel, rmt_item32_t* item, int item_num, uint16_t addr, uint16_t cmd_data)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
if(item_num < NEC_DATA_ITEM_NUM) {
|
||||
return -1;
|
||||
}
|
||||
nec_fill_item_header(item++);
|
||||
i++;
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(addr & 0x1) {
|
||||
nec_fill_item_bit_one(item);
|
||||
} else {
|
||||
nec_fill_item_bit_zero(item);
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
addr >>= 1;
|
||||
}
|
||||
for(j = 0; j < 16; j++) {
|
||||
if(cmd_data & 0x1) {
|
||||
nec_fill_item_bit_one(item);
|
||||
} else {
|
||||
nec_fill_item_bit_zero(item);
|
||||
}
|
||||
item++;
|
||||
i++;
|
||||
cmd_data >>= 1;
|
||||
}
|
||||
nec_fill_item_end(item);
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief RMT transmitter initialization
|
||||
*/
|
||||
static void nec_tx_init()
|
||||
{
|
||||
rmt_config_t rmt_tx;
|
||||
rmt_tx.channel = RMT_TX_CHANNEL;
|
||||
rmt_tx.gpio_num = RMT_TX_GPIO_NUM;
|
||||
rmt_tx.mem_block_num = 1;
|
||||
rmt_tx.clk_div = RMT_CLK_DIV;
|
||||
rmt_tx.tx_config.loop_en = false;
|
||||
rmt_tx.tx_config.carrier_duty_percent = 50;
|
||||
rmt_tx.tx_config.carrier_freq_hz = 38000;
|
||||
rmt_tx.tx_config.carrier_level = 1;
|
||||
rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN;
|
||||
rmt_tx.tx_config.idle_level = 0;
|
||||
rmt_tx.tx_config.idle_output_en = true;
|
||||
rmt_tx.rmt_mode = 0;
|
||||
rmt_config(&rmt_tx);
|
||||
rmt_driver_install(rmt_tx.channel, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief RMT receiver initialization
|
||||
*/
|
||||
static void nec_rx_init()
|
||||
{
|
||||
rmt_config_t rmt_rx;
|
||||
rmt_rx.channel = RMT_RX_CHANNEL;
|
||||
rmt_rx.gpio_num = RMT_RX_GPIO_NUM;
|
||||
rmt_rx.clk_div = RMT_CLK_DIV;
|
||||
rmt_rx.mem_block_num = 1;
|
||||
rmt_rx.rmt_mode = RMT_MODE_RX;
|
||||
rmt_rx.rx_config.filter_en = true;
|
||||
rmt_rx.rx_config.filter_ticks_thresh = 100;
|
||||
rmt_rx.rx_config.idle_threshold = rmt_item32_tIMEOUT_US / 10 * (RMT_TICK_10_US);
|
||||
rmt_config(&rmt_rx);
|
||||
rmt_driver_install(rmt_rx.channel, 1000, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RMT receiver demo, this task will print each received NEC data.
|
||||
*
|
||||
*/
|
||||
static void rmt_example_nec_rx_task()
|
||||
{
|
||||
int channel = RMT_RX_CHANNEL;
|
||||
nec_rx_init();
|
||||
RingbufHandle_t rb = NULL;
|
||||
//get RMT RX ringbuffer
|
||||
rmt_get_ringbuf_handler(channel, &rb);
|
||||
rmt_rx_start(channel, 1);
|
||||
while(rb) {
|
||||
size_t rx_size = 0;
|
||||
//try to receive data from ringbuffer.
|
||||
//RMT driver will push all the data it receives to its ringbuffer.
|
||||
//We just need to parse the value and return the spaces of ringbuffer.
|
||||
rmt_item32_t* item = (rmt_item32_t*) xRingbufferReceive(rb, &rx_size, 1000);
|
||||
if(item) {
|
||||
uint16_t rmt_addr;
|
||||
uint16_t rmt_cmd;
|
||||
int offset = 0;
|
||||
while(1) {
|
||||
//parse data value from ringbuffer.
|
||||
int res = nec_parse_items(item + offset, rx_size / 4 - offset, &rmt_addr, &rmt_cmd);
|
||||
if(res > 0) {
|
||||
offset += res + 1;
|
||||
ESP_LOGI(NEC_TAG, "RMT RCV --- addr: 0x%04x cmd: 0x%04x", rmt_addr, rmt_cmd);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//after parsing the data, return spaces to ringbuffer.
|
||||
vRingbufferReturnItem(rb, (void*) item);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.)
|
||||
*
|
||||
*/
|
||||
static void rmt_example_nec_tx_task()
|
||||
{
|
||||
vTaskDelay(10);
|
||||
nec_tx_init();
|
||||
esp_log_level_set(NEC_TAG, ESP_LOG_INFO);
|
||||
int channel = RMT_TX_CHANNEL;
|
||||
uint16_t cmd = 0x0;
|
||||
uint16_t addr = 0x11;
|
||||
int nec_tx_num = RMT_TX_DATA_NUM;
|
||||
for(;;) {
|
||||
ESP_LOGI(NEC_TAG, "RMT TX DATA");
|
||||
size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num);
|
||||
//each item represent a cycle of waveform.
|
||||
rmt_item32_t* item = (rmt_item32_t*) malloc(size);
|
||||
int item_num = NEC_DATA_ITEM_NUM * nec_tx_num;
|
||||
memset((void*) item, 0, size);
|
||||
int i, offset = 0;
|
||||
while(1) {
|
||||
//To build a series of waveforms.
|
||||
i = nec_build_items(channel, item + offset, item_num - offset, ((~addr) << 8) | addr, cmd);
|
||||
if(i < 0) {
|
||||
break;
|
||||
}
|
||||
cmd++;
|
||||
addr++;
|
||||
offset += i;
|
||||
}
|
||||
//To send data according to the waveform items.
|
||||
rmt_write_items(channel, item, item_num, true);
|
||||
//Wait until sending is done.
|
||||
rmt_wait_tx_done(channel);
|
||||
//before we free the data, make sure sending is already done.
|
||||
free(item);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
xTaskCreate(rmt_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL);
|
||||
xTaskCreate(rmt_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL);
|
||||
xTaskCreate(rmt_example_nec_rx_task, "rmt_nec_rx_task", 2048, NULL, 10, NULL);
|
||||
xTaskCreate(rmt_example_nec_tx_task, "rmt_nec_tx_task", 2048, NULL, 10, NULL);
|
||||
}
|
||||
|
Reference in New Issue
Block a user