test_touch_button.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <time.h>
  10. #include "freertos/FreeRTOS.h"
  11. #include "freertos/task.h"
  12. #include "freertos/queue.h"
  13. #include "freertos/semphr.h"
  14. #include "unity.h"
  15. #include "esp_random.h"
  16. #include "touch_element/touch_element_private.h"
  17. #include "touch_element/touch_button.h"
  18. static portMUX_TYPE test_button_spinlock = portMUX_INITIALIZER_UNLOCKED;
  19. #define TEST_BUTTON_ENTER_CRITICAL() portENTER_CRITICAL(&test_button_spinlock)
  20. #define TEST_BUTTON_EXIT_CRITICAL() portEXIT_CRITICAL(&test_button_spinlock)
  21. static const touch_pad_t button_channel_array[14] = {
  22. TOUCH_PAD_NUM1,
  23. TOUCH_PAD_NUM2,
  24. TOUCH_PAD_NUM3,
  25. TOUCH_PAD_NUM4,
  26. TOUCH_PAD_NUM5,
  27. TOUCH_PAD_NUM6,
  28. TOUCH_PAD_NUM7,
  29. TOUCH_PAD_NUM8,
  30. TOUCH_PAD_NUM9,
  31. TOUCH_PAD_NUM10,
  32. TOUCH_PAD_NUM11,
  33. TOUCH_PAD_NUM12,
  34. TOUCH_PAD_NUM13,
  35. TOUCH_PAD_NUM14,
  36. };
  37. const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);
  38. typedef struct {
  39. QueueHandle_t valid_msg_handle;
  40. SemaphoreHandle_t response_sig_handle;
  41. } test_monitor_t;
  42. typedef struct {
  43. QueueHandle_t valid_msg_handle;
  44. SemaphoreHandle_t response_sig_handle;
  45. touch_button_handle_t button_handle;
  46. } test_concurrent_monitor_t;
  47. /* ------------------------------------------------------------------------------------------------------------------ */
  48. void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event);
  49. void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
  50. static void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message);
  51. void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event);
  52. void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor);
  53. /* ------------------------------------------------ Dispatch method test -------------------------------------------- */
  54. static void test_button_disp_event(void);
  55. static void test_button_disp_callback(void);
  56. void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
  57. /* ------------------------------------------------ Run-time test --------------------------------------------------- */
  58. static void test_button_event_change_lp(void);
  59. static void test_button_callback_change_lp(void);
  60. static void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
  61. /* ------------------------------------------------ Concurrent test ------------------------------------------------- */
  62. static void test_button_event_concurrent(void);
  63. static void test_button_random_trigger_concurrent(void);
  64. void test_random_trigger_concurrent_task(void *arg);
  65. static void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
  66. /* ------------------------------------------------------------------------------------------------------------------ */
  67. TEST_CASE("Touch button dispatch methods test", "[button][touch_element]")
  68. {
  69. touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
  70. TEST_ESP_OK(touch_element_install(&global_config));
  71. test_button_disp_event();
  72. test_button_disp_callback();
  73. touch_element_uninstall();
  74. }
  75. TEST_CASE("Touch button run-time test", "[button][touch_element]")
  76. {
  77. touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
  78. TEST_ESP_OK(touch_element_install(&global_config));
  79. test_button_event_change_lp();
  80. test_button_callback_change_lp();
  81. touch_element_uninstall();
  82. }
  83. TEST_CASE("Touch button concurrent test", "[button][touch_element]")
  84. {
  85. touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
  86. TEST_ESP_OK(touch_element_install(&global_config));
  87. test_button_event_concurrent();
  88. test_button_random_trigger_concurrent();
  89. touch_element_uninstall();
  90. }
  91. void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event)
  92. {
  93. te_button_handle_t te_button = (te_button_handle_t) button_handle;
  94. touch_pad_t channel = te_button->device->channel;
  95. if (button_event == TOUCH_BUTTON_EVT_ON_PRESS) {
  96. touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
  97. } else if (button_event == TOUCH_BUTTON_EVT_ON_RELEASE) {
  98. touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
  99. } else {
  100. touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT); //LongPress
  101. }
  102. }
  103. void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)
  104. {
  105. TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, "check handle failed");
  106. TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, "check element type failed");
  107. const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);
  108. const touch_button_message_t *current_button_message = touch_button_get_message(current_message);
  109. TEST_ASSERT_MESSAGE(current_button_message->event == valid_button_message->event, "check event failed");
  110. }
  111. static void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message)
  112. {
  113. const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);
  114. TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, "check handle failed");
  115. TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_BUTTON, "check element type failed");
  116. TEST_ASSERT_MESSAGE(valid_button_message->event == current_message->event, "check event failed");
  117. }
  118. void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event)
  119. {//TODO: refactor this with a constructor
  120. touch_elem_message_t valid_message = {
  121. .handle = handle,
  122. .element_type = TOUCH_ELEM_TYPE_BUTTON,
  123. .arg = NULL,
  124. };
  125. touch_button_message_t button_message = {
  126. .event = button_event
  127. };
  128. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  129. test_button_event_simulator(handle, button_event); //Trigger signal
  130. touch_elem_message_t current_message;
  131. te_button_handle_t te_button = handle;
  132. esp_err_t ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));
  133. TEST_ASSERT_MESSAGE(ret == ESP_OK, "button event receive timeout");
  134. test_button_event_check(&valid_message, &current_message); //Verification
  135. }
  136. void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor)
  137. {
  138. if (should_trigger) {
  139. touch_elem_message_t valid_message = {
  140. .handle = handle,
  141. .element_type = TOUCH_ELEM_TYPE_BUTTON,
  142. .arg = NULL
  143. };
  144. touch_button_message_t button_message = {
  145. .event = button_event
  146. };
  147. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  148. xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
  149. }
  150. test_button_event_simulator(handle, button_event); //Trigger signal
  151. te_button_handle_t te_button = handle;
  152. if (should_trigger) { //Verification
  153. BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));
  154. TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Button queue timeout");
  155. } else {
  156. BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(500));
  157. TEST_ASSERT_MESSAGE(os_ret == pdFALSE, "Button invalid trigger");
  158. }
  159. }
  160. static void test_button_disp_event(void)
  161. {
  162. touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
  163. touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  164. TEST_ESP_OK(touch_button_install(&global_config));
  165. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  166. touch_button_config_t button_config = {
  167. .channel_num = button_channel_array[i],
  168. .channel_sens = 0.1F
  169. };
  170. TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
  171. TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],
  172. TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,
  173. (void *) button_channel_array[i]));
  174. TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));
  175. TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
  176. }
  177. TEST_ESP_OK(touch_element_start());
  178. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  179. srandom((unsigned int)time(NULL));
  180. //10 times random press/longpress/release test
  181. printf("Touch button event test start\n");
  182. for (int i = 0; i < 10; i++) {
  183. printf("Touch button event test... (%d/10)\n", i + 1);
  184. touch_button_handle_t current_handle = button_handle[random() % 14];
  185. test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS);
  186. test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS);
  187. test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE);
  188. }
  189. printf("Touch button event test finish\n");
  190. TEST_ESP_OK(touch_element_stop());
  191. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  192. TEST_ESP_OK(touch_button_delete(button_handle[i]));
  193. }
  194. touch_button_uninstall();
  195. }
  196. static void test_button_disp_callback(void)
  197. {
  198. test_monitor_t monitor;
  199. touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
  200. monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
  201. monitor.response_sig_handle = xSemaphoreCreateBinary();
  202. TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
  203. touch_button_global_config_t button_init = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  204. TEST_ESP_OK(touch_button_install(&button_init));
  205. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  206. touch_button_config_t button_config = {
  207. .channel_num = button_channel_array[i],
  208. .channel_sens = 0.1F
  209. };
  210. TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
  211. TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],
  212. TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,
  213. (void *) &monitor));
  214. TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));
  215. TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_handler));
  216. TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));
  217. }
  218. TEST_ESP_OK(touch_element_start());
  219. srandom((unsigned int)time(NULL));
  220. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  221. //10 times random press/longpress/release test
  222. printf("Touch button callback test start\n");
  223. for (int i = 0; i < 10; i++) {
  224. printf("Touch button callback test... (%d/10)\n", i + 1);
  225. touch_button_handle_t current_handle = button_handle[random() % 14];
  226. test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, true, &monitor);
  227. test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS, true, &monitor);
  228. test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, true, &monitor);
  229. }
  230. printf("Touch button callback test finish\n");
  231. TEST_ESP_OK(touch_element_stop());
  232. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  233. TEST_ESP_OK(touch_button_delete(button_handle[i]));
  234. }
  235. touch_button_uninstall();
  236. vQueueDelete(monitor.valid_msg_handle);
  237. vSemaphoreDelete(monitor.response_sig_handle);
  238. }
  239. void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
  240. {
  241. test_monitor_t *monitor = (test_monitor_t *)arg;
  242. touch_elem_message_t valid_message;
  243. BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200)); //Get the valid message for the verification, 500ms timeout
  244. TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_button_handler: queue timeout");
  245. test_button_callback_check(handle, message, &valid_message);
  246. xSemaphoreGive(monitor->response_sig_handle);
  247. }
  248. static void test_button_event_change_lp(void)
  249. {
  250. touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
  251. touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  252. TEST_ESP_OK(touch_button_install(&global_config));
  253. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  254. touch_button_config_t button_config = {
  255. .channel_num = button_channel_array[i],
  256. .channel_sens = 0.1F
  257. };
  258. TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
  259. TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));
  260. TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
  261. }
  262. TEST_ESP_OK(touch_element_start());
  263. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  264. srandom((unsigned int)time(NULL));
  265. //10 times random press/longpress/release test
  266. printf("Touch button event change longtime test start\n");
  267. for (int i = 0; i < 10; i++) {
  268. printf("Touch button event change longtime test... (%d/10)\n", i + 1);
  269. esp_err_t ret;
  270. uint8_t channel_index = random() % BUTTON_CHANNEL_NUM;
  271. touch_elem_message_t valid_message = {
  272. .handle = button_handle[channel_index],
  273. .element_type = TOUCH_ELEM_TYPE_BUTTON,
  274. .arg = NULL
  275. };
  276. touch_button_message_t button_message = {
  277. .event = TOUCH_BUTTON_EVT_ON_LONGPRESS
  278. };
  279. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  280. TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 200 + (i + 1) * 50));
  281. test_button_event_simulator(valid_message.handle, button_message.event); //Trigger signal
  282. touch_elem_message_t current_message;
  283. ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(10 * 1000));
  284. TEST_ASSERT_MESSAGE(ret == ESP_OK, "button event LongPress timeout");
  285. test_button_event_check(&valid_message, &current_message); //Verification
  286. test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Release the button.
  287. }
  288. printf("Touch button event change longtime test finish\n");
  289. TEST_ESP_OK(touch_element_stop());
  290. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  291. TEST_ESP_OK(touch_button_delete(button_handle[i]));
  292. }
  293. touch_button_uninstall();
  294. }
  295. static void test_button_callback_change_lp(void)
  296. {
  297. test_monitor_t monitor;
  298. touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
  299. monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
  300. monitor.response_sig_handle = xSemaphoreCreateBinary();
  301. TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
  302. touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  303. TEST_ESP_OK(touch_button_install(&global_config));
  304. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  305. touch_button_config_t button_config = {
  306. .channel_num = button_channel_array[i],
  307. .channel_sens = 0.1F
  308. };
  309. TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
  310. TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, (void *)&monitor));
  311. TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));
  312. TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_change_lp_handler));
  313. }
  314. TEST_ESP_OK(touch_element_start());
  315. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  316. //10 times random press/longpress/release test
  317. printf("Touch button event change longtime test start\n");
  318. for (int i = 0; i < 10; i++) {
  319. printf("Touch button event change longtime test... (%d/10)\n", i + 1);
  320. uint8_t channel_index = 5; //Always this channel
  321. touch_elem_message_t valid_message = {
  322. .handle = button_handle[channel_index],
  323. .element_type = TOUCH_ELEM_TYPE_BUTTON,
  324. .arg = NULL,
  325. };
  326. touch_button_message_t button_message = {
  327. .event = TOUCH_BUTTON_EVT_ON_LONGPRESS
  328. };
  329. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  330. xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
  331. test_button_event_simulator(button_handle[channel_index], button_message.event);
  332. BaseType_t os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(10 * 1000)); //100ms timeout
  333. TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Button LongPress queue timeout");
  334. test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Reset hardware
  335. }
  336. printf("Touch button event change longtime test finish\n");
  337. TEST_ESP_OK(touch_element_stop());
  338. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  339. TEST_ESP_OK(touch_button_delete(button_handle[i]));
  340. }
  341. touch_button_uninstall();
  342. }
  343. static void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
  344. {
  345. test_monitor_t *monitor = (test_monitor_t *)arg;
  346. touch_elem_message_t valid_message;
  347. BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200)); //Get the valid message for the verification, 500ms timeout
  348. TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_button_handler: queue timeout");
  349. test_button_callback_check(handle, message, &valid_message);
  350. xSemaphoreGive(monitor->response_sig_handle);
  351. TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 300)); // Always 300ms
  352. }
  353. static void test_button_event_concurrent(void)
  354. {
  355. touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
  356. touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  357. TEST_ESP_OK(touch_button_install(&global_config));
  358. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  359. touch_button_config_t button_config = {
  360. .channel_num = button_channel_array[i],
  361. .channel_sens = 0.1F
  362. };
  363. TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
  364. TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
  365. TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
  366. }
  367. TEST_ESP_OK(touch_element_start());
  368. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  369. //10 times random press/longpress/release test
  370. printf("Touch button event concurrent test start\n");
  371. for (int i = 0; i < 10; i++) {
  372. printf("Touch button event concurrent test... (%d/10)\n", i + 1);
  373. esp_err_t ret;
  374. uint32_t message_count = 0;
  375. touch_elem_message_t current_message;
  376. TEST_BUTTON_ENTER_CRITICAL();
  377. for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {
  378. test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_PRESS); //All channels trigger
  379. }
  380. TEST_BUTTON_EXIT_CRITICAL();
  381. message_count = 0;
  382. do {
  383. ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));
  384. if (ret == ESP_OK) {
  385. message_count++;
  386. }
  387. } while (ret == ESP_OK);
  388. TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, "button concurrent Press failed");
  389. TEST_BUTTON_ENTER_CRITICAL();
  390. for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {
  391. test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_RELEASE); //All channels trigger
  392. }
  393. TEST_BUTTON_EXIT_CRITICAL();
  394. message_count = 0;
  395. do {
  396. ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));
  397. if (ret == ESP_OK) {
  398. message_count++;
  399. }
  400. } while (ret == ESP_OK);
  401. TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, "button concurrent Release failed");
  402. }
  403. printf("Touch button event concurrent test finish\n");
  404. TEST_ESP_OK(touch_element_stop());
  405. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  406. TEST_ESP_OK(touch_button_delete(button_handle[i]));
  407. }
  408. touch_button_uninstall();
  409. }
  410. static void test_button_random_trigger_concurrent(void)
  411. {
  412. uint64_t sem_and_monitor[BUTTON_CHANNEL_NUM];
  413. printf("Touch button random trigger concurrent test start\n");
  414. test_concurrent_monitor_t monitor[BUTTON_CHANNEL_NUM];
  415. SemaphoreHandle_t count_sem = xSemaphoreCreateCounting(BUTTON_CHANNEL_NUM, 0);
  416. touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
  417. TEST_ESP_OK(touch_button_install(&global_config));
  418. for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  419. touch_button_config_t button_config = {
  420. .channel_num = button_channel_array[i],
  421. .channel_sens = 0.1F
  422. };
  423. monitor[i].response_sig_handle = xSemaphoreCreateBinary();
  424. monitor[i].valid_msg_handle = xQueueCreate(BUTTON_CHANNEL_NUM, sizeof(touch_elem_message_t));
  425. TEST_ASSERT(monitor[i].valid_msg_handle != NULL && monitor[i].response_sig_handle != NULL);
  426. uintptr_t temp_count_sem = (uint32_t)count_sem;
  427. uintptr_t temp_monitor = (uint32_t)&monitor[i]; //Prevent compiler warning
  428. sem_and_monitor[i] = (uint64_t)(((uint64_t)temp_count_sem << 32) | (uint64_t) temp_monitor);
  429. TEST_ESP_OK(touch_button_create(&button_config, &monitor[i].button_handle));
  430. TEST_ESP_OK(touch_button_subscribe_event(monitor[i].button_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&sem_and_monitor[i]));
  431. TEST_ESP_OK(touch_button_set_longpress(monitor[i].button_handle, 500));
  432. TEST_ESP_OK(touch_button_set_dispatch_method(monitor[i].button_handle, TOUCH_ELEM_DISP_CALLBACK));
  433. TEST_ESP_OK(touch_button_set_callback(monitor[i].button_handle, &random_trigger_concurrent_handler));
  434. }
  435. TEST_ESP_OK(touch_element_start());
  436. vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
  437. for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  438. BaseType_t os_ret = xTaskCreate(test_random_trigger_concurrent_task, "test_random_trigger_concurrent_task", 1024 * 4, (void *)&sem_and_monitor[i], 10, NULL);
  439. TEST_ASSERT(os_ret == pdPASS);
  440. }
  441. uint32_t run_count = 0;
  442. while (1) {
  443. if (run_count++ % 1000 == 0) {
  444. printf("Touch button random trigger concurrent test running... (1/1)\n");
  445. }
  446. uint8_t count = uxSemaphoreGetCount(count_sem);
  447. if (count == BUTTON_CHANNEL_NUM) {
  448. vTaskDelay(1); //Let IDLE task running and get tasks cleanup
  449. break;
  450. }
  451. vTaskDelay(1);
  452. }
  453. TEST_ESP_OK(touch_element_stop());
  454. for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
  455. vQueueDelete(monitor[i].valid_msg_handle);
  456. vSemaphoreDelete(monitor[i].response_sig_handle);
  457. TEST_ESP_OK(touch_button_delete(monitor[i].button_handle));
  458. }
  459. touch_button_uninstall();
  460. printf("Touch button random trigger concurrent test stop\n");
  461. }
  462. void test_random_trigger_concurrent_task(void *arg)
  463. {
  464. uintptr_t temp_monitor = *((uint32_t *) arg);
  465. uintptr_t temp_count_sem = (*((uint64_t *) arg) >> 32); //Prevent compiler warning
  466. test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *)temp_monitor;
  467. SemaphoreHandle_t count_sem = (SemaphoreHandle_t) temp_count_sem;
  468. uint32_t start_delay_time = (esp_random() % 100) * 10;
  469. vTaskDelay(pdMS_TO_TICKS(start_delay_time));
  470. touch_elem_message_t valid_message = {
  471. .handle = monitor->button_handle,
  472. .element_type = TOUCH_ELEM_TYPE_BUTTON,
  473. .arg = NULL,
  474. };
  475. touch_button_message_t button_message;
  476. button_message.event = TOUCH_BUTTON_EVT_ON_PRESS;
  477. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  478. xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
  479. test_button_event_simulator(valid_message.handle, button_message.event); //Trigger signal
  480. BaseType_t res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));
  481. TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
  482. uint32_t hold_state_time_ms = (esp_random() % 100) * 10 + 100;
  483. te_button_handle_t te_button = (te_button_handle_t) valid_message.handle;
  484. if ((int)(hold_state_time_ms - te_button->trigger_thr * 10) > 50) { //should raise longpress event
  485. button_message.event = TOUCH_BUTTON_EVT_ON_LONGPRESS;
  486. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  487. xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
  488. test_button_event_simulator(valid_message.handle, button_message.event); //Trigger signal
  489. res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000)); //+100 make sure it will really raise longpress event
  490. TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
  491. } else { //should not raise longpress event
  492. //Do nothing
  493. }
  494. button_message.event = TOUCH_BUTTON_EVT_ON_RELEASE;
  495. memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t)); //Construct valid_message
  496. xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
  497. test_button_event_simulator(valid_message.handle, button_message.event); //Trigger signal
  498. res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));
  499. TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
  500. xSemaphoreGive(count_sem);
  501. vTaskDelete(NULL);
  502. }
  503. static void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
  504. {
  505. uintptr_t temp_monitor = *((uint32_t *) arg); //Prevent compiler warning
  506. test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *) temp_monitor;
  507. touch_elem_message_t valid_message;
  508. BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(1000));
  509. TEST_ASSERT_MESSAGE(os_ret == pdPASS, "valid message timeout");
  510. const touch_button_message_t *button_message = touch_button_get_message(&valid_message);
  511. if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {
  512. touch_button_set_longpress(handle, portMAX_DELAY); //Prevent button triggers LongPress event again
  513. }
  514. TEST_ASSERT_MESSAGE(handle == valid_message.handle, "check handle failed");
  515. TEST_ASSERT_MESSAGE(valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON, "check element type failed");
  516. TEST_ASSERT_MESSAGE(message->event == button_message->event, "check event failed");
  517. xSemaphoreGive(monitor->response_sig_handle);
  518. }