touch_slider.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  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_SLD_DEFAULT_QTF_THR(obj) ((obj)->global_config->quantify_lower_threshold)
  19. #define TE_SLD_DEFAULT_POS_FILTER_FACTOR(obj) ((obj)->global_config->position_filter_factor)
  20. #define TE_SLD_DEFAULT_CALCULATE_CHANNEL(obj) ((obj)->global_config->calculate_channel_count)
  21. #define TE_SLD_DEFAULT_BCM_UPDATE_TIME(obj) ((obj)->global_config->benchmark_update_time)
  22. #define TE_SLD_DEFAULT_FILTER_RESET_TIME(obj) ((obj)->global_config->filter_reset_time)
  23. #define TE_SLD_DEFAULT_POS_FILTER_SIZE(obj) ((obj)->global_config->position_filter_size)
  24. typedef struct te_slider_handle_list {
  25. te_slider_handle_t slider_handle; //Slider handle
  26. SLIST_ENTRY(te_slider_handle_list) next; //Slider handle list entry
  27. } te_slider_handle_list_t;
  28. typedef struct {
  29. SLIST_HEAD(te_slider_handle_list_head, te_slider_handle_list) handle_list; //Slider handle (instance) list
  30. touch_slider_global_config_t *global_config; //Slider global configuration
  31. SemaphoreHandle_t mutex; //Slider object mutex
  32. } te_slider_obj_t;
  33. te_slider_obj_t *s_te_sld_obj = NULL;
  34. /* ---------------------------------------- Slider handle(instance) methods ----------------------------------------- */
  35. static bool slider_channel_check(te_slider_handle_t slider_handle, touch_pad_t channel_num);
  36. static esp_err_t slider_set_threshold(te_slider_handle_t slider_handle);
  37. static inline te_state_t slider_get_state(te_dev_t **device, int device_num);
  38. static void slider_reset_state(te_slider_handle_t slider_handle);
  39. static void slider_update_position(te_slider_handle_t slider_handle);
  40. static void slider_reset_position(te_slider_handle_t slider_handle);
  41. static void slider_update_benchmark(te_slider_handle_t slider_handle);
  42. static void slider_update_state(te_slider_handle_t slider_handle, touch_pad_t channel_num, te_state_t channel_state);
  43. static void slider_proc_state(te_slider_handle_t slider_handle);
  44. static void slider_event_give(te_slider_handle_t slider_handle);
  45. static inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method);
  46. /* ------------------------------------------ Slider object(class) methods ------------------------------------------ */
  47. static esp_err_t slider_object_add_instance(te_slider_handle_t slider_handle);
  48. static esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle);
  49. static bool slider_object_check_channel(touch_pad_t channel_num);
  50. static esp_err_t slider_object_set_threshold(void);
  51. static void slider_object_process_state(void);
  52. static void slider_object_update_state(touch_pad_t channel_num, te_state_t channel_state);
  53. /* ------------------------------------------------------------------------------------------------------------------ */
  54. esp_err_t touch_slider_install(const touch_slider_global_config_t *global_config)
  55. {
  56. TE_CHECK(te_system_check_state() == true, ESP_ERR_INVALID_STATE);
  57. TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);
  58. //Fixme: Make it thread-safe
  59. s_te_sld_obj = (te_slider_obj_t *)calloc(1, sizeof(te_slider_obj_t));
  60. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_NO_MEM);
  61. s_te_sld_obj->global_config = (touch_slider_global_config_t *)calloc(1, sizeof(touch_slider_global_config_t));
  62. s_te_sld_obj->mutex = xSemaphoreCreateMutex();
  63. TE_CHECK_GOTO(s_te_sld_obj->global_config != NULL && s_te_sld_obj->mutex != NULL, cleanup);
  64. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  65. SLIST_INIT(&s_te_sld_obj->handle_list);
  66. memcpy(s_te_sld_obj->global_config, global_config, sizeof(touch_slider_global_config_t));
  67. te_object_methods_t slider_methods = {
  68. .handle = s_te_sld_obj,
  69. .check_channel = slider_object_check_channel,
  70. .set_threshold = slider_object_set_threshold,
  71. .process_state = slider_object_process_state,
  72. .update_state = slider_object_update_state
  73. };
  74. te_object_method_register(&slider_methods, TE_CLS_TYPE_SLIDER);
  75. xSemaphoreGive(s_te_sld_obj->mutex);
  76. return ESP_OK;
  77. cleanup:
  78. TE_FREE_AND_NULL(s_te_sld_obj->global_config);
  79. if (s_te_sld_obj->mutex != NULL) {
  80. vSemaphoreDelete(s_te_sld_obj->mutex);
  81. }
  82. TE_FREE_AND_NULL(s_te_sld_obj);
  83. return ESP_ERR_NO_MEM;
  84. }
  85. void touch_slider_uninstall(void)
  86. {
  87. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  88. if (s_te_sld_obj == NULL) {
  89. xSemaphoreGive(s_te_sld_obj->mutex);
  90. return;
  91. }
  92. te_object_method_unregister(TE_CLS_TYPE_SLIDER);
  93. free(s_te_sld_obj->global_config);
  94. s_te_sld_obj->global_config = NULL;
  95. while (!SLIST_EMPTY(&s_te_sld_obj->handle_list)) {
  96. SLIST_FIRST(&s_te_sld_obj->handle_list);
  97. SLIST_REMOVE_HEAD(&s_te_sld_obj->handle_list, next);
  98. }
  99. xSemaphoreGive(s_te_sld_obj->mutex);
  100. vSemaphoreDelete(s_te_sld_obj->mutex);
  101. free(s_te_sld_obj);
  102. s_te_sld_obj = NULL;
  103. }
  104. esp_err_t touch_slider_create(const touch_slider_config_t *slider_config, touch_slider_handle_t *slider_handle)
  105. {
  106. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);
  107. TE_CHECK(slider_handle != NULL && slider_config != NULL, ESP_ERR_INVALID_ARG);
  108. TE_CHECK(slider_config->channel_num > 2 &&
  109. slider_config->channel_num < TOUCH_PAD_MAX &&
  110. slider_config->channel_array != NULL &&
  111. slider_config->sensitivity_array != NULL &&
  112. slider_config->position_range > slider_config->channel_num,
  113. ESP_ERR_INVALID_ARG);
  114. TE_CHECK(te_object_check_channel(slider_config->channel_array, slider_config->channel_num) == false,
  115. ESP_ERR_INVALID_ARG);
  116. te_slider_handle_t te_slider = (te_slider_handle_t)calloc(1, sizeof(struct te_slider_s));
  117. TE_CHECK(te_slider != NULL, ESP_ERR_NO_MEM);
  118. esp_err_t ret = ESP_ERR_NO_MEM;
  119. te_slider->config = (te_slider_handle_config_t *)calloc(1, sizeof(te_slider_handle_config_t));
  120. te_slider->pos_filter_window = calloc(TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj), sizeof(uint8_t));
  121. te_slider->device = (te_dev_t **)calloc(slider_config->channel_num, sizeof(te_dev_t *));
  122. te_slider->channel_bcm = (uint32_t *)calloc(slider_config->channel_num, sizeof(uint32_t));
  123. te_slider->quantify_signal_array = (float *)calloc(slider_config->channel_num, sizeof(float));
  124. TE_CHECK_GOTO(te_slider->config != NULL &&
  125. te_slider->pos_filter_window != NULL &&
  126. te_slider->device != NULL &&
  127. te_slider->channel_bcm &&
  128. te_slider->quantify_signal_array,
  129. cleanup);
  130. for (int idx = 0; idx < slider_config->channel_num; idx++) {
  131. te_slider->device[idx] = (te_dev_t *)calloc(1, sizeof(te_dev_t));
  132. if (te_slider->device[idx] == NULL) {
  133. ret = ESP_ERR_NO_MEM;
  134. goto cleanup;
  135. }
  136. }
  137. ret = te_dev_init(te_slider->device, slider_config->channel_num, TOUCH_ELEM_TYPE_SLIDER,
  138. slider_config->channel_array, slider_config->sensitivity_array,
  139. TE_DEFAULT_THRESHOLD_DIVIDER(s_te_sld_obj));
  140. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  141. te_slider->config->event_mask = TOUCH_ELEM_EVENT_NONE;
  142. te_slider->config->dispatch_method = TOUCH_ELEM_DISP_MAX;
  143. te_slider->config->callback = NULL;
  144. te_slider->config->arg = NULL;
  145. te_slider->channel_bcm_update_cnt = TE_SLD_DEFAULT_BCM_UPDATE_TIME(s_te_sld_obj); //update at first time
  146. te_slider->filter_reset_cnt = TE_SLD_DEFAULT_FILTER_RESET_TIME(s_te_sld_obj); //reset at first time
  147. te_slider->channel_sum = slider_config->channel_num;
  148. te_slider->position_range = slider_config->position_range;
  149. te_slider->position_scale = (float)(slider_config->position_range) / (slider_config->channel_num - 1);
  150. te_slider->current_state = TE_STATE_IDLE;
  151. te_slider->last_state = TE_STATE_IDLE;
  152. te_slider->event = TOUCH_SLIDER_EVT_MAX;
  153. te_slider->position = 0;
  154. te_slider->last_position = 0;
  155. te_slider->pos_window_idx = 0;
  156. te_slider->is_first_sample = true;
  157. ret = slider_object_add_instance(te_slider);
  158. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  159. *slider_handle = (touch_elem_handle_t)te_slider;
  160. return ESP_OK;
  161. cleanup:
  162. TE_FREE_AND_NULL(te_slider->config);
  163. TE_FREE_AND_NULL(te_slider->pos_filter_window);
  164. TE_FREE_AND_NULL(te_slider->channel_bcm);
  165. TE_FREE_AND_NULL(te_slider->quantify_signal_array);
  166. if (te_slider->device != NULL) {
  167. for (int idx = 0; idx < slider_config->channel_num; idx++) {
  168. TE_FREE_AND_NULL(te_slider->device[idx]);
  169. }
  170. free(te_slider->device);
  171. te_slider->device = NULL;
  172. }
  173. TE_FREE_AND_NULL(te_slider);
  174. return ret;
  175. }
  176. esp_err_t touch_slider_delete(touch_slider_handle_t slider_handle)
  177. {
  178. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);
  179. TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);
  180. /*< Release touch sensor application resource */
  181. esp_err_t ret = slider_object_remove_instance(slider_handle);
  182. TE_CHECK(ret == ESP_OK, ret);
  183. te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;
  184. /*< Release touch sensor device resource */
  185. te_dev_deinit(te_slider->device, te_slider->channel_sum);
  186. for (int idx = 0; idx < te_slider->channel_sum; idx++) {
  187. free(te_slider->device[idx]);
  188. }
  189. free(te_slider->config);
  190. free(te_slider->quantify_signal_array);
  191. free(te_slider->pos_filter_window);
  192. free(te_slider->channel_bcm);
  193. free(te_slider->device);
  194. free(te_slider);
  195. return ESP_OK;
  196. }
  197. esp_err_t touch_slider_set_dispatch_method(touch_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method)
  198. {
  199. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);
  200. TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);
  201. TE_CHECK(dispatch_method >= TOUCH_ELEM_DISP_EVENT && dispatch_method <= TOUCH_ELEM_DISP_MAX, ESP_ERR_INVALID_ARG);
  202. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  203. te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;
  204. te_slider->config->dispatch_method = dispatch_method;
  205. xSemaphoreGive(s_te_sld_obj->mutex);
  206. return ESP_OK;
  207. }
  208. esp_err_t touch_slider_subscribe_event(touch_slider_handle_t slider_handle, uint32_t event_mask, void *arg)
  209. {
  210. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);
  211. TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);
  212. if (!(event_mask & TOUCH_ELEM_EVENT_ON_PRESS) && !(event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) &&
  213. !(event_mask & TOUCH_ELEM_EVENT_NONE) && !(event_mask & TOUCH_ELEM_EVENT_ON_CALCULATION)) {
  214. ESP_LOGE(TE_TAG, "Touch button only support TOUCH_ELEM_EVENT_ON_PRESS, "
  215. "TOUCH_ELEM_EVENT_ON_RELEASE, TOUCH_ELEM_EVENT_ON_CALCULATION event mask");
  216. return ESP_ERR_INVALID_ARG;
  217. }
  218. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  219. te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;
  220. te_slider->config->event_mask = event_mask;
  221. te_slider->config->arg = arg;
  222. xSemaphoreGive(s_te_sld_obj->mutex);
  223. return ESP_OK;
  224. }
  225. esp_err_t touch_slider_set_callback(touch_slider_handle_t slider_handle, touch_slider_callback_t slider_callback)
  226. {
  227. TE_CHECK(s_te_sld_obj != NULL, ESP_ERR_INVALID_STATE);
  228. TE_CHECK(slider_handle != NULL, ESP_ERR_INVALID_ARG);
  229. TE_CHECK(slider_callback != NULL, ESP_ERR_INVALID_ARG);
  230. te_slider_handle_t te_slider = (te_slider_handle_t)slider_handle;
  231. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  232. te_slider->config->callback = slider_callback;
  233. xSemaphoreGive(s_te_sld_obj->mutex);
  234. return ESP_OK;
  235. }
  236. const touch_slider_message_t* touch_slider_get_message(const touch_elem_message_t* element_message)
  237. {
  238. return (touch_slider_message_t*)&element_message->child_msg;
  239. _Static_assert(sizeof(element_message->child_msg) >= sizeof(touch_slider_message_t), "Message size overflow");
  240. }
  241. static bool slider_object_check_channel(touch_pad_t channel_num)
  242. {
  243. te_slider_handle_list_t *item;
  244. SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
  245. if (slider_channel_check(item->slider_handle, channel_num)) {
  246. return true;
  247. }
  248. }
  249. return false;
  250. }
  251. static esp_err_t slider_object_set_threshold(void)
  252. {
  253. esp_err_t ret = ESP_OK;
  254. te_slider_handle_list_t *item;
  255. SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
  256. ret = slider_set_threshold(item->slider_handle);
  257. if (ret != ESP_OK) {
  258. break;
  259. }
  260. }
  261. return ret;
  262. }
  263. static void slider_object_process_state(void)
  264. {
  265. te_slider_handle_list_t *item;
  266. SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
  267. if (waterproof_check_mask_handle(item->slider_handle)) {
  268. slider_reset_state(item->slider_handle);
  269. slider_reset_position(item->slider_handle);
  270. continue;
  271. }
  272. slider_proc_state(item->slider_handle);
  273. }
  274. }
  275. static void slider_object_update_state(touch_pad_t channel_num, te_state_t channel_state)
  276. {
  277. te_slider_handle_list_t *item;
  278. SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
  279. if (waterproof_check_mask_handle(item->slider_handle)) {
  280. continue;
  281. }
  282. slider_update_state(item->slider_handle, channel_num, channel_state);
  283. }
  284. }
  285. static esp_err_t slider_object_add_instance(te_slider_handle_t slider_handle)
  286. {
  287. te_slider_handle_list_t *item = (te_slider_handle_list_t *)calloc(1, sizeof(te_slider_handle_list_t));
  288. TE_CHECK(item != NULL, ESP_ERR_NO_MEM);
  289. item->slider_handle = slider_handle;
  290. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  291. SLIST_INSERT_HEAD(&s_te_sld_obj->handle_list, item, next);
  292. xSemaphoreGive(s_te_sld_obj->mutex);
  293. return ESP_OK;
  294. }
  295. static esp_err_t slider_object_remove_instance(te_slider_handle_t slider_handle)
  296. {
  297. esp_err_t ret = ESP_ERR_NOT_FOUND;
  298. te_slider_handle_list_t *item;
  299. SLIST_FOREACH(item, &s_te_sld_obj->handle_list, next) {
  300. if (slider_handle == item->slider_handle) {
  301. xSemaphoreTake(s_te_sld_obj->mutex, portMAX_DELAY);
  302. SLIST_REMOVE(&s_te_sld_obj->handle_list, item, te_slider_handle_list, next);
  303. xSemaphoreGive(s_te_sld_obj->mutex);
  304. free(item);
  305. ret = ESP_OK;
  306. break;
  307. }
  308. }
  309. return ret;
  310. }
  311. static bool slider_channel_check(te_slider_handle_t slider_handle, touch_pad_t channel_num)
  312. {
  313. te_dev_t *device;
  314. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  315. device = slider_handle->device[idx];
  316. if (device->channel == channel_num) {
  317. return true;
  318. }
  319. }
  320. return false;
  321. }
  322. static esp_err_t slider_set_threshold(te_slider_handle_t slider_handle)
  323. {
  324. esp_err_t ret = ESP_OK;
  325. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  326. ret |= te_dev_set_threshold(slider_handle->device[idx]);
  327. }
  328. slider_update_benchmark(slider_handle); //Update benchmark at startup
  329. return ret;
  330. }
  331. static void slider_update_benchmark(te_slider_handle_t slider_handle)
  332. {
  333. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  334. uint32_t bcm_val;
  335. te_dev_t *device = slider_handle->device[idx];
  336. bcm_val = te_read_smooth_signal(device->channel);
  337. slider_handle->channel_bcm[idx] = bcm_val;
  338. }
  339. }
  340. static void slider_update_state(te_slider_handle_t slider_handle, touch_pad_t channel_num, te_state_t channel_state)
  341. {
  342. te_dev_t *device;
  343. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  344. device = slider_handle->device[idx];
  345. if (channel_num == device->channel) {
  346. device->state = channel_state;
  347. }
  348. }
  349. }
  350. static void slider_reset_state(te_slider_handle_t slider_handle)
  351. {
  352. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  353. slider_handle->device[idx]->state = TE_STATE_IDLE;
  354. }
  355. slider_handle->current_state = TE_STATE_IDLE;
  356. }
  357. static void slider_event_give(te_slider_handle_t slider_handle)
  358. {
  359. touch_elem_message_t element_message;
  360. touch_slider_message_t slider_message = {
  361. .event = slider_handle->event,
  362. .position = slider_handle->position
  363. };
  364. element_message.handle = (touch_elem_handle_t)slider_handle;
  365. element_message.element_type = TOUCH_ELEM_TYPE_SLIDER;
  366. element_message.arg = slider_handle->config->arg;
  367. memcpy(element_message.child_msg, &slider_message, sizeof(slider_message));
  368. te_event_give(element_message);
  369. }
  370. static inline void slider_dispatch(te_slider_handle_t slider_handle, touch_elem_dispatch_t dispatch_method)
  371. {
  372. if (dispatch_method == TOUCH_ELEM_DISP_EVENT) {
  373. slider_event_give(slider_handle); //Event queue
  374. } else if (dispatch_method == TOUCH_ELEM_DISP_CALLBACK) {
  375. touch_slider_message_t slider_info;
  376. slider_info.event = slider_handle->event;
  377. slider_info.position = slider_handle->position;
  378. void *arg = slider_handle->config->arg;
  379. slider_handle->config->callback(slider_handle, &slider_info, arg); //Event callback
  380. }
  381. }
  382. /**
  383. * @brief Slider process
  384. *
  385. * This function will process the slider state and maintain a slider FSM:
  386. * IDLE ----> Press ----> Release ----> IDLE
  387. *
  388. * The state transition procedure is as follow:
  389. * (channel state ----> slider state)
  390. *
  391. * TODO: add state transition diagram
  392. */
  393. static void slider_proc_state(te_slider_handle_t slider_handle)
  394. {
  395. uint32_t event_mask = slider_handle->config->event_mask;
  396. touch_elem_dispatch_t dispatch_method = slider_handle->config->dispatch_method;
  397. BaseType_t mux_ret = xSemaphoreTake(s_te_sld_obj->mutex, 0);
  398. if (mux_ret != pdPASS) {
  399. return;
  400. }
  401. slider_handle->current_state = slider_get_state(slider_handle->device, slider_handle->channel_sum);
  402. if (slider_handle->current_state == TE_STATE_PRESS) {
  403. slider_handle->channel_bcm_update_cnt = 0; // Reset benchmark update counter
  404. slider_update_position(slider_handle);
  405. if (slider_handle->last_state == TE_STATE_IDLE) { //IDLE ---> Press = On_Press
  406. ESP_LOGD(TE_DEBUG_TAG, "slider press");
  407. if (event_mask & TOUCH_ELEM_EVENT_ON_PRESS) {
  408. slider_handle->event = TOUCH_SLIDER_EVT_ON_PRESS;
  409. slider_dispatch(slider_handle, dispatch_method);
  410. }
  411. } else if (slider_handle->last_state == TE_STATE_PRESS) { //Press ---> Press = On_Calculation
  412. ESP_LOGD(TE_DEBUG_TAG, "slider calculation");
  413. if (event_mask & TOUCH_ELEM_EVENT_ON_CALCULATION) {
  414. slider_handle->event = TOUCH_SLIDER_EVT_ON_CALCULATION;
  415. slider_dispatch(slider_handle, dispatch_method);
  416. }
  417. }
  418. } else if (slider_handle->current_state == TE_STATE_RELEASE) {
  419. if (slider_handle->last_state == TE_STATE_PRESS) { //Press ---> Release = On_Release
  420. ESP_LOGD(TE_DEBUG_TAG, "slider release");
  421. if (event_mask & TOUCH_ELEM_EVENT_ON_RELEASE) {
  422. slider_handle->event = TOUCH_SLIDER_EVT_ON_RELEASE;
  423. slider_dispatch(slider_handle, dispatch_method);
  424. }
  425. } else if (slider_handle->last_state == TE_STATE_RELEASE) { // Release ---> Release = On_IDLE (Not dispatch)
  426. slider_reset_state(slider_handle);//Reset the slider state for the next time touch action detection
  427. }
  428. } else if (slider_handle->current_state == TE_STATE_IDLE) {
  429. if (slider_handle->last_state == TE_STATE_RELEASE) { //Release ---> IDLE = On_IDLE (Not dispatch)
  430. //Nothing
  431. } else if (slider_handle->last_state == TE_STATE_IDLE) { //IDLE ---> IDLE = Running IDLE (Not dispatch)
  432. if (++slider_handle->channel_bcm_update_cnt >= TE_SLD_DEFAULT_BCM_UPDATE_TIME(s_te_sld_obj)) { //Update channel benchmark
  433. slider_handle->channel_bcm_update_cnt = 0;
  434. slider_update_benchmark(slider_handle);
  435. ESP_LOGD(TE_DEBUG_TAG, "slider bcm update");
  436. }
  437. if (++slider_handle->filter_reset_cnt >= TE_SLD_DEFAULT_FILTER_RESET_TIME(s_te_sld_obj)) {
  438. slider_reset_position(slider_handle); //Reset slider filter so as to speed up next time position calculation
  439. }
  440. }
  441. }
  442. slider_handle->last_state = slider_handle->current_state;
  443. xSemaphoreGive(s_te_sld_obj->mutex);
  444. }
  445. static inline te_state_t slider_get_state(te_dev_t **device, int device_num)
  446. {
  447. /*< Scan the state of all the slider channel and calculate the number of them if the state is Press*/
  448. uint8_t press_cnt = 0;
  449. uint8_t idle_cnt = 0;
  450. for (int idx = 0; idx < device_num; idx++) { //Calculate how many channel is pressed
  451. if (device[idx]->state == TE_STATE_PRESS) {
  452. press_cnt++;
  453. } else if (device[idx]->state == TE_STATE_IDLE) {
  454. idle_cnt++;
  455. }
  456. }
  457. if (press_cnt > 0) {
  458. return TE_STATE_PRESS;
  459. } else if (idle_cnt == device_num) {
  460. return TE_STATE_IDLE;
  461. } else {
  462. return TE_STATE_RELEASE;
  463. }
  464. }
  465. /**
  466. * @brief Slider channel difference-rate re-quantization
  467. *
  468. * This function will re-quantifies the touch sensor slider channel difference-rate
  469. * so as to make the different size of touch pad in PCB has the same difference value
  470. *
  471. */
  472. static inline void slider_quantify_signal(te_slider_handle_t slider_handle)
  473. {
  474. float weight_sum = 0;
  475. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  476. te_dev_t *device = slider_handle->device[idx];
  477. weight_sum += device->sens;
  478. uint32_t current_signal = te_read_smooth_signal(device->channel);
  479. int ans = current_signal - slider_handle->channel_bcm[idx];
  480. float diff_rate = (float)ans / slider_handle->channel_bcm[idx];
  481. slider_handle->quantify_signal_array[idx] = diff_rate / device->sens;
  482. if (slider_handle->quantify_signal_array[idx] < TE_SLD_DEFAULT_QTF_THR(s_te_sld_obj)) {
  483. slider_handle->quantify_signal_array[idx] = 0;
  484. }
  485. }
  486. for (int idx = 0; idx < slider_handle->channel_sum; idx++) {
  487. te_dev_t *device = slider_handle->device[idx];
  488. slider_handle->quantify_signal_array[idx] = slider_handle->quantify_signal_array[idx] * weight_sum / device->sens;
  489. }
  490. }
  491. /**
  492. * @brief Calculate max sum subarray
  493. *
  494. * This function will figure out the max sum subarray from the
  495. * input array, return the max sum and max sum start index
  496. *
  497. */
  498. static inline float slider_search_max_subarray(const float *array, int array_size, int *max_array_idx)
  499. {
  500. *max_array_idx = 0;
  501. float max_array_sum = 0;
  502. float current_array_sum = 0;
  503. for (int idx = 0; idx <= (array_size - TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj)); idx++) {
  504. for (int x = idx; x < idx + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); x++) {
  505. current_array_sum += array[x];
  506. }
  507. if (max_array_sum < current_array_sum) {
  508. max_array_sum = current_array_sum;
  509. *max_array_idx = idx;
  510. }
  511. current_array_sum = 0;
  512. }
  513. return max_array_sum;
  514. }
  515. /**
  516. * @brief Calculate zero number
  517. *
  518. * This function will figure out the number of non-zero items from
  519. * the subarray
  520. */
  521. static inline uint8_t slider_get_non_zero_num(const float *array, uint8_t array_idx)
  522. {
  523. uint8_t zero_cnt = 0;
  524. for (int idx = array_idx; idx < array_idx + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); idx++) {
  525. zero_cnt += (array[idx] > 0) ? 1 : 0;
  526. }
  527. return zero_cnt;
  528. }
  529. static inline uint32_t slider_calculate_position(te_slider_handle_t slider_handle, int subarray_index, float subarray_sum, int non_zero_num)
  530. {
  531. int range = slider_handle->position_range;
  532. int array_size = slider_handle->channel_sum;
  533. float scale = slider_handle->position_scale;
  534. const float *array = slider_handle->quantify_signal_array;
  535. uint32_t position = 0;
  536. if (non_zero_num == 0) {
  537. position = slider_handle->position;
  538. } else if (non_zero_num == 1) {
  539. for (int index = subarray_index; index < subarray_index + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); index++) {
  540. if (0 != array[index]) {
  541. if (index == array_size - 1) {
  542. position = range;
  543. } else {
  544. position = (uint32_t)((float)index * scale);
  545. }
  546. break;
  547. }
  548. }
  549. } else {
  550. for (int idx = subarray_index; idx < subarray_index + TE_SLD_DEFAULT_CALCULATE_CHANNEL(s_te_sld_obj); idx++) {
  551. position += ((float)idx * array[idx]);
  552. }
  553. position = position * scale / subarray_sum;
  554. }
  555. return position;
  556. }
  557. static uint32_t slider_filter_average(te_slider_handle_t slider_handle, uint32_t current_position)
  558. {
  559. uint32_t position_average = 0;
  560. if (slider_handle->is_first_sample) {
  561. for (int win_idx = 0; win_idx < TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj); win_idx++) {
  562. slider_handle->pos_filter_window[win_idx] = current_position; //Preload filter buffer
  563. }
  564. slider_handle->is_first_sample = false;
  565. } else {
  566. slider_handle->pos_filter_window[slider_handle->pos_window_idx++] = current_position; //Moving average filter
  567. if (slider_handle->pos_window_idx >= TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj)) {
  568. slider_handle->pos_window_idx = 0;
  569. }
  570. }
  571. for (int win_idx = 0; win_idx < TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj); win_idx++) { //Moving average filter
  572. position_average += slider_handle->pos_filter_window[win_idx];
  573. }
  574. position_average = position_average / TE_SLD_DEFAULT_POS_FILTER_SIZE(s_te_sld_obj) + 0.5;
  575. return position_average;
  576. }
  577. static inline uint32_t slider_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k)
  578. {
  579. if (k == 0) {
  580. return in_now;
  581. } else {
  582. uint32_t out_now = (in_now + (k - 1) * out_last) / k;
  583. return out_now;
  584. }
  585. }
  586. /**
  587. * @brief touch sensor slider position update
  588. *
  589. * This function is the core algorithm about touch sensor slider
  590. * position update, mainly has several steps:
  591. * 1. Re-quantization
  592. * 2. Figure out changed channel
  593. * 3. Calculate position
  594. * 4. Filter
  595. *
  596. */
  597. static void slider_update_position(te_slider_handle_t slider_handle)
  598. {
  599. int max_array_idx = 0;
  600. float max_array_sum;
  601. uint8_t non_zero_num;
  602. uint32_t current_position;
  603. slider_quantify_signal(slider_handle);
  604. max_array_sum = slider_search_max_subarray(slider_handle->quantify_signal_array, slider_handle->channel_sum, &max_array_idx);
  605. non_zero_num = slider_get_non_zero_num(slider_handle->quantify_signal_array, max_array_idx);
  606. current_position = slider_calculate_position(slider_handle, max_array_idx, max_array_sum, non_zero_num);
  607. uint32_t position_average = slider_filter_average(slider_handle, current_position);
  608. slider_handle->last_position = slider_handle->last_position == 0 ? (position_average << 4) : slider_handle->last_position;
  609. slider_handle->last_position = slider_filter_iir((position_average << 4), slider_handle->last_position, TE_SLD_DEFAULT_POS_FILTER_FACTOR(s_te_sld_obj));
  610. slider_handle->position = ((slider_handle->last_position + 8) >> 4); //(x + 8) >> 4 ----> (x + 8) / 16 ----> x/16 + 0.5
  611. }
  612. static void slider_reset_position(te_slider_handle_t slider_handle)
  613. {
  614. slider_handle->is_first_sample = true;
  615. slider_handle->last_position = 0;
  616. slider_handle->pos_window_idx = 0;
  617. }