1 /*
2  * SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include "sdkconfig.h"
10 #include "esp_types.h"
11 #include "esp_log.h"
12 #include "sys/lock.h"
13 #include "soc/soc_pins.h"
14 #include "freertos/FreeRTOS.h"
15 #include "freertos/semphr.h"
16 #include "freertos/timers.h"
17 #include "esp_intr_alloc.h"
18 #include "driver/rtc_io.h"
19 #include "driver/touch_pad.h"
20 #include "esp_private/rtc_ctrl.h"
21 #include "driver/gpio.h"
22 #include "hal/touch_sensor_types.h"
23 #include "hal/touch_sensor_hal.h"
24 
25 static const char *TOUCH_TAG = "TOUCH_SENSOR";
26 #define TOUCH_CHECK(a, str, ret_val) ({                                             \
27     if (!(a)) {                                                                     \
28         ESP_LOGE(TOUCH_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str);              \
29         return (ret_val);                                                           \
30     }                                                                               \
31 })
32 #ifdef CONFIG_IDF_TARGET_ESP32
33 #define TOUCH_CHANNEL_CHECK(channel) do { \
34         TOUCH_CHECK(channel < SOC_TOUCH_SENSOR_NUM && channel >= 0, "Touch channel error", ESP_ERR_INVALID_ARG); \
35     } while (0);
36 #else // !CONFIG_IDF_TARGET_ESP32
37 #define TOUCH_CHANNEL_CHECK(channel) do { \
38         TOUCH_CHECK(channel < SOC_TOUCH_SENSOR_NUM && channel >= 0, "Touch channel error", ESP_ERR_INVALID_ARG); \
39         TOUCH_CHECK(channel != SOC_TOUCH_DENOISE_CHANNEL, "TOUCH0 is internal denoise channel", ESP_ERR_INVALID_ARG); \
40     } while (0);
41 #endif // CONFIG_IDF_TARGET_ESP32
42 
43 #define TOUCH_GET_IO_NUM(channel) (touch_sensor_channel_io_map[channel])
44 
45 _Static_assert(TOUCH_PAD_MAX == SOC_TOUCH_SENSOR_NUM, "Touch sensor channel number not equal to chip capabilities");
46 
47 extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
48 #define TOUCH_ENTER_CRITICAL()  portENTER_CRITICAL(&rtc_spinlock)
49 #define TOUCH_EXIT_CRITICAL()  portEXIT_CRITICAL(&rtc_spinlock)
50 
touch_pad_isr_deregister(intr_handler_t fn,void * arg)51 esp_err_t touch_pad_isr_deregister(intr_handler_t fn, void *arg)
52 {
53     return rtc_isr_deregister(fn, arg);
54 }
55 
touch_pad_set_voltage(touch_high_volt_t refh,touch_low_volt_t refl,touch_volt_atten_t atten)56 esp_err_t touch_pad_set_voltage(touch_high_volt_t refh, touch_low_volt_t refl, touch_volt_atten_t atten)
57 {
58     TOUCH_CHECK(((refh < TOUCH_HVOLT_MAX) && (refh >= (int )TOUCH_HVOLT_KEEP)), "touch refh error",
59                 ESP_ERR_INVALID_ARG);
60     TOUCH_CHECK(((refl < TOUCH_LVOLT_MAX) && (refh >= (int )TOUCH_LVOLT_KEEP)), "touch refl error",
61                 ESP_ERR_INVALID_ARG);
62     TOUCH_CHECK(((atten < TOUCH_HVOLT_ATTEN_MAX) && (refh >= (int )TOUCH_HVOLT_ATTEN_KEEP)), "touch atten error",
63                 ESP_ERR_INVALID_ARG);
64 
65     const touch_hal_volt_t volt = {
66         .refh = refh,
67         .refl = refl,
68         .atten = atten,
69     };
70     TOUCH_ENTER_CRITICAL();
71     touch_hal_set_voltage(&volt);
72     TOUCH_EXIT_CRITICAL();
73 
74     return ESP_OK;
75 }
76 
touch_pad_get_voltage(touch_high_volt_t * refh,touch_low_volt_t * refl,touch_volt_atten_t * atten)77 esp_err_t touch_pad_get_voltage(touch_high_volt_t *refh, touch_low_volt_t *refl, touch_volt_atten_t *atten)
78 {
79     touch_hal_volt_t volt = {0};
80     TOUCH_ENTER_CRITICAL();
81     touch_hal_get_voltage(&volt);
82     TOUCH_EXIT_CRITICAL();
83     *refh = volt.refh;
84     *refl = volt.refl;
85     *atten = volt.atten;
86 
87     return ESP_OK;
88 }
89 
touch_pad_set_cnt_mode(touch_pad_t touch_num,touch_cnt_slope_t slope,touch_tie_opt_t opt)90 esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope, touch_tie_opt_t opt)
91 {
92     TOUCH_CHECK(touch_num < SOC_TOUCH_SENSOR_NUM, "Touch channel error", ESP_ERR_INVALID_ARG);
93     TOUCH_CHECK(slope < TOUCH_PAD_SLOPE_MAX, "touch slope error", ESP_ERR_INVALID_ARG);
94     TOUCH_CHECK(opt < TOUCH_PAD_TIE_OPT_MAX, "touch opt error", ESP_ERR_INVALID_ARG);
95 
96     const touch_hal_meas_mode_t meas = {
97         .slope = slope,
98         .tie_opt = opt,
99     };
100     TOUCH_ENTER_CRITICAL();
101     touch_hal_set_meas_mode(touch_num, &meas);
102     TOUCH_EXIT_CRITICAL();
103 
104     return ESP_OK;
105 }
106 
touch_pad_get_cnt_mode(touch_pad_t touch_num,touch_cnt_slope_t * slope,touch_tie_opt_t * opt)107 esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t *slope, touch_tie_opt_t *opt)
108 {
109     TOUCH_CHECK(touch_num < SOC_TOUCH_SENSOR_NUM, "Touch channel error", ESP_ERR_INVALID_ARG);
110 
111     touch_hal_meas_mode_t meas = {0};
112     TOUCH_ENTER_CRITICAL();
113     touch_hal_get_meas_mode(touch_num, &meas);
114     TOUCH_EXIT_CRITICAL();
115     *slope = meas.slope;
116     *opt = meas.tie_opt;
117 
118     return ESP_OK;
119 }
120 
touch_pad_io_init(touch_pad_t touch_num)121 esp_err_t touch_pad_io_init(touch_pad_t touch_num)
122 {
123     TOUCH_CHANNEL_CHECK(touch_num);
124     gpio_num_t gpio_num = TOUCH_GET_IO_NUM(touch_num);
125     rtc_gpio_init(gpio_num);
126     rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED);
127     rtc_gpio_pulldown_dis(gpio_num);
128     rtc_gpio_pullup_dis(gpio_num);
129     return ESP_OK;
130 }
131 
touch_pad_fsm_start(void)132 esp_err_t touch_pad_fsm_start(void)
133 {
134     TOUCH_ENTER_CRITICAL();
135     touch_hal_start_fsm();
136     TOUCH_EXIT_CRITICAL();
137     return ESP_OK;
138 }
139 
touch_pad_fsm_stop(void)140 esp_err_t touch_pad_fsm_stop(void)
141 {
142     TOUCH_ENTER_CRITICAL();
143     touch_hal_stop_fsm();
144     TOUCH_EXIT_CRITICAL();
145     return ESP_OK;
146 }
147 
touch_pad_set_fsm_mode(touch_fsm_mode_t mode)148 esp_err_t touch_pad_set_fsm_mode(touch_fsm_mode_t mode)
149 {
150     TOUCH_CHECK((mode < TOUCH_FSM_MODE_MAX), "touch fsm mode error", ESP_ERR_INVALID_ARG);
151 
152     TOUCH_ENTER_CRITICAL();
153     touch_hal_set_fsm_mode(mode);
154     TOUCH_EXIT_CRITICAL();
155 #ifdef CONFIG_IDF_TARGET_ESP32
156     if (mode == TOUCH_FSM_MODE_TIMER) {
157         touch_pad_fsm_start();
158     } else {
159         touch_pad_fsm_stop();
160     }
161 #endif
162     return ESP_OK;
163 }
164 
touch_pad_get_fsm_mode(touch_fsm_mode_t * mode)165 esp_err_t touch_pad_get_fsm_mode(touch_fsm_mode_t *mode)
166 {
167     touch_hal_get_fsm_mode(mode);
168     return ESP_OK;
169 }
170 
touch_pad_sw_start(void)171 esp_err_t touch_pad_sw_start(void)
172 {
173     TOUCH_ENTER_CRITICAL();
174     touch_hal_start_sw_meas();
175     TOUCH_EXIT_CRITICAL();
176     return ESP_OK;
177 }
178 
179 #ifdef CONFIG_IDF_TARGET_ESP32
touch_pad_set_thresh(touch_pad_t touch_num,uint16_t threshold)180 esp_err_t touch_pad_set_thresh(touch_pad_t touch_num, uint16_t threshold)
181 {
182     TOUCH_CHANNEL_CHECK(touch_num);
183     TOUCH_ENTER_CRITICAL();
184     touch_hal_set_threshold(touch_num, threshold);
185     TOUCH_EXIT_CRITICAL();
186     return ESP_OK;
187 }
188 #else // !CONFIG_IDF_TARGET_ESP32
touch_pad_set_thresh(touch_pad_t touch_num,uint32_t threshold)189 esp_err_t touch_pad_set_thresh(touch_pad_t touch_num, uint32_t threshold)
190 {
191     TOUCH_CHANNEL_CHECK(touch_num);
192     TOUCH_CHECK(touch_num != SOC_TOUCH_DENOISE_CHANNEL,
193                 "TOUCH0 is internal denoise channel", ESP_ERR_INVALID_ARG);
194     TOUCH_ENTER_CRITICAL();
195     touch_hal_set_threshold(touch_num, threshold);
196     TOUCH_EXIT_CRITICAL();
197     return ESP_OK;
198 }
199 #endif // CONFIG_IDF_TARGET_ESP32
200 
201 #ifdef CONFIG_IDF_TARGET_ESP32
touch_pad_get_thresh(touch_pad_t touch_num,uint16_t * threshold)202 esp_err_t touch_pad_get_thresh(touch_pad_t touch_num, uint16_t *threshold)
203 {
204     TOUCH_CHANNEL_CHECK(touch_num);
205     touch_hal_get_threshold(touch_num, threshold);
206     return ESP_OK;
207 }
208 #else // !CONFIG_IDF_TARGET_ESP32
touch_pad_get_thresh(touch_pad_t touch_num,uint32_t * threshold)209 esp_err_t touch_pad_get_thresh(touch_pad_t touch_num, uint32_t *threshold)
210 {
211     TOUCH_CHANNEL_CHECK(touch_num);
212     TOUCH_CHECK(touch_num != SOC_TOUCH_DENOISE_CHANNEL,
213                 "TOUCH0 is internal denoise channel", ESP_ERR_INVALID_ARG);
214     touch_hal_get_threshold(touch_num, threshold);
215     return ESP_OK;
216 }
217 #endif // CONFIG_IDF_TARGET_ESP32
218 
touch_pad_get_wakeup_status(touch_pad_t * pad_num)219 esp_err_t touch_pad_get_wakeup_status(touch_pad_t *pad_num)
220 {
221     touch_hal_get_wakeup_status(pad_num);
222     TOUCH_CHANNEL_CHECK(*pad_num);
223     return ESP_OK;
224 }
225 
touch_pad_get_status(void)226 uint32_t IRAM_ATTR touch_pad_get_status(void)
227 {
228     uint32_t status = 0;
229     touch_hal_read_trigger_status_mask(&status);
230     return status;
231 }
232 
touch_pad_clear_status(void)233 esp_err_t IRAM_ATTR touch_pad_clear_status(void)
234 {
235     touch_hal_clear_trigger_status_mask();
236     return ESP_OK;
237 }
238