touch_matrix.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /*
  2. * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include <sys/queue.h>
  8. #include <inttypes.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include "freertos/semphr.h"
  11. #include "esp_log.h"
  12. #include "touch_element/touch_element_private.h"
  13. #define TE_MAT_POS_MAX (0xff) //!< Matrix button startup position
  14. typedef struct te_matrix_handle_list {
  15. te_matrix_handle_t matrix_handle; //Matrix handle
  16. SLIST_ENTRY(te_matrix_handle_list) next; //Matrix handle list entry
  17. } te_matrix_handle_list_t;
  18. typedef struct {
  19. SLIST_HEAD(te_matrix_handle_list_head, te_matrix_handle_list) handle_list; //Matrix handle (instance) list
  20. touch_matrix_global_config_t *global_config; //Matrix global configuration
  21. SemaphoreHandle_t mutex; //Matrix object mutex
  22. } te_matrix_obj_t;
  23. te_matrix_obj_t *s_te_mat_obj = NULL;
  24. /* ---------------------------------------- Matrix handle(instance) methods ----------------------------------------- */
  25. static bool matrix_channel_check(te_matrix_handle_t matrix_handle, touch_pad_t channel_num);
  26. static esp_err_t matrix_set_threshold(te_matrix_handle_t matrix_handle);
  27. static inline te_state_t matrix_get_state(te_matrix_state_t x_axis_state, te_matrix_state_t y_axis_state);
  28. static void matrix_reset_state(te_matrix_handle_t matrix_handle);
  29. static void matrix_update_state(te_matrix_handle_t matrix_handle, touch_pad_t channel_num, te_state_t channel_state);
  30. static void matrix_update_position(te_matrix_handle_t matrix_handle, touch_matrix_position_t new_pos);
  31. static void matrix_proc_state(te_matrix_handle_t matrix_handle);
  32. static void matrix_event_give(te_matrix_handle_t matrix_handle);
  33. static inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method);
  34. /* ------------------------------------------ Matrix object(class) methods ------------------------------------------ */
  35. static esp_err_t matrix_object_add_instance(te_matrix_handle_t matrix_handle);
  36. static esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle);
  37. static bool matrix_object_check_channel(touch_pad_t channel_num);
  38. static esp_err_t matrix_object_set_threshold(void);
  39. static void matrix_object_process_state(void);
  40. static void matrix_object_update_state(touch_pad_t channel_num, te_state_t channel_state);
  41. /* ------------------------------------------------------------------------------------------------------------------ */
  42. esp_err_t touch_matrix_install(const touch_matrix_global_config_t *global_config)
  43. {
  44. TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);
  45. TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);
  46. //Fixme: Make it thread-safe
  47. s_te_mat_obj = (te_matrix_obj_t *)calloc(1, sizeof(te_matrix_obj_t));
  48. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_NO_MEM);
  49. s_te_mat_obj->global_config = (touch_matrix_global_config_t *)calloc(1, sizeof(touch_matrix_global_config_t));
  50. s_te_mat_obj->mutex = xSemaphoreCreateMutex();
  51. TE_CHECK_GOTO(s_te_mat_obj->global_config != NULL && s_te_mat_obj->mutex != NULL, cleanup);
  52. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  53. SLIST_INIT(&s_te_mat_obj->handle_list);
  54. memcpy(s_te_mat_obj->global_config, global_config, sizeof(touch_matrix_global_config_t));
  55. te_object_methods_t matrix_methods = {
  56. .handle = s_te_mat_obj,
  57. .check_channel = matrix_object_check_channel,
  58. .set_threshold = matrix_object_set_threshold,
  59. .process_state = matrix_object_process_state,
  60. .update_state = matrix_object_update_state
  61. };
  62. te_object_method_register(&matrix_methods, TE_CLS_TYPE_MATRIX);
  63. xSemaphoreGive(s_te_mat_obj->mutex);
  64. return ESP_OK;
  65. cleanup:
  66. TE_FREE_AND_NULL(s_te_mat_obj->global_config);
  67. if (s_te_mat_obj->mutex != NULL) {
  68. vSemaphoreDelete(s_te_mat_obj->mutex);
  69. }
  70. TE_FREE_AND_NULL(s_te_mat_obj);
  71. return ESP_ERR_NO_MEM;
  72. }
  73. void touch_matrix_uninstall(void)
  74. {
  75. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  76. if (s_te_mat_obj == NULL) {
  77. xSemaphoreGive(s_te_mat_obj->mutex);
  78. return;
  79. }
  80. te_object_method_unregister(TE_CLS_TYPE_MATRIX);
  81. free(s_te_mat_obj->global_config);
  82. s_te_mat_obj->global_config = NULL;
  83. while (!SLIST_EMPTY(&s_te_mat_obj->handle_list)) {
  84. SLIST_FIRST(&s_te_mat_obj->handle_list);
  85. SLIST_REMOVE_HEAD(&s_te_mat_obj->handle_list, next);
  86. }
  87. xSemaphoreGive(s_te_mat_obj->mutex);
  88. vSemaphoreDelete(s_te_mat_obj->mutex);
  89. free(s_te_mat_obj);
  90. s_te_mat_obj = NULL;
  91. }
  92. esp_err_t touch_matrix_create(const touch_matrix_config_t *matrix_config, touch_matrix_handle_t *matrix_handle)
  93. {
  94. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  95. TE_CHECK(matrix_handle != NULL && matrix_config != NULL, ESP_ERR_INVALID_ARG);
  96. TE_CHECK(matrix_config->x_channel_array != NULL &&
  97. matrix_config->y_channel_array != NULL &&
  98. matrix_config->x_sensitivity_array != NULL &&
  99. matrix_config->y_sensitivity_array != NULL &&
  100. matrix_config->x_channel_num > 1 &&
  101. matrix_config->x_channel_num < TOUCH_PAD_MAX &&
  102. matrix_config->y_channel_num > 1 &&
  103. matrix_config->y_channel_num < TOUCH_PAD_MAX,
  104. ESP_ERR_INVALID_ARG);
  105. TE_CHECK(te_object_check_channel(matrix_config->x_channel_array, matrix_config->x_channel_num) == false &&
  106. te_object_check_channel(matrix_config->y_channel_array, matrix_config->y_channel_num) == false,
  107. ESP_ERR_INVALID_ARG);
  108. te_matrix_handle_t te_matrix = (te_matrix_handle_t)calloc(1, sizeof(struct te_slider_s));
  109. TE_CHECK(te_matrix != NULL, ESP_ERR_NO_MEM);
  110. esp_err_t ret = ESP_ERR_NO_MEM;
  111. te_matrix->config = (te_matrix_handle_config_t *)calloc(1, sizeof(te_matrix_handle_config_t));
  112. te_matrix->device = (te_dev_t **)calloc(matrix_config->x_channel_num + matrix_config->y_channel_num, sizeof(te_dev_t *));
  113. TE_CHECK_GOTO(te_matrix->config != NULL && te_matrix->device != NULL, cleanup);
  114. for (int idx = 0; idx < matrix_config->x_channel_num + matrix_config->y_channel_num; idx++) {
  115. te_matrix->device[idx] = (te_dev_t *)calloc(1, sizeof(te_dev_t));
  116. if (te_matrix->device[idx] == NULL) {
  117. ret = ESP_ERR_NO_MEM;
  118. goto cleanup;
  119. }
  120. }
  121. /*< Initialize x-axis */
  122. ret = te_dev_init(&te_matrix->device[0], matrix_config->x_channel_num, TOUCH_ELEM_TYPE_MATRIX,
  123. matrix_config->x_channel_array, matrix_config->x_sensitivity_array,
  124. TE_DEFAULT_THRESHOLD_DIVIDER(s_te_mat_obj));
  125. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  126. /*< Initialize y-axis */
  127. ret = te_dev_init(&te_matrix->device[matrix_config->x_channel_num], matrix_config->y_channel_num,
  128. TOUCH_ELEM_TYPE_MATRIX, matrix_config->y_channel_array, matrix_config->y_sensitivity_array,
  129. TE_DEFAULT_THRESHOLD_DIVIDER(s_te_mat_obj));
  130. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  131. te_matrix->config->event_mask = TOUCH_ELEM_EVENT_NONE;
  132. te_matrix->config->dispatch_method = TOUCH_ELEM_DISP_MAX;
  133. te_matrix->config->callback = NULL;
  134. te_matrix->config->arg = NULL;
  135. te_matrix->current_state = TE_STATE_IDLE;
  136. te_matrix->last_state = TE_STATE_IDLE;
  137. te_matrix->event = TOUCH_MATRIX_EVT_MAX;
  138. te_matrix->x_channel_num = matrix_config->x_channel_num;
  139. te_matrix->y_channel_num = matrix_config->y_channel_num;
  140. te_matrix->trigger_cnt = 0;
  141. te_matrix->trigger_thr = 0xffffffff;
  142. te_matrix->position.x_axis = TE_MAT_POS_MAX;
  143. te_matrix->position.y_axis = TE_MAT_POS_MAX;
  144. te_matrix->position.index = TE_MAT_POS_MAX;
  145. ret = matrix_object_add_instance(te_matrix);
  146. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  147. *matrix_handle = (touch_elem_handle_t) te_matrix;
  148. return ESP_OK;
  149. cleanup:
  150. TE_FREE_AND_NULL(te_matrix->config);
  151. if (te_matrix->device != NULL) {
  152. for (int idx = 0; idx < matrix_config->x_channel_num + matrix_config->y_channel_num; idx++) {
  153. TE_FREE_AND_NULL(te_matrix->device[idx]);
  154. }
  155. free(te_matrix->device);
  156. te_matrix->device = NULL;
  157. }
  158. TE_FREE_AND_NULL(te_matrix);
  159. return ret;
  160. }
  161. esp_err_t touch_matrix_delete(touch_matrix_handle_t matrix_handle)
  162. {
  163. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  164. TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);
  165. /*< Release touch sensor application resource */
  166. esp_err_t ret = matrix_object_remove_instance(matrix_handle);
  167. TE_CHECK(ret == ESP_OK, ret);
  168. te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;
  169. /*< Release touch sensor device resource */
  170. te_dev_deinit(te_matrix->device, te_matrix->x_channel_num + te_matrix->y_channel_num);
  171. for (int idx = 0; idx < te_matrix->x_channel_num + te_matrix->y_channel_num; idx++) {
  172. free(te_matrix->device[idx]);
  173. }
  174. free(te_matrix->config);
  175. free(te_matrix->device);
  176. free(te_matrix);
  177. return ESP_OK;
  178. }
  179. esp_err_t touch_matrix_set_dispatch_method(touch_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method)
  180. {
  181. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  182. TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);
  183. TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);
  184. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  185. te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;
  186. te_matrix->config->dispatch_method = dispatch_method;
  187. xSemaphoreGive(s_te_mat_obj->mutex);
  188. return ESP_OK;
  189. }
  190. esp_err_t touch_matrix_subscribe_event(touch_matrix_handle_t matrix_handle, uint32_t event_mask, void *arg)
  191. {
  192. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  193. TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);
  194. if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&
  195. !(event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) && !(event_mask & TOUCH_ELEM_EVENT_NONE)) {
  196. ESP_LOGE(TE_TAG, "Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, "
  197. "TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_LONGPRESS event mask");
  198. return ESP_ERR_INVALID_ARG;
  199. }
  200. if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {
  201. touch_matrix_set_longpress(matrix_handle, TE_DEFAULT_LONGPRESS_TIME(s_te_mat_obj)); //set the default time(1000ms) for long press
  202. }
  203. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  204. te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;
  205. te_matrix->config->event_mask = event_mask;
  206. te_matrix->config->arg = arg;
  207. xSemaphoreGive(s_te_mat_obj->mutex);
  208. return ESP_OK;
  209. }
  210. esp_err_t touch_matrix_set_callback(touch_matrix_handle_t matrix_handle, touch_matrix_callback_t matrix_callback)
  211. {
  212. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  213. TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);
  214. TE_CHECK(matrix_callback != NULL, ESP_ERR_INVALID_ARG);
  215. te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;
  216. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  217. te_matrix->config->callback = matrix_callback;
  218. xSemaphoreGive(s_te_mat_obj->mutex);
  219. return ESP_OK;
  220. }
  221. esp_err_t touch_matrix_set_longpress(touch_matrix_handle_t matrix_handle, uint32_t threshold_time)
  222. {
  223. TE_CHECK(s_te_mat_obj != NULL, ESP_ERR_INVALID_STATE);
  224. TE_CHECK(matrix_handle != NULL, ESP_ERR_INVALID_ARG);
  225. TE_CHECK(threshold_time > 0, ESP_ERR_INVALID_ARG);
  226. te_matrix_handle_t te_matrix = (te_matrix_handle_t)matrix_handle;
  227. touch_elem_dispatch_t dispatch_method = te_matrix->config->dispatch_method;
  228. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  229. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  230. }
  231. uint8_t timer_period = te_get_timer_period();
  232. te_matrix->trigger_thr = threshold_time / timer_period;
  233. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  234. xSemaphoreGive(s_te_mat_obj->mutex);
  235. }
  236. return ESP_OK;
  237. }
  238. const touch_matrix_message_t* touch_matrix_get_message(const touch_elem_message_t* element_message)
  239. {
  240. return (touch_matrix_message_t*)&element_message->child_msg;
  241. _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_matrix_message_t), "Message size overflow");
  242. }
  243. static bool matrix_object_check_channel(touch_pad_t channel_num)
  244. {
  245. te_matrix_handle_list_t *item;
  246. SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
  247. if (matrix_channel_check(item->matrix_handle, channel_num)) {
  248. return true;
  249. }
  250. }
  251. return false;
  252. }
  253. static esp_err_t matrix_object_set_threshold(void)
  254. {
  255. esp_err_t ret = ESP_OK;
  256. te_matrix_handle_list_t *item;
  257. SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
  258. ret = matrix_set_threshold(item->matrix_handle);
  259. if (ret != ESP_OK) {
  260. break;
  261. }
  262. }
  263. return ret;
  264. }
  265. static void matrix_object_process_state(void)
  266. {
  267. te_matrix_handle_list_t *item;
  268. SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
  269. if (waterproof_check_mask_handle(item->matrix_handle)) {
  270. matrix_reset_state(item->matrix_handle);
  271. continue;
  272. }
  273. matrix_proc_state(item->matrix_handle);
  274. }
  275. }
  276. static void matrix_object_update_state(touch_pad_t channel_num, te_state_t channel_state)
  277. {
  278. te_matrix_handle_list_t *item;
  279. SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
  280. if (waterproof_check_mask_handle(item->matrix_handle)) {
  281. continue;
  282. }
  283. matrix_update_state(item->matrix_handle, channel_num, channel_state);
  284. }
  285. }
  286. static esp_err_t matrix_object_add_instance(te_matrix_handle_t matrix_handle)
  287. {
  288. te_matrix_handle_list_t *item = (te_matrix_handle_list_t *)calloc(1, sizeof(te_matrix_handle_list_t));
  289. TE_CHECK(item != NULL, ESP_ERR_NO_MEM);
  290. item->matrix_handle = matrix_handle;
  291. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  292. SLIST_INSERT_HEAD(&s_te_mat_obj->handle_list, item, next);
  293. xSemaphoreGive(s_te_mat_obj->mutex);
  294. return ESP_OK;
  295. }
  296. static esp_err_t matrix_object_remove_instance(te_matrix_handle_t matrix_handle)
  297. {
  298. esp_err_t ret = ESP_ERR_NOT_FOUND;
  299. te_matrix_handle_list_t *item;
  300. SLIST_FOREACH(item, &s_te_mat_obj->handle_list, next) {
  301. if (matrix_handle == item->matrix_handle) {
  302. xSemaphoreTake(s_te_mat_obj->mutex, portMAX_DELAY);
  303. SLIST_REMOVE(&s_te_mat_obj->handle_list, item, te_matrix_handle_list, next);
  304. xSemaphoreGive(s_te_mat_obj->mutex);
  305. free(item);
  306. ret = ESP_OK;
  307. break;
  308. }
  309. }
  310. return ret;
  311. }
  312. static bool matrix_channel_check(te_matrix_handle_t matrix_handle, touch_pad_t channel_num)
  313. {
  314. te_dev_t *device;
  315. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  316. device = matrix_handle->device[idx];
  317. if (device->channel == channel_num) {
  318. return true;
  319. }
  320. }
  321. return false;
  322. }
  323. static esp_err_t matrix_set_threshold(te_matrix_handle_t matrix_handle)
  324. {
  325. esp_err_t ret = ESP_OK;
  326. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  327. ret |= te_dev_set_threshold(matrix_handle->device[idx]);
  328. }
  329. return ret;
  330. }
  331. static void matrix_update_state(te_matrix_handle_t matrix_handle, touch_pad_t channel_num, te_state_t channel_state)
  332. {
  333. te_dev_t *device;
  334. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  335. device = matrix_handle->device[idx];
  336. if (channel_num == device->channel) {
  337. device->state = channel_state;
  338. }
  339. }
  340. }
  341. static void matrix_reset_state(te_matrix_handle_t matrix_handle)
  342. {
  343. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  344. matrix_handle->device[idx]->state = TE_STATE_IDLE;
  345. }
  346. matrix_handle->trigger_cnt = 0;
  347. matrix_handle->current_state = TE_STATE_IDLE;
  348. }
  349. static void matrix_event_give(te_matrix_handle_t matrix_handle)
  350. {
  351. touch_elem_message_t element_message;
  352. touch_matrix_message_t matrix_message = {
  353. .event = matrix_handle->event,
  354. .position = matrix_handle->position
  355. };
  356. element_message.handle = (touch_elem_handle_t)matrix_handle;
  357. element_message.element_type = TOUCH_ELEM_TYPE_MATRIX;
  358. element_message.arg = matrix_handle->config->arg;
  359. memcpy(element_message.child_msg, &matrix_message, sizeof(matrix_message));
  360. te_event_give(element_message);
  361. }
  362. static inline void matrix_dispatch(te_matrix_handle_t matrix_handle, touch_elem_dispatch_t dispatch_method)
  363. {
  364. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  365. matrix_event_give(matrix_handle); //Event queue
  366. } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {
  367. touch_matrix_message_t matrix_info;
  368. matrix_info.event = matrix_handle->event;
  369. matrix_info.position = matrix_handle->position;
  370. void *arg = matrix_handle->config->arg;
  371. matrix_handle->config->callback(matrix_handle, &matrix_info, arg); //Event callback
  372. }
  373. }
  374. /**
  375. * @brief Scan the matrix channel
  376. *
  377. * This function will output the press position and release position info
  378. * so as to determine which operation(press/release) is happening, since there
  379. * will get the invalid state if user operates multi-points at the same time.
  380. *
  381. */
  382. static void matrix_scan_axis(te_matrix_handle_t matrix_handle, touch_matrix_position_t *press_pos,
  383. uint8_t *press_cnt, touch_matrix_position_t *release_pos, uint8_t *release_cnt)
  384. {
  385. press_pos->x_axis = TE_MAT_POS_MAX;
  386. press_pos->y_axis = TE_MAT_POS_MAX;
  387. release_pos->x_axis = TE_MAT_POS_MAX;
  388. release_pos->y_axis = TE_MAT_POS_MAX;
  389. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  390. te_dev_t *device = matrix_handle->device[idx];
  391. if (device->state == TE_STATE_PRESS) {
  392. if (idx < matrix_handle->x_channel_num) {
  393. press_pos->x_axis = idx; //Write down the x axis info
  394. } else {
  395. press_pos->y_axis = idx - matrix_handle->x_channel_num; //Write down the y axis info
  396. }
  397. (*press_cnt)++;
  398. } else if (device->state == TE_STATE_RELEASE) {
  399. if (idx < matrix_handle->x_channel_num) {
  400. release_pos->x_axis = idx;
  401. } else {
  402. release_pos->y_axis = idx - matrix_handle->x_channel_num;
  403. }
  404. (*release_cnt)++;
  405. }
  406. }
  407. }
  408. /**
  409. * @brief Pre-check and fix
  410. *
  411. * This function will pre-check and fix the invalid state, preparing for the
  412. * next detection.
  413. *
  414. */
  415. static void matrix_pre_fixed(te_matrix_handle_t matrix_handle, touch_matrix_position_t *press_pos,
  416. uint8_t press_cnt, touch_matrix_position_t *release_pos, uint8_t release_cnt)
  417. {
  418. te_dev_t *device;
  419. te_matrix_state_t last_state = matrix_handle->current_state;
  420. touch_matrix_position_t last_pos = {
  421. .x_axis = matrix_handle->position.x_axis,
  422. .y_axis = matrix_handle->position.y_axis
  423. };
  424. if (last_state == TE_STATE_IDLE) {
  425. if (release_cnt > 0) {
  426. /*< Release is not allowed while matrix is in IDLE state, */
  427. /*< if that happened, reset it from Release into IDLE. */
  428. for (int idx = 0; idx < matrix_handle->x_channel_num + matrix_handle->y_channel_num; idx++) {
  429. device = matrix_handle->device[idx];
  430. if (device->state != TE_STATE_RELEASE) {
  431. continue;
  432. }
  433. device->state = TE_STATE_IDLE; //Reset to IDLE
  434. }
  435. }
  436. } else if (last_state == TE_STATE_PRESS) {
  437. if (release_cnt > 0) {
  438. /*< Release position must be the same as the last Press position, */
  439. /*< if it is not, reset it into IDLE. */
  440. if (release_pos->x_axis != TE_MAT_POS_MAX && release_pos->x_axis != last_pos.x_axis) {
  441. device = matrix_handle->device[release_pos->x_axis];
  442. device->state = TE_STATE_IDLE;
  443. }
  444. if (release_pos->y_axis != TE_MAT_POS_MAX && release_pos->y_axis != last_pos.y_axis) {
  445. device = matrix_handle->device[release_pos->y_axis + matrix_handle->x_channel_num];
  446. device->state = TE_STATE_IDLE;
  447. }
  448. }
  449. if (press_cnt > 2) { //TODO: remove or rewrite here
  450. /*< If the last state is Press and current press count more than 2, */
  451. /*< there must be multi-touch occurred, reset all of the channels */
  452. /*< into IDLE except the last position channels. */
  453. if (press_pos->x_axis != TE_MAT_POS_MAX && press_pos->x_axis != last_pos.x_axis) {
  454. device = matrix_handle->device[press_pos->x_axis];
  455. device->state = TE_STATE_IDLE;
  456. }
  457. if (press_pos->y_axis != TE_MAT_POS_MAX && press_pos->y_axis != last_pos.y_axis) {
  458. device = matrix_handle->device[press_pos->y_axis + matrix_handle->x_channel_num];
  459. device->state = TE_STATE_IDLE;
  460. }
  461. }
  462. }
  463. }
  464. //TODO: refactor this ugly implementation
  465. static esp_err_t matrix_get_axis_state(touch_matrix_position_t *press_pos, uint8_t press_cnt, touch_matrix_position_t *release_pos,
  466. uint8_t release_cnt, te_matrix_state_t *x_axis_state, te_matrix_state_t *y_axis_state)
  467. {
  468. esp_err_t ret;
  469. if (press_cnt >= 2) {
  470. if (press_pos->x_axis != TE_MAT_POS_MAX && press_pos->y_axis != TE_MAT_POS_MAX) {
  471. *x_axis_state = TE_STATE_PRESS;
  472. *y_axis_state = TE_STATE_PRESS;
  473. ret = ESP_OK;
  474. } else {
  475. ret = ESP_ERR_INVALID_STATE;
  476. }
  477. } else if (release_cnt >= 2) {
  478. if (release_pos->x_axis != TE_MAT_POS_MAX && release_pos->y_axis != TE_MAT_POS_MAX) {
  479. *x_axis_state = TE_STATE_RELEASE;
  480. *y_axis_state = TE_STATE_RELEASE;
  481. ret = ESP_OK;
  482. } else {
  483. ret = ESP_ERR_INVALID_STATE;
  484. }
  485. } else {
  486. ret = ESP_ERR_INVALID_STATE;
  487. }
  488. return ret;
  489. }
  490. /**
  491. * @brief Matrix button process
  492. *
  493. * This function will process the matrix button state and maintain a matrix FSM:
  494. * IDLE ----> Press ----> Release ----> IDLE
  495. *
  496. * The state transition procedure is as follow:
  497. * (channel state ----> x,y axis state ----> matrix button state)
  498. *
  499. * TODO: add state transition diagram
  500. */
  501. static void matrix_proc_state(te_matrix_handle_t matrix_handle)
  502. {
  503. esp_err_t ret;
  504. uint8_t press_cnt = 0;
  505. uint8_t release_cnt = 0;
  506. touch_matrix_position_t press_pos;
  507. touch_matrix_position_t release_pos;
  508. te_matrix_state_t x_axis_state = TE_STATE_IDLE;
  509. te_matrix_state_t y_axis_state = TE_STATE_IDLE;
  510. uint32_t event_mask = matrix_handle->config->event_mask;
  511. touch_elem_dispatch_t dispatch_method = matrix_handle->config->dispatch_method;
  512. BaseType_t mux_ret = xSemaphoreTake(s_te_mat_obj->mutex, 0);
  513. if (mux_ret != pdPASS) {
  514. return;
  515. }
  516. //TODO: refactor those functions
  517. /*< Scan the state of all the matrix buttons channel */
  518. matrix_scan_axis(matrix_handle, &press_pos, &press_cnt, &release_pos, &release_cnt);
  519. /*< Pre check and fixed the invalid state */
  520. matrix_pre_fixed(matrix_handle, &press_pos, press_cnt, &release_pos, release_cnt);
  521. /*< Figure out x,y axis state and take the position */
  522. ret = matrix_get_axis_state(&press_pos, press_cnt, &release_pos, release_cnt, &x_axis_state, &y_axis_state);
  523. if (ret != ESP_OK) { //TODO: remove return
  524. xSemaphoreGive(s_te_mat_obj->mutex);
  525. return;
  526. }
  527. matrix_handle->current_state = matrix_get_state(x_axis_state, y_axis_state);
  528. if (matrix_handle->current_state == TE_STATE_PRESS) {
  529. if (matrix_handle->last_state == TE_STATE_IDLE) { //IDLE ---> Press = On_Press
  530. matrix_update_position(matrix_handle, press_pos);
  531. ESP_LOGD(TE_DEBUG_TAG, "matrix press (%"PRIu8", %"PRIu8")", matrix_handle->position.x_axis, matrix_handle->position.y_axis);
  532. if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {
  533. matrix_handle->event = TOUCH_MATRIX_EVT_ON_PRESS;
  534. matrix_dispatch(matrix_handle, dispatch_method);
  535. }
  536. } else if (matrix_handle->last_state == TE_STATE_PRESS) { //Press ---> Press = On_LongPress
  537. if (event_mask & TOUCH_ELEM_EVENT_ON_LONGPRESS) {
  538. if (++matrix_handle->trigger_cnt >= matrix_handle->trigger_thr) {
  539. ESP_LOGD(TE_DEBUG_TAG, "matrix longpress (%"PRIu8", %"PRIu8")", matrix_handle->position.x_axis, matrix_handle->position.y_axis);
  540. matrix_handle->event = TOUCH_MATRIX_EVT_ON_LONGPRESS;
  541. matrix_dispatch(matrix_handle, dispatch_method);
  542. matrix_handle->trigger_cnt = 0;
  543. }
  544. }
  545. }
  546. } else if (matrix_handle->current_state == TE_STATE_RELEASE) {
  547. if (matrix_handle->last_state == TE_STATE_PRESS) { //Press ---> Release = On_Release
  548. ESP_LOGD(TE_DEBUG_TAG, "matrix release (%"PRIu8", %"PRIu8")", matrix_handle->position.x_axis, matrix_handle->position.y_axis);
  549. if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {
  550. matrix_handle->event = TOUCH_MATRIX_EVT_ON_RELEASE;
  551. matrix_dispatch(matrix_handle, dispatch_method);
  552. }
  553. } else if (matrix_handle->last_state == TE_STATE_RELEASE) { // Release ---> Release = On_IDLE (Not dispatch)
  554. matrix_reset_state(matrix_handle);
  555. }
  556. } else if (matrix_handle->current_state == TE_STATE_IDLE) {
  557. if (matrix_handle->last_state == TE_STATE_RELEASE) { //Release ---> IDLE = On_IDLE (Not dispatch)
  558. //Nothing
  559. } else if (matrix_handle->last_state == TE_STATE_IDLE) { //IDLE ---> IDLE = Running IDLE (Not dispatch)
  560. //Move Pre-fix into here
  561. }
  562. }
  563. matrix_handle->last_state = matrix_handle->current_state;
  564. xSemaphoreGive(s_te_mat_obj->mutex);
  565. }
  566. static inline te_state_t matrix_get_state(te_matrix_state_t x_axis_state, te_matrix_state_t y_axis_state)
  567. {
  568. te_state_t matrix_state;
  569. if ((x_axis_state == TE_STATE_PRESS) && (y_axis_state == TE_STATE_PRESS)) {
  570. matrix_state = TE_STATE_PRESS;
  571. } else if ((x_axis_state == TE_STATE_RELEASE) && (y_axis_state == TE_STATE_RELEASE)) {
  572. matrix_state = TE_STATE_RELEASE;
  573. } else {
  574. matrix_state = TE_STATE_IDLE;
  575. }
  576. return matrix_state;
  577. }
  578. static void matrix_update_position(te_matrix_handle_t matrix_handle, touch_matrix_position_t new_pos) {
  579. matrix_handle->position.x_axis = new_pos.x_axis;
  580. matrix_handle->position.y_axis = new_pos.y_axis;
  581. matrix_handle->position.index = matrix_handle->position.x_axis * matrix_handle->y_channel_num + matrix_handle->position.y_axis;
  582. }