button.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "freertos/queue.h"
  10. #include "freertos/timers.h"
  11. #include "esp_log.h"
  12. #include "driver/gpio.h"
  13. #include "iot_button.h"
  14. #include "esp_timer.h"
  15. #include "esp_rom_sys.h"
  16. #define USE_ESP_TIMER CONFIG_BUTTON_USE_ESP_TIMER
  17. #if USE_ESP_TIMER
  18. #define STOP_TIMER(tmr) esp_timer_stop(tmr)
  19. #define DELETE_TIMER(tmr) esp_timer_delete(tmr)
  20. #else
  21. #define STOP_TIMER(tmr) xTimerStop(tmr, portMAX_DELAY)
  22. #define DELETE_TIMER(tmr) xTimerDelete(tmr, portMAX_DELAY);
  23. #endif
  24. #define IOT_CHECK(tag, a, ret) if(!(a)) { \
  25. ESP_LOGE(tag,"%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \
  26. return (ret); \
  27. }
  28. #define ERR_ASSERT(tag, param) IOT_CHECK(tag, (param) == ESP_OK, ESP_FAIL)
  29. #define POINT_ASSERT(tag, param, ret) IOT_CHECK(tag, (param) != NULL, (ret))
  30. typedef enum {
  31. BUTTON_STATE_IDLE = 0,
  32. BUTTON_STATE_PUSH,
  33. BUTTON_STATE_PRESSED,
  34. } button_status_t;
  35. typedef struct button_dev button_dev_t;
  36. typedef struct btn_cb button_cb_t;
  37. struct btn_cb{
  38. TickType_t interval;
  39. button_cb cb;
  40. void* arg;
  41. #if !USE_ESP_TIMER
  42. TimerHandle_t tmr;
  43. #else
  44. esp_timer_handle_t tmr;
  45. #endif
  46. button_dev_t *pbtn;
  47. button_cb_t *next_cb;
  48. };
  49. struct button_dev{
  50. uint8_t io_num;
  51. uint8_t active_level;
  52. uint32_t serial_thres_sec;
  53. button_status_t state;
  54. button_cb_t tap_short_cb;
  55. button_cb_t tap_psh_cb;
  56. button_cb_t tap_rls_cb;
  57. button_cb_t press_serial_cb;
  58. button_cb_t* cb_head;
  59. };
  60. #define BUTTON_GLITCH_FILTER_TIME_MS CONFIG_BUTTON_IO_GLITCH_FILTER_TIME_MS
  61. static const char* TAG = "button";
  62. // static void button_press_cb(TimerHandle_t tmr)
  63. static void button_press_cb(void* tmr)
  64. {
  65. #if !USE_ESP_TIMER
  66. button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
  67. #else
  68. button_cb_t* btn_cb = (button_cb_t*)(tmr);
  69. #endif
  70. button_dev_t* btn = btn_cb->pbtn;
  71. // low, then restart
  72. if (btn->active_level == gpio_get_level(btn->io_num)) {
  73. btn->state = BUTTON_STATE_PRESSED;
  74. if (btn_cb->cb) {
  75. btn_cb->cb(btn_cb->arg);
  76. }
  77. }
  78. }
  79. // static void button_tap_psh_cb(TimerHandle_t tmr)
  80. static void button_tap_psh_cb(void* tmr)
  81. {
  82. #if !USE_ESP_TIMER
  83. button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
  84. #else
  85. button_cb_t* btn_cb = (button_cb_t*)(tmr);
  86. #endif
  87. button_dev_t* btn = btn_cb->pbtn;
  88. STOP_TIMER(btn->tap_rls_cb.tmr);
  89. int lv = gpio_get_level(btn->io_num);
  90. if (btn->active_level == lv) {
  91. // high, then key is up
  92. btn->state = BUTTON_STATE_PUSH;
  93. if (btn->press_serial_cb.tmr) {
  94. #if !USE_ESP_TIMER
  95. xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
  96. xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
  97. #else
  98. esp_timer_stop(btn->press_serial_cb.tmr);
  99. esp_timer_start_once(btn->press_serial_cb.tmr, btn->serial_thres_sec * 1000 * 1000);
  100. #endif
  101. }
  102. if (btn->tap_psh_cb.cb) {
  103. btn->tap_psh_cb.cb(btn->tap_psh_cb.arg);
  104. }
  105. } else {
  106. // 50ms, check if this is a real key up
  107. if (btn->tap_rls_cb.tmr) {
  108. STOP_TIMER(btn->tap_rls_cb.tmr);
  109. #if !USE_ESP_TIMER
  110. xTimerReset(btn->tap_rls_cb.tmr, portMAX_DELAY);
  111. #else
  112. esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
  113. #endif
  114. }
  115. }
  116. }
  117. static void button_tap_rls_cb(void* tmr)
  118. {
  119. #if !USE_ESP_TIMER
  120. button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
  121. #else
  122. button_cb_t* btn_cb = (button_cb_t*)(tmr);
  123. #endif
  124. button_dev_t* btn = btn_cb->pbtn;
  125. STOP_TIMER(btn->tap_rls_cb.tmr);
  126. if (btn->active_level == gpio_get_level(btn->io_num)) {
  127. } else {
  128. // high, then key is up
  129. button_cb_t *pcb = btn->cb_head;
  130. while (pcb != NULL) {
  131. if (pcb->tmr != NULL) {
  132. STOP_TIMER(pcb->tmr);
  133. }
  134. pcb = pcb->next_cb;
  135. }
  136. if (btn->press_serial_cb.tmr && btn->press_serial_cb.tmr != NULL) {
  137. STOP_TIMER(btn->press_serial_cb.tmr);
  138. }
  139. if (btn->tap_short_cb.cb && btn->state == BUTTON_STATE_PUSH) {
  140. btn->tap_short_cb.cb(btn->tap_short_cb.arg);
  141. }
  142. if(btn->tap_rls_cb.cb && btn->state != BUTTON_STATE_IDLE) {
  143. btn->tap_rls_cb.cb(btn->tap_rls_cb.arg);
  144. }
  145. btn->state = BUTTON_STATE_IDLE;
  146. }
  147. }
  148. static void button_press_serial_cb(void* tmr)
  149. {
  150. #if !USE_ESP_TIMER
  151. button_dev_t* btn = (button_dev_t*) pvTimerGetTimerID(tmr);
  152. #else
  153. button_dev_t* btn = (button_dev_t*)(tmr);
  154. #endif
  155. if (btn->press_serial_cb.cb) {
  156. btn->press_serial_cb.cb(btn->press_serial_cb.arg);
  157. }
  158. #if !USE_ESP_TIMER
  159. xTimerChangePeriod(btn->press_serial_cb.tmr, btn->press_serial_cb.interval, portMAX_DELAY);
  160. xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
  161. #else
  162. esp_timer_stop(btn->press_serial_cb.tmr);
  163. esp_timer_start_once(btn->press_serial_cb.tmr, btn->press_serial_cb.interval * portTICK_PERIOD_MS * 1000);
  164. #endif
  165. }
  166. static void button_gpio_isr_handler(void* arg)
  167. {
  168. button_dev_t* btn = (button_dev_t*) arg;
  169. BaseType_t HPTaskAwoken = pdFALSE;
  170. int level = gpio_get_level(btn->io_num);
  171. if (level == btn->active_level) {
  172. if (btn->tap_psh_cb.tmr) {
  173. #if !USE_ESP_TIMER
  174. xTimerStopFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
  175. xTimerResetFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
  176. #else
  177. esp_timer_stop(btn->tap_psh_cb.tmr);
  178. esp_timer_start_once(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval * portTICK_PERIOD_MS * 1000);
  179. #endif
  180. }
  181. button_cb_t *pcb = btn->cb_head;
  182. while (pcb != NULL) {
  183. if (pcb->tmr != NULL) {
  184. #if !USE_ESP_TIMER
  185. xTimerStopFromISR(pcb->tmr, &HPTaskAwoken);
  186. xTimerResetFromISR(pcb->tmr, &HPTaskAwoken);
  187. #else
  188. esp_timer_stop(pcb->tmr);
  189. esp_timer_start_once(pcb->tmr, pcb->interval * portTICK_PERIOD_MS * 1000);
  190. #endif
  191. }
  192. pcb = pcb->next_cb;
  193. }
  194. } else {
  195. // 50ms, check if this is a real key up
  196. if (btn->tap_rls_cb.tmr) {
  197. #if !USE_ESP_TIMER
  198. xTimerStopFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
  199. xTimerResetFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
  200. #else
  201. esp_timer_stop(btn->tap_rls_cb.tmr);
  202. esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
  203. #endif
  204. }
  205. }
  206. if(HPTaskAwoken == pdTRUE) {
  207. portYIELD_FROM_ISR();
  208. }
  209. }
  210. #if !USE_ESP_TIMER
  211. static void button_free_tmr(TimerHandle_t* tmr)
  212. #else
  213. static void button_free_tmr(esp_timer_handle_t *tmr)
  214. #endif
  215. {
  216. if (tmr && *tmr) {
  217. STOP_TIMER(*tmr);
  218. DELETE_TIMER(*tmr);
  219. *tmr = NULL;
  220. }
  221. }
  222. esp_err_t iot_button_delete(button_handle_t btn_handle)
  223. {
  224. POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
  225. button_dev_t* btn = (button_dev_t*) btn_handle;
  226. gpio_set_intr_type(btn->io_num, GPIO_INTR_DISABLE);
  227. gpio_isr_handler_remove(btn->io_num);
  228. button_free_tmr(&btn->tap_rls_cb.tmr);
  229. button_free_tmr(&btn->tap_psh_cb.tmr);
  230. button_free_tmr(&btn->tap_short_cb.tmr);
  231. button_free_tmr(&btn->press_serial_cb.tmr);
  232. button_cb_t *pcb = btn->cb_head;
  233. while (pcb != NULL) {
  234. button_cb_t *cb_next = pcb->next_cb;
  235. button_free_tmr(&pcb->tmr);
  236. free(pcb);
  237. pcb = cb_next;
  238. }
  239. free(btn);
  240. return ESP_OK;
  241. }
  242. button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level)
  243. {
  244. #if USE_ESP_TIMER
  245. esp_rom_printf("use esp timer !!!\n");
  246. esp_timer_init();
  247. #endif
  248. IOT_CHECK(TAG, gpio_num < GPIO_NUM_MAX, NULL);
  249. button_dev_t* btn = (button_dev_t*) calloc(1, sizeof(button_dev_t));
  250. POINT_ASSERT(TAG, btn, NULL);
  251. btn->active_level = active_level;
  252. btn->io_num = gpio_num;
  253. btn->state = BUTTON_STATE_IDLE;
  254. btn->tap_rls_cb.arg = NULL;
  255. btn->tap_rls_cb.cb = NULL;
  256. btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
  257. btn->tap_rls_cb.pbtn = btn;
  258. #if !USE_ESP_TIMER
  259. btn->tap_rls_cb.tmr = xTimerCreate("btn_rls_tmr", btn->tap_rls_cb.interval, pdFALSE,
  260. &btn->tap_rls_cb, button_tap_rls_cb);
  261. #else
  262. esp_timer_create_args_t tmr_param_rls;
  263. tmr_param_rls.arg = &btn->tap_rls_cb;
  264. tmr_param_rls.callback = button_tap_rls_cb;
  265. tmr_param_rls.dispatch_method = ESP_TIMER_TASK;
  266. tmr_param_rls.name = "btn_rls_tmr";
  267. esp_timer_create(&tmr_param_rls, &btn->tap_rls_cb.tmr);
  268. #endif
  269. btn->tap_psh_cb.arg = NULL;
  270. btn->tap_psh_cb.cb = NULL;
  271. btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
  272. btn->tap_psh_cb.pbtn = btn;
  273. #if !USE_ESP_TIMER
  274. btn->tap_psh_cb.tmr = xTimerCreate("btn_psh_tmr", btn->tap_psh_cb.interval, pdFALSE,
  275. &btn->tap_psh_cb, button_tap_psh_cb);
  276. #else
  277. esp_timer_create_args_t tmr_param_psh;
  278. tmr_param_psh.arg = &btn->tap_psh_cb;
  279. tmr_param_psh.callback = button_tap_psh_cb;
  280. tmr_param_psh.dispatch_method = ESP_TIMER_TASK;
  281. tmr_param_psh.name = "btn_psh_tmr";
  282. esp_timer_create(&tmr_param_psh, &btn->tap_psh_cb.tmr);
  283. #endif
  284. gpio_install_isr_service(0);
  285. gpio_config_t gpio_conf;
  286. gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
  287. gpio_conf.mode = GPIO_MODE_INPUT;
  288. gpio_conf.pin_bit_mask = (1ULL << gpio_num);
  289. gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  290. gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  291. gpio_config(&gpio_conf);
  292. gpio_isr_handler_add(gpio_num, button_gpio_isr_handler, btn);
  293. return (button_handle_t) btn;
  294. }
  295. esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type)
  296. {
  297. button_dev_t* btn = (button_dev_t*) btn_handle;
  298. button_cb_t* btn_cb = NULL;
  299. if (type == BUTTON_CB_PUSH) {
  300. btn_cb = &btn->tap_psh_cb;
  301. } else if (type == BUTTON_CB_RELEASE) {
  302. btn_cb = &btn->tap_rls_cb;
  303. } else if (type == BUTTON_CB_TAP) {
  304. btn_cb = &btn->tap_short_cb;
  305. } else if (type == BUTTON_CB_SERIAL) {
  306. btn_cb = &btn->press_serial_cb;
  307. }
  308. btn_cb->cb = NULL;
  309. btn_cb->arg = NULL;
  310. btn_cb->pbtn = btn;
  311. button_free_tmr(&btn_cb->tmr);
  312. return ESP_OK;
  313. }
  314. esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg)
  315. {
  316. button_dev_t* btn = (button_dev_t*) btn_handle;
  317. btn->serial_thres_sec = start_after_sec;
  318. if (btn->press_serial_cb.tmr == NULL) {
  319. #if !USE_ESP_TIMER
  320. btn->press_serial_cb.tmr = xTimerCreate("btn_serial_tmr", btn->serial_thres_sec*1000 / portTICK_PERIOD_MS,
  321. pdFALSE, btn, button_press_serial_cb);
  322. #else
  323. esp_timer_create_args_t tmr_param_ser;
  324. tmr_param_ser.arg = btn;
  325. tmr_param_ser.callback = button_press_serial_cb;
  326. tmr_param_ser.dispatch_method = ESP_TIMER_TASK;
  327. tmr_param_ser.name = "btn_serial_tmr";
  328. esp_timer_create(&tmr_param_ser, &btn->press_serial_cb.tmr);
  329. #endif
  330. }
  331. btn->press_serial_cb.arg = arg;
  332. btn->press_serial_cb.cb = cb;
  333. btn->press_serial_cb.interval = interval_tick;
  334. btn->press_serial_cb.pbtn = btn;
  335. #if !USE_ESP_TIMER
  336. xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
  337. #endif
  338. return ESP_OK;
  339. }
  340. esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg)
  341. {
  342. POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
  343. button_dev_t* btn = (button_dev_t*) btn_handle;
  344. if (type == BUTTON_CB_PUSH) {
  345. btn->tap_psh_cb.arg = arg;
  346. btn->tap_psh_cb.cb = cb;
  347. btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
  348. btn->tap_psh_cb.pbtn = btn;
  349. #if !USE_ESP_TIMER
  350. xTimerChangePeriod(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
  351. #endif
  352. } else if (type == BUTTON_CB_RELEASE) {
  353. btn->tap_rls_cb.arg = arg;
  354. btn->tap_rls_cb.cb = cb;
  355. btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
  356. btn->tap_rls_cb.pbtn = btn;
  357. #if !USE_ESP_TIMER
  358. xTimerChangePeriod(btn->tap_rls_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
  359. #endif
  360. } else if (type == BUTTON_CB_TAP) {
  361. btn->tap_short_cb.arg = arg;
  362. btn->tap_short_cb.cb = cb;
  363. btn->tap_short_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
  364. btn->tap_short_cb.pbtn = btn;
  365. } else if (type == BUTTON_CB_SERIAL) {
  366. iot_button_set_serial_cb(btn_handle, 1, 1000 / portTICK_PERIOD_MS, cb, arg);
  367. }
  368. return ESP_OK;
  369. }
  370. esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg)
  371. {
  372. POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
  373. IOT_CHECK(TAG, press_sec != 0, ESP_ERR_INVALID_ARG);
  374. button_dev_t* btn = (button_dev_t*) btn_handle;
  375. button_cb_t* cb_new = (button_cb_t*) calloc(1, sizeof(button_cb_t));
  376. POINT_ASSERT(TAG, cb_new, ESP_FAIL);
  377. cb_new->arg = arg;
  378. cb_new->cb = cb;
  379. cb_new->interval = press_sec * 1000 / portTICK_PERIOD_MS;
  380. cb_new->pbtn = btn;
  381. #if !USE_ESP_TIMER
  382. cb_new->tmr = xTimerCreate("btn_press_tmr", cb_new->interval, pdFALSE, cb_new, button_press_cb);
  383. #else
  384. esp_timer_create_args_t tmr_param_cus;
  385. tmr_param_cus.arg = cb_new;
  386. tmr_param_cus.callback = button_press_cb;
  387. tmr_param_cus.dispatch_method = ESP_TIMER_TASK;
  388. tmr_param_cus.name = "btn_press_custom_tmr";
  389. esp_timer_create(&tmr_param_cus, &cb_new->tmr);
  390. #endif
  391. cb_new->next_cb = btn->cb_head;
  392. btn->cb_head = cb_new;
  393. return ESP_OK;
  394. }