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