touch_button.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. // Licensed under the Apache License, Version 2.0 (the "License");
  2. // you may not use this file except in compliance with the License.
  3. // You may obtain a copy of the License at
  4. //
  5. // http://www.apache.org/licenses/LICENSE-2.0
  6. //
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS,
  9. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. // See the License for the specific language governing permissions and
  11. // limitations under the License.
  12. #include <string.h>
  13. #include <sys/queue.h>
  14. #include "freertos/FreeRTOS.h"
  15. #include "freertos/semphr.h"
  16. #include "esp_log.h"
  17. #include "touch_element/touch_element_private.h"
  18. typedef struct te_button_handle_list {
  19. te_button_handle_t button_handle; //Button handle
  20. SLIST_ENTRY(te_button_handle_list) next; //Button handle list entry
  21. } te_button_handle_list_t;
  22. typedef struct {
  23. SLIST_HEAD(te_button_handle_list_head, te_button_handle_list) handle_list; //Button handle (instance) list
  24. touch_button_global_config_t *global_config; //Button global configuration
  25. SemaphoreHandle_t mutex; //Button object mutex
  26. } te_button_obj_t;
  27. static te_button_obj_t *s_te_btn_obj = NULL; //Button object
  28. /* ---------------------------------------- Button handle(instance) methods ----------------------------------------- */
  29. static bool button_channel_check(te_button_handle_t button_handle, touch_pad_t channel_num);
  30. static esp_err_t button_set_threshold(te_button_handle_t button_handle);
  31. static inline te_state_t button_get_state(te_dev_t *device);
  32. static void button_reset_state(te_button_handle_t button_handle);
  33. static void button_update_state(te_button_handle_t button_handle, touch_pad_t channel_num, te_state_t channel_state);
  34. static void button_proc_state(te_button_handle_t button_handle);
  35. static void button_event_give(te_button_handle_t button_handle);
  36. static inline void button_dispatch(te_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method);
  37. /* ------------------------------------------ Button object(class) methods ------------------------------------------ */
  38. static esp_err_t button_object_add_instance(te_button_handle_t button_handle);
  39. static esp_err_t button_object_remove_instance(te_button_handle_t button_handle);
  40. static bool button_object_check_channel(touch_pad_t channel_num);
  41. static esp_err_t button_object_set_threshold(void);
  42. static void button_object_process_state(void);
  43. static void button_object_update_state(touch_pad_t channel_num, te_state_t channel_state);
  44. /* ------------------------------------------------------------------------------------------------------------------ */
  45. esp_err_t touch_button_install(const touch_button_global_config_t *global_config)
  46. {
  47. TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);
  48. TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);
  49. //Fixme: Make it thread-safe
  50. s_te_btn_obj = (te_button_obj_t *)calloc(1, sizeof(te_button_obj_t));
  51. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_NO_MEM);
  52. s_te_btn_obj->global_config = (touch_button_global_config_t *)calloc(1, sizeof(touch_button_global_config_t));
  53. s_te_btn_obj->mutex = xSemaphoreCreateMutex();
  54. TE_CHECK_GOTO(s_te_btn_obj->global_config != NULL && s_te_btn_obj->global_config != NULL, cleanup);
  55. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  56. SLIST_INIT(&s_te_btn_obj->handle_list);
  57. memcpy(s_te_btn_obj->global_config, global_config, sizeof(touch_button_global_config_t));
  58. te_object_methods_t button_methods = {
  59. .handle = s_te_btn_obj,
  60. .check_channel = button_object_check_channel,
  61. .set_threshold = button_object_set_threshold,
  62. .process_state = button_object_process_state,
  63. .update_state = button_object_update_state
  64. };
  65. te_object_method_register(&button_methods, TE_CLS_TYPE_BUTTON);
  66. xSemaphoreGive(s_te_btn_obj->mutex);
  67. return ESP_OK;
  68. cleanup:
  69. TE_FREE_AND_NULL(s_te_btn_obj->global_config);
  70. if (s_te_btn_obj->mutex != NULL) {
  71. vSemaphoreDelete(s_te_btn_obj->mutex);
  72. }
  73. TE_FREE_AND_NULL(s_te_btn_obj);
  74. return ESP_ERR_NO_MEM;
  75. }
  76. void touch_button_uninstall(void)
  77. {
  78. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  79. if (s_te_btn_obj == NULL) {
  80. xSemaphoreGive(s_te_btn_obj->mutex);
  81. return;
  82. }
  83. te_object_method_unregister(TE_CLS_TYPE_BUTTON);
  84. free(s_te_btn_obj->global_config);
  85. s_te_btn_obj->global_config = NULL;
  86. while (!SLIST_EMPTY(&s_te_btn_obj->handle_list)) {
  87. SLIST_FIRST(&s_te_btn_obj->handle_list);
  88. SLIST_REMOVE_HEAD(&s_te_btn_obj->handle_list, next);
  89. }
  90. xSemaphoreGive(s_te_btn_obj->mutex);
  91. vSemaphoreDelete(s_te_btn_obj->mutex);
  92. free(s_te_btn_obj);
  93. s_te_btn_obj = NULL;
  94. }
  95. esp_err_t touch_button_create(const touch_button_config_t *button_config, touch_button_handle_t *button_handle)
  96. {
  97. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  98. TE_CHECK(button_handle != NULL && button_config != NULL, ESP_ERR_INVALID_ARG);
  99. TE_CHECK(button_config->channel_num > TOUCH_PAD_NUM0 &&
  100. button_config->channel_num < TOUCH_PAD_MAX &&
  101. button_config->channel_sens > 0,
  102. ESP_ERR_INVALID_ARG);
  103. TE_CHECK(te_object_check_channel(&button_config->channel_num, 1) == false, ESP_ERR_INVALID_ARG);
  104. te_button_handle_t te_button = (te_button_handle_t)calloc(1, sizeof(struct te_button_s));
  105. TE_CHECK(te_button != NULL, ESP_ERR_NO_MEM);
  106. esp_err_t ret = ESP_ERR_NO_MEM;
  107. te_button->config = (te_button_handle_config_t *)calloc(1, sizeof(te_button_handle_config_t));
  108. te_button->device = (te_dev_t *)calloc(1, sizeof(te_dev_t));
  109. TE_CHECK_GOTO(te_button->config != NULL && te_button->device != NULL, cleanup);
  110. ret = te_dev_init(&te_button->device, 1, TOUCH_ELEM_TYPE_BUTTON,
  111. &button_config->channel_num, &button_config->channel_sens, TE_DEFAULT_THRESHOLD_DIVIDER(s_te_btn_obj));
  112. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  113. te_button->config->event_mask = TOUCH_ELEM_EVENT_NONE;
  114. te_button->config->dispatch_method = TOUCH_ELEM_DISP_MAX;
  115. te_button->config->callback = NULL;
  116. te_button->config->arg = NULL;
  117. te_button->current_state = TE_STATE_IDLE;
  118. te_button->last_state = TE_STATE_IDLE;
  119. te_button->event = TOUCH_BUTTON_EVT_MAX;
  120. te_button->trigger_cnt = 0;
  121. te_button->trigger_thr = 0xffffffff;
  122. ret = button_object_add_instance(te_button);
  123. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  124. *button_handle = (touch_elem_handle_t)te_button;
  125. ESP_LOGD(TE_DEBUG_TAG, "channel: %d, channel_sens: %f", button_config->channel_num, button_config->channel_sens);
  126. return ESP_OK;
  127. cleanup:
  128. TE_FREE_AND_NULL(te_button->config);
  129. TE_FREE_AND_NULL(te_button->device);
  130. TE_FREE_AND_NULL(te_button);
  131. return ret;
  132. }
  133. esp_err_t touch_button_delete(touch_button_handle_t button_handle)
  134. {
  135. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  136. TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);
  137. esp_err_t ret = button_object_remove_instance(button_handle);
  138. TE_CHECK(ret == ESP_OK, ret);
  139. te_button_handle_t te_button = (te_button_handle_t)button_handle;
  140. te_dev_deinit(&te_button->device, 1);
  141. free(te_button->config);
  142. free(te_button->device);
  143. free(te_button);
  144. return ESP_OK;
  145. }
  146. esp_err_t touch_button_set_dispatch_method(touch_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method)
  147. {
  148. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  149. TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);
  150. TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);
  151. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  152. te_button_handle_t te_button = (te_button_handle_t)button_handle;
  153. te_button->config->dispatch_method = dispatch_method;
  154. xSemaphoreGive(s_te_btn_obj->mutex);
  155. return ESP_OK;
  156. }
  157. esp_err_t touch_button_subscribe_event(touch_button_handle_t button_handle, uint32_t event_mask, void *arg)
  158. {
  159. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  160. TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);
  161. if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&
  162. !(event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) && !(event_mask & TOUCH_ELEM_EVENT_NONE)) {
  163. ESP_LOGE(TE_TAG, "Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, "
  164. "TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS event mask");
  165. return ESP_ERR_INVALID_ARG;
  166. }
  167. if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {
  168. touch_button_set_longpress(button_handle, TE_DEFAULT_LONGPRESS_TIME(s_te_btn_obj)); //set the default time(1000ms) for long press
  169. }
  170. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  171. te_button_handle_t te_button = (te_button_handle_t)button_handle;
  172. te_button->config->event_mask = event_mask;
  173. te_button->config->arg = arg;
  174. xSemaphoreGive(s_te_btn_obj->mutex);
  175. return ESP_OK;
  176. }
  177. esp_err_t touch_button_set_callback(touch_button_handle_t button_handle, touch_button_callback_t button_callback)
  178. {
  179. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  180. TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);
  181. TE_CHECK(button_callback != NULL, ESP_ERR_INVALID_ARG);
  182. te_button_handle_t te_button = (te_button_handle_t)button_handle;
  183. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  184. te_button->config->callback = button_callback;
  185. xSemaphoreGive(s_te_btn_obj->mutex);
  186. return ESP_OK;
  187. }
  188. esp_err_t touch_button_set_longpress(touch_button_handle_t button_handle, uint32_t threshold_time)
  189. {
  190. TE_CHECK(s_te_btn_obj != NULL, ESP_ERR_INVALID_STATE);
  191. TE_CHECK(button_handle != NULL, ESP_ERR_INVALID_ARG);
  192. TE_CHECK(threshold_time > 0, ESP_ERR_INVALID_ARG);
  193. te_button_handle_t te_button = (te_button_handle_t)button_handle;
  194. touch_elem_dispatch_t dispatch_method = te_button->config->dispatch_method;
  195. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  196. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  197. }
  198. uint8_t timer_period = te_get_timer_period();
  199. te_button->trigger_thr = threshold_time / timer_period;
  200. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  201. xSemaphoreGive(s_te_btn_obj->mutex);
  202. }
  203. return ESP_OK;
  204. }
  205. const touch_button_message_t* touch_button_get_message(const touch_elem_message_t* element_message)
  206. {
  207. return (touch_button_message_t*)&element_message->child_msg;
  208. _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_button_message_t), "Message size overflow");
  209. }
  210. static bool button_object_check_channel(touch_pad_t channel_num)
  211. {
  212. te_button_handle_list_t *item;
  213. SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
  214. if (button_channel_check(item->button_handle, channel_num)) {
  215. return true;
  216. }
  217. }
  218. return false;
  219. }
  220. static esp_err_t button_object_set_threshold(void)
  221. {
  222. esp_err_t ret = ESP_OK;
  223. te_button_handle_list_t *item;
  224. SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
  225. ret = button_set_threshold(item->button_handle);
  226. if (ret != ESP_OK) {
  227. break;
  228. }
  229. }
  230. return ret;
  231. }
  232. static void button_object_process_state(void)
  233. {
  234. te_button_handle_list_t *item;
  235. SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
  236. if (waterproof_check_mask_handle(item->button_handle)) {
  237. button_reset_state(item->button_handle);
  238. continue;
  239. }
  240. button_proc_state(item->button_handle);
  241. }
  242. }
  243. static void button_object_update_state(touch_pad_t channel_num, te_state_t channel_state)
  244. {
  245. te_button_handle_list_t *item;
  246. SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
  247. if (waterproof_check_mask_handle(item->button_handle)) {
  248. continue;
  249. }
  250. button_update_state(item->button_handle, channel_num, channel_state);
  251. }
  252. }
  253. static esp_err_t button_object_add_instance(te_button_handle_t button_handle)
  254. {
  255. te_button_handle_list_t *item = (te_button_handle_list_t *)calloc(1, sizeof(te_button_handle_list_t));
  256. TE_CHECK(item != NULL, ESP_ERR_NO_MEM);
  257. item->button_handle = button_handle;
  258. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  259. SLIST_INSERT_HEAD(&s_te_btn_obj->handle_list, item, next);
  260. xSemaphoreGive(s_te_btn_obj->mutex);
  261. return ESP_OK;
  262. }
  263. static esp_err_t button_object_remove_instance(te_button_handle_t button_handle)
  264. {
  265. esp_err_t ret = ESP_ERR_NOT_FOUND;
  266. te_button_handle_list_t *item;
  267. SLIST_FOREACH(item, &s_te_btn_obj->handle_list, next) {
  268. if (button_handle == item->button_handle) {
  269. xSemaphoreTake(s_te_btn_obj->mutex, portMAX_DELAY);
  270. SLIST_REMOVE(&s_te_btn_obj->handle_list, item, te_button_handle_list, next);
  271. xSemaphoreGive(s_te_btn_obj->mutex);
  272. free(item);
  273. ret = ESP_OK;
  274. break;
  275. }
  276. }
  277. return ret;
  278. }
  279. static bool button_channel_check(te_button_handle_t button_handle, touch_pad_t channel_num)
  280. {
  281. return (channel_num == button_handle->device->channel);
  282. }
  283. static esp_err_t button_set_threshold(te_button_handle_t button_handle)
  284. {
  285. return te_dev_set_threshold(button_handle->device);
  286. }
  287. static void button_update_state(te_button_handle_t button_handle, touch_pad_t channel_num, te_state_t channel_state)
  288. {
  289. te_dev_t *device = button_handle->device;
  290. if (channel_num != device->channel) {
  291. return;
  292. }
  293. device->state = channel_state;
  294. }
  295. static void button_reset_state(te_button_handle_t button_handle)
  296. {
  297. button_handle->trigger_cnt = 0;
  298. button_handle->current_state = TE_STATE_IDLE;
  299. button_handle->device->state = TE_STATE_IDLE;
  300. }
  301. static void button_event_give(te_button_handle_t button_handle)
  302. {
  303. touch_elem_message_t element_message;
  304. touch_button_message_t button_message = {
  305. .event = button_handle->event
  306. };
  307. element_message.handle = (touch_elem_handle_t)button_handle;
  308. element_message.element_type = TOUCH_ELEM_TYPE_BUTTON;
  309. element_message.arg = button_handle->config->arg;
  310. memcpy(element_message.child_msg, &button_message, sizeof(button_message));
  311. te_event_give(element_message);
  312. }
  313. static inline void button_dispatch(te_button_handle_t button_handle, touch_elem_dispatch_t dispatch_method)
  314. {
  315. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  316. button_event_give(button_handle); //Event queue
  317. } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {
  318. touch_button_message_t button_info;
  319. button_info.event = button_handle->event;
  320. button_handle->config->callback(button_handle, &button_info, button_handle->config->arg); //Event callback
  321. }
  322. }
  323. /**
  324. * @brief Button process
  325. *
  326. * This function will process the button state and maintain a button FSM:
  327. * IDLE ----> Press ----> Release ----> IDLE
  328. *
  329. * The state transition procedure is as follow:
  330. * (channel state ----> button state)
  331. *
  332. * TODO: add state transition diagram
  333. */
  334. static void button_proc_state(te_button_handle_t button_handle)
  335. {
  336. uint32_t event_mask = button_handle->config->event_mask;
  337. touch_elem_dispatch_t dispatch_method = button_handle->config->dispatch_method;
  338. BaseType_t mux_ret = xSemaphoreTake(s_te_btn_obj->mutex, 0);
  339. if (mux_ret != pdPASS) {
  340. return;
  341. }
  342. button_handle->current_state = button_get_state(button_handle->device);
  343. if (button_handle->current_state == TE_STATE_PRESS) {
  344. if (button_handle->last_state == TE_STATE_IDLE) { //IDLE ---> Press = On_Press
  345. ESP_LOGD(TE_DEBUG_TAG, "button press");
  346. if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {
  347. button_handle->event = TOUCH_BUTTON_EVT_ON_PRESS;
  348. button_dispatch(button_handle, dispatch_method);
  349. }
  350. } else if (button_handle->last_state == TE_STATE_PRESS) { //Press ---> Press = On_LongPress
  351. if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {
  352. if (++button_handle->trigger_cnt >= button_handle->trigger_thr) {
  353. ESP_LOGD(TE_DEBUG_TAG, "button longpress");
  354. button_handle->event = TOUCH_BUTTON_EVT_ON_LONGPRESS;
  355. button_dispatch(button_handle, dispatch_method);
  356. button_handle->trigger_cnt = 0;
  357. }
  358. }
  359. }
  360. } else if (button_handle->current_state == TE_STATE_RELEASE) {
  361. if (button_handle->last_state == TE_STATE_PRESS) { //Press ---> Release = On_Release
  362. ESP_LOGD(TE_DEBUG_TAG, "button release");
  363. if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {
  364. button_handle->event = TOUCH_BUTTON_EVT_ON_RELEASE;
  365. button_dispatch(button_handle, dispatch_method);
  366. }
  367. } else if (button_handle->last_state == TE_STATE_RELEASE) { // Release ---> Release = On_IDLE (Not dispatch)
  368. button_reset_state(button_handle); //Reset the button state for the next time touch action detection
  369. }
  370. } else if (button_handle->current_state == TE_STATE_IDLE) {
  371. if (button_handle->last_state == TE_STATE_RELEASE) { //Release ---> IDLE = On_IDLE (Not dispatch)
  372. //Nothing
  373. } else if (button_handle->last_state == TE_STATE_IDLE) { //IDLE ---> IDLE = Running IDLE (Not dispatch)
  374. //Nothing
  375. }
  376. }
  377. button_handle->last_state = button_handle->current_state;
  378. xSemaphoreGive(s_te_btn_obj->mutex);
  379. }
  380. static inline te_state_t button_get_state(te_dev_t *device)
  381. {
  382. te_state_t button_state;
  383. if (device->state == TE_STATE_PRESS) {
  384. button_state = TE_STATE_PRESS;
  385. } else if (device->state == TE_STATE_RELEASE) {
  386. button_state = TE_STATE_RELEASE;
  387. } else {
  388. button_state = TE_STATE_IDLE;
  389. }
  390. return button_state;
  391. }