Skip to content

Commit b2608b1

Browse files
author
Jamie C. Driver
committed
input: refactor input.c into several files per input device/config
Make navigation button handling consistent for hold/repeat events and for treating both navigation buttons pressed simultaneously as a 'click/select' event. Extract touchscreen and rotary wheel handling into their own files.
1 parent 41b9be5 commit b2608b1

File tree

10 files changed

+423
-382
lines changed

10 files changed

+423
-382
lines changed

main/camera.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
#include "power.h"
1010
#include "sensitive.h"
1111
#include "ui.h"
12-
#if defined(CONFIG_DISPLAY_TOUCHSCREEN)
13-
#include "input.h"
14-
#endif
1512
#include "utils/event.h"
1613
#include "utils/malloc_ext.h"
1714

15+
#if defined(CONFIG_DISPLAY_TOUCHSCREEN)
16+
void touchscreen_init(void);
17+
void touchscreen_deinit(void);
18+
#endif
19+
1820
#ifdef CONFIG_DEBUG_MODE
1921
// Debug/testing function to cache an image - the next time the camera is called
2022
// a frame is captured but is ignored/discarded and this image presented instead.

main/input.c

Lines changed: 16 additions & 354 deletions
Original file line numberDiff line numberDiff line change
@@ -1,360 +1,22 @@
11
#include "input.h"
2-
#include "gui.h"
3-
#include "iot_button.h"
4-
#include "jade_assert.h"
5-
#include "jade_tasks.h"
6-
#include "rotary_encoder.h"
7-
#include "utils/malloc_ext.h"
2+
#include "sdkconfig.h"
83

