mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
Display brightness support (#26)
* cleanup * brightness control and app * cleanup * persistant storage of display settings * fix for missing include * header cleanup * fix pc build * add docs * move display app to tactility project
This commit is contained in:
parent
ae5c828f42
commit
d171b9a231
@ -50,7 +50,7 @@ Predefined configurations are available for:
|
||||
(*) Note: Only the capacitive version is supported. See AliExpress [here][2432s024c_1] and [here][2432s024c_2].
|
||||
|
||||
[tdeck]: https://www.lilygo.cc/products/t-deck
|
||||
[waveshare_s3_touch]: https://www.aliexpress.com/item/1005005692235592.html
|
||||
[waveshare_s3_touch]: https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-4.3
|
||||
[2432s024c_1]: https://www.aliexpress.com/item/1005005902429049.html
|
||||
[2432s024c_2]: https://www.aliexpress.com/item/1005005865107357.html
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "hello_world.h"
|
||||
#include "services/gui/gui.h"
|
||||
#include "services/loader/loader.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
static void app_show(TT_UNUSED App app, lv_obj_t* parent) {
|
||||
lv_obj_t* label = lv_label_create(parent);
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "display_i.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "keyboard.h"
|
||||
#include "log.h"
|
||||
#include <driver/spi_common.h>
|
||||
#include "tactility_core.h"
|
||||
|
||||
#define TAG "tdeck_bootstrap"
|
||||
|
||||
lv_disp_t* tdeck_display_init();
|
||||
|
||||
static bool tdeck_power_on() {
|
||||
gpio_config_t device_power_signal_config = {
|
||||
.pin_bit_mask = BIT64(TDECK_POWERON_GPIO),
|
||||
@ -38,8 +36,7 @@ static bool init_i2c() {
|
||||
.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;
|
||||
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;
|
||||
}
|
||||
|
||||
static bool init_spi() {
|
||||
@ -89,6 +86,13 @@ bool tdeck_bootstrap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't turn the backlight on yet - Tactility init will take care of it
|
||||
TT_LOG_I(TAG, "Init backlight");
|
||||
if (!tdeck_backlight_init()) {
|
||||
TT_LOG_E(TAG, "Init backlight failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
keyboard_wait_for_response();
|
||||
|
||||
return true;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#define TAG "tdeck_display"
|
||||
|
||||
void tdeck_enable_backlight() {
|
||||
bool tdeck_backlight_init() {
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE,
|
||||
.timer_num = TDECK_LCD_BACKLIGHT_LEDC_TIMER,
|
||||
@ -17,20 +17,31 @@ void tdeck_enable_backlight() {
|
||||
.freq_hz = TDECK_LCD_BACKLIGHT_LEDC_FREQUENCY,
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
|
||||
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Backlight led timer config failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tdeck_backlight_set(uint8_t duty) {
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.speed_mode = TDECK_LCD_BACKLIGHT_LEDC_MODE,
|
||||
.channel = TDECK_LCD_BACKLIGHT_LEDC_CHANNEL,
|
||||
.timer_sel = TDECK_LCD_BACKLIGHT_LEDC_TIMER,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = TDECK_LCD_BACKLIGHT_LEDC_OUTPUT_IO,
|
||||
.duty = 0, // Set duty to 0%
|
||||
.gpio_num = TDECK_LCD_PIN_BACKLIGHT,
|
||||
.duty = duty,
|
||||
.hpoint = 0
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
|
||||
ESP_ERROR_CHECK(ledc_set_duty(TDECK_LCD_BACKLIGHT_LEDC_MODE, TDECK_LCD_BACKLIGHT_LEDC_CHANNEL, TDECK_LCD_BACKLIGHT_LEDC_DUTY));
|
||||
// Setting the config in the timer init and then calling ledc_set_duty() doesn't work when
|
||||
// the app is running. For an unknown reason we have to call this config method every time:
|
||||
if (ledc_channel_config(&ledc_channel) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure display backlight");
|
||||
}
|
||||
}
|
||||
|
||||
lv_disp_t* tdeck_display_init() {
|
||||
|
||||
18
boards/lilygo_tdeck/display_i.h
Normal file
18
boards/lilygo_tdeck/display_i.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "hal/lv_hal_disp.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
lv_disp_t* tdeck_display_init();
|
||||
|
||||
bool tdeck_backlight_init();
|
||||
|
||||
void tdeck_backlight_set(uint8_t duty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,4 +1,5 @@
|
||||
#include "lilygo_tdeck.h"
|
||||
#include "display_i.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
bool tdeck_bootstrap();
|
||||
@ -8,6 +9,9 @@ extern const SdCard tdeck_sdcard;
|
||||
|
||||
const HardwareConfig lilygo_tdeck = {
|
||||
.bootstrap = &tdeck_bootstrap,
|
||||
.display = {
|
||||
.set_backlight_duty = &tdeck_backlight_set
|
||||
},
|
||||
.init_lvgl = &tdeck_init_lvgl,
|
||||
.sdcard = &tdeck_sdcard
|
||||
};
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
#include "config.h"
|
||||
#include "display_i.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "keyboard.h"
|
||||
#include "log.h"
|
||||
#include "ui/lvgl_sync.h"
|
||||
#include <thread.h>
|
||||
#include "thread.h"
|
||||
|
||||
#define TAG "tdeck_lvgl"
|
||||
|
||||
lv_disp_t* tdeck_display_init();
|
||||
void tdeck_enable_backlight();
|
||||
bool tdeck_init_touch(esp_lcd_panel_io_handle_t* io_handle, esp_lcd_touch_handle_t* touch_handle);
|
||||
|
||||
bool tdeck_init_lvgl() {
|
||||
@ -16,11 +15,9 @@ bool tdeck_init_lvgl() {
|
||||
static esp_lcd_panel_io_handle_t touch_io_handle;
|
||||
static esp_lcd_touch_handle_t touch_handle;
|
||||
|
||||
// Init LVGL Port library
|
||||
|
||||
const lvgl_port_cfg_t lvgl_cfg = {
|
||||
.task_priority = THREAD_PRIORITY_RENDER,
|
||||
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH ,
|
||||
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
|
||||
.task_affinity = -1, // core pinning
|
||||
.task_max_sleep_ms = 500,
|
||||
.timer_period_ms = 5
|
||||
@ -66,8 +63,5 @@ bool tdeck_init_lvgl() {
|
||||
|
||||
keyboard_alloc(display);
|
||||
|
||||
TT_LOG_D(TAG, "enabling backlight");
|
||||
tdeck_enable_backlight();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6,5 +6,8 @@ bool ws3t_bootstrap();
|
||||
|
||||
const HardwareConfig waveshare_s3_touch = {
|
||||
.bootstrap = &ws3t_bootstrap,
|
||||
.display = {
|
||||
.set_backlight_duty = NULL // TODO: This requires implementing the CH422G IO expander
|
||||
},
|
||||
.init_lvgl = &ws3t_init_lvgl
|
||||
};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "tactility_core.h"
|
||||
#include "display_i.h"
|
||||
#include <driver/spi_common.h>
|
||||
|
||||
#define TAG "twodotfour_bootstrap"
|
||||
@ -83,5 +83,12 @@ bool twodotfour_bootstrap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't turn the backlight on yet - Tactility init will take care of it
|
||||
TT_LOG_I(TAG, "Init backlight");
|
||||
if (!twodotfour_backlight_init()) {
|
||||
TT_LOG_E(TAG, "Init backlight failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,28 +1,56 @@
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "tactility_core.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_lcd_ili9341.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "hal/lv_hal_disp.h"
|
||||
#include <esp_lcd_panel_io.h>
|
||||
|
||||
#define TAG "twodotfour_ili9341"
|
||||
|
||||
static void twodotfour_backlight_on() {
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = BIT64(TWODOTFOUR_LCD_PIN_BACKLIGHT),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
// Dipslay backlight (PWM)
|
||||
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER LEDC_TIMER_0
|
||||
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL LEDC_CHANNEL_0
|
||||
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES LEDC_TIMER_8_BIT
|
||||
#define TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY (1000)
|
||||
|
||||
bool twodotfour_backlight_init() {
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE,
|
||||
.timer_num = TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER,
|
||||
.duty_resolution = TWODOTFOUR_LCD_BACKLIGHT_LEDC_DUTY_RES,
|
||||
.freq_hz = TWODOTFOUR_LCD_BACKLIGHT_LEDC_FREQUENCY,
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
};
|
||||
|
||||
gpio_config(&io_conf);
|
||||
if (ledc_timer_config(&ledc_timer) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Backlight led timer config failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gpio_set_level(TWODOTFOUR_LCD_PIN_BACKLIGHT, 1) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to turn backlight on");
|
||||
return true;
|
||||
}
|
||||
|
||||
void twodotfour_backlight_set(uint8_t duty) {
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.speed_mode = TWODOTFOUR_LCD_BACKLIGHT_LEDC_MODE,
|
||||
.channel = TWODOTFOUR_LCD_BACKLIGHT_LEDC_CHANNEL,
|
||||
.timer_sel = TWODOTFOUR_LCD_BACKLIGHT_LEDC_TIMER,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = TWODOTFOUR_LCD_PIN_BACKLIGHT,
|
||||
.duty = duty,
|
||||
.hpoint = 0
|
||||
};
|
||||
|
||||
// Setting the config in the timer init and then calling ledc_set_duty() doesn't work when
|
||||
// the app is running. For an unknown reason we have to call this config method every time:
|
||||
if (ledc_channel_config(&ledc_channel) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure display backlight");
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,7 +122,5 @@ lv_disp_t* twodotfour_display_init() {
|
||||
|
||||
lv_disp_t* display = lvgl_port_add_disp(&disp_cfg);
|
||||
|
||||
twodotfour_backlight_on();
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
15
boards/yellow_board/display_i.h
Normal file
15
boards/yellow_board/display_i.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool twodotfour_backlight_init();
|
||||
void twodotfour_backlight_set(uint8_t duty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,4 +1,5 @@
|
||||
#include "yellow_board.h"
|
||||
#include "display_i.h"
|
||||
|
||||
bool twodotfour_lvgl_init();
|
||||
bool twodotfour_bootstrap();
|
||||
@ -7,6 +8,9 @@ extern const SdCard twodotfour_sdcard;
|
||||
|
||||
const HardwareConfig yellow_board_24inch_cap = {
|
||||
.bootstrap = &twodotfour_bootstrap,
|
||||
.display = {
|
||||
.set_backlight_duty = &twodotfour_backlight_set
|
||||
},
|
||||
.init_lvgl = &twodotfour_lvgl_init,
|
||||
.sdcard = &twodotfour_sdcard
|
||||
};
|
||||
|
||||
@ -7,10 +7,22 @@
|
||||
is not automatically called. This is normally done by a hook in `FreeRTOSConfig.h`
|
||||
but that seems to not work with ESP32. I should investigate task cleanup hooks further.
|
||||
- Set DPI in sdkconfig for Waveshare display
|
||||
- Try to drive Yellow Board backlight with PWM to reduce backlight strength
|
||||
- Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials.
|
||||
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
||||
- Try out Waveshare S3 120MHz mode for PSRAM (see "enabling 120M PSRAM is necessary" in [docs](https://www.waveshare.com/wiki/ESP32-S3-Touch-LCD-4.3#Other_Notes))
|
||||
- Fix for dark theme: the wifi icons should use the colour of the theme (they remain black when dark theme is set)
|
||||
|
||||
# Core Ideas
|
||||
- Make a HAL? It would mainly be there to support PC development. It's a lot of effort for supporting what's effectively a dev-only feature.
|
||||
- Support for displays with different DPI. Consider the layer-based system like on Android.
|
||||
- Display orientation support for Display app
|
||||
- If present, use LED to show boot status
|
||||
|
||||
# App Improvement Ideas
|
||||
- Make a Settings app to show all the apps that have a "settings" app type (and hide those in desktop)
|
||||
- Sort desktop apps by name.
|
||||
- Light/dark mode selection in Display settings app.
|
||||
|
||||
# App Ideas
|
||||
- Chip 8 emulator
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
typedef enum {
|
||||
BUNDLE_ENTRY_TYPE_BOOL,
|
||||
BUNDLE_ENTRY_TYPE_INT,
|
||||
BUNDLE_ENTRY_TYPE_INT32,
|
||||
BUNDLE_ENTRY_TYPE_STRING,
|
||||
} BundleEntryType;
|
||||
|
||||
@ -16,7 +16,7 @@ typedef struct {
|
||||
BundleEntryType type;
|
||||
union {
|
||||
bool bool_value;
|
||||
int int_value;
|
||||
int32_t int32_value;
|
||||
char* string_ptr;
|
||||
};
|
||||
} BundleEntry;
|
||||
@ -28,10 +28,10 @@ BundleEntry* bundle_entry_alloc_bool(bool value) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
BundleEntry* bundle_entry_alloc_int(int value) {
|
||||
BundleEntry* bundle_entry_alloc_int32(int32_t value) {
|
||||
BundleEntry* entry = malloc(sizeof(BundleEntry));
|
||||
entry->type = BUNDLE_ENTRY_TYPE_INT;
|
||||
entry->int_value = value;
|
||||
entry->type = BUNDLE_ENTRY_TYPE_INT32;
|
||||
entry->int32_value = value;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ BundleEntry* bundle_entry_alloc_copy(BundleEntry* source) {
|
||||
entry->string_ptr = malloc(strlen(source->string_ptr) + 1);
|
||||
strcpy(entry->string_ptr, source->string_ptr);
|
||||
} else {
|
||||
entry->int_value = source->int_value;
|
||||
entry->int32_value = source->int32_value;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@ -112,11 +112,11 @@ bool tt_bundle_get_bool(Bundle bundle, const char* key) {
|
||||
return (*entry)->bool_value;
|
||||
}
|
||||
|
||||
int tt_bundle_get_int(Bundle bundle, const char* key) {
|
||||
int32_t tt_bundle_get_int32(Bundle bundle, const char* key) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
tt_check(entry != NULL);
|
||||
return (*entry)->int_value;
|
||||
return (*entry)->int32_value;
|
||||
}
|
||||
|
||||
const char* tt_bundle_get_string(Bundle bundle, const char* key) {
|
||||
@ -126,23 +126,51 @@ const char* tt_bundle_get_string(Bundle bundle, const char* key) {
|
||||
return (*entry)->string_ptr;
|
||||
}
|
||||
|
||||
bool tt_bundle_opt_bool(Bundle bundle, const char* key, bool* out) {
|
||||
bool tt_bundle_has_bool(Bundle bundle, const char* key) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
if (entry != NULL) {
|
||||
*out = (*entry)->bool_value;
|
||||
return true;
|
||||
return (entry != NULL) && ((*entry)->type == BUNDLE_ENTRY_TYPE_BOOL);
|
||||
}
|
||||
|
||||
bool tt_bundle_has_int32(Bundle bundle, const char* key) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
return (entry != NULL) && ((*entry)->type == BUNDLE_ENTRY_TYPE_INT32);
|
||||
}
|
||||
|
||||
bool tt_bundle_has_string(Bundle bundle, const char* key) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
return (entry != NULL) && ((*entry)->type == BUNDLE_ENTRY_TYPE_STRING);
|
||||
}
|
||||
|
||||
bool tt_bundle_opt_bool(Bundle bundle, const char* key, bool* out) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry_ptr = BundleDict_get(data->dict, key);
|
||||
if (entry_ptr != NULL) {
|
||||
BundleEntry* entry = *entry_ptr;
|
||||
if (entry->type == BUNDLE_ENTRY_TYPE_BOOL) {
|
||||
*out = entry->bool_value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool tt_bundle_opt_int(Bundle bundle, const char* key, int* out) {
|
||||
bool tt_bundle_opt_int32(Bundle bundle, const char* key, int32_t* out) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
if (entry != NULL) {
|
||||
*out = (*entry)->int_value;
|
||||
return true;
|
||||
BundleEntry** entry_ptr = BundleDict_get(data->dict, key);
|
||||
if (entry_ptr != NULL) {
|
||||
BundleEntry* entry = *entry_ptr;
|
||||
if (entry->type == BUNDLE_ENTRY_TYPE_INT32) {
|
||||
*out = entry->int32_value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -150,10 +178,15 @@ bool tt_bundle_opt_int(Bundle bundle, const char* key, int* out) {
|
||||
|
||||
bool tt_bundle_opt_string(Bundle bundle, const char* key, char** out) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry = BundleDict_get(data->dict, key);
|
||||
if (entry != NULL) {
|
||||
*out = (*entry)->string_ptr;
|
||||
return true;
|
||||
BundleEntry** entry_ptr = BundleDict_get(data->dict, key);
|
||||
if (entry_ptr != NULL) {
|
||||
BundleEntry* entry = *entry_ptr;
|
||||
if (entry->type == BUNDLE_ENTRY_TYPE_STRING) {
|
||||
*out = entry->string_ptr;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -172,15 +205,15 @@ void tt_bundle_put_bool(Bundle bundle, const char* key, bool value) {
|
||||
}
|
||||
}
|
||||
|
||||
void tt_bundle_put_int(Bundle bundle, const char* key, int value) {
|
||||
void tt_bundle_put_int32(Bundle bundle, const char* key, int32_t value) {
|
||||
BundleData* data = (BundleData*)bundle;
|
||||
BundleEntry** entry_handle = BundleDict_get(data->dict, key);
|
||||
if (entry_handle != NULL) {
|
||||
BundleEntry* entry = *entry_handle;
|
||||
tt_assert(entry->type == BUNDLE_ENTRY_TYPE_INT);
|
||||
entry->int_value = value;
|
||||
tt_assert(entry->type == BUNDLE_ENTRY_TYPE_INT32);
|
||||
entry->int32_value = value;
|
||||
} else {
|
||||
BundleEntry* entry = bundle_entry_alloc_int(value);
|
||||
BundleEntry* entry = bundle_entry_alloc_int32(value);
|
||||
BundleDict_set_at(data->dict, key, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -18,15 +19,19 @@ Bundle tt_bundle_alloc_copy(Bundle source);
|
||||
void tt_bundle_free(Bundle bundle);
|
||||
|
||||
bool tt_bundle_get_bool(Bundle bundle, const char* key);
|
||||
int tt_bundle_get_int(Bundle bundle, const char* key);
|
||||
int32_t tt_bundle_get_int32(Bundle bundle, const char* key);
|
||||
const char* tt_bundle_get_string(Bundle bundle, const char* key);
|
||||
|
||||
bool tt_bundle_has_bool(Bundle bundle, const char* key);
|
||||
bool tt_bundle_has_int32(Bundle bundle, const char* key);
|
||||
bool tt_bundle_has_string(Bundle bundle, const char* key);
|
||||
|
||||
bool tt_bundle_opt_bool(Bundle bundle, const char* key, bool* out);
|
||||
bool tt_bundle_opt_int(Bundle bundle, const char* key, int* out);
|
||||
bool tt_bundle_opt_int32(Bundle bundle, const char* key, int32_t* out);
|
||||
bool tt_bundle_opt_string(Bundle bundle, const char* key, char** out);
|
||||
|
||||
void tt_bundle_put_bool(Bundle bundle, const char* key, bool value);
|
||||
void tt_bundle_put_int(Bundle bundle, const char* key, int value);
|
||||
void tt_bundle_put_int32(Bundle bundle, const char* key, int32_t value);
|
||||
void tt_bundle_put_string(Bundle bundle, const char* key, const char* value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -2,11 +2,10 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(BOARD_COMPONENTS esp_wifi)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES src/*.c)
|
||||
|
||||
idf_component_register(
|
||||
SRC_DIRS "src"
|
||||
"src/apps/system/wifi_connect"
|
||||
"src/apps/system/wifi_manage"
|
||||
"src/services/wifi"
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS "src/"
|
||||
REQUIRES esp_wifi nvs_flash spiffs
|
||||
)
|
||||
|
||||
@ -115,7 +115,7 @@ AppManifest wifi_connect_app = {
|
||||
.id = "wifi_connect",
|
||||
.name = "Wi-Fi Connect",
|
||||
.icon = NULL,
|
||||
.type = AppTypeSystem,
|
||||
.type = AppTypeSettings,
|
||||
.on_start = &app_start,
|
||||
.on_stop = &app_stop,
|
||||
.on_show = &app_show,
|
||||
|
||||
@ -67,13 +67,9 @@ void wifi_connect_view_create_bottom_buttons(WifiConnect* wifi, lv_obj_t* parent
|
||||
void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {
|
||||
WifiConnect* wifi_connect = (WifiConnect*)wifi;
|
||||
WifiConnectView* view = &wifi_connect->view;
|
||||
// TODO: Standardize this into "window content" function?
|
||||
// TODO: It can then be dynamically determined based on screen res and size
|
||||
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_top(parent, 8, 0);
|
||||
lv_obj_set_style_pad_bottom(parent, 8, 0);
|
||||
lv_obj_set_style_pad_left(parent, 16, 0);
|
||||
lv_obj_set_style_pad_right(parent, 16, 0);
|
||||
tt_lv_obj_set_style_auto_padding(parent);
|
||||
|
||||
view->root = parent;
|
||||
|
||||
|
||||
@ -158,7 +158,7 @@ AppManifest wifi_manage_app = {
|
||||
.id = "wifi_manage",
|
||||
.name = "Wi-Fi",
|
||||
.icon = NULL,
|
||||
.type = AppTypeSystem,
|
||||
.type = AppTypeSettings,
|
||||
.on_start = &app_start,
|
||||
.on_stop = &app_stop,
|
||||
.on_show = &app_show,
|
||||
|
||||
@ -150,13 +150,8 @@ static void update_connected_ap(WifiManageView* view, WifiManageState* state, Wi
|
||||
void wifi_manage_view_create(WifiManageView* view, WifiManageBindings* bindings, lv_obj_t* parent) {
|
||||
view->root = parent;
|
||||
|
||||
// TODO: Standardize this into "window content" function?
|
||||
// TODO: It can then be dynamically determined based on screen res and size
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_top(parent, 8, 0);
|
||||
lv_obj_set_style_pad_bottom(parent, 8, 0);
|
||||
lv_obj_set_style_pad_left(parent, 16, 0);
|
||||
lv_obj_set_style_pad_right(parent, 16, 0);
|
||||
tt_lv_obj_set_style_auto_padding(parent);
|
||||
|
||||
// Top row: enable/disable
|
||||
lv_obj_t* switch_container = lv_obj_create(parent);
|
||||
|
||||
@ -23,6 +23,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
PUBLIC idf::lvgl # libs/
|
||||
PUBLIC idf::driver
|
||||
PUBLIC idf::spiffs
|
||||
PUBLIC idf::nvs_flash
|
||||
)
|
||||
else()
|
||||
add_definitions(-D_Nullable=)
|
||||
|
||||
@ -25,6 +25,8 @@ static void desktop_show(TT_UNUSED App app, TT_UNUSED lv_obj_t* parent) {
|
||||
|
||||
lv_list_add_text(list, "System");
|
||||
tt_app_manifest_registry_for_each_of_type(AppTypeSystem, list, create_app_widget);
|
||||
lv_list_add_text(list, "Settings");
|
||||
tt_app_manifest_registry_for_each_of_type(AppTypeSettings, list, create_app_widget);
|
||||
lv_list_add_text(list, "User");
|
||||
tt_app_manifest_registry_for_each_of_type(AppTypeUser, list, create_app_widget);
|
||||
}
|
||||
|
||||
71
tactility/src/apps/settings/display/display.c
Normal file
71
tactility/src/apps/settings/display/display.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include "app.h"
|
||||
#include "lvgl.h"
|
||||
#include "preferences.h"
|
||||
#include "tactility.h"
|
||||
#include "ui/spacer.h"
|
||||
#include "ui/style.h"
|
||||
|
||||
static bool backlight_duty_set = false;
|
||||
static uint8_t backlight_duty = 255;
|
||||
|
||||
static void slider_event_cb(lv_event_t* e) {
|
||||
lv_obj_t* slider = lv_event_get_target(e);
|
||||
const Config* config = tt_get_config();
|
||||
SetBacklightDuty set_backlight_duty = config->hardware->display.set_backlight_duty;
|
||||
|
||||
if (set_backlight_duty != NULL) {
|
||||
int32_t slider_value = lv_slider_get_value(slider);
|
||||
|
||||
backlight_duty = (uint8_t)slider_value;
|
||||
backlight_duty_set = true;
|
||||
|
||||
set_backlight_duty(backlight_duty);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_show(TT_UNUSED App app, lv_obj_t* parent) {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
tt_lv_obj_set_style_auto_padding(parent);
|
||||
|
||||
lv_obj_t* label = lv_label_create(parent);
|
||||
lv_label_set_text(label, "Brightness");
|
||||
|
||||
tt_lv_spacer_create(parent, 1, 2);
|
||||
|
||||
lv_obj_t* slider_container = lv_obj_create(parent);
|
||||
lv_obj_set_size(slider_container, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
|
||||
lv_obj_t* slider = lv_slider_create(slider_container);
|
||||
lv_obj_set_width(slider, LV_PCT(90));
|
||||
lv_obj_center(slider);
|
||||
lv_slider_set_range(slider, 0, 255);
|
||||
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
|
||||
const Config* config = tt_get_config();
|
||||
SetBacklightDuty set_backlight_duty = config->hardware->display.set_backlight_duty;
|
||||
if (set_backlight_duty == NULL) {
|
||||
lv_slider_set_value(slider, 255, LV_ANIM_OFF);
|
||||
lv_obj_add_state(slider, LV_STATE_DISABLED);
|
||||
} else {
|
||||
int32_t value = 255;
|
||||
tt_preferences()->opt_int32("display", "backlight_duty", &value);
|
||||
lv_slider_set_value(slider, value, LV_ANIM_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void app_hide(App app) {
|
||||
if (backlight_duty_set) {
|
||||
tt_preferences()->put_int32("display", "backlight_duty", backlight_duty);
|
||||
}
|
||||
}
|
||||
|
||||
const AppManifest display_app = {
|
||||
.id = "display",
|
||||
.name = "Display",
|
||||
.icon = NULL,
|
||||
.type = AppTypeSettings,
|
||||
.on_start = NULL,
|
||||
.on_stop = NULL,
|
||||
.on_show = &app_show,
|
||||
.on_hide = &app_hide
|
||||
};
|
||||
@ -1,7 +1,5 @@
|
||||
#include "app_manifest.h"
|
||||
#include "core_extra_defines.h"
|
||||
#include "app.h"
|
||||
#include "lvgl.h"
|
||||
#include "thread.h"
|
||||
|
||||
static void app_show(TT_UNUSED App app, lv_obj_t* parent) {
|
||||
lv_obj_t* heap_info = lv_label_create(parent);
|
||||
|
||||
@ -5,10 +5,34 @@
|
||||
|
||||
typedef bool (*Bootstrap)();
|
||||
typedef bool (*InitLvgl)();
|
||||
typedef bool (*InitLvgl)();
|
||||
|
||||
typedef void (*SetBacklightDuty)(uint8_t);
|
||||
typedef struct {
|
||||
/** Set backlight duty */
|
||||
SetBacklightDuty set_backlight_duty;
|
||||
} Display;
|
||||
|
||||
typedef struct {
|
||||
// Optional bootstrapping method (e.g. to turn peripherals on)
|
||||
/**
|
||||
* Optional bootstrapping method (e.g. to turn peripherals on)
|
||||
* This is called after Tactility core init and before any other inits in the HardwareConfig.
|
||||
* */
|
||||
const Bootstrap _Nullable bootstrap;
|
||||
|
||||
/**
|
||||
* Initializes LVGL with all relevant hardware.
|
||||
* This includes the display and optional pointer devices (such as touch) or a keyboard.
|
||||
*/
|
||||
const InitLvgl init_lvgl;
|
||||
|
||||
/**
|
||||
* An interface for display features such as setting the backlight.
|
||||
*/
|
||||
const Display display;
|
||||
|
||||
/**
|
||||
* An optional SD card interface.
|
||||
*/
|
||||
const SdCard* _Nullable sdcard;
|
||||
} HardwareConfig;
|
||||
|
||||
15
tactility/src/preferences.c
Normal file
15
tactility/src/preferences.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include "preferences.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
extern const Preferences preferences_esp;
|
||||
#else
|
||||
extern const Preferences preferences_memory;
|
||||
#endif
|
||||
|
||||
const Preferences* tt_preferences() {
|
||||
#ifdef ESP_PLATFORM
|
||||
return &preferences_esp;
|
||||
#else
|
||||
return &preferences_memory;
|
||||
#endif
|
||||
}
|
||||
44
tactility/src/preferences.h
Normal file
44
tactility/src/preferences.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef bool (*PreferencesHasBool)(const char* namespace, const char* key);
|
||||
typedef bool (*PreferencesHasInt32)(const char* namespace, const char* key);
|
||||
typedef bool (*PreferencesHasString)(const char* namespace, const char* key);
|
||||
|
||||
typedef bool (*PreferencesOptBool)(const char* namespace, const char* key, bool* out);
|
||||
typedef bool (*PreferencesOptInt32)(const char* namespace, const char* key, int32_t* out);
|
||||
typedef bool (*PreferencesOptString)(const char* namespace, const char* key, char* out, size_t* size);
|
||||
|
||||
typedef void (*PreferencesPutBool)(const char* namespace, const char* key, bool value);
|
||||
typedef void (*PreferencesPutInt32)(const char* namespace, const char* key, int32_t value);
|
||||
typedef void (*PreferencesPutString)(const char* namespace, const char* key, const char* value);
|
||||
|
||||
typedef struct {
|
||||
PreferencesHasBool has_bool;
|
||||
PreferencesHasInt32 has_int32;
|
||||
PreferencesHasString has_string;
|
||||
|
||||
PreferencesOptBool opt_bool;
|
||||
PreferencesOptInt32 opt_int32;
|
||||
PreferencesOptString opt_string;
|
||||
|
||||
PreferencesPutBool put_bool;
|
||||
PreferencesPutInt32 put_int32;
|
||||
PreferencesPutString put_string;
|
||||
} Preferences;
|
||||
|
||||
/**
|
||||
* @return an instance of Preferences.
|
||||
*/
|
||||
const Preferences* tt_preferences();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
96
tactility/src/preferences_esp.c
Normal file
96
tactility/src/preferences_esp.c
Normal file
@ -0,0 +1,96 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "preferences.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "tactility_core.h"
|
||||
|
||||
static bool opt_bool(const char* namespace, const char* key, bool* out) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
return false;
|
||||
} else {
|
||||
uint8_t out_number;
|
||||
bool success = nvs_get_u8(handle, key, &out_number) == ESP_OK;
|
||||
nvs_close(handle);
|
||||
if (success) {
|
||||
*out = (bool)out_number;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
static bool opt_int32(const char* namespace, const char* key, int32_t* out) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
return false;
|
||||
} else {
|
||||
bool success = nvs_get_i32(handle, key, out) == ESP_OK;
|
||||
nvs_close(handle);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
static bool opt_string(const char* namespace, const char* key, char* out, size_t* size) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) != ESP_OK) {
|
||||
return false;
|
||||
} else {
|
||||
bool success = nvs_get_str(handle, key, out, size) == ESP_OK;
|
||||
nvs_close(handle);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_bool(const char* namespace, const char* key) {
|
||||
bool temp;
|
||||
return opt_bool(namespace, key, &temp);
|
||||
}
|
||||
|
||||
static bool has_int32(const char* namespace, const char* key) {
|
||||
int32_t temp;
|
||||
return opt_int32(namespace, key, &temp);
|
||||
}
|
||||
|
||||
static bool has_string(const char* namespace, const char* key) {
|
||||
char temp[128];
|
||||
size_t temp_size = 128;
|
||||
return opt_string(namespace, key, temp, &temp_size);
|
||||
}
|
||||
|
||||
static void put_bool(const char* namespace, const char* key, bool value) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
||||
nvs_set_u8(handle, key, (uint8_t)value) == ESP_OK;
|
||||
nvs_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void put_int32(const char* namespace, const char* key, int32_t value) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
||||
nvs_set_i32(handle, key, value) == ESP_OK;
|
||||
nvs_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void put_string(const char* namespace, const char* key, const char* text) {
|
||||
nvs_handle_t handle;
|
||||
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
||||
nvs_set_str(handle, key, text);
|
||||
nvs_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
const Preferences preferences_esp = {
|
||||
.has_bool = &has_bool,
|
||||
.has_int32 = &has_int32,
|
||||
.has_string = &has_string,
|
||||
.opt_bool = &opt_bool,
|
||||
.opt_int32 = &opt_int32,
|
||||
.opt_string = &opt_string,
|
||||
.put_bool = &put_bool,
|
||||
.put_int32 = &put_int32,
|
||||
.put_string = &put_string
|
||||
};
|
||||
|
||||
#endif
|
||||
109
tactility/src/preferences_memory.c
Normal file
109
tactility/src/preferences_memory.c
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef ESP_PLATFOM
|
||||
|
||||
#include "bundle.h"
|
||||
#include "preferences.h"
|
||||
#include <string.h>
|
||||
#include <tactility_core.h>
|
||||
|
||||
static Bundle* preferences_bundle;
|
||||
|
||||
static Bundle* get_preferences_bundle() {
|
||||
if (preferences_bundle == NULL) {
|
||||
preferences_bundle = tt_bundle_alloc();
|
||||
}
|
||||
return preferences_bundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string that is effectively "namespace:key" so we can create a single map (bundle)
|
||||
* to store all the key/value pairs.
|
||||
*
|
||||
* @param[in] namespace
|
||||
* @param[in] key
|
||||
* @param[out] out
|
||||
*/
|
||||
static void get_bundle_key(const char* namespace, const char* key, char* out) {
|
||||
strcpy(out, namespace);
|
||||
size_t namespace_len = strlen(namespace);
|
||||
out[namespace_len] = ':';
|
||||
char* out_with_key_offset = &out[namespace_len + 1];
|
||||
strcpy(out_with_key_offset, key);
|
||||
}
|
||||
|
||||
static bool has_bool(const char* namespace, const char* key) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_has_bool(get_preferences_bundle(), bundle_key);
|
||||
}
|
||||
|
||||
static bool has_int32(const char* namespace, const char* key) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_has_int32(get_preferences_bundle(), bundle_key);
|
||||
}
|
||||
|
||||
static bool has_string(const char* namespace, const char* key) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_has_string(get_preferences_bundle(), bundle_key);
|
||||
}
|
||||
|
||||
static bool opt_bool(const char* namespace, const char* key, bool* out) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_opt_bool(get_preferences_bundle(), bundle_key, out);
|
||||
}
|
||||
|
||||
static bool opt_int32(const char* namespace, const char* key, int32_t* out) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_opt_int32(get_preferences_bundle(), bundle_key, out);
|
||||
}
|
||||
|
||||
static bool opt_string(const char* namespace, const char* key, char* out, size_t* size) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
char* bundle_out = NULL;
|
||||
if (tt_bundle_opt_string(get_preferences_bundle(), bundle_key, &bundle_out)) {
|
||||
tt_assert(bundle_out != NULL);
|
||||
size_t found_length = strlen(bundle_out);
|
||||
tt_check(found_length <= (*size + 1), "output buffer not large enough");
|
||||
*size = found_length;
|
||||
strcpy(out, bundle_out);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void put_bool(const char* namespace, const char* key, bool value) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_put_bool(get_preferences_bundle(), bundle_key, value);
|
||||
}
|
||||
|
||||
static void put_int32(const char* namespace, const char* key, int32_t value) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_put_int32(get_preferences_bundle(), bundle_key, value);
|
||||
}
|
||||
|
||||
static void put_string(const char* namespace, const char* key, const char* text) {
|
||||
char bundle_key[128];
|
||||
get_bundle_key(namespace, key, bundle_key);
|
||||
return tt_bundle_put_string(get_preferences_bundle(), bundle_key, text);
|
||||
}
|
||||
|
||||
const Preferences preferences_memory = {
|
||||
.has_bool = &has_bool,
|
||||
.has_int32 = &has_int32,
|
||||
.has_string = &has_string,
|
||||
.opt_bool = &opt_bool,
|
||||
.opt_int32 = &opt_int32,
|
||||
.opt_string = &opt_string,
|
||||
.put_bool = &put_bool,
|
||||
.put_int32 = &put_int32,
|
||||
.put_string = &put_string
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -2,12 +2,15 @@
|
||||
|
||||
#include "app_manifest_registry.h"
|
||||
#include "hardware_i.h"
|
||||
#include "preferences.h"
|
||||
#include "service_registry.h"
|
||||
#include "services/loader/loader.h"
|
||||
|
||||
#define TAG "tactility"
|
||||
|
||||
// region System services
|
||||
static const Config* config_instance = NULL;
|
||||
|
||||
// region Default services
|
||||
|
||||
extern const ServiceManifest gui_service;
|
||||
extern const ServiceManifest loader_service;
|
||||
@ -19,13 +22,15 @@ static const ServiceManifest* const system_services[] = {
|
||||
|
||||
// endregion
|
||||
|
||||
// region System apps
|
||||
// region Default apps
|
||||
|
||||
extern const AppManifest desktop_app;
|
||||
extern const AppManifest display_app;
|
||||
extern const AppManifest system_info_app;
|
||||
|
||||
static const AppManifest* const system_apps[] = {
|
||||
&desktop_app,
|
||||
&display_app,
|
||||
&system_info_app
|
||||
};
|
||||
|
||||
@ -83,6 +88,16 @@ TT_UNUSED void tt_init(const Config* config) {
|
||||
|
||||
tt_hardware_init(config->hardware);
|
||||
|
||||
SetBacklightDuty set_backlight_duty = config->hardware->display.set_backlight_duty;
|
||||
if (set_backlight_duty != NULL) {
|
||||
int32_t backlight_duty = 200;
|
||||
if (!tt_preferences()->opt_int32("display", "backlight_duty", &backlight_duty)) {
|
||||
tt_preferences()->put_int32("display", "backlight_duty", backlight_duty);
|
||||
}
|
||||
int32_t safe_backlight_duty = TT_MIN(backlight_duty, 255);
|
||||
set_backlight_duty((uint8_t)safe_backlight_duty);
|
||||
}
|
||||
|
||||
// Note: the order of starting apps and services is critical!
|
||||
// System services are registered first so the apps below can use them
|
||||
register_and_start_system_services();
|
||||
@ -103,4 +118,10 @@ TT_UNUSED void tt_init(const Config* config) {
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "tt_init complete");
|
||||
|
||||
config_instance = config;
|
||||
}
|
||||
|
||||
const Config* _Nullable tt_get_config() {
|
||||
return config_instance;
|
||||
}
|
||||
|
||||
@ -17,8 +17,18 @@ typedef struct {
|
||||
const char* auto_start_app_id;
|
||||
} Config;
|
||||
|
||||
/**
|
||||
* Attempts to initialize Tactility and all configured hardware.
|
||||
* @param config
|
||||
*/
|
||||
TT_UNUSED void tt_init(const Config* config);
|
||||
|
||||
/**
|
||||
* While technically nullable, this instance is always set if tt_init() succeeds.
|
||||
* @return the Configuration instance that was passed on to tt_init() if init is successful
|
||||
*/
|
||||
const Config* _Nullable tt_get_config();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -14,3 +14,10 @@ void tt_lv_obj_set_style_no_padding(lv_obj_t* obj) {
|
||||
lv_obj_set_style_pad_all(obj, LV_STATE_DEFAULT, 0);
|
||||
lv_obj_set_style_pad_gap(obj, LV_STATE_DEFAULT, 0);
|
||||
}
|
||||
|
||||
void tt_lv_obj_set_style_auto_padding(lv_obj_t* obj) {
|
||||
lv_obj_set_style_pad_top(obj, 8, 0);
|
||||
lv_obj_set_style_pad_bottom(obj, 8, 0);
|
||||
lv_obj_set_style_pad_left(obj, 16, 0);
|
||||
lv_obj_set_style_pad_right(obj, 16, 0);
|
||||
}
|
||||
|
||||
@ -10,6 +10,15 @@ void tt_lv_obj_set_style_bg_blacken(lv_obj_t* obj);
|
||||
void tt_lv_obj_set_style_bg_invisible(lv_obj_t* obj);
|
||||
void tt_lv_obj_set_style_no_padding(lv_obj_t* obj);
|
||||
|
||||
/**
|
||||
* This is to create automatic padding depending on the screen size.
|
||||
* The larger the screen, the more padding it gets.
|
||||
* TODO: It currently only applies a single basic padding, but will be improved later.
|
||||
*
|
||||
* @param obj
|
||||
*/
|
||||
void tt_lv_obj_set_style_auto_padding(lv_obj_t* obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user