diff --git a/CMakeLists.txt b/CMakeLists.txt index dfd40cf1..ceadf2dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,9 @@ if (DEFINED ENV{ESP_IDF_VERSION}) set(COMPONENTS app-esp) set(EXTRA_COMPONENT_DIRS "boards" - "tactility-esp" "app-esp" + "tactility" + "tactility-headless" "libs/esp_lvgl_port" "libs/lvgl" "libs/M5Unified" @@ -40,7 +41,12 @@ endif() project(tactility-root) -add_subdirectory(tactility) +# Defined as regular project for PC and component for ESP +if (NOT DEFINED ENV{ESP_IDF_VERSION}) + add_subdirectory(tactility) + add_subdirectory(tactility-headless) +endif() + add_subdirectory(tactility-core) add_subdirectory(libs/mlib) diff --git a/app-esp/CMakeLists.txt b/app-esp/CMakeLists.txt index 4949ae44..e07c9772 100644 --- a/app-esp/CMakeLists.txt +++ b/app-esp/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -set(BOARD_COMPONENTS tactility-esp) +set(BOARD_COMPONENTS tactility) if("${IDF_TARGET}" STREQUAL "esp32") list(APPEND BOARD_COMPONENTS @@ -22,7 +22,3 @@ idf_component_register( "src/hello_world" REQUIRES ${BOARD_COMPONENTS} ) - -# TODO Remove? -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) - diff --git a/app-esp/src/main.c b/app-esp/src/main.c index 125e5fd8..767a3ebf 100644 --- a/app-esp/src/main.c +++ b/app-esp/src/main.c @@ -1,16 +1,11 @@ #include "board_config.h" -#include "tactility_esp.h" // Apps #include "hello_world/hello_world.h" +#include "tactility.h" extern void wifi_main(void*); -extern const ServiceManifest wifi_service; -extern const AppManifest gpio_app; -extern const AppManifest wifi_connect_app; -extern const AppManifest wifi_manage_app; - void app_main(void) { static const Config config = { /** @@ -19,19 +14,12 @@ void app_main(void) { */ .hardware = TT_BOARD_HARDWARE, .apps = { - &gpio_app, &hello_world_app, - &wifi_connect_app, - &wifi_manage_app - }, - .services = { - &wifi_service }, + .services = {}, .auto_start_app_id = NULL }; - tt_esp_init(); - tt_init(&config); wifi_main(NULL); diff --git a/app-sim/CMakeLists.txt b/app-sim/CMakeLists.txt index aa545d8c..49c24c92 100644 --- a/app-sim/CMakeLists.txt +++ b/app-sim/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(app-sim ${SOURCES}) target_link_libraries(app-sim PRIVATE tactility PRIVATE tactility-core + PRIVATE tactility-headless PRIVATE lvgl ) diff --git a/app-sim/src/hardware_config.c b/app-sim/src/hardware_config.c index 3fbf1e73..3fbea738 100644 --- a/app-sim/src/hardware_config.c +++ b/app-sim/src/hardware_config.c @@ -24,5 +24,5 @@ TT_UNUSED static void lvgl_deinit() { HardwareConfig sim_hardware = { .bootstrap = NULL, - .init_lvgl = &lvgl_init, + .init_graphics = &lvgl_init, }; diff --git a/app-sim/src/main.c b/app-sim/src/main.c index 1ccbec1f..4642916a 100644 --- a/app-sim/src/main.c +++ b/app-sim/src/main.c @@ -1,11 +1,5 @@ #include "hello_world/hello_world.h" #include "tactility.h" -#include "assets.h" - -#include "FreeRTOS.h" -#include "ui/statusbar.h" - -#define TAG "main" extern HardwareConfig sim_hardware; @@ -20,9 +14,4 @@ void app_main() { }; tt_init(&config); - - // Note: this is just to test the statusbar as Wi-Fi - // and sd card apps are not available for PC - tt_statusbar_icon_add(TT_ASSETS_ICON_SDCARD_ALERT); - tt_statusbar_icon_add(TT_ASSETS_ICON_WIFI_OFF); } diff --git a/boards/lilygo_tdeck/CMakeLists.txt b/boards/lilygo_tdeck/CMakeLists.txt index 56fd7fc8..c86e52e5 100644 --- a/boards/lilygo_tdeck/CMakeLists.txt +++ b/boards/lilygo_tdeck/CMakeLists.txt @@ -1,7 +1,5 @@ idf_component_register( SRC_DIRS "." INCLUDE_DIRS "." - REQUIRES esp_lvgl_port esp_lcd esp_lcd_touch_gt911 driver vfs fatfs + REQUIRES tactility esp_lvgl_port esp_lcd esp_lcd_touch_gt911 driver vfs fatfs ) - -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) \ No newline at end of file diff --git a/boards/lilygo_tdeck/lilygo_tdeck.c b/boards/lilygo_tdeck/lilygo_tdeck.c index d7bb06f4..d1d9c15e 100644 --- a/boards/lilygo_tdeck/lilygo_tdeck.c +++ b/boards/lilygo_tdeck/lilygo_tdeck.c @@ -12,6 +12,6 @@ const HardwareConfig lilygo_tdeck = { .display = { .set_backlight_duty = &tdeck_backlight_set }, - .init_lvgl = &tdeck_init_lvgl, + .init_graphics = &tdeck_init_lvgl, .sdcard = &tdeck_sdcard }; diff --git a/boards/m5stack_core2/CMakeLists.txt b/boards/m5stack_core2/CMakeLists.txt index 2e0eec03..5c3a61b5 100644 --- a/boards/m5stack_core2/CMakeLists.txt +++ b/boards/m5stack_core2/CMakeLists.txt @@ -2,7 +2,5 @@ idf_component_register( SRC_DIRS "source" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private" - REQUIRES esp_lvgl_port esp_lcd_ili9341 driver vfs fatfs M5Unified + REQUIRES tactility esp_lvgl_port esp_lcd_ili9341 driver vfs fatfs M5Unified ) - -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) diff --git a/boards/m5stack_core2/source/m5stack_core2.c b/boards/m5stack_core2/source/m5stack_core2.c index f5f71e59..c8cc3b52 100644 --- a/boards/m5stack_core2/source/m5stack_core2.c +++ b/boards/m5stack_core2/source/m5stack_core2.c @@ -9,6 +9,6 @@ const HardwareConfig m5stack_core2 = { .display = { .set_backlight_duty = NULL }, - .init_lvgl = &core2_lvgl_init, + .init_graphics = &core2_lvgl_init, .sdcard = &core2_sdcard }; diff --git a/boards/waveshare_s3_touch/CMakeLists.txt b/boards/waveshare_s3_touch/CMakeLists.txt index 523f2e8a..442e5ebe 100644 --- a/boards/waveshare_s3_touch/CMakeLists.txt +++ b/boards/waveshare_s3_touch/CMakeLists.txt @@ -1,7 +1,5 @@ idf_component_register( SRC_DIRS "." INCLUDE_DIRS "." - REQUIRES lvgl esp_lcd esp_lcd_touch_gt911 + REQUIRES tactility lvgl esp_lcd esp_lcd_touch_gt911 ) - -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) \ No newline at end of file diff --git a/boards/waveshare_s3_touch/waveshare_s3_touch.c b/boards/waveshare_s3_touch/waveshare_s3_touch.c index 2793ab47..9e65a13b 100644 --- a/boards/waveshare_s3_touch/waveshare_s3_touch.c +++ b/boards/waveshare_s3_touch/waveshare_s3_touch.c @@ -9,5 +9,5 @@ const HardwareConfig waveshare_s3_touch = { .display = { .set_backlight_duty = NULL // TODO: This requires implementing the CH422G IO expander }, - .init_lvgl = &ws3t_init_lvgl + .init_graphics = &ws3t_init_lvgl }; diff --git a/boards/yellow_board/CMakeLists.txt b/boards/yellow_board/CMakeLists.txt index cc39151c..8fe057d5 100644 --- a/boards/yellow_board/CMakeLists.txt +++ b/boards/yellow_board/CMakeLists.txt @@ -1,7 +1,5 @@ idf_component_register( SRC_DIRS "." INCLUDE_DIRS "." - REQUIRES esp_lvgl_port esp_lcd_touch_cst816s esp_lcd_ili9341 driver vfs fatfs + REQUIRES tactility esp_lvgl_port esp_lcd_touch_cst816s esp_lcd_ili9341 driver vfs fatfs ) - -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) \ No newline at end of file diff --git a/boards/yellow_board/yellow_board.c b/boards/yellow_board/yellow_board.c index 03f08d9b..b678092e 100644 --- a/boards/yellow_board/yellow_board.c +++ b/boards/yellow_board/yellow_board.c @@ -11,6 +11,6 @@ const HardwareConfig yellow_board_24inch_cap = { .display = { .set_backlight_duty = &twodotfour_backlight_set }, - .init_lvgl = &twodotfour_lvgl_init, + .init_graphics = &twodotfour_lvgl_init, .sdcard = &twodotfour_sdcard }; diff --git a/docs/ideas.md b/docs/ideas.md index 03c34b20..86d82595 100644 --- a/docs/ideas.md +++ b/docs/ideas.md @@ -14,7 +14,7 @@ - App lifecycle docs mention on_create/on_destroy but app lifecycle is on_start/on_stop - Explore LVGL9's FreeRTOS functionality - Explore LVGL9's ILI93414 driver for 2.4" Yellow Board - + # 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. @@ -22,7 +22,7 @@ - 2 wire speaker support - tt_app_start() and similar functions as proxies for Loader app start/stop/etc. - tt_app_set_result() for apps that need to return data to other apps (e.g. file selection) -- Introduce co-routines for calling wifi/lvgl/etc functionality. +- Wi-Fi using dispatcher to dispatch its main functionality to the dedicated Wi-Fi CPU core (to avoid main loop hack) # App Improvement Ideas - Sort desktop apps by name. @@ -30,7 +30,6 @@ # App Ideas - File viewer (images, text... binary?) -- GPIO status viewer - BlueTooth keyboard app - Chip 8 emulator - BadUSB diff --git a/docs/project-structure.puml b/docs/project-structure.puml new file mode 100644 index 00000000..5a9d99e2 --- /dev/null +++ b/docs/project-structure.puml @@ -0,0 +1,23 @@ +@startuml +skinparam componentStyle uml1 + +[tactility] as t +note right of t : to build and use graphical apps +[tactility-headless] as theadless +note right of theadless : to build and use background services +[tactility-core] as tcore +note right of tcore : defines, data types, logging, async, etc. + +package "Applications" { + [app-sim] as appsim + [app-esp] as appesp +} + +note right of appesp : app-esp depends on the board \n projects for configuration + +[t] ..> [theadless] +[theadless] ..> [tcore] +[appsim] ..> [t] +[appesp] ..> [t] + +@enduml \ No newline at end of file diff --git a/tactility-core/CMakeLists.txt b/tactility-core/CMakeLists.txt index 619d9261..c02a35ee 100644 --- a/tactility-core/CMakeLists.txt +++ b/tactility-core/CMakeLists.txt @@ -8,6 +8,7 @@ file(GLOB SOURCES "src/*.c") file(GLOB HEADERS "src/*.h") add_library(tactility-core OBJECT) + target_sources(tactility-core PRIVATE ${SOURCES} PUBLIC ${HEADERS} diff --git a/tactility-core/src/dispatcher.c b/tactility-core/src/dispatcher.c index a7d272d3..9d00fa81 100644 --- a/tactility-core/src/dispatcher.c +++ b/tactility-core/src/dispatcher.c @@ -2,9 +2,20 @@ #include "tactility_core.h" +typedef struct { + Callback callback; + void* context; +} DispatcherMessage; + +typedef struct { + MessageQueue* queue; + Mutex* mutex; + DispatcherMessage buffer; // Buffer for consuming a message +} DispatcherData; + Dispatcher* tt_dispatcher_alloc(uint32_t message_count) { - Dispatcher* dispatcher = malloc(sizeof(Dispatcher)); - *dispatcher = (Dispatcher) { + DispatcherData* data = malloc(sizeof(DispatcherData)); + *data = (DispatcherData) { .queue = tt_message_queue_alloc(message_count, sizeof(DispatcherMessage)), .mutex = tt_mutex_alloc(MutexTypeNormal), .buffer = { @@ -12,37 +23,40 @@ Dispatcher* tt_dispatcher_alloc(uint32_t message_count) { .context = NULL } }; - return dispatcher; + return data; } void tt_dispatcher_free(Dispatcher* dispatcher) { - tt_mutex_acquire(dispatcher->mutex, TtWaitForever); - tt_message_queue_reset(dispatcher->queue); - tt_message_queue_free(dispatcher->queue); - tt_mutex_release(dispatcher->mutex); - tt_mutex_free(dispatcher->mutex); - free(dispatcher); + DispatcherData* data = (DispatcherData*)dispatcher; + tt_mutex_acquire(data->mutex, TtWaitForever); + tt_message_queue_reset(data->queue); + tt_message_queue_free(data->queue); + tt_mutex_release(data->mutex); + tt_mutex_free(data->mutex); + free(data); } void tt_dispatcher_dispatch(Dispatcher* dispatcher, Callback callback, void* context) { + DispatcherData* data = (DispatcherData*)dispatcher; DispatcherMessage message = { .callback = callback, .context = context }; - tt_mutex_acquire(dispatcher->mutex, TtWaitForever); - tt_message_queue_put(dispatcher->queue, &message, TtWaitForever); - tt_mutex_release(dispatcher->mutex); + tt_mutex_acquire(data->mutex, TtWaitForever); + tt_message_queue_put(data->queue, &message, TtWaitForever); + tt_mutex_release(data->mutex); } bool tt_dispatcher_consume(Dispatcher* dispatcher, uint32_t timeout_ticks) { - tt_mutex_acquire(dispatcher->mutex, TtWaitForever); - if (tt_message_queue_get(dispatcher->queue, &(dispatcher->buffer), timeout_ticks) == TtStatusOk) { - DispatcherMessage* message = &(dispatcher->buffer); + DispatcherData* data = (DispatcherData*)dispatcher; + tt_mutex_acquire(data->mutex, TtWaitForever); + if (tt_message_queue_get(data->queue, &(data->buffer), timeout_ticks) == TtStatusOk) { + DispatcherMessage* message = &(data->buffer); message->callback(message->context); - tt_mutex_release(dispatcher->mutex); + tt_mutex_release(data->mutex); return true; } else { - tt_mutex_release(dispatcher->mutex); + tt_mutex_release(data->mutex); return false; } } diff --git a/tactility-core/src/dispatcher.h b/tactility-core/src/dispatcher.h index 1c1f6318..31191e58 100644 --- a/tactility-core/src/dispatcher.h +++ b/tactility-core/src/dispatcher.h @@ -1,7 +1,7 @@ /** -* @file message_queue.h +* @file dispatcher.h * -* Dispatcher is a thread-safe message queue implementation for callbacks. +* Dispatcher is a thread-safe code execution queue. */ #pragma once @@ -15,21 +15,12 @@ extern "C" { typedef void (*Callback)(void* data); -typedef struct { - Callback callback; - void* context; -} DispatcherMessage; - -typedef struct { - MessageQueue* queue; - Mutex* mutex; - DispatcherMessage buffer; // Buffer for consuming a message -} Dispatcher; +typedef void Dispatcher; Dispatcher* tt_dispatcher_alloc(uint32_t message_count); void tt_dispatcher_free(Dispatcher* dispatcher); -void tt_dispatcher_dispatch(Dispatcher* dispatcher, Callback callback, void* context); -bool tt_dispatcher_consume(Dispatcher* dispatcher, uint32_t timeout_ticks); +void tt_dispatcher_dispatch(Dispatcher* data, Callback callback, void* context); +bool tt_dispatcher_consume(Dispatcher* data, uint32_t timeout_ticks); #ifdef __cplusplus } diff --git a/tactility-core/src/log.h b/tactility-core/src/log.h index 0deaa107..3f4714c0 100644 --- a/tactility-core/src/log.h +++ b/tactility-core/src/log.h @@ -1,6 +1,6 @@ #pragma once -#ifdef ESP_PLATFORM +#ifdef ESP_TARGET #include "esp_log.h" #else #include @@ -11,7 +11,7 @@ extern "C" { #endif -#ifdef ESP_PLATFORM +#ifdef ESP_TARGET #define TT_LOG_E(tag, format, ...) \ ESP_LOGE(tag, format, ##__VA_ARGS__) @@ -47,7 +47,7 @@ void tt_log(LogLevel level, const char* tag, const char* format, ...); #define TT_LOG_T(tag, format, ...) \ tt_log(LOG_LEVEL_TRACE, tag, format, ##__VA_ARGS__) -#endif +#endif // ESP_TARGET #ifdef __cplusplus } diff --git a/tactility-esp/CMakeLists.txt b/tactility-esp/CMakeLists.txt deleted file mode 100644 index c759af9e..00000000 --- a/tactility-esp/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -set(BOARD_COMPONENTS esp_wifi) - -file(GLOB_RECURSE SOURCE_FILES src/*.c) - -idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "src/" - REQUIRES esp_wifi nvs_flash spiffs -) - -set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/assets") -spiffs_create_partition_image(assets ${ASSETS_SRC_DIR} FLASH_IN_PROJECT) - -set(CONFIG_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/config") -spiffs_create_partition_image(config ${CONFIG_SRC_DIR} FLASH_IN_PROJECT) - -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) -target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility-core) - diff --git a/tactility-headless/CMakeLists.txt b/tactility-headless/CMakeLists.txt new file mode 100644 index 00000000..646ccd7e --- /dev/null +++ b/tactility-headless/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.16) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +if (DEFINED ENV{ESP_IDF_VERSION}) + file(GLOB_RECURSE SOURCE_FILES src/*.c) + + idf_component_register( + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "src/" + REQUIRES esp_wifi nvs_flash spiffs driver newlib + ) + + set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/assets") + spiffs_create_partition_image(assets ${ASSETS_SRC_DIR} FLASH_IN_PROJECT) + + set(CONFIG_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/config") + spiffs_create_partition_image(config ${CONFIG_SRC_DIR} FLASH_IN_PROJECT) + + target_link_libraries(${COMPONENT_LIB} + PUBLIC tactility-core + ) + + add_definitions(-DESP_PLATFORM) +else() + file(GLOB_RECURSE SOURCES "src/*.c") + file(GLOB_RECURSE HEADERS "src/*.h") + + add_library(tactility-headless OBJECT) + target_sources(tactility-headless + PRIVATE ${SOURCES} + PUBLIC ${HEADERS} + ) + + target_include_directories(tactility-headless + PRIVATE src/ + INTERFACE src/ + ) + + add_definitions(-D_Nullable=) + add_definitions(-D_Nonnull=) + target_link_libraries(tactility-headless + PUBLIC tactility-core + PUBLIC freertos_kernel + ) +endif() diff --git a/tactility/src/assets.h b/tactility-headless/src/assets.h similarity index 100% rename from tactility/src/assets.h rename to tactility-headless/src/assets.h diff --git a/tactility-esp/src/tactility_esp.c b/tactility-headless/src/esp_init.c similarity index 73% rename from tactility-esp/src/tactility_esp.c rename to tactility-headless/src/esp_init.c index 94c606b3..5a186aa6 100644 --- a/tactility-esp/src/tactility_esp.c +++ b/tactility-headless/src/esp_init.c @@ -1,14 +1,18 @@ #include "tactility_core.h" +#ifdef ESP_TARGET + +#include "esp_partitions.h" +#include "services/wifi/wifi_credentials.h" + #include "esp_event.h" #include "esp_netif.h" #include "nvs_flash.h" -#include "partitions.h" -#include "services/wifi/wifi_credentials.h" #define TAG "tactility" -void tt_esp_init() { - // Initialize NVS + +// Initialize NVS +static void tt_esp_nvs_init() { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { TT_LOG_I(TAG, "nvs erasing"); @@ -17,12 +21,20 @@ void tt_esp_init() { } ESP_ERROR_CHECK(ret); TT_LOG_I(TAG, "nvs initialized"); +} - // Network interface +static void tt_esp_network_init() { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); +} - tt_partitions_init(); +void tt_esp_init() { + tt_esp_nvs_init(); + tt_esp_partitions_init(); + + tt_esp_network_init(); tt_wifi_credentials_init(); } + +#endif \ No newline at end of file diff --git a/tactility-esp/src/tactility_esp.h b/tactility-headless/src/esp_init.h similarity index 66% rename from tactility-esp/src/tactility_esp.h rename to tactility-headless/src/esp_init.h index 52cbc8a1..2a7697c6 100644 --- a/tactility-esp/src/tactility_esp.h +++ b/tactility-headless/src/esp_init.h @@ -1,7 +1,6 @@ #pragma once -#include "hardware_config.h" -#include "tactility.h" +#ifdef ESP_TARGET #ifdef __cplusplus extern "C" { @@ -12,3 +11,5 @@ void tt_esp_init(); #ifdef __cplusplus } #endif + +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-esp/src/partitions.c b/tactility-headless/src/esp_partitions.c similarity index 94% rename from tactility-esp/src/partitions.c rename to tactility-headless/src/esp_partitions.c index ef3ecd2f..017d936f 100644 --- a/tactility-esp/src/partitions.c +++ b/tactility-headless/src/esp_partitions.c @@ -1,4 +1,6 @@ -#include "partitions.h" +#ifdef ESP_TARGET + +#include "esp_partitions.h" #include "esp_spiffs.h" #include "log.h" #include "nvs_flash.h" @@ -37,7 +39,7 @@ static esp_err_t spiffs_init(esp_vfs_spiffs_conf_t* conf) { return ESP_OK; } -esp_err_t tt_partitions_init() { +esp_err_t tt_esp_partitions_init() { ESP_ERROR_CHECK(nvs_flash_init_safely()); esp_vfs_spiffs_conf_t assets_spiffs = { @@ -64,3 +66,5 @@ esp_err_t tt_partitions_init() { return ESP_OK; } + +#endif // ESP_TARGET diff --git a/tactility-esp/src/partitions.h b/tactility-headless/src/esp_partitions.h similarity index 59% rename from tactility-esp/src/partitions.h rename to tactility-headless/src/esp_partitions.h index faeac64a..d3b259dd 100644 --- a/tactility-esp/src/partitions.h +++ b/tactility-headless/src/esp_partitions.h @@ -1,8 +1,12 @@ #pragma once +#ifdef ESP_TARGET + #include "esp_err.h" #define MOUNT_POINT_ASSETS "/assets" #define MOUNT_POINT_CONFIG "/config" -esp_err_t tt_partitions_init(); +esp_err_t tt_esp_partitions_init(); + +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-headless/src/hardware.c b/tactility-headless/src/hardware.c new file mode 100644 index 00000000..3b9b9311 --- /dev/null +++ b/tactility-headless/src/hardware.c @@ -0,0 +1,22 @@ +#include "hardware_i.h" + +#include "preferences.h" +#include "sdcard_i.h" + +#define TAG "hardware" + +void tt_hardware_init(const HardwareConfig* config) { + if (config->bootstrap != NULL) { + TT_LOG_I(TAG, "Bootstrapping"); + tt_check(config->bootstrap(), "bootstrap failed"); + } + + tt_sdcard_init(); + if (config->sdcard != NULL) { + TT_LOG_I(TAG, "Mounting sdcard"); + tt_sdcard_mount(config->sdcard); + } + + tt_check(config->init_graphics, "lvlg init not set"); + tt_check(config->init_graphics(), "lvgl init failed"); +} diff --git a/tactility/src/hardware_config.h b/tactility-headless/src/hardware_config.h similarity index 87% rename from tactility/src/hardware_config.h rename to tactility-headless/src/hardware_config.h index 0247c43a..c93dbe79 100644 --- a/tactility/src/hardware_config.h +++ b/tactility-headless/src/hardware_config.h @@ -4,8 +4,7 @@ #include "sdcard.h" typedef bool (*Bootstrap)(); -typedef bool (*InitLvgl)(); -typedef bool (*InitLvgl)(); +typedef bool (*InitGraphics)(); typedef void (*SetBacklightDuty)(uint8_t); typedef struct { @@ -24,10 +23,11 @@ typedef struct { * Initializes LVGL with all relevant hardware. * This includes the display and optional pointer devices (such as touch) or a keyboard. */ - const InitLvgl init_lvgl; + const InitGraphics init_graphics; /** * An interface for display features such as setting the backlight. + * This does nothing when a display isn't present. */ const Display display; diff --git a/tactility/src/hardware_i.h b/tactility-headless/src/hardware_i.h similarity index 100% rename from tactility/src/hardware_i.h rename to tactility-headless/src/hardware_i.h diff --git a/tactility/src/preferences.c b/tactility-headless/src/preferences.c similarity index 100% rename from tactility/src/preferences.c rename to tactility-headless/src/preferences.c diff --git a/tactility/src/preferences.h b/tactility-headless/src/preferences.h similarity index 100% rename from tactility/src/preferences.h rename to tactility-headless/src/preferences.h diff --git a/tactility/src/preferences_esp.c b/tactility-headless/src/preferences_esp.c similarity index 81% rename from tactility/src/preferences_esp.c rename to tactility-headless/src/preferences_esp.c index 140cc005..b9ef8de3 100644 --- a/tactility/src/preferences_esp.c +++ b/tactility-headless/src/preferences_esp.c @@ -4,6 +4,8 @@ #include "nvs_flash.h" #include "tactility_core.h" +#define TAG "preferences" + 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) { @@ -60,16 +62,24 @@ static bool has_string(const char* namespace, const char* key) { 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; + if (nvs_set_u8(handle, key, (uint8_t)value) != ESP_OK) { + TT_LOG_E(TAG, "failed to write %s:%s", namespace, key); + } nvs_close(handle); + } else { + TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace); } } 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; + if (nvs_set_i32(handle, key, value) != ESP_OK) { + TT_LOG_E(TAG, "failed to write %s:%s", namespace, key); + } nvs_close(handle); + } else { + TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace); } } @@ -78,6 +88,8 @@ static void put_string(const char* namespace, const char* key, const char* text) if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) { nvs_set_str(handle, key, text); nvs_close(handle); + } else { + TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace); } } diff --git a/tactility/src/preferences_memory.c b/tactility-headless/src/preferences_memory.c similarity index 100% rename from tactility/src/preferences_memory.c rename to tactility-headless/src/preferences_memory.c diff --git a/tactility/src/sdcard.c b/tactility-headless/src/sdcard.c similarity index 100% rename from tactility/src/sdcard.c rename to tactility-headless/src/sdcard.c diff --git a/tactility/src/sdcard.h b/tactility-headless/src/sdcard.h similarity index 100% rename from tactility/src/sdcard.h rename to tactility-headless/src/sdcard.h diff --git a/tactility/src/sdcard_i.h b/tactility-headless/src/sdcard_i.h similarity index 100% rename from tactility/src/sdcard_i.h rename to tactility-headless/src/sdcard_i.h diff --git a/tactility/src/service.c b/tactility-headless/src/service.c similarity index 100% rename from tactility/src/service.c rename to tactility-headless/src/service.c diff --git a/tactility/src/service.h b/tactility-headless/src/service.h similarity index 100% rename from tactility/src/service.h rename to tactility-headless/src/service.h diff --git a/tactility/src/service_i.h b/tactility-headless/src/service_i.h similarity index 100% rename from tactility/src/service_i.h rename to tactility-headless/src/service_i.h diff --git a/tactility/src/service_manifest.h b/tactility-headless/src/service_manifest.h similarity index 100% rename from tactility/src/service_manifest.h rename to tactility-headless/src/service_manifest.h diff --git a/tactility/src/service_registry.c b/tactility-headless/src/service_registry.c similarity index 100% rename from tactility/src/service_registry.c rename to tactility-headless/src/service_registry.c diff --git a/tactility/src/service_registry.h b/tactility-headless/src/service_registry.h similarity index 100% rename from tactility/src/service_registry.h rename to tactility-headless/src/service_registry.h diff --git a/tactility/src/services/sdcard/sdcard.c b/tactility-headless/src/services/sdcard/sdcard.c similarity index 76% rename from tactility/src/services/sdcard/sdcard.c rename to tactility-headless/src/services/sdcard/sdcard.c index a5d1fd03..9a364987 100644 --- a/tactility/src/services/sdcard/sdcard.c +++ b/tactility-headless/src/services/sdcard/sdcard.c @@ -1,11 +1,9 @@ #include -#include "assets.h" #include "mutex.h" #include "service.h" -#include "tactility.h" #include "tactility_core.h" -#include "ui/statusbar.h" +#include "tactility_headless.h" #define TAG "sdcard_service" @@ -15,7 +13,6 @@ typedef struct { Mutex* mutex; Thread* thread; SdcardState last_state; - int8_t statusbar_icon_id; bool interrupted; } ServiceData; @@ -30,7 +27,6 @@ static ServiceData* service_data_alloc() { data ), .last_state = -1, - .statusbar_icon_id = tt_statusbar_icon_add(NULL), .interrupted = false }; tt_thread_set_priority(data->thread, ThreadPriorityLow); @@ -39,7 +35,6 @@ static ServiceData* service_data_alloc() { static void service_data_free(ServiceData* data) { tt_mutex_free(data->mutex); - tt_statusbar_icon_remove(data->statusbar_icon_id); tt_thread_free(data->thread); } @@ -56,9 +51,6 @@ static int32_t sdcard_task(void* context) { bool interrupted = false; - // We set NULL as statusbar image by default, so it's hidden by default - tt_statusbar_icon_set_visibility(data->statusbar_icon_id, true); - do { service_data_lock(data); @@ -72,12 +64,6 @@ static int32_t sdcard_task(void* context) { } if (new_state != data->last_state) { - TT_LOG_I(TAG, "State change %d -> %d", data->last_state, new_state); - if (new_state == SdcardStateMounted) { - tt_statusbar_icon_set_image(data->statusbar_icon_id, TT_ASSETS_ICON_SDCARD); - } else { - tt_statusbar_icon_set_image(data->statusbar_icon_id, TT_ASSETS_ICON_SDCARD_ALERT); - } data->last_state = new_state; } @@ -89,7 +75,7 @@ static int32_t sdcard_task(void* context) { } static void on_start(Service service) { - if (tt_get_config()->hardware->sdcard != NULL) { + if (tt_get_hardware_config()->sdcard != NULL) { ServiceData* data = service_data_alloc(); tt_service_set_data(service, data); tt_thread_start(data->thread); diff --git a/tactility-headless/src/services/sdcard/sdcard.h b/tactility-headless/src/services/sdcard/sdcard.h new file mode 100644 index 00000000..af80ff83 --- /dev/null +++ b/tactility-headless/src/services/sdcard/sdcard.h @@ -0,0 +1,9 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tactility-esp/src/services/wifi/wifi.h b/tactility-headless/src/services/wifi/wifi.h similarity index 64% rename from tactility-esp/src/services/wifi/wifi.h rename to tactility-headless/src/services/wifi/wifi.h index 4d543685..4fef308b 100644 --- a/tactility-esp/src/services/wifi/wifi.h +++ b/tactility-headless/src/services/wifi/wifi.h @@ -10,6 +10,26 @@ extern "C" { #ifdef ESP_PLATFORM #include "esp_wifi.h" +#else +#include +// From esp_wifi_types.h in ESP-IDF 5.2 +typedef enum { + WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */ + WIFI_AUTH_WEP, /**< authenticate mode : WEP */ + WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */ + WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */ + WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */ + WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */ + WIFI_AUTH_WPA2_ENTERPRISE = WIFI_AUTH_ENTERPRISE, /**< authenticate mode : WiFi EAP security */ + WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */ + WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */ + WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */ + WIFI_AUTH_OWE, /**< authenticate mode : OWE */ + WIFI_AUTH_WPA3_ENT_192, /**< authenticate mode : WPA3_ENT_SUITE_B_192_BIT */ + WIFI_AUTH_WPA3_EXT_PSK, /**< authenticate mode : WPA3_PSK_EXT_KEY */ + WIFI_AUTH_WPA3_EXT_PSK_MIXED_MODE, /**< authenticate mode: WPA3_PSK + WPA3_PSK_EXT_KEY */ + WIFI_AUTH_MAX +} wifi_auth_mode_t; #endif typedef enum { @@ -100,12 +120,14 @@ void wifi_connect(const char* ssid, const char _Nullable password[64]); void wifi_disconnect(); /** - * Return the relevant icon asset from assets.h for the given inputs - * @param rssi the rssi value - * @param secured whether the access point is a secured one (as in: not an open one) - * @return + * Return true if the connection isn't unencrypted. */ -const char* wifi_get_status_icon_for_rssi(int rssi, bool secured); +bool wifi_is_connection_secure(); + +/** + * Returns the RSSI value (negative number) or return 1 when not connected + */ +int wifi_get_rssi(); #ifdef __cplusplus } diff --git a/tactility-esp/src/services/wifi/wifi_credentials.h b/tactility-headless/src/services/wifi/wifi_credentials.h similarity index 98% rename from tactility-esp/src/services/wifi/wifi_credentials.h rename to tactility-headless/src/services/wifi/wifi_credentials.h index dee09e73..133b1db6 100644 --- a/tactility-esp/src/services/wifi/wifi_credentials.h +++ b/tactility-headless/src/services/wifi/wifi_credentials.h @@ -22,4 +22,4 @@ bool tt_wifi_credentials_remove(const char* ssid); #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/tactility-esp/src/services/wifi/wifi_credentials.c b/tactility-headless/src/services/wifi/wifi_credentials_esp.c similarity index 99% rename from tactility-esp/src/services/wifi/wifi_credentials.c rename to tactility-headless/src/services/wifi/wifi_credentials_esp.c index 07be2fbe..333c1ba7 100644 --- a/tactility-esp/src/services/wifi/wifi_credentials.c +++ b/tactility-headless/src/services/wifi/wifi_credentials_esp.c @@ -1,3 +1,5 @@ +#ifdef ESP_TARGET + #include "wifi_credentials.h" #include "nvs_flash.h" @@ -230,3 +232,4 @@ bool tt_wifi_credentials_remove(const char* ssid) { // end region Wi-Fi Credentials - public +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-headless/src/services/wifi/wifi_credentials_mock.c b/tactility-headless/src/services/wifi/wifi_credentials_mock.c new file mode 100644 index 00000000..7d1b065e --- /dev/null +++ b/tactility-headless/src/services/wifi/wifi_credentials_mock.c @@ -0,0 +1,30 @@ +#ifndef ESP_TARGET + +#include "wifi_credentials.h" +#include "log.h" + +#define TAG "wifi_credentials_mock" + +static void hash_reset_all(); + +bool tt_wifi_credentials_contains(const char* ssid) { + return false; +} + +void tt_wifi_credentials_init() { + TT_LOG_I(TAG, "init"); +} + +bool tt_wifi_credentials_get(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) { + return false; +} + +bool tt_wifi_credentials_set(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) { + return false; +} + +bool tt_wifi_credentials_remove(const char* ssid) { + return false; +} + +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-esp/src/services/wifi/wifi.c b/tactility-headless/src/services/wifi/wifi_esp.c similarity index 91% rename from tactility-esp/src/services/wifi/wifi.c rename to tactility-headless/src/services/wifi/wifi_esp.c index 9ae4fe1c..a975a1db 100644 --- a/tactility-esp/src/services/wifi/wifi.c +++ b/tactility-headless/src/services/wifi/wifi_esp.c @@ -1,3 +1,5 @@ +#ifdef ESP_TARGET + #include "wifi.h" #include "assets.h" @@ -9,7 +11,6 @@ #include "mutex.h" #include "pubsub.h" #include "service.h" -#include "ui/statusbar.h" #include #define TAG "wifi" @@ -32,14 +33,12 @@ typedef struct { uint16_t scan_list_count; /** @brief Maximum amount of records to scan (value > 0) */ uint16_t scan_list_limit; - int8_t statusbar_icon_id; bool scan_active; bool secure_connection; esp_event_handler_instance_t event_handler_any_id; esp_event_handler_instance_t event_handler_got_ip; EventGroupHandle_t event_group; WifiRadioState radio_state; - const char* _Nullable last_statusbar_icon; } Wifi; typedef enum { @@ -89,14 +88,11 @@ static Wifi* wifi_alloc() { instance->event_handler_got_ip = NULL; instance->event_group = xEventGroupCreate(); instance->radio_state = WIFI_RADIO_OFF; - instance->statusbar_icon_id = tt_statusbar_icon_add(TT_ASSETS_ICON_WIFI_OFF); - instance->last_statusbar_icon = NULL; instance->secure_connection = false; return instance; } static void wifi_free(Wifi* instance) { - tt_statusbar_icon_remove(instance->statusbar_icon_id); tt_mutex_free(instance->mutex); tt_pubsub_free(instance->pubsub); tt_message_queue_free(instance->queue); @@ -188,10 +184,24 @@ void wifi_set_enabled(bool enabled) { } } +bool wifi_is_connection_secure() { + tt_check(wifi_singleton); + return wifi_singleton->secure_connection; +} + +int wifi_get_rssi() { + static int rssi = 0; + if (esp_wifi_sta_get_rssi(&rssi) == ESP_OK) { + return rssi; + } else { + return 1; + } +} + // endregion Public functions static void wifi_lock(Wifi* wifi) { - tt_crash("this fails for now"); + tt_crash("this fails for now"); // TODO: Fix tt_assert(wifi); tt_assert(wifi->mutex); tt_check(xSemaphoreTakeRecursive(wifi->mutex, portMAX_DELAY) == pdPASS); @@ -422,47 +432,6 @@ static void wifi_scan_internal(Wifi* wifi) { TT_LOG_I(TAG, "Finished scan"); } -const char* wifi_get_status_icon_for_rssi(int rssi, bool secured) { - if (rssi > -67) { - return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_4_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_4; - } else if (rssi > -70) { - return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_3_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_3; - } else if (rssi > -80) { - return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_2_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_2; - } else { - return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_1_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_1; - } -} - -static const char* wifi_get_status_icon(WifiRadioState state, bool secure) { - static int rssi = 0; - switch (state) { - case WIFI_RADIO_ON_PENDING: - case WIFI_RADIO_ON: - case WIFI_RADIO_OFF_PENDING: - case WIFI_RADIO_OFF: - return TT_ASSETS_ICON_WIFI_OFF; - case WIFI_RADIO_CONNECTION_PENDING: - return TT_ASSETS_ICON_WIFI_FIND; - case WIFI_RADIO_CONNECTION_ACTIVE: - if (esp_wifi_sta_get_rssi(&rssi) == ESP_OK) { - return wifi_get_status_icon_for_rssi(rssi, secure); - } else { - return secure ? TT_ASSETS_ICON_WIFI_SIGNAL_0_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_0; - } - default: - tt_crash_implementation("not implemented"); - } -} - -static void wifi_update_statusbar(Wifi* wifi) { - const char* icon = wifi_get_status_icon(wifi->radio_state, wifi->secure_connection); - if (icon != wifi->last_statusbar_icon) { - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, icon); - wifi->last_statusbar_icon = icon; - } -} - static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_message) { // TODO: only when connected! wifi_disconnect_internal(wifi); @@ -536,6 +505,7 @@ static void wifi_disconnect_internal(Wifi* wifi) { TT_LOG_E(TAG, "Failed to disconnect (%s)", esp_err_to_name(stop_result)); } else { wifi->radio_state = WIFI_RADIO_ON; + wifi->secure_connection = false; wifi_publish_event_simple(wifi, WifiEventTypeDisconnected); TT_LOG_I(TAG, "Disconnected"); } @@ -610,8 +580,6 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { break; } } - - wifi_update_statusbar(wifi); } } @@ -642,3 +610,4 @@ const ServiceManifest wifi_service = { .on_stop = &wifi_service_stop }; +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-headless/src/services/wifi/wifi_mock.c b/tactility-headless/src/services/wifi/wifi_mock.c new file mode 100644 index 00000000..34f73371 --- /dev/null +++ b/tactility-headless/src/services/wifi/wifi_mock.c @@ -0,0 +1,157 @@ +#include "wifi.h" + +#ifndef ESP_TARGET + +#include "assets.h" +#include "check.h" +#include "log.h" +#include "message_queue.h" +#include "mutex.h" +#include "pubsub.h" +#include "service.h" +#include + +#define TAG "wifi" +#define WIFI_SCAN_RECORD_LIMIT 16 // default, can be overridden +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +typedef struct { + /** @brief Locking mechanism for modifying the Wifi instance */ + Mutex* mutex; + /** @brief The public event bus */ + PubSub* pubsub; + /** @brief The internal message queue */ + MessageQueue* queue; + bool scan_active; + bool secure_connection; + WifiRadioState radio_state; +} Wifi; + + +static Wifi* wifi_singleton = NULL; + +// Forward declarations +static void wifi_lock(Wifi* wifi); +static void wifi_unlock(Wifi* wifi); + +// region Alloc + +static Wifi* wifi_alloc() { + Wifi* instance = malloc(sizeof(Wifi)); + instance->mutex = tt_mutex_alloc(MutexTypeRecursive); + instance->pubsub = tt_pubsub_alloc(); + instance->scan_active = false; + instance->radio_state = WIFI_RADIO_OFF; + instance->secure_connection = false; + return instance; +} + +static void wifi_free(Wifi* instance) { + tt_mutex_free(instance->mutex); + tt_pubsub_free(instance->pubsub); + tt_message_queue_free(instance->queue); + free(instance); +} + +// endregion Alloc + +// region Public functions + +PubSub* wifi_get_pubsub() { + tt_assert(wifi_singleton); + return wifi_singleton->pubsub; +} + +WifiRadioState wifi_get_radio_state() { + return wifi_singleton->radio_state; +} + +void wifi_scan() { + tt_assert(wifi_singleton); + wifi_singleton->scan_active = false; // TODO: enable and then later disable automatically +} + +bool wifi_is_scanning() { + tt_assert(wifi_singleton); + return wifi_singleton->scan_active; +} + +void wifi_connect(const char* ssid, const char _Nullable password[64]) { + tt_assert(wifi_singleton); + tt_check(strlen(ssid) <= 32); + // TODO: implement +} + +void wifi_disconnect() { + tt_assert(wifi_singleton); + // TODO: implement +} + +void wifi_set_scan_records(uint16_t records) { + tt_assert(wifi_singleton); + // TODO: implement +} + +void wifi_get_scan_results(WifiApRecord records[], uint16_t limit, uint16_t* result_count) { + tt_check(wifi_singleton); + tt_check(result_count); + + // TODO: implement + *result_count = 0; +} + +void wifi_set_enabled(bool enabled) { + tt_assert(wifi_singleton != NULL); + if (enabled) { + wifi_singleton->radio_state = WIFI_RADIO_CONNECTION_ACTIVE; + wifi_singleton->secure_connection = true; + } else { + wifi_singleton->radio_state = WIFI_RADIO_OFF; + } +} + +bool wifi_is_connection_secure() { + return wifi_singleton->secure_connection; +} + +int wifi_get_rssi() { + // TODO: implement + return -10; +} + +// endregion Public functions + +static void wifi_lock(Wifi* wifi) { + tt_crash("this fails for now"); + tt_assert(wifi); + tt_assert(wifi->mutex); + tt_mutex_acquire(wifi->mutex, 100); +} + +static void wifi_unlock(Wifi* wifi) { + tt_assert(wifi); + tt_assert(wifi->mutex); + tt_mutex_release(wifi->mutex); +} + + +static void wifi_service_start(TT_UNUSED Service service) { + tt_check(wifi_singleton == NULL); + wifi_singleton = wifi_alloc(); +} + +static void wifi_service_stop(TT_UNUSED Service service) { + tt_check(wifi_singleton != NULL); + + wifi_free(wifi_singleton); + wifi_singleton = NULL; +} + +const ServiceManifest wifi_service = { + .id = "wifi", + .on_start = &wifi_service_start, + .on_stop = &wifi_service_stop +}; + +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-headless/src/tactility_headless.c b/tactility-headless/src/tactility_headless.c new file mode 100644 index 00000000..aad9c2b3 --- /dev/null +++ b/tactility-headless/src/tactility_headless.c @@ -0,0 +1,16 @@ +#include "tactility_headless.h" +#include "hardware_config.h" +#include "hardware_i.h" +#include "service_registry.h" + +static const HardwareConfig* hardwareConfig = NULL; + +void tt_tactility_headless_init(const HardwareConfig* config, const ServiceManifest* const services[32]) { + tt_service_registry_init(); + tt_hardware_init(config); + hardwareConfig = config; +} + +const HardwareConfig* tt_get_hardware_config() { + return hardwareConfig; +} diff --git a/tactility-headless/src/tactility_headless.h b/tactility-headless/src/tactility_headless.h new file mode 100644 index 00000000..c53ec97d --- /dev/null +++ b/tactility-headless/src/tactility_headless.h @@ -0,0 +1,17 @@ +#pragma once + +#include "hardware_config.h" +#include "service_manifest.h" +#include "tactility_headless_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void tt_tactility_headless_init(const HardwareConfig* config, const ServiceManifest* const services[32]); + +const HardwareConfig* tt_get_hardware_config(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tactility-headless/src/tactility_headless_config.h b/tactility-headless/src/tactility_headless_config.h new file mode 100644 index 00000000..7b1dd854 --- /dev/null +++ b/tactility-headless/src/tactility_headless_config.h @@ -0,0 +1,3 @@ +#pragma once + +#define TT_CONFIG_SERVICES_LIMIT 32 \ No newline at end of file diff --git a/tactility/CMakeLists.txt b/tactility/CMakeLists.txt index 54cb8781..e206cf8b 100644 --- a/tactility/CMakeLists.txt +++ b/tactility/CMakeLists.txt @@ -3,35 +3,39 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -file(GLOB_RECURSE SOURCES "src/*.c") -file(GLOB_RECURSE HEADERS "src/*.h") - -add_library(tactility OBJECT) -target_sources(tactility - PRIVATE ${SOURCES} - PUBLIC ${HEADERS} -) -target_include_directories(tactility - PRIVATE src/ - INTERFACE src/ -) - if (DEFINED ENV{ESP_IDF_VERSION}) - add_definitions(-DESP_PLATFORM) - target_link_libraries(tactility - PUBLIC tactility-core - PUBLIC idf::lvgl # libs/ - PUBLIC idf::driver - PUBLIC idf::spiffs - PUBLIC idf::nvs_flash - PUBLIC idf::newlib # for scandir() and related + file(GLOB_RECURSE SOURCE_FILES src/*.c) + + idf_component_register( + SRCS ${SOURCE_FILES} + INCLUDE_DIRS "src/" + REQUIRES tactility-headless lvgl + ) + + target_link_libraries(${COMPONENT_LIB} PUBLIC lv_screenshot ) + + add_definitions(-DESP_PLATFORM) else() + file(GLOB_RECURSE SOURCES "src/*.c") + file(GLOB_RECURSE HEADERS "src/*.h") + + add_library(tactility OBJECT) + target_sources(tactility + PRIVATE ${SOURCES} + PUBLIC ${HEADERS} + ) + + target_include_directories(tactility + PRIVATE src/ + INTERFACE src/ + ) + add_definitions(-D_Nullable=) add_definitions(-D_Nonnull=) target_link_libraries(tactility - PUBLIC tactility-core + PUBLIC tactility-headless PUBLIC lvgl PUBLIC freertos_kernel PUBLIC lv_screenshot diff --git a/tactility-esp/src/apps/system/gpio/gpio.c b/tactility/src/apps/gpio/gpio.c similarity index 99% rename from tactility-esp/src/apps/system/gpio/gpio.c rename to tactility/src/apps/gpio/gpio.c index fce9f330..dbef9a73 100644 --- a/tactility-esp/src/apps/system/gpio/gpio.c +++ b/tactility/src/apps/gpio/gpio.c @@ -1,3 +1,5 @@ +#ifdef ESP_TARGET + #include "services/loader/loader.h" #include "ui/toolbar.h" #include "thread.h" @@ -203,3 +205,5 @@ const AppManifest gpio_app = { .on_show = &app_show, .on_hide = &on_hide }; + +#endif // ESP_TARGET \ No newline at end of file diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect.c b/tactility/src/apps/wifi_connect/wifi_connect.c similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect.c rename to tactility/src/apps/wifi_connect/wifi_connect.c diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect.h b/tactility/src/apps/wifi_connect/wifi_connect.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect.h rename to tactility/src/apps/wifi_connect/wifi_connect.h diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_bindings.h b/tactility/src/apps/wifi_connect/wifi_connect_bindings.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_bindings.h rename to tactility/src/apps/wifi_connect/wifi_connect_bindings.h diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_bundle.h b/tactility/src/apps/wifi_connect/wifi_connect_bundle.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_bundle.h rename to tactility/src/apps/wifi_connect/wifi_connect_bundle.h diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_state.h b/tactility/src/apps/wifi_connect/wifi_connect_state.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_state.h rename to tactility/src/apps/wifi_connect/wifi_connect_state.h diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_state_updating.c b/tactility/src/apps/wifi_connect/wifi_connect_state_updating.c similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_state_updating.c rename to tactility/src/apps/wifi_connect/wifi_connect_state_updating.c diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_state_updating.h b/tactility/src/apps/wifi_connect/wifi_connect_state_updating.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_state_updating.h rename to tactility/src/apps/wifi_connect/wifi_connect_state_updating.h diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c b/tactility/src/apps/wifi_connect/wifi_connect_view.c similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c rename to tactility/src/apps/wifi_connect/wifi_connect_view.c diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.h b/tactility/src/apps/wifi_connect/wifi_connect_view.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.h rename to tactility/src/apps/wifi_connect/wifi_connect_view.h diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage.c b/tactility/src/apps/wifi_manage/wifi_manage.c similarity index 98% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage.c rename to tactility/src/apps/wifi_manage/wifi_manage.c index 399b9249..e335cb2d 100644 --- a/tactility-esp/src/apps/system/wifi_manage/wifi_manage.c +++ b/tactility/src/apps/wifi_manage/wifi_manage.c @@ -1,7 +1,7 @@ #include "wifi_manage.h" #include "app.h" -#include "apps/system/wifi_connect/wifi_connect_bundle.h" +#include "apps/wifi_connect/wifi_connect_bundle.h" #include "services/loader/loader.h" #include "tactility_core.h" #include "ui/lvgl_sync.h" diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage.h b/tactility/src/apps/wifi_manage/wifi_manage.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage.h rename to tactility/src/apps/wifi_manage/wifi_manage.h diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_bindings.h b/tactility/src/apps/wifi_manage/wifi_manage_bindings.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_bindings.h rename to tactility/src/apps/wifi_manage/wifi_manage_bindings.h diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_state.h b/tactility/src/apps/wifi_manage/wifi_manage_state.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_state.h rename to tactility/src/apps/wifi_manage/wifi_manage_state.h diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_state_updating.c b/tactility/src/apps/wifi_manage/wifi_manage_state_updating.c similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_state_updating.c rename to tactility/src/apps/wifi_manage/wifi_manage_state_updating.c diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_state_updating.h b/tactility/src/apps/wifi_manage/wifi_manage_state_updating.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_state_updating.h rename to tactility/src/apps/wifi_manage/wifi_manage_state_updating.h diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c b/tactility/src/apps/wifi_manage/wifi_manage_view.c similarity index 99% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c rename to tactility/src/apps/wifi_manage/wifi_manage_view.c index 365f9d36..b921b533 100644 --- a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c +++ b/tactility/src/apps/wifi_manage/wifi_manage_view.c @@ -1,6 +1,7 @@ #include "wifi_manage_view.h" #include "log.h" +#include "services/statusbar_updater/statusbar_updater.h" #include "services/wifi/wifi.h" #include "ui/style.h" #include "ui/toolbar.h" diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.h b/tactility/src/apps/wifi_manage/wifi_manage_view.h similarity index 100% rename from tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.h rename to tactility/src/apps/wifi_manage/wifi_manage_view.h diff --git a/tactility/src/hardware.c b/tactility/src/lvgl_init.c similarity index 54% rename from tactility/src/hardware.c rename to tactility/src/lvgl_init.c index 8856df3f..f50ac0af 100644 --- a/tactility/src/hardware.c +++ b/tactility/src/lvgl_init.c @@ -1,12 +1,8 @@ -#include "hardware_i.h" - -#include "lvgl.h" +#include "lvgl_init_i.h" #include "preferences.h" -#include "sdcard_i.h" +#include "lvgl.h" -#define TAG "hardware" - -static void init_display_settings(const HardwareConfig* config) { +void tt_lvgl_init(const HardwareConfig* config) { SetBacklightDuty set_backlight_duty = config->display.set_backlight_duty; if (set_backlight_duty != NULL) { int32_t backlight_duty = 200; @@ -24,21 +20,3 @@ static void init_display_settings(const HardwareConfig* config) { } } } - -void tt_hardware_init(const HardwareConfig* config) { - if (config->bootstrap != NULL) { - TT_LOG_I(TAG, "Bootstrapping"); - tt_check(config->bootstrap(), "bootstrap failed"); - } - - tt_sdcard_init(); - if (config->sdcard != NULL) { - TT_LOG_I(TAG, "Mounting sdcard"); - tt_sdcard_mount(config->sdcard); - } - - tt_check(config->init_lvgl, "lvlg init not set"); - tt_check(config->init_lvgl(), "lvgl init failed"); - - init_display_settings(config); -} diff --git a/tactility/src/lvgl_init_i.h b/tactility/src/lvgl_init_i.h new file mode 100644 index 00000000..a7509690 --- /dev/null +++ b/tactility/src/lvgl_init_i.h @@ -0,0 +1,13 @@ +#pragma once + +#include "hardware_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void tt_lvgl_init(const HardwareConfig* config); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tactility/src/services/gui/gui.c b/tactility/src/services/gui/gui.c index 78fe28c4..1a951489 100644 --- a/tactility/src/services/gui/gui.c +++ b/tactility/src/services/gui/gui.c @@ -1,6 +1,7 @@ #include "gui_i.h" #include "tactility.h" +#include "services/loader/loader.h" #include "ui/lvgl_sync.h" #include "ui/lvgl_keypad.h" @@ -18,6 +19,19 @@ static int32_t gui_main(void*); Gui* gui = NULL; +typedef void (*PubSubCallback)(const void* message, void* context); +void gui_loader_callback(const void* message, void* context) { + Gui* gui = (Gui*)context; + LoaderEvent* event = (LoaderEvent*)message; + if (event->type == LoaderEventTypeApplicationShowing) { + App* app = event->app_showing.app; + AppManifest* app_manifest = tt_app_get_manifest(app); + gui_show_app(app, app_manifest->on_show, app_manifest->on_hide); + } else if (event->type == LoaderEventTypeApplicationHiding) { + gui_hide_app(); + } +} + Gui* gui_alloc() { Gui* instance = malloc(sizeof(Gui)); memset(instance, 0, sizeof(Gui)); @@ -30,7 +44,7 @@ Gui* gui_alloc() { ); instance->mutex = tt_mutex_alloc(MutexTypeRecursive); instance->keyboard = NULL; - + instance->loader_pubsub_subscription = tt_pubsub_subscribe(loader_get_pubsub(), &gui_loader_callback, instance); tt_check(tt_lvgl_lock(1000 / portTICK_PERIOD_MS)); instance->keyboard_group = lv_group_create(); instance->lvgl_parent = lv_scr_act(); diff --git a/tactility/src/services/gui/gui_i.h b/tactility/src/services/gui/gui_i.h index da9022ae..8abb95b8 100644 --- a/tactility/src/services/gui/gui_i.h +++ b/tactility/src/services/gui/gui_i.h @@ -18,6 +18,7 @@ struct Gui { // Thread and lock Thread* thread; Mutex* mutex; + PubSubSubscription* loader_pubsub_subscription; // Layers and Canvas lv_obj_t* lvgl_parent; diff --git a/tactility/src/services/loader/loader.c b/tactility/src/services/loader/loader.c index 6d3e4c24..f91e7580 100644 --- a/tactility/src/services/loader/loader.c +++ b/tactility/src/services/loader/loader.c @@ -17,6 +17,10 @@ #define TAG "loader" +typedef struct { + LoaderEventType type; +} LoaderEventInternal; + // Forward declarations static int32_t loader_main(void* p); @@ -25,7 +29,8 @@ static Loader* loader_singleton = NULL; static Loader* loader_alloc() { tt_check(loader_singleton == NULL); loader_singleton = malloc(sizeof(Loader)); - loader_singleton->pubsub = tt_pubsub_alloc(); + loader_singleton->pubsub_internal = tt_pubsub_alloc(); + loader_singleton->pubsub_external = tt_pubsub_alloc(); loader_singleton->queue = tt_message_queue_alloc(1, sizeof(LoaderMessage)); loader_singleton->thread = tt_thread_alloc_ex( "loader", @@ -42,7 +47,8 @@ static Loader* loader_alloc() { static void loader_free() { tt_check(loader_singleton != NULL); tt_thread_free(loader_singleton->thread); - tt_pubsub_free(loader_singleton->pubsub); + tt_pubsub_free(loader_singleton->pubsub_internal); + tt_pubsub_free(loader_singleton->pubsub_external); tt_message_queue_free(loader_singleton->queue); tt_mutex_free(loader_singleton->mutex); free(loader_singleton); @@ -104,7 +110,7 @@ PubSub* loader_get_pubsub() { // it's safe to return pubsub without locking // because it's never freed and loader is never exited // also the loader instance cannot be obtained until the pubsub is created - return loader_singleton->pubsub; + return loader_singleton->pubsub_external; } static const char* app_state_to_string(AppState state) { @@ -147,15 +153,23 @@ static void app_transition_to_state(App app, AppState state) { tt_app_set_state(app, AppStateStarted); break; case AppStateShowing: - gui_show_app( - app, - manifest->on_show, - manifest->on_hide - ); + LoaderEvent event_showing = { + .type = LoaderEventTypeApplicationShowing, + .app_showing = { + .app = app + } + }; + tt_pubsub_publish(loader_singleton->pubsub_external, &event_showing); tt_app_set_state(app, AppStateShowing); break; case AppStateHiding: - gui_hide_app(); + LoaderEvent event_hiding = { + .type = LoaderEventTypeApplicationHiding, + .app_hiding = { + .app = app + } + }; + tt_pubsub_publish(loader_singleton->pubsub_external, &event_hiding); tt_app_set_state(app, AppStateHiding); break; case AppStateStopped: @@ -200,8 +214,16 @@ LoaderStatus loader_do_start_app_with_manifest( loader_unlock(); - LoaderEvent event = {.type = LoaderEventTypeApplicationStarted}; - tt_pubsub_publish(loader_singleton->pubsub, &event); + LoaderEventInternal event_internal = {.type = LoaderEventTypeApplicationStarted}; + tt_pubsub_publish(loader_singleton->pubsub_internal, &event_internal); + + LoaderEvent event_external = { + .type = LoaderEventTypeApplicationStarted, + .app_started = { + .app = app + } + }; + tt_pubsub_publish(loader_singleton->pubsub_external, &event_external); return LoaderStatusOk; } @@ -240,6 +262,7 @@ static void loader_do_stop_app() { // Stop current app App app_to_stop = loader_singleton->app_stack[current_app_index]; + AppManifest* manifest = tt_app_get_manifest(app_to_stop); app_transition_to_state(app_to_stop, AppStateHiding); app_transition_to_state(app_to_stop, AppStateStopped); @@ -258,8 +281,16 @@ static void loader_do_stop_app() { loader_unlock(); - LoaderEvent event = {.type = LoaderEventTypeApplicationStopped}; - tt_pubsub_publish(loader_singleton->pubsub, &event); + LoaderEventInternal event_internal = {.type = LoaderEventTypeApplicationStopped}; + tt_pubsub_publish(loader_singleton->pubsub_internal, &event_internal); + + LoaderEvent event_external = { + .type = LoaderEventTypeApplicationStopped, + .app_stopped = { + .manifest = manifest + } + }; + tt_pubsub_publish(loader_singleton->pubsub_external, &event_external); } diff --git a/tactility/src/services/loader/loader.h b/tactility/src/services/loader/loader.h index 07312b74..2827a2d1 100644 --- a/tactility/src/services/loader/loader.h +++ b/tactility/src/services/loader/loader.h @@ -21,15 +21,39 @@ typedef enum { typedef enum { LoaderEventTypeApplicationStarted, + LoaderEventTypeApplicationShowing, + LoaderEventTypeApplicationHiding, LoaderEventTypeApplicationStopped } LoaderEventType; +typedef struct { + App* app; +} LoaderEventAppStarted; + +typedef struct { + App* app; +} LoaderEventAppShowing; + +typedef struct { + App* app; +} LoaderEventAppHiding; + +typedef struct { + AppManifest* manifest; +} LoaderEventAppStopped; + typedef struct { LoaderEventType type; + union { + LoaderEventAppStarted app_started; + LoaderEventAppShowing app_showing; + LoaderEventAppHiding app_hiding; + LoaderEventAppStopped app_stopped; + }; } LoaderEvent; /** - * @brief Close any running app, then start new one. Blocking. + * @brief Start an app * @param[in] id application name or id * @param[in] blocking application arguments * @param[in] bundle optional bundle. Ownership is transferred to Loader. @@ -37,13 +61,15 @@ typedef struct { */ LoaderStatus loader_start_app(const char* id, bool blocking, Bundle* _Nullable bundle); +/** + * @brief Stop the currently showing app. Show the previous app if any app was still running. + */ void loader_stop_app(); App _Nullable loader_get_current_app(); /** - * @brief Get loader pubsub - * @return PubSub* + * @brief PubSub for LoaderEvent */ PubSub* loader_get_pubsub(); diff --git a/tactility/src/services/loader/loader_i.h b/tactility/src/services/loader/loader_i.h index 785475c9..8def8e16 100644 --- a/tactility/src/services/loader/loader_i.h +++ b/tactility/src/services/loader/loader_i.h @@ -20,7 +20,8 @@ struct Loader { Thread* thread; - PubSub* pubsub; + PubSub* pubsub_internal; + PubSub* pubsub_external; MessageQueue* queue; Mutex* mutex; int8_t app_stack_index; diff --git a/tactility/src/services/statusbar_updater/statusbar_updater.c b/tactility/src/services/statusbar_updater/statusbar_updater.c new file mode 100644 index 00000000..5fa46f33 --- /dev/null +++ b/tactility/src/services/statusbar_updater/statusbar_updater.c @@ -0,0 +1,160 @@ +#include "mutex.h" +#include "service.h" +#include "ui/statusbar.h" + +#define TAG "wifi_statusbar_service" + +#include "assets.h" +#include "sdcard.h" +#include "services/wifi/wifi.h" + +typedef struct { + Mutex* mutex; + Thread* thread; + bool service_interrupted; + int8_t wifi_icon_id; + const char* wifi_last_icon; + int8_t sdcard_icon_id; + const char* sdcard_last_icon; +} ServiceData; + +const char* wifi_get_status_icon_for_rssi(int rssi, bool secured) { + if (rssi > 0) { + return TT_ASSETS_ICON_WIFI_CONNECTION_ISSUE; + } else if (rssi > -67) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_4_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_4; + } else if (rssi > -70) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_3_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_3; + } else if (rssi > -80) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_2_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_2; + } else { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_1_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_1; + } +} + +static const char* wifi_get_status_icon(WifiRadioState state, bool secure) { + int rssi; + switch (state) { + case WIFI_RADIO_ON_PENDING: + case WIFI_RADIO_ON: + case WIFI_RADIO_OFF_PENDING: + case WIFI_RADIO_OFF: + return TT_ASSETS_ICON_WIFI_OFF; + case WIFI_RADIO_CONNECTION_PENDING: + return TT_ASSETS_ICON_WIFI_FIND; + case WIFI_RADIO_CONNECTION_ACTIVE: + rssi = wifi_get_rssi(); + return wifi_get_status_icon_for_rssi(rssi, secure); + default: + tt_crash_implementation("not implemented"); + } +} + +static _Nullable const char* sdcard_get_status_icon(SdcardState state) { + switch (state) { + case SdcardStateMounted: + return TT_ASSETS_ICON_SDCARD; + case SdcardStateError: + case SdcardStateUnmounted: + return TT_ASSETS_ICON_SDCARD_ALERT; + default: + return NULL; + } +} + +static void update_wifi_icon(ServiceData* data) { + WifiRadioState radio_state = wifi_get_radio_state(); + bool is_secure = wifi_is_connection_secure(); + const char* desired_icon = wifi_get_status_icon(radio_state, is_secure); + if (data->wifi_last_icon != desired_icon) { + tt_statusbar_icon_set_image(data->wifi_icon_id, desired_icon); + data->wifi_last_icon = desired_icon; + } +} + +static void update_sdcard_icon(ServiceData* data) { + SdcardState state = tt_sdcard_get_state(); + const char* desired_icon = sdcard_get_status_icon(state); + if (data->sdcard_last_icon != desired_icon) { + tt_statusbar_icon_set_image(data->sdcard_icon_id, desired_icon); + tt_statusbar_icon_set_visibility(data->sdcard_icon_id, desired_icon != NULL); + data->sdcard_last_icon = desired_icon; + } +} + +static ServiceData* service_data_alloc() { + ServiceData* data = malloc(sizeof(ServiceData)); + *data = (ServiceData) { + .mutex = tt_mutex_alloc(MutexTypeNormal), + .thread = tt_thread_alloc(), + .service_interrupted = false, + .wifi_icon_id = tt_statusbar_icon_add(NULL), + .wifi_last_icon = NULL, + .sdcard_icon_id = tt_statusbar_icon_add(NULL), + .sdcard_last_icon = NULL, + }; + + tt_statusbar_icon_set_visibility(data->wifi_icon_id, true); + update_wifi_icon(data); + update_sdcard_icon(data); // also updates visibility + + return data; +} + +static void service_data_free(ServiceData* data) { + tt_mutex_free(data->mutex); + tt_thread_free(data->thread); + tt_statusbar_icon_remove(data->wifi_icon_id); + free(data); +} + +static void service_data_lock(ServiceData* data) { + tt_check(tt_mutex_acquire(data->mutex, TtWaitForever) == TtStatusOk); +} + +static void service_data_unlock(ServiceData* data) { + tt_check(tt_mutex_release(data->mutex) == TtStatusOk); +} + +int32_t service_main(TT_UNUSED void* parameter) { + TT_LOG_I(TAG, "Started main loop"); + ServiceData* data = (ServiceData*)parameter; + tt_check(data != NULL); + while (!data->service_interrupted) { + update_wifi_icon(data); + update_sdcard_icon(data); + tt_delay_ms(1000); + } + return 0; +} + +static void on_start(Service service) { + ServiceData* data = service_data_alloc(); + + tt_service_set_data(service, data); + + tt_thread_set_callback(data->thread, service_main); + tt_thread_set_current_priority(ThreadPriorityLow); + tt_thread_set_stack_size(data->thread, 2048); // 2048 was the minimum when last tested + tt_thread_set_context(data->thread, data); + tt_thread_start(data->thread); +} + +static void on_stop(Service service) { + ServiceData* data = tt_service_get_data(service); + + // Stop thread + service_data_lock(data); + data->service_interrupted = true; + service_data_unlock(data); + tt_mutex_release(data->mutex); + tt_thread_join(data->thread); + + service_data_free(data); +} + +const ServiceManifest statusbar_updater_service = { + .id = "statusbar_updater", + .on_start = &on_start, + .on_stop = &on_stop +}; diff --git a/tactility/src/services/statusbar_updater/statusbar_updater.h b/tactility/src/services/statusbar_updater/statusbar_updater.h new file mode 100644 index 00000000..3119e50d --- /dev/null +++ b/tactility/src/services/statusbar_updater/statusbar_updater.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return the relevant icon asset from assets.h for the given inputs + * @param rssi the rssi value + * @param secured whether the access point is a secured one (as in: not an open one) + * @return + */ +const char* wifi_get_status_icon_for_rssi(int rssi, bool secured); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tactility/src/tactility.c b/tactility/src/tactility.c index c1076f02..e1e10365 100644 --- a/tactility/src/tactility.c +++ b/tactility/src/tactility.c @@ -1,9 +1,11 @@ #include "tactility.h" #include "app_manifest_registry.h" -#include "hardware_i.h" +#include "esp_init.h" +#include "lvgl_init_i.h" #include "service_registry.h" #include "services/loader/loader.h" +#include "tactility_headless.h" #define TAG "tactility" @@ -15,14 +17,18 @@ extern const ServiceManifest gui_service; extern const ServiceManifest loader_service; extern const ServiceManifest screenshot_service; extern const ServiceManifest sdcard_service; +extern const ServiceManifest wifi_service; +extern const ServiceManifest statusbar_updater_service; static const ServiceManifest* const system_services[] = { - &gui_service, - &loader_service, // depends on gui service + &loader_service, + &gui_service, // depends on loader service #ifndef ESP_PLATFORM // Screenshots don't work yet on ESP32 &screenshot_service, #endif - &sdcard_service + &sdcard_service, + &wifi_service, + &statusbar_updater_service }; // endregion @@ -32,19 +38,28 @@ static const ServiceManifest* const system_services[] = { extern const AppManifest desktop_app; extern const AppManifest display_app; extern const AppManifest files_app; -extern const AppManifest screenshot_app; extern const AppManifest settings_app; extern const AppManifest system_info_app; +extern const AppManifest wifi_connect_app; +extern const AppManifest wifi_manage_app; + +#ifdef ESP_PLATFORM +extern const AppManifest screenshot_app; +extern const AppManifest gpio_app; +#endif static const AppManifest* const system_apps[] = { &desktop_app, &display_app, &files_app, -#ifndef ESP_PLATFORM // Screenshots don't work yet on ESP32 + &settings_app, + &system_info_app, + &wifi_connect_app, + &wifi_manage_app, +#ifdef ESP_PLATFORM // Screenshots don't work yet on ESP32 + &gpio_app, &screenshot_app, #endif - &settings_app, - &system_info_app }; // endregion @@ -96,13 +111,18 @@ static void register_and_start_user_services(const ServiceManifest* const servic void tt_init(const Config* config) { TT_LOG_I(TAG, "tt_init started"); +#ifdef ESP_PLATFORM + tt_esp_init(); +#endif + // Assign early so starting services can use it config_instance = config; - tt_service_registry_init(); - tt_app_manifest_registry_init(); + tt_tactility_headless_init(config->hardware, config->services); - tt_hardware_init(config->hardware); + tt_lvgl_init(config->hardware); + + tt_app_manifest_registry_init(); // Note: the order of starting apps and services is critical! // System services are registered first so the apps below can use them diff --git a/tactility/src/tactility_config.h b/tactility/src/tactility_config.h index 41780321..9fd1e7ae 100644 --- a/tactility/src/tactility_config.h +++ b/tactility/src/tactility_config.h @@ -1,6 +1,6 @@ #pragma once -#define TT_CONFIG_APPS_LIMIT 32 -#define TT_CONFIG_SERVICES_LIMIT 32 +#include "tactility_headless_config.h" +#define TT_CONFIG_APPS_LIMIT 32 #define TT_CONFIG_FORCE_ONSCREEN_KEYBOARD false \ No newline at end of file diff --git a/tactility/src/ui/statusbar.c b/tactility/src/ui/statusbar.c index 8f7015f5..016831db 100644 --- a/tactility/src/ui/statusbar.c +++ b/tactility/src/ui/statusbar.c @@ -25,7 +25,7 @@ typedef struct { static StatusbarData statusbar_data = { .mutex = NULL, - .icons = {0} + .icons = {} }; typedef struct {