Skip to content

Commit 765df2e

Browse files
committed
fix(touch_slider_sensor): support 2 channel slider
1 parent eab1f42 commit 765df2e

File tree

10 files changed

+199
-89
lines changed

10 files changed

+199
-89
lines changed

components/touch/touch_slider_sensor/Kconfig

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ menu "Touch Slider Sensor Configuration"
88

99
config TOUCH_SLIDER_SENSOR_CALIBRATION_TIMES
1010
int "Calibration times"
11-
default 50 if !IDF_TARGET_ESP32
1211
default 20
1312
range 10 1000
1413
help
@@ -54,19 +53,19 @@ menu "Touch Slider Sensor Configuration"
5453

5554
config TOUCH_SLIDER_SENSOR_MAX_P_X1000
5655
int "Maximum positive change ratio (/1000)"
57-
default 200
56+
default 0
5857
range 0 1000
5958
help
6059
Maximum positive change ratio from baseline, multiplied by 1000.
61-
For example, 200 means 0.2. 0 means no limit.
60+
For example, 200 means 0.2. 0 means automatically calculated.
6261

6362
config TOUCH_SLIDER_SENSOR_MIN_N_X1000
6463
int "Minimum negative change ratio (/1000)"
65-
default 200
64+
default 0
6665
range 0 1000
6766
help
6867
Minimum negative change ratio from baseline, multiplied by 1000.
69-
For example, 200 means 0.2. 0 means no limit.
68+
For example, 200 means 0.2. 0 means automatically calculated.
7069

7170
config TOUCH_SLIDER_SENSOR_NEGATIVE_LOGIC
7271
bool "Using negative logic to detect touch"
@@ -90,7 +89,6 @@ menu "Touch Slider Sensor Configuration"
9089

9190
config TOUCH_SLIDER_SENSOR_RESET_COVER
9291
int "Reset count from cover"
93-
default 1000 if !IDF_TARGET_ESP32
9492
default 300
9593
range 0 5000
9694
help
@@ -105,7 +103,7 @@ menu "Touch Slider Sensor Configuration"
105103

106104
config TOUCH_SLIDER_SENSOR_RAW_BUF_SIZE
107105
int "Raw buffer size"
108-
default 40 if !IDF_TARGET_ESP32
106+
default 20 if !IDF_TARGET_ESP32
109107
default 10
110108
range 10 100
111109
help
@@ -147,10 +145,4 @@ menu "Touch Slider Sensor Configuration"
147145
help
148146
Divisor of slider position IIR filter.
149147

150-
config TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL
151-
int "Position calculation window"
152-
default 3
153-
range 1 10
154-
help
155-
Number of channels in position calculation
156148
endmenu

components/touch/touch_slider_sensor/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,35 @@ A component providing enhanced touch slider detection functionality for ESP32 se
77
## Features
88

99
- FSM-based touch detection with configurable thresholds
10-
- Support for slider gesture detection
10+
- Support for slider gesture detection with configurable position calculation window
11+
- Automatic default value selection for optimal performance
1112
- Callback-based event notification
1213

1314
## Dependencies
1415

