Remove TactilityC and Firmware subprojects (#638)

- Removed TactilityC, moved its symbols to existing modules and several new ones (pthread-module, c-symbols-module, cpp-symbols-module, posix-symbols-module, freertos-module).
- Removed Firmware subproject and moved main() into Tactility subproject.
- Strengthened application archive, path, version, stack-size, and device validation.
- Moved symbol resolution for elf_loader to app-esp32-module.
- Improved `struct Module` declarations and made module and symbol definitions in modules more consistent.
- Removed old http download code from Tactility subproject.
- Rename app-module's source files for consistency.
- Add missing pthread symbols.
- Kernel module symbols are now resolvable on all platforms.
This commit is contained in:
Ken Van Hoeylandt
2026-08-29 21:06:43 +02:00
committed by GitHub
parent d3556fb536
commit 19b11eb9a8
99 changed files with 2678 additions and 2092 deletions
+123 -6
View File
@@ -2,25 +2,59 @@ cmake_minimum_required(VERSION 3.20)
include("${CMAKE_CURRENT_LIST_DIR}/../Buildscripts/module.cmake")
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
# Get the project and device id
if (DEFINED ENV{ESP_IDF_VERSION})
include("../Buildscripts/device.cmake")
init_tactility_globals("../sdkconfig")
get_property(TACTILITY_DEVICE_PROJECT GLOBAL PROPERTY TACTILITY_DEVICE_PROJECT)
get_property(TACTILITY_DEVICE_ID GLOBAL PROPERTY TACTILITY_DEVICE_ID)
else ()
set(TACTILITY_DEVICE_ID simulator)
set(COMPONENT_LIB Tactility)
set(TACTILITY_DEVICE_PROJECT Simulator)
endif ()
set(DEVICETREE_LOCATION "${PROJECT_ROOT}/Devices/${TACTILITY_DEVICE_ID}")
list(APPEND REQUIRES_LIST
# Main projects
TactilityKernel
TactilityKernelCpp
TactilityFreeRtos
# Modules/*
lvgl-module
lvgl-window-manager-module
app-module
c-symbols-module
cpp-symbols-module
crypt-module
freertos-module
gps-module
http-module
mbedtls-module
posix-symbols-module
pthread-module
gps-generic-module
gps-meshtastic-module
service-module
# Libraries/*
lv_screenshot
minitar
)
# Check if device has Bluetooth enabled
# Fixes the sdkconfig bluetooth enable options from getting nuked on non-P4+C6 builds when idf build runs
if (DEFINED ENV{ESP_IDF_VERSION})
file(READ "${DEVICETREE_LOCATION}/device.properties" device_properties_content)
if (device_properties_content MATCHES "hardware\\.bluetooth=true")
list(APPEND REQUIRES_LIST bt)
endif()
endif()
if (DEFINED ENV{ESP_IDF_VERSION})
list(APPEND REQUIRES_LIST
@@ -62,14 +96,69 @@ else ()
endif ()
tactility_add_module(Tactility
SRCS ${SOURCE_FILES}
INCLUDE_DIRS Include/
PRIV_INCLUDE_DIRS Private/
REQUIRES ${REQUIRES_LIST}
#
# Devicetree code generation: DTS compiler python dependencies
#
execute_process(
COMMAND python -m pip install lark==1.3.1 pyyaml==6.0.3
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
#
# Devicetree code generation: Devicetree dependency collection
#
# REQUIRES_LIST below is computed once, at configure time. Without this, editing
# devicetree.yaml (e.g. adding a driver dependency) doesn't trigger a cmake reconfigure,
# so the new component's include dirs never reach the compiler until a fullclean.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${DEVICETREE_LOCATION}/devicetree.yaml"
"${DEVICETREE_LOCATION}/device.properties" # due to the "hardware.bluetooth = true" search in this file from this CMakeLists.txt
)
execute_process(
COMMAND python "${PROJECT_ROOT}/Buildscripts/DevicetreeCompiler/dependencies.py" "${DEVICETREE_LOCATION}"
WORKING_DIRECTORY "${PROJECT_ROOT}"
OUTPUT_VARIABLE DEVICE_DEPENDENCIES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Tokenize to array of lines
separate_arguments(DEVICE_DEPENDENCIES UNIX_COMMAND "${DEVICE_DEPENDENCIES}")
# Devicetree dependencies go on a separate list, not REQUIRES_LIST itself: the "simulator" device
# component links back against Tactility, so folding it into Tactility's own REQUIRES here would
# create a dependency cycle. They only apply to the Tactility target itself once it's built as the
# final executable (both platforms), never to a library consumer like TactilityTests.
set(TACTILITY_REQUIRES_LIST ${REQUIRES_LIST})
foreach(dts_dependency IN LISTS DEVICE_DEPENDENCIES)
message("Adding DTS dependency ${dts_dependency}")
list(APPEND TACTILITY_REQUIRES_LIST ${dts_dependency})
endforeach()
#
# Devicetree code generation: "Generated/" directory creation
#
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/Generated")
# Ensure the directory is built in the correct CMake build phase
# If the check is not done, then another directory is created in the root of the build folder.
if (DEFINED CMAKE_CURRENT_BINARY_DIR)
file(MAKE_DIRECTORY "${GENERATED_DIR}")
endif ()
#
# Component
#
if (DEFINED ENV{ESP_IDF_VERSION})
idf_component_register(
SRCS ${SOURCE_FILES} "${GENERATED_DIR}/devicetree.c"
INCLUDE_DIRS Include/
PRIV_INCLUDE_DIRS Private/
REQUIRES ${TACTILITY_REQUIRES_LIST}
)
idf_component_optional_requires(PRIVATE bt)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@@ -84,6 +173,34 @@ if (DEFINED ENV{ESP_IDF_VERSION})
fatfs_create_spiflash_image(data "${CMAKE_CURRENT_SOURCE_DIR}/../Data/data" FLASH_IN_PROJECT PRESERVE_TIME)
endif ()
endif ()
else ()
list(APPEND TACTILITY_REQUIRES_LIST
SDL2::SDL2-static
SDL2-static
)
add_executable(Tactility ${SOURCE_FILES})
target_include_directories(Tactility PUBLIC Include/)
target_include_directories(Tactility PRIVATE Private/)
target_link_libraries(Tactility PRIVATE ${TACTILITY_REQUIRES_LIST})
endif ()
#
# Devicetree code generation: custom target
#
# A custom target (not add_custom_command(OUTPUT ...)) so this always reruns: the devicetree's
# real inputs span many files (dts, bindings yaml, driver headers) that no fixed DEPENDS list can
# enumerate. BYPRODUCTS still wires a proper dependency for the sources that consume the output.
add_custom_target(Generated ALL
COMMAND python "${CMAKE_SOURCE_DIR}/Buildscripts/DevicetreeCompiler/compile.py"
"${DEVICETREE_LOCATION}" "${GENERATED_DIR}"
BYPRODUCTS "${GENERATED_DIR}/devicetree.c" "${GENERATED_DIR}/devicetree.h"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Generating devicetree source files..."
)
set_source_files_properties("${GENERATED_DIR}/devicetree.c" PROPERTIES GENERATED TRUE)
set_source_files_properties("${GENERATED_DIR}/devicetree.h" PROPERTIES GENERATED TRUE)
# Update target for generated code
target_sources(${COMPONENT_LIB} PRIVATE "${GENERATED_DIR}/devicetree.c")
target_include_directories(${COMPONENT_LIB} PRIVATE "${GENERATED_DIR}")
add_dependencies(${COMPONENT_LIB} Generated)
@@ -1,24 +0,0 @@
#pragma once
#include <string>
#include <functional>
namespace tt::network::http {
/**
* Download a file from a URL.
* The server must send the Content-Length header.
* @param url download source URL
* @param certFilePath the path to the .pem file
* @param downloadFilePath The path to downloadd the file to. The parent directories must exist.
* @param onSuccess the success result callback
* @param onError the error result callback
*/
void download(
const std::string& url,
const std::string& certFilePath,
const std::string &downloadFilePath,
const std::function<void()>& onSuccess,
const std::function<void(const char* errorMessage)>& onError
);
}
+106
View File
@@ -0,0 +1,106 @@
# Kconfig file for Tactility example app
menu "Tactility App"
config TT_DEVICE_NAME
string "Device Name"
default ""
help
Human-readable device name, including vendor (e.g. "M5Stack Cardputer")
config TT_DEVICE_NAME_SIMPLE
string "Device Name (simple)"
default ""
help
Human-readable simple device name, excluding vendor (e.g. "Cardputer")
config TT_DEVICE_VENDOR
string "Device Vendor Name"
default ""
help
Human-readable device vendor name (e.g. "LilyGO")
config TT_DEVICE_ID
string "Device Identifier"
default ""
help
The name of the directory in Devices/
See https://docs.tactilityproject.org for formatting guidance.
config TT_LAUNCHER_APP_ID
string "Launcher App ID"
default "tactility.launcher"
help
The applications that gives access to other application.
This is the first thing that starts after the boot screen.
The user can override it with a boot.properties file
config TT_LVGL_FONT_SIZE_SMALL
int "Small font size"
default 10
range 8 200
help
Small font size in pixels
config TT_LVGL_FONT_SIZE_DEFAULT
int "Default font size"
default 14
range 8 200
help
Default font size in pixels
config TT_LVGL_FONT_SIZE_LARGE
int "Large font size"
default 18
range 8 200
help
Large font size in pixels
config TT_LVGL_STATUSBAR_ICON_SIZE
int "Statusbar icon size"
default 20
range 0 200
help
Statusbar icon size in pixels
config TT_LVGL_LAUNCHER_ICON_SIZE
int "Launcher icon size"
default 20
range 0 200
help
Launcher icon size in pixels
config TT_LVGL_SHARED_ICON_SIZE
int "Shared icon size"
default 16
range 0 200
help
Shared icon size in pixels
config TT_AUTO_START_APP_ID
string "Auto Start App ID"
default ""
help
An application that gets automatically started from the launcher application.
This is optional and can be left empty.
The user can override it from a boot.properties file.
# T-Deck device-related code was directly referenced from Tactility in a pull request.
# This breaks other devices because the code does not exist in those implementations.
# Until we move it out into a proper driver, we have to have pre-processor definition for that.
config TT_TDECK_WORKAROUND
bool "Temporary work-around until we fix the T-Deck keyboard and trackball settings"
default n
choice TT_USER_DATA_LOCATION
prompt "User Data Location"
default TT_USER_DATA_LOCATION_INTERNAL
help
Where user data is stored on this device.
"Internal Flash" assumes /data always exists.
"SD Card" looks for the first mounted SD card at runtime and requires one to be present.
config TT_USER_DATA_LOCATION_SD
bool "SD Card"
config TT_USER_DATA_LOCATION_INTERNAL
bool "Internal Flash"
endchoice
config TT_SPLASH_DURATION
int "Splash Duration (ms)"
default 1000
range 0 3000
help
The minimum time to show the splash screen in milliseconds.
When set to 0, startup will continue to desktop as soon as boot operations are finished.
config TT_TOUCH_CALIBRATION_SUPPORTED
bool "Set true when a touch screen calibration app should be included"
default n
config TT_TOUCH_CALIBRATION_REQUIRED
bool "Set true when a touch screen calibration is required before the device is usable"
default n
depends on TT_TOUCH_CALIBRATION_SUPPORTED
endmenu
+15
View File
@@ -0,0 +1,15 @@
#include <Tactility/Tactility.h>
#include <devicetree.h>
#ifndef ESP_PLATFORM
#include <Simulator.h>
#endif
extern "C" {
void app_main() {
tt::run(dts_modules, dts_devices);
}
} // extern
+19 -3
View File
@@ -36,12 +36,18 @@
#include <Tactility/settings/TimePrivate.h>
#include <Tactility/settings/TouchCalibrationSettings.h>
#include <c_symbols/module.h>
#include <cpp_symbols/module.h>
#include <crypt/module.h>
#include <freertos/module.h>
#include <gps/module.h>
#include <gps_generic/module.h>
#include <gps_meshtastic/module.h>
#include <http/module.h>
#include <mbedtls/module.h>
#include <posix_symbols/module.h>
#include <pthread/module.h>
#include <crypt/module.h>
#include <lvgl/devices/keyboard.h>
@@ -472,13 +478,23 @@ void run(Module* const dtsModules[], const DtsDevice dtsDevices[]) {
return;
}
// The following groups of symbols are sorted by the estimated chance of them occurring
// C/C++/Posix symbols
check(module_ensure_started(&c_symbols_module) == ERROR_NONE);
check(module_ensure_started(&posix_symbols_module) == ERROR_NONE);
check(module_ensure_started(&cpp_symbols_module) == ERROR_NONE);
// OS level symbols
check(module_ensure_started(&freertos_module) == ERROR_NONE);
check(module_ensure_started(&pthread_module) == ERROR_NONE);
// Other libraries
check(module_ensure_started(&http_module) == ERROR_NONE);
check(module_ensure_started(&app_module) == ERROR_NONE);
check(module_ensure_started(&crypt_module) == ERROR_NONE);
check(module_ensure_started(&mbedtls_module) == ERROR_NONE);
check(module_ensure_started(&gps_module) == ERROR_NONE);
check(module_ensure_started(&gps_generic_module) == ERROR_NONE);
check(module_ensure_started(&gps_meshtastic_module) == ERROR_NONE);
check(module_ensure_started(&http_module) == ERROR_NONE);
// Registers the APP_LOCATION_MEMORY app loader (boot/launcher need it below).
check(module_ensure_started(&app_module) == ERROR_NONE);
#ifdef ESP_PLATFORM
check(module_ensure_started(&app_esp32_module) == ERROR_NONE);
#endif
-105
View File
@@ -1,105 +0,0 @@
#include <Tactility/Tactility.h>
#include <Tactility/file/File.h>
#include <Tactility/network/Http.h>
#include <tactility/log.h>
#ifdef ESP_PLATFORM
#include <Tactility/network/EspHttpClient.h>
#include <esp_http_client.h>
#endif
namespace tt::network::http {
constexpr auto* TAG = "HTTP";
void download(
const std::string& url,
const std::string& certFilePath,
const std::string &downloadFilePath,
const std::function<void()>& onSuccess,
const std::function<void(const char* errorMessage)>& onError
) {
LOG_I(TAG, "Downloading from %s to %s", url.c_str(), downloadFilePath.c_str());
#ifdef ESP_PLATFORM
getMainDispatcher().dispatch([url, certFilePath, downloadFilePath, onSuccess, onError] {
LOG_I(TAG, "Loading certificate");
auto certificate = file::readString(certFilePath);
if (certificate == nullptr) {
onError("Failed to read certificate");
return;
}
auto certificate_length = strlen(reinterpret_cast<const char*>(certificate.get())) + 1;
// TODO: Fix for missing initializer warnings
auto config = std::make_unique<esp_http_client_config_t>();
memset(config.get(), 0, sizeof(esp_http_client_config_t));
config->url = url.c_str();
config->auth_type = HTTP_AUTH_TYPE_NONE;
config->cert_pem = reinterpret_cast<const char*>(certificate.get());
config->cert_len = certificate_length;
config->tls_version = ESP_HTTP_CLIENT_TLS_VER_TLS_1_2;
config->method = HTTP_METHOD_GET;
config->timeout_ms = 5000;
config->transport_type = HTTP_TRANSPORT_OVER_SSL;
auto client = std::make_unique<EspHttpClient>();
if (!client->init(std::move(config))) {
onError("Failed to initialize client");
return;
}
if (!client->open()) {
onError("Failed to open connection");
return;
}
if (!client->fetchHeaders()) {
onError("Failed to get request headers");
return;
}
if (!client->isStatusCodeOk()) {
onError("Server response is not OK");
return;
}
auto bytes_left = client->getContentLength();
LOG_I(TAG, "Opening %s", downloadFilePath.c_str());
auto* file = fopen(downloadFilePath.c_str(), "wb");
if (file == nullptr) {
onError("Failed to open file");
return;
}
LOG_I(TAG, "Writing %d bytes to %s", bytes_left, downloadFilePath.c_str());
char buffer[512];
while (bytes_left > 0) {
int data_read = client->read(buffer, 512);
if (data_read <= 0) {
fclose(file);
onError("Failed to read data");
return;
}
bytes_left -= data_read;
if (fwrite(buffer, 1, data_read, file) != data_read) {
fclose(file);
onError("Failed to write all bytes");
return;
}
taskYIELD();
}
fclose(file);
LOG_I(TAG, "Downloaded %s to %s", url.c_str(), downloadFilePath.c_str());
onSuccess();
});
#else
getMainDispatcher().dispatch([onError] {
onError("Not implemented");
});
#endif
}
}
+21 -2
View File
@@ -4,25 +4,44 @@ enable_language(C CXX ASM)
file(GLOB_RECURSE TEST_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/Source/*.cpp)
add_executable(TactilityTests EXCLUDE_FROM_ALL ${TEST_SOURCES})
# Compile Tactility's own sources directly rather than linking the Tactility executable target.
# Main.cpp is excluded - it pulls in the device's Module/devicetree symbols, which would drag
# the whole device stack into the test binary just to get plain helpers like file/String.
file(GLOB_RECURSE TACTILITY_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/../Source/*.c*)
list(FILTER TACTILITY_SOURCES EXCLUDE REGEX ".*/Main\\.cpp$")
add_executable(TactilityTests EXCLUDE_FROM_ALL ${TEST_SOURCES} ${TACTILITY_SOURCES})
target_include_directories(TactilityTests PRIVATE ${DOCTESTINC})
target_include_directories(TactilityTests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../Include)
target_include_directories(TactilityTests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../Private)
add_test(NAME TactilityTests COMMAND TactilityTests)
target_link_libraries(TactilityTests PRIVATE
Tactility
TactilityKernel
TactilityKernelCpp
TactilityFreeRtos
platform-posix
lvgl-module
lvgl-window-manager-module
app-module
c-symbols-module
cpp-symbols-module
crypt-module
freertos-module
gps-module
http-module
mbedtls-module
posix-symbols-module
pthread-module
gps-generic-module
gps-meshtastic-module
service-module
lv_screenshot
minitar
lvgl
cJSON
SDL2::SDL2-static SDL2-static
)
+97
View File
@@ -0,0 +1,97 @@
dependencies:
espressif/esp_codec_dev: "1.5.10"
espressif/esp_video:
version: "2.2.0"
rules:
- if: "target in [esp32s3, esp32c6, esp32p4]"
espressif/esp_hosted:
version: "2.12.11"
rules:
- if: "target == esp32p4"
espressif/esp_wifi_remote:
version: "1.2.3"
rules:
- if: "target == esp32p4"
espressif/esp_lcd_ili9341:
version: "2.0.1"
rules:
- if: "target in [esp32, esp32s3]"
atanisoft/esp_lcd_ili9488:
version: "1.0.10"
rules:
- if: "target in [esp32, esp32s3]"
teriyakigod/esp_lcd_st7735:
version: "0.0.1"
rules:
- if: "target in [esp32, esp32s3]"
espressif/esp_lcd_touch: "1.2.1"
atanisoft/esp_lcd_touch_xpt2046:
version: "1.0.6"
rules:
- if: "target in [esp32, esp32s3]"
espressif/esp_lcd_touch_cst816s: "1.0.3"
espressif/esp_lcd_touch_gt911: "1.1.3"
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
espressif/esp_lcd_axs15231b: "2.0.2"
lambage/esp_lcd_touch_ft6336u: "1.0.8"
espressif/esp_lcd_st7701:
version: "1.1.3"
rules:
- if: "target in [esp32s3, esp32p4]"
espressif/esp_lcd_st7796:
version: "1.3.4"
rules:
- if: "target in [esp32, esp32s3]"
espressif/esp_lcd_gc9a01: "2.0.3"
espressif/esp_lcd_jd9165:
version: "1.0.3"
rules:
# More hardware seems to be supported - enable as needed
- if: "target in [esp32p4]"
espressif/esp_lcd_ili9881c:
version: "1.1.0"
rules:
# More hardware seems to be supported - enable as needed
- if: "target in [esp32p4]"
espressif/esp_lcd_st7123:
version: "1.0.2"
rules:
# More hardware seems to be supported - enable as needed
- if: "target in [esp32p4]"
espressif/esp_lcd_st7121:
version: "1.0.1"
rules:
# More hardware seems to be supported - enable as needed
- if: "target in [esp32p4]"
espressif/esp_lcd_touch_st7123:
version: "1.0.1"
rules:
# More hardware seems to be supported - enable as needed
- if: "target in [esp32p4]"
espressif/esp_lcd_panel_io_additions: "1.0.1"
espressif/esp_tinyusb:
version: "1.7.6~1"
rules:
- if: "target in [esp32s3, esp32p4]"
espressif/esp_lvgl_port: "2.7.2"
lvgl/lvgl: "9.3.0"
epdiy:
git: https://github.com/Shadowtrance/epdiy.git
version: 2.0.1
rules:
# More hardware might be supported - enable as needed
- if: "target in [esp32s3]"
espressif/usb_host_hid:
version: "1.1.0"
rules:
- if: "target in [esp32s3, esp32p4]"
espressif/usb_host_msc:
version: "1.1.4"
rules:
- if: "target in [esp32s3, esp32p4]"
jgromes/radiolib:
version: "7.3.0"
rules:
- if: "target in [esp32, esp32s3, esp32p4]"
idf: '5.5.2'