-
Notifications
You must be signed in to change notification settings - Fork 7k
/
ir_nec_encoder.c
154 lines (143 loc) · 6.52 KB
/
ir_nec_encoder.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "ir_nec_encoder.h"
static const char *TAG = "nec_encoder";
typedef struct {
rmt_encoder_t base; // the base "class", declares the standard encoder interface
rmt_encoder_t *copy_encoder; // use the copy_encoder to encode the leading and ending pulse
rmt_encoder_t *bytes_encoder; // use the bytes_encoder to encode the address and command data
rmt_symbol_word_t nec_leading_symbol; // NEC leading code with RMT representation
rmt_symbol_word_t nec_ending_symbol; // NEC ending code with RMT representation
int state;
} rmt_ir_nec_encoder_t;
static size_t rmt_encode_ir_nec(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
rmt_encode_state_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
ir_nec_scan_code_t *scan_code = (ir_nec_scan_code_t *)primary_data;
rmt_encoder_handle_t copy_encoder = nec_encoder->copy_encoder;
rmt_encoder_handle_t bytes_encoder = nec_encoder->bytes_encoder;
switch (nec_encoder->state) {
case 0: // send leading code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &nec_encoder->nec_leading_symbol,
sizeof(rmt_symbol_word_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
nec_encoder->state = 1; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
// fall-through
case 1: // send address
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &scan_code->address, sizeof(uint16_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
nec_encoder->state = 2; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
// fall-through
case 2: // send command
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, &scan_code->command, sizeof(uint16_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
nec_encoder->state = 3; // we can only switch to next state when current encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
// fall-through
case 3: // send ending code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &nec_encoder->nec_ending_symbol,
sizeof(rmt_symbol_word_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
nec_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
state |= RMT_ENCODING_COMPLETE;
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_ir_nec_encoder(rmt_encoder_t *encoder)
{
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
rmt_del_encoder(nec_encoder->copy_encoder);
rmt_del_encoder(nec_encoder->bytes_encoder);
free(nec_encoder);
return ESP_OK;
}
static esp_err_t rmt_ir_nec_encoder_reset(rmt_encoder_t *encoder)
{
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
rmt_encoder_reset(nec_encoder->copy_encoder);
rmt_encoder_reset(nec_encoder->bytes_encoder);
nec_encoder->state = RMT_ENCODING_RESET;
return ESP_OK;
}
esp_err_t rmt_new_ir_nec_encoder(const ir_nec_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_ir_nec_encoder_t *nec_encoder = NULL;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
nec_encoder = rmt_alloc_encoder_mem(sizeof(rmt_ir_nec_encoder_t));
ESP_GOTO_ON_FALSE(nec_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for ir nec encoder");
nec_encoder->base.encode = rmt_encode_ir_nec;
nec_encoder->base.del = rmt_del_ir_nec_encoder;
nec_encoder->base.reset = rmt_ir_nec_encoder_reset;
rmt_copy_encoder_config_t copy_encoder_config = {};
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &nec_encoder->copy_encoder), err, TAG, "create copy encoder failed");
// construct the leading code and ending code with RMT symbol format
nec_encoder->nec_leading_symbol = (rmt_symbol_word_t) {
.level0 = 1,
.duration0 = 9000ULL * config->resolution / 1000000,
.level1 = 0,
.duration1 = 4500ULL * config->resolution / 1000000,
};
nec_encoder->nec_ending_symbol = (rmt_symbol_word_t) {
.level0 = 1,
.duration0 = 560 * config->resolution / 1000000,
.level1 = 0,
.duration1 = 0x7FFF,
};
rmt_bytes_encoder_config_t bytes_encoder_config = {
.bit0 = {
.level0 = 1,
.duration0 = 560 * config->resolution / 1000000, // T0H=560us
.level1 = 0,
.duration1 = 560 * config->resolution / 1000000, // T0L=560us
},
.bit1 = {
.level0 = 1,
.duration0 = 560 * config->resolution / 1000000, // T1H=560us
.level1 = 0,
.duration1 = 1690 * config->resolution / 1000000, // T1L=1690us
},
};
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &nec_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
*ret_encoder = &nec_encoder->base;
return ESP_OK;
err:
if (nec_encoder) {
if (nec_encoder->bytes_encoder) {
rmt_del_encoder(nec_encoder->bytes_encoder);
}
if (nec_encoder->copy_encoder) {
rmt_del_encoder(nec_encoder->copy_encoder);
}
free(nec_encoder);
}
return ret;
}