button_test.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  2. *
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. #include "stdio.h"
  6. #include "freertos/FreeRTOS.h"
  7. #include "freertos/task.h"
  8. #include "freertos/queue.h"
  9. #include "freertos/timers.h"
  10. #include "freertos/semphr.h"
  11. #include "freertos/event_groups.h"
  12. #include "esp_idf_version.h"
  13. #include "esp_log.h"
  14. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
  15. #include "esp_adc/adc_cali.h"
  16. #endif
  17. #include "unity.h"
  18. #include "iot_button.h"
  19. #include "sdkconfig.h"
  20. static const char *TAG = "BUTTON TEST";
  21. #define TEST_MEMORY_LEAK_THRESHOLD (-400)
  22. #define BUTTON_IO_NUM 0
  23. #define BUTTON_ACTIVE_LEVEL 0
  24. #define BUTTON_NUM 16
  25. #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
  26. #define ADC_BUTTON_WIDTH SOC_ADC_RTC_MAX_BITWIDTH
  27. #else
  28. #define ADC_BUTTON_WIDTH ADC_WIDTH_MAX - 1
  29. #endif
  30. static size_t before_free_8bit;
  31. static size_t before_free_32bit;
  32. static button_handle_t g_btns[BUTTON_NUM] = {0};
  33. static int get_btn_index(button_handle_t btn)
  34. {
  35. for (size_t i = 0; i < BUTTON_NUM; i++) {
  36. if (btn == g_btns[i]) {
  37. return i;
  38. }
  39. }
  40. return -1;
  41. }
  42. static void button_press_down_cb(void *arg, void *data)
  43. {
  44. TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_DOWN, iot_button_get_event(arg));
  45. ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_DOWN", get_btn_index((button_handle_t)arg));
  46. }
  47. static void button_press_up_cb(void *arg, void *data)
  48. {
  49. TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_UP, iot_button_get_event(arg));
  50. ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_UP[%d]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg));
  51. }
  52. static void button_press_repeat_cb(void *arg, void *data)
  53. {
  54. ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg));
  55. }
  56. static void button_single_click_cb(void *arg, void *data)
  57. {
  58. TEST_ASSERT_EQUAL_HEX(BUTTON_SINGLE_CLICK, iot_button_get_event(arg));
  59. ESP_LOGI(TAG, "BTN%d: BUTTON_SINGLE_CLICK", get_btn_index((button_handle_t)arg));
  60. }
  61. static void button_double_click_cb(void *arg, void *data)
  62. {
  63. TEST_ASSERT_EQUAL_HEX(BUTTON_DOUBLE_CLICK, iot_button_get_event(arg));
  64. ESP_LOGI(TAG, "BTN%d: BUTTON_DOUBLE_CLICK", get_btn_index((button_handle_t)arg));
  65. }
  66. static void button_long_press_start_cb(void *arg, void *data)
  67. {
  68. TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_START, iot_button_get_event(arg));
  69. ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_START", get_btn_index((button_handle_t)arg));
  70. }
  71. static void button_long_press_hold_cb(void *arg, void *data)
  72. {
  73. TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_HOLD, iot_button_get_event(arg));
  74. ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_HOLD[%d],count is [%d]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg), iot_button_get_long_press_hold_cnt((button_handle_t)arg));
  75. }
  76. static void button_press_repeat_done_cb(void *arg, void *data)
  77. {
  78. TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_REPEAT_DONE, iot_button_get_event(arg));
  79. ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT_DONE[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg));
  80. }
  81. static esp_err_t custom_button_gpio_init(void *param)
  82. {
  83. button_gpio_config_t *cfg = (button_gpio_config_t *)param;
  84. return button_gpio_init(cfg);
  85. }
  86. static uint8_t custom_button_gpio_get_key_value(void *param)
  87. {
  88. button_gpio_config_t *cfg = (button_gpio_config_t *)param;
  89. return button_gpio_get_key_level((void *)cfg->gpio_num);
  90. }
  91. static esp_err_t custom_button_gpio_deinit(void *param)
  92. {
  93. button_gpio_config_t *cfg = (button_gpio_config_t *)param;
  94. return button_gpio_deinit(cfg->gpio_num);
  95. }
  96. TEST_CASE("custom button test", "[button][iot]")
  97. {
  98. button_gpio_config_t *gpio_cfg = calloc(1, sizeof(button_gpio_config_t));
  99. gpio_cfg->active_level = 0;
  100. gpio_cfg->gpio_num = 0;
  101. button_config_t cfg = {
  102. .type = BUTTON_TYPE_CUSTOM,
  103. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  104. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  105. .custom_button_config = {
  106. .button_custom_init = custom_button_gpio_init,
  107. .button_custom_deinit = custom_button_gpio_deinit,
  108. .button_custom_get_key_value = custom_button_gpio_get_key_value,
  109. .active_level = 0,
  110. .priv = gpio_cfg,
  111. },
  112. };
  113. g_btns[0] = iot_button_create(&cfg);
  114. TEST_ASSERT_NOT_NULL(g_btns[0]);
  115. iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  116. iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  117. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  118. iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  119. iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  120. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  121. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  122. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  123. while (1) {
  124. vTaskDelay(pdMS_TO_TICKS(1000));
  125. }
  126. iot_button_delete(g_btns[0]);
  127. }
  128. TEST_CASE("gpio button test", "[button][iot]")
  129. {
  130. button_config_t cfg = {
  131. .type = BUTTON_TYPE_GPIO,
  132. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  133. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  134. .gpio_button_config = {
  135. .gpio_num = 0,
  136. .active_level = 0,
  137. },
  138. };
  139. g_btns[0] = iot_button_create(&cfg);
  140. TEST_ASSERT_NOT_NULL(g_btns[0]);
  141. iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  142. iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  143. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  144. iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  145. iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  146. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  147. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  148. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  149. while (1) {
  150. vTaskDelay(pdMS_TO_TICKS(1000));
  151. }
  152. iot_button_delete(g_btns[0]);
  153. }
  154. TEST_CASE("gpio button test power save", "[button][iot][power save]")
  155. {
  156. button_config_t cfg = {
  157. .type = BUTTON_TYPE_GPIO,
  158. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  159. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  160. .gpio_button_config = {
  161. .gpio_num = 0,
  162. .active_level = 0,
  163. },
  164. };
  165. g_btns[0] = iot_button_create(&cfg);
  166. TEST_ASSERT_NOT_NULL(g_btns[0]);
  167. iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  168. iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  169. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  170. iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  171. iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  172. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  173. iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  174. iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  175. TEST_ASSERT_EQUAL(ESP_OK, iot_button_stop());
  176. vTaskDelay(pdMS_TO_TICKS(1000));
  177. TEST_ASSERT_EQUAL(ESP_OK, iot_button_resume());
  178. while (1)
  179. {
  180. vTaskDelay(pdMS_TO_TICKS(1000));
  181. }
  182. iot_button_delete(g_btns[0]);
  183. }
  184. TEST_CASE("matrix keyboard button test","[button][matrix key]")
  185. {
  186. int32_t row_gpio[4] = {4,5,6,7};
  187. int32_t col_gpio[4] = {3,8,16,15};
  188. button_config_t cfg = {
  189. .type = BUTTON_TYPE_MATRIX,
  190. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  191. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  192. .matrix_button_config = {
  193. .row_gpio_num = 0,
  194. .col_gpio_num = 0,
  195. }
  196. };
  197. for (int i=0;i<4;i++){
  198. cfg.matrix_button_config.row_gpio_num = row_gpio[i];
  199. for (int j=0;j<4;j++) {
  200. cfg.matrix_button_config.col_gpio_num = col_gpio[j];
  201. g_btns[i*4+j] = iot_button_create(&cfg);
  202. TEST_ASSERT_NOT_NULL(g_btns[i*4+j]);
  203. iot_button_register_cb(g_btns[i*4+j], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  204. iot_button_register_cb(g_btns[i*4+j], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  205. iot_button_register_cb(g_btns[i*4+j], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  206. iot_button_register_cb(g_btns[i*4+j], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  207. iot_button_register_cb(g_btns[i*4+j], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  208. iot_button_register_cb(g_btns[i*4+j], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  209. iot_button_register_cb(g_btns[i*4+j], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  210. iot_button_register_cb(g_btns[i*4+j], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  211. }
  212. }
  213. while (1)
  214. {
  215. vTaskDelay(pdMS_TO_TICKS(1000));
  216. }
  217. for (int i=0;i<4;i++){
  218. for (int j=0;j<4;j++) {
  219. iot_button_delete(g_btns[i*4+j]);
  220. }
  221. }
  222. }
  223. #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
  224. TEST_CASE("adc button test", "[button][iot]")
  225. {
  226. /** ESP32-S3-Korvo board */
  227. const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
  228. button_config_t cfg = {0};
  229. cfg.type = BUTTON_TYPE_ADC;
  230. cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS;
  231. cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS;
  232. for (size_t i = 0; i < 6; i++) {
  233. cfg.adc_button_config.adc_channel = 7,
  234. cfg.adc_button_config.button_index = i;
  235. if (i == 0) {
  236. cfg.adc_button_config.min = (0 + vol[i]) / 2;
  237. } else {
  238. cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2;
  239. }
  240. if (i == 5) {
  241. cfg.adc_button_config.max = (vol[i] + 3000) / 2;
  242. } else {
  243. cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2;
  244. }
  245. g_btns[i] = iot_button_create(&cfg);
  246. TEST_ASSERT_NOT_NULL(g_btns[i]);
  247. iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  248. iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  249. iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  250. iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  251. iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  252. iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  253. iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  254. iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  255. }
  256. while (1) {
  257. vTaskDelay(pdMS_TO_TICKS(1000));
  258. }
  259. for (size_t i = 0; i < 6; i++) {
  260. iot_button_delete(g_btns[i]);
  261. }
  262. }
  263. #else
  264. static esp_err_t adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle)
  265. {
  266. adc_cali_handle_t handle = NULL;
  267. esp_err_t ret = ESP_FAIL;
  268. bool calibrated = false;
  269. #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
  270. if (!calibrated) {
  271. ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
  272. adc_cali_curve_fitting_config_t cali_config = {
  273. .unit_id = unit,
  274. .atten = atten,
  275. .bitwidth = ADC_BUTTON_WIDTH,
  276. };
  277. ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
  278. if (ret == ESP_OK) {
  279. calibrated = true;
  280. }
  281. }
  282. #endif
  283. #if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
  284. if (!calibrated) {
  285. ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
  286. adc_cali_line_fitting_config_t cali_config = {
  287. .unit_id = unit,
  288. .atten = atten,
  289. .bitwidth = ADC_BUTTON_WIDTH,
  290. };
  291. ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
  292. if (ret == ESP_OK) {
  293. calibrated = true;
  294. }
  295. }
  296. #endif
  297. *out_handle = handle;
  298. if (ret == ESP_OK) {
  299. ESP_LOGI(TAG, "Calibration Success");
  300. } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
  301. ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
  302. } else {
  303. ESP_LOGE(TAG, "Invalid arg or no memory");
  304. }
  305. return calibrated ? ESP_OK : ESP_FAIL;
  306. }
  307. TEST_CASE("adc button idf5 drive test", "[button][iot]")
  308. {
  309. adc_oneshot_unit_handle_t adc1_handle;
  310. adc_cali_handle_t adc1_cali_handle;
  311. adc_oneshot_unit_init_cfg_t init_config = {
  312. .unit_id = ADC_UNIT_1,
  313. };
  314. esp_err_t ret = adc_oneshot_new_unit(&init_config, &adc1_handle);
  315. TEST_ASSERT_TRUE(ret == ESP_OK);
  316. adc_calibration_init(ADC_UNIT_1, ADC_ATTEN_DB_11, &adc1_cali_handle);
  317. /** ESP32-S3-Korvo board */
  318. const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
  319. button_config_t cfg = {0};
  320. cfg.type = BUTTON_TYPE_ADC;
  321. cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS;
  322. cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS;
  323. for (size_t i = 0; i < 6; i++) {
  324. cfg.adc_button_config.adc_handle = &adc1_handle;
  325. cfg.adc_button_config.adc_channel = 7,
  326. cfg.adc_button_config.button_index = i;
  327. if (i == 0) {
  328. cfg.adc_button_config.min = (0 + vol[i]) / 2;
  329. } else {
  330. cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2;
  331. }
  332. if (i == 5) {
  333. cfg.adc_button_config.max = (vol[i] + 3000) / 2;
  334. } else {
  335. cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2;
  336. }
  337. g_btns[i] = iot_button_create(&cfg);
  338. TEST_ASSERT_NOT_NULL(g_btns[i]);
  339. iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
  340. iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL);
  341. iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
  342. iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
  343. iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
  344. iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
  345. iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
  346. iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
  347. }
  348. while (1) {
  349. vTaskDelay(pdMS_TO_TICKS(1000));
  350. }
  351. for (size_t i = 0; i < 6; i++) {
  352. iot_button_delete(g_btns[i]);
  353. }
  354. }
  355. #endif
  356. #define GPIO_OUTPUT_IO_45 45
  357. static EventGroupHandle_t g_check = NULL;
  358. static SemaphoreHandle_t g_auto_check_pass = NULL;
  359. static const char* button_event_str[BUTTON_EVENT_MAX] = {
  360. "BUTTON_PRESS_DOWN",
  361. "BUTTON_PRESS_UP",
  362. "BUTTON_PRESS_REPEAT",
  363. "BUTTON_PRESS_REPEAT_DONE",
  364. "BUTTON_SINGLE_CLICK",
  365. "BUTTON_DOUBLE_CLICK",
  366. "BUTTON_MULTIPLE_CLICK",
  367. "BUTTON_LONG_PRESS_START",
  368. "BUTTON_LONG_PRESS_HOLD",
  369. "BUTTON_LONG_PRESS_UP"
  370. };
  371. static button_event_t state = BUTTON_PRESS_DOWN;
  372. static void button_auto_press_test_task(void *arg)
  373. {
  374. // test BUTTON_PRESS_DOWN
  375. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  376. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  377. vTaskDelay(pdMS_TO_TICKS(100));
  378. // // test BUTTON_PRESS_UP
  379. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  380. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  381. vTaskDelay(pdMS_TO_TICKS(200));
  382. // test BUTTON_PRESS_REPEAT
  383. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  384. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  385. vTaskDelay(pdMS_TO_TICKS(100));
  386. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  387. vTaskDelay(pdMS_TO_TICKS(100));
  388. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  389. vTaskDelay(pdMS_TO_TICKS(100));
  390. // test BUTTON_PRESS_REPEAT_DONE
  391. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  392. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  393. vTaskDelay(pdMS_TO_TICKS(200));
  394. // test BUTTON_SINGLE_CLICK
  395. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  396. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  397. vTaskDelay(pdMS_TO_TICKS(100));
  398. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  399. vTaskDelay(pdMS_TO_TICKS(200));
  400. // test BUTTON_DOUBLE_CLICK
  401. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  402. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  403. vTaskDelay(pdMS_TO_TICKS(100));
  404. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  405. vTaskDelay(pdMS_TO_TICKS(100));
  406. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  407. vTaskDelay(pdMS_TO_TICKS(100));
  408. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  409. vTaskDelay(pdMS_TO_TICKS(200));
  410. // test BUTTON_MULTIPLE_CLICK
  411. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  412. for (int i = 0; i < 4; i++) {
  413. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  414. vTaskDelay(pdMS_TO_TICKS(100));
  415. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  416. vTaskDelay(pdMS_TO_TICKS(100));
  417. }
  418. vTaskDelay(pdMS_TO_TICKS(100));
  419. // test BUTTON_LONG_PRESS_START
  420. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  421. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  422. vTaskDelay(pdMS_TO_TICKS(1600));
  423. // test BUTTON_LONG_PRESS_HOLD and BUTTON_LONG_PRESS_UP
  424. xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
  425. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  426. ESP_LOGI(TAG, "Auto Press Success!");
  427. vTaskDelete(NULL);
  428. }
  429. static void button_auto_check_cb_1(void *arg, void *data)
  430. {
  431. if (iot_button_get_event(g_btns[0]) == state) {
  432. xEventGroupSetBits(g_check, BIT(1));
  433. }
  434. }
  435. static void button_auto_check_cb(void *arg, void *data)
  436. {
  437. if (iot_button_get_event(g_btns[0]) == state) {
  438. ESP_LOGI(TAG, "Auto check: button event %s pass", button_event_str[state]);
  439. xEventGroupSetBits(g_check, BIT(0));
  440. if (++state >= BUTTON_EVENT_MAX) {
  441. xSemaphoreGive(g_auto_check_pass);
  442. return;
  443. }
  444. }
  445. }
  446. TEST_CASE("gpio button auto-test", "[button][iot][auto]")
  447. {
  448. state = BUTTON_PRESS_DOWN;
  449. g_check = xEventGroupCreate();
  450. g_auto_check_pass = xSemaphoreCreateBinary();
  451. xEventGroupSetBits(g_check, BIT(0) | BIT(1));
  452. button_config_t cfg = {
  453. .type = BUTTON_TYPE_GPIO,
  454. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  455. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  456. .gpio_button_config = {
  457. .gpio_num = 0,
  458. .active_level = 0,
  459. },
  460. };
  461. g_btns[0] = iot_button_create(&cfg);
  462. TEST_ASSERT_NOT_NULL(g_btns[0]);
  463. /* register iot_button callback for all the button_event */
  464. for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) {
  465. if (i == BUTTON_MULTIPLE_CLICK) {
  466. button_event_config_t btn_cfg;
  467. btn_cfg.event = i;
  468. btn_cfg.event_data.multiple_clicks.clicks = 4;
  469. iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb_1, NULL);
  470. iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb, NULL);
  471. } else {
  472. iot_button_register_cb(g_btns[0], i, button_auto_check_cb_1, NULL);
  473. iot_button_register_cb(g_btns[0], i, button_auto_check_cb, NULL);
  474. }
  475. }
  476. TEST_ASSERT_EQUAL(ESP_OK, iot_button_set_param(g_btns[0], BUTTON_LONG_PRESS_TIME_MS, (void *)1500));
  477. gpio_config_t io_conf = {
  478. .intr_type = GPIO_INTR_DISABLE,
  479. .mode = GPIO_MODE_OUTPUT,
  480. .pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45),
  481. .pull_down_en = 0,
  482. .pull_up_en = 0,
  483. };
  484. gpio_config(&io_conf);
  485. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  486. xTaskCreate(button_auto_press_test_task, "button_auto_press_test_task", 1024 * 4, NULL, 10, NULL);
  487. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(g_auto_check_pass, pdMS_TO_TICKS(6000)));
  488. for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) {
  489. button_event_config_t btn_cfg;
  490. btn_cfg.event = i;
  491. if (i == BUTTON_MULTIPLE_CLICK) {
  492. btn_cfg.event_data.multiple_clicks.clicks = 4;
  493. } else if ( i == BUTTON_LONG_PRESS_UP || i == BUTTON_LONG_PRESS_START) {
  494. btn_cfg.event_data.long_press.press_time = 1500;
  495. }
  496. iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb);
  497. iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb_1);
  498. }
  499. TEST_ASSERT_EQUAL(ESP_OK,iot_button_delete(g_btns[0]));
  500. vEventGroupDelete(g_check);
  501. vSemaphoreDelete(g_auto_check_pass);
  502. vTaskDelay(pdMS_TO_TICKS(100));
  503. }
  504. #define TOLERANCE CONFIG_BUTTON_LONG_PRESS_TOLERANCE_MS
  505. uint16_t long_press_time[5] = {2000, 2500, 3000, 3500, 4000};
  506. static SemaphoreHandle_t long_press_check = NULL;
  507. static SemaphoreHandle_t long_press_auto_check_pass = NULL;
  508. unsigned int status = 0;
  509. static void button_auto_long_press_test_task(void *arg)
  510. {
  511. // Test for BUTTON_LONG_PRESS_START
  512. for (int i = 0; i < 5; i++) {
  513. xSemaphoreTake(long_press_check, portMAX_DELAY);
  514. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  515. status = (BUTTON_LONG_PRESS_START << 16) | long_press_time[i];
  516. if (i > 0)
  517. vTaskDelay(pdMS_TO_TICKS(long_press_time[i] - long_press_time[i - 1]));
  518. else
  519. vTaskDelay(pdMS_TO_TICKS(long_press_time[i]));
  520. }
  521. vTaskDelay(pdMS_TO_TICKS(100));
  522. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  523. xSemaphoreGive(long_press_auto_check_pass);
  524. vTaskDelay(pdMS_TO_TICKS(100));
  525. // Test for BUTTON_LONG_PRESS_UP
  526. for (int i = 0; i < 5; i++) {
  527. xSemaphoreTake(long_press_check, portMAX_DELAY);
  528. status = (BUTTON_LONG_PRESS_UP << 16) | long_press_time[i];
  529. gpio_set_level(GPIO_OUTPUT_IO_45, 0);
  530. vTaskDelay(pdMS_TO_TICKS(long_press_time[i] + 10));
  531. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  532. }
  533. ESP_LOGI(TAG, "Auto Long Press Success!");
  534. vTaskDelete(NULL);
  535. }
  536. static void button_long_press_auto_check_cb(void *arg, void *data)
  537. {
  538. uint32_t value = (uint32_t)data;
  539. uint16_t event = (0xffff0000 & value) >> 16;
  540. uint16_t time = 0xffff & value;
  541. uint16_t ticks_time = iot_button_get_ticks_time(g_btns[0]);
  542. if (status == value && abs(ticks_time - time) <= TOLERANCE) {
  543. ESP_LOGI(TAG, "Auto check: button event: %s and time: %d pass", button_event_str[event], time);
  544. if (event == BUTTON_LONG_PRESS_UP && time == long_press_time[4]) {
  545. xSemaphoreGive(long_press_auto_check_pass);
  546. }
  547. xSemaphoreGive(long_press_check);
  548. }
  549. }
  550. TEST_CASE("gpio button long_press auto-test", "[button][long_press][auto]")
  551. {
  552. ESP_LOGI(TAG, "Starting the test");
  553. long_press_check = xSemaphoreCreateBinary();
  554. long_press_auto_check_pass = xSemaphoreCreateBinary();
  555. xSemaphoreGive(long_press_check);
  556. button_config_t cfg = {
  557. .type = BUTTON_TYPE_GPIO,
  558. .long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
  559. .short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
  560. .gpio_button_config = {
  561. .gpio_num = 0,
  562. .active_level = 0,
  563. },
  564. };
  565. g_btns[0] = iot_button_create(&cfg);
  566. TEST_ASSERT_NOT_NULL(g_btns[0]);
  567. button_event_config_t btn_cfg;
  568. btn_cfg.event = BUTTON_LONG_PRESS_START;
  569. for (int i = 0; i < 5; i++) {
  570. btn_cfg.event_data.long_press.press_time = long_press_time[i];
  571. uint32_t data = (btn_cfg.event << 16) | long_press_time[i];
  572. iot_button_register_event_cb(g_btns[0], btn_cfg, button_long_press_auto_check_cb, (void*)data);
  573. }
  574. gpio_config_t io_conf = {
  575. .intr_type = GPIO_INTR_DISABLE,
  576. .mode = GPIO_MODE_OUTPUT,
  577. .pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45),
  578. .pull_down_en = 0,
  579. .pull_up_en = 0,
  580. };
  581. gpio_config(&io_conf);
  582. gpio_set_level(GPIO_OUTPUT_IO_45, 1);
  583. xTaskCreate(button_auto_long_press_test_task, "button_auto_long_press_test_task", 1024 * 4, NULL, 10, NULL);
  584. xSemaphoreTake(long_press_auto_check_pass, portMAX_DELAY);
  585. iot_button_unregister_cb(g_btns[0], BUTTON_LONG_PRESS_START);
  586. btn_cfg.event = BUTTON_LONG_PRESS_UP;
  587. for (int i = 0; i < 5; i++) {
  588. btn_cfg.event_data.long_press.press_time = long_press_time[i];
  589. uint32_t data = (btn_cfg.event << 16) | long_press_time[i];
  590. iot_button_register_event_cb(g_btns[0], btn_cfg, button_long_press_auto_check_cb, (void*)data);
  591. }
  592. TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(long_press_auto_check_pass, pdMS_TO_TICKS(17000)));
  593. TEST_ASSERT_EQUAL(ESP_OK,iot_button_delete(g_btns[0]));
  594. vSemaphoreDelete(long_press_check);
  595. vSemaphoreDelete(long_press_auto_check_pass);
  596. vTaskDelay(pdMS_TO_TICKS(100));
  597. }
  598. static void check_leak(size_t before_free, size_t after_free, const char *type)
  599. {
  600. ssize_t delta = after_free - before_free;
  601. printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
  602. TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
  603. }
  604. void setUp(void)
  605. {
  606. before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  607. before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
  608. }
  609. void tearDown(void)
  610. {
  611. size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  612. size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
  613. check_leak(before_free_8bit, after_free_8bit, "8BIT");
  614. check_leak(before_free_32bit, after_free_32bit, "32BIT");
  615. }
  616. void app_main(void)
  617. {
  618. printf("USB STREAM TEST \n");
  619. unity_run_menu();
  620. }