Project restructuring: add tactility-headless (#55)
- Created `tactility-headless` to support ESP32 firmwares that don't require graphics - `tactility` subproject now contains both PC and ESP32 code (to avoid having to split up `tactility` and `tactility-headless` into separate projects, which would result in a very complex dependency tree) - `tactility` subproject is now defined as component for ESP32 and as regular module for PC - Improvements for dispatcher - Added `project-structure.puml` to docs - `Gui` service now depends on `Loader` service instead of the reverse - Added `statusbar_updater` service for updating Wi-Fi and SD card icons
This commit is contained in:
parent
b659d5b940
commit
27730260e0
@ -15,8 +15,9 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
set(COMPONENTS app-esp)
|
set(COMPONENTS app-esp)
|
||||||
set(EXTRA_COMPONENT_DIRS
|
set(EXTRA_COMPONENT_DIRS
|
||||||
"boards"
|
"boards"
|
||||||
"tactility-esp"
|
|
||||||
"app-esp"
|
"app-esp"
|
||||||
|
"tactility"
|
||||||
|
"tactility-headless"
|
||||||
"libs/esp_lvgl_port"
|
"libs/esp_lvgl_port"
|
||||||
"libs/lvgl"
|
"libs/lvgl"
|
||||||
"libs/M5Unified"
|
"libs/M5Unified"
|
||||||
@ -40,7 +41,12 @@ endif()
|
|||||||
|
|
||||||
project(tactility-root)
|
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(tactility-core)
|
||||||
|
|
||||||
add_subdirectory(libs/mlib)
|
add_subdirectory(libs/mlib)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
set(BOARD_COMPONENTS tactility-esp)
|
set(BOARD_COMPONENTS tactility)
|
||||||
|
|
||||||
if("${IDF_TARGET}" STREQUAL "esp32")
|
if("${IDF_TARGET}" STREQUAL "esp32")
|
||||||
list(APPEND BOARD_COMPONENTS
|
list(APPEND BOARD_COMPONENTS
|
||||||
@ -22,7 +22,3 @@ idf_component_register(
|
|||||||
"src/hello_world"
|
"src/hello_world"
|
||||||
REQUIRES ${BOARD_COMPONENTS}
|
REQUIRES ${BOARD_COMPONENTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO Remove?
|
|
||||||
target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility)
|
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,11 @@
|
|||||||
#include "board_config.h"
|
#include "board_config.h"
|
||||||
#include "tactility_esp.h"
|
|
||||||
|
|
||||||
// Apps
|
// Apps
|
||||||
#include "hello_world/hello_world.h"
|
#include "hello_world/hello_world.h"
|
||||||
|
#include "tactility.h"
|
||||||
|
|
||||||
extern void wifi_main(void*);
|
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) {
|
void app_main(void) {
|
||||||
static const Config config = {
|
static const Config config = {
|
||||||
/**
|
/**
|
||||||
@ -19,19 +14,12 @@ void app_main(void) {
|
|||||||
*/
|
*/
|
||||||
.hardware = TT_BOARD_HARDWARE,
|
.hardware = TT_BOARD_HARDWARE,
|
||||||
.apps = {
|
.apps = {
|
||||||
&gpio_app,
|
|
||||||
&hello_world_app,
|
&hello_world_app,
|
||||||
&wifi_connect_app,
|
|
||||||
&wifi_manage_app
|
|
||||||
},
|
|
||||||
.services = {
|
|
||||||
&wifi_service
|
|
||||||
},
|
},
|
||||||
|
.services = {},
|
||||||
.auto_start_app_id = NULL
|
.auto_start_app_id = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
tt_esp_init();
|
|
||||||
|
|
||||||
tt_init(&config);
|
tt_init(&config);
|
||||||
|
|
||||||
wifi_main(NULL);
|
wifi_main(NULL);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ add_executable(app-sim ${SOURCES})
|
|||||||
target_link_libraries(app-sim
|
target_link_libraries(app-sim
|
||||||
PRIVATE tactility
|
PRIVATE tactility
|
||||||
PRIVATE tactility-core
|
PRIVATE tactility-core
|
||||||
|
PRIVATE tactility-headless
|
||||||
PRIVATE lvgl
|
PRIVATE lvgl
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -24,5 +24,5 @@ TT_UNUSED static void lvgl_deinit() {
|
|||||||
|
|
||||||
HardwareConfig sim_hardware = {
|
HardwareConfig sim_hardware = {
|
||||||
.bootstrap = NULL,
|
.bootstrap = NULL,
|
||||||
.init_lvgl = &lvgl_init,
|
.init_graphics = &lvgl_init,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,11 +1,5 @@
|
|||||||
#include "hello_world/hello_world.h"
|
#include "hello_world/hello_world.h"
|
||||||
#include "tactility.h"
|
#include "tactility.h"
|
||||||
#include "assets.h"
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "ui/statusbar.h"
|
|
||||||
|
|
||||||
#define TAG "main"
|
|
||||||
|
|
||||||
extern HardwareConfig sim_hardware;
|
extern HardwareConfig sim_hardware;
|
||||||
|
|
||||||
@ -20,9 +14,4 @@ void app_main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
tt_init(&config);
|
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRC_DIRS "."
|
SRC_DIRS "."
|
||||||
INCLUDE_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)
|
|
||||||
@ -12,6 +12,6 @@ const HardwareConfig lilygo_tdeck = {
|
|||||||
.display = {
|
.display = {
|
||||||
.set_backlight_duty = &tdeck_backlight_set
|
.set_backlight_duty = &tdeck_backlight_set
|
||||||
},
|
},
|
||||||
.init_lvgl = &tdeck_init_lvgl,
|
.init_graphics = &tdeck_init_lvgl,
|
||||||
.sdcard = &tdeck_sdcard
|
.sdcard = &tdeck_sdcard
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,5 @@ idf_component_register(
|
|||||||
SRC_DIRS "source"
|
SRC_DIRS "source"
|
||||||
INCLUDE_DIRS "include"
|
INCLUDE_DIRS "include"
|
||||||
PRIV_INCLUDE_DIRS "private"
|
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)
|
|
||||||
|
|||||||
@ -9,6 +9,6 @@ const HardwareConfig m5stack_core2 = {
|
|||||||
.display = {
|
.display = {
|
||||||
.set_backlight_duty = NULL
|
.set_backlight_duty = NULL
|
||||||
},
|
},
|
||||||
.init_lvgl = &core2_lvgl_init,
|
.init_graphics = &core2_lvgl_init,
|
||||||
.sdcard = &core2_sdcard
|
.sdcard = &core2_sdcard
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRC_DIRS "."
|
SRC_DIRS "."
|
||||||
INCLUDE_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)
|
|
||||||
@ -9,5 +9,5 @@ const HardwareConfig waveshare_s3_touch = {
|
|||||||
.display = {
|
.display = {
|
||||||
.set_backlight_duty = NULL // TODO: This requires implementing the CH422G IO expander
|
.set_backlight_duty = NULL // TODO: This requires implementing the CH422G IO expander
|
||||||
},
|
},
|
||||||
.init_lvgl = &ws3t_init_lvgl
|
.init_graphics = &ws3t_init_lvgl
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRC_DIRS "."
|
SRC_DIRS "."
|
||||||
INCLUDE_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)
|
|
||||||
@ -11,6 +11,6 @@ const HardwareConfig yellow_board_24inch_cap = {
|
|||||||
.display = {
|
.display = {
|
||||||
.set_backlight_duty = &twodotfour_backlight_set
|
.set_backlight_duty = &twodotfour_backlight_set
|
||||||
},
|
},
|
||||||
.init_lvgl = &twodotfour_lvgl_init,
|
.init_graphics = &twodotfour_lvgl_init,
|
||||||
.sdcard = &twodotfour_sdcard
|
.sdcard = &twodotfour_sdcard
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
- 2 wire speaker support
|
- 2 wire speaker support
|
||||||
- tt_app_start() and similar functions as proxies for Loader app start/stop/etc.
|
- 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)
|
- 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
|
# App Improvement Ideas
|
||||||
- Sort desktop apps by name.
|
- Sort desktop apps by name.
|
||||||
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
# App Ideas
|
# App Ideas
|
||||||
- File viewer (images, text... binary?)
|
- File viewer (images, text... binary?)
|
||||||
- GPIO status viewer
|
|
||||||
- BlueTooth keyboard app
|
- BlueTooth keyboard app
|
||||||
- Chip 8 emulator
|
- Chip 8 emulator
|
||||||
- BadUSB
|
- BadUSB
|
||||||
|
|||||||
23
docs/project-structure.puml
Normal file
23
docs/project-structure.puml
Normal file
@ -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
|
||||||
@ -8,6 +8,7 @@ file(GLOB SOURCES "src/*.c")
|
|||||||
file(GLOB HEADERS "src/*.h")
|
file(GLOB HEADERS "src/*.h")
|
||||||
|
|
||||||
add_library(tactility-core OBJECT)
|
add_library(tactility-core OBJECT)
|
||||||
|
|
||||||
target_sources(tactility-core
|
target_sources(tactility-core
|
||||||
PRIVATE ${SOURCES}
|
PRIVATE ${SOURCES}
|
||||||
PUBLIC ${HEADERS}
|
PUBLIC ${HEADERS}
|
||||||
|
|||||||
@ -2,9 +2,20 @@
|
|||||||
|
|
||||||
#include "tactility_core.h"
|
#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* tt_dispatcher_alloc(uint32_t message_count) {
|
||||||
Dispatcher* dispatcher = malloc(sizeof(Dispatcher));
|
DispatcherData* data = malloc(sizeof(DispatcherData));
|
||||||
*dispatcher = (Dispatcher) {
|
*data = (DispatcherData) {
|
||||||
.queue = tt_message_queue_alloc(message_count, sizeof(DispatcherMessage)),
|
.queue = tt_message_queue_alloc(message_count, sizeof(DispatcherMessage)),
|
||||||
.mutex = tt_mutex_alloc(MutexTypeNormal),
|
.mutex = tt_mutex_alloc(MutexTypeNormal),
|
||||||
.buffer = {
|
.buffer = {
|
||||||
@ -12,37 +23,40 @@ Dispatcher* tt_dispatcher_alloc(uint32_t message_count) {
|
|||||||
.context = NULL
|
.context = NULL
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return dispatcher;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_dispatcher_free(Dispatcher* dispatcher) {
|
void tt_dispatcher_free(Dispatcher* dispatcher) {
|
||||||
tt_mutex_acquire(dispatcher->mutex, TtWaitForever);
|
DispatcherData* data = (DispatcherData*)dispatcher;
|
||||||
tt_message_queue_reset(dispatcher->queue);
|
tt_mutex_acquire(data->mutex, TtWaitForever);
|
||||||
tt_message_queue_free(dispatcher->queue);
|
tt_message_queue_reset(data->queue);
|
||||||
tt_mutex_release(dispatcher->mutex);
|
tt_message_queue_free(data->queue);
|
||||||
tt_mutex_free(dispatcher->mutex);
|
tt_mutex_release(data->mutex);
|
||||||
free(dispatcher);
|
tt_mutex_free(data->mutex);
|
||||||
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tt_dispatcher_dispatch(Dispatcher* dispatcher, Callback callback, void* context) {
|
void tt_dispatcher_dispatch(Dispatcher* dispatcher, Callback callback, void* context) {
|
||||||
|
DispatcherData* data = (DispatcherData*)dispatcher;
|
||||||
DispatcherMessage message = {
|
DispatcherMessage message = {
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.context = context
|
.context = context
|
||||||
};
|
};
|
||||||
tt_mutex_acquire(dispatcher->mutex, TtWaitForever);
|
tt_mutex_acquire(data->mutex, TtWaitForever);
|
||||||
tt_message_queue_put(dispatcher->queue, &message, TtWaitForever);
|
tt_message_queue_put(data->queue, &message, TtWaitForever);
|
||||||
tt_mutex_release(dispatcher->mutex);
|
tt_mutex_release(data->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tt_dispatcher_consume(Dispatcher* dispatcher, uint32_t timeout_ticks) {
|
bool tt_dispatcher_consume(Dispatcher* dispatcher, uint32_t timeout_ticks) {
|
||||||
tt_mutex_acquire(dispatcher->mutex, TtWaitForever);
|
DispatcherData* data = (DispatcherData*)dispatcher;
|
||||||
if (tt_message_queue_get(dispatcher->queue, &(dispatcher->buffer), timeout_ticks) == TtStatusOk) {
|
tt_mutex_acquire(data->mutex, TtWaitForever);
|
||||||
DispatcherMessage* message = &(dispatcher->buffer);
|
if (tt_message_queue_get(data->queue, &(data->buffer), timeout_ticks) == TtStatusOk) {
|
||||||
|
DispatcherMessage* message = &(data->buffer);
|
||||||
message->callback(message->context);
|
message->callback(message->context);
|
||||||
tt_mutex_release(dispatcher->mutex);
|
tt_mutex_release(data->mutex);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
tt_mutex_release(dispatcher->mutex);
|
tt_mutex_release(data->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
#pragma once
|
||||||
|
|
||||||
@ -15,21 +15,12 @@ extern "C" {
|
|||||||
|
|
||||||
typedef void (*Callback)(void* data);
|
typedef void (*Callback)(void* data);
|
||||||
|
|
||||||
typedef struct {
|
typedef void Dispatcher;
|
||||||
Callback callback;
|
|
||||||
void* context;
|
|
||||||
} DispatcherMessage;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
MessageQueue* queue;
|
|
||||||
Mutex* mutex;
|
|
||||||
DispatcherMessage buffer; // Buffer for consuming a message
|
|
||||||
} Dispatcher;
|
|
||||||
|
|
||||||
Dispatcher* tt_dispatcher_alloc(uint32_t message_count);
|
Dispatcher* tt_dispatcher_alloc(uint32_t message_count);
|
||||||
void tt_dispatcher_free(Dispatcher* dispatcher);
|
void tt_dispatcher_free(Dispatcher* dispatcher);
|
||||||
void tt_dispatcher_dispatch(Dispatcher* dispatcher, Callback callback, void* context);
|
void tt_dispatcher_dispatch(Dispatcher* data, Callback callback, void* context);
|
||||||
bool tt_dispatcher_consume(Dispatcher* dispatcher, uint32_t timeout_ticks);
|
bool tt_dispatcher_consume(Dispatcher* data, uint32_t timeout_ticks);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_TARGET
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#else
|
#else
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#define TT_LOG_E(tag, format, ...) \
|
#define TT_LOG_E(tag, format, ...) \
|
||||||
ESP_LOGE(tag, format, ##__VA_ARGS__)
|
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, ...) \
|
#define TT_LOG_T(tag, format, ...) \
|
||||||
tt_log(LOG_LEVEL_TRACE, tag, format, ##__VA_ARGS__)
|
tt_log(LOG_LEVEL_TRACE, tag, format, ##__VA_ARGS__)
|
||||||
|
|
||||||
#endif
|
#endif // ESP_TARGET
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
|
||||||
|
|
||||||
48
tactility-headless/CMakeLists.txt
Normal file
48
tactility-headless/CMakeLists.txt
Normal file
@ -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()
|
||||||
@ -1,14 +1,18 @@
|
|||||||
#include "tactility_core.h"
|
#include "tactility_core.h"
|
||||||
|
|
||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
|
#include "esp_partitions.h"
|
||||||
|
#include "services/wifi/wifi_credentials.h"
|
||||||
|
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "esp_netif.h"
|
#include "esp_netif.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "partitions.h"
|
|
||||||
#include "services/wifi/wifi_credentials.h"
|
|
||||||
|
|
||||||
#define TAG "tactility"
|
#define TAG "tactility"
|
||||||
void tt_esp_init() {
|
|
||||||
// Initialize NVS
|
// Initialize NVS
|
||||||
|
static void tt_esp_nvs_init() {
|
||||||
esp_err_t ret = nvs_flash_init();
|
esp_err_t ret = nvs_flash_init();
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
TT_LOG_I(TAG, "nvs erasing");
|
TT_LOG_I(TAG, "nvs erasing");
|
||||||
@ -17,12 +21,20 @@ void tt_esp_init() {
|
|||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
TT_LOG_I(TAG, "nvs initialized");
|
TT_LOG_I(TAG, "nvs initialized");
|
||||||
|
}
|
||||||
|
|
||||||
// Network interface
|
static void tt_esp_network_init() {
|
||||||
ESP_ERROR_CHECK(esp_netif_init());
|
ESP_ERROR_CHECK(esp_netif_init());
|
||||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
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();
|
tt_wifi_credentials_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hardware_config.h"
|
#ifdef ESP_TARGET
|
||||||
#include "tactility.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -12,3 +11,5 @@ void tt_esp_init();
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
@ -1,4 +1,6 @@
|
|||||||
#include "partitions.h"
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
|
#include "esp_partitions.h"
|
||||||
#include "esp_spiffs.h"
|
#include "esp_spiffs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
@ -37,7 +39,7 @@ static esp_err_t spiffs_init(esp_vfs_spiffs_conf_t* conf) {
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t tt_partitions_init() {
|
esp_err_t tt_esp_partitions_init() {
|
||||||
ESP_ERROR_CHECK(nvs_flash_init_safely());
|
ESP_ERROR_CHECK(nvs_flash_init_safely());
|
||||||
|
|
||||||
esp_vfs_spiffs_conf_t assets_spiffs = {
|
esp_vfs_spiffs_conf_t assets_spiffs = {
|
||||||
@ -64,3 +66,5 @@ esp_err_t tt_partitions_init() {
|
|||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
@ -1,8 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
|
||||||
#define MOUNT_POINT_ASSETS "/assets"
|
#define MOUNT_POINT_ASSETS "/assets"
|
||||||
#define MOUNT_POINT_CONFIG "/config"
|
#define MOUNT_POINT_CONFIG "/config"
|
||||||
|
|
||||||
esp_err_t tt_partitions_init();
|
esp_err_t tt_esp_partitions_init();
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
22
tactility-headless/src/hardware.c
Normal file
22
tactility-headless/src/hardware.c
Normal file
@ -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");
|
||||||
|
}
|
||||||
@ -4,8 +4,7 @@
|
|||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
|
|
||||||
typedef bool (*Bootstrap)();
|
typedef bool (*Bootstrap)();
|
||||||
typedef bool (*InitLvgl)();
|
typedef bool (*InitGraphics)();
|
||||||
typedef bool (*InitLvgl)();
|
|
||||||
|
|
||||||
typedef void (*SetBacklightDuty)(uint8_t);
|
typedef void (*SetBacklightDuty)(uint8_t);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -24,10 +23,11 @@ typedef struct {
|
|||||||
* Initializes LVGL with all relevant hardware.
|
* Initializes LVGL with all relevant hardware.
|
||||||
* This includes the display and optional pointer devices (such as touch) or a keyboard.
|
* 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.
|
* An interface for display features such as setting the backlight.
|
||||||
|
* This does nothing when a display isn't present.
|
||||||
*/
|
*/
|
||||||
const Display display;
|
const Display display;
|
||||||
|
|
||||||
@ -4,6 +4,8 @@
|
|||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "tactility_core.h"
|
#include "tactility_core.h"
|
||||||
|
|
||||||
|
#define TAG "preferences"
|
||||||
|
|
||||||
static bool opt_bool(const char* namespace, const char* key, bool* out) {
|
static bool opt_bool(const char* namespace, const char* key, bool* out) {
|
||||||
nvs_handle_t handle;
|
nvs_handle_t handle;
|
||||||
if (nvs_open(namespace, NVS_READWRITE, &handle) != ESP_OK) {
|
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) {
|
static void put_bool(const char* namespace, const char* key, bool value) {
|
||||||
nvs_handle_t handle;
|
nvs_handle_t handle;
|
||||||
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
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);
|
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) {
|
static void put_int32(const char* namespace, const char* key, int32_t value) {
|
||||||
nvs_handle_t handle;
|
nvs_handle_t handle;
|
||||||
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
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);
|
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) {
|
if (nvs_open(namespace, NVS_READWRITE, &handle) == ESP_OK) {
|
||||||
nvs_set_str(handle, key, text);
|
nvs_set_str(handle, key, text);
|
||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
|
} else {
|
||||||
|
TT_LOG_E(TAG, "failed to open namespace %s for writing", namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,11 +1,9 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "assets.h"
|
|
||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "tactility.h"
|
|
||||||
#include "tactility_core.h"
|
#include "tactility_core.h"
|
||||||
#include "ui/statusbar.h"
|
#include "tactility_headless.h"
|
||||||
|
|
||||||
#define TAG "sdcard_service"
|
#define TAG "sdcard_service"
|
||||||
|
|
||||||
@ -15,7 +13,6 @@ typedef struct {
|
|||||||
Mutex* mutex;
|
Mutex* mutex;
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
SdcardState last_state;
|
SdcardState last_state;
|
||||||
int8_t statusbar_icon_id;
|
|
||||||
bool interrupted;
|
bool interrupted;
|
||||||
} ServiceData;
|
} ServiceData;
|
||||||
|
|
||||||
@ -30,7 +27,6 @@ static ServiceData* service_data_alloc() {
|
|||||||
data
|
data
|
||||||
),
|
),
|
||||||
.last_state = -1,
|
.last_state = -1,
|
||||||
.statusbar_icon_id = tt_statusbar_icon_add(NULL),
|
|
||||||
.interrupted = false
|
.interrupted = false
|
||||||
};
|
};
|
||||||
tt_thread_set_priority(data->thread, ThreadPriorityLow);
|
tt_thread_set_priority(data->thread, ThreadPriorityLow);
|
||||||
@ -39,7 +35,6 @@ static ServiceData* service_data_alloc() {
|
|||||||
|
|
||||||
static void service_data_free(ServiceData* data) {
|
static void service_data_free(ServiceData* data) {
|
||||||
tt_mutex_free(data->mutex);
|
tt_mutex_free(data->mutex);
|
||||||
tt_statusbar_icon_remove(data->statusbar_icon_id);
|
|
||||||
tt_thread_free(data->thread);
|
tt_thread_free(data->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +51,6 @@ static int32_t sdcard_task(void* context) {
|
|||||||
|
|
||||||
bool interrupted = false;
|
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 {
|
do {
|
||||||
service_data_lock(data);
|
service_data_lock(data);
|
||||||
|
|
||||||
@ -72,12 +64,6 @@ static int32_t sdcard_task(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_state != data->last_state) {
|
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;
|
data->last_state = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +75,7 @@ static int32_t sdcard_task(void* context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void on_start(Service service) {
|
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();
|
ServiceData* data = service_data_alloc();
|
||||||
tt_service_set_data(service, data);
|
tt_service_set_data(service, data);
|
||||||
tt_thread_start(data->thread);
|
tt_thread_start(data->thread);
|
||||||
9
tactility-headless/src/services/sdcard/sdcard.h
Normal file
9
tactility-headless/src/services/sdcard/sdcard.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -10,6 +10,26 @@ extern "C" {
|
|||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
// 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
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -100,12 +120,14 @@ void wifi_connect(const char* ssid, const char _Nullable password[64]);
|
|||||||
void wifi_disconnect();
|
void wifi_disconnect();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the relevant icon asset from assets.h for the given inputs
|
* Return true if the connection isn't unencrypted.
|
||||||
* @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);
|
bool wifi_is_connection_secure();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the RSSI value (negative number) or return 1 when not connected
|
||||||
|
*/
|
||||||
|
int wifi_get_rssi();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include "wifi_credentials.h"
|
#include "wifi_credentials.h"
|
||||||
|
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
@ -230,3 +232,4 @@ bool tt_wifi_credentials_remove(const char* ssid) {
|
|||||||
|
|
||||||
// end region Wi-Fi Credentials - public
|
// end region Wi-Fi Credentials - public
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
30
tactility-headless/src/services/wifi/wifi_credentials_mock.c
Normal file
30
tactility-headless/src/services/wifi/wifi_credentials_mock.c
Normal file
@ -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
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
|
|
||||||
#include "assets.h"
|
#include "assets.h"
|
||||||
@ -9,7 +11,6 @@
|
|||||||
#include "mutex.h"
|
#include "mutex.h"
|
||||||
#include "pubsub.h"
|
#include "pubsub.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "ui/statusbar.h"
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#define TAG "wifi"
|
#define TAG "wifi"
|
||||||
@ -32,14 +33,12 @@ typedef struct {
|
|||||||
uint16_t scan_list_count;
|
uint16_t scan_list_count;
|
||||||
/** @brief Maximum amount of records to scan (value > 0) */
|
/** @brief Maximum amount of records to scan (value > 0) */
|
||||||
uint16_t scan_list_limit;
|
uint16_t scan_list_limit;
|
||||||
int8_t statusbar_icon_id;
|
|
||||||
bool scan_active;
|
bool scan_active;
|
||||||
bool secure_connection;
|
bool secure_connection;
|
||||||
esp_event_handler_instance_t event_handler_any_id;
|
esp_event_handler_instance_t event_handler_any_id;
|
||||||
esp_event_handler_instance_t event_handler_got_ip;
|
esp_event_handler_instance_t event_handler_got_ip;
|
||||||
EventGroupHandle_t event_group;
|
EventGroupHandle_t event_group;
|
||||||
WifiRadioState radio_state;
|
WifiRadioState radio_state;
|
||||||
const char* _Nullable last_statusbar_icon;
|
|
||||||
} Wifi;
|
} Wifi;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -89,14 +88,11 @@ static Wifi* wifi_alloc() {
|
|||||||
instance->event_handler_got_ip = NULL;
|
instance->event_handler_got_ip = NULL;
|
||||||
instance->event_group = xEventGroupCreate();
|
instance->event_group = xEventGroupCreate();
|
||||||
instance->radio_state = WIFI_RADIO_OFF;
|
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;
|
instance->secure_connection = false;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wifi_free(Wifi* instance) {
|
static void wifi_free(Wifi* instance) {
|
||||||
tt_statusbar_icon_remove(instance->statusbar_icon_id);
|
|
||||||
tt_mutex_free(instance->mutex);
|
tt_mutex_free(instance->mutex);
|
||||||
tt_pubsub_free(instance->pubsub);
|
tt_pubsub_free(instance->pubsub);
|
||||||
tt_message_queue_free(instance->queue);
|
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
|
// endregion Public functions
|
||||||
|
|
||||||
static void wifi_lock(Wifi* wifi) {
|
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);
|
||||||
tt_assert(wifi->mutex);
|
tt_assert(wifi->mutex);
|
||||||
tt_check(xSemaphoreTakeRecursive(wifi->mutex, portMAX_DELAY) == pdPASS);
|
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");
|
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) {
|
static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_message) {
|
||||||
// TODO: only when connected!
|
// TODO: only when connected!
|
||||||
wifi_disconnect_internal(wifi);
|
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));
|
TT_LOG_E(TAG, "Failed to disconnect (%s)", esp_err_to_name(stop_result));
|
||||||
} else {
|
} else {
|
||||||
wifi->radio_state = WIFI_RADIO_ON;
|
wifi->radio_state = WIFI_RADIO_ON;
|
||||||
|
wifi->secure_connection = false;
|
||||||
wifi_publish_event_simple(wifi, WifiEventTypeDisconnected);
|
wifi_publish_event_simple(wifi, WifiEventTypeDisconnected);
|
||||||
TT_LOG_I(TAG, "Disconnected");
|
TT_LOG_I(TAG, "Disconnected");
|
||||||
}
|
}
|
||||||
@ -610,8 +580,6 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_update_statusbar(wifi);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,3 +610,4 @@ const ServiceManifest wifi_service = {
|
|||||||
.on_stop = &wifi_service_stop
|
.on_stop = &wifi_service_stop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
157
tactility-headless/src/services/wifi/wifi_mock.c
Normal file
157
tactility-headless/src/services/wifi/wifi_mock.c
Normal file
@ -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 <sys/cdefs.h>
|
||||||
|
|
||||||
|
#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
|
||||||
16
tactility-headless/src/tactility_headless.c
Normal file
16
tactility-headless/src/tactility_headless.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
17
tactility-headless/src/tactility_headless.h
Normal file
17
tactility-headless/src/tactility_headless.h
Normal file
@ -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
|
||||||
3
tactility-headless/src/tactility_headless_config.h
Normal file
3
tactility-headless/src/tactility_headless_config.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TT_CONFIG_SERVICES_LIMIT 32
|
||||||
@ -3,35 +3,39 @@ set(CMAKE_CXX_STANDARD 11)
|
|||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
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})
|
if (DEFINED ENV{ESP_IDF_VERSION})
|
||||||
add_definitions(-DESP_PLATFORM)
|
file(GLOB_RECURSE SOURCE_FILES src/*.c)
|
||||||
target_link_libraries(tactility
|
|
||||||
PUBLIC tactility-core
|
idf_component_register(
|
||||||
PUBLIC idf::lvgl # libs/
|
SRCS ${SOURCE_FILES}
|
||||||
PUBLIC idf::driver
|
INCLUDE_DIRS "src/"
|
||||||
PUBLIC idf::spiffs
|
REQUIRES tactility-headless lvgl
|
||||||
PUBLIC idf::nvs_flash
|
)
|
||||||
PUBLIC idf::newlib # for scandir() and related
|
|
||||||
|
target_link_libraries(${COMPONENT_LIB}
|
||||||
PUBLIC lv_screenshot
|
PUBLIC lv_screenshot
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_definitions(-DESP_PLATFORM)
|
||||||
else()
|
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_Nullable=)
|
||||||
add_definitions(-D_Nonnull=)
|
add_definitions(-D_Nonnull=)
|
||||||
target_link_libraries(tactility
|
target_link_libraries(tactility
|
||||||
PUBLIC tactility-core
|
PUBLIC tactility-headless
|
||||||
PUBLIC lvgl
|
PUBLIC lvgl
|
||||||
PUBLIC freertos_kernel
|
PUBLIC freertos_kernel
|
||||||
PUBLIC lv_screenshot
|
PUBLIC lv_screenshot
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#ifdef ESP_TARGET
|
||||||
|
|
||||||
#include "services/loader/loader.h"
|
#include "services/loader/loader.h"
|
||||||
#include "ui/toolbar.h"
|
#include "ui/toolbar.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -203,3 +205,5 @@ const AppManifest gpio_app = {
|
|||||||
.on_show = &app_show,
|
.on_show = &app_show,
|
||||||
.on_hide = &on_hide
|
.on_hide = &on_hide
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // ESP_TARGET
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#include "wifi_manage.h"
|
#include "wifi_manage.h"
|
||||||
|
|
||||||
#include "app.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 "services/loader/loader.h"
|
||||||
#include "tactility_core.h"
|
#include "tactility_core.h"
|
||||||
#include "ui/lvgl_sync.h"
|
#include "ui/lvgl_sync.h"
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#include "wifi_manage_view.h"
|
#include "wifi_manage_view.h"
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "services/statusbar_updater/statusbar_updater.h"
|
||||||
#include "services/wifi/wifi.h"
|
#include "services/wifi/wifi.h"
|
||||||
#include "ui/style.h"
|
#include "ui/style.h"
|
||||||
#include "ui/toolbar.h"
|
#include "ui/toolbar.h"
|
||||||
@ -1,12 +1,8 @@
|
|||||||
#include "hardware_i.h"
|
#include "lvgl_init_i.h"
|
||||||
|
|
||||||
#include "lvgl.h"
|
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "sdcard_i.h"
|
#include "lvgl.h"
|
||||||
|
|
||||||
#define TAG "hardware"
|
void tt_lvgl_init(const HardwareConfig* config) {
|
||||||
|
|
||||||
static void init_display_settings(const HardwareConfig* config) {
|
|
||||||
SetBacklightDuty set_backlight_duty = config->display.set_backlight_duty;
|
SetBacklightDuty set_backlight_duty = config->display.set_backlight_duty;
|
||||||
if (set_backlight_duty != NULL) {
|
if (set_backlight_duty != NULL) {
|
||||||
int32_t backlight_duty = 200;
|
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);
|
|
||||||
}
|
|
||||||
13
tactility/src/lvgl_init_i.h
Normal file
13
tactility/src/lvgl_init_i.h
Normal file
@ -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
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#include "gui_i.h"
|
#include "gui_i.h"
|
||||||
|
|
||||||
#include "tactility.h"
|
#include "tactility.h"
|
||||||
|
#include "services/loader/loader.h"
|
||||||
#include "ui/lvgl_sync.h"
|
#include "ui/lvgl_sync.h"
|
||||||
#include "ui/lvgl_keypad.h"
|
#include "ui/lvgl_keypad.h"
|
||||||
|
|
||||||
@ -18,6 +19,19 @@ static int32_t gui_main(void*);
|
|||||||
|
|
||||||
Gui* gui = NULL;
|
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* gui_alloc() {
|
||||||
Gui* instance = malloc(sizeof(Gui));
|
Gui* instance = malloc(sizeof(Gui));
|
||||||
memset(instance, 0, sizeof(Gui));
|
memset(instance, 0, sizeof(Gui));
|
||||||
@ -30,7 +44,7 @@ Gui* gui_alloc() {
|
|||||||
);
|
);
|
||||||
instance->mutex = tt_mutex_alloc(MutexTypeRecursive);
|
instance->mutex = tt_mutex_alloc(MutexTypeRecursive);
|
||||||
instance->keyboard = NULL;
|
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));
|
tt_check(tt_lvgl_lock(1000 / portTICK_PERIOD_MS));
|
||||||
instance->keyboard_group = lv_group_create();
|
instance->keyboard_group = lv_group_create();
|
||||||
instance->lvgl_parent = lv_scr_act();
|
instance->lvgl_parent = lv_scr_act();
|
||||||
|
|||||||
@ -18,6 +18,7 @@ struct Gui {
|
|||||||
// Thread and lock
|
// Thread and lock
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
Mutex* mutex;
|
Mutex* mutex;
|
||||||
|
PubSubSubscription* loader_pubsub_subscription;
|
||||||
|
|
||||||
// Layers and Canvas
|
// Layers and Canvas
|
||||||
lv_obj_t* lvgl_parent;
|
lv_obj_t* lvgl_parent;
|
||||||
|
|||||||
@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
#define TAG "loader"
|
#define TAG "loader"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LoaderEventType type;
|
||||||
|
} LoaderEventInternal;
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
static int32_t loader_main(void* p);
|
static int32_t loader_main(void* p);
|
||||||
|
|
||||||
@ -25,7 +29,8 @@ static Loader* loader_singleton = NULL;
|
|||||||
static Loader* loader_alloc() {
|
static Loader* loader_alloc() {
|
||||||
tt_check(loader_singleton == NULL);
|
tt_check(loader_singleton == NULL);
|
||||||
loader_singleton = malloc(sizeof(Loader));
|
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->queue = tt_message_queue_alloc(1, sizeof(LoaderMessage));
|
||||||
loader_singleton->thread = tt_thread_alloc_ex(
|
loader_singleton->thread = tt_thread_alloc_ex(
|
||||||
"loader",
|
"loader",
|
||||||
@ -42,7 +47,8 @@ static Loader* loader_alloc() {
|
|||||||
static void loader_free() {
|
static void loader_free() {
|
||||||
tt_check(loader_singleton != NULL);
|
tt_check(loader_singleton != NULL);
|
||||||
tt_thread_free(loader_singleton->thread);
|
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_message_queue_free(loader_singleton->queue);
|
||||||
tt_mutex_free(loader_singleton->mutex);
|
tt_mutex_free(loader_singleton->mutex);
|
||||||
free(loader_singleton);
|
free(loader_singleton);
|
||||||
@ -104,7 +110,7 @@ PubSub* loader_get_pubsub() {
|
|||||||
// it's safe to return pubsub without locking
|
// it's safe to return pubsub without locking
|
||||||
// because it's never freed and loader is never exited
|
// because it's never freed and loader is never exited
|
||||||
// also the loader instance cannot be obtained until the pubsub is created
|
// 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) {
|
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);
|
tt_app_set_state(app, AppStateStarted);
|
||||||
break;
|
break;
|
||||||
case AppStateShowing:
|
case AppStateShowing:
|
||||||
gui_show_app(
|
LoaderEvent event_showing = {
|
||||||
app,
|
.type = LoaderEventTypeApplicationShowing,
|
||||||
manifest->on_show,
|
.app_showing = {
|
||||||
manifest->on_hide
|
.app = app
|
||||||
);
|
}
|
||||||
|
};
|
||||||
|
tt_pubsub_publish(loader_singleton->pubsub_external, &event_showing);
|
||||||
tt_app_set_state(app, AppStateShowing);
|
tt_app_set_state(app, AppStateShowing);
|
||||||
break;
|
break;
|
||||||
case AppStateHiding:
|
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);
|
tt_app_set_state(app, AppStateHiding);
|
||||||
break;
|
break;
|
||||||
case AppStateStopped:
|
case AppStateStopped:
|
||||||
@ -200,8 +214,16 @@ LoaderStatus loader_do_start_app_with_manifest(
|
|||||||
|
|
||||||
loader_unlock();
|
loader_unlock();
|
||||||
|
|
||||||
LoaderEvent event = {.type = LoaderEventTypeApplicationStarted};
|
LoaderEventInternal event_internal = {.type = LoaderEventTypeApplicationStarted};
|
||||||
tt_pubsub_publish(loader_singleton->pubsub, &event);
|
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;
|
return LoaderStatusOk;
|
||||||
}
|
}
|
||||||
@ -240,6 +262,7 @@ static void loader_do_stop_app() {
|
|||||||
|
|
||||||
// Stop current app
|
// Stop current app
|
||||||
App app_to_stop = loader_singleton->app_stack[current_app_index];
|
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, AppStateHiding);
|
||||||
app_transition_to_state(app_to_stop, AppStateStopped);
|
app_transition_to_state(app_to_stop, AppStateStopped);
|
||||||
|
|
||||||
@ -258,8 +281,16 @@ static void loader_do_stop_app() {
|
|||||||
|
|
||||||
loader_unlock();
|
loader_unlock();
|
||||||
|
|
||||||
LoaderEvent event = {.type = LoaderEventTypeApplicationStopped};
|
LoaderEventInternal event_internal = {.type = LoaderEventTypeApplicationStopped};
|
||||||
tt_pubsub_publish(loader_singleton->pubsub, &event);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -21,15 +21,39 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LoaderEventTypeApplicationStarted,
|
LoaderEventTypeApplicationStarted,
|
||||||
|
LoaderEventTypeApplicationShowing,
|
||||||
|
LoaderEventTypeApplicationHiding,
|
||||||
LoaderEventTypeApplicationStopped
|
LoaderEventTypeApplicationStopped
|
||||||
} LoaderEventType;
|
} LoaderEventType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
App* app;
|
||||||
|
} LoaderEventAppStarted;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
App* app;
|
||||||
|
} LoaderEventAppShowing;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
App* app;
|
||||||
|
} LoaderEventAppHiding;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
AppManifest* manifest;
|
||||||
|
} LoaderEventAppStopped;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LoaderEventType type;
|
LoaderEventType type;
|
||||||
|
union {
|
||||||
|
LoaderEventAppStarted app_started;
|
||||||
|
LoaderEventAppShowing app_showing;
|
||||||
|
LoaderEventAppHiding app_hiding;
|
||||||
|
LoaderEventAppStopped app_stopped;
|
||||||
|
};
|
||||||
} LoaderEvent;
|
} LoaderEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Close any running app, then start new one. Blocking.
|
* @brief Start an app
|
||||||
* @param[in] id application name or id
|
* @param[in] id application name or id
|
||||||
* @param[in] blocking application arguments
|
* @param[in] blocking application arguments
|
||||||
* @param[in] bundle optional bundle. Ownership is transferred to Loader.
|
* @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);
|
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();
|
void loader_stop_app();
|
||||||
|
|
||||||
App _Nullable loader_get_current_app();
|
App _Nullable loader_get_current_app();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get loader pubsub
|
* @brief PubSub for LoaderEvent
|
||||||
* @return PubSub*
|
|
||||||
*/
|
*/
|
||||||
PubSub* loader_get_pubsub();
|
PubSub* loader_get_pubsub();
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,8 @@
|
|||||||
|
|
||||||
struct Loader {
|
struct Loader {
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
PubSub* pubsub;
|
PubSub* pubsub_internal;
|
||||||
|
PubSub* pubsub_external;
|
||||||
MessageQueue* queue;
|
MessageQueue* queue;
|
||||||
Mutex* mutex;
|
Mutex* mutex;
|
||||||
int8_t app_stack_index;
|
int8_t app_stack_index;
|
||||||
|
|||||||
160
tactility/src/services/statusbar_updater/statusbar_updater.c
Normal file
160
tactility/src/services/statusbar_updater/statusbar_updater.c
Normal file
@ -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
|
||||||
|
};
|
||||||
19
tactility/src/services/statusbar_updater/statusbar_updater.h
Normal file
19
tactility/src/services/statusbar_updater/statusbar_updater.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#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
|
||||||
@ -1,9 +1,11 @@
|
|||||||
#include "tactility.h"
|
#include "tactility.h"
|
||||||
|
|
||||||
#include "app_manifest_registry.h"
|
#include "app_manifest_registry.h"
|
||||||
#include "hardware_i.h"
|
#include "esp_init.h"
|
||||||
|
#include "lvgl_init_i.h"
|
||||||
#include "service_registry.h"
|
#include "service_registry.h"
|
||||||
#include "services/loader/loader.h"
|
#include "services/loader/loader.h"
|
||||||
|
#include "tactility_headless.h"
|
||||||
|
|
||||||
#define TAG "tactility"
|
#define TAG "tactility"
|
||||||
|
|
||||||
@ -15,14 +17,18 @@ extern const ServiceManifest gui_service;
|
|||||||
extern const ServiceManifest loader_service;
|
extern const ServiceManifest loader_service;
|
||||||
extern const ServiceManifest screenshot_service;
|
extern const ServiceManifest screenshot_service;
|
||||||
extern const ServiceManifest sdcard_service;
|
extern const ServiceManifest sdcard_service;
|
||||||
|
extern const ServiceManifest wifi_service;
|
||||||
|
extern const ServiceManifest statusbar_updater_service;
|
||||||
|
|
||||||
static const ServiceManifest* const system_services[] = {
|
static const ServiceManifest* const system_services[] = {
|
||||||
&gui_service,
|
&loader_service,
|
||||||
&loader_service, // depends on gui service
|
&gui_service, // depends on loader service
|
||||||
#ifndef ESP_PLATFORM // Screenshots don't work yet on ESP32
|
#ifndef ESP_PLATFORM // Screenshots don't work yet on ESP32
|
||||||
&screenshot_service,
|
&screenshot_service,
|
||||||
#endif
|
#endif
|
||||||
&sdcard_service
|
&sdcard_service,
|
||||||
|
&wifi_service,
|
||||||
|
&statusbar_updater_service
|
||||||
};
|
};
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -32,19 +38,28 @@ static const ServiceManifest* const system_services[] = {
|
|||||||
extern const AppManifest desktop_app;
|
extern const AppManifest desktop_app;
|
||||||
extern const AppManifest display_app;
|
extern const AppManifest display_app;
|
||||||
extern const AppManifest files_app;
|
extern const AppManifest files_app;
|
||||||
extern const AppManifest screenshot_app;
|
|
||||||
extern const AppManifest settings_app;
|
extern const AppManifest settings_app;
|
||||||
extern const AppManifest system_info_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[] = {
|
static const AppManifest* const system_apps[] = {
|
||||||
&desktop_app,
|
&desktop_app,
|
||||||
&display_app,
|
&display_app,
|
||||||
&files_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,
|
&screenshot_app,
|
||||||
#endif
|
#endif
|
||||||
&settings_app,
|
|
||||||
&system_info_app
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -96,13 +111,18 @@ static void register_and_start_user_services(const ServiceManifest* const servic
|
|||||||
void tt_init(const Config* config) {
|
void tt_init(const Config* config) {
|
||||||
TT_LOG_I(TAG, "tt_init started");
|
TT_LOG_I(TAG, "tt_init started");
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
tt_esp_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Assign early so starting services can use it
|
// Assign early so starting services can use it
|
||||||
config_instance = config;
|
config_instance = config;
|
||||||
|
|
||||||
tt_service_registry_init();
|
tt_tactility_headless_init(config->hardware, config->services);
|
||||||
tt_app_manifest_registry_init();
|
|
||||||
|
|
||||||
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!
|
// Note: the order of starting apps and services is critical!
|
||||||
// System services are registered first so the apps below can use them
|
// System services are registered first so the apps below can use them
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TT_CONFIG_APPS_LIMIT 32
|
#include "tactility_headless_config.h"
|
||||||
#define TT_CONFIG_SERVICES_LIMIT 32
|
|
||||||
|
|
||||||
|
#define TT_CONFIG_APPS_LIMIT 32
|
||||||
#define TT_CONFIG_FORCE_ONSCREEN_KEYBOARD false
|
#define TT_CONFIG_FORCE_ONSCREEN_KEYBOARD false
|
||||||
@ -25,7 +25,7 @@ typedef struct {
|
|||||||
|
|
||||||
static StatusbarData statusbar_data = {
|
static StatusbarData statusbar_data = {
|
||||||
.mutex = NULL,
|
.mutex = NULL,
|
||||||
.icons = {0}
|
.icons = {}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user