touch_element.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. // Copyright 2016-2020 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <string.h>
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/semphr.h"
  17. #include "freertos/queue.h"
  18. #include "esp_timer.h"
  19. #include "esp_log.h"
  20. #include "hal/touch_sensor_hal.h" //TODO: remove hal
  21. #include "touch_element/touch_element_private.h"
  22. #define TE_CLASS_ITEM(cls, cls_type, cls_item) ((&((cls)[cls_type]))->cls_item)
  23. #define TE_CLASS_FOREACH(cls_var, cls_start, cls_end) \
  24. for ((cls_var) = (cls_start); \
  25. (cls_var) < (cls_end); \
  26. (cls_var)++)
  27. #define TE_CLS_METHODS_INITIALIZER(cls, cls_start, cls_end) do { \
  28. typeof(cls_start) cls_method; \
  29. TE_CLASS_FOREACH(cls_method, cls_start, cls_end) { \
  30. TE_CLASS_ITEM(cls, cls_method, handle) = NULL; \
  31. } \
  32. } while (0)
  33. #define TE_CLASS_FOREACH_CHECK_CHANNEL(cls, cls_start, cls_end, channel) ({ \
  34. bool ret = false; \
  35. typeof(cls_start) cls_method; \
  36. TE_CLASS_FOREACH(cls_method, cls_start, cls_end) { \
  37. if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) { \
  38. ret |= TE_CLASS_ITEM(cls, cls_method, check_channel(channel)); \
  39. } \
  40. } \
  41. ret; \
  42. })
  43. #define TE_CLASS_FOREACH_SET_THRESHOLD(cls, cls_start, cls_end) do { \
  44. typeof(cls_start) cls_method; \
  45. TE_CLASS_FOREACH(cls_method, cls_start, cls_end) { \
  46. if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) { \
  47. TE_CLASS_ITEM(cls, cls_method, set_threshold()); \
  48. } \
  49. } \
  50. } while (0)
  51. #define TE_CLASS_FOREACH_PROCESS_STATE(cls, cls_start, cls_end) do { \
  52. typeof(cls_start) cls_method; \
  53. TE_CLASS_FOREACH(cls_method, cls_start, cls_end) { \
  54. if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) { \
  55. TE_CLASS_ITEM(cls, cls_method, process_state()); \
  56. } \
  57. } \
  58. } while (0)
  59. #define TE_CLASS_FOREACH_UPDATE_STATE(cls, cls_start, cls_end, channel, state) do {\
  60. typeof(cls_start) cls_method; \
  61. TE_CLASS_FOREACH(cls_method, cls_start, cls_end) { \
  62. if (TE_CLASS_ITEM(cls, cls_method, handle) != NULL) { \
  63. TE_CLASS_ITEM(cls, cls_method, update_state(channel, state)); \
  64. } \
  65. } \
  66. } while (0)
  67. #define TE_PROCESSING_PERIOD(obj) ((obj)->global_config->software.processing_period)
  68. #define TE_WATERPROOF_DIVIDER(obj) ((obj)->global_config->software.waterproof_threshold_divider)
  69. typedef enum {
  70. TE_INTR_PRESS = 0, //Touch sensor press interrupt(TOUCH_PAD_INTR_MASK_ACTIVE)
  71. TE_INTR_RELEASE, //Touch sensor release interrupt(TOUCH_PAD_INTR_MASK_INACTIVE)
  72. TE_INTR_TIMEOUT, //Touch sensor scan timeout interrupt(TOUCH_PAD_INTR_MASK_TIMEOUT)
  73. TE_INTR_SCAN_DONE, //Touch sensor scan done interrupt(TOUCH_PAD_INTR_MASK_SCAN_DONE), now just use for setting threshold
  74. TE_INTR_MAX
  75. } te_intr_t;
  76. typedef struct {
  77. te_intr_t intr_type; //channel interrupt type
  78. te_state_t channel_state; //channel state
  79. touch_pad_t channel_num; //channel index
  80. } te_intr_msg_t;
  81. typedef struct {
  82. te_object_methods_t object_methods[TE_CLS_TYPE_MAX]; //Class(object) methods
  83. touch_elem_global_config_t *global_config; //Global initialization
  84. te_waterproof_handle_t waterproof_handle; //Waterproof configuration
  85. esp_timer_handle_t proc_timer; //Processing timer handle
  86. QueueHandle_t event_msg_queue; //Application event message queue (for user)
  87. QueueHandle_t intr_msg_queue; //Interrupt message (for internal)
  88. SemaphoreHandle_t mutex; //Global resource mutex
  89. bool is_set_threshold; //Threshold configuration state bit
  90. uint32_t denoise_channel_raw; //De-noise channel(TO) raw signal
  91. } te_obj_t;
  92. static te_obj_t *s_te_obj = NULL;
  93. /**
  94. * Internal de-noise channel(Touch channel 0) equivalent capacitance table, depends on hardware design
  95. *
  96. * Units: pF
  97. */
  98. static const float denoise_channel_equ_cap[TOUCH_PAD_DENOISE_CAP_MAX] = {5.0f, 6.4f, 7.8f, 9.2f, 10.6f, 12.0f, 13.4f, 14.8f};
  99. /**
  100. * Waterproof shield channel(Touch channel 14) equivalent capacitance table, depends on hardware design
  101. *
  102. * Units: pF
  103. */
  104. static const float shield_channel_ref_cap[TOUCH_PAD_SHIELD_DRV_MAX] = {40.0f, 80.0f, 120.0f, 160.0f, 200.0f, 240.0f, 280.0f, 320.0f};
  105. /* -------------------------------------------- Internal shared methods --------------------------------------------- */
  106. /* ------------------------------------------------- */
  107. /* ------------------------------------------------- System methods ------------------------------------------------- */
  108. static esp_err_t te_hw_init(const touch_elem_hw_config_t *hardware_init);
  109. static esp_err_t te_sw_init(const touch_elem_sw_config_t *software_init);
  110. static inline float te_get_internal_equ_cap(touch_pad_denoise_cap_t denoise_level);
  111. static float te_channel_get_equ_cap(touch_pad_t channel_num);
  112. static uint32_t te_read_raw_signal(touch_pad_t channel_num);
  113. static void te_intr_cb(void *arg);
  114. static void te_proc_timer_cb(void *arg);
  115. static inline esp_err_t te_object_set_threshold(void);
  116. static inline void te_object_process_state(void);
  117. static inline void te_object_update_state(te_intr_msg_t te_intr_msg);
  118. /* ----------------------------------------------- Waterproof methods ----------------------------------------------- */
  119. static inline bool waterproof_check_state(void);
  120. static inline bool waterproof_shield_check_state(void);
  121. static inline bool waterproof_guard_check_state(void);
  122. static bool waterproof_channel_check(touch_pad_t channel_num);
  123. static void waterproof_guard_set_threshold(void);
  124. static void waterproof_guard_update_state(touch_pad_t current_channel, te_state_t current_state);
  125. static touch_pad_shield_driver_t waterproof_get_shield_level(touch_pad_t guard_channel_num);
  126. /* ------------------------------------------------------------------------------------------------------------------ */
  127. esp_err_t touch_element_install(const touch_elem_global_config_t *global_config)
  128. {
  129. TE_CHECK(s_te_obj == NULL, ESP_ERR_INVALID_STATE);
  130. TE_CHECK(global_config != NULL, ESP_ERR_INVALID_ARG);
  131. s_te_obj = (te_obj_t *)calloc(1, sizeof(te_obj_t));
  132. TE_CHECK(s_te_obj != NULL, ESP_ERR_NO_MEM);
  133. esp_err_t ret = ESP_ERR_NO_MEM;
  134. s_te_obj->global_config = (touch_elem_global_config_t *)calloc(1, sizeof(touch_elem_global_config_t));
  135. s_te_obj->mutex = xSemaphoreCreateMutex();
  136. TE_CHECK_GOTO(s_te_obj->global_config != NULL && s_te_obj->mutex != NULL, cleanup);
  137. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  138. TE_CLS_METHODS_INITIALIZER(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);
  139. ret = te_hw_init(&global_config->hardware);
  140. if (ret != ESP_OK) {
  141. abort();
  142. }
  143. ret = te_sw_init(&global_config->software);
  144. if (ret != ESP_OK) {
  145. xSemaphoreGive(s_te_obj->mutex);
  146. goto cleanup;
  147. }
  148. xSemaphoreGive(s_te_obj->mutex);
  149. return ESP_OK;
  150. cleanup:
  151. TE_FREE_AND_NULL(s_te_obj->global_config);
  152. if (s_te_obj->mutex != NULL) {
  153. vSemaphoreDelete(s_te_obj->mutex);
  154. }
  155. TE_FREE_AND_NULL(s_te_obj);
  156. return ret;
  157. }
  158. esp_err_t touch_element_start(void)
  159. {
  160. TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
  161. esp_err_t ret;
  162. uint16_t inited_channel_mask;
  163. do {
  164. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  165. ret = touch_pad_get_channel_mask(&inited_channel_mask);
  166. if (inited_channel_mask == 0x0) {
  167. ESP_LOGE(TE_TAG, "Can not find Touch Sensor channel that has been initialized");
  168. ret = ESP_ERR_INVALID_STATE;
  169. break;
  170. }
  171. if (ret != ESP_OK) {
  172. break;
  173. }
  174. s_te_obj->is_set_threshold = false; //Threshold configuration will be set on touch sense start
  175. ret = esp_timer_start_periodic(s_te_obj->proc_timer, TE_PROCESSING_PERIOD(s_te_obj) * 1000);
  176. if (ret != ESP_OK) {
  177. break;
  178. }
  179. ret = touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_SCAN_DONE); //Use scan done interrupt to set threshold
  180. if (ret != ESP_OK) {
  181. break;
  182. }
  183. ret = touch_pad_fsm_start();
  184. if (ret != ESP_OK) {
  185. break;
  186. }
  187. xQueueReset(s_te_obj->event_msg_queue);
  188. xQueueReset(s_te_obj->intr_msg_queue);
  189. xSemaphoreGive(s_te_obj->mutex);
  190. return ESP_OK;
  191. } while (0);
  192. ESP_LOGE(TE_TAG, "Touch interface start failed:(%s)", __FUNCTION__ );
  193. xSemaphoreGive(s_te_obj->mutex);
  194. return ret;
  195. }
  196. esp_err_t touch_element_stop(void)
  197. {
  198. TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
  199. esp_err_t ret;
  200. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  201. ret = touch_pad_fsm_stop();
  202. if (ret != ESP_OK) {
  203. return ret;
  204. }
  205. ret = touch_pad_intr_disable(TOUCH_PAD_INTR_MASK_SCAN_DONE);
  206. if (ret != ESP_OK) {
  207. return ret;
  208. }
  209. ret = esp_timer_stop(s_te_obj->proc_timer);
  210. if (ret != ESP_OK) {
  211. return ret;
  212. }
  213. xSemaphoreGive(s_te_obj->mutex);
  214. return ESP_OK;
  215. }
  216. //TODO: add a new api that output system's run-time state
  217. void touch_element_uninstall(void)
  218. {
  219. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  220. if (s_te_obj == NULL) {
  221. xSemaphoreGive(s_te_obj->mutex);
  222. return;
  223. }
  224. esp_err_t ret;
  225. ret = touch_pad_deinit();
  226. if (ret != ESP_OK) {
  227. abort();
  228. }
  229. ret = esp_timer_delete(s_te_obj->proc_timer);
  230. if (ret != ESP_OK) {
  231. abort();
  232. }
  233. ret = touch_pad_intr_disable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT);
  234. if (ret != ESP_OK) {
  235. abort();
  236. }
  237. ret = touch_pad_isr_deregister(te_intr_cb, NULL);
  238. if (ret != ESP_OK) {
  239. abort();
  240. }
  241. vQueueDelete(s_te_obj->event_msg_queue);
  242. vQueueDelete(s_te_obj->intr_msg_queue);
  243. xSemaphoreGive(s_te_obj->mutex);
  244. vSemaphoreDelete(s_te_obj->mutex);
  245. free(s_te_obj->global_config);
  246. s_te_obj->global_config = NULL;
  247. free(s_te_obj);
  248. s_te_obj = NULL;
  249. }
  250. esp_err_t touch_element_message_receive(touch_elem_message_t *element_message, uint32_t ticks_to_wait)
  251. {
  252. //TODO: Use the generic data struct to refactor this api
  253. TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
  254. TE_CHECK(element_message != NULL, ESP_ERR_INVALID_ARG);
  255. TE_CHECK(s_te_obj->event_msg_queue != NULL, ESP_ERR_INVALID_STATE);
  256. int ret = xQueueReceive(s_te_obj->event_msg_queue, element_message, ticks_to_wait);
  257. return (ret == pdTRUE) ? ESP_OK : ESP_ERR_TIMEOUT;
  258. }
  259. static uint32_t te_read_raw_signal(touch_pad_t channel_num)
  260. {
  261. uint32_t raw_signal = 0;
  262. touch_pad_sleep_channel_t sleep_channel_info;
  263. touch_pad_sleep_channel_get_info(&sleep_channel_info);
  264. if (channel_num != sleep_channel_info.touch_num) {
  265. touch_pad_read_raw_data(channel_num, &raw_signal);
  266. } else {
  267. touch_pad_sleep_channel_read_data(channel_num, &raw_signal);
  268. }
  269. return raw_signal;
  270. }
  271. uint32_t te_read_smooth_signal(touch_pad_t channel_num)
  272. {
  273. uint32_t smooth_signal = 0;
  274. touch_pad_sleep_channel_t sleep_channel_info;
  275. touch_pad_sleep_channel_get_info(&sleep_channel_info);
  276. if (channel_num != sleep_channel_info.touch_num) {
  277. touch_pad_filter_read_smooth(channel_num, &smooth_signal);
  278. } else {
  279. touch_pad_sleep_channel_read_smooth(channel_num, &smooth_signal);
  280. }
  281. return smooth_signal;
  282. }
  283. esp_err_t te_event_give(touch_elem_message_t te_message)
  284. {
  285. //TODO: add queue overwrite here when the queue is full
  286. int ret = xQueueSend(s_te_obj->event_msg_queue, &te_message, 0);
  287. if (ret != pdTRUE) {
  288. ESP_LOGE(TE_TAG, "event queue send failed, event message queue is full");
  289. return ESP_ERR_TIMEOUT;
  290. }
  291. return ESP_OK;
  292. }
  293. /**
  294. * @brief Touch sensor interrupt service routine
  295. *
  296. * This function is touch sensor ISR, all the touch
  297. * sensor channel state will be updated here.
  298. */
  299. static void te_intr_cb(void *arg)
  300. {
  301. TE_UNUSED(arg);
  302. static int scan_done_cnt = 0;
  303. int task_awoken = pdFALSE;
  304. te_intr_msg_t te_intr_msg;
  305. /*< Figure out which touch sensor channel is triggered and the trigger type */
  306. uint32_t intr_mask = touch_pad_read_intr_status_mask();
  307. te_intr_msg.channel_num = touch_pad_get_current_meas_channel();
  308. if (intr_mask == 0x0) { //For dummy interrupt
  309. return;
  310. }
  311. bool need_send_queue = true;
  312. if (intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) {
  313. te_intr_msg.channel_state = TE_STATE_PRESS;
  314. te_intr_msg.intr_type = TE_INTR_PRESS;
  315. } else if (intr_mask & TOUCH_PAD_INTR_MASK_INACTIVE) {
  316. te_intr_msg.channel_state = TE_STATE_RELEASE;
  317. te_intr_msg.intr_type = TE_INTR_RELEASE;
  318. } else if (intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {
  319. te_intr_msg.channel_state = TE_STATE_IDLE;
  320. te_intr_msg.intr_type = TE_INTR_TIMEOUT;
  321. } else if (intr_mask & TOUCH_PAD_INTR_MASK_SCAN_DONE) {
  322. te_intr_msg.channel_state = TE_STATE_IDLE;
  323. te_intr_msg.intr_type = TE_INTR_SCAN_DONE;
  324. need_send_queue = false;
  325. /*< Due to a hardware issue, all of the data read operation(read raw, read smooth, read benchmark) */
  326. /*< must be after the second times of measure_done interrupt. */
  327. if (++scan_done_cnt >= 5) {
  328. touch_hal_intr_disable(TOUCH_PAD_INTR_MASK_SCAN_DONE); //TODO: remove hal
  329. scan_done_cnt = 0;
  330. need_send_queue = true;
  331. }
  332. /*< De-noise channel signal must be read at the time between SCAN_DONE and next measurement beginning(sleep)!!! */
  333. touch_pad_denoise_read_data(&s_te_obj->denoise_channel_raw); //Update de-noise signal
  334. } else {
  335. te_intr_msg.intr_type = TE_INTR_MAX; // Unknown Exception
  336. }
  337. if (need_send_queue) {
  338. xQueueSendFromISR(s_te_obj->intr_msg_queue, &te_intr_msg, &task_awoken);
  339. }
  340. if (task_awoken == pdTRUE) {
  341. portYIELD_FROM_ISR();
  342. }
  343. }
  344. /**
  345. * @brief esp-timer callback routine
  346. *
  347. * This function is an esp-timer daemon routine, all the touch sensor
  348. * application(button, slider, etc...) will be processed in here.
  349. *
  350. */
  351. static void te_proc_timer_cb(void *arg)
  352. {
  353. TE_UNUSED(arg);
  354. te_intr_msg_t te_intr_msg;
  355. te_intr_msg.intr_type = TE_INTR_MAX;
  356. BaseType_t ret = xSemaphoreTake(s_te_obj->mutex, 0);
  357. if (ret != pdPASS) {
  358. return;
  359. }
  360. ret = xQueueReceive(s_te_obj->intr_msg_queue, &te_intr_msg, 0);
  361. if (ret == pdPASS) {
  362. if (te_intr_msg.intr_type == TE_INTR_PRESS || te_intr_msg.intr_type == TE_INTR_RELEASE) {
  363. te_object_update_state(te_intr_msg);
  364. } else if (te_intr_msg.intr_type == TE_INTR_SCAN_DONE) {
  365. if (s_te_obj->is_set_threshold != true) {
  366. s_te_obj->is_set_threshold = true;
  367. te_object_set_threshold(); //TODO: add set threshold error processing
  368. ESP_LOGD(TE_DEBUG_TAG, "Set threshold");
  369. }
  370. if (waterproof_check_state()) {
  371. te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
  372. if (waterproof_handle->is_shield_level_set != true) {
  373. waterproof_handle->is_shield_level_set = true;
  374. touch_pad_waterproof_t wp_conf;
  375. wp_conf.shield_driver = waterproof_get_shield_level(waterproof_handle->shield_channel);
  376. wp_conf.guard_ring_pad = (waterproof_guard_check_state() ? waterproof_handle->guard_device->channel : TOUCH_WATERPROOF_GUARD_NOUSE);
  377. touch_pad_waterproof_set_config(&wp_conf);
  378. touch_pad_waterproof_enable();
  379. ESP_LOGD(TE_DEBUG_TAG, "Set waterproof shield level");
  380. }
  381. }
  382. ESP_LOGD(TE_DEBUG_TAG, "read denoise channel %d", s_te_obj->denoise_channel_raw);
  383. } else if (te_intr_msg.intr_type == TE_INTR_TIMEOUT) { //Timeout processing
  384. touch_pad_timeout_resume();
  385. }
  386. }
  387. te_object_process_state();
  388. xSemaphoreGive(s_te_obj->mutex);
  389. }
  390. void te_object_method_register(te_object_methods_t *object_methods, te_class_type_t object_type)
  391. {
  392. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  393. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, handle) = object_methods->handle;
  394. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, check_channel) = object_methods->check_channel;
  395. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, set_threshold) = object_methods->set_threshold;
  396. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, process_state) = object_methods->process_state;
  397. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, update_state) = object_methods->update_state;
  398. xSemaphoreGive(s_te_obj->mutex);
  399. }
  400. void te_object_method_unregister(te_class_type_t object_type)
  401. {
  402. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  403. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, handle) = NULL;
  404. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, check_channel) = NULL;
  405. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, set_threshold) = NULL;
  406. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, process_state) = NULL;
  407. TE_CLASS_ITEM(s_te_obj->object_methods, object_type, update_state) = NULL;
  408. xSemaphoreGive(s_te_obj->mutex);
  409. }
  410. /**
  411. * @brief Touch Sense channel check
  412. *
  413. * This function will check the input channel whether is
  414. * associated with the Touch Sense Object
  415. *
  416. * @return
  417. * - true: Channel has been initialized, pls adjust the input channel
  418. * - false: Channel has not been initialized, pass
  419. */
  420. bool te_object_check_channel(const touch_pad_t *channel_array, uint8_t channel_sum)
  421. {
  422. touch_pad_t current_channel;
  423. for (int idx = 0; idx < channel_sum; idx++) {
  424. current_channel = channel_array[idx];
  425. if (waterproof_channel_check(current_channel)) {
  426. goto INITIALIZED;
  427. }
  428. if (TE_CLASS_FOREACH_CHECK_CHANNEL(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX, current_channel)) {
  429. goto INITIALIZED;
  430. }
  431. }
  432. return false;
  433. INITIALIZED:
  434. ESP_LOGE(TE_TAG, "Current channel [%d] has been initialized:(%s)", current_channel, __FUNCTION__ );
  435. return true;
  436. }
  437. static inline esp_err_t te_object_set_threshold(void)
  438. {
  439. if (waterproof_guard_check_state() == true) { //TODO: add to object methods
  440. waterproof_guard_set_threshold();
  441. }
  442. TE_CLASS_FOREACH_SET_THRESHOLD(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);
  443. return ESP_OK;
  444. }
  445. static inline void te_object_process_state(void)
  446. {
  447. TE_CLASS_FOREACH_PROCESS_STATE(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX);
  448. }
  449. static inline void te_object_update_state(te_intr_msg_t te_intr_msg)
  450. {
  451. if (waterproof_guard_check_state()) {
  452. waterproof_guard_update_state(te_intr_msg.channel_num, te_intr_msg.channel_state);
  453. }
  454. TE_CLASS_FOREACH_UPDATE_STATE(s_te_obj->object_methods, TE_CLS_TYPE_BUTTON, TE_CLS_TYPE_MAX,
  455. te_intr_msg.channel_num, te_intr_msg.channel_state);
  456. }
  457. uint8_t te_get_timer_period(void)
  458. {
  459. return (TE_PROCESSING_PERIOD(s_te_obj));
  460. }
  461. esp_err_t te_dev_init(te_dev_t **device, uint8_t device_num, te_dev_type_t type, const touch_pad_t *channel, const float *sens, float divider)
  462. {
  463. for (int idx = 0; idx < device_num; idx++) {
  464. device[idx]->channel = channel[idx];
  465. device[idx]->sens = sens[idx] * divider;
  466. device[idx]->type = type;
  467. device[idx]->state = TE_STATE_IDLE;
  468. esp_err_t ret = touch_pad_config(device[idx]->channel);
  469. TE_CHECK(ret == ESP_OK, ret);
  470. }
  471. return ESP_OK;
  472. }
  473. void te_dev_deinit(te_dev_t **device, uint8_t device_num)
  474. {
  475. for (int idx = 0; idx < device_num; idx++) {
  476. touch_pad_clear_channel_mask((1UL << device[idx]->channel));
  477. }
  478. }
  479. esp_err_t te_dev_set_threshold(te_dev_t *device)
  480. {
  481. uint32_t smo_val = te_read_smooth_signal(device->channel);
  482. esp_err_t ret = touch_pad_set_thresh(device->channel, device->sens * smo_val);
  483. ESP_LOGD(TE_DEBUG_TAG, "channel: %d, smo_val: %d", device->channel, smo_val);
  484. return ret;
  485. }
  486. /**
  487. * This function returns the s_te_obj whether is initialized
  488. *
  489. * @return
  490. * - true: initialized
  491. * - false: not initialized
  492. */
  493. bool te_system_check_state(void)
  494. {
  495. return (s_te_obj != NULL);
  496. }
  497. static inline float te_get_internal_equ_cap(touch_pad_denoise_cap_t denoise_level)
  498. {
  499. return denoise_channel_equ_cap[denoise_level];
  500. }
  501. /**
  502. * @brief Get channel equivalent capacitance
  503. *
  504. * This function calculates the equivalent capacitance of input channel by
  505. * using the Touch channel 0 equivalent capacitance. The formula is:
  506. *
  507. * Raw_N / Raw_0 = Cap_N / Cap_0
  508. *
  509. * Note that Raw_N and Raw_0 are the raw data of touch channel N and touch channel 0 respectively,
  510. * Cap_N and Cap_0 are the equivalent capacitance of touch channel N and touch channel 0.
  511. *
  512. * @param[in] channel_num Input touch sensor channel
  513. *
  514. * @note The unit is pF
  515. *
  516. * @return Specified channel equivalent capacitance.
  517. */
  518. static float te_channel_get_equ_cap(touch_pad_t channel_num)
  519. {
  520. //Fixme: add a mutex in here and prevent the system call this function
  521. TE_CHECK(channel_num > TOUCH_PAD_NUM0 && channel_num < TOUCH_PAD_MAX, 0);
  522. uint32_t tn_raw, t0_raw;
  523. float tn_ref_cap, t0_ref_cap;
  524. touch_pad_denoise_t denoise_channel_conf;
  525. touch_pad_denoise_get_config(&denoise_channel_conf);
  526. tn_raw = te_read_raw_signal(channel_num);
  527. t0_raw = s_te_obj->denoise_channel_raw;
  528. t0_ref_cap = te_get_internal_equ_cap(denoise_channel_conf.cap_level);
  529. if (t0_raw == 0) {
  530. return 0;
  531. }
  532. tn_ref_cap = (float)tn_raw / t0_raw * t0_ref_cap;
  533. return tn_ref_cap;
  534. }
  535. /**
  536. * @brief Touch sensor driver default init [ESP32S2 only]
  537. *
  538. * 1. Channel measure time: Raw_value / RTC_FAST_CLK ==> Raw_value / 8000 000
  539. * 2. Channel sleep time: TOUCH_PAD_SLEEP_CYCLE_DEFAULT / RTC_SLOW_CLK ==> 0xf / 90 000(default) = 0.16ms
  540. * 3. Channel charge voltage threshold(upper/lower): 2.7V upper voltage, 0.5V lower voltage, 0.5V attenuation voltage
  541. * 4. IDLE channel processing: Connecting to GND
  542. * 5. Interrupt type: ACTIVE, INACTIVE, TIMEOUT
  543. *
  544. * @note A touch sensor channel will spend the time = measure time + sleep time, RTC_FAST_CLK is 8M
  545. *
  546. */
  547. static esp_err_t te_hw_init(const touch_elem_hw_config_t *hardware_init)
  548. {
  549. esp_err_t ret;
  550. ret = touch_pad_init();
  551. TE_CHECK(ret == ESP_OK, ret);
  552. ret = touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
  553. TE_CHECK(ret == ESP_OK, ret);
  554. ret = touch_pad_set_meas_time(hardware_init->sleep_cycle, hardware_init->sample_count);
  555. TE_CHECK(ret == ESP_OK, ret);
  556. ret = touch_pad_set_voltage(hardware_init->upper_voltage, hardware_init->lower_voltage,
  557. hardware_init->voltage_attenuation);
  558. TE_CHECK(ret == ESP_OK, ret);
  559. ret = touch_pad_set_idle_channel_connect(hardware_init->suspend_channel_polarity);
  560. TE_CHECK(ret == ESP_OK, ret);
  561. ret = touch_pad_isr_register(te_intr_cb, NULL,
  562. TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE |
  563. TOUCH_PAD_INTR_MASK_TIMEOUT | TOUCH_PAD_INTR_MASK_SCAN_DONE);
  564. TE_CHECK(ret == ESP_OK, ret);
  565. ret = touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE |
  566. TOUCH_PAD_INTR_MASK_INACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT);
  567. TE_CHECK(ret == ESP_OK, ret);
  568. /*< Internal de-noise configuration */
  569. touch_pad_denoise_t denoise_config;
  570. denoise_config.grade = hardware_init->denoise_level;
  571. denoise_config.cap_level = hardware_init->denoise_equivalent_cap;
  572. ret = touch_pad_denoise_set_config(&denoise_config);
  573. TE_CHECK(ret == ESP_OK, ret);
  574. ret = touch_pad_denoise_enable();
  575. TE_CHECK(ret == ESP_OK, ret);
  576. /*< benchmark filter configuration */
  577. touch_filter_config_t filter_config;
  578. filter_config.smh_lvl = hardware_init->smooth_filter_mode;
  579. filter_config.mode = hardware_init->benchmark_filter_mode;
  580. filter_config.debounce_cnt = hardware_init->benchmark_debounce_count;
  581. filter_config.noise_thr = hardware_init->benchmark_calibration_threshold;
  582. filter_config.jitter_step = hardware_init->benchmark_jitter_step;
  583. ret = touch_pad_filter_set_config(&filter_config);
  584. TE_CHECK(ret == ESP_OK, ret);
  585. ret = touch_pad_filter_enable();
  586. TE_CHECK(ret == ESP_OK, ret);
  587. memcpy(&s_te_obj->global_config->hardware, hardware_init, sizeof(touch_elem_hw_config_t));
  588. return ESP_OK;
  589. }
  590. static esp_err_t te_sw_init(const touch_elem_sw_config_t *software_init)
  591. {
  592. TE_CHECK(software_init->processing_period > 1, ESP_ERR_INVALID_ARG);
  593. TE_CHECK(software_init->waterproof_threshold_divider > 0, ESP_ERR_INVALID_ARG);
  594. TE_CHECK(software_init->intr_message_size >= (TOUCH_PAD_MAX - 1), ESP_ERR_INVALID_ARG);
  595. TE_CHECK(software_init->event_message_size > 0, ESP_ERR_INVALID_ARG);
  596. esp_err_t ret = ESP_ERR_NO_MEM;
  597. s_te_obj->intr_msg_queue = xQueueCreate(software_init->intr_message_size, sizeof(te_intr_msg_t));
  598. s_te_obj->event_msg_queue = xQueueCreate(software_init->event_message_size, sizeof(touch_elem_message_t));
  599. TE_CHECK_GOTO(s_te_obj->event_msg_queue != NULL && s_te_obj->intr_msg_queue != NULL, cleanup);
  600. const esp_timer_create_args_t te_proc_timer_args = {
  601. .name = "te_proc_timer_cb",
  602. .arg = NULL,
  603. .callback = &te_proc_timer_cb
  604. };
  605. ret = esp_timer_create(&te_proc_timer_args, &s_te_obj->proc_timer);
  606. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  607. memcpy(&s_te_obj->global_config->software, software_init, sizeof(touch_elem_sw_config_t));
  608. return ret;
  609. cleanup:
  610. if (s_te_obj->event_msg_queue != NULL) {
  611. vQueueDelete(s_te_obj->event_msg_queue);
  612. }
  613. if (s_te_obj->intr_msg_queue != NULL) {
  614. vQueueDelete(s_te_obj->intr_msg_queue);
  615. }
  616. return ret;
  617. }
  618. //TODO: add waterproof guard-lock hysteresis
  619. esp_err_t touch_element_waterproof_install(const touch_elem_waterproof_config_t *waterproof_config)
  620. {
  621. TE_CHECK(s_te_obj != NULL, ESP_ERR_INVALID_STATE);
  622. TE_CHECK(waterproof_config != NULL, ESP_ERR_INVALID_ARG);
  623. TE_CHECK(waterproof_config->guard_channel >= TOUCH_PAD_NUM0 &&
  624. waterproof_config->guard_channel < TOUCH_PAD_MAX,
  625. ESP_ERR_INVALID_ARG);
  626. te_waterproof_handle_t waterproof_handle = (te_waterproof_handle_t)calloc(1, sizeof(struct te_waterproof_s));
  627. TE_CHECK(waterproof_handle != NULL, ESP_ERR_NO_MEM);
  628. waterproof_handle->shield_channel = TOUCH_PAD_NUM14;
  629. esp_err_t ret;
  630. if (waterproof_config->guard_channel != TOUCH_WATERPROOF_GUARD_NOUSE) { //Use guard sensor
  631. if (te_object_check_channel(&waterproof_config->guard_channel, 1)) {
  632. ret = ESP_ERR_INVALID_ARG;
  633. goto cleanup;
  634. }
  635. ret = ESP_ERR_NO_MEM;
  636. waterproof_handle->mask_handle = (touch_elem_handle_t *) calloc(TOUCH_PAD_MAX, sizeof(touch_elem_handle_t));
  637. waterproof_handle->guard_device = (te_dev_t *)calloc(1, sizeof(te_dev_t));
  638. TE_CHECK_GOTO(waterproof_handle->mask_handle != NULL && waterproof_handle->guard_device, cleanup);
  639. ret = te_dev_init(&waterproof_handle->guard_device, 1, TOUCH_ELEM_TYPE_BUTTON,
  640. &waterproof_config->guard_channel, &waterproof_config->guard_sensitivity,
  641. TE_WATERPROOF_DIVIDER(s_te_obj));
  642. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  643. waterproof_handle->guard_device->state = TE_STATE_RELEASE;
  644. for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {
  645. waterproof_handle->mask_handle[idx] = NULL;
  646. }
  647. } else { //No use waterproof guard sensor
  648. waterproof_handle->guard_device = NULL;
  649. waterproof_handle->mask_handle = NULL;
  650. }
  651. waterproof_handle->is_shield_level_set = 0; //Set a state bit so as to configure the shield level at the run-time
  652. touch_pad_waterproof_t wp_conf;
  653. wp_conf.shield_driver = TOUCH_PAD_SHIELD_DRV_L0; //Set a default shield level
  654. wp_conf.guard_ring_pad = waterproof_config->guard_channel;
  655. ret = touch_pad_waterproof_set_config(&wp_conf);
  656. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  657. ret = touch_pad_waterproof_enable();
  658. TE_CHECK_GOTO(ret == ESP_OK, cleanup);
  659. s_te_obj->waterproof_handle = waterproof_handle; //Fixme: add mutex
  660. return ESP_OK;
  661. cleanup:
  662. TE_FREE_AND_NULL(waterproof_handle->mask_handle);
  663. TE_FREE_AND_NULL(waterproof_handle->guard_device);
  664. TE_FREE_AND_NULL(waterproof_handle);
  665. return ret;
  666. }
  667. esp_err_t touch_element_waterproof_add(touch_elem_handle_t element_handle)
  668. {
  669. TE_CHECK(s_te_obj->waterproof_handle != NULL, ESP_ERR_INVALID_STATE);
  670. TE_CHECK(s_te_obj->waterproof_handle->guard_device != NULL, ESP_ERR_INVALID_STATE);
  671. TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);
  672. te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
  673. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  674. for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {
  675. if (waterproof_handle->mask_handle[idx] == NULL) {
  676. waterproof_handle->mask_handle[idx] = element_handle;
  677. break;
  678. }
  679. }
  680. xSemaphoreGive(s_te_obj->mutex);
  681. return ESP_OK;
  682. }
  683. esp_err_t touch_element_waterproof_remove(touch_elem_handle_t element_handle)
  684. {
  685. TE_CHECK(s_te_obj->waterproof_handle != NULL, ESP_ERR_INVALID_STATE);
  686. TE_CHECK(element_handle != NULL, ESP_ERR_INVALID_ARG);
  687. esp_err_t ret = ESP_ERR_NOT_FOUND;
  688. te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
  689. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  690. for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {
  691. if (waterproof_handle->mask_handle[idx] == element_handle) {
  692. waterproof_handle->mask_handle[idx] = NULL;
  693. ret = ESP_OK;
  694. break;
  695. }
  696. }
  697. xSemaphoreGive(s_te_obj->mutex);
  698. return ret;
  699. }
  700. void touch_element_waterproof_uninstall(void)
  701. {
  702. xSemaphoreTake(s_te_obj->mutex, portMAX_DELAY);
  703. touch_pad_waterproof_disable();
  704. free(s_te_obj->waterproof_handle->guard_device);
  705. free(s_te_obj->waterproof_handle->mask_handle);
  706. free(s_te_obj->waterproof_handle);
  707. s_te_obj->waterproof_handle = NULL;
  708. xSemaphoreGive(s_te_obj->mutex);
  709. }
  710. static touch_pad_shield_driver_t waterproof_get_shield_level(touch_pad_t guard_channel_num)
  711. {
  712. touch_pad_shield_driver_t shield_level = TOUCH_PAD_SHIELD_DRV_L7;
  713. float guard_ref_cap = te_channel_get_equ_cap(guard_channel_num);
  714. for (int level = 0; level < TOUCH_PAD_SHIELD_DRV_MAX; level++) {
  715. if (guard_ref_cap <= shield_channel_ref_cap[level]) {
  716. shield_level = (touch_pad_shield_driver_t)level;
  717. break;
  718. }
  719. }
  720. return shield_level;
  721. }
  722. /**
  723. * This function returns the waterproof_handle whether is initialized
  724. *
  725. * @return
  726. * - true: initialized
  727. * - false: not initialized
  728. */
  729. static inline bool waterproof_check_state(void)
  730. {
  731. return (s_te_obj->waterproof_handle != NULL);
  732. }
  733. static inline bool waterproof_shield_check_state(void)
  734. {
  735. return waterproof_check_state(); //Driver does not allow to disable shield sensor after waterproof enabling
  736. }
  737. static inline bool waterproof_guard_check_state(void)
  738. {
  739. if (waterproof_check_state() == false) {
  740. return false;
  741. }
  742. if (s_te_obj->waterproof_handle->guard_device == NULL || s_te_obj->waterproof_handle->mask_handle == NULL) {
  743. return false;
  744. }
  745. return true;
  746. }
  747. static bool waterproof_channel_check(touch_pad_t channel_num)
  748. {
  749. if (waterproof_check_state() == false) {
  750. return false;
  751. }
  752. te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
  753. if (waterproof_shield_check_state()) {
  754. if (channel_num == waterproof_handle->shield_channel) {
  755. ESP_LOGE(TE_TAG, "TOUCH_PAD_NUM%d has been used for waterproof shield channel,"
  756. " please change the touch sensor channel or disable waterproof", channel_num);
  757. return true;
  758. }
  759. }
  760. if (waterproof_guard_check_state()) {
  761. if (channel_num == waterproof_handle->guard_device->channel) {
  762. ESP_LOGE(TE_TAG, "TOUCH_PAD_NUM%d has been used for waterproof guard channel,"
  763. " please change the touch sensor channel or disable waterproof", channel_num);
  764. return true;
  765. }
  766. }
  767. return false;
  768. }
  769. static void waterproof_guard_set_threshold(void)
  770. {
  771. if (waterproof_check_state() == false) {
  772. return;
  773. }
  774. if (waterproof_guard_check_state() == false) {
  775. return;
  776. }
  777. te_dev_set_threshold(s_te_obj->waterproof_handle->guard_device);
  778. }
  779. /**
  780. * This function will figure out current handle whether is a masked channel
  781. * while guard channel is triggered.
  782. *
  783. * @param[in] te_handle Touch sensor application handle
  784. * @return
  785. * - true current handle is a masked channel
  786. * - false current handle is not a masked channel
  787. */
  788. bool waterproof_check_mask_handle(touch_elem_handle_t te_handle)
  789. {
  790. if (waterproof_check_state() == false) {
  791. return false;
  792. }
  793. if (waterproof_guard_check_state() == false) {
  794. return false;
  795. }
  796. te_waterproof_handle_t waterproof_handle = s_te_obj->waterproof_handle;
  797. bool ret = false;
  798. if (waterproof_handle->guard_device->state == TE_STATE_PRESS) {
  799. for (int idx = 0; idx < TOUCH_PAD_MAX; idx++) {
  800. if (waterproof_handle->mask_handle[idx] == NULL) {
  801. break;
  802. }
  803. if (waterproof_handle->mask_handle[idx] == te_handle) {
  804. ret = true;
  805. }
  806. }
  807. }
  808. return ret;
  809. }
  810. static void waterproof_guard_update_state(touch_pad_t current_channel, te_state_t current_state)
  811. {
  812. te_dev_t *guard_device = s_te_obj->waterproof_handle->guard_device;
  813. if (current_channel == guard_device->channel) {
  814. guard_device->state = current_state;
  815. }
  816. ESP_LOGD(TE_DEBUG_TAG, "waterproof guard state update %d", guard_device->state);
  817. }