test_touch_button.c 27 KB

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