1516
- [touch_sensor_fsm](https://components.espressif.com/components/espressif/touch_sensor_fsm)
1617
- [touch_sensor_lowlevel](https://components.espressif.com/components/espressif/touch_sensor_lowlevel)
1718

19+
## Configuration Options
20+
21+
### Calculate Window (`calculate_window`)
22+
23+
The `calculate_window` parameter determines how many adjacent touch channels are used for position calculation. This affects the precision and noise immunity of the slider.
24+
25+
**Default Values (when set to 0):**
26+
- **2 channels**: `calculate_window = 2` (uses all available channels)
27+
- **3+ channels**: `calculate_window = 3` (optimal balance between precision and noise immunity)
28+
29+
**Manual Configuration:**
30+
- You can explicitly set any value from 1 to `channel_num`
31+
- Smaller values (1-2): Higher sensitivity but more susceptible to noise
32+
- Larger values (3+): Better noise immunity but potentially lower resolution
33+
- For high-precision applications: Recommended value is `min(3, channel_num)`
34+
35+
**Backward Compatibility:**
36+
- Setting `calculate_window = 0` enables automatic default selection
37+
- Existing code that doesn't initialize this field will use optimal defaults
38+
- Explicitly set values continue to work as before
1839

1940
## Example
2041

@@ -70,6 +91,7 @@ void app_main(void)
7091
.swipe_hysterisis = 40,
7192
.channel_gold_value = NULL,
7293
.debounce_times = 0,
94+
.calculate_window = 0, // Use default value (auto-selected based on channel count)
7395
.skip_lowlevel_init = false
7496
};
7597

components/touch/touch_slider_sensor/idf_component.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "0.1.0"
1+
version: "0.2.0"
22
targets:
33
- esp32
44
- esp32s2
@@ -14,9 +14,9 @@ dependencies:
1414
idf: ">=4.4"
1515
cmake_utilities: "0.*"
1616
touch_sensor_fsm:
17-
version: ">=0.7.0"
17+
version: ">=0.8.1~1,<0.9.0"
1818
touch_sensor_lowlevel:
19-
version: ">=0.8.1"
19+
version: ">=0.9.1~1,<0.10.0"
2020
public: true
2121
files:
2222
exclude:

components/touch/touch_slider_sensor/include/touch_slider_sensor.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ typedef struct {
2929
uint32_t *channel_gold_value; /*!< (Optional) Reference values for touch channels */
3030
uint32_t debounce_times; /*!< Number of consecutive readings needed to confirm state change */
3131
uint32_t filter_reset_times; /*!< Number of consecutive readings to reset position filter */
32-
uint32_t position_range; /*!< The right region of touch slider position range, [0, position_range (less than or equal to 255)] */
32+
uint32_t position_range; /*!< Maximum position value of touch slider, range [0, position_range]. Higher values provide better position resolution */
33+
uint8_t calculate_window; /*!< Window size for position calculation (should be <= channel_num). Set to 0 for auto-default: 2 for 2-channel, 3 for 3+ channels */
3334
float swipe_threshold; /*!< The speed threshold for identifying swiping */
3435
float swipe_hysterisis; /*!< The speed hysterisis for identifying swiping */
3536
float swipe_alpha; /*!< Filter parameter for estimating speed */
@@ -54,14 +55,22 @@ typedef void (*touch_slider_event_cb_t)(touch_slider_handle_t handle, touch_slid
5455
* This function initializes the touch sensor hardware (unless skip_lowlevel_init is true),
5556
* sets up FSM instances for touch detection, and registers callbacks for touch events.
5657
*
58+
* @note The calculate_window parameter determines how many adjacent channels are used
59+
* for position calculation. For backward compatibility, if set to 0, default
60+
* values will be used:
61+
* - 2 channels: window_size = 2 (use all channels)
62+
* - 3+ channels: window_size = 3 (optimal balance between precision and noise immunity)
63+
* - For high-precision applications: window_size = min(3, channel_num)
64+
*
5765
* @param config Touch slider sensor configuration
5866
* @param handle Pointer to receive the created touch slider sensor handle
5967
* @param cb Callback function for touch slider events
6068
* @param cb_arg User data to pass to callback function
6169
*
6270
* @return
6371
* - ESP_OK on success
64-
* - ESP_ERR_INVALID_ARG if config, handle, or required config fields are NULL
72+
* - ESP_ERR_INVALID_ARG if config, handle, or required config fields are NULL,
73+
* or if calculate_window is less than 2 or greater than channel_num (0 is acceptable for auto-default)
6574
* - ESP_ERR_NO_MEM if memory allocation fails
6675
* - ESP_FAIL if touch sensor or FSM initialization fails
6776
*/

components/touch/touch_slider_sensor/test_apps/main/test_touch_slider_sensor.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ TEST_CASE("touch slider sensor create/delete test", "[touch_slider][create]")
5757
.position_range = 10000,
5858
.channel_gold_value = NULL,
5959
.debounce_times = 3,
60+
.calculate_window = 0, // Test default value (should auto-select based on channel_num)
6061
.skip_lowlevel_init = false
6162
};
6263

63-
// Test successful creation
64+
// Test successful creation with default calculate_window
6465
TEST_ASSERT_EQUAL(ESP_OK, touch_slider_sensor_create(&config, &s_touch_slider, touch_slider_event_callback, NULL));
6566
TEST_ASSERT_NOT_NULL(s_touch_slider);
6667

@@ -79,6 +80,7 @@ TEST_CASE("touch slider sensor position test", "[touch_slider][events]")
7980
.position_range = 10000,
8081
.channel_gold_value = NULL,
8182
.debounce_times = 0,
83+
.calculate_window = 0, // Test default value
8284
.skip_lowlevel_init = false
8385
};
8486

@@ -114,6 +116,7 @@ TEST_CASE("touch slider sensor event handling test", "[touch_slider][events]")
114116
.swipe_hysterisis = 40,
115117
.channel_gold_value = NULL,
116118
.debounce_times = 0,
119+
.calculate_window = 3, // Explicitly set to 3 for testing
117120
.skip_lowlevel_init = false
118121
};
119122