9-
#if defined(CONFIG_DISPLAY_TOUCHSCREEN)
10-
#include <esp_lcd_touch.h>
11-
#include <esp_lcd_touch_ft5x06.h>
12-
#endif
13-
14-
void input_init(void) {}
15-
16-
#if defined(CONFIG_DISPLAY_TOUCHSCREEN)
17-
static volatile bool shutdown_requested = false;
18-
static volatile bool shutdown_finished = false;
19-
20-
esp_err_t _i2c_init_master(i2c_port_t port_num, int sda_io_num, int scl_io_num, uint32_t clk_speed);
21-
esp_err_t _i2c_deinit(i2c_port_t port_num);
22-
23-
static void touchscreen_task(void* ignored)
24-
{
25-
esp_lcd_touch_handle_t ret_touch = NULL;
26-
// FIXME: check mirror flags?
27-
const esp_lcd_touch_config_t tp_cfg = {
28-
.x_max = CONFIG_DISPLAY_WIDTH + CONFIG_DISPLAY_OFFSET_X,
29-
.y_max = CONFIG_DISPLAY_HEIGHT + CONFIG_DISPLAY_OFFSET_Y,
30-
.rst_gpio_num = GPIO_NUM_NC,
31-
.int_gpio_num = GPIO_NUM_NC,
32-
.levels = {
33-
.reset = 0,
34-
.interrupt = 0,
35-
},
36-
.flags = {
37-
.swap_xy = 0,
38-
.mirror_x = 0,
39-
.mirror_y = 0,
40-
},
41-
};
42-
43-
ESP_ERROR_CHECK(
44-
_i2c_init_master(CONFIG_DISPLAY_TOUCHSCREEN_I2C, CONFIG_I2C_TOUCH_SDA, CONFIG_I2C_TOUCH_SCL, 10000));
45-
46-
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
47-
esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();
48-
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c(CONFIG_DISPLAY_TOUCHSCREEN_I2C, &tp_io_config, &tp_io_handle));
49-
ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &ret_touch));
50-
51-
uint16_t touch_x[1];
52-
uint16_t touch_y[1];
53-
uint16_t touch_strength[1];
54-
uint8_t touch_cnt = 10;
55-
56-
// FIXME: don't allow multiple touches within 300 ms?
57-
// FIXME: this doesn't currently work with Display -> Flip Orientation feature
58-
// but it could by changing the touch_y[0] > 200 logic with < 40 and inverting prev with next and viceversa
59-
while (!shutdown_requested) {
60-
if (esp_lcd_touch_read_data(ret_touch) == ESP_OK) {
61-
bool touchpad_pressed
62-
= esp_lcd_touch_get_coordinates(ret_touch, touch_x, touch_y, touch_strength, &touch_cnt, 1);
63-
if (touchpad_pressed) {
64-
const uint16_t first_third_end = CONFIG_DISPLAY_WIDTH / 3;
65-
const uint16_t middle_thirds_end = (CONFIG_DISPLAY_WIDTH * 2) / 3;
66-
if (touch_y[0] > 200) {
67-
if (touch_x[0] <= first_third_end) {
68-
gui_prev();
69-
} else if (touch_x[0] > first_third_end && touch_x[0] < middle_thirds_end) {
70-
gui_front_click();
71-
} else if (touch_x[0] >= middle_thirds_end) {
72-
gui_next();
73-
} else {
74-
continue;
75-
}
76-
vTaskDelay(100 / portTICK_PERIOD_MS);
77-
}
78-
}
79-
}
80-
vTaskDelay(20 / portTICK_PERIOD_MS);
81-
}
82-
ESP_ERROR_CHECK(_i2c_deinit(CONFIG_DISPLAY_TOUCHSCREEN_I2C));
83-
shutdown_finished = true;
84-
vTaskDelete(NULL);
85-
}
86-
87-
void touchscreen_init(void)
88-
{
89-
const BaseType_t retval = xTaskCreatePinnedToCore(
90-
&touchscreen_task, "touchscreen task", 3 * 1024, NULL, JADE_TASK_PRIO_WHEEL, NULL, JADE_CORE_PRIMARY);
91-
JADE_ASSERT_MSG(
92-
retval == pdPASS, "Failed to create touchscreen task, xTaskCreatePinnedToCore() returned %d", retval);
93-
}
94-
95-
void touchscreen_deinit(void)
96-
{
97-
shutdown_requested = true;
98-
while (!shutdown_finished) {
99-
vTaskDelay(100 / portTICK_PERIOD_MS);
100-
}
101-
shutdown_requested = false;
102-
shutdown_finished = false;
103-
}
104-
#endif
105-
106-
#if CONFIG_INPUT_FRONT_SW >= 0
107-
static void button_front_release(void* arg, void* ctx) { gui_front_click(); }
108-
109-
static void button_front_long(void* arg, void* ctx)
110-
{
111-
JADE_LOGW("front-btn long-press ignored");
112-
// gui_front_click();
113-
}
114-
#endif
115-
116-
#if CONFIG_INPUT_WHEEL_SW >= 0
117-
static void button_wheel_release(void* arg, void* ctx) { gui_wheel_click(); }
118-
119-
static void button_wheel_long(void* arg, void* ctx)
120-
{
121-
JADE_LOGW("wheel long-press ignored");
122-
// gui_wheel_click();
123-
}
124-
#endif
125-
126-
void button_init(void)
127-
{
128-
#if CONFIG_INPUT_FRONT_SW >= 0
129-
button_config_t front_sw_btn_cfg = {
130-
.type = BUTTON_TYPE_GPIO,
131-
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
132-
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
133-
.gpio_button_config = {
134-
.gpio_num = CONFIG_INPUT_FRONT_SW,
135-
.active_level = 0,
136-
},
137-
};
138-
button_handle_t btn_handle_front = iot_button_create(&front_sw_btn_cfg);
139-
iot_button_register_cb(btn_handle_front, BUTTON_PRESS_UP, button_front_release, NULL);
140-
iot_button_register_cb(btn_handle_front, BUTTON_LONG_PRESS_START, button_front_long, NULL);
141-
#endif
142-
143-
#if CONFIG_INPUT_WHEEL_SW >= 0
144-
button_config_t wheel_btn_cfg = {
145-
.type = BUTTON_TYPE_GPIO,
146-
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
147-
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
148-
.gpio_button_config = {
149-
.gpio_num = CONFIG_INPUT_WHEEL_SW,
150-
.active_level = 0,
151-
},
152-
};
153-
button_handle_t btn_handle_wheel = iot_button_create(&wheel_btn_cfg);
154-
iot_button_register_cb(btn_handle_wheel, BUTTON_PRESS_UP, button_wheel_release, NULL);
155-
iot_button_register_cb(btn_handle_wheel, BUTTON_LONG_PRESS_START, button_wheel_long, NULL);
156-
#endif
157-
}
158-
159-
#if !defined(CONFIG_BOARD_TYPE_JADE) && !defined(CONFIG_DISPLAY_TOUCHSCREEN)
160-
static void wheel_common(button_handle_t* btn_handle_prev, button_handle_t* btn_handle_next)
161-
{
162-
button_config_t prev_btn_cfg = {
163-
.type = BUTTON_TYPE_GPIO,
164-
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
165-
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
166-
.gpio_button_config = {
167-
.gpio_num = CONFIG_INPUT_BTN_A,
168-
.active_level = 0,
169-
},
170-
};
171-
*btn_handle_prev = iot_button_create(&prev_btn_cfg);
172-
173-
button_config_t next_btn_cfg = {
174-
.type = BUTTON_TYPE_GPIO,
175-
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
176-
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
177-
.gpio_button_config = {
178-
.gpio_num = CONFIG_INPUT_BTN_B,
179-
#ifdef CONFIG_BUTTON_B_ACTIVE_HIGH
180-
.active_level = 1,
181-
#else
182-
.active_level = 0,
183-
#endif
184-
},
185-
};
186-
*btn_handle_next = iot_button_create(&next_btn_cfg);
187-
}
188-
#endif
189-
190-
#if defined(CONFIG_BOARD_TYPE_JADE)
191-
// Original Jade v1.0 hardware has a rotary-encoder/wheel
192-
193-
// Set to true to enable tracking of rotary encoder at half step resolution
194-
#define ENABLE_HALF_STEPS false
195-
196-
// Set to true to reverse the clockwise/counterclockwise sense
197-
#ifdef CONFIG_INPUT_INVERT_WHEEL
198-
#define FLIP_DIRECTION true
4+
#if defined(CONFIG_ETH_USE_OPENETH)
5+
#include <input/noinput.inc>
6+
#elif defined(CONFIG_DISPLAY_TOUCHSCREEN)
7+
#include <input/touchscreen.inc>
8+
#elif defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS) || defined(CONFIG_INPUT_ONE_BUTTON_MODE)
9+
#include <input/singlebtn.inc>
10+
#elif defined(CONFIG_BOARD_TYPE_JADE)
11+
#include <input/selectbtn.inc>
12+
#include <input/wheel.inc>
19913
#else
200-
#define FLIP_DIRECTION false
201-
#endif
202-
203-
// Jade proper wheel init
204-
static QueueHandle_t event_queue;
205-
static rotary_encoder_info_t info = {};
206-
207-
void wheel_watch_task(void* unused)
208-
{
209-
int32_t last_position = 0;
210-
211-
for (;;) {
212-
rotary_encoder_event_t event = { 0 };
213-
if (xQueueReceive(event_queue, &event, 1000 / portTICK_PERIOD_MS) == pdTRUE) {
214-
if (event.state.position < last_position) {
215-
gui_prev();
216-
} else {
217-
gui_next();
218-
}
219-
220-
last_position = event.state.position;
221-
}
222-
}
223-
224-
JADE_LOGE("queue receive failed");
225-
vTaskDelete(NULL);
226-
}
227-
228-
void wheel_init(void)
229-
{
230-
// Create a queue for events from the rotary encoder driver.
231-
event_queue = rotary_encoder_create_queue();
232-
233-
esp_err_t rc = gpio_install_isr_service(0);
234-
JADE_ASSERT(rc == ESP_OK);
235-
236-
rc = rotary_encoder_init(&info, CONFIG_INPUT_WHEEL_A, CONFIG_INPUT_WHEEL_B);
237-
JADE_ASSERT(rc == ESP_OK);
238-
rc = rotary_encoder_enable_half_steps(&info, ENABLE_HALF_STEPS);
239-
JADE_ASSERT(rc == ESP_OK);
240-
#ifdef FLIP_DIRECTION
241-
rc = rotary_encoder_flip_direction(&info);
242-
JADE_ASSERT(rc == ESP_OK);
243-
#endif
244-
JADE_ASSERT(event_queue);
245-
246-
// Tasks can read from this queue to receive up to date position information.
247-
rc = rotary_encoder_set_queue(&info, event_queue);
248-
JADE_ASSERT(rc == ESP_OK);
249-
250-
const BaseType_t retval = xTaskCreatePinnedToCore(
251-
&wheel_watch_task, "wheel_watcher", 2 * 1024, NULL, JADE_TASK_PRIO_WHEEL, NULL, JADE_CORE_SECONDARY);
252-
JADE_ASSERT_MSG(
253-
retval == pdPASS, "Failed to create wheel_watcher task, xTaskCreatePinnedToCore() returned %d", retval);
254-
}
255-
256-
#elif defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAY) || defined(CONFIG_BOARD_TYPE_TTGO_TDISPLAYS3)
257-
// wheel_init() to mock wheel with buttons
258-
259-
// Slightly complicated to allow both-buttons pressed to mock selection button
260-
// To acheive this we only action the button when it is released - and we check
261-
// to see if the other button is depressed at the time.
262-
static bool button_A_pressed = false;
263-
static bool button_B_pressed = false;
264-
265-
static void button_pressed(void* arg, void* ctx)
266-
{
267-
JADE_ASSERT(ctx);
268-
bool* button = ctx;
269-
*button = true;
270-
}
271-
272-
static void button_released(void* arg, void* ctx)
273-
{
274-
JADE_ASSERT(ctx);
275-
// button_A_pressed or button_B_pressed passed in ctx to indicate which was released
276-
if (button_A_pressed && button_B_pressed) {
277-
gui_front_click();
278-
} else if (button_A_pressed && ctx == &button_A_pressed) {
279-
gui_prev();
280-
} else if (button_B_pressed && ctx == &button_B_pressed) {
281-
gui_next();
282-
}
283-
284-
// Clear both flags here so we ignore the second button release when both pressed
285-
button_B_pressed = false;
286-
button_A_pressed = false;
287-
}
288-
289-
void wheel_init(void)
290-
{
291-
#if !defined(CONFIG_DISPLAY_TOUCHSCREEN)
292-
button_handle_t btn_handle_prev = NULL;
293-
button_handle_t btn_handle_next = NULL;
294-
wheel_common(&btn_handle_prev, &btn_handle_next);
295-
iot_button_register_cb(btn_handle_prev, BUTTON_PRESS_DOWN, button_pressed, &button_A_pressed);
296-
iot_button_register_cb(btn_handle_prev, BUTTON_PRESS_UP, button_released, &button_A_pressed);
297-
iot_button_register_cb(btn_handle_next, BUTTON_PRESS_DOWN, button_pressed, &button_B_pressed);
298-
iot_button_register_cb(btn_handle_next, BUTTON_PRESS_UP, button_released, &button_B_pressed);
14+
#include <input/navbtns.inc>
15+
#include <input/selectbtn.inc>
29916
#endif
300-
}
301-
#elif defined(CONFIG_BOARD_TYPE_M5_STICKC_PLUS) || defined(CONFIG_INPUT_ONE_BUTTON_MODE)
302-
/*
303-
M5StickC-Plus is similar to the TTGO T-Display in that it is two buttons,
304-
but one of the buttons behaves badly when Bluetooth is active.
305-
*/
306-
307-
// In the case of the M5StickC-Plus, the A button stops giving a "Released" event.
308-
// As such, the A button simply looks for input when the button is pressed and calls "Prev"
309-
310-
static void button_A_pressed(void* arg, void* ctx) { gui_prev(); }
31117

