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