touch_matrix.c 27 KB

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