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.
14 #include <stdlib.h>
15 #include <sys/cdefs.h>
16 #include "esp_log.h"
17 #include "ir_tools.h"
18 #include "ir_timings.h"
19 #include "driver/rmt.h"
20 
21 static const char *TAG = "nec_parser";
22 #define NEC_CHECK(a, str, goto_tag, ret_value, ...)                               \
23     do                                                                            \
24     {                                                                             \
25         if (!(a))                                                                 \
26         {                                                                         \
27             ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
28             ret = ret_value;                                                      \
29             goto goto_tag;                                                        \
30         }                                                                         \
31     } while (0)
32 
33 #define NEC_DATA_FRAME_RMT_WORDS (34)
34 #define NEC_REPEAT_FRAME_RMT_WORDS (2)
35 
36 typedef struct {
37     ir_parser_t parent;
38     uint32_t flags;
39     uint32_t leading_code_high_ticks;
40     uint32_t leading_code_low_ticks;
41     uint32_t repeat_code_high_ticks;
42     uint32_t repeat_code_low_ticks;
43     uint32_t payload_logic0_high_ticks;
44     uint32_t payload_logic0_low_ticks;
45     uint32_t payload_logic1_high_ticks;
46     uint32_t payload_logic1_low_ticks;
47     uint32_t margin_ticks;
48     rmt_item32_t *buffer;
49     uint32_t cursor;
50     uint32_t last_address;
51     uint32_t last_command;
52     bool repeat;
53     bool inverse;
54 } nec_parser_t;
55 
nec_check_in_range(uint32_t raw_ticks,uint32_t target_ticks,uint32_t margin_ticks)56 static inline bool nec_check_in_range(uint32_t raw_ticks, uint32_t target_ticks, uint32_t margin_ticks)
57 {
58     return (raw_ticks < (target_ticks + margin_ticks)) && (raw_ticks > (target_ticks - margin_ticks));
59 }
60 
nec_parse_head(nec_parser_t * nec_parser)61 static bool nec_parse_head(nec_parser_t *nec_parser)
62 {
63     nec_parser->cursor = 0;
64     rmt_item32_t item = nec_parser->buffer[nec_parser->cursor];
65     bool ret = (item.level0 == nec_parser->inverse) && (item.level1 != nec_parser->inverse) &&
66                nec_check_in_range(item.duration0, nec_parser->leading_code_high_ticks, nec_parser->margin_ticks) &&
67                nec_check_in_range(item.duration1, nec_parser->leading_code_low_ticks, nec_parser->margin_ticks);
68     nec_parser->cursor += 1;
69     return ret;
70 }
71 
nec_parse_logic0(nec_parser_t * nec_parser)72 static bool nec_parse_logic0(nec_parser_t *nec_parser)
73 {
74     rmt_item32_t item = nec_parser->buffer[nec_parser->cursor];
75     bool ret = (item.level0 == nec_parser->inverse) && (item.level1 != nec_parser->inverse) &&
76                nec_check_in_range(item.duration0, nec_parser->payload_logic0_high_ticks, nec_parser->margin_ticks) &&
77                nec_check_in_range(item.duration1, nec_parser->payload_logic0_low_ticks, nec_parser->margin_ticks);
78     return ret;
79 }
80 
nec_parse_logic1(nec_parser_t * nec_parser)81 static bool nec_parse_logic1(nec_parser_t *nec_parser)
82 {
83     rmt_item32_t item = nec_parser->buffer[nec_parser->cursor];
84     bool ret = (item.level0 == nec_parser->inverse) && (item.level1 != nec_parser->inverse) &&
85                nec_check_in_range(item.duration0, nec_parser->payload_logic1_high_ticks, nec_parser->margin_ticks) &&
86                nec_check_in_range(item.duration1, nec_parser->payload_logic1_low_ticks, nec_parser->margin_ticks);
87     return ret;
88 }
89 
nec_parse_logic(ir_parser_t * parser,bool * logic)90 static esp_err_t nec_parse_logic(ir_parser_t *parser, bool *logic)
91 {
92     esp_err_t ret = ESP_FAIL;
93     bool logic_value = false;
94     nec_parser_t *nec_parser = __containerof(parser, nec_parser_t, parent);
95     if (nec_parse_logic0(nec_parser)) {
96         logic_value = false;
97         ret = ESP_OK;
98     } else if (nec_parse_logic1(nec_parser)) {
99         logic_value = true;
100         ret = ESP_OK;
101     }
102     if (ret == ESP_OK) {
103         *logic = logic_value;
104     }
105     nec_parser->cursor += 1;
106     return ret;
107 }
108 
nec_parse_repeat_frame(nec_parser_t * nec_parser)109 static bool nec_parse_repeat_frame(nec_parser_t *nec_parser)
110 {
111     nec_parser->cursor = 0;
112     rmt_item32_t item = nec_parser->buffer[nec_parser->cursor];
113     bool ret = (item.level0 == nec_parser->inverse) && (item.level1 != nec_parser->inverse) &&
114                nec_check_in_range(item.duration0, nec_parser->repeat_code_high_ticks, nec_parser->margin_ticks) &&
115                nec_check_in_range(item.duration1, nec_parser->repeat_code_low_ticks, nec_parser->margin_ticks);
116     nec_parser->cursor += 1;
117     return ret;
118 }
119 
nec_parser_input(ir_parser_t * parser,void * raw_data,uint32_t length)120 static esp_err_t nec_parser_input(ir_parser_t *parser, void *raw_data, uint32_t length)
121 {
122     esp_err_t ret = ESP_OK;
123     nec_parser_t *nec_parser = __containerof(parser, nec_parser_t, parent);
124     NEC_CHECK(raw_data, "input data can't be null", err, ESP_ERR_INVALID_ARG);
125     nec_parser->buffer = raw_data;
126     // Data Frame costs 34 items and Repeat Frame costs 2 items
127     if (length == NEC_DATA_FRAME_RMT_WORDS) {
128         nec_parser->repeat = false;
129     } else if (length == NEC_REPEAT_FRAME_RMT_WORDS) {
130         nec_parser->repeat = true;
131     } else {
132         ret = ESP_FAIL;
133     }
134     return ret;
135 err:
136     return ret;
137 }
138 
nec_parser_get_scan_code(ir_parser_t * parser,uint32_t * address,uint32_t * command,bool * repeat)139 static esp_err_t nec_parser_get_scan_code(ir_parser_t *parser, uint32_t *address, uint32_t *command, bool *repeat)
140 {
141     esp_err_t ret = ESP_FAIL;
142     uint32_t addr = 0;
143     uint32_t cmd = 0;
144     bool logic_value = false;
145     nec_parser_t *nec_parser = __containerof(parser, nec_parser_t, parent);
146     NEC_CHECK(address && command && repeat, "address, command and repeat can't be null", out, ESP_ERR_INVALID_ARG);
147     if (nec_parser->repeat) {
148         if (nec_parse_repeat_frame(nec_parser)) {
149             *address = nec_parser->last_address;
150             *command = nec_parser->last_command;
151             *repeat = true;
152             ret = ESP_OK;
153         }
154     } else {
155         if (nec_parse_head(nec_parser)) {
156             for (int i = 0; i < 16; i++) {
157                 if (nec_parse_logic(parser, &logic_value) == ESP_OK) {
158                     addr |= (logic_value << i);
159                 }
160             }
161             for (int i = 0; i < 16; i++) {
162                 if (nec_parse_logic(parser, &logic_value) == ESP_OK) {
163                     cmd |= (logic_value << i);
164                 }
165             }
166             *address = addr;
167             *command = cmd;
168             *repeat = false;
169             // keep it as potential repeat code
170             nec_parser->last_address = addr;
171             nec_parser->last_command = cmd;
172             ret = ESP_OK;
173         }
174     }
175 out:
176     return ret;
177 }
178 
nec_parser_del(ir_parser_t * parser)179 static esp_err_t nec_parser_del(ir_parser_t *parser)
180 {
181     nec_parser_t *nec_parser = __containerof(parser, nec_parser_t, parent);
182     free(nec_parser);
183     return ESP_OK;
184 }
185 
ir_parser_rmt_new_nec(const ir_parser_config_t * config)186 ir_parser_t *ir_parser_rmt_new_nec(const ir_parser_config_t *config)
187 {
188     ir_parser_t *ret = NULL;
189     NEC_CHECK(config, "nec configuration can't be null", err, NULL);
190 
191     nec_parser_t *nec_parser = calloc(1, sizeof(nec_parser_t));
192     NEC_CHECK(nec_parser, "request memory for nec_parser failed", err, NULL);
193 
194     nec_parser->flags = config->flags;
195     if (config->flags & IR_TOOLS_FLAGS_INVERSE) {
196         nec_parser->inverse = true;
197     }
198 
199     uint32_t counter_clk_hz = 0;
200     NEC_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev_hdl, &counter_clk_hz) == ESP_OK,
201               "get rmt counter clock failed", err, NULL);
202     float ratio = (float)counter_clk_hz / 1e6;
203     nec_parser->leading_code_high_ticks = (uint32_t)(ratio * NEC_LEADING_CODE_HIGH_US);
204     nec_parser->leading_code_low_ticks = (uint32_t)(ratio * NEC_LEADING_CODE_LOW_US);
205     nec_parser->repeat_code_high_ticks = (uint32_t)(ratio * NEC_REPEAT_CODE_HIGH_US);
206     nec_parser->repeat_code_low_ticks = (uint32_t)(ratio * NEC_REPEAT_CODE_LOW_US);
207     nec_parser->payload_logic0_high_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ZERO_HIGH_US);
208     nec_parser->payload_logic0_low_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ZERO_LOW_US);
209     nec_parser->payload_logic1_high_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ONE_HIGH_US);
210     nec_parser->payload_logic1_low_ticks = (uint32_t)(ratio * NEC_PAYLOAD_ONE_LOW_US);
211     nec_parser->margin_ticks = (uint32_t)(ratio * config->margin_us);
212     nec_parser->parent.input = nec_parser_input;
213     nec_parser->parent.get_scan_code = nec_parser_get_scan_code;
214     nec_parser->parent.del = nec_parser_del;
215     return &nec_parser->parent;
216 err:
217     return ret;
218 }
219