zephyr/modules/lvgl/input/lvgl_pointer_kscan.c
Fabian Blatz 5e5d9f481c modules: lvgl: Move lvgl kscan pointer handling to separate file
Moves lvgl pointer driver handling based on kscan to its own file, to ease
deletion when the usage of kscan for display touch input has been
deprecated.

Signed-off-by: Fabian Blatz <fabianblatz@gmail.com>
2023-08-29 10:17:52 +02:00

150 lines
3.7 KiB
C

/*
* Copyright 2023 Fabian Blatz <fabianblatz@gmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <lvgl.h>
#include <zephyr/drivers/kscan.h>
#include <zephyr/kernel.h>
#include "lvgl_display.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(lvgl);
static lv_indev_drv_t indev_drv;
#define KSCAN_NODE DT_CHOSEN(zephyr_keyboard_scan)
K_MSGQ_DEFINE(kscan_msgq, sizeof(lv_indev_data_t), CONFIG_LV_Z_POINTER_KSCAN_MSGQ_COUNT, 4);
static void lvgl_pointer_kscan_callback(const struct device *dev, uint32_t row, uint32_t col,
bool pressed)
{
lv_indev_data_t data = {
.point.x = col,
.point.y = row,
.state = pressed ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL,
};
if (k_msgq_put(&kscan_msgq, &data, K_NO_WAIT) != 0) {
LOG_DBG("Could not put input data into queue");
}
}
static void lvgl_pointer_kscan_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
lv_disp_t *disp;
struct lvgl_disp_data *disp_data;
struct display_capabilities *cap;
lv_indev_data_t curr;
static lv_indev_data_t prev = {
.point.x = 0,
.point.y = 0,
.state = LV_INDEV_STATE_REL,
};
if (k_msgq_get(&kscan_msgq, &curr, K_NO_WAIT) != 0) {
goto set_and_release;
}
prev = curr;
disp = lv_disp_get_default();
disp_data = disp->driver->user_data;
cap = &disp_data->cap;
/* adjust kscan coordinates */
if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_SWAP_XY)) {
lv_coord_t x;
x = prev.point.x;
prev.point.x = prev.point.y;
prev.point.y = x;
}
if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_INVERT_X)) {
if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
prev.point.x = cap->x_resolution - prev.point.x;
} else {
prev.point.x = cap->y_resolution - prev.point.x;
}
}
if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN_INVERT_Y)) {
if (cap->current_orientation == DISPLAY_ORIENTATION_NORMAL ||
cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
prev.point.y = cap->y_resolution - prev.point.y;
} else {
prev.point.y = cap->x_resolution - prev.point.y;
}
}
/* rotate touch point to match display rotation */
if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_90) {
lv_coord_t x;
x = prev.point.x;
prev.point.x = prev.point.y;
prev.point.y = cap->y_resolution - x;
} else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_180) {
prev.point.x = cap->x_resolution - prev.point.x;
prev.point.y = cap->y_resolution - prev.point.y;
} else if (cap->current_orientation == DISPLAY_ORIENTATION_ROTATED_270) {
lv_coord_t x;
x = prev.point.x;
prev.point.x = cap->x_resolution - prev.point.y;
prev.point.y = x;
}
/* filter readings within display */
if (prev.point.x <= 0) {
prev.point.x = 0;
} else if (prev.point.x >= cap->x_resolution) {
prev.point.x = cap->x_resolution - 1;
}
if (prev.point.y <= 0) {
prev.point.y = 0;
} else if (prev.point.y >= cap->y_resolution) {
prev.point.y = cap->y_resolution - 1;
}
set_and_release:
*data = prev;
data->continue_reading = k_msgq_num_used_get(&kscan_msgq) > 0;
}
static int lvgl_kscan_pointer_init(void)
{
const struct device *kscan_dev = DEVICE_DT_GET(KSCAN_NODE);
if (!device_is_ready(kscan_dev)) {
LOG_ERR("Keyboard scan device not ready.");
return -ENODEV;
}
if (kscan_config(kscan_dev, lvgl_pointer_kscan_callback) < 0) {
LOG_ERR("Could not configure keyboard scan device.");
return -ENODEV;
}
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = lvgl_pointer_kscan_read;
if (lv_indev_drv_register(&indev_drv) == NULL) {
LOG_ERR("Failed to register input device.");
return -EPERM;
}
kscan_enable_callback(kscan_dev);
return 0;
}
SYS_INIT(lvgl_kscan_pointer_init, APPLICATION, CONFIG_LV_Z_INPUT_INIT_PRIORITY);