Skip to content

Commit

Permalink
LilyGo T-Deck keyboard support
Browse files Browse the repository at this point in the history
  • Loading branch information
KenVanHoeylandt committed Jan 27, 2024
1 parent 14eb432 commit 0540c3f
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 55 deletions.
54 changes: 43 additions & 11 deletions boards/lilygo_tdeck/bootstrap.c
Original file line number Diff line number Diff line change
@@ -1,29 +1,61 @@
#include "esp_log.h"
#include "driver/gpio.h"
#include "config.h"
#include "keyboard.h"
#include "kernel.h"
#include "esp_lvgl_port.h"
#include "log.h"

#define TAG "lilygo_tdeck_bootstrap"
#define TDECK_PERI_POWERON GPIO_NUM_10
#define TAG "tdeck_bootstrap"

lv_disp_t* lilygo_tdeck_init_display();

static void tdeck_power_on() {
static bool tdeck_power_on() {
ESP_LOGI(TAG, "power on");
gpio_config_t device_power_signal_config = {
.pin_bit_mask = BIT64(TDECK_PERI_POWERON),
.pin_bit_mask = BIT64(TDECK_POWERON_GPIO),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&device_power_signal_config);
gpio_set_level(TDECK_PERI_POWERON, 1);

if (gpio_config(&device_power_signal_config) != ESP_OK) {
return false;
}

if (gpio_set_level(TDECK_POWERON_GPIO, 1) != ESP_OK) {
return false;
}

return true;
}

void lilygo_tdeck_bootstrap() {
tdeck_power_on();
static bool init_i2c() {
const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_18,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_io_num = GPIO_NUM_8,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
.master.clk_speed = 400000
};

return i2c_param_config(TDECK_I2C_BUS_HANDLE, &i2c_conf) == ESP_OK
&& i2c_driver_install(TDECK_I2C_BUS_HANDLE, i2c_conf.mode, 0, 0, 0) == ESP_OK;
}

bool lilygo_tdeck_bootstrap() {
if (!tdeck_power_on()) {
TT_LOG_E(TAG, "failed to power on device");
}

// Give keyboard's ESP time to boot
// It uses I2C and seems to interfere with the touch driver
tt_delay_ms(500);

if (!init_i2c()) {
TT_LOG_E(TAG, "failed to init I2C");
}

keyboard_wait_for_response();

return true;
}
7 changes: 7 additions & 0 deletions boards/lilygo_tdeck/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "driver/i2c.h"
#include "driver/gpio.h"

#define TDECK_I2C_BUS_HANDLE (0)
#define TDECK_POWERON_GPIO GPIO_NUM_10
2 changes: 1 addition & 1 deletion boards/lilygo_tdeck/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "esp_log.h"
#include "esp_lvgl_port.h"

#define TAG "lilygo_tdeck_display"
#define TAG "tdeck_display"

#define LCD_SPI_HOST SPI2_HOST
#define LCD_PIN_SCLK GPIO_NUM_40
Expand Down
86 changes: 86 additions & 0 deletions boards/lilygo_tdeck/keyboard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include "keyboard.h"
#include "config.h"
#include "hal/lv_hal.h"
#include "tactility_core.h"
#include "ui/lvgl_keypad.h"
#include <driver/i2c.h>

#define TAG "tdeck_keyboard"
#define KEYBOARD_SLAVE_ADDRESS 0x55

typedef struct {
lv_indev_drv_t* driver;
lv_indev_t* device;
} KeyboardData;

static inline esp_err_t keyboard_i2c_read(uint8_t* output) {
return i2c_master_read_from_device(
TDECK_I2C_BUS_HANDLE,
KEYBOARD_SLAVE_ADDRESS,
output,
1,
configTICK_RATE_HZ / 10
);
}

void keyboard_wait_for_response() {
TT_LOG_I(TAG, "wake await...");
bool awake = false;
uint8_t read_buffer = 0x00;
do {
awake = keyboard_i2c_read(&read_buffer) == ESP_OK;
if (!awake) {
tt_delay_ms(100);
}
} while (!awake);
TT_LOG_I(TAG, "awake");
}

static void keyboard_read_callback(struct _lv_indev_drv_t* indev_drv, lv_indev_data_t* data) {
static uint8_t last_buffer = 0x00;
uint8_t read_buffer = 0x00;

// Defaults
data->key = 0;
data->state = LV_INDEV_STATE_RELEASED;

if (keyboard_i2c_read(&read_buffer) == ESP_OK) {
if (read_buffer == 0 && read_buffer != last_buffer) {
TT_LOG_I(TAG, "released %d", last_buffer);
data->key = last_buffer;
data->state = LV_INDEV_STATE_RELEASED;
} else if (read_buffer != 0) {
TT_LOG_I(TAG, "pressed %d", read_buffer);
data->key = read_buffer;
data->state = LV_INDEV_STATE_PRESSED;
}
}

last_buffer = read_buffer;
}

Keyboard keyboard_alloc(_Nullable lv_disp_t* display) {
KeyboardData* data = malloc(sizeof(KeyboardData));

data->driver = malloc(sizeof(lv_indev_drv_t));
memset(data->driver, 0, sizeof(lv_indev_drv_t));
lv_indev_drv_init(data->driver);

data->driver->type = LV_INDEV_TYPE_KEYPAD;
data->driver->read_cb = &keyboard_read_callback;
data->driver->disp = display;

data->device = lv_indev_drv_register(data->driver);
tt_check(data->device != NULL);

tt_lvgl_keypad_set_indev(data->device);

return data;
}

void keyboard_free(Keyboard keyboard) {
KeyboardData* data = (KeyboardData*)keyboard;
lv_indev_delete(data->device);
free(data->driver);
free(data);
}
18 changes: 18 additions & 0 deletions boards/lilygo_tdeck/keyboard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "lvgl.h"

#ifdef __cplusplus
extern "C" {
#endif

void keyboard_wait_for_response();

typedef void* Keyboard;

Keyboard keyboard_alloc(_Nullable lv_disp_t* display);
void keyboard_free(Keyboard keyboard);

#ifdef __cplusplus
}
#endif
6 changes: 4 additions & 2 deletions boards/lilygo_tdeck/lvgl.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include "esp_lvgl_port.h"
#include "keyboard.h"
#include "log.h"
#include "ui/lvgl_sync.h"
#include <thread.h>

#define TAG "lilygo_tdeck_lvgl"
#define TAG "tdeck_lvgl"

lv_disp_t* lilygo_tdeck_init_display();
bool lilygo_tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle);
Expand Down Expand Up @@ -33,7 +34,6 @@ bool lilygo_init_lvgl() {
return false;
}


