test_rmt.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. // RMT driver unit test is based on extended NEC protocol
  7. // Please don't use channel number: SOC_RMT_CHANNELS_NUM - 1
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "sdkconfig.h"
  11. #include "freertos/FreeRTOS.h"
  12. #include "freertos/task.h"
  13. #include "esp_log.h"
  14. #include "driver/rmt.h"
  15. #include "ir_tools.h"
  16. #include "unity.h"
  17. #include "test_utils.h"
  18. // CI ONLY: Don't connect any other signals to this GPIO
  19. #define RMT_DATA_IO (0) // bind signal RMT_SIG_OUT0_IDX and RMT_SIG_IN0_IDX on the same GPIO
  20. #define RMT_TESTBENCH_FLAGS_ALWAYS_ON (1<<0)
  21. #define RMT_TESTBENCH_FLAGS_CARRIER_ON (1<<1)
  22. #define RMT_TESTBENCH_FLAGS_LOOP_ON (1<<2)
  23. static const char *TAG = "RMT.test";
  24. static ir_builder_t *s_ir_builder = NULL;
  25. static ir_parser_t *s_ir_parser = NULL;
  26. static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
  27. {
  28. // RMT channel configuration
  29. if (tx_channel >= 0) {
  30. rmt_config_t tx_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, tx_channel);
  31. if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
  32. tx_config.flags |= RMT_CHANNEL_FLAGS_ALWAYS_ON;
  33. }
  34. if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
  35. tx_config.tx_config.carrier_en = true;
  36. }
  37. #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
  38. if (flags & RMT_TESTBENCH_FLAGS_LOOP_ON) {
  39. tx_config.tx_config.loop_en = true;
  40. tx_config.tx_config.loop_count = 10;
  41. }
  42. #endif
  43. TEST_ESP_OK(rmt_config(&tx_config));
  44. }
  45. if (rx_channel >= 0) {
  46. rmt_config_t rx_config = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, rx_channel);
  47. if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
  48. rx_config.flags |= RMT_CHANNEL_FLAGS_ALWAYS_ON;
  49. }
  50. #if SOC_RMT_SUPPORT_RX_DEMODULATION
  51. if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
  52. rx_config.rx_config.rm_carrier = true;
  53. rx_config.rx_config.carrier_freq_hz = 38000;
  54. rx_config.rx_config.carrier_duty_percent = 33;
  55. rx_config.rx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
  56. }
  57. #endif
  58. TEST_ESP_OK(rmt_config(&rx_config));
  59. }
  60. // Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO)
  61. PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
  62. TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT));
  63. gpio_matrix_out(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0);
  64. gpio_matrix_in(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0);
  65. // install driver
  66. if (tx_channel >= 0) {
  67. TEST_ESP_OK(rmt_driver_install(tx_channel, 0, 0));
  68. ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
  69. ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
  70. s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
  71. TEST_ASSERT_NOT_NULL(s_ir_builder);
  72. }
  73. if (rx_channel >= 0) {
  74. TEST_ESP_OK(rmt_driver_install(rx_channel, 3000, 0));
  75. ir_parser_config_t ir_parser_config = IR_PARSER_DEFAULT_CONFIG((ir_dev_t)rx_channel);
  76. ir_parser_config.flags = IR_TOOLS_FLAGS_PROTO_EXT | IR_TOOLS_FLAGS_INVERSE;
  77. s_ir_parser = ir_parser_rmt_new_nec(&ir_parser_config);
  78. TEST_ASSERT_NOT_NULL(s_ir_parser);
  79. }
  80. }
  81. static void rmt_clean_testbench(int tx_channel, int rx_channel)
  82. {
  83. if (tx_channel >= 0) {
  84. TEST_ESP_OK(rmt_driver_uninstall(tx_channel));
  85. TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
  86. s_ir_builder = NULL;
  87. }
  88. if (rx_channel >= 0) {
  89. TEST_ESP_OK(rmt_driver_uninstall(rx_channel));
  90. TEST_ESP_OK(s_ir_parser->del(s_ir_parser));
  91. s_ir_parser = NULL;
  92. }
  93. }
  94. TEST_CASE("RMT wrong configuration", "[rmt][error]")
  95. {
  96. rmt_config_t correct_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
  97. rmt_config_t wrong_config = correct_config;
  98. wrong_config.clk_div = 0;
  99. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  100. wrong_config = correct_config;
  101. wrong_config.channel = SOC_RMT_CHANNELS_NUM;
  102. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  103. wrong_config = correct_config;
  104. wrong_config.channel = 2;
  105. wrong_config.mem_block_num = 8;
  106. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  107. TEST_ASSERT(rmt_set_mem_block_num(wrong_config.channel, -1) == ESP_ERR_INVALID_ARG);
  108. }
  109. TEST_CASE("RMT miscellaneous functions", "[rmt]")
  110. {
  111. rmt_channel_t channel = SOC_RMT_CHANNELS_NUM - 2;
  112. uint8_t div_cnt;
  113. rmt_source_clk_t src_clk;
  114. uint8_t memNum;
  115. uint16_t idle_thres;
  116. rmt_mem_owner_t owner;
  117. // TX related functions
  118. rmt_setup_testbench(channel, -1, 0);
  119. TEST_ESP_OK(rmt_set_mem_block_num(channel, 2));
  120. TEST_ESP_OK(rmt_get_mem_block_num(channel, &memNum));
  121. TEST_ASSERT_EQUAL_UINT8(2, memNum);
  122. TEST_ESP_OK(rmt_set_clk_div(channel, 160));
  123. TEST_ESP_OK(rmt_get_clk_div(channel, &div_cnt));
  124. TEST_ASSERT_EQUAL_UINT8(160, div_cnt);
  125. TEST_ESP_OK(rmt_set_source_clk(channel, RMT_BASECLK_REF));
  126. TEST_ESP_OK(rmt_get_source_clk(channel, &src_clk));
  127. TEST_ASSERT_EQUAL_INT(RMT_BASECLK_REF, src_clk);
  128. TEST_ESP_OK(rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX));
  129. TEST_ESP_OK(rmt_get_memory_owner(channel, &owner));
  130. TEST_ASSERT_EQUAL_INT(RMT_MEM_OWNER_RX, owner);
  131. TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 1, 0, 1));
  132. TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0));
  133. rmt_clean_testbench(channel, -1);
  134. // RX related functions
  135. rmt_setup_testbench(-1, channel, 0);
  136. TEST_ESP_OK(rmt_set_rx_idle_thresh(channel, 200));
  137. TEST_ESP_OK(rmt_get_rx_idle_thresh(channel, &idle_thres));
  138. TEST_ASSERT_EQUAL_UINT16(200, idle_thres);
  139. TEST_ESP_OK(rmt_set_rx_filter(channel, 1, 100));
  140. rmt_clean_testbench(-1, channel);
  141. }
  142. TEST_CASE("RMT multiple channels", "[rmt]")
  143. {
  144. rmt_config_t tx_cfg1 = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
  145. TEST_ESP_OK(rmt_config(&tx_cfg1));
  146. TEST_ESP_OK(rmt_driver_install(tx_cfg1.channel, 0, 0));
  147. rmt_config_t tx_cfg2 = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 1);
  148. TEST_ESP_OK(rmt_config(&tx_cfg2));
  149. TEST_ESP_OK(rmt_driver_install(tx_cfg2.channel, 0, 0));
  150. rmt_config_t tx_cfg3 = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 2);
  151. TEST_ESP_OK(rmt_config(&tx_cfg3));
  152. TEST_ESP_OK(rmt_driver_install(tx_cfg3.channel, 0, 0));
  153. TEST_ESP_OK(rmt_driver_uninstall(2));
  154. TEST_ESP_OK(rmt_driver_uninstall(1));
  155. TEST_ESP_OK(rmt_driver_uninstall(0));
  156. }
  157. TEST_CASE("RMT install/uninstall test", "[rmt][pressure]")
  158. {
  159. rmt_config_t rx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, SOC_RMT_CHANNELS_NUM - 2);
  160. TEST_ESP_OK(rmt_config(&rx_cfg));
  161. for (int i = 0; i < 100; i++) {
  162. TEST_ESP_OK(rmt_driver_install(rx_cfg.channel, 1000, 0));
  163. TEST_ESP_OK(rmt_driver_uninstall(rx_cfg.channel));
  164. }
  165. }
  166. static void do_nec_tx_rx(uint32_t flags)
  167. {
  168. RingbufHandle_t rb = NULL;
  169. rmt_item32_t *items = NULL;
  170. uint32_t length = 0;
  171. uint32_t addr = 0x10;
  172. uint32_t cmd = 0x20;
  173. bool repeat = false;
  174. int tx_channel = 0;
  175. int rx_channel = 1;
  176. // test on different flags combinations
  177. rmt_setup_testbench(tx_channel, rx_channel, flags);
  178. // get ready to receive
  179. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  180. TEST_ASSERT_NOT_NULL(rb);
  181. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  182. vTaskDelay(pdMS_TO_TICKS(1000));
  183. // build NEC codes
  184. cmd = 0x20;
  185. while (cmd <= 0x30) {
  186. ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
  187. // Send new key code
  188. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  189. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
  190. if (cmd & 0x01) {
  191. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, false)); // no wait
  192. TEST_ESP_OK(rmt_wait_tx_done(tx_channel, portMAX_DELAY));
  193. } else {
  194. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
  195. }
  196. cmd++;
  197. }
  198. // parse NEC codes
  199. while (rb) {
  200. items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  201. if (items) {
  202. length /= 4; // one RMT = 4 Bytes
  203. if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
  204. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  205. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  206. }
  207. }
  208. vRingbufferReturnItem(rb, (void *) items);
  209. } else {
  210. ESP_LOGI(TAG, "done");
  211. break;
  212. }
  213. }
  214. TEST_ASSERT_EQUAL(0x30, cmd);
  215. rmt_clean_testbench(tx_channel, rx_channel);
  216. }
  217. // basic nec tx and rx test, using APB source clock, no modulation
  218. TEST_CASE("RMT NEC TX and RX (APB)", "[rmt]")
  219. {
  220. do_nec_tx_rx(0);
  221. }
  222. // test with RMT_TESTBENCH_FLAGS_ALWAYS_ON will take a long time (REF_TICK is much slower than APB CLOCK)
  223. TEST_CASE("RMT NEC TX and RX (REF_TICK)", "[rmt][timeout=240]")
  224. {
  225. do_nec_tx_rx(RMT_TESTBENCH_FLAGS_ALWAYS_ON);
  226. }
  227. #if SOC_RMT_SUPPORT_RX_DEMODULATION
  228. // basic nec tx and rx test, using APB source clock, with modulation and demodulation on
  229. TEST_CASE("RMT NEC TX and RX (Modulation/Demodulation)", "[rmt]")
  230. {
  231. do_nec_tx_rx(RMT_TESTBENCH_FLAGS_CARRIER_ON);
  232. }
  233. #endif
  234. TEST_CASE("RMT TX (SOC_RMT_CHANNEL_MEM_WORDS-1) symbols", "[rmt][boundary]")
  235. {
  236. int tx_channel = 0;
  237. rmt_setup_testbench(tx_channel, -1, 0);
  238. rmt_item32_t *items = malloc(sizeof(rmt_item32_t) * (SOC_RMT_CHANNEL_MEM_WORDS - 1));
  239. for (int i = 0; i < SOC_RMT_CHANNEL_MEM_WORDS - 1; i++) {
  240. items[i] = (rmt_item32_t) {
  241. {{
  242. 200, 1, 200, 0
  243. }
  244. }
  245. };
  246. }
  247. TEST_ESP_OK(rmt_write_items(tx_channel, items, SOC_RMT_CHANNEL_MEM_WORDS - 1, 1));
  248. free(items);
  249. rmt_clean_testbench(tx_channel, -1);
  250. }
  251. TEST_CASE("RMT TX stop", "[rmt]")
  252. {
  253. RingbufHandle_t rb = NULL;
  254. rmt_item32_t *frames = NULL;
  255. uint32_t length = 0;
  256. uint32_t count = 10;
  257. uint32_t addr = 0x10;
  258. uint32_t cmd = 0x20;
  259. bool repeat = false;
  260. int tx_channel = 0;
  261. int rx_channel = 1;
  262. rmt_setup_testbench(tx_channel, rx_channel, 0);
  263. // re-install ir_builder, to enlarge internal buffer size
  264. TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
  265. ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
  266. ir_builder_config.buffer_size *= count;
  267. ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
  268. s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
  269. TEST_ASSERT_NOT_NULL(s_ir_builder);
  270. // get ready to receive
  271. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  272. TEST_ASSERT_NOT_NULL(rb);
  273. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  274. vTaskDelay(pdMS_TO_TICKS(1000));
  275. // build NEC codes
  276. ESP_LOGI(TAG, "Plan to send command 0x%x~0x%x to address 0x%x", cmd, cmd + count, addr);
  277. for (int i = 0; i <= count; i++) {
  278. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  279. cmd++;
  280. }
  281. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &frames, &length));
  282. // send for 1 second and then stop
  283. TEST_ESP_OK(rmt_write_items(tx_channel, frames, length, true));
  284. vTaskDelay(pdMS_TO_TICKS(100));
  285. TEST_ESP_OK(rmt_tx_stop(tx_channel));
  286. // parse NEC codes
  287. uint32_t num = 0;
  288. while (rb) {
  289. frames = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  290. if (frames) {
  291. length /= 4; // one RMT = 4 Bytes
  292. if (s_ir_parser->input(s_ir_parser, frames, length) == ESP_OK) {
  293. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  294. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  295. num++;
  296. }
  297. }
  298. vRingbufferReturnItem(rb, (void *) frames);
  299. } else {
  300. ESP_LOGI(TAG, "done");
  301. break;
  302. }
  303. }
  304. TEST_ASSERT(num < count);
  305. rmt_clean_testbench(tx_channel, rx_channel);
  306. }
  307. #if SOC_RMT_SUPPORT_RX_PINGPONG
  308. TEST_CASE("RMT Ping-Pong operation", "[rmt]")
  309. {
  310. int tx_channel = 0;
  311. int rx_channel = 1;
  312. rmt_item32_t frames[SOC_RMT_CHANNEL_MEM_WORDS * 2]; // send two block data using ping-pong
  313. RingbufHandle_t rb = NULL;
  314. uint32_t size = sizeof(frames) / sizeof(frames[0]);
  315. // The design of the following test frame should trigger three rx threshold interrupt and one rx end interrupt
  316. int i = 0;
  317. for (i = 0; i < size - 1; i++) {
  318. frames[i].level0 = 1;
  319. frames[i].duration0 = 100;
  320. frames[i].level1 = 0;
  321. frames[i].duration1 = 100;
  322. }
  323. frames[i].level0 = 1;
  324. frames[i].duration0 = 0;
  325. frames[i].level1 = 0;
  326. frames[i].duration1 = 0;
  327. rmt_setup_testbench(tx_channel, rx_channel, 0);
  328. // get ready to receive
  329. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  330. TEST_ASSERT_NOT_NULL(rb);
  331. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  332. vTaskDelay(pdMS_TO_TICKS(1000));
  333. for (uint32_t test_count = 0; test_count < 5; test_count++) {
  334. TEST_ESP_OK(rmt_write_items(tx_channel, frames, size, true));
  335. // parse received data
  336. uint32_t length = 0;
  337. rmt_item32_t *items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  338. if (items) {
  339. vRingbufferReturnItem(rb, (void *) items);
  340. }
  341. TEST_ASSERT_EQUAL(4 * (size - 1), length);
  342. }
  343. rmt_clean_testbench(tx_channel, rx_channel);
  344. }
  345. #endif
  346. #if SOC_RMT_SUPPORT_TX_GROUP
  347. static uint32_t tx_end_time0, tx_end_time1;
  348. static void rmt_tx_end_cb(rmt_channel_t channel, void *arg)
  349. {
  350. if (channel == 0) {
  351. tx_end_time0 = esp_cpu_get_ccount();
  352. } else {
  353. tx_end_time1 = esp_cpu_get_ccount();
  354. }
  355. }
  356. TEST_CASE("RMT TX simultaneously", "[rmt]")
  357. {
  358. rmt_item32_t frames[SOC_RMT_CHANNEL_MEM_WORDS];
  359. uint32_t size = sizeof(frames) / sizeof(frames[0]);
  360. int channel0 = 0;
  361. int channel1 = 1;
  362. int i = 0;
  363. for (i = 0; i < size - 1; i++) {
  364. frames[i].level0 = 1;
  365. frames[i].duration0 = 1000;
  366. frames[i].level1 = 0;
  367. frames[i].duration1 = 1000;
  368. }
  369. frames[i].level0 = 0;
  370. frames[i].duration0 = 0;
  371. frames[i].level1 = 0;
  372. frames[i].duration1 = 0;
  373. rmt_config_t tx_config0 = RMT_DEFAULT_CONFIG_TX(12, channel0);
  374. rmt_config_t tx_config1 = RMT_DEFAULT_CONFIG_TX(13, channel1);
  375. TEST_ESP_OK(rmt_config(&tx_config0));
  376. TEST_ESP_OK(rmt_config(&tx_config1));
  377. TEST_ESP_OK(rmt_driver_install(channel0, 0, 0));
  378. TEST_ESP_OK(rmt_driver_install(channel1, 0, 0));
  379. rmt_register_tx_end_callback(rmt_tx_end_cb, NULL);
  380. TEST_ESP_OK(rmt_add_channel_to_group(channel0));
  381. TEST_ESP_OK(rmt_add_channel_to_group(channel1));
  382. TEST_ESP_OK(rmt_write_items(channel0, frames, size, false));
  383. vTaskDelay(pdMS_TO_TICKS(1000));
  384. TEST_ESP_OK(rmt_write_items(channel1, frames, size, false));
  385. TEST_ESP_OK(rmt_wait_tx_done(channel0, portMAX_DELAY));
  386. TEST_ESP_OK(rmt_wait_tx_done(channel1, portMAX_DELAY));
  387. ESP_LOGI(TAG, "tx_end_time0=%u, tx_end_time1=%u", tx_end_time0, tx_end_time1);
  388. TEST_ASSERT_LESS_OR_EQUAL_UINT32(2000, tx_end_time1 - tx_end_time0);
  389. TEST_ESP_OK(rmt_remove_channel_from_group(channel0));
  390. TEST_ESP_OK(rmt_remove_channel_from_group(channel1));
  391. TEST_ESP_OK(rmt_driver_uninstall(channel0));
  392. TEST_ESP_OK(rmt_driver_uninstall(channel1));
  393. }
  394. #endif
  395. #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
  396. static void rmt_tx_loop_end(rmt_channel_t channel, void *arg)
  397. {
  398. rmt_tx_stop(channel);
  399. }
  400. TEST_CASE("RMT TX loop", "[rmt]")
  401. {
  402. RingbufHandle_t rb = NULL;
  403. rmt_item32_t *items = NULL;
  404. uint32_t length = 0;
  405. uint32_t addr = 0x10;
  406. uint32_t cmd = 0x20;
  407. bool repeat = false;
  408. int tx_channel = 0;
  409. int rx_channel = 1;
  410. uint32_t count = 0;
  411. rmt_setup_testbench(tx_channel, rx_channel, RMT_TESTBENCH_FLAGS_LOOP_ON);
  412. // get ready to receive
  413. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  414. TEST_ASSERT_NOT_NULL(rb);
  415. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  416. vTaskDelay(pdMS_TO_TICKS(1000));
  417. // register callback functions, invoked when tx loop count to ceiling
  418. rmt_register_tx_end_callback(rmt_tx_loop_end, NULL);
  419. // build NEC codes
  420. ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
  421. // Send new key code
  422. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  423. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
  424. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
  425. // parse NEC codes
  426. while (rb) {
  427. items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  428. if (items) {
  429. length /= 4; // one RMT = 4 Bytes
  430. if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
  431. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  432. count++;
  433. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  434. }
  435. }
  436. vRingbufferReturnItem(rb, (void *) items);
  437. } else {
  438. ESP_LOGI(TAG, "done");
  439. break;
  440. }
  441. }
  442. TEST_ASSERT_EQUAL(10, count);
  443. rmt_clean_testbench(tx_channel, rx_channel);
  444. }
  445. #endif