Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8c5a55fe8 | |||
| 56bbd6a90e |
@@ -0,0 +1,4 @@
|
|||||||
|
idf_component_register(
|
||||||
|
SRCS "source/module.cpp"
|
||||||
|
REQUIRES TactilityKernel
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
general.vendor=LCDWIKI/Hosyond
|
||||||
|
general.name=ES3C35P
|
||||||
|
|
||||||
|
apps.launcherAppId=Launcher
|
||||||
|
|
||||||
|
hardware.target=ESP32S3
|
||||||
|
hardware.flashSize=16MB
|
||||||
|
hardware.spiRam=true
|
||||||
|
hardware.spiRamMode=OCT
|
||||||
|
hardware.spiRamSpeed=120M
|
||||||
|
hardware.esptoolFlashFreq=120M
|
||||||
|
hardware.tinyUsb=true
|
||||||
|
hardware.bluetooth=true
|
||||||
|
|
||||||
|
display.size=3.5"
|
||||||
|
display.shape=rectangle
|
||||||
|
display.dpi=165
|
||||||
|
|
||||||
|
lvgl.colorDepth=16
|
||||||
|
|
||||||
|
storage.userDataLocation=SD
|
||||||
|
|
||||||
|
dependencies.useDeprecatedHal=false
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
dependencies:
|
||||||
|
- Platforms/platform-esp32
|
||||||
|
- Drivers/st77922-module
|
||||||
|
- Drivers/es8311-module
|
||||||
|
- Drivers/audio-stream-module
|
||||||
|
dts: es3c35p.dts
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/dts-v1/;
|
||||||
|
|
||||||
|
#include <tactility/bindings/root.h>
|
||||||
|
#include <tactility/bindings/esp32_adc_oneshot.h>
|
||||||
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
|
#include <tactility/bindings/esp32_pwm_ledc.h>
|
||||||
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
|
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||||
|
#include <tactility/bindings/battery_sense.h>
|
||||||
|
#include <tactility/bindings/gpio_hog.h>
|
||||||
|
#include <tactility/bindings/pwm_backlight.h>
|
||||||
|
#include <bindings/st77922.h>
|
||||||
|
#include <bindings/st77922_touch.h>
|
||||||
|
#include <bindings/es8311.h>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
compatible = "root";
|
||||||
|
model = "LCDWIKI/Hosyond ES3C35P";
|
||||||
|
|
||||||
|
wifi0 {
|
||||||
|
compatible = "espressif,esp32-wifi-pinned";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
ble0 {
|
||||||
|
compatible = "espressif,esp32-ble";
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
|
gpio0 {
|
||||||
|
compatible = "espressif,esp32-gpio";
|
||||||
|
gpio-count = <49>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FM8002E speaker amplifier enable, active-low on GPIO1. */
|
||||||
|
amp_enable {
|
||||||
|
compatible = "gpio-hog";
|
||||||
|
pin = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
|
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
|
||||||
|
};
|
||||||
|
|
||||||
|
adc0 {
|
||||||
|
compatible = "espressif,esp32-adc-oneshot";
|
||||||
|
unit-id = <ADC_UNIT_1>;
|
||||||
|
clk-src = <ADC_RTC_CLK_SRC_DEFAULT>;
|
||||||
|
channels = <ADC_CHANNEL_7 ADC_ATTEN_DB_12 ADC_BITWIDTH_DEFAULT>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* BAT+ through a 200K/200K divider into GPIO8 / ADC1_CH7. */
|
||||||
|
battery-sense {
|
||||||
|
compatible = "battery-sense";
|
||||||
|
io-channel = <&adc0 0>;
|
||||||
|
reference-voltage-mv = <3300>;
|
||||||
|
multiplier = <2000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
i2s0 {
|
||||||
|
compatible = "espressif,esp32-i2s";
|
||||||
|
port = <I2S_NUM_0>;
|
||||||
|
pin-bclk = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||||
|
pin-ws = <&gpio0 21 GPIO_FLAG_NONE>;
|
||||||
|
pin-data-out = <&gpio0 15 GPIO_FLAG_NONE>;
|
||||||
|
pin-data-in = <&gpio0 16 GPIO_FLAG_NONE>;
|
||||||
|
pin-mclk = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||||
|
};
|
||||||
|
|
||||||
|
i2c0 {
|
||||||
|
compatible = "espressif,esp32-i2c";
|
||||||
|
port = <I2C_NUM_0>;
|
||||||
|
clock-frequency = <400000>;
|
||||||
|
pin-sda = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||||
|
pin-scl = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||||
|
|
||||||
|
touch@55 {
|
||||||
|
compatible = "sitronix,st77922-touch";
|
||||||
|
reg = <0x55>;
|
||||||
|
x-max = <320>;
|
||||||
|
y-max = <480>;
|
||||||
|
pin-reset = <&gpio0 48 GPIO_FLAG_NONE>;
|
||||||
|
pin-interrupt = <&gpio0 47 GPIO_FLAG_NONE>;
|
||||||
|
};
|
||||||
|
|
||||||
|
es8311: es8311@18 {
|
||||||
|
compatible = "everest,es8311";
|
||||||
|
reg = <0x18>;
|
||||||
|
i2s = <&i2s0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
display_backlight_pwm {
|
||||||
|
compatible = "espressif,esp32-pwm-ledc";
|
||||||
|
pin = <&gpio0 41 GPIO_FLAG_NONE>;
|
||||||
|
period-ns = <200000>;
|
||||||
|
ledc-timer = <0>;
|
||||||
|
ledc-channel = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
display_backlight {
|
||||||
|
compatible = "pwm-backlight";
|
||||||
|
status = "disabled";
|
||||||
|
pwm = <&display_backlight_pwm>;
|
||||||
|
};
|
||||||
|
|
||||||
|
spi0 {
|
||||||
|
compatible = "espressif,esp32-spi";
|
||||||
|
host = <SPI2_HOST>;
|
||||||
|
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||||
|
pin-mosi = <&gpio0 11 GPIO_FLAG_NONE>;
|
||||||
|
pin-miso = <&gpio0 13 GPIO_FLAG_NONE>;
|
||||||
|
pin-wp = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||||
|
pin-hd = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||||
|
cs-gpios = <&gpio0 10 GPIO_FLAG_NONE>;
|
||||||
|
/* Accommodate the driver's 1/10-frame DMA staging transfers, matching
|
||||||
|
* the vendor LVGL port's full-frame refresh path. */
|
||||||
|
max-transfer-size = <65536>;
|
||||||
|
|
||||||
|
display@0 {
|
||||||
|
compatible = "sitronix,st77922";
|
||||||
|
horizontal-resolution = <320>;
|
||||||
|
vertical-resolution = <480>;
|
||||||
|
/* 80 MHz works in the vendor demo, but produces visible QSPI corruption on
|
||||||
|
* some modules/cables. The component's 40 MHz default is reliably clean. */
|
||||||
|
pixel-clock-hz = <40000000>;
|
||||||
|
backlight = <&display_backlight>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sdmmc0 {
|
||||||
|
compatible = "espressif,esp32-sdmmc";
|
||||||
|
pin-clk = <&gpio0 5 GPIO_FLAG_NONE>;
|
||||||
|
pin-cmd = <&gpio0 4 GPIO_FLAG_NONE>;
|
||||||
|
pin-d0 = <&gpio0 6 GPIO_FLAG_NONE>;
|
||||||
|
pin-d1 = <&gpio0 7 GPIO_FLAG_NONE>;
|
||||||
|
pin-d2 = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
|
pin-d3 = <&gpio0 3 GPIO_FLAG_NONE>;
|
||||||
|
slot = <SDMMC_HOST_SLOT_1>;
|
||||||
|
bus-width = <4>;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
Module es3c35p_module = {
|
||||||
|
.name = "es3c35p"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||||
|
|
||||||
|
tactility_add_module(st77922-module
|
||||||
|
SRCS ${SOURCE_FILES}
|
||||||
|
INCLUDE_DIRS include/
|
||||||
|
REQUIRES TactilityKernel platform-esp32 esp_lcd_st77922 driver
|
||||||
|
)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
description: Touch interface integrated in the Sitronix ST77922 TDDI
|
||||||
|
|
||||||
|
include: ["i2c-device.yaml"]
|
||||||
|
|
||||||
|
compatible: "sitronix,st77922-touch"
|
||||||
|
|
||||||
|
bus: i2c
|
||||||
|
|
||||||
|
properties:
|
||||||
|
x-max:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Maximum X coordinate
|
||||||
|
y-max:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Maximum Y coordinate
|
||||||
|
swap-xy:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Swap the X and Y axes
|
||||||
|
mirror-x:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Mirror the X axis
|
||||||
|
mirror-y:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Mirror the Y axis
|
||||||
|
pin-reset:
|
||||||
|
type: phandles
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
description: Reset GPIO pin
|
||||||
|
pin-interrupt:
|
||||||
|
type: phandles
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
description: Interrupt GPIO pin
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
description: Sitronix ST77922 QSPI display panel
|
||||||
|
|
||||||
|
compatible: "sitronix,st77922"
|
||||||
|
|
||||||
|
bus: spi
|
||||||
|
|
||||||
|
properties:
|
||||||
|
horizontal-resolution:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Horizontal resolution in pixels
|
||||||
|
vertical-resolution:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Vertical resolution in pixels
|
||||||
|
mirror-x:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Mirror the X axis
|
||||||
|
mirror-y:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Mirror the Y axis
|
||||||
|
invert-color:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Invert the panel's color output
|
||||||
|
bgr-order:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Use BGR element order instead of RGB
|
||||||
|
bits-per-pixel:
|
||||||
|
type: int
|
||||||
|
default: 16
|
||||||
|
description: Color depth in bits per pixel
|
||||||
|
pixel-clock-hz:
|
||||||
|
type: int
|
||||||
|
default: 80000000
|
||||||
|
description: QSPI pixel clock frequency in Hz
|
||||||
|
transaction-queue-depth:
|
||||||
|
type: int
|
||||||
|
default: 10
|
||||||
|
description: Size of the internal SPI transaction queue
|
||||||
|
backlight:
|
||||||
|
type: phandle
|
||||||
|
default: "NULL"
|
||||||
|
description: Optional reference to this display's backlight device
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
dependencies:
|
||||||
|
- TactilityKernel
|
||||||
|
bindings: bindings
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <drivers/st77922.h>
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(st77922, struct St77922Config)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <drivers/st77922_touch.h>
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(st77922_touch, struct St77922TouchConfig)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
|
struct St77922Config {
|
||||||
|
uint16_t horizontal_resolution;
|
||||||
|
uint16_t vertical_resolution;
|
||||||
|
bool mirror_x;
|
||||||
|
bool mirror_y;
|
||||||
|
bool invert_color;
|
||||||
|
bool bgr_order;
|
||||||
|
uint32_t bits_per_pixel;
|
||||||
|
uint32_t pixel_clock_hz;
|
||||||
|
uint8_t transaction_queue_depth;
|
||||||
|
struct Device* backlight;
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tactility/drivers/gpio.h>
|
||||||
|
|
||||||
|
struct St77922TouchConfig {
|
||||||
|
uint8_t address;
|
||||||
|
uint16_t x_max;
|
||||||
|
uint16_t y_max;
|
||||||
|
bool swap_xy;
|
||||||
|
bool mirror_x;
|
||||||
|
bool mirror_y;
|
||||||
|
struct GpioPinSpec pin_reset;
|
||||||
|
struct GpioPinSpec pin_interrupt;
|
||||||
|
};
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern Module st77922_module;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Driver st77922_driver;
|
||||||
|
extern Driver st77922_touch_driver;
|
||||||
|
|
||||||
|
static Driver* const st77922_drivers[] = {
|
||||||
|
&st77922_driver,
|
||||||
|
&st77922_touch_driver,
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
Module st77922_module = {
|
||||||
|
.name = "st77922",
|
||||||
|
.drivers = st77922_drivers
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <drivers/st77922.h>
|
||||||
|
#include <st77922_module.h>
|
||||||
|
#include "st77922_init.h"
|
||||||
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/display.h>
|
||||||
|
#include <tactility/drivers/esp32_spi.h>
|
||||||
|
#include <tactility/drivers/spi_controller.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <esp_err.h>
|
||||||
|
#include <esp_heap_caps.h>
|
||||||
|
#include <esp_lcd_io_spi.h>
|
||||||
|
#include <esp_lcd_panel_io.h>
|
||||||
|
#include <esp_lcd_panel_ops.h>
|
||||||
|
#include <esp_lcd_st77922.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#define TAG "ST77922"
|
||||||
|
#define GET_CONFIG(device) (static_cast<const St77922Config*>((device)->config))
|
||||||
|
|
||||||
|
struct St77922Internal {
|
||||||
|
esp_lcd_panel_io_handle_t io_handle;
|
||||||
|
esp_lcd_panel_handle_t panel_handle;
|
||||||
|
SemaphoreHandle_t draw_done;
|
||||||
|
uint8_t* transfer_buffer;
|
||||||
|
size_t transfer_buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool IRAM_ATTR transfer_done(esp_lcd_panel_io_handle_t, esp_lcd_panel_io_event_data_t*, void* context) {
|
||||||
|
auto* internal = static_cast<St77922Internal*>(context);
|
||||||
|
BaseType_t task_woken = pdFALSE;
|
||||||
|
xSemaphoreGiveFromISR(internal->draw_done, &task_woken);
|
||||||
|
return task_woken == pdTRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
auto* parent = device_get_parent(device);
|
||||||
|
check(device_get_type(parent) == &SPI_CONTROLLER_TYPE);
|
||||||
|
const auto* spi = static_cast<const Esp32SpiConfig*>(parent->config);
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
GpioPinSpec cs;
|
||||||
|
if (esp32_spi_get_cs_pin(device, &cs) != ERROR_NONE) {
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* internal = static_cast<St77922Internal*>(calloc(1, sizeof(St77922Internal)));
|
||||||
|
if (internal == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
internal->draw_done = xSemaphoreCreateBinary();
|
||||||
|
if (internal->draw_done == nullptr) {
|
||||||
|
free(internal);
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
// The vendor port renders a complete frame in PSRAM, then copies it through a
|
||||||
|
// 1/10-frame DMA buffer. Besides making full-frame refresh possible, this keeps
|
||||||
|
// the panel's GRAM synchronized when animated objects invalidate old and new
|
||||||
|
// positions in separate LVGL regions.
|
||||||
|
const size_t bytes_per_pixel = config->bits_per_pixel / 8;
|
||||||
|
const size_t rows_per_transfer = config->vertical_resolution > 10
|
||||||
|
? config->vertical_resolution / 10 : config->vertical_resolution;
|
||||||
|
internal->transfer_buffer_size =
|
||||||
|
static_cast<size_t>(config->horizontal_resolution) * rows_per_transfer * bytes_per_pixel;
|
||||||
|
if (spi->max_transfer_size > 0
|
||||||
|
&& internal->transfer_buffer_size > static_cast<size_t>(spi->max_transfer_size)) {
|
||||||
|
internal->transfer_buffer_size = static_cast<size_t>(spi->max_transfer_size);
|
||||||
|
}
|
||||||
|
internal->transfer_buffer = static_cast<uint8_t*>(heap_caps_malloc(
|
||||||
|
internal->transfer_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
|
||||||
|
if (internal->transfer_buffer == nullptr) {
|
||||||
|
vSemaphoreDelete(internal->draw_done);
|
||||||
|
free(internal);
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_lcd_panel_io_spi_config_t io_config = {
|
||||||
|
.cs_gpio_num = static_cast<int>(cs.pin),
|
||||||
|
.dc_gpio_num = -1,
|
||||||
|
.spi_mode = 0,
|
||||||
|
.pclk_hz = config->pixel_clock_hz,
|
||||||
|
.trans_queue_depth = config->transaction_queue_depth,
|
||||||
|
.on_color_trans_done = transfer_done,
|
||||||
|
.user_ctx = internal,
|
||||||
|
.lcd_cmd_bits = 32,
|
||||||
|
.lcd_param_bits = 8,
|
||||||
|
.cs_ena_pretrans = 0,
|
||||||
|
.cs_ena_posttrans = 0,
|
||||||
|
.flags = {
|
||||||
|
.dc_high_on_cmd = 0,
|
||||||
|
.dc_low_on_data = 0,
|
||||||
|
.dc_low_on_param = 0,
|
||||||
|
.octal_mode = 0,
|
||||||
|
.quad_mode = 1,
|
||||||
|
.sio_mode = 0,
|
||||||
|
.lsb_first = 0,
|
||||||
|
.cs_high_active = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t result = esp_lcd_new_panel_io_spi(
|
||||||
|
static_cast<esp_lcd_spi_bus_handle_t>(spi->host), &io_config, &internal->io_handle);
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Failed to create panel IO: %s", esp_err_to_name(result));
|
||||||
|
heap_caps_free(internal->transfer_buffer);
|
||||||
|
vSemaphoreDelete(internal->draw_done);
|
||||||
|
free(internal);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t init_count = 0;
|
||||||
|
st77922_vendor_config_t vendor = {
|
||||||
|
.init_cmds = st77922_board_init_commands(&init_count),
|
||||||
|
.init_cmds_size = static_cast<uint16_t>(init_count),
|
||||||
|
.flags = { .use_qspi_interface = 1 },
|
||||||
|
};
|
||||||
|
esp_lcd_panel_dev_config_t panel_config = {
|
||||||
|
.reset_gpio_num = -1,
|
||||||
|
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
|
||||||
|
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
||||||
|
.bits_per_pixel = config->bits_per_pixel,
|
||||||
|
.flags = { .reset_active_high = false },
|
||||||
|
.vendor_config = &vendor,
|
||||||
|
};
|
||||||
|
result = esp_lcd_new_panel_st77922(internal->io_handle, &panel_config, &internal->panel_handle);
|
||||||
|
bool ok = result == ESP_OK;
|
||||||
|
ok = ok && esp_lcd_panel_reset(internal->panel_handle) == ESP_OK;
|
||||||
|
ok = ok && esp_lcd_panel_init(internal->panel_handle) == ESP_OK;
|
||||||
|
ok = ok && ((!config->mirror_x && !config->mirror_y)
|
||||||
|
|| esp_lcd_panel_mirror(internal->panel_handle, config->mirror_x, config->mirror_y) == ESP_OK);
|
||||||
|
ok = ok && (!config->invert_color || esp_lcd_panel_invert_color(internal->panel_handle, true) == ESP_OK);
|
||||||
|
ok = ok && esp_lcd_panel_disp_on_off(internal->panel_handle, true) == ESP_OK;
|
||||||
|
if (!ok) {
|
||||||
|
LOG_E(TAG, "Failed to bring up panel: %s", esp_err_to_name(result));
|
||||||
|
if (internal->panel_handle != nullptr) esp_lcd_panel_del(internal->panel_handle);
|
||||||
|
esp_lcd_panel_io_del(internal->io_handle);
|
||||||
|
heap_caps_free(internal->transfer_buffer);
|
||||||
|
vSemaphoreDelete(internal->draw_done);
|
||||||
|
free(internal);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
device_set_driver_data(device, internal);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
auto* internal = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK
|
||||||
|
|| esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) {
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
heap_caps_free(internal->transfer_buffer);
|
||||||
|
vSemaphoreDelete(internal->draw_done);
|
||||||
|
free(internal);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t reset(Device* device) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_reset(data->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static error_t init(Device* device) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_init(data->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static error_t draw_bitmap(Device* device, int32_t xs, int32_t ys, int32_t xe, int32_t ye, const void* pixels) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
const size_t row_bytes = static_cast<size_t>(xe - xs) * config->bits_per_pixel / 8;
|
||||||
|
if (row_bytes == 0 || row_bytes > data->transfer_buffer_size) {
|
||||||
|
return ERROR_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t rows_per_transfer = data->transfer_buffer_size / row_bytes;
|
||||||
|
const auto* source = static_cast<const uint8_t*>(pixels);
|
||||||
|
int32_t chunk_y = ys;
|
||||||
|
while (chunk_y < ye) {
|
||||||
|
const size_t remaining_rows = static_cast<size_t>(ye - chunk_y);
|
||||||
|
const size_t chunk_rows = remaining_rows < rows_per_transfer ? remaining_rows : rows_per_transfer;
|
||||||
|
const size_t chunk_bytes = chunk_rows * row_bytes;
|
||||||
|
memcpy(data->transfer_buffer, source, chunk_bytes);
|
||||||
|
|
||||||
|
xSemaphoreTake(data->draw_done, 0);
|
||||||
|
if (esp_lcd_panel_draw_bitmap(
|
||||||
|
data->panel_handle, xs, chunk_y, xe, chunk_y + static_cast<int32_t>(chunk_rows),
|
||||||
|
data->transfer_buffer) != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Failed to queue color transfer at y=%ld", static_cast<long>(chunk_y));
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
if (xSemaphoreTake(data->draw_done, pdMS_TO_TICKS(1000)) != pdTRUE) {
|
||||||
|
LOG_E(TAG, "Timed out waiting for color transfer at y=%ld", static_cast<long>(chunk_y));
|
||||||
|
return ERROR_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
source += chunk_bytes;
|
||||||
|
chunk_y += static_cast<int32_t>(chunk_rows);
|
||||||
|
}
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t mirror(Device* device, bool x, bool y) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_mirror(data->panel_handle, x, y) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static bool get_mirror_x(Device* device) { return GET_CONFIG(device)->mirror_x; }
|
||||||
|
static bool get_mirror_y(Device* device) { return GET_CONFIG(device)->mirror_y; }
|
||||||
|
static error_t invert(Device* device, bool value) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_invert_color(data->panel_handle, value) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static error_t on_off(Device* device, bool value) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_disp_on_off(data->panel_handle, value) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static error_t sleep(Device* device, bool value) {
|
||||||
|
auto* data = static_cast<St77922Internal*>(device_get_driver_data(device));
|
||||||
|
return esp_lcd_panel_disp_sleep(data->panel_handle, value) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
static DisplayColorFormat color_format(Device*) { return DISPLAY_COLOR_FORMAT_RGB565_SWAPPED; }
|
||||||
|
static uint16_t resolution_x(Device* device) { return GET_CONFIG(device)->horizontal_resolution; }
|
||||||
|
static uint16_t resolution_y(Device* device) { return GET_CONFIG(device)->vertical_resolution; }
|
||||||
|
static void frame_buffer(Device*, uint8_t, void** output) { *output = nullptr; }
|
||||||
|
static uint8_t frame_buffer_count(Device*) { return 0; }
|
||||||
|
static error_t backlight(Device* device, Device** output) {
|
||||||
|
*output = GET_CONFIG(device)->backlight;
|
||||||
|
return *output == nullptr ? ERROR_NOT_SUPPORTED : ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DisplayApi display_api = {
|
||||||
|
.capabilities = DISPLAY_CAPABILITY_CAP_MIRROR | DISPLAY_CAPABILITY_INVERT_COLOR |
|
||||||
|
DISPLAY_CAPABILITY_ON_OFF | DISPLAY_CAPABILITY_SLEEP | DISPLAY_CAPABILITY_BACKLIGHT |
|
||||||
|
DISPLAY_CAPABILITY_REQUIRES_FULL_FRAME,
|
||||||
|
.reset = reset,
|
||||||
|
.init = init,
|
||||||
|
.draw_bitmap = draw_bitmap,
|
||||||
|
.mirror = mirror,
|
||||||
|
.swap_xy = nullptr,
|
||||||
|
.get_swap_xy = nullptr,
|
||||||
|
.get_mirror_x = get_mirror_x,
|
||||||
|
.get_mirror_y = get_mirror_y,
|
||||||
|
.set_gap = nullptr,
|
||||||
|
.get_gap_x = nullptr,
|
||||||
|
.get_gap_y = nullptr,
|
||||||
|
.invert_color = invert,
|
||||||
|
.disp_on_off = on_off,
|
||||||
|
.disp_sleep = sleep,
|
||||||
|
.get_color_format = color_format,
|
||||||
|
.get_resolution_x = resolution_x,
|
||||||
|
.get_resolution_y = resolution_y,
|
||||||
|
.get_frame_buffer = frame_buffer,
|
||||||
|
.get_frame_buffer_count = frame_buffer_count,
|
||||||
|
.get_backlight = backlight,
|
||||||
|
.has_capability = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
Driver st77922_driver = {
|
||||||
|
.name = "st77922",
|
||||||
|
.compatible = (const char*[]) { "sitronix,st77922", nullptr },
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = &display_api,
|
||||||
|
.device_type = &DISPLAY_TYPE,
|
||||||
|
.owner = &st77922_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include "st77922_init.h"
|
||||||
|
|
||||||
|
// Initialization sequence supplied with the LCDWIKI/Hosyond ES3C35P vendor ESP-IDF demo.
|
||||||
|
static const st77922_lcd_init_cmd_t init_commands[] = {
|
||||||
|
{0xF1, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x60, (uint8_t []){0x00, 0x00, 0x00}, 3, 0},
|
||||||
|
{0x65, (uint8_t []){0x80}, 1, 0},
|
||||||
|
{0x79, (uint8_t []){0x06}, 1, 0},
|
||||||
|
{0x7B, (uint8_t []){0x00, 0x08, 0x08}, 3, 0},
|
||||||
|
{0x80, (uint8_t []){0x55, 0x62, 0x2F, 0x17, 0xF0, 0x52, 0x70, 0xD2, 0x52, 0x62, 0xEA}, 11, 0},
|
||||||
|
{0x81, (uint8_t []){0x26, 0x52, 0x72, 0x27}, 4, 0},
|
||||||
|
{0x84, (uint8_t []){0x92, 0x25}, 2, 0},
|
||||||
|
{0x87, (uint8_t []){0x10, 0x10, 0x58, 0x00, 0x02, 0x3A}, 6, 0},
|
||||||
|
{0x88, (uint8_t []){0x00, 0x00, 0x2C, 0x10, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x06}, 15, 0},
|
||||||
|
{0x89, (uint8_t []){0x00, 0x00, 0x00}, 3, 0},
|
||||||
|
{0x8A, (uint8_t []){0x13, 0x00, 0x2C, 0x00, 0x00, 0x2C, 0x10, 0x10, 0x00, 0x3E, 0x19}, 11, 0},
|
||||||
|
{0x8B, (uint8_t []){0x15, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x97, 0x8E}, 9, 0},
|
||||||
|
{0x8C, (uint8_t []){0x1D, 0xB1, 0xB1, 0x44, 0x96, 0x2C, 0x10, 0x50, 0x0F, 0x01, 0xC5, 0x12, 0x09}, 13, 0},
|
||||||
|
{0x8D, (uint8_t []){0x0C}, 1, 0},
|
||||||
|
{0x8E, (uint8_t []){0x33, 0x01, 0x0C, 0x13, 0x01, 0x01}, 6, 0},
|
||||||
|
{0xB3, (uint8_t []){0x00, 0x30}, 2, 0},
|
||||||
|
{0xF1, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x71, (uint8_t []){0xD0}, 1, 0},
|
||||||
|
{0x66, (uint8_t []){0x02, 0x3F}, 2, 0},
|
||||||
|
{0xBE, (uint8_t []){0x26, 0x00, 0x9D}, 3, 0},
|
||||||
|
{0x70, (uint8_t []){0x01, 0xA0, 0x11, 0x40, 0xE0, 0x00, 0x11, 0x69, 0x11, 0x00, 0x00, 0x1A}, 12, 0},
|
||||||
|
{0x90, (uint8_t []){0x04, 0x04, 0x55, 0x74, 0x00, 0x40, 0x43, 0x27, 0x27}, 9, 0},
|
||||||
|
{0x91, (uint8_t []){0x04, 0x04, 0x55, 0x75, 0x00, 0x40, 0x42, 0x27, 0x27}, 9, 0},
|
||||||
|
{0x92, (uint8_t []){0x04, 0x44, 0x55, 0xC0, 0x06, 0x00, 0x07, 0x05, 0x90, 0x27}, 10, 0},
|
||||||
|
{0x93, (uint8_t []){0x04, 0x43, 0x11, 0x00, 0x00, 0x00, 0x00, 0x05, 0x90, 0x27}, 10, 0},
|
||||||
|
{0x94, (uint8_t []){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 6, 0},
|
||||||
|
{0x95, (uint8_t []){0x96, 0x16, 0x00, 0x00, 0xFF}, 5, 0},
|
||||||
|
{0x96, (uint8_t []){0x44, 0x53, 0x03, 0x12, 0x23, 0x24, 0x06, 0x05, 0x94, 0x27, 0x00, 0x44}, 12, 0},
|
||||||
|
{0x97, (uint8_t []){0x44, 0x53, 0x47, 0x56, 0x20, 0x20, 0x02, 0x01, 0x94, 0x27, 0x00, 0x44}, 12, 0},
|
||||||
|
{0xBA, (uint8_t []){0x55, 0x94, 0x2D, 0x94, 0x27}, 5, 0},
|
||||||
|
{0x9A, (uint8_t []){0x40, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0},
|
||||||
|
{0x9B, (uint8_t []){0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00}, 7, 0},
|
||||||
|
{0x9C, (uint8_t []){0x5C, 0x12, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00}, 13, 0},
|
||||||
|
{0x9D, (uint8_t []){0x8A, 0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01}, 8, 0},
|
||||||
|
{0x9E, (uint8_t []){0x51, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x01}, 7, 0},
|
||||||
|
{0xB4, (uint8_t []){0x1D, 0x1C, 0x1E, 0x0B, 0x14, 0x02, 0x13, 0x09, 0x1E, 0x00, 0x1E, 0x10}, 12, 0},
|
||||||
|
{0xB5, (uint8_t []){0x1D, 0x1C, 0x1E, 0x0A, 0x15, 0x03, 0x11, 0x08, 0x1E, 0x01, 0x1E, 0x12}, 12, 0},
|
||||||
|
{0xB6, (uint8_t []){0x77, 0x77, 0x00, 0x0A, 0xFF, 0x0A, 0xFF}, 7, 0},
|
||||||
|
{0x86, (uint8_t []){0xCD, 0x04, 0xB1, 0x02, 0x58, 0x12, 0x58, 0x0C, 0x13, 0x01, 0xA5, 0x00, 0xA5, 0xA5}, 14, 0},
|
||||||
|
{0xB7, (uint8_t []){0x07, 0x0A, 0x0E, 0x06, 0x05, 0x03, 0x2B, 0x03, 0x03, 0x42, 0x07, 0x10, 0x10, 0x2E, 0x3F, 0x0D}, 16, 0},
|
||||||
|
{0xB8, (uint8_t []){0x07, 0x0A, 0x0D, 0x05, 0x05, 0x02, 0x2B, 0x02, 0x03, 0x42, 0x06, 0x10, 0x0F, 0x2E, 0x3F, 0x0D}, 16, 0},
|
||||||
|
{0xB9, (uint8_t []){0x23, 0x23}, 2, 0},
|
||||||
|
{0xBF, (uint8_t []){0x10, 0x14, 0x14, 0x0B, 0x0B, 0x0B}, 6, 0},
|
||||||
|
{0xF2, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x73, (uint8_t []){0x04, 0xDA, 0x12, 0x54, 0x47}, 5, 0},
|
||||||
|
{0x77, (uint8_t []){0x6B, 0x5B, 0xFD, 0xC3, 0xC5}, 5, 0},
|
||||||
|
{0x7A, (uint8_t []){0x15, 0x27}, 2, 0},
|
||||||
|
{0x7B, (uint8_t []){0x04, 0x57}, 2, 0},
|
||||||
|
{0x7E, (uint8_t []){0x01, 0x0E}, 2, 0},
|
||||||
|
{0xBF, (uint8_t []){0x36}, 1, 0},
|
||||||
|
{0xE3, (uint8_t []){0x40, 0x40}, 2, 0},
|
||||||
|
{0xF0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0xD0, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x2A, (uint8_t []){0x00, 0x00, 0x01, 0x3F}, 4, 0},
|
||||||
|
{0x2B, (uint8_t []){0x00, 0x00, 0x01, 0xDF}, 4, 0},
|
||||||
|
{0x21, NULL, 0, 0},
|
||||||
|
{0x11, NULL, 0, 120},
|
||||||
|
{0x29, NULL, 0, 0},
|
||||||
|
{0x2C, NULL, 0, 0},
|
||||||
|
{0x3A, (uint8_t []){0x01}, 1, 0},
|
||||||
|
{0x36, (uint8_t []){0x00}, 1, 0},
|
||||||
|
{0x35, (uint8_t []){0x01}, 1, 20},
|
||||||
|
};
|
||||||
|
|
||||||
|
const st77922_lcd_init_cmd_t* st77922_board_init_commands(size_t* count) {
|
||||||
|
*count = sizeof(init_commands) / sizeof(init_commands[0]);
|
||||||
|
return init_commands;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <esp_lcd_st77922.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const st77922_lcd_init_cmd_t* st77922_board_init_commands(size_t* count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <drivers/st77922_touch.h>
|
||||||
|
#include <st77922_module.h>
|
||||||
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
#include <tactility/drivers/pointer.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#define TAG "ST77922 touch"
|
||||||
|
#define GET_CONFIG(device) (static_cast<const St77922TouchConfig*>((device)->config))
|
||||||
|
|
||||||
|
static constexpr uint16_t REG_MAX_TOUCHES = 0x0009;
|
||||||
|
static constexpr uint16_t REG_TOUCH_INFO = 0x0010;
|
||||||
|
static constexpr uint16_t REG_TOUCH_POINT0 = 0x0014;
|
||||||
|
static constexpr uint8_t MAX_POINTS = 10;
|
||||||
|
static constexpr TickType_t TIMEOUT = pdMS_TO_TICKS(1000);
|
||||||
|
|
||||||
|
struct TouchPoint {
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct St77922TouchInternal {
|
||||||
|
Device* i2c;
|
||||||
|
GpioDescriptor* reset;
|
||||||
|
uint8_t supported_points;
|
||||||
|
uint8_t point_count;
|
||||||
|
TouchPoint points[MAX_POINTS];
|
||||||
|
bool swap_xy;
|
||||||
|
bool mirror_x;
|
||||||
|
bool mirror_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t read_register(Device* i2c, uint16_t reg, uint8_t* data, size_t size, TickType_t timeout) {
|
||||||
|
const uint8_t address[] = {
|
||||||
|
static_cast<uint8_t>(reg >> 8),
|
||||||
|
static_cast<uint8_t>(reg & 0xFF),
|
||||||
|
};
|
||||||
|
return i2c_controller_write_read(i2c, 0x55, address, sizeof(address), data, size, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
auto* parent = device_get_parent(device);
|
||||||
|
check(device_get_type(parent) == &I2C_CONTROLLER_TYPE);
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
auto* internal = static_cast<St77922TouchInternal*>(calloc(1, sizeof(St77922TouchInternal)));
|
||||||
|
if (internal == nullptr) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
internal->i2c = parent;
|
||||||
|
internal->supported_points = 1;
|
||||||
|
internal->swap_xy = config->swap_xy;
|
||||||
|
internal->mirror_x = config->mirror_x;
|
||||||
|
internal->mirror_y = config->mirror_y;
|
||||||
|
|
||||||
|
if (config->pin_reset.gpio_controller != nullptr) {
|
||||||
|
internal->reset = gpio_descriptor_acquire(config->pin_reset.gpio_controller,
|
||||||
|
config->pin_reset.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
|
||||||
|
if (internal->reset == nullptr) {
|
||||||
|
free(internal);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
if (gpio_descriptor_set_level(internal->reset, true) != ERROR_NONE) {
|
||||||
|
gpio_descriptor_release(internal->reset);
|
||||||
|
free(internal);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
gpio_descriptor_set_level(internal->reset, false);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t supported = 0;
|
||||||
|
if (read_register(parent, REG_MAX_TOUCHES, &supported, 1, TIMEOUT) == ERROR_NONE
|
||||||
|
&& supported > 0 && supported <= MAX_POINTS) {
|
||||||
|
internal->supported_points = supported;
|
||||||
|
}
|
||||||
|
LOG_I(TAG, "Controller reports %u touch points", internal->supported_points);
|
||||||
|
device_set_driver_data(device, internal);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
auto* internal = static_cast<St77922TouchInternal*>(device_get_driver_data(device));
|
||||||
|
if (internal->reset != nullptr) {
|
||||||
|
gpio_descriptor_release(internal->reset);
|
||||||
|
}
|
||||||
|
free(internal);
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t enter_sleep(Device*) { return ERROR_NOT_SUPPORTED; }
|
||||||
|
static error_t exit_sleep(Device*) { return ERROR_NOT_SUPPORTED; }
|
||||||
|
|
||||||
|
static error_t read_data(Device* device, TickType_t timeout) {
|
||||||
|
auto* internal = static_cast<St77922TouchInternal*>(device_get_driver_data(device));
|
||||||
|
uint8_t touch_info = 0;
|
||||||
|
if (read_register(internal->i2c, REG_TOUCH_INFO, &touch_info, 1, timeout) != ERROR_NONE) {
|
||||||
|
internal->point_count = 0;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
if ((touch_info & 0x08) == 0) {
|
||||||
|
internal->point_count = 0;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t data[7 * MAX_POINTS] = {};
|
||||||
|
const size_t read_size = 7 * internal->supported_points;
|
||||||
|
if (read_register(internal->i2c, REG_TOUCH_POINT0, data, read_size, timeout) != ERROR_NONE) {
|
||||||
|
internal->point_count = 0;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal->point_count = 0;
|
||||||
|
for (uint8_t index = 0; index < internal->supported_points; index++) {
|
||||||
|
const uint8_t offset = index * 7;
|
||||||
|
if ((data[offset] & 0x80) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
internal->points[internal->point_count++] = {
|
||||||
|
.x = static_cast<uint16_t>(((data[offset] & 0x3F) << 8) | data[offset + 1]),
|
||||||
|
.y = static_cast<uint16_t>(((data[offset + 2] & 0x3F) << 8) | data[offset + 3]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_touched_points(Device* device, uint16_t* x, uint16_t* y, uint16_t* strength,
|
||||||
|
uint8_t* count, uint8_t maximum) {
|
||||||
|
auto* internal = static_cast<St77922TouchInternal*>(device_get_driver_data(device));
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
*count = std::min(internal->point_count, maximum);
|
||||||
|
for (uint8_t index = 0; index < *count; index++) {
|
||||||
|
uint16_t point_x = internal->points[index].x;
|
||||||
|
uint16_t point_y = internal->points[index].y;
|
||||||
|
if (internal->swap_xy) {
|
||||||
|
std::swap(point_x, point_y);
|
||||||
|
}
|
||||||
|
const uint16_t max_x = internal->swap_xy ? config->y_max : config->x_max;
|
||||||
|
const uint16_t max_y = internal->swap_xy ? config->x_max : config->y_max;
|
||||||
|
x[index] = internal->mirror_x ? max_x - point_x : point_x;
|
||||||
|
y[index] = internal->mirror_y ? max_y - point_y : point_y;
|
||||||
|
if (strength != nullptr) {
|
||||||
|
strength[index] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t set_swap_xy(Device* device, bool value) {
|
||||||
|
static_cast<St77922TouchInternal*>(device_get_driver_data(device))->swap_xy = value;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t get_swap_xy(Device* device, bool* value) {
|
||||||
|
*value = static_cast<St77922TouchInternal*>(device_get_driver_data(device))->swap_xy;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t set_mirror_x(Device* device, bool value) {
|
||||||
|
static_cast<St77922TouchInternal*>(device_get_driver_data(device))->mirror_x = value;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t get_mirror_x(Device* device, bool* value) {
|
||||||
|
*value = static_cast<St77922TouchInternal*>(device_get_driver_data(device))->mirror_x;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t set_mirror_y(Device* device, bool value) {
|
||||||
|
static_cast<St77922TouchInternal*>(device_get_driver_data(device))->mirror_y = value;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
static error_t get_mirror_y(Device* device, bool* value) {
|
||||||
|
*value = static_cast<St77922TouchInternal*>(device_get_driver_data(device))->mirror_y;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PointerApi pointer_api = {
|
||||||
|
.enter_sleep = enter_sleep,
|
||||||
|
.exit_sleep = exit_sleep,
|
||||||
|
.read_data = read_data,
|
||||||
|
.get_touched_points = get_touched_points,
|
||||||
|
.set_swap_xy = set_swap_xy,
|
||||||
|
.get_swap_xy = get_swap_xy,
|
||||||
|
.set_mirror_x = set_mirror_x,
|
||||||
|
.get_mirror_x = get_mirror_x,
|
||||||
|
.set_mirror_y = set_mirror_y,
|
||||||
|
.get_mirror_y = get_mirror_y,
|
||||||
|
};
|
||||||
|
|
||||||
|
Driver st77922_touch_driver = {
|
||||||
|
.name = "st77922-touch",
|
||||||
|
.compatible = (const char*[]) { "sitronix,st77922-touch", nullptr },
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = &pointer_api,
|
||||||
|
.device_type = &POINTER_TYPE,
|
||||||
|
.owner = &st77922_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
@@ -42,6 +42,10 @@ dependencies:
|
|||||||
version: "1.3.4"
|
version: "1.3.4"
|
||||||
rules:
|
rules:
|
||||||
- if: "target in [esp32, esp32s3]"
|
- if: "target in [esp32, esp32s3]"
|
||||||
|
espressif/esp_lcd_st77922:
|
||||||
|
version: "1.0.3"
|
||||||
|
rules:
|
||||||
|
- if: "target in [esp32s3]"
|
||||||
espressif/esp_lcd_gc9a01: "2.0.3"
|
espressif/esp_lcd_gc9a01: "2.0.3"
|
||||||
espressif/esp_lcd_jd9165:
|
espressif/esp_lcd_jd9165:
|
||||||
version: "1.0.3"
|
version: "1.0.3"
|
||||||
@@ -85,4 +89,3 @@ dependencies:
|
|||||||
rules:
|
rules:
|
||||||
- if: "target in [esp32s3, esp32p4]"
|
- if: "target in [esp32s3, esp32p4]"
|
||||||
idf: '5.5.2'
|
idf: '5.5.2'
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,15 @@ enum LvglFontSize {
|
|||||||
FONT_SIZE_LARGE,
|
FONT_SIZE_LARGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum LvglFontScale {
|
||||||
|
FONT_SCALE_SMALL,
|
||||||
|
FONT_SCALE_DEFAULT,
|
||||||
|
FONT_SCALE_LARGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
void lvgl_set_text_font_scale(enum LvglFontScale font_scale);
|
||||||
|
enum LvglFontScale lvgl_get_text_font_scale(void);
|
||||||
|
|
||||||
const lv_font_t* lvgl_get_shared_icon_font();
|
const lv_font_t* lvgl_get_shared_icon_font();
|
||||||
uint32_t lvgl_get_shared_icon_font_height();
|
uint32_t lvgl_get_shared_icon_font_height();
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,30 @@ extern const lv_font_t TT_LVGL_LAUNCHER_FONT_ICON_SYMBOL;
|
|||||||
extern const lv_font_t TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL;
|
extern const lv_font_t TT_LVGL_STATUSBAR_FONT_ICON_SYMBOL;
|
||||||
extern const lv_font_t TT_LVGL_SHARED_FONT_ICON_SYMBOL;
|
extern const lv_font_t TT_LVGL_SHARED_FONT_ICON_SYMBOL;
|
||||||
|
|
||||||
|
static enum LvglFontScale text_font_scale = FONT_SCALE_DEFAULT;
|
||||||
|
|
||||||
|
void lvgl_set_text_font_scale(enum LvglFontScale font_scale) {
|
||||||
|
check(font_scale >= FONT_SCALE_SMALL && font_scale <= FONT_SCALE_LARGE);
|
||||||
|
text_font_scale = font_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum LvglFontScale lvgl_get_text_font_scale(void) {
|
||||||
|
return text_font_scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum LvglFontSize resolve_text_font_size(enum LvglFontSize font_size) {
|
||||||
|
int resolved = (int)font_size + (int)text_font_scale - (int)FONT_SCALE_DEFAULT;
|
||||||
|
if (resolved < FONT_SIZE_SMALL) {
|
||||||
|
return FONT_SIZE_SMALL;
|
||||||
|
}
|
||||||
|
if (resolved > FONT_SIZE_LARGE) {
|
||||||
|
return FONT_SIZE_LARGE;
|
||||||
|
}
|
||||||
|
return (enum LvglFontSize)resolved;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) {
|
uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) {
|
||||||
switch (font_size) {
|
switch (resolve_text_font_size(font_size)) {
|
||||||
case FONT_SIZE_SMALL: return TT_LVGL_TEXT_FONT_SMALL_SIZE;
|
case FONT_SIZE_SMALL: return TT_LVGL_TEXT_FONT_SMALL_SIZE;
|
||||||
case FONT_SIZE_DEFAULT: return TT_LVGL_TEXT_FONT_DEFAULT_SIZE;
|
case FONT_SIZE_DEFAULT: return TT_LVGL_TEXT_FONT_DEFAULT_SIZE;
|
||||||
case FONT_SIZE_LARGE: return TT_LVGL_TEXT_FONT_LARGE_SIZE;
|
case FONT_SIZE_LARGE: return TT_LVGL_TEXT_FONT_LARGE_SIZE;
|
||||||
@@ -22,7 +44,7 @@ uint32_t lvgl_get_text_font_height(enum LvglFontSize font_size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const lv_font_t* lvgl_get_text_font(enum LvglFontSize font_size) {
|
const lv_font_t* lvgl_get_text_font(enum LvglFontSize font_size) {
|
||||||
switch (font_size) {
|
switch (resolve_text_font_size(font_size)) {
|
||||||
case FONT_SIZE_SMALL: return &TT_LVGL_TEXT_FONT_SMALL_SYMBOL;
|
case FONT_SIZE_SMALL: return &TT_LVGL_TEXT_FONT_SMALL_SYMBOL;
|
||||||
case FONT_SIZE_DEFAULT: return &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL;
|
case FONT_SIZE_DEFAULT: return &TT_LVGL_TEXT_FONT_DEFAULT_SYMBOL;
|
||||||
case FONT_SIZE_LARGE: return &TT_LVGL_TEXT_FONT_LARGE_SYMBOL;
|
case FONT_SIZE_LARGE: return &TT_LVGL_TEXT_FONT_LARGE_SYMBOL;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(lvgl_is_running),
|
DEFINE_MODULE_SYMBOL(lvgl_is_running),
|
||||||
DEFINE_MODULE_SYMBOL(lvgl_get_ui_density),
|
DEFINE_MODULE_SYMBOL(lvgl_get_ui_density),
|
||||||
// lvgl_fonts
|
// lvgl_fonts
|
||||||
|
DEFINE_MODULE_SYMBOL(lvgl_set_text_font_scale),
|
||||||
|
DEFINE_MODULE_SYMBOL(lvgl_get_text_font_scale),
|
||||||
DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font),
|
DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font),
|
||||||
DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font_height),
|
DEFINE_MODULE_SYMBOL(lvgl_get_shared_icon_font_height),
|
||||||
DEFINE_MODULE_SYMBOL(lvgl_get_text_font),
|
DEFINE_MODULE_SYMBOL(lvgl_get_text_font),
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace tt::settings::display {
|
||||||
|
enum class FontSize;
|
||||||
|
}
|
||||||
|
|
||||||
namespace tt::lvgl {
|
namespace tt::lvgl {
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
@@ -12,6 +16,9 @@ static constexpr auto* PATH_PREFIX = "A:/";
|
|||||||
|
|
||||||
bool isStarted();
|
bool isStarted();
|
||||||
|
|
||||||
|
/** Applies the selected semantic text size to the LVGL theme and future widgets. */
|
||||||
|
void applyFontSize(settings::display::FontSize fontSize);
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|||||||
@@ -22,8 +22,16 @@ enum class ScreensaverType {
|
|||||||
Count // Sentinel for bounds checking - must be last
|
Count // Sentinel for bounds checking - must be last
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class FontSize {
|
||||||
|
Small,
|
||||||
|
Default,
|
||||||
|
Large,
|
||||||
|
Count
|
||||||
|
};
|
||||||
|
|
||||||
struct DisplaySettings {
|
struct DisplaySettings {
|
||||||
Orientation orientation;
|
Orientation orientation;
|
||||||
|
FontSize fontSize = FontSize::Default;
|
||||||
uint8_t gammaCurve;
|
uint8_t gammaCurve;
|
||||||
uint8_t backlightDuty;
|
uint8_t backlightDuty;
|
||||||
bool backlightTimeoutEnabled;
|
bool backlightTimeoutEnabled;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <Tactility/app/App.h>
|
#include <Tactility/app/App.h>
|
||||||
#include <Tactility/hal/display/DisplayDevice.h>
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/settings/DisplaySettings.h>
|
#include <Tactility/settings/DisplaySettings.h>
|
||||||
|
|
||||||
@@ -74,6 +75,21 @@ class HalDisplayApp final : public App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void onFontSizeChanged(lv_event_t* event) {
|
||||||
|
auto* app = static_cast<HalDisplayApp*>(lv_event_get_user_data(event));
|
||||||
|
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||||
|
uint32_t selected_index = lv_dropdown_get_selected(dropdown);
|
||||||
|
if (selected_index >= static_cast<uint32_t>(settings::display::FontSize::Count)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto selected_size = static_cast<settings::display::FontSize>(selected_index);
|
||||||
|
if (selected_size != app->displaySettings.fontSize) {
|
||||||
|
app->displaySettings.fontSize = selected_size;
|
||||||
|
app->displaySettingsUpdated = true;
|
||||||
|
lvgl::applyFontSize(selected_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void onDisableWhenChargingChanged(lv_event_t* event) {
|
static void onDisableWhenChargingChanged(lv_event_t* event) {
|
||||||
auto* app = static_cast<HalDisplayApp*>(lv_event_get_user_data(event));
|
auto* app = static_cast<HalDisplayApp*>(lv_event_get_user_data(event));
|
||||||
auto* sw = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
auto* sw = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||||
@@ -224,6 +240,23 @@ public:
|
|||||||
// Set the dropdown to match current orientation enum
|
// Set the dropdown to match current orientation enum
|
||||||
lv_dropdown_set_selected(orientation_dropdown, static_cast<uint16_t>(displaySettings.orientation));
|
lv_dropdown_set_selected(orientation_dropdown, static_cast<uint16_t>(displaySettings.orientation));
|
||||||
|
|
||||||
|
// Font size
|
||||||
|
|
||||||
|
auto* font_size_wrapper = lv_obj_create(main_wrapper);
|
||||||
|
lv_obj_set_size(font_size_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_style_pad_all(font_size_wrapper, 0, LV_STATE_DEFAULT);
|
||||||
|
lv_obj_set_style_border_width(font_size_wrapper, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
|
auto* font_size_label = lv_label_create(font_size_wrapper);
|
||||||
|
lv_label_set_text(font_size_label, "Font size");
|
||||||
|
lv_obj_align(font_size_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||||
|
|
||||||
|
auto* font_size_dropdown = lv_dropdown_create(font_size_wrapper);
|
||||||
|
lv_dropdown_set_options(font_size_dropdown, "Small\nDefault\nLarge");
|
||||||
|
lv_obj_align(font_size_dropdown, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||||
|
lv_obj_add_event_cb(font_size_dropdown, onFontSizeChanged, LV_EVENT_VALUE_CHANGED, this);
|
||||||
|
lv_dropdown_set_selected(font_size_dropdown, static_cast<uint16_t>(displaySettings.fontSize));
|
||||||
|
|
||||||
// Screen timeout
|
// Screen timeout
|
||||||
|
|
||||||
if (hal_display->supportsBacklightDuty()) {
|
if (hal_display->supportsBacklightDuty()) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <Tactility/service/displayidle/DisplayIdleService.h>
|
#include <Tactility/service/displayidle/DisplayIdleService.h>
|
||||||
#endif
|
#endif
|
||||||
#include <Tactility/app/App.h>
|
#include <Tactility/app/App.h>
|
||||||
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/settings/DisplaySettings.h>
|
#include <Tactility/settings/DisplaySettings.h>
|
||||||
|
|
||||||
@@ -69,6 +70,21 @@ class KernelDisplayApp final : public App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void onFontSizeChanged(lv_event_t* event) {
|
||||||
|
auto* app = static_cast<KernelDisplayApp*>(lv_event_get_user_data(event));
|
||||||
|
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||||
|
uint32_t selected_index = lv_dropdown_get_selected(dropdown);
|
||||||
|
if (selected_index >= static_cast<uint32_t>(settings::display::FontSize::Count)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto selected_size = static_cast<settings::display::FontSize>(selected_index);
|
||||||
|
if (selected_size != app->displaySettings.fontSize) {
|
||||||
|
app->displaySettings.fontSize = selected_size;
|
||||||
|
app->displaySettingsUpdated = true;
|
||||||
|
lvgl::applyFontSize(selected_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void onTimeoutSwitch(lv_event_t* event) {
|
static void onTimeoutSwitch(lv_event_t* event) {
|
||||||
auto* app = static_cast<KernelDisplayApp*>(lv_event_get_user_data(event));
|
auto* app = static_cast<KernelDisplayApp*>(lv_event_get_user_data(event));
|
||||||
auto* sw = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
auto* sw = static_cast<lv_obj_t*>(lv_event_get_target(event));
|
||||||
@@ -183,6 +199,23 @@ public:
|
|||||||
// Set the dropdown to match current orientation enum
|
// Set the dropdown to match current orientation enum
|
||||||
lv_dropdown_set_selected(orientation_dropdown, static_cast<uint16_t>(displaySettings.orientation));
|
lv_dropdown_set_selected(orientation_dropdown, static_cast<uint16_t>(displaySettings.orientation));
|
||||||
|
|
||||||
|
// Font size
|
||||||
|
|
||||||
|
auto* font_size_wrapper = lv_obj_create(main_wrapper);
|
||||||
|
lv_obj_set_size(font_size_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_style_pad_all(font_size_wrapper, 0, LV_STATE_DEFAULT);
|
||||||
|
lv_obj_set_style_border_width(font_size_wrapper, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
|
auto* font_size_label = lv_label_create(font_size_wrapper);
|
||||||
|
lv_label_set_text(font_size_label, "Font size");
|
||||||
|
lv_obj_align(font_size_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||||
|
|
||||||
|
auto* font_size_dropdown = lv_dropdown_create(font_size_wrapper);
|
||||||
|
lv_dropdown_set_options(font_size_dropdown, "Small\nDefault\nLarge");
|
||||||
|
lv_obj_align(font_size_dropdown, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||||
|
lv_obj_add_event_cb(font_size_dropdown, onFontSizeChanged, LV_EVENT_VALUE_CHANGED, this);
|
||||||
|
lv_dropdown_set_selected(font_size_dropdown, static_cast<uint16_t>(displaySettings.fontSize));
|
||||||
|
|
||||||
// Screen timeout
|
// Screen timeout
|
||||||
// Note: DisplayIdleService doesn't act on these settings for kernel-driver displays yet
|
// Note: DisplayIdleService doesn't act on these settings for kernel-driver displays yet
|
||||||
// (it only looks up the deprecated tt::hal::display::DisplayDevice), so these currently
|
// (it only looks up the deprecated tt::hal::display::DisplayDevice), so these currently
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/drivers/backlight.h>
|
#include <tactility/drivers/backlight.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
#include <tactility/lvgl_fonts.h>
|
||||||
#include <tactility/lvgl_module.h>
|
#include <tactility/lvgl_module.h>
|
||||||
#include <tactility/lvgl_pointer.h>
|
#include <tactility/lvgl_pointer.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
@@ -27,6 +28,49 @@ bool isStarted() {
|
|||||||
return module_is_started(&lvgl_module);
|
return module_is_started(&lvgl_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void applyFontSize(settings::display::FontSize fontSize) {
|
||||||
|
LvglFontScale scale;
|
||||||
|
switch (fontSize) {
|
||||||
|
using enum settings::display::FontSize;
|
||||||
|
case Small:
|
||||||
|
scale = FONT_SCALE_SMALL;
|
||||||
|
break;
|
||||||
|
case Large:
|
||||||
|
scale = FONT_SCALE_LARGE;
|
||||||
|
break;
|
||||||
|
case Default:
|
||||||
|
default:
|
||||||
|
scale = FONT_SCALE_DEFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lvgl_set_text_font_scale(scale);
|
||||||
|
const lv_font_t* font = lvgl_get_text_font(FONT_SIZE_DEFAULT);
|
||||||
|
|
||||||
|
for (lv_display_t* display = lv_display_get_next(nullptr);
|
||||||
|
display != nullptr;
|
||||||
|
display = lv_display_get_next(display)) {
|
||||||
|
#if LV_USE_THEME_DEFAULT
|
||||||
|
if (lv_display_get_theme(display) == lv_theme_default_get()) {
|
||||||
|
lv_obj_t* screen = lv_display_get_screen_active(display);
|
||||||
|
lv_theme_default_init(
|
||||||
|
display,
|
||||||
|
lv_theme_get_color_primary(screen),
|
||||||
|
lv_theme_get_color_secondary(screen),
|
||||||
|
LV_THEME_DEFAULT_DARK,
|
||||||
|
font
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// The display layers are independent inheritance roots. Updating all of them makes
|
||||||
|
// the new size visible immediately in regular screens, overlays, and the status bar.
|
||||||
|
lv_obj_set_style_text_font(lv_display_get_screen_active(display), font, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_text_font(lv_display_get_layer_top(display), font, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_text_font(lv_display_get_layer_sys(display), font, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_text_font(lv_display_get_layer_bottom(display), font, LV_PART_MAIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void attachDevices() {
|
void attachDevices() {
|
||||||
LOG_I(TAG, "Adding devices");
|
LOG_I(TAG, "Adding devices");
|
||||||
|
|
||||||
@@ -55,6 +99,7 @@ void attachDevices() {
|
|||||||
if (rotation != lv_display_get_rotation(primary_lvgl_display)) {
|
if (rotation != lv_display_get_rotation(primary_lvgl_display)) {
|
||||||
lv_display_set_rotation(primary_lvgl_display, rotation);
|
lv_display_set_rotation(primary_lvgl_display, rotation);
|
||||||
}
|
}
|
||||||
|
applyFontSize(settings.fontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start touch
|
// Start touch
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ static std::string getSettingsFilePath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto* SETTINGS_KEY_ORIENTATION = "orientation";
|
constexpr auto* SETTINGS_KEY_ORIENTATION = "orientation";
|
||||||
|
constexpr auto* SETTINGS_KEY_FONT_SIZE = "fontSize";
|
||||||
constexpr auto* SETTINGS_KEY_GAMMA_CURVE = "gammaCurve";
|
constexpr auto* SETTINGS_KEY_GAMMA_CURVE = "gammaCurve";
|
||||||
constexpr auto* SETTINGS_KEY_BACKLIGHT_DUTY = "backlightDuty";
|
constexpr auto* SETTINGS_KEY_BACKLIGHT_DUTY = "backlightDuty";
|
||||||
constexpr auto* SETTINGS_KEY_TIMEOUT_ENABLED = "backlightTimeoutEnabled";
|
constexpr auto* SETTINGS_KEY_TIMEOUT_ENABLED = "backlightTimeoutEnabled";
|
||||||
@@ -71,6 +72,34 @@ static bool fromString(const std::string& str, Orientation& orientation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string toString(FontSize font_size) {
|
||||||
|
switch (font_size) {
|
||||||
|
using enum FontSize;
|
||||||
|
case Small:
|
||||||
|
return "Small";
|
||||||
|
case Default:
|
||||||
|
return "Default";
|
||||||
|
case Large:
|
||||||
|
return "Large";
|
||||||
|
default:
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fromString(const std::string& str, FontSize& font_size) {
|
||||||
|
if (str == "Small") {
|
||||||
|
font_size = FontSize::Small;
|
||||||
|
return true;
|
||||||
|
} else if (str == "Default") {
|
||||||
|
font_size = FontSize::Default;
|
||||||
|
return true;
|
||||||
|
} else if (str == "Large") {
|
||||||
|
font_size = FontSize::Large;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string toString(ScreensaverType type) {
|
static std::string toString(ScreensaverType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
using enum ScreensaverType;
|
using enum ScreensaverType;
|
||||||
@@ -132,6 +161,12 @@ bool load(DisplaySettings& settings) {
|
|||||||
orientation = getDefaultOrientation();
|
orientation = getDefaultOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto font_size_entry = map.find(SETTINGS_KEY_FONT_SIZE);
|
||||||
|
FontSize font_size = FontSize::Default;
|
||||||
|
if (font_size_entry != map.end()) {
|
||||||
|
fromString(font_size_entry->second, font_size);
|
||||||
|
}
|
||||||
|
|
||||||
auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE);
|
auto gamma_entry = map.find(SETTINGS_KEY_GAMMA_CURVE);
|
||||||
int gamma_curve = 0;
|
int gamma_curve = 0;
|
||||||
if (gamma_entry != map.end()) {
|
if (gamma_entry != map.end()) {
|
||||||
@@ -172,6 +207,7 @@ bool load(DisplaySettings& settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
settings.orientation = orientation;
|
settings.orientation = orientation;
|
||||||
|
settings.fontSize = font_size;
|
||||||
settings.gammaCurve = gamma_curve;
|
settings.gammaCurve = gamma_curve;
|
||||||
settings.backlightDuty = backlight_duty;
|
settings.backlightDuty = backlight_duty;
|
||||||
settings.backlightTimeoutEnabled = timeout_enabled;
|
settings.backlightTimeoutEnabled = timeout_enabled;
|
||||||
@@ -185,6 +221,7 @@ bool load(DisplaySettings& settings) {
|
|||||||
DisplaySettings getDefault() {
|
DisplaySettings getDefault() {
|
||||||
return DisplaySettings {
|
return DisplaySettings {
|
||||||
.orientation = getDefaultOrientation(),
|
.orientation = getDefaultOrientation(),
|
||||||
|
.fontSize = FontSize::Default,
|
||||||
.gammaCurve = 1,
|
.gammaCurve = 1,
|
||||||
.backlightDuty = 200,
|
.backlightDuty = 200,
|
||||||
.backlightTimeoutEnabled = false,
|
.backlightTimeoutEnabled = false,
|
||||||
@@ -207,6 +244,7 @@ bool save(const DisplaySettings& settings) {
|
|||||||
map[SETTINGS_KEY_BACKLIGHT_DUTY] = std::to_string(settings.backlightDuty);
|
map[SETTINGS_KEY_BACKLIGHT_DUTY] = std::to_string(settings.backlightDuty);
|
||||||
map[SETTINGS_KEY_GAMMA_CURVE] = std::to_string(settings.gammaCurve);
|
map[SETTINGS_KEY_GAMMA_CURVE] = std::to_string(settings.gammaCurve);
|
||||||
map[SETTINGS_KEY_ORIENTATION] = toString(settings.orientation);
|
map[SETTINGS_KEY_ORIENTATION] = toString(settings.orientation);
|
||||||
|
map[SETTINGS_KEY_FONT_SIZE] = toString(settings.fontSize);
|
||||||
map[SETTINGS_KEY_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0";
|
map[SETTINGS_KEY_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0";
|
||||||
map[SETTINGS_KEY_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs);
|
map[SETTINGS_KEY_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs);
|
||||||
map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType);
|
map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType);
|
||||||
|
|||||||
Reference in New Issue
Block a user