// Add touch
if (!lilygo_tdeck_init_touch(&touch_io_handle, &touch_handle)) {
return false;
Expand All @@ -53,5 +53,7 @@ bool lilygo_init_lvgl() {
// Set syncing functions
tt_lvgl_sync_set(&lvgl_port_lock, &lvgl_port_unlock);

keyboard_alloc(display);

return true;
}
31 changes: 5 additions & 26 deletions boards/lilygo_tdeck/touch.c
Original file line number Diff line number Diff line change
@@ -1,37 +1,16 @@
#include "config.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/i2c.h"

#define TOUCH_I2C_PORT 0

#define TAG "lilygo_tdeck_touch"
#define TAG "tdeck_touch"

bool lilygo_tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle) {
ESP_LOGI(TAG, "creating touch");

const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_18,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_io_num = GPIO_NUM_8,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
.master.clk_speed = 400000
};

if (i2c_param_config(TOUCH_I2C_PORT, &i2c_conf) != ESP_OK) {
ESP_LOGE(TAG, "i2c config failed");
return false;
}

if (i2c_driver_install(TOUCH_I2C_PORT, i2c_conf.mode, 0, 0, 0) != ESP_OK) {
ESP_LOGE(TAG, "i2c driver install failed");
return false;
}

const esp_lcd_panel_io_i2c_config_t touch_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();