components/touch/touch_slider_sensor/touch_slider_sensor.c

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef struct touch_slider_sensor_t {
5959
uint32_t filter_reset_times;
6060
float quantify_signal_array[SOC_TOUCH_SENSOR_NUM]; // Slider re-quantization array
6161
uint32_t position_range;
62+
uint8_t calculate_window; // Window size for position calculation
6263
float swipe_threshold;
6364
float swipe_hysterisis;
6465
float swipe_alpha;
@@ -155,6 +156,21 @@ esp_err_t touch_slider_sensor_create(touch_slider_config_t *config, touch_slider
155156
ESP_RETURN_ON_FALSE(config && handle, ESP_ERR_INVALID_ARG, TAG, "Invalid arguments");
156157
ESP_RETURN_ON_FALSE(config->channel_num > 1 && config->channel_list, ESP_ERR_INVALID_ARG, TAG, "Invalid channel config");
157158

159+
// Set default calculate_window if not specified or invalid (for backward compatibility)
160+
if (config->calculate_window == 0) {
161+
// Recommended default values based on channel count
162+
if (config->channel_num == 2) {
163+
config->calculate_window = 2; // Use all channels for 2-channel setup
164+
} else {
165+
config->calculate_window = 3; // Optimal balance for 3+ channels
166+
}
167+
ESP_LOGI(TAG, "Using default calculate_window: %"PRIu8, config->calculate_window);
168+
}
169+
170+
// Validate calculation window size
171+
ESP_RETURN_ON_FALSE(config->calculate_window >= 2 && config->calculate_window <= config->channel_num,
172+
ESP_ERR_INVALID_ARG, TAG, "Invalid calculate_window: must be >= 2 and <= channel_num (%"PRIu32")", config->channel_num);
173+
158174
touch_slider_sensor_t *sensor = calloc(1, sizeof(touch_slider_sensor_t));
159175
ESP_RETURN_ON_FALSE(sensor, ESP_ERR_NO_MEM, TAG, "Failed to allocate memory");
160176

@@ -174,6 +190,7 @@ esp_err_t touch_slider_sensor_create(touch_slider_config_t *config, touch_slider
174190
sensor->channel_bcm_update_cnt = CONFIG_TOUCH_SLIDER_SENSOR_BENCHMARK_UPDATE_TIME; // update at first time
175191
sensor->filter_reset_cnt = config->filter_reset_times;
176192
sensor->position_range = config->position_range;
193+
sensor->calculate_window = config->calculate_window; // Store calculate window size
177194
sensor->swipe_threshold = config->swipe_threshold;
178195
sensor->swipe_hysterisis = config->swipe_hysterisis;
179196
sensor->swipe_alpha = config->swipe_alpha;
@@ -385,22 +402,23 @@ static inline void slider_quantify_signal(touch_slider_handle_t slider_handle)
385402
*
386403
* This function will figure out the max sum subarray from the
387404
* input array, return the max sum and max sum start index
388-
*
389405
*/
390-
static inline float slider_search_max_subarray(const float *array, int array_size, int *max_array_idx)
406+
static inline float slider_search_max_subarray(const float *array, uint8_t array_size, uint8_t window_size, uint8_t *max_array_idx)
391407
{
392408
*max_array_idx = 0;
393409
float max_array_sum = 0;
394410
float current_array_sum = 0;
395-
for (int idx = 0; idx <= (array_size - CONFIG_TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL); idx++) {
396-
for (int x = idx; x < idx + CONFIG_TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL; x++) {
411+
uint8_t max_start_idx = array_size - window_size;
412+
413+
for (uint8_t idx = 0; idx <= max_start_idx; idx++) {
414+
current_array_sum = 0;
415+
for (uint8_t x = idx; x < idx + window_size; x++) {
397416
current_array_sum += array[x];
398417
}
399418
if (max_array_sum < current_array_sum) {
400419
max_array_sum = current_array_sum;
401420
*max_array_idx = idx;
402421
}
403-
current_array_sum = 0;
404422
}
405423
return max_array_sum;
406424
}
@@ -411,26 +429,34 @@ static inline float slider_search_max_subarray(const float *array, int array_siz
411429
* This function will figure out the number of non-zero items from
412430
* the subarray
413431
*/
414-
static inline uint8_t slider_get_non_zero_num(const float *array, uint8_t array_idx)
432+
static inline uint8_t slider_get_non_zero_num(const float *array, uint8_t array_idx, uint8_t window_size, uint8_t array_size)
415433
{
416434
uint8_t zero_cnt = 0;
417-
for (int idx = array_idx; idx < array_idx + CONFIG_TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL; idx++) {
435+
// Prevent uint8_t overflow and ensure we don't exceed array bounds
436+
uint8_t end_idx = (array_idx + window_size > array_size) ? array_size : array_idx + window_size;
437+
438+
for (uint8_t idx = array_idx; idx < end_idx; idx++) {
418439
zero_cnt += (array[idx] > 0) ? 1 : 0;
419440
}
420441
return zero_cnt;
421442
}
422443

423-
static inline uint32_t slider_calculate_position(touch_slider_handle_t slider_handle, int subarray_index, float subarray_sum, int non_zero_num)
444+
static inline uint32_t slider_calculate_position(touch_slider_handle_t slider_handle, uint8_t subarray_index, float subarray_sum, uint8_t non_zero_num)
424445
{
425-
int range = slider_handle->position_range;
426-
int array_size = slider_handle->channel_num;
446+
uint32_t range = slider_handle->position_range;
447+
uint8_t array_size = slider_handle->channel_num;
448+
uint8_t window_size = slider_handle->calculate_window; // Use user-configured window size
427449
float scale = (float)range / (slider_handle->channel_num - 1);
428450
const float *array = slider_handle->quantify_signal_array;
429451
uint32_t position = 0;
452+
430453
if (non_zero_num == 0) {
431454
position = slider_handle->position;
432455
} else if (non_zero_num == 1) {
433-
for (int index = subarray_index; index < subarray_index + CONFIG_TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL; index++) {
456+
// Search for non-zero elements within actual window range
457+
uint8_t end_idx = (subarray_index + window_size > array_size) ? array_size : subarray_index + window_size;
458+
459+
for (uint8_t index = subarray_index; index < end_idx; index++) {
434460
if (0 != array[index]) {
435461
if (index == array_size - 1) {
436462
position = range;
@@ -441,7 +467,9 @@ static inline uint32_t slider_calculate_position(touch_slider_handle_t slider_ha
441467
}
442468
}
443469
} else {
444-
for (int idx = subarray_index; idx < subarray_index + CONFIG_TOUCH_SLIDER_SENSOR_CALCULATE_CHANNEL; idx++) {
470+
// Multiple channels have signals, use weighted average
471+
uint8_t end_idx = (subarray_index + window_size > array_size) ? array_size : subarray_index + window_size; // Prevent uint8_t overflow and ensure we don't exceed array bounds
472+
for (uint8_t idx = subarray_index; idx < end_idx; idx++) {
445473
position += ((float)idx * array[idx]);
446474
}
447475
position = position * scale / subarray_sum;
@@ -495,14 +523,14 @@ static inline uint32_t slider_filter_iir(uint32_t in_now, uint32_t out_last, uin
495523
*/
496524
static void slider_update_position(touch_slider_handle_t slider_handle)
497525
{
498-
int max_array_idx = 0;
526+
uint8_t max_array_idx = 0;
499527
float max_array_sum;
500528
uint8_t non_zero_num;
501529
uint32_t current_position;
502530

503531
slider_quantify_signal(slider_handle);
504-
max_array_sum = slider_search_max_subarray(slider_handle->quantify_signal_array, slider_handle->channel_num, &max_array_idx);
505-
non_zero_num = slider_get_non_zero_num(slider_handle->quantify_signal_array, max_array_idx);
532+
max_array_sum = slider_search_max_subarray(slider_handle->quantify_signal_array, slider_handle->channel_num, slider_handle->calculate_window, &max_array_idx);
533+
non_zero_num = slider_get_non_zero_num(slider_handle->quantify_signal_array, max_array_idx, slider_handle->calculate_window, slider_handle->channel_num);
506534
current_position = slider_calculate_position(slider_handle, max_array_idx, max_array_sum, non_zero_num);
507535
uint32_t position_average = slider_filter_average(slider_handle, current_position);
508536
slider_handle->last_position = slider_handle->position == 0 ? position_average : slider_handle->position;

0 commit comments

Comments
 (0)