1 // RMT driver unit test is based on extended NEC protocol
2 #include <stdio.h>
3 #include <string.h>
4 #include "sdkconfig.h"
5 #include "hal/cpu_hal.h"
6 #include "hal/gpio_hal.h"
7 #include "freertos/FreeRTOS.h"
8 #include "freertos/task.h"
9 #include "esp_log.h"
10 #include "driver/rmt.h"
11 #include "ir_tools.h"
12 #include "unity.h"
13 #include "test_utils.h"
14 #include "esp_rom_gpio.h"
15
16 #define RMT_RX_CHANNEL_ENCODING_START (SOC_RMT_CHANNELS_NUM-SOC_RMT_TX_CHANNELS_NUM)
17 #define RMT_TX_CHANNEL_ENCODING_END (SOC_RMT_TX_CHANNELS_NUM-1)
18
19 // CI ONLY: Don't connect any other signals to this GPIO
20 #define RMT_DATA_IO (4) // bind signal RMT_SIG_OUT0_IDX and RMT_SIG_IN0_IDX on the same GPIO
21
22 #define RMT_TESTBENCH_FLAGS_ALWAYS_ON (1<<0)
23 #define RMT_TESTBENCH_FLAGS_CARRIER_ON (1<<1)
24 #define RMT_TESTBENCH_FLAGS_LOOP_ON (1<<2)
25
26 static const char *TAG = "RMT.test";
27 static ir_builder_t *s_ir_builder = NULL;
28 static ir_parser_t *s_ir_parser = NULL;
29
rmt_setup_testbench(int tx_channel,int rx_channel,uint32_t flags)30 static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
31 {
32 // RMT channel configuration
33 if (tx_channel >= 0) {
34 rmt_config_t tx_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, tx_channel);
35 if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
36 tx_config.flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
37 }
38 if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
39 tx_config.tx_config.carrier_en = true;
40 }
41 #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
42 if (flags & RMT_TESTBENCH_FLAGS_LOOP_ON) {
43 tx_config.tx_config.loop_en = true;
44 tx_config.tx_config.loop_count = 10;
45 }
46 #endif
47 TEST_ESP_OK(rmt_config(&tx_config));
48 }
49
50 if (rx_channel >= 0) {
51 rmt_config_t rx_config = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, rx_channel);
52 if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
53 rx_config.flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
54 }
55 #if SOC_RMT_SUPPORT_RX_DEMODULATION
56 if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
57 rx_config.rx_config.rm_carrier = true;
58 rx_config.rx_config.carrier_freq_hz = 38000;
59 rx_config.rx_config.carrier_duty_percent = 33;
60 rx_config.rx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
61 }
62 #endif
63 TEST_ESP_OK(rmt_config(&rx_config));
64 }
65
66 // Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO)
67 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
68 TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT));
69 esp_rom_gpio_connect_out_signal(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0);
70 esp_rom_gpio_connect_in_signal(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0);
71
72 // install driver
73 if (tx_channel >= 0) {
74 TEST_ESP_OK(rmt_driver_install(tx_channel, 0, 0));
75
76 ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
77 ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
78 s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
79 TEST_ASSERT_NOT_NULL(s_ir_builder);
80 }
81
82 if (rx_channel >= 0) {
83 TEST_ESP_OK(rmt_driver_install(rx_channel, 3000, 0));
84
85 ir_parser_config_t ir_parser_config = IR_PARSER_DEFAULT_CONFIG((ir_dev_t)rx_channel);
86 ir_parser_config.flags = IR_TOOLS_FLAGS_PROTO_EXT | IR_TOOLS_FLAGS_INVERSE;
87 s_ir_parser = ir_parser_rmt_new_nec(&ir_parser_config);
88 TEST_ASSERT_NOT_NULL(s_ir_parser);
89 }
90 }
91
rmt_clean_testbench(int tx_channel,int rx_channel)92 static void rmt_clean_testbench(int tx_channel, int rx_channel)
93 {
94 if (tx_channel >= 0) {
95 TEST_ESP_OK(rmt_driver_uninstall(tx_channel));
96 TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
97 s_ir_builder = NULL;
98 }
99
100 if (rx_channel >= 0) {
101 TEST_ESP_OK(rmt_driver_uninstall(rx_channel));
102 TEST_ESP_OK(s_ir_parser->del(s_ir_parser));
103 s_ir_parser = NULL;
104 }
105 }
106
107 TEST_CASE("RMT wrong configuration", "[rmt]")
108 {
109 rmt_config_t correct_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
110 rmt_config_t wrong_config = correct_config;
111
112 wrong_config.clk_div = 0;
113 TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
114
115 wrong_config = correct_config;
116 wrong_config.channel = SOC_RMT_CHANNELS_NUM;
117 TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
118
119 wrong_config = correct_config;
120 wrong_config.channel = 2;
121 wrong_config.mem_block_num = 8;
122 TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
123 TEST_ASSERT(rmt_set_mem_block_num(wrong_config.channel, -1) == ESP_ERR_INVALID_ARG);
124 }
125
126 TEST_CASE("RMT miscellaneous functions", "[rmt]")
127 {
128 rmt_channel_t channel = 0;
129 uint8_t div_cnt;
130 rmt_source_clk_t src_clk;
131 uint8_t memNum;
132 uint16_t idle_thres;
133 rmt_mem_owner_t owner;
134
135 // TX related functions
136 rmt_setup_testbench(channel, -1, 0);
137
138 TEST_ESP_OK(rmt_set_mem_block_num(channel, 2));
139 TEST_ESP_OK(rmt_get_mem_block_num(channel, &memNum));
140 TEST_ASSERT_EQUAL_UINT8(2, memNum);
141
142 TEST_ESP_OK(rmt_set_clk_div(channel, 160));
143 TEST_ESP_OK(rmt_get_clk_div(channel, &div_cnt));
144 TEST_ASSERT_EQUAL_UINT8(160, div_cnt);
145
146 #if SOC_RMT_SUPPORT_REF_TICK
147 TEST_ESP_OK(rmt_set_source_clk(channel, RMT_BASECLK_REF));
148 TEST_ESP_OK(rmt_get_source_clk(channel, &src_clk));
149 TEST_ASSERT_EQUAL_INT(RMT_BASECLK_REF, src_clk);
150 #endif
151
152 #if SOC_RMT_SUPPORT_XTAL
153 TEST_ESP_OK(rmt_set_source_clk(channel, RMT_BASECLK_XTAL));
154 TEST_ESP_OK(rmt_get_source_clk(channel, &src_clk));
155 TEST_ASSERT_EQUAL_INT(RMT_BASECLK_XTAL, src_clk);
156 #endif
157
158
159 TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 1, 0, 1));
160 TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0));
161
162 rmt_clean_testbench(channel, -1);
163
164 // RX related functions
165 channel = RMT_RX_CHANNEL_ENCODING_START;
166 rmt_setup_testbench(-1, channel, 0);
167
168 TEST_ESP_OK(rmt_set_rx_idle_thresh(channel, 200));
169 TEST_ESP_OK(rmt_get_rx_idle_thresh(channel, &idle_thres));
170 TEST_ASSERT_EQUAL_UINT16(200, idle_thres);
171
172 TEST_ESP_OK(rmt_set_rx_filter(channel, 1, 100));
173
174 TEST_ESP_OK(rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX));
175 TEST_ESP_OK(rmt_get_memory_owner(channel, &owner));
176 TEST_ASSERT_EQUAL_INT(RMT_MEM_OWNER_RX, owner);
177
178 rmt_clean_testbench(-1, channel);
179 }
180
181 TEST_CASE("RMT multiple channels", "[rmt]")
182 {
183 rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
184 for (int i = 0; i < SOC_RMT_TX_CHANNELS_NUM; i++) {
185 tx_cfg.channel = i;
186 TEST_ESP_OK(rmt_config(&tx_cfg));
187 TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 0, 0));
188 }
189
190 for (int i = 0; i < SOC_RMT_TX_CHANNELS_NUM; i++) {
191 TEST_ESP_OK(rmt_driver_uninstall(i));
192 }
193
194 rmt_config_t rx_cfg = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, RMT_RX_CHANNEL_ENCODING_START);
195 for (int i = RMT_RX_CHANNEL_ENCODING_START; i < SOC_RMT_CHANNELS_NUM; i++) {
196 rx_cfg.channel = i;
197 TEST_ESP_OK(rmt_config(&rx_cfg));
198 TEST_ESP_OK(rmt_driver_install(rx_cfg.channel, 0, 0));
199 }
200
201 for (int i = RMT_RX_CHANNEL_ENCODING_START; i < SOC_RMT_CHANNELS_NUM; i++) {
202 TEST_ESP_OK(rmt_driver_uninstall(i));
203 }
204 }
205
206 TEST_CASE("RMT install/uninstall test", "[rmt]")
207 {
208 rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, RMT_TX_CHANNEL_ENCODING_END);
209 TEST_ESP_OK(rmt_config(&tx_cfg));
210 for (int i = 0; i < 100; i++) {
211 TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 1000, 0));
212 TEST_ESP_OK(rmt_driver_uninstall(tx_cfg.channel));
213 }
214 rmt_config_t rx_cfg = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, RMT_RX_CHANNEL_ENCODING_START);
215 TEST_ESP_OK(rmt_config(&rx_cfg));
216 for (int i = 0; i < 100; i++) {
217 TEST_ESP_OK(rmt_driver_install(rx_cfg.channel, 1000, 0));
218 TEST_ESP_OK(rmt_driver_uninstall(rx_cfg.channel));
219 }
220 }
221
test_rmt_translator(const void * src,rmt_item32_t * dest,size_t src_size,size_t wanted_num,size_t * translated_size,size_t * item_num)222 static void test_rmt_translator(const void *src, rmt_item32_t *dest, size_t src_size,
223 size_t wanted_num, size_t *translated_size, size_t *item_num)
224 {
225 const rmt_item32_t bit0 = {{{ 10, 1, 20, 0 }}}; //Logical 0
226 const rmt_item32_t bit1 = {{{ 20, 1, 10, 0 }}}; //Logical 1
227 size_t size = 0;
228 size_t num = 0;
229 uint8_t *psrc = (uint8_t *)src;
230 rmt_item32_t *pdest = dest;
231 while (size < src_size && num < wanted_num) {
232 for (int i = 0; i < 8; i++) {
233 // MSB first
234 if (*psrc & (1 << (7 - i))) {
235 pdest->val = bit1.val;
236 } else {
237 pdest->val = bit0.val;
238 }
239 num++;
240 pdest++;
241 }
242 size++;
243 psrc++;
244 }
245 *translated_size = size;
246 *item_num = num;
247 int *user_data = NULL;
248 rmt_translator_get_context(item_num, (void **)&user_data);
249 esp_rom_printf("user data=%d\r\n", *user_data);
250 *user_data = 100;
251 }
252
253 TEST_CASE("RMT translator with user context", "[rmt]")
254 {
255 rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
256 TEST_ESP_OK(rmt_config(&tx_cfg));
257 TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 0, 0));
258 rmt_translator_init(tx_cfg.channel, test_rmt_translator);
259 int user_data = 999;
260 rmt_translator_set_context(tx_cfg.channel, &user_data);
261 uint8_t test_buf[] = {1, 2, 3, 4, 5, 6};
262 rmt_write_sample(tx_cfg.channel, test_buf, sizeof(test_buf), true);
263 vTaskDelay(pdMS_TO_TICKS(100));
264 TEST_ASSERT_EQUAL(100, user_data);
265 TEST_ESP_OK(rmt_driver_uninstall(tx_cfg.channel));
266 }
267
do_nec_tx_rx(uint32_t flags)268 static void do_nec_tx_rx(uint32_t flags)
269 {
270 RingbufHandle_t rb = NULL;
271 rmt_item32_t *items = NULL;
272 size_t length = 0;
273 uint32_t addr = 0x10;
274 uint32_t cmd = 0x20;
275 bool repeat = false;
276 int tx_channel = 0;
277 int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
278
279 // test on different flags combinations
280 rmt_setup_testbench(tx_channel, rx_channel, flags);
281
282 // get ready to receive
283 TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
284 TEST_ASSERT_NOT_NULL(rb);
285 TEST_ESP_OK(rmt_rx_start(rx_channel, true));
286
287 vTaskDelay(pdMS_TO_TICKS(1000));
288
289 // build NEC codes
290 cmd = 0x20;
291 while (cmd <= 0x30) {
292 ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
293 // Send new key code
294 TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
295 TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
296 if (cmd & 0x01) {
297 TEST_ESP_OK(rmt_write_items(tx_channel, items, length, false)); // no wait
298 TEST_ESP_OK(rmt_wait_tx_done(tx_channel, portMAX_DELAY));
299 } else {
300 TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
301 }
302 cmd++;
303 }
304
305 // parse NEC codes
306 while (rb) {
307 items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
308 if (items) {
309 length /= 4; // one RMT = 4 Bytes
310 if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
311 if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
312 ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
313 }
314 }
315 vRingbufferReturnItem(rb, (void *) items);
316 } else {
317 ESP_LOGI(TAG, "done");
318 break;
319 }
320 }
321
322 TEST_ASSERT_EQUAL(0x30, cmd);
323 rmt_clean_testbench(tx_channel, rx_channel);
324 }
325
326 // basic nec tx and rx test, using APB source clock, no modulation
327 TEST_CASE("RMT NEC TX and RX (APB)", "[rmt]")
328 {
329 do_nec_tx_rx(0);
330 }
331
332 // test with RMT_TESTBENCH_FLAGS_ALWAYS_ON will take a long time (REF_TICK is much slower than APB CLOCK)
333 TEST_CASE("RMT NEC TX and RX (always on)", "[rmt][timeout=240]")
334 {
335 do_nec_tx_rx(RMT_TESTBENCH_FLAGS_ALWAYS_ON);
336 }
337
338 #if SOC_RMT_SUPPORT_RX_DEMODULATION
339 // basic nec tx and rx test, using APB source clock, with modulation and demodulation on
340 TEST_CASE("RMT NEC TX and RX (Modulation/Demodulation)", "[rmt]")
341 {
342 do_nec_tx_rx(RMT_TESTBENCH_FLAGS_CARRIER_ON);
343 }
344 #endif
345
346 TEST_CASE("RMT TX (SOC_RMT_CHANNEL_MEM_WORDS-1) symbols", "[rmt][boundary]")
347 {
348 int tx_channel = 0;
349 rmt_setup_testbench(tx_channel, -1, 0);
350 rmt_item32_t *items = malloc(sizeof(rmt_item32_t) * (SOC_RMT_CHANNEL_MEM_WORDS - 1));
351 for (int i = 0; i < SOC_RMT_CHANNEL_MEM_WORDS - 1; i++) {
352 items[i] = (rmt_item32_t) {
353 {{
354 200, 1, 200, 0
355 }
356 }
357 };
358 }
359 TEST_ESP_OK(rmt_write_items(tx_channel, items, SOC_RMT_CHANNEL_MEM_WORDS - 1, 1));
360 free(items);
361 rmt_clean_testbench(tx_channel, -1);
362 }
363
364 TEST_CASE("RMT TX stop", "[rmt]")
365 {
366 RingbufHandle_t rb = NULL;
367 rmt_item32_t *frames = NULL;
368 size_t length = 0;
369 uint32_t count = 10;
370 uint32_t addr = 0x10;
371 uint32_t cmd = 0x20;
372 bool repeat = false;
373 int tx_channel = 0;
374 int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
375
376 rmt_setup_testbench(tx_channel, rx_channel, 0);
377
378 // re-install ir_builder, to enlarge internal buffer size
379 TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
380 ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
381 ir_builder_config.buffer_size *= count;
382 ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
383 s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
384 TEST_ASSERT_NOT_NULL(s_ir_builder);
385
386 // get ready to receive
387 TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
388 TEST_ASSERT_NOT_NULL(rb);
389 TEST_ESP_OK(rmt_rx_start(rx_channel, true));
390
391 vTaskDelay(pdMS_TO_TICKS(1000));
392
393 // build NEC codes
394 ESP_LOGI(TAG, "Plan to send command 0x%x~0x%x to address 0x%x", cmd, cmd + count, addr);
395 for (int i = 0; i <= count; i++) {
396 TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
397 cmd++;
398 }
399 TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &frames, &length));
400
401 // send for 1 second and then stop
402 TEST_ESP_OK(rmt_write_items(tx_channel, frames, length, true));
403 vTaskDelay(pdMS_TO_TICKS(100));
404 TEST_ESP_OK(rmt_tx_stop(tx_channel));
405
406 // parse NEC codes
407 uint32_t num = 0;
408 while (rb) {
409 frames = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
410 if (frames) {
411 length /= 4; // one RMT = 4 Bytes
412 if (s_ir_parser->input(s_ir_parser, frames, length) == ESP_OK) {
413 if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
414 ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
415 num++;
416 }
417 }
418 vRingbufferReturnItem(rb, (void *) frames);
419 } else {
420 ESP_LOGI(TAG, "done");
421 break;
422 }
423 }
424
425 TEST_ASSERT(num < count);
426 rmt_clean_testbench(tx_channel, rx_channel);
427 }
428
429 #if SOC_RMT_SUPPORT_RX_PINGPONG
430 TEST_CASE("RMT Ping-Pong operation", "[rmt]")
431 {
432 int tx_channel = 0;
433 int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
434 rmt_item32_t frames[SOC_RMT_CHANNEL_MEM_WORDS * 2]; // send two block data using ping-pong
435 RingbufHandle_t rb = NULL;
436 uint32_t size = sizeof(frames) / sizeof(frames[0]);
437
438 // The design of the following test frame should trigger three rx threshold interrupt and one rx end interrupt
439 int i = 0;
440 for (i = 0; i < size - 1; i++) {
441 frames[i].level0 = 1;
442 frames[i].duration0 = 100;
443 frames[i].level1 = 0;
444 frames[i].duration1 = 100;
445 }
446 frames[i].level0 = 1;
447 frames[i].duration0 = 0;
448 frames[i].level1 = 0;
449 frames[i].duration1 = 0;
450
451 rmt_setup_testbench(tx_channel, rx_channel, 0);
452
453 // get ready to receive
454 TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
455 TEST_ASSERT_NOT_NULL(rb);
456 TEST_ESP_OK(rmt_rx_start(rx_channel, true));
457
458 vTaskDelay(pdMS_TO_TICKS(1000));
459
460 for (uint32_t test_count = 0; test_count < 5; test_count++) {
461 TEST_ESP_OK(rmt_write_items(tx_channel, frames, size, true));
462
463 // parse received data
464 size_t length = 0;
465 rmt_item32_t *items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
466 if (items) {
467 vRingbufferReturnItem(rb, (void *) items);
468 }
469 TEST_ASSERT_EQUAL(4 * (size - 1), length);
470 }
471
472 rmt_clean_testbench(tx_channel, rx_channel);
473 }
474 #endif
475 #if SOC_RMT_SUPPORT_TX_GROUP
476 static uint32_t tx_end_time0, tx_end_time1;
rmt_tx_end_cb(rmt_channel_t channel,void * arg)477 static void rmt_tx_end_cb(rmt_channel_t channel, void *arg)
478 {
479 if (channel == 0) {
480 tx_end_time0 = cpu_hal_get_cycle_count();
481 } else {
482 tx_end_time1 = cpu_hal_get_cycle_count();
483 }
484 }
485 TEST_CASE("RMT TX simultaneously", "[rmt]")
486 {
487 rmt_item32_t frames[SOC_RMT_CHANNEL_MEM_WORDS];
488 uint32_t size = sizeof(frames) / sizeof(frames[0]);
489 int channel0 = 0;
490 int channel1 = 1;
491
492 int i = 0;
493 for (i = 0; i < size - 1; i++) {
494 frames[i].level0 = 1;
495 frames[i].duration0 = 1000;
496 frames[i].level1 = 0;
497 frames[i].duration1 = 1000;
498 }
499 frames[i].level0 = 0;
500 frames[i].duration0 = 0;
501 frames[i].level1 = 0;
502 frames[i].duration1 = 0;
503
504 rmt_config_t tx_config0 = RMT_DEFAULT_CONFIG_TX(4, channel0);
505 rmt_config_t tx_config1 = RMT_DEFAULT_CONFIG_TX(5, channel1);
506 TEST_ESP_OK(rmt_config(&tx_config0));
507 TEST_ESP_OK(rmt_config(&tx_config1));
508
509 TEST_ESP_OK(rmt_driver_install(channel0, 0, 0));
510 TEST_ESP_OK(rmt_driver_install(channel1, 0, 0));
511
512 rmt_register_tx_end_callback(rmt_tx_end_cb, NULL);
513
514 TEST_ESP_OK(rmt_add_channel_to_group(channel0));
515 TEST_ESP_OK(rmt_add_channel_to_group(channel1));
516
517 TEST_ESP_OK(rmt_write_items(channel0, frames, size, false));
518 vTaskDelay(pdMS_TO_TICKS(1000));
519 TEST_ESP_OK(rmt_write_items(channel1, frames, size, false));
520
521 TEST_ESP_OK(rmt_wait_tx_done(channel0, portMAX_DELAY));
522 TEST_ESP_OK(rmt_wait_tx_done(channel1, portMAX_DELAY));
523
524 ESP_LOGI(TAG, "tx_end_time0=%u, tx_end_time1=%u", tx_end_time0, tx_end_time1);
525 TEST_ASSERT_LESS_OR_EQUAL_UINT32(2000, tx_end_time1 - tx_end_time0);
526
527 TEST_ESP_OK(rmt_remove_channel_from_group(channel0));
528 TEST_ESP_OK(rmt_remove_channel_from_group(channel1));
529
530 TEST_ESP_OK(rmt_driver_uninstall(channel0));
531 TEST_ESP_OK(rmt_driver_uninstall(channel1));
532
533 }
534 #endif
535
536 #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
rmt_tx_loop_end(rmt_channel_t channel,void * arg)537 static void rmt_tx_loop_end(rmt_channel_t channel, void *arg)
538 {
539 rmt_tx_stop(channel);
540 }
541 TEST_CASE("RMT TX loop", "[rmt]")
542 {
543 RingbufHandle_t rb = NULL;
544 rmt_item32_t *items = NULL;
545 size_t length = 0;
546 uint32_t addr = 0x10;
547 uint32_t cmd = 0x20;
548 bool repeat = false;
549 int tx_channel = 0;
550 int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
551 uint32_t count = 0;
552
553 rmt_setup_testbench(tx_channel, rx_channel, RMT_TESTBENCH_FLAGS_LOOP_ON);
554
555 // get ready to receive
556 TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
557 TEST_ASSERT_NOT_NULL(rb);
558 TEST_ESP_OK(rmt_rx_start(rx_channel, true));
559
560 vTaskDelay(pdMS_TO_TICKS(1000));
561
562 // register callback functions, invoked when tx loop count to ceiling
563 rmt_register_tx_end_callback(rmt_tx_loop_end, NULL);
564 // build NEC codes
565 ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
566 // Send new key code
567 TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
568 TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
569 TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
570
571 // parse NEC codes
572 while (rb) {
573 items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
574 if (items) {
575 length /= 4; // one RMT = 4 Bytes
576 if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
577 if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
578 count++;
579 ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
580 }
581 }
582 vRingbufferReturnItem(rb, (void *) items);
583 } else {
584 ESP_LOGI(TAG, "done");
585 break;
586 }
587 }
588
589 TEST_ASSERT_EQUAL(10, count);
590 rmt_clean_testbench(tx_channel, rx_channel);
591 }
592 #endif
593