if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TOUCH_I2C_PORT, &touch_io_config, io_handle) != ESP_OK) {
if (esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TDECK_I2C_BUS_HANDLE, &touch_io_config, io_handle) != ESP_OK) {
ESP_LOGE(TAG, "touch io i2c creation failed");
return false;
}
Expand Down
25 changes: 18 additions & 7 deletions tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "lvgl.h"
#include "services/gui/gui.h"
#include "services/wifi/wifi_credentials.h"
#include "ui/lvgl_keypad.h"
#include "ui/spacer.h"
#include "ui/style.h"
#include "wifi_connect.h"
Expand Down Expand Up @@ -103,12 +104,14 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {

wifi_connect_view_create_bottom_buttons(wifi, parent);

lv_obj_add_event_cb(view->ssid_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_READY, NULL);
lv_obj_add_event_cb(view->password_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_READY, NULL);
if (gui_keyboard_is_enabled()) {
lv_obj_add_event_cb(view->ssid_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_READY, NULL);
lv_obj_add_event_cb(view->password_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_READY, NULL);
}

// Init from app parameters
Bundle* _Nullable bundle = tt_app_get_parameters(app);
Expand All @@ -123,10 +126,18 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {
lv_textarea_set_text(view->password_textarea, password);
}
}

// Hardware keyboard("keypad") requires a group
view->group = lv_group_create();
lv_group_add_obj(view->group, view->ssid_textarea);
lv_group_add_obj(view->group, view->password_textarea);
tt_lvgl_keypad_activate(view->group);
}

void wifi_connect_view_destroy(TT_UNUSED WifiConnectView* view) {
// NO-OP
// Cleanup keypad group
tt_lvgl_keypad_deactivate();
lv_group_del(view->group);
}

void wifi_connect_view_update(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef struct {
lv_obj_t* connect_button;
lv_obj_t* cancel_button;
lv_obj_t* remember_switch;
lv_group_t* group;
} WifiConnectView;

void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent);
Expand Down
6 changes: 3 additions & 3 deletions tactility/src/hardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
void tt_hardware_init(const HardwareConfig* config) {
if (config->bootstrap != NULL) {
TT_LOG_I(TAG, "Bootstrapping");
config->bootstrap();
tt_check(config->bootstrap(), "bootstrap failed");
}

tt_check(config->init_lvgl);
config->init_lvgl();
tt_check(config->init_lvgl, "lvlg init not set");
tt_check(config->init_lvgl(), "lvgl init failed");
}
13 changes: 8 additions & 5 deletions tactility/src/services/gui/gui.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
#include "gui_i.h"

#include "check.h"
#include "core_extra_defines.h"
#include "tactility.h"
#include "ui/lvgl_sync.h"
#include "kernel.h"
#include "log.h"
#include "ui/lvgl_keypad.h"

#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
Expand All @@ -30,7 +28,7 @@ Gui* gui_alloc() {
&gui_main,
NULL
);
instance->mutex = tt_mutex_alloc(MutexTypeNormal);
instance->mutex = tt_mutex_alloc(MutexTypeRecursive);
instance->keyboard = NULL;

tt_check(tt_lvgl_lock(1000 / portTICK_PERIOD_MS));
Expand Down Expand Up @@ -102,6 +100,10 @@ void gui_keyboard_hide() {
}
}

bool gui_keyboard_is_enabled() {
return tt_lvgl_keypad_is_available() && !FORCE_ONSCREEN_KEYBOARD;
}

void gui_hide_app() {
gui_lock();
ViewPort* view_port = gui->app_view_port;
Expand Down Expand Up @@ -158,6 +160,7 @@ static void gui_stop(TT_UNUSED Service service) {
ThreadId thread_id = tt_thread_get_id(gui->thread);
tt_thread_flags_set(thread_id, GUI_THREAD_FLAG_EXIT);
tt_thread_join(gui->thread);
tt_thread_free(gui->thread);

gui_unlock();

Expand Down
3 changes: 3 additions & 0 deletions tactility/src/services/gui/gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "app.h"
#include "service_manifest.h"
#include "view_port.h"
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -18,6 +19,8 @@ void gui_keyboard_show(lv_obj_t* textarea);

void gui_keyboard_hide();

bool gui_keyboard_is_enabled();

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit 0540c3f

Please sign in to comment.