312-
// The B button works fine, so it makes sense to have the "Front Click" as long click on the "B" Button
313-
// (On the front face of the device) and also have the short click be "Next"
314-
315-
static uint64_t button_B_pressed_time = 0;
316-
static void button_B_pressed(void* arg, void* ctx) { button_B_pressed_time = xTaskGetTickCount(); }
317-
318-
static void button_B_released(void* arg, void* ctx)
18+
void input_init(void)
31919
{
320-
const uint64_t current = xTaskGetTickCount();
321-
if ((current - button_B_pressed_time) > 50) {
322-
gui_front_click();
323-
} else {
324-
gui_next();
325-
}
326-
}
327-
328-
void wheel_init(void)
329-
{
330-
button_handle_t btn_handle_prev = NULL;
331-
button_handle_t btn_handle_next = NULL;
332-
wheel_common(&btn_handle_prev, &btn_handle_next);
333-
iot_button_register_cb(btn_handle_prev, BUTTON_PRESS_DOWN, button_A_pressed, NULL);
334-
iot_button_register_cb(btn_handle_next, BUTTON_PRESS_DOWN, button_B_pressed, NULL);
335-
iot_button_register_cb(btn_handle_next, BUTTON_PRESS_UP, button_B_released, NULL);
336-
}
337-
#elif !defined(CONFIG_DISPLAY_TOUCHSCREEN)
338-
// wheel_init() to mock wheel with buttons
339-
// Long press buttons mocks wheel spin (multiple events)
340-
static void button_A_pressed(void* arg, void* ctx) { gui_prev(); }
341-
342-
static void button_B_pressed(void* arg, void* ctx) { gui_next(); }
343-
344-
void wheel_init(void)
345-
{
346-
button_handle_t btn_handle_prev = NULL;
347-
button_handle_t btn_handle_next = NULL;
348-
wheel_common(&btn_handle_prev, &btn_handle_next);
349-
iot_button_register_cb(btn_handle_prev, BUTTON_PRESS_UP, button_A_pressed, NULL);
350-
iot_button_register_cb(btn_handle_next, BUTTON_PRESS_UP, button_B_pressed, NULL);
351-
352-
// M5Stack-Basic/Fire hw has three buttons, but the A button behaves behaves badly when Bluetooth is active.
353-
// In this case the A button generates constant input if serial input is enabled, so the simplest fix is to remove
354-
// the ability to hold the button down (ie. do not add serial event handlers).
355-
#if (!defined(CONFIG_BT_ENABLED)) || (!defined(CONFIG_BOARD_TYPE_M5_BLACK_GRAY) && !defined(CONFIG_BOARD_TYPE_M5_FIRE))
356-
iot_button_register_cb(btn_handle_prev, BUTTON_LONG_PRESS_HOLD, button_A_pressed, NULL);
357-
iot_button_register_cb(btn_handle_next, BUTTON_LONG_PRESS_HOLD, button_B_pressed, NULL);
358-
#endif
359-
}
360-
#endif // CONFIG_BOARD_TYPE_xxx / !CONFIG_DISPLAY_TOUCHSCREEN
20+
navigation_init();
21+
select_init();
22+
}

0 commit comments

Comments
 (0)