mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-08-19 00:15:05 +00:00
Fixes and improvements (#616)
This commit is contained in:
parent
f943c4dd69
commit
b03759a111
@ -41,6 +41,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
"Modules"
|
||||
"Platforms/platform-esp32"
|
||||
"TactilityKernel"
|
||||
"TactilityKernelCpp"
|
||||
"Tactility"
|
||||
"TactilityC"
|
||||
"TactilityFreeRtos"
|
||||
@ -77,7 +78,7 @@ else ()
|
||||
add_compile_definitions(CONFIG_TT_DEVICE_NAME="Simulator")
|
||||
add_compile_definitions(CONFIG_TT_DEVICE_VENDOR="")
|
||||
add_compile_definitions(CONFIG_TT_DEVICE_NAME_SIMPLE="Simulator")
|
||||
add_compile_definitions(CONFIG_TT_LAUNCHER_APP_ID="Launcher")
|
||||
add_compile_definitions(CONFIG_TT_LAUNCHER_APP_ID="tactility.launcher")
|
||||
add_compile_definitions(CONFIG_TT_AUTO_START_APP_ID="")
|
||||
add_compile_definitions(CONFIG_TT_USER_DATA_LOCATION_INTERNAL)
|
||||
endif ()
|
||||
@ -89,6 +90,7 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION})
|
||||
add_subdirectory(Tactility)
|
||||
add_subdirectory(TactilityFreeRtos)
|
||||
add_subdirectory(TactilityKernel)
|
||||
add_subdirectory(TactilityKernelCpp)
|
||||
add_subdirectory(Platforms/platform-posix)
|
||||
add_subdirectory(Devices/simulator)
|
||||
add_subdirectory(Libraries/cJSON)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=BigTreeTech
|
||||
general.name=Panda Touch,K Touch
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CL-32
|
||||
general.name=CL-32
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=2432S024C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=2432S024R
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=2432S028R
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=2432S028R v3
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=2432S032C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=3248S035C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=4848S040C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,7 +2,7 @@ general.vendor=CYD
|
||||
general.name=8048S043C
|
||||
general.incubating=false
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=E32R28T
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=E32R32P
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Advance 2.8"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Advance 3.5"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Advance 5.0"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Basic 2.8"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Basic 3.5"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Elecrow
|
||||
general.name=CrowPanel Basic 5.0"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=CYD
|
||||
general.name=ES3C28P
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Generic
|
||||
general.name=ESP32
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Generic
|
||||
general.name=ESP32-C6
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32C6
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Generic
|
||||
general.name=ESP32-P4
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32P4
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Generic
|
||||
general.name=ESP32-S3
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Guition
|
||||
general.name=JC1060P470C-I-W-Y
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32P4
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Guition
|
||||
general.name=JC2432W328C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=4MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Guition
|
||||
general.name=JC8048W550C
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=Heltec
|
||||
general.name=WiFi LoRa 32 v3
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -3,7 +3,7 @@ general.name=T-Deck Max
|
||||
# SD card support is not yet working, display driver is untested since refactoring; remove once it is functional.
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=LilyGO
|
||||
general.name=T-Deck Plus
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -3,7 +3,7 @@ general.name=T-Deck Pro
|
||||
# The display driver is not reliable yet
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=LilyGO
|
||||
general.name=T-Deck
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
general.vendor=LilyGO
|
||||
general.name=T-Display S3
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=LilyGO
|
||||
general.name=T-Display
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=LilyGO
|
||||
general.name=T-Dongle S3
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=LilyGO
|
||||
general.name=T-HMI
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=LilyGO
|
||||
general.name=T-Lora Pager
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=Cardputer Adv
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=Cardputer,Cardputer v1.1
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=Core2
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=CoreS3
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,7 +2,7 @@ general.vendor=M5Stack
|
||||
general.name=PaperS3
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=esp32s3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=StackChan
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=StickC Plus2
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=StickS3
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=M5Stack
|
||||
general.name=Tab5
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32P4
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Simulator
|
||||
general.name=Tab5Simulator
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=POSIX
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Tulip
|
||||
general.name=Tulip Creative Computer (4r11)
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=32MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=unPhone
|
||||
general.name=unPhone
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=8MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=Waveshare
|
||||
general.name=ESP32 S3 GEEK
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=WaveShare
|
||||
general.name=S3 LCD 1.3"
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,8 +2,8 @@ general.vendor=WaveShare
|
||||
general.name=S3 Touch LCD 1.28"
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.autoStartAppId=ApWebServer
|
||||
apps.launcherAppId=tactility.launcher
|
||||
apps.autoStartAppId=tactility.apwebserver
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -2,7 +2,7 @@ general.vendor=WaveShare
|
||||
general.name=S3 Touch LCD 1.47"
|
||||
general.incubating=true
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=WaveShare
|
||||
general.name=S3 Touch LCD 4.3"
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
# Some models have 16MB flash, but some have 8MB. We only support the latter to avoid making more builds.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
general.vendor=Wireless Tag
|
||||
general.name=WT32 SC01 Plus
|
||||
|
||||
apps.launcherAppId=Launcher
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
## Higher Priority
|
||||
|
||||
- AppHubApp: Prevent download callbacks from accessing a destroyed view.
|
||||
- Move USB host task stacks to SPIRAM when available: esp32_usbhost*.cpp
|
||||
- wifi: wifi_add_event_callback() and wifi_remove_event_callback() should be replaced by a subscribe/await pattern like system events.
|
||||
When that's changed reduce LVGL callstack size in Tactility.cpp run()
|
||||
|
||||
@ -1,11 +1,6 @@
|
||||
# Audio codec module
|
||||
|
||||
Defines codec-agnostic `AudioCodecApi` (open/close/read/write/volume/mute/native-rate/native-channels/capabilities)
|
||||
that every audio codec driver in this repo implements (ES8311, ES8388, ES7210, AW88298, the dummy I2S amps, the PDM mic).
|
||||
This is intentionally low-level: no resampling or mixing, one codec device per chip. Most app code should go through
|
||||
`audio_stream` (see `Drivers/audio-stream-module`) instead of talking to a codec device directly.
|
||||
|
||||
Also provides `audio_codec_adapters.h`: glue that lets a codec driver build an `esp_codec_dev` control/data/GPIO
|
||||
Provides `audio_codec_adapters.h`: glue that lets a codec driver build an `esp_codec_dev` control/data/GPIO
|
||||
interface (`audio_codec_ctrl_if_t` / `audio_codec_data_if_t` / `audio_codec_gpio_if_t`) directly from Tactility's
|
||||
own I2C controller, I2S controller, and GPIO pin devices, so a codec driver only ever needs
|
||||
`device_get_parent()`/`device_find_by_name()` plus a handful of devicetree properties -- it never touches the platform
|
||||
|
||||
@ -23,7 +23,7 @@ menu "Tactility App"
|
||||
See https://docs.tactilityproject.org for formatting guidance.
|
||||
config TT_LAUNCHER_APP_ID
|
||||
string "Launcher App ID"
|
||||
default "Launcher"
|
||||
default "tactility.launcher"
|
||||
help
|
||||
The applications that gives access to other application.
|
||||
This is the first thing that starts after the boot screen.
|
||||
|
||||
@ -13,6 +13,7 @@ extern "C" {
|
||||
#define APP_METADATA_APP_ID_LENGTH 32
|
||||
#define APP_METADATA_APP_NAME_LENGTH 32
|
||||
#define APP_METADATA_APP_VERSION_NAME_LENGTH 16
|
||||
#define APP_METADATA_REQUIRES_DEVICE_ID_LENGTH 64
|
||||
|
||||
struct AppMetadata {
|
||||
|
||||
@ -42,6 +43,13 @@ struct AppMetadata {
|
||||
|
||||
/** The technical version (must be incremented with new releases of the app) */
|
||||
uint64_t app_version_code;
|
||||
|
||||
/**
|
||||
* Comma-separated list of device ids the app is restricted to (e.g. "m5stack-tab5"), matching
|
||||
* the folder names under Devices/. Empty means unrestricted.
|
||||
* Must be NULL-terminated.
|
||||
*/
|
||||
char requires_device_id[APP_METADATA_REQUIRES_DEVICE_ID_LENGTH + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -18,6 +18,9 @@ bool app_metadata_is_valid_name(const std::string& name);
|
||||
bool app_metadata_is_valid_version_name(const std::string& version);
|
||||
bool app_metadata_is_valid_version_code(const std::string& version);
|
||||
|
||||
/** Validates a comma-separated list of device ids (alphanumeric + '-' items, matching Devices/<id> folder names). */
|
||||
bool app_metadata_is_valid_device_id_list(const std::string& value);
|
||||
|
||||
/** Copies @a value into @a dest (a fixed-size buffer of @a dest_size bytes, including the NULL
|
||||
* terminator) if it fits.
|
||||
* @retval false @a value doesn't fit in @a dest_size bytes - @a dest is left untouched */
|
||||
|
||||
@ -37,6 +37,26 @@ bool validate_string(const std::string& value, bool (*is_valid_char)(char)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Validates a comma-separated list: non-empty, no leading/trailing/double commas (which would
|
||||
* produce an empty item), and every item passing @a is_valid_item. */
|
||||
bool validate_csv_list(const std::string& value, bool (*is_valid_item)(const std::string&)) {
|
||||
if (value.empty()) {
|
||||
return false;
|
||||
}
|
||||
size_t start = 0;
|
||||
while (true) {
|
||||
auto comma = value.find(',', start);
|
||||
auto end = comma == std::string::npos ? value.size() : comma;
|
||||
if (end == start || !is_valid_item(value.substr(start, end - start))) {
|
||||
return false;
|
||||
}
|
||||
if (comma == std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
start = comma + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** manifest.properties format: "key=value" lines, "[section]" lines prefix every following key
|
||||
* until the next section, "#" lines are comments, blank lines are skipped. Deliberately a local,
|
||||
* minimal re-implementation rather than depending on Tactility's file::loadPropertiesFile() -
|
||||
@ -130,6 +150,20 @@ bool app_metadata_is_valid_version_code(const std::string& version) {
|
||||
});
|
||||
}
|
||||
|
||||
bool app_metadata_is_valid_device_id_list(const std::string& value) {
|
||||
return validate_csv_list(value, [](const std::string& item) {
|
||||
bool has_alnum = false;
|
||||
for (char c: item) {
|
||||
if (std::isalnum(static_cast<unsigned char>(c)) != 0) {
|
||||
has_alnum = true;
|
||||
} else if (c != '-') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return has_alnum;
|
||||
});
|
||||
}
|
||||
|
||||
bool app_metadata_copy_bounded(char* dest, size_t dest_size, const std::string& value) {
|
||||
if (value.size() >= dest_size) {
|
||||
return false;
|
||||
@ -141,6 +175,10 @@ bool app_metadata_copy_bounded(char* dest, size_t dest_size, const std::string&
|
||||
error_t app_metadata_parse(const char* path, struct AppMetadata* out_metadata) {
|
||||
LOG_I(TAG, "Parsing manifest %s", path);
|
||||
|
||||
// requires_device_id is optional in V2 and unwritten by V1; zeroing here (rather than relying
|
||||
// on the caller) guarantees it reads back as empty ("unrestricted") either way.
|
||||
*out_metadata = {};
|
||||
|
||||
std::map<std::string, std::string> properties;
|
||||
std::string first_line;
|
||||
if (!load_properties(path, properties, first_line)) {
|
||||
|
||||
@ -99,5 +99,20 @@ bool app_metadata_parse_v2(const std::map<std::string, std::string>& properties,
|
||||
return false;
|
||||
}
|
||||
|
||||
// requires.device.id (optional; if present, must be a non-empty comma-separated list)
|
||||
|
||||
auto device_id_iterator = properties.find("requires.device.id");
|
||||
if (device_id_iterator != properties.end()) {
|
||||
const std::string& device_id = device_id_iterator->second;
|
||||
if (!app_metadata_is_valid_device_id_list(device_id)) {
|
||||
LOG_E(TAG, "Invalid requires.device.id");
|
||||
return false;
|
||||
}
|
||||
if (!app_metadata_copy_bounded(out_metadata.requires_device_id, sizeof(out_metadata.requires_device_id), device_id)) {
|
||||
LOG_E(TAG, "requires.device.id too long");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ error_t app_paths_get_user_data_directory(const char* app_id, char* out_path, si
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
int written = std::snprintf(out_path, out_path_size, "%s/app/%s", root, app_id);
|
||||
int written = std::snprintf(out_path, out_path_size, "%s/user/app/%s", root, app_id);
|
||||
if (written < 0 || (size_t)written >= out_path_size) {
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ constexpr auto* TAG = "gps_settings";
|
||||
|
||||
// Storage key for the persisted configuration file (services would use their own service ID for
|
||||
// this; gps_settings has no service backing it, so it defines its own).
|
||||
constexpr auto* GPS_SETTINGS_STORAGE_ID = "gps";
|
||||
constexpr auto* GPS_SETTINGS_STORAGE_ID = "tactility.gps";
|
||||
|
||||
// region Configuration persistence
|
||||
|
||||
|
||||
@ -4,9 +4,12 @@
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include <tactility/drivers/keyboard.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
constexpr auto* TAG = "lvgl_keyboard";
|
||||
|
||||
static LvglSoftwareKeyboard last_software_keyboard = {
|
||||
.object = nullptr
|
||||
};
|
||||
@ -106,16 +109,23 @@ void lvgl_keyboard_disable(lv_indev_t* indev) {
|
||||
lv_indev_set_group(indev, nullptr);
|
||||
}
|
||||
|
||||
bool lvgl_hardware_keyboard_is_available() {
|
||||
Device* keyboard_device;
|
||||
if (device_get_first_active_by_type(&KEYBOARD_TYPE, &keyboard_device) != ERROR_NONE) {
|
||||
return false;
|
||||
static bool lvgl_hardware_keyboard_check_present(Device* device, void* context) {
|
||||
bool ready = device_is_ready(device);
|
||||
bool present = ready && keyboard_is_present(device);
|
||||
LOG_D(TAG, "keyboard device %s: ready=%d present=%d", device->name, (int)ready, (int)present);
|
||||
if (!present) {
|
||||
return true; // keep looking
|
||||
}
|
||||
*static_cast<bool*>(context) = true;
|
||||
return false; // found one, stop iterating
|
||||
}
|
||||
|
||||
bool lvgl_hardware_keyboard_is_available() {
|
||||
// TODO: Refactor the driver subsystem to so it does proper probing/releasing of such devices
|
||||
// This work-around exists for the Tab5 keyboard driver.
|
||||
bool present = keyboard_is_present(keyboard_device);
|
||||
device_put(keyboard_device);
|
||||
bool present = false;
|
||||
device_for_each_of_type(&KEYBOARD_TYPE, &present, lvgl_hardware_keyboard_check_present);
|
||||
LOG_D(TAG, "lvgl_hardware_keyboard_is_available() -> %d", (int)present);
|
||||
return present;
|
||||
}
|
||||
|
||||
@ -138,6 +148,11 @@ void lvgl_hardware_keyboard_remove_custom(lv_indev_t* indev) {
|
||||
}
|
||||
|
||||
static void textarea_show_keyboard(lv_event_t* event) {
|
||||
// Re-checked here rather than gated once at lvgl_keyboard_add_textarea() time, so a hardware
|
||||
// keyboard that connects/disconnects after the textarea was created is honored immediately.
|
||||
if (!lvgl_software_keyboard_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
lv_obj_t* target = lv_event_get_current_target_obj(event);
|
||||
if (last_software_keyboard.object != nullptr) {
|
||||
lvgl_software_keyboard_show(&last_software_keyboard, target);
|
||||
@ -192,18 +207,10 @@ LvglSoftwareKeyboard* lvgl_software_keyboard_get_last() {
|
||||
}
|
||||
|
||||
void lvgl_keyboard_add_textarea(LvglSoftwareKeyboard* keyboard, lv_obj_t* textarea) {
|
||||
// Only the on-screen keyboard's show/hide wiring is specific to "no hardware keyboard"
|
||||
// mode. Group membership must NOT be gated on it: a hardware keypad indev (see
|
||||
// lvgl_keyboard_enable()/lvgl_software_keyboard_activate()) is bound to keyboard_group
|
||||
// regardless of whether a software keyboard is in use, so skipping lv_group_add_obj()
|
||||
// here left every textarea unreachable from a hardware keyboard - it was never a member
|
||||
// of the group its indev delivers key events through.
|
||||
if (lvgl_software_keyboard_is_enabled()) {
|
||||
lv_obj_add_event_cb(textarea, textarea_show_keyboard, LV_EVENT_FOCUSED, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DEFOCUSED, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_READY, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DELETE, nullptr);
|
||||
}
|
||||
lv_obj_add_event_cb(textarea, textarea_show_keyboard, LV_EVENT_FOCUSED, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DEFOCUSED, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_READY, nullptr);
|
||||
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DELETE, nullptr);
|
||||
|
||||
// lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3)
|
||||
lv_group_add_obj(keyboard_group, textarea);
|
||||
|
||||
@ -35,11 +35,10 @@ static constexpr size_t COMPOSITE_STRING_DESCRIPTOR_MAX = 6;
|
||||
|
||||
// ---- Controller state ----
|
||||
// One TinyUSB device-mode slot, shared by every USB device class (each a separate child device
|
||||
// under usbdevice0 in the devicetree - see esp32_usb_hid_device.cpp / esp32_usb_device_msc.cpp /
|
||||
// esp32_usb_midi_device.cpp). Only one primary class may be installed at a time - see
|
||||
// UsbDeviceControllerApi::claim(). CDC (esp32_usb_cdc_device.cpp) is a separate, orthogonal
|
||||
// devicetree-presence addon composited into whichever primary is active (HID or MIDI; MSC is
|
||||
// deliberately excluded, see claim()'s cdc_enabled computation) - see claim() below.
|
||||
// under usbdevice0 in the devicetree; \see esp32_usb_hid_device.cpp, esp32_usb_device_msc.cpp,
|
||||
// esp32_usb_midi_device.cpp). Only one primary class may be installed at a time, enforced in
|
||||
// claim(). CDC (esp32_usb_cdc_device.cpp) is a separate, orthogonal devicetree-presence addon
|
||||
// composited into whichever primary is active; \see claim()'s cdc_enabled computation.
|
||||
|
||||
struct UsbDeviceControllerCtx {
|
||||
enum UsbDeviceClass active_class = USB_DEVICE_CLASS_NONE;
|
||||
@ -53,10 +52,10 @@ struct UsbDeviceControllerCtx {
|
||||
uint8_t next_in_endpoint = 1; // EP0 reserved
|
||||
uint8_t next_out_endpoint = 1;
|
||||
|
||||
// Composite descriptor scratch, rebuilt on every claim() - can't be `static const` per-class
|
||||
// Composite descriptor scratch, rebuilt on every claim(); can't be `static const` per-class
|
||||
// anymore now that CDC's presence is a runtime devicetree fact, not compile-time. Two buffers
|
||||
// since a primary (MSC) may need different bytes per speed (see UsbInterfaceContribution's
|
||||
// hs_descriptor_bytes) - under !TUD_OPT_HIGH_SPEED only the fs buffer is ever used.
|
||||
// since a primary (MSC) may need different bytes per speed (\see UsbInterfaceContribution's
|
||||
// hs_descriptor_bytes). Under !TUD_OPT_HIGH_SPEED only the fs buffer is ever used.
|
||||
uint8_t composite_fs_config_descriptor[COMPOSITE_CONFIG_DESCRIPTOR_MAX];
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
uint8_t composite_hs_config_descriptor[COMPOSITE_CONFIG_DESCRIPTOR_MAX];
|
||||
@ -101,7 +100,7 @@ static bool find_cdc_child(struct Device* child, void* context) {
|
||||
}
|
||||
|
||||
// Devicetree children are constructed/added/started strictly after their parent
|
||||
// (kernel_init.cpp's dts_devices[] loop starts each device in list order, parent first) - so the
|
||||
// (kernel_init.cpp's dts_devices[] loop starts each device in list order, parent first), so the
|
||||
// usbdevicecdc0 child does not exist yet when this controller's own start_device() runs.
|
||||
// Discovering it lazily here (called from is_cdc_enabled(), well after all devicetree devices
|
||||
// have finished starting) instead of once at start_device() time is the only way to actually see
|
||||
@ -168,14 +167,7 @@ static error_t claim(struct Device* device, enum UsbDeviceClass usb_class, const
|
||||
return ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
// MSC is deliberately excluded from CDC compositing - a MSC-presenting device is meant to
|
||||
// look/behave like plain mass storage to the host's storage stack, and there's no real use
|
||||
// case for a console interface while acting as a flash drive, unlike HID/MIDI which
|
||||
// plausibly want a console alongside. (A Windows safe-eject hang was seen during development
|
||||
// of this compositing code but traced to a stale Windows-side driver/device-cache state,
|
||||
// cleared by a host reboot - not caused by CDC compositing or this exclusion. Kept the
|
||||
// exclusion anyway since it matches MSC's actual intended behavior.)
|
||||
const bool cdc_enabled = usb_class != USB_DEVICE_CLASS_MSC && is_cdc_enabled(device);
|
||||
const bool cdc_enabled = is_cdc_enabled(device);
|
||||
|
||||
// ---- String table: primary's table, plus CDC's own interface string appended last.
|
||||
size_t string_count = config->string_descriptor_count;
|
||||
@ -207,7 +199,7 @@ static error_t claim(struct Device* device, enum UsbDeviceClass usb_class, const
|
||||
|
||||
// ---- Descriptor byte assembly: primary's bytes, then CDC's (if enabled), behind one config
|
||||
// header. Built twice (fs/hs) under TUD_OPT_HIGH_SPEED if the primary supplied distinct
|
||||
// high-speed bytes (see UsbInterfaceContribution::hs_descriptor_bytes) - CDC never varies by
|
||||
// high-speed bytes (\see UsbInterfaceContribution::hs_descriptor_bytes). CDC never varies by
|
||||
// speed, so its bytes are reused verbatim in both buffers.
|
||||
auto assemble = [&](uint8_t* dest, size_t dest_capacity, const uint8_t* primary_bytes, size_t primary_len) -> error_t {
|
||||
const size_t total_len = TUD_CONFIG_DESC_LEN + primary_len + (cdc_enabled ? cdc_contribution.descriptor_bytes_len : 0);
|
||||
@ -250,13 +242,6 @@ static error_t claim(struct Device* device, enum UsbDeviceClass usb_class, const
|
||||
|
||||
ctx->allocation_open = false;
|
||||
|
||||
// ---- Device descriptor: primary's metadata (idVendor/idProduct/strings), controller decides
|
||||
// the class triad since CDC's presence (not the primary's identity) is what needs IAD in the
|
||||
// general case - except MSC, which always got MISC/IAD unconditionally even standalone in
|
||||
// the pre-refactor code (see esp32_usb_device_msc.cpp history). Kept that behavior verbatim
|
||||
// for MSC (regardless of cdc_enabled, which is always false for MSC anyway - see the
|
||||
// cdc_enabled computation above) simply to match what shipped before rather than introduce
|
||||
// an unrelated behavior change while separating CDC out of HID's descriptor.
|
||||
ctx->composite_device_descriptor = *static_cast<const tusb_desc_device_t*>(config->device_descriptor);
|
||||
if (cdc_enabled || usb_class == USB_DEVICE_CLASS_MSC) {
|
||||
ctx->composite_device_descriptor.bDeviceClass = TUSB_CLASS_MISC;
|
||||
@ -277,7 +262,7 @@ static error_t claim(struct Device* device, enum UsbDeviceClass usb_class, const
|
||||
ctx->composite_tusb_cfg.fs_configuration_descriptor = ctx->composite_fs_config_descriptor;
|
||||
ctx->composite_tusb_cfg.hs_configuration_descriptor = ctx->composite_hs_config_descriptor;
|
||||
// The qualifier descriptor's class triad must mirror the device descriptor's (same IAD
|
||||
// reasoning) - built here rather than supplied per-primary since its content is boilerplate
|
||||
// reasoning). Built here rather than supplied per-primary since its content is boilerplate
|
||||
// (same bMaxPacketSize0/bNumConfigurations for every class) and the controller already knows
|
||||
// the class triad.
|
||||
ctx->composite_device_qualifier = {
|
||||
@ -366,7 +351,7 @@ extern const UsbDeviceControllerApi usb_device_controller_api = {
|
||||
};
|
||||
|
||||
// ---- Driver lifecycle ----
|
||||
// This device is defined in each board's .dts (usbdevice0), same pattern as usbhost0 - its
|
||||
// This device is defined in each board's .dts (usbdevice0), same pattern as usbhost0. Its
|
||||
// child classes (usbdevicehid0, usbdevicemsc0, usbdevicemidi0, usbdevicecdc0) are separate .dts
|
||||
// nodes with their own drivers, wired to this device as their parent by the devicetree compiler.
|
||||
|
||||
@ -377,19 +362,19 @@ static error_t start_device(struct Device* device) {
|
||||
auto* ctx = new UsbDeviceControllerCtx();
|
||||
device_set_driver_data(device, ctx);
|
||||
// cdc_child is NOT resolved here: usbdevicecdc0 (a child of this device in the devicetree)
|
||||
// hasn't been constructed/started yet at this point - kernel_init.cpp starts devicetree
|
||||
// devices in list order, parent before children. Resolved lazily instead, see
|
||||
// find_cdc_child_lazy() / is_cdc_enabled().
|
||||
// hasn't been constructed/started yet at this point; kernel_init.cpp starts devicetree
|
||||
// devices in list order, parent before children.
|
||||
// \see find_cdc_child_lazy(), is_cdc_enabled() for the lazy resolution.
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop_device(struct Device* device) {
|
||||
auto* ctx = static_cast<UsbDeviceControllerCtx*>(device_get_driver_data(device));
|
||||
// Safety cleanup: if a class still holds the slot (e.g. this device is stopped while HID/
|
||||
// MSC/MIDI is still active), tear TinyUSB down and restore the PHY route before freeing ctx -
|
||||
// MSC/MIDI is still active), tear TinyUSB down and restore the PHY route before freeing ctx;
|
||||
// otherwise the installed TinyUSB driver and mis-routed PHY would outlive the context that
|
||||
// tracks them. Mirrors the same safety-release pattern each child driver's own stop_device
|
||||
// uses (see esp32_usb_hid_device.cpp / esp32_usb_device_msc.cpp / esp32_usb_midi_device.cpp).
|
||||
// tracks them. Mirrors the same safety-release pattern each child driver's own stop_device uses.
|
||||
// \see esp32_usb_hid_device.cpp, esp32_usb_device_msc.cpp, esp32_usb_midi_device.cpp
|
||||
if (ctx->active_class != USB_DEVICE_CLASS_NONE) {
|
||||
release(device, ctx->active_class);
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/keyboard.h>
|
||||
#include <tactility/drivers/usb_host_hid.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
@ -26,6 +27,7 @@ constexpr auto HID_PROC_TASK_STACK = 4096;
|
||||
constexpr auto HID_PROC_TASK_PRIORITY = 5;
|
||||
constexpr auto HID_STOP_TIMEOUT_MS = 2000;
|
||||
constexpr auto MAX_SUBSCRIBERS = 4;
|
||||
constexpr auto USB_HID_KB_QUEUE_SIZE = 16;
|
||||
|
||||
typedef struct {
|
||||
hid_host_device_handle_t handle;
|
||||
@ -53,8 +55,20 @@ struct UsbHidContext {
|
||||
|
||||
QueueHandle_t subscribers[MAX_SUBSCRIBERS] = {};
|
||||
SemaphoreHandle_t sub_mutex = nullptr;
|
||||
|
||||
// The controller Device itself (set in start_device()), used as the parent for kb_device.
|
||||
Device* controller_device = nullptr;
|
||||
// Dynamic KEYBOARD_TYPE child device, constructed while a physical USB keyboard is connected.
|
||||
Device kb_device{};
|
||||
bool kb_device_active = false;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static void usb_hid_keyboard_device_construct(UsbHidContext* ctx);
|
||||
static void usb_hid_keyboard_device_destruct(UsbHidContext* ctx);
|
||||
static void usb_hid_keyboard_publish_key(UsbHidContext* ctx, uint32_t lv_key, bool pressed, bool ctrl, bool alt, uint8_t hid_keycode, uint8_t hid_modifier);
|
||||
}
|
||||
|
||||
static const uint8_t keycode2ascii[57][2] = {
|
||||
{0, 0}, {0, 0}, {0, 0}, {0, 0},
|
||||
{'a', 'A'}, {'b', 'B'}, {'c', 'C'}, {'d', 'D'}, {'e', 'E'},
|
||||
@ -182,8 +196,7 @@ static void hid_interface_callback(hid_host_device_handle_t handle,
|
||||
uint32_t lv_key = ctx->pressed_lv_keys[prev_hid];
|
||||
ctx->pressed_lv_keys[prev_hid] = 0;
|
||||
if (lv_key) {
|
||||
UsbHidEvent evt = { .type = USB_HID_EVENT_KEY, .key = { lv_key, false, with_ctrl, with_alt } };
|
||||
publish_event(ctx, &evt);
|
||||
usb_hid_keyboard_publish_key(ctx, lv_key, false, with_ctrl, with_alt, prev_hid, kb->modifier.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,11 +234,7 @@ static void hid_interface_callback(hid_host_device_handle_t handle,
|
||||
uint32_t lv_key = hid_keycode_to_key(kb->modifier.val, hid_code,
|
||||
ctx->caps_lock_active, ctx->num_lock_active);
|
||||
if (lv_key) {
|
||||
UsbHidEvent evt = {
|
||||
.type = USB_HID_EVENT_KEY,
|
||||
.key = { lv_key, true, with_ctrl, with_alt }
|
||||
};
|
||||
publish_event(ctx, &evt);
|
||||
usb_hid_keyboard_publish_key(ctx, lv_key, true, with_ctrl, with_alt, hid_code, kb->modifier.val);
|
||||
ctx->pressed_lv_keys[hid_code] = lv_key;
|
||||
}
|
||||
}
|
||||
@ -271,6 +280,7 @@ static void hid_interface_callback(hid_host_device_handle_t handle,
|
||||
memset(ctx->pressed_lv_keys, 0, sizeof(ctx->pressed_lv_keys));
|
||||
ctx->kb_handle.store(nullptr);
|
||||
ctx->kb_led_pending.store(false);
|
||||
usb_hid_keyboard_device_destruct(ctx);
|
||||
} else if (params.proto == HID_PROTOCOL_MOUSE) {
|
||||
ctx->mouse_connected = false;
|
||||
}
|
||||
@ -349,6 +359,7 @@ static void hid_proc_task(void* arg) {
|
||||
| (ctx->caps_lock_active ? 0x02 : 0)
|
||||
| (ctx->scroll_lock_active ? 0x04 : 0);
|
||||
hid_class_request_set_report(dev_evt.handle, HID_REPORT_TYPE_OUTPUT, 0, &leds, 1);
|
||||
usb_hid_keyboard_device_construct(ctx);
|
||||
} else if (params.proto == HID_PROTOCOL_MOUSE) {
|
||||
ctx->mouse_connected = true;
|
||||
}
|
||||
@ -419,8 +430,122 @@ static const UsbHidApi hid_api = {
|
||||
|
||||
extern "C" {
|
||||
|
||||
// region Dynamic KEYBOARD_TYPE device
|
||||
//
|
||||
// While a physical USB keyboard is connected, a KEYBOARD_TYPE child device is constructed so the
|
||||
// rest of the system (lvgl_hardware_keyboard_is_available(), Tactility's KeyboardDeviceListener)
|
||||
// sees a real hardware keyboard through the same generic device model as any other keyboard, e.g.
|
||||
// Devices/m5stack-tab5/Source/devices/tab5_keyboard.cpp. Real key events are delivered exclusively
|
||||
// through this device (kb_handle's hid_interface_callback pushes into its queue below); the
|
||||
// generic UsbHidEvent publish/subscribe channel above is unaffected for mouse move/button/scroll
|
||||
// and the right-click-as-ESC synthesis it already does.
|
||||
|
||||
static error_t usb_hid_kb_device_start(Device* device) {
|
||||
auto* queue = xQueueCreate(USB_HID_KB_QUEUE_SIZE, sizeof(KeyboardKeyData));
|
||||
if (queue == nullptr) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
device_set_driver_data(device, queue);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t usb_hid_kb_device_stop(Device* device) {
|
||||
auto* queue = static_cast<QueueHandle_t>(device_get_driver_data(device));
|
||||
vQueueDelete(queue);
|
||||
device_set_driver_data(device, nullptr);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t usb_hid_kb_device_read_key(Device* device, KeyboardKeyData* data) {
|
||||
auto* queue = static_cast<QueueHandle_t>(device_get_driver_data(device));
|
||||
if (queue == nullptr) {
|
||||
*data = {};
|
||||
return ERROR_NONE;
|
||||
}
|
||||
if (xQueueReceive(queue, data, 0) != pdTRUE) {
|
||||
*data = {};
|
||||
return ERROR_NONE;
|
||||
}
|
||||
data->continue_reading = uxQueueMessagesWaiting(queue) > 0;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static const KeyboardApi esp32_usbhost_hid_keyboard_api = {
|
||||
.read_key = usb_hid_kb_device_read_key,
|
||||
.get_backlight = nullptr,
|
||||
.is_present = nullptr,
|
||||
};
|
||||
|
||||
Driver esp32_usbhost_hid_keyboard_driver = {
|
||||
.name = "esp32_usbhost_hid_keyboard",
|
||||
.compatible = (const char*[]) { nullptr },
|
||||
.start_device = usb_hid_kb_device_start,
|
||||
.stop_device = usb_hid_kb_device_stop,
|
||||
.api = &esp32_usbhost_hid_keyboard_api,
|
||||
.device_type = &KEYBOARD_TYPE,
|
||||
.owner = nullptr,
|
||||
.internal = nullptr,
|
||||
};
|
||||
|
||||
static void usb_hid_keyboard_device_construct(UsbHidContext* ctx) {
|
||||
if (ctx->kb_device_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->kb_device = Device {
|
||||
.address = 0,
|
||||
.name = "usb_keyboard0",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr,
|
||||
};
|
||||
|
||||
if (device_construct(&ctx->kb_device) != ERROR_NONE) {
|
||||
LOG_E(TAG, "failed to construct USB keyboard device");
|
||||
return;
|
||||
}
|
||||
device_set_parent(&ctx->kb_device, ctx->controller_device);
|
||||
device_set_driver(&ctx->kb_device, &esp32_usbhost_hid_keyboard_driver);
|
||||
if (device_add(&ctx->kb_device) != ERROR_NONE) {
|
||||
LOG_E(TAG, "failed to add USB keyboard device");
|
||||
device_destruct(&ctx->kb_device);
|
||||
return;
|
||||
}
|
||||
if (device_start(&ctx->kb_device) != ERROR_NONE) {
|
||||
LOG_E(TAG, "failed to start USB keyboard device");
|
||||
device_remove(&ctx->kb_device);
|
||||
device_destruct(&ctx->kb_device);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->kb_device_active = true;
|
||||
}
|
||||
|
||||
static void usb_hid_keyboard_device_destruct(UsbHidContext* ctx) {
|
||||
if (!ctx->kb_device_active) {
|
||||
return;
|
||||
}
|
||||
ctx->kb_device_active = false;
|
||||
|
||||
device_stop(&ctx->kb_device);
|
||||
device_remove(&ctx->kb_device);
|
||||
device_destruct(&ctx->kb_device);
|
||||
}
|
||||
|
||||
static void usb_hid_keyboard_publish_key(UsbHidContext* ctx, uint32_t lv_key, bool pressed, bool ctrl, bool alt, uint8_t hid_keycode, uint8_t hid_modifier) {
|
||||
if (!ctx->kb_device_active) {
|
||||
return;
|
||||
}
|
||||
auto* queue = static_cast<QueueHandle_t>(device_get_driver_data(&ctx->kb_device));
|
||||
KeyboardKeyData data = { lv_key, pressed, false, ctrl, alt, hid_keycode, hid_modifier };
|
||||
xQueueSend(queue, &data, 0);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static error_t start_device(struct Device* device) {
|
||||
auto* ctx = new UsbHidContext();
|
||||
ctx->controller_device = device;
|
||||
|
||||
ctx->sub_mutex = xSemaphoreCreateMutex();
|
||||
if (!ctx->sub_mutex) {
|
||||
@ -486,6 +611,13 @@ static error_t stop_device(struct Device* device) {
|
||||
auto* ctx = static_cast<UsbHidContext*>(device_get_driver_data(device));
|
||||
if (!ctx) return ERROR_NONE;
|
||||
|
||||
// hid_host_device_close() halts and flushes the pending IN transfer before returning, so no
|
||||
// hid_interface_callback() for this handle can race the queue delete below.
|
||||
if (auto kb_handle = ctx->kb_handle.load()) {
|
||||
hid_host_device_close(kb_handle);
|
||||
}
|
||||
usb_hid_keyboard_device_destruct(ctx);
|
||||
|
||||
ctx->hid_proc_running = false;
|
||||
|
||||
if (xSemaphoreTake(ctx->hid_proc_task_done, pdMS_TO_TICKS(HID_STOP_TIMEOUT_MS)) != pdTRUE) {
|
||||
|
||||
@ -40,6 +40,7 @@ extern Driver esp32_ble_hid_device_driver;
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
extern Driver esp32_usbhost_driver;
|
||||
extern Driver esp32_usbhost_hid_driver;
|
||||
extern Driver esp32_usbhost_hid_keyboard_driver;
|
||||
extern Driver esp32_usbhost_midi_driver;
|
||||
extern Driver esp32_usbhost_msc_driver;
|
||||
#endif
|
||||
@ -91,6 +92,7 @@ static error_t start() {
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
check(driver_construct_add(&esp32_usbhost_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_hid_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_hid_keyboard_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
||||
check(driver_construct_add(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
||||
#endif
|
||||
@ -141,6 +143,7 @@ static error_t stop() {
|
||||
#if SOC_USB_OTG_SUPPORTED
|
||||
check(driver_remove_destruct(&esp32_usbhost_msc_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_midi_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_hid_keyboard_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_hid_driver) == ERROR_NONE);
|
||||
check(driver_remove_destruct(&esp32_usbhost_driver) == ERROR_NONE);
|
||||
#endif
|
||||
|
||||
@ -6,6 +6,7 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
list(APPEND REQUIRES_LIST
|
||||
TactilityKernel
|
||||
TactilityKernelCpp
|
||||
TactilityFreeRtos
|
||||
lvgl-module
|
||||
lvgl-window-manager-module
|
||||
|
||||
21
Tactility/Include/Tactility/lvgl/KeyboardDeviceListener.h
Normal file
21
Tactility/Include/Tactility/lvgl/KeyboardDeviceListener.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace tt::lvgl {
|
||||
|
||||
/**
|
||||
* @brief Starts listening for KEYBOARD_TYPE kernel devices being started/stopped at runtime
|
||||
* (e.g. a USB HID keyboard being plugged in/out) and binds/unbinds each one to LVGL via
|
||||
* lvgl_keyboard_add()/lvgl_keyboard_remove().
|
||||
*
|
||||
* Devices already started before this is called are picked up by lvgl-module's own boot-time
|
||||
* scan instead (see Modules/lvgl-module/source/devices/devices.cpp's lvgl_devices_attach()) -
|
||||
* this only reacts to devices that start/stop afterwards.
|
||||
*/
|
||||
void startKeyboardDeviceListener();
|
||||
|
||||
/**
|
||||
* @brief Stops listening and unbinds every KEYBOARD_TYPE device this listener bound to LVGL.
|
||||
*/
|
||||
void stopKeyboardDeviceListener();
|
||||
|
||||
} // namespace tt::lvgl
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <TactilityCpp/Allocator.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -16,6 +18,10 @@ struct AppHubEntry {
|
||||
std::string file;
|
||||
};
|
||||
|
||||
bool parseJson(const std::string& filePath, std::vector<AppHubEntry>& entries);
|
||||
// The top-level entries buffer prefers PSRAM/SPIRAM via OptExternalAllocator; individual
|
||||
// AppHubEntry string/vector members still use the default (internal-RAM) allocator.
|
||||
using AppHubEntryList = std::vector<AppHubEntry, OptExternalAllocator<AppHubEntry>>;
|
||||
|
||||
bool parseJson(const std::string& filePath, AppHubEntryList& entries);
|
||||
|
||||
}
|
||||
@ -25,6 +25,7 @@
|
||||
#include <Tactility/bluetooth/Bluetooth.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/hal/SdCard.h>
|
||||
#include <Tactility/lvgl/KeyboardDeviceListener.h>
|
||||
#include <Tactility/lvgl/Statusbar.h>
|
||||
#include <Tactility/lvgl/TrackballInit.h>
|
||||
#include <Tactility/lvgl/UsbHidInput.h>
|
||||
@ -441,6 +442,7 @@ static void onLvglStarted() {
|
||||
#endif
|
||||
|
||||
lvgl::startUsbHidInput();
|
||||
lvgl::startKeyboardDeviceListener();
|
||||
lvgl::initTrackball();
|
||||
|
||||
#ifdef CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED
|
||||
@ -457,6 +459,7 @@ static void onLvglStopped() {
|
||||
|
||||
module_stop(&lvgl_window_manager_module);
|
||||
|
||||
lvgl::stopKeyboardDeviceListener();
|
||||
lvgl::stopUsbHidInput();
|
||||
|
||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||
|
||||
@ -237,7 +237,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AddGps",
|
||||
.id = "tactility.addgps",
|
||||
.name = "Add GPS",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -152,7 +152,7 @@ uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AlertDialog",
|
||||
.id = "tactility.alertdialog",
|
||||
.name = "Alert Dialog",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -162,7 +162,7 @@ void start(const std::string& appId) {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AppDetails",
|
||||
.id = "tactility.appdetails",
|
||||
.name = "App Details",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -36,8 +36,11 @@ struct Context {
|
||||
lv_obj_t* contentWrapper = nullptr;
|
||||
lv_obj_t* refreshButton = nullptr;
|
||||
std::string cachedAppsJsonFile = std::format("{}/app_hub.json", getTempPath());
|
||||
std::vector<AppHubEntry> entries;
|
||||
AppHubEntryList entries;
|
||||
Mutex mutex;
|
||||
|
||||
// Survives across a bury/resurface cycle (e.g. opening AppHubDetailsApp and returning),
|
||||
int32_t scrollY = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -46,10 +49,6 @@ void refresh(Context* ctx);
|
||||
|
||||
void onBackPressed(lv_event_t* event) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
|
||||
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
|
||||
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
|
||||
// deadlock against itself.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
@ -86,9 +85,25 @@ void showNoInternet(Context* ctx) {
|
||||
}
|
||||
|
||||
void showApps(Context* ctx) {
|
||||
// Refresh rebuilds the list from scratch (cached copy, then again once the network fetch
|
||||
// lands), which would otherwise reset the user's scroll position each time.
|
||||
auto scrollY = lv_obj_get_scroll_y(ctx->contentWrapper);
|
||||
lv_obj_clean(ctx->contentWrapper);
|
||||
ctx->mutex.lock();
|
||||
if (parseJson(ctx->cachedAppsJsonFile, ctx->entries)) {
|
||||
// An empty targetPlatforms list means the entry runs everywhere; otherwise it must name
|
||||
// this build's own target to be installable here. The simulator isn't a real MCU target,
|
||||
// so it has nothing to match against and skips this filter entirely.
|
||||
std::erase_if(ctx->entries, [](const AppHubEntry& entry) {
|
||||
#ifdef ESP_PLATFORM
|
||||
return !entry.targetPlatforms.empty() &&
|
||||
std::ranges::find(entry.targetPlatforms, CONFIG_IDF_TARGET) == entry.targetPlatforms.end();
|
||||
#else
|
||||
(void)entry;
|
||||
return false;
|
||||
#endif
|
||||
});
|
||||
|
||||
std::ranges::sort(ctx->entries, [](auto left, auto right) {
|
||||
return left.appName < right.appName;
|
||||
});
|
||||
@ -106,6 +121,8 @@ void showApps(Context* ctx) {
|
||||
lv_obj_set_user_data(entry_button, int_as_voidptr);
|
||||
lv_obj_add_event_cb(entry_button, onAppPressed, LV_EVENT_SHORT_CLICKED, ctx);
|
||||
}
|
||||
|
||||
lv_obj_scroll_to_y(ctx->contentWrapper, scrollY, LV_ANIM_OFF);
|
||||
} else {
|
||||
showRefreshFailedError(ctx, "Failed to load content");
|
||||
}
|
||||
@ -169,6 +186,15 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
lv_obj_set_style_pad_ver(ctx->contentWrapper, 0, LV_STATE_DEFAULT);
|
||||
|
||||
refresh(ctx);
|
||||
|
||||
lv_obj_scroll_to_y(ctx->contentWrapper, ctx->scrollY, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
void destroyWidgets(void* userData) {
|
||||
auto* ctx = static_cast<Context*>(userData);
|
||||
ctx->scrollY = lv_obj_get_scroll_y(ctx->contentWrapper);
|
||||
ctx->contentWrapper = nullptr;
|
||||
ctx->refreshButton = nullptr;
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
@ -179,7 +205,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
@ -206,7 +232,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AppHub",
|
||||
.id = "tactility.apphub",
|
||||
.name = "App Hub",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -20,7 +20,7 @@ static bool parseEntry(const cJSON* object, AppHubEntry& entry) {
|
||||
reader.readStringArray("targetPlatforms", entry.targetPlatforms);
|
||||
}
|
||||
|
||||
bool parseJson(const std::string& filePath, std::vector<AppHubEntry>& entries) {
|
||||
bool parseJson(const std::string& filePath, AppHubEntryList& entries) {
|
||||
file::FileMutexGuard guard(filePath);
|
||||
|
||||
auto data = file::readString(filePath);
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
#include "../../../../Modules/app-module/private/app/private/app_ledger.h"
|
||||
#include "app/metadata.h"
|
||||
|
||||
|
||||
#include <Tactility/DeprecatedPaths.h>
|
||||
#include <Tactility/StringUtils.h>
|
||||
#include <Tactility/app/alertdialog/AlertDialog.h>
|
||||
@ -12,6 +8,7 @@
|
||||
|
||||
#include <app/event.h>
|
||||
#include <app/install.h>
|
||||
#include <app/metadata.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
|
||||
@ -64,10 +61,6 @@ uint32_t showConfirmDialog(Context* ctx, const char* action) {
|
||||
|
||||
void onBackPressed(lv_event_t* e) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
|
||||
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
|
||||
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
|
||||
// deadlock against itself.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
@ -308,7 +301,7 @@ void start(const apphub::AppHubEntry& entry) {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AppHubDetails",
|
||||
.id = "tactility.apphubdetails",
|
||||
.name = "App Details",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -106,7 +106,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AppList",
|
||||
.id = "tactility.applist",
|
||||
.name = "Apps",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -121,7 +121,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AppSettings",
|
||||
.id = "tactility.appsettings",
|
||||
.name = "Apps",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -176,7 +176,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "ApWebServer",
|
||||
.id = "tactility.apwebserver",
|
||||
.name = "AP Web Server",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -251,7 +251,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "AudioSettings",
|
||||
.id = "tactility.audiosettings",
|
||||
.name = "Audio",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -326,7 +326,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Boot",
|
||||
.id = "tactility.boot",
|
||||
.name = "Boot",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -283,7 +283,7 @@ uint32_t start() {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "BtManage",
|
||||
.id = "tactility.btmanage",
|
||||
.name = "Bluetooth",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -256,7 +256,7 @@ void start(const std::string& addrHex) {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "BtPeerSettings",
|
||||
.id = "tactility.btpeersettings",
|
||||
.name = "BT Device Settings",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -219,7 +219,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Chat",
|
||||
.id = "tactility.chat",
|
||||
.name = "Chat",
|
||||
.category = APP_CATEGORY_USER,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
#include <Tactility/app/chat/ChatSettings.h>
|
||||
#include <Tactility/app/chat/ChatProtocol.h>
|
||||
|
||||
#include <Tactility/DeprecatedPaths.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
|
||||
#include <app/paths.h>
|
||||
#include <crypt/crypt.h>
|
||||
|
||||
#include <esp_random.h>
|
||||
@ -28,7 +28,11 @@ namespace tt::app::chat {
|
||||
constexpr auto* TAG = "ChatSettings";
|
||||
|
||||
static std::string getSettingsFilePath() {
|
||||
return getUserDataPath() + "/settings/chat.properties";
|
||||
char path[256];
|
||||
if (app_paths_get_user_data_path("tactility.chat", "chat.properties", path, sizeof(path)) != ERROR_NONE) {
|
||||
return "";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
constexpr auto* KEY_SENDER_ID = "senderId";
|
||||
|
||||
@ -199,7 +199,7 @@ void start() {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "CrashDiagnostics",
|
||||
.id = "tactility.crashdiagnostics",
|
||||
.name = "Crash Diagnostics",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -226,7 +226,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Development",
|
||||
.id = "tactility.development",
|
||||
.name = "Development",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -66,7 +66,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Files",
|
||||
.id = "tactility.files",
|
||||
.name = "Files",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -106,7 +106,7 @@ uint32_t startForExistingOrNewFile(uint32_t callerAppInstanceId) {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "FileSelection",
|
||||
.id = "tactility.fileselection",
|
||||
.name = "File Selection",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -320,7 +320,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "GpsSettings",
|
||||
.id = "tactility.gpssettings",
|
||||
.name = "GPS",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -124,7 +124,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "GroveSettings",
|
||||
.id = "tactility.grovesettings",
|
||||
.name = "Grove",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -419,7 +419,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "I2cScanner",
|
||||
.id = "tactility.i2cscanner",
|
||||
.name = "I2C Scanner",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -126,7 +126,7 @@ void start(const std::string& file) {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "ImageViewer",
|
||||
.id = "tactility.imageviewer",
|
||||
.name = "Image Viewer",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -148,7 +148,7 @@ std::string getLastText() {
|
||||
}
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "InputDialog",
|
||||
.id = "tactility.inputdialog",
|
||||
.name = "Input Dialog",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -340,7 +340,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Display",
|
||||
.id = "tactility.display",
|
||||
.name = "Display",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -241,7 +241,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "KeyboardSettings",
|
||||
.id = "tactility.keyboardsettings",
|
||||
.name = "Keyboard",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
@ -168,9 +168,9 @@ void createWidgets(lv_obj_t* parent, void*) {
|
||||
? computeButtonMargin(lv_display_get_horizontal_resolution(display), total_button_size)
|
||||
: computeButtonMargin(lv_display_get_vertical_resolution(display), total_button_size);
|
||||
|
||||
auto* app_list_button = createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_APPS, "AppList", margin, is_landscape_display);
|
||||
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_FOLDER, "Files", margin, is_landscape_display);
|
||||
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_SETTINGS, "Settings", margin, is_landscape_display);
|
||||
auto* app_list_button = createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_APPS, "tactility.applist", margin, is_landscape_display);
|
||||
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_FOLDER, "tactility.files", margin, is_landscape_display);
|
||||
createAppButton(buttons_wrapper, ui_density, LVGL_ICON_LAUNCHER_SETTINGS, "tactility.settings", margin, is_landscape_display);
|
||||
|
||||
// The launcher's container is several levels below the screen, and LVGL only sends
|
||||
// LV_EVENT_SIZE_CHANGED to the screen object itself on a resolution change - so the
|
||||
@ -184,7 +184,7 @@ void createWidgets(lv_obj_t* parent, void*) {
|
||||
auto* power_button = lv_button_create(parent);
|
||||
lv_obj_set_style_pad_all(power_button, 8, 0);
|
||||
lv_obj_align(power_button, LV_ALIGN_BOTTOM_MID, 0, -10);
|
||||
lv_obj_add_event_cb(power_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)"PowerOff");
|
||||
lv_obj_add_event_cb(power_button, onAppPressed, LV_EVENT_SHORT_CLICKED, (void*)"tactility.poweroff");
|
||||
lv_obj_set_style_shadow_width(power_button, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(power_button, 0, LV_PART_MAIN);
|
||||
|
||||
@ -261,7 +261,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "Launcher",
|
||||
.id = "tactility.launcher",
|
||||
.name = "Launcher",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
|
||||
@ -176,7 +176,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "LocaleSettings",
|
||||
.id = "tactility.localesettings",
|
||||
.name = "Region & Language",
|
||||
.category = APP_CATEGORY_SETTINGS,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user