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