1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.#include <stdlib.h>
14 #include <sys/cdefs.h>
15 #include "esp_log.h"
16 #include "ir_tools.h"
17 #include "ir_timings.h"
18 #include "driver/rmt.h"
19
20 static const char *TAG = "nec_builder";
21 #define NEC_CHECK(a, str, goto_tag, ret_value, ...) \
22 do \
23 { \
24 if (!(a)) \
25 { \
26 ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
27 ret = ret_value; \
28 goto goto_tag; \
29 } \
30 } while (0)
31
32 typedef struct {
33 ir_builder_t parent;
34 uint32_t buffer_size;
35 uint32_t cursor;
36 uint32_t flags;
37 uint32_t leading_code_high_ticks;
38 uint32_t leading_code_low_ticks;
39 uint32_t repeat_code_high_ticks;
40 uint32_t repeat_code_low_ticks;
41 uint32_t payload_logic0_high_ticks;
42 uint32_t payload_logic0_low_ticks;
43 uint32_t payload_logic1_high_ticks;
44 uint32_t payload_logic1_low_ticks;
45 uint32_t ending_code_high_ticks;
46 uint32_t ending_code_low_ticks;
47 bool inverse;
48 rmt_item32_t buffer[0];
49 } nec_builder_t;
50
nec_builder_make_head(ir_builder_t * builder)51 static esp_err_t nec_builder_make_head(ir_builder_t *builder)
52 {
53 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
54 nec_builder->cursor = 0;
55 nec_builder->buffer[nec_builder->cursor].level0 = !nec_builder->inverse;
56 nec_builder->buffer[nec_builder->cursor].duration0 = nec_builder->leading_code_high_ticks;
57 nec_builder->buffer[nec_builder->cursor].level1 = nec_builder->inverse;
58 nec_builder->buffer[nec_builder->cursor].duration1 = nec_builder->leading_code_low_ticks;
59 nec_builder->cursor += 1;
60 return ESP_OK;
61 }
62
nec_builder_make_logic0(ir_builder_t * builder)63 static esp_err_t nec_builder_make_logic0(ir_builder_t *builder)
64 {
65 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
66 nec_builder->buffer[nec_builder->cursor].level0 = !nec_builder->inverse;
67 nec_builder->buffer[nec_builder->cursor].duration0 = nec_builder->payload_logic0_high_ticks;
68 nec_builder->buffer[nec_builder->cursor].level1 = nec_builder->inverse;
69 nec_builder->buffer[nec_builder->cursor].duration1 = nec_builder->payload_logic0_low_ticks;
70 nec_builder->cursor += 1;
71 return ESP_OK;
72 }
73
nec_builder_make_logic1(ir_builder_t * builder)74 static esp_err_t nec_builder_make_logic1(ir_builder_t *builder)
75 {
76 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
77 nec_builder->buffer[nec_builder->cursor].level0 = !nec_builder->inverse;
78 nec_builder->buffer[nec_builder->cursor].duration0 = nec_builder->payload_logic1_high_ticks;
79 nec_builder->buffer[nec_builder->cursor].level1 = nec_builder->inverse;
80 nec_builder->buffer[nec_builder->cursor].duration1 = nec_builder->payload_logic1_low_ticks;
81 nec_builder->cursor += 1;
82 return ESP_OK;
83 }
84
nec_builder_make_end(ir_builder_t * builder)85 static esp_err_t nec_builder_make_end(ir_builder_t *builder)
86 {
87 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
88 nec_builder->buffer[nec_builder->cursor].level0 = !nec_builder->inverse;
89 nec_builder->buffer[nec_builder->cursor].duration0 = nec_builder->ending_code_high_ticks;
90 nec_builder->buffer[nec_builder->cursor].level1 = nec_builder->inverse;
91 nec_builder->buffer[nec_builder->cursor].duration1 = nec_builder->ending_code_low_ticks;
92 nec_builder->cursor += 1;
93 nec_builder->buffer[nec_builder->cursor].val = 0;
94 nec_builder->cursor += 1;
95 return ESP_OK;
96 }
97
nec_build_frame(ir_builder_t * builder,uint32_t address,uint32_t command)98 static esp_err_t nec_build_frame(ir_builder_t *builder, uint32_t address, uint32_t command)
99 {
100 esp_err_t ret = ESP_OK;
101 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
102 if (!nec_builder->flags & IR_TOOLS_FLAGS_PROTO_EXT) {
103 uint8_t low_byte = address & 0xFF;
104 uint8_t high_byte = (address >> 8) & 0xFF;
105 NEC_CHECK(low_byte == (~high_byte & 0xFF), "address not match standard NEC protocol", err, ESP_ERR_INVALID_ARG);
106 low_byte = command & 0xFF;
107 high_byte = (command >> 8) & 0xFF;
108 NEC_CHECK(low_byte == (~high_byte & 0xFF), "command not match standard NEC protocol", err, ESP_ERR_INVALID_ARG);
109 }
110 builder->make_head(builder);
111 // LSB -> MSB
112 for (int i = 0; i < 16; i++) {
113 if (address & (1 << i)) {
114 builder->make_logic1(builder);
115 } else {
116 builder->make_logic0(builder);
117 }
118 }
119 for (int i = 0; i < 16; i++) {
120 if (command & (1 << i)) {
121 builder->make_logic1(builder);
122 } else {
123 builder->make_logic0(builder);
124 }
125 }
126 builder->make_end(builder);
127 return ESP_OK;
128 err:
129 return ret;
130 }
131
nec_build_repeat_frame(ir_builder_t * builder)132 static esp_err_t nec_build_repeat_frame(ir_builder_t *builder)
133 {
134 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
135 nec_builder->cursor = 0;
136 nec_builder->buffer[nec_builder->cursor].level0 = !nec_builder->inverse;
137 nec_builder->buffer[nec_builder->cursor].duration0 = nec_builder->repeat_code_high_ticks;
138 nec_builder->buffer[nec_builder->cursor].level1 = nec_builder->inverse;
139 nec_builder->buffer[nec_builder->cursor].duration1 = nec_builder->repeat_code_low_ticks;
140 nec_builder->cursor += 1;
141 nec_builder_make_end(builder);
142 return ESP_OK;
143 }
144
nec_builder_get_result(ir_builder_t * builder,void * result,size_t * length)145 static esp_err_t nec_builder_get_result(ir_builder_t *builder, void *result, size_t *length)
146 {
147 esp_err_t ret = ESP_OK;
148 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
149 NEC_CHECK(result && length, "result and length can't be null", err, ESP_ERR_INVALID_ARG);
150 *(rmt_item32_t **)result = nec_builder->buffer;
151 *length = nec_builder->cursor;
152 return ESP_OK;
153 err:
154 return ret;
155 }
156
nec_builder_del(ir_builder_t * builder)157 static esp_err_t nec_builder_del(ir_builder_t *builder)
158 {
159 nec_builder_t *nec_builder = __containerof(builder, nec_builder_t, parent);
160 free(nec_builder);
161 return ESP_OK;
162 }
163
ir_builder_rmt_new_nec(const ir_builder_config_t * config)164 ir_builder_t *ir_builder_rmt_new_nec(const ir_builder_config_t *config)
165 {
166 ir_builder_t *ret = NULL;
167 NEC_CHECK(config, "nec configuration can't be null", err, NULL);
168 NEC_CHECK(config->buffer_size, "buffer size can't be zero", err, NULL);
169
170 uint32_t builder_size = sizeof(nec_builder_t) + config->buffer_size * sizeof(rmt_item32_t);
171 nec_builder_t *nec_builder = calloc(1, builder_size);
172 NEC_CHECK(nec_builder, "request memory for nec_builder failed", err, NULL);
173
174 nec_builder->buffer_size = config->buffer_size;
175 nec_builder->flags = config->flags;
176 if (config->flags & IR_TOOLS_FLAGS_INVERSE) {
177 nec_builder->inverse = true;
178 }
179
180 uint32_t counter_clk_hz = 0;
181 NEC_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev_hdl, &counter_clk_hz) == ESP_OK,
182 "get rmt counter clock failed", err, NULL);
183 float ratio = (float)counter_clk_hz / 1e6;
184 nec_builder->leading_code_high_ticks = (uint32_t)(ratio * NEC_LEADING_CODE_HIGH_US);
185 nec_builder->leading_code_low_ticks = (uint32_t)(ratio * NEC_LEADING_CODE_LOW_US);
186 nec_builder->repeat_code_high_ticks = (uint32_t)(ratio * NEC_REPEAT_CODE_HIGH_US);
187 nec_builder->repeat_code_low_ticks = (uint32_t)(ratio * NEC_REPEAT_CODE_LOW_US);
188 nec_builder->payload_logic0_high_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ZERO_HIGH_US);
189 nec_builder->payload_logic0_low_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ZERO_LOW_US);
190 nec_builder->payload_logic1_high_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ONE_HIGH_US);
191 nec_builder->payload_logic1_low_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ONE_LOW_US);
192 nec_builder->ending_code_high_ticks = (uint32_t)(ratio * NEC_ENDING_CODE_HIGH_US);
193 nec_builder->ending_code_low_ticks = 0x7FFF;
194 nec_builder->parent.make_head = nec_builder_make_head;
195 nec_builder->parent.make_logic0 = nec_builder_make_logic0;
196 nec_builder->parent.make_logic1 = nec_builder_make_logic1;
197 nec_builder->parent.make_end = nec_builder_make_end;
198 nec_builder->parent.build_frame = nec_build_frame;
199 nec_builder->parent.build_repeat_frame = nec_build_repeat_frame;
200 nec_builder->parent.get_result = nec_builder_get_result;
201 nec_builder->parent.del = nec_builder_del;
202 nec_builder->parent.repeat_period_ms = 110;
203 return &nec_builder->parent;
204 err:
205 return ret;
206 }
207