diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c6152f73..ff2a8f874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/Devices/btt-panda-touch/device.properties b/Devices/btt-panda-touch/device.properties index 8e65fa6d2..4bab9a870 100644 --- a/Devices/btt-panda-touch/device.properties +++ b/Devices/btt-panda-touch/device.properties @@ -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 diff --git a/Devices/cl32/device.properties b/Devices/cl32/device.properties index 09ed3d8da..98ce693ff 100644 --- a/Devices/cl32/device.properties +++ b/Devices/cl32/device.properties @@ -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 diff --git a/Devices/cyd-2432s024c/device.properties b/Devices/cyd-2432s024c/device.properties index 0f2a5c1de..aac1bb88f 100644 --- a/Devices/cyd-2432s024c/device.properties +++ b/Devices/cyd-2432s024c/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=2432S024C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-2432s024r/device.properties b/Devices/cyd-2432s024r/device.properties index b2e05d040..d9e22b351 100644 --- a/Devices/cyd-2432s024r/device.properties +++ b/Devices/cyd-2432s024r/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=2432S024R -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-2432s028r/device.properties b/Devices/cyd-2432s028r/device.properties index 847dc1fb0..4559a5c63 100644 --- a/Devices/cyd-2432s028r/device.properties +++ b/Devices/cyd-2432s028r/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=2432S028R -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-2432s028rv3/device.properties b/Devices/cyd-2432s028rv3/device.properties index 332e1ed11..303a2ad6c 100644 --- a/Devices/cyd-2432s028rv3/device.properties +++ b/Devices/cyd-2432s028rv3/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=2432S028R v3 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-2432s032c/device.properties b/Devices/cyd-2432s032c/device.properties index e483bd8c2..ffcd24643 100644 --- a/Devices/cyd-2432s032c/device.properties +++ b/Devices/cyd-2432s032c/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=2432S032C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-3248s035c/device.properties b/Devices/cyd-3248s035c/device.properties index c8fc929d1..7e468efc9 100644 --- a/Devices/cyd-3248s035c/device.properties +++ b/Devices/cyd-3248s035c/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=3248S035C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-4848s040c/device.properties b/Devices/cyd-4848s040c/device.properties index 45c66c54e..ba432221a 100644 --- a/Devices/cyd-4848s040c/device.properties +++ b/Devices/cyd-4848s040c/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=4848S040C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/cyd-8048s043c/device.properties b/Devices/cyd-8048s043c/device.properties index 8056421d5..d89583ac2 100644 --- a/Devices/cyd-8048s043c/device.properties +++ b/Devices/cyd-8048s043c/device.properties @@ -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 diff --git a/Devices/cyd-e32r28t/device.properties b/Devices/cyd-e32r28t/device.properties index 097eaa62d..e97a5ef5b 100644 --- a/Devices/cyd-e32r28t/device.properties +++ b/Devices/cyd-e32r28t/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=E32R28T -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/cyd-e32r32p/device.properties b/Devices/cyd-e32r32p/device.properties index 27f2ad0a6..e2627342d 100644 --- a/Devices/cyd-e32r32p/device.properties +++ b/Devices/cyd-e32r32p/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=E32R32P -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/elecrow-crowpanel-advance-28/device.properties b/Devices/elecrow-crowpanel-advance-28/device.properties index c17ec1404..a94a9e8d0 100644 --- a/Devices/elecrow-crowpanel-advance-28/device.properties +++ b/Devices/elecrow-crowpanel-advance-28/device.properties @@ -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 diff --git a/Devices/elecrow-crowpanel-advance-35/device.properties b/Devices/elecrow-crowpanel-advance-35/device.properties index 29851d8d2..4e4960227 100644 --- a/Devices/elecrow-crowpanel-advance-35/device.properties +++ b/Devices/elecrow-crowpanel-advance-35/device.properties @@ -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 diff --git a/Devices/elecrow-crowpanel-advance-50/device.properties b/Devices/elecrow-crowpanel-advance-50/device.properties index 7b0e0246a..9840c228b 100644 --- a/Devices/elecrow-crowpanel-advance-50/device.properties +++ b/Devices/elecrow-crowpanel-advance-50/device.properties @@ -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 diff --git a/Devices/elecrow-crowpanel-basic-28/device.properties b/Devices/elecrow-crowpanel-basic-28/device.properties index acc1405a4..58ee43716 100644 --- a/Devices/elecrow-crowpanel-basic-28/device.properties +++ b/Devices/elecrow-crowpanel-basic-28/device.properties @@ -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 diff --git a/Devices/elecrow-crowpanel-basic-35/device.properties b/Devices/elecrow-crowpanel-basic-35/device.properties index cb07c7757..4f2471d28 100644 --- a/Devices/elecrow-crowpanel-basic-35/device.properties +++ b/Devices/elecrow-crowpanel-basic-35/device.properties @@ -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 diff --git a/Devices/elecrow-crowpanel-basic-50/device.properties b/Devices/elecrow-crowpanel-basic-50/device.properties index 3d9425edf..7e0b5e18d 100644 --- a/Devices/elecrow-crowpanel-basic-50/device.properties +++ b/Devices/elecrow-crowpanel-basic-50/device.properties @@ -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 diff --git a/Devices/es3c28p/device.properties b/Devices/es3c28p/device.properties index 51c42c137..7140e6178 100644 --- a/Devices/es3c28p/device.properties +++ b/Devices/es3c28p/device.properties @@ -1,7 +1,7 @@ general.vendor=CYD general.name=ES3C28P -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/generic-esp32/device.properties b/Devices/generic-esp32/device.properties index 8b803a84d..d1d130b54 100644 --- a/Devices/generic-esp32/device.properties +++ b/Devices/generic-esp32/device.properties @@ -1,7 +1,7 @@ general.vendor=Generic general.name=ESP32 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=8MB diff --git a/Devices/generic-esp32c6/device.properties b/Devices/generic-esp32c6/device.properties index bd332c250..07ce7ed4d 100644 --- a/Devices/generic-esp32c6/device.properties +++ b/Devices/generic-esp32c6/device.properties @@ -1,7 +1,7 @@ general.vendor=Generic general.name=ESP32-C6 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32C6 hardware.flashSize=8MB diff --git a/Devices/generic-esp32p4/device.properties b/Devices/generic-esp32p4/device.properties index 4a050b399..815fac6e7 100644 --- a/Devices/generic-esp32p4/device.properties +++ b/Devices/generic-esp32p4/device.properties @@ -1,7 +1,7 @@ general.vendor=Generic general.name=ESP32-P4 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32P4 hardware.flashSize=8MB diff --git a/Devices/generic-esp32s3/device.properties b/Devices/generic-esp32s3/device.properties index 8512a4506..cf04146bd 100644 --- a/Devices/generic-esp32s3/device.properties +++ b/Devices/generic-esp32s3/device.properties @@ -1,7 +1,7 @@ general.vendor=Generic general.name=ESP32-S3 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=8MB diff --git a/Devices/guition-jc1060p470ciwy/device.properties b/Devices/guition-jc1060p470ciwy/device.properties index fcc7421ee..c126dc66b 100644 --- a/Devices/guition-jc1060p470ciwy/device.properties +++ b/Devices/guition-jc1060p470ciwy/device.properties @@ -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 diff --git a/Devices/guition-jc2432w328c/device.properties b/Devices/guition-jc2432w328c/device.properties index 7ef40633b..f2c06450f 100644 --- a/Devices/guition-jc2432w328c/device.properties +++ b/Devices/guition-jc2432w328c/device.properties @@ -1,7 +1,7 @@ general.vendor=Guition general.name=JC2432W328C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=4MB diff --git a/Devices/guition-jc8048w550c/device.properties b/Devices/guition-jc8048w550c/device.properties index 3cebf4d42..fb2540242 100644 --- a/Devices/guition-jc8048w550c/device.properties +++ b/Devices/guition-jc8048w550c/device.properties @@ -1,7 +1,7 @@ general.vendor=Guition general.name=JC8048W550C -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/heltec-wifi-lora-32-v3/device.properties b/Devices/heltec-wifi-lora-32-v3/device.properties index b656de2e2..aa55fb021 100644 --- a/Devices/heltec-wifi-lora-32-v3/device.properties +++ b/Devices/heltec-wifi-lora-32-v3/device.properties @@ -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 diff --git a/Devices/lilygo-tdeck-max/device.properties b/Devices/lilygo-tdeck-max/device.properties index 379418968..2df9188c0 100644 --- a/Devices/lilygo-tdeck-max/device.properties +++ b/Devices/lilygo-tdeck-max/device.properties @@ -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 diff --git a/Devices/lilygo-tdeck-plus/device.properties b/Devices/lilygo-tdeck-plus/device.properties index aa12e18ae..b9a460775 100644 --- a/Devices/lilygo-tdeck-plus/device.properties +++ b/Devices/lilygo-tdeck-plus/device.properties @@ -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 diff --git a/Devices/lilygo-tdeck-pro/device.properties b/Devices/lilygo-tdeck-pro/device.properties index 63781264a..f7d383006 100644 --- a/Devices/lilygo-tdeck-pro/device.properties +++ b/Devices/lilygo-tdeck-pro/device.properties @@ -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 diff --git a/Devices/lilygo-tdeck/device.properties b/Devices/lilygo-tdeck/device.properties index 8e84bd536..512c11681 100644 --- a/Devices/lilygo-tdeck/device.properties +++ b/Devices/lilygo-tdeck/device.properties @@ -1,7 +1,7 @@ general.vendor=LilyGO general.name=T-Deck -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/lilygo-tdisplay-s3/device.properties b/Devices/lilygo-tdisplay-s3/device.properties index 6936ecbaf..8c1fd943d 100644 --- a/Devices/lilygo-tdisplay-s3/device.properties +++ b/Devices/lilygo-tdisplay-s3/device.properties @@ -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 diff --git a/Devices/lilygo-tdisplay/device.properties b/Devices/lilygo-tdisplay/device.properties index 590086137..c303178b4 100644 --- a/Devices/lilygo-tdisplay/device.properties +++ b/Devices/lilygo-tdisplay/device.properties @@ -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 diff --git a/Devices/lilygo-tdongle-s3/device.properties b/Devices/lilygo-tdongle-s3/device.properties index 4b68fa89c..6bdcf84d4 100644 --- a/Devices/lilygo-tdongle-s3/device.properties +++ b/Devices/lilygo-tdongle-s3/device.properties @@ -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 diff --git a/Devices/lilygo-thmi/device.properties b/Devices/lilygo-thmi/device.properties index 46fb227c7..b2676f753 100644 --- a/Devices/lilygo-thmi/device.properties +++ b/Devices/lilygo-thmi/device.properties @@ -1,7 +1,7 @@ general.vendor=LilyGO general.name=T-HMI -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/lilygo-tlora-pager/device.properties b/Devices/lilygo-tlora-pager/device.properties index 0c820c81b..e9cfa96ee 100644 --- a/Devices/lilygo-tlora-pager/device.properties +++ b/Devices/lilygo-tlora-pager/device.properties @@ -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 diff --git a/Devices/m5stack-cardputer-adv/device.properties b/Devices/m5stack-cardputer-adv/device.properties index ef8018f15..dcbe6a8bd 100644 --- a/Devices/m5stack-cardputer-adv/device.properties +++ b/Devices/m5stack-cardputer-adv/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=Cardputer Adv -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=8MB diff --git a/Devices/m5stack-cardputer/device.properties b/Devices/m5stack-cardputer/device.properties index 96ba51432..6f4f0529a 100644 --- a/Devices/m5stack-cardputer/device.properties +++ b/Devices/m5stack-cardputer/device.properties @@ -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 diff --git a/Devices/m5stack-core2/device.properties b/Devices/m5stack-core2/device.properties index 2bda9c380..0df414df0 100644 --- a/Devices/m5stack-core2/device.properties +++ b/Devices/m5stack-core2/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=Core2 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=16MB diff --git a/Devices/m5stack-cores3/device.properties b/Devices/m5stack-cores3/device.properties index a06fe84b9..d20fc67dd 100644 --- a/Devices/m5stack-cores3/device.properties +++ b/Devices/m5stack-cores3/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=CoreS3 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/m5stack-papers3/device.properties b/Devices/m5stack-papers3/device.properties index edd194126..ab703f9d9 100644 --- a/Devices/m5stack-papers3/device.properties +++ b/Devices/m5stack-papers3/device.properties @@ -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 diff --git a/Devices/m5stack-stackchan/device.properties b/Devices/m5stack-stackchan/device.properties index edd65a81c..e145ac025 100644 --- a/Devices/m5stack-stackchan/device.properties +++ b/Devices/m5stack-stackchan/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=StackChan -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=16MB diff --git a/Devices/m5stack-stickc-plus2/device.properties b/Devices/m5stack-stickc-plus2/device.properties index 9178ad240..15cf14a13 100644 --- a/Devices/m5stack-stickc-plus2/device.properties +++ b/Devices/m5stack-stickc-plus2/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=StickC Plus2 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32 hardware.flashSize=8MB diff --git a/Devices/m5stack-sticks3/device.properties b/Devices/m5stack-sticks3/device.properties index f4d8df5db..afe3717c4 100644 --- a/Devices/m5stack-sticks3/device.properties +++ b/Devices/m5stack-sticks3/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=StickS3 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=8MB diff --git a/Devices/m5stack-tab5/device.properties b/Devices/m5stack-tab5/device.properties index 946c24842..38d7e4243 100644 --- a/Devices/m5stack-tab5/device.properties +++ b/Devices/m5stack-tab5/device.properties @@ -1,7 +1,7 @@ general.vendor=M5Stack general.name=Tab5 -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32P4 hardware.flashSize=16MB diff --git a/Devices/simulator/device.properties b/Devices/simulator/device.properties index 8406fffb3..1d1e7935f 100644 --- a/Devices/simulator/device.properties +++ b/Devices/simulator/device.properties @@ -1,7 +1,7 @@ general.vendor=Simulator general.name=Tab5Simulator -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=POSIX diff --git a/Devices/tulip-4r11/device.properties b/Devices/tulip-4r11/device.properties index c0ece6b84..9afa9cf72 100644 --- a/Devices/tulip-4r11/device.properties +++ b/Devices/tulip-4r11/device.properties @@ -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 diff --git a/Devices/unphone/device.properties b/Devices/unphone/device.properties index 45de3205b..e49500535 100644 --- a/Devices/unphone/device.properties +++ b/Devices/unphone/device.properties @@ -1,7 +1,7 @@ general.vendor=unPhone general.name=unPhone -apps.launcherAppId=Launcher +apps.launcherAppId=tactility.launcher hardware.target=ESP32S3 hardware.flashSize=8MB diff --git a/Devices/waveshare-esp32-s3-geek/device.properties b/Devices/waveshare-esp32-s3-geek/device.properties index 63695d23e..685e389ca 100644 --- a/Devices/waveshare-esp32-s3-geek/device.properties +++ b/Devices/waveshare-esp32-s3-geek/device.properties @@ -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 diff --git a/Devices/waveshare-s3-lcd-13/device.properties b/Devices/waveshare-s3-lcd-13/device.properties index 5e603fc40..e8752d276 100644 --- a/Devices/waveshare-s3-lcd-13/device.properties +++ b/Devices/waveshare-s3-lcd-13/device.properties @@ -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 diff --git a/Devices/waveshare-s3-touch-lcd-128/device.properties b/Devices/waveshare-s3-touch-lcd-128/device.properties index 58caf1d92..f73d29aa3 100644 --- a/Devices/waveshare-s3-touch-lcd-128/device.properties +++ b/Devices/waveshare-s3-touch-lcd-128/device.properties @@ -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 diff --git a/Devices/waveshare-s3-touch-lcd-147/device.properties b/Devices/waveshare-s3-touch-lcd-147/device.properties index 92f228724..d1f59300e 100644 --- a/Devices/waveshare-s3-touch-lcd-147/device.properties +++ b/Devices/waveshare-s3-touch-lcd-147/device.properties @@ -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 diff --git a/Devices/waveshare-s3-touch-lcd-43/device.properties b/Devices/waveshare-s3-touch-lcd-43/device.properties index 63b432e04..7d326801a 100644 --- a/Devices/waveshare-s3-touch-lcd-43/device.properties +++ b/Devices/waveshare-s3-touch-lcd-43/device.properties @@ -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. diff --git a/Devices/wireless-tag-wt32-sc01-plus/device.properties b/Devices/wireless-tag-wt32-sc01-plus/device.properties index 5d797a0cd..1c70f0135 100644 --- a/Devices/wireless-tag-wt32-sc01-plus/device.properties +++ b/Devices/wireless-tag-wt32-sc01-plus/device.properties @@ -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 diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 94dfea1df..c1c302c05 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -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() diff --git a/Drivers/audio-codec-module/README.md b/Drivers/audio-codec-module/README.md index 1c830dc99..478292787 100644 --- a/Drivers/audio-codec-module/README.md +++ b/Drivers/audio-codec-module/README.md @@ -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 diff --git a/Firmware/Kconfig b/Firmware/Kconfig index dd3e2ad51..813bbb54d 100644 --- a/Firmware/Kconfig +++ b/Firmware/Kconfig @@ -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. diff --git a/Modules/app-module/include/app/metadata.h b/Modules/app-module/include/app/metadata.h index 6cd039ec8..ae0a16db4 100644 --- a/Modules/app-module/include/app/metadata.h +++ b/Modules/app-module/include/app/metadata.h @@ -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]; }; /** diff --git a/Modules/app-module/private/app/private/app_metadata_parsing_internal.h b/Modules/app-module/private/app/private/app_metadata_parsing_internal.h index f611b0a50..9259e5691 100644 --- a/Modules/app-module/private/app/private/app_metadata_parsing_internal.h +++ b/Modules/app-module/private/app/private/app_metadata_parsing_internal.h @@ -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/ 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 */ diff --git a/Modules/app-module/source/app_metadata_parsing.cpp b/Modules/app-module/source/app_metadata_parsing.cpp index 208f7ea99..d1ca9c8de 100644 --- a/Modules/app-module/source/app_metadata_parsing.cpp +++ b/Modules/app-module/source/app_metadata_parsing.cpp @@ -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(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 properties; std::string first_line; if (!load_properties(path, properties, first_line)) { diff --git a/Modules/app-module/source/app_metadata_parsing_v2.cpp b/Modules/app-module/source/app_metadata_parsing_v2.cpp index fe7a58991..b6baaa0ab 100644 --- a/Modules/app-module/source/app_metadata_parsing_v2.cpp +++ b/Modules/app-module/source/app_metadata_parsing_v2.cpp @@ -99,5 +99,20 @@ bool app_metadata_parse_v2(const std::map& 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; } diff --git a/Modules/app-module/source/app_paths.cpp b/Modules/app-module/source/app_paths.cpp index eb7ac418a..fb102ac0a 100644 --- a/Modules/app-module/source/app_paths.cpp +++ b/Modules/app-module/source/app_paths.cpp @@ -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; } diff --git a/Modules/gps-module/source/gps_settings.cpp b/Modules/gps-module/source/gps_settings.cpp index 7023f75e0..7f9729d92 100644 --- a/Modules/gps-module/source/gps_settings.cpp +++ b/Modules/gps-module/source/gps_settings.cpp @@ -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 diff --git a/Modules/lvgl-module/source/devices/keyboard.cpp b/Modules/lvgl-module/source/devices/keyboard.cpp index e3319a983..02bee3d89 100644 --- a/Modules/lvgl-module/source/devices/keyboard.cpp +++ b/Modules/lvgl-module/source/devices/keyboard.cpp @@ -4,9 +4,12 @@ #include #include +#include #include +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(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); diff --git a/Platforms/platform-esp32/source/drivers/usb/esp32_usb_device_controller.cpp b/Platforms/platform-esp32/source/drivers/usb/esp32_usb_device_controller.cpp index d760f67a1..bccf09d19 100644 --- a/Platforms/platform-esp32/source/drivers/usb/esp32_usb_device_controller.cpp +++ b/Platforms/platform-esp32/source/drivers/usb/esp32_usb_device_controller.cpp @@ -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(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(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); } diff --git a/Platforms/platform-esp32/source/drivers/usb/esp32_usbhost_hid.cpp b/Platforms/platform-esp32/source/drivers/usb/esp32_usbhost_hid.cpp index dd55b1f73..00dbe6524 100644 --- a/Platforms/platform-esp32/source/drivers/usb/esp32_usbhost_hid.cpp +++ b/Platforms/platform-esp32/source/drivers/usb/esp32_usbhost_hid.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -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(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(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(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(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) { diff --git a/Platforms/platform-esp32/source/module.cpp b/Platforms/platform-esp32/source/module.cpp index 557be5474..8e2b492d3 100644 --- a/Platforms/platform-esp32/source/module.cpp +++ b/Platforms/platform-esp32/source/module.cpp @@ -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 diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index 3de858ac9..241713e02 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -6,6 +6,7 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*) list(APPEND REQUIRES_LIST TactilityKernel + TactilityKernelCpp TactilityFreeRtos lvgl-module lvgl-window-manager-module diff --git a/Tactility/Include/Tactility/lvgl/KeyboardDeviceListener.h b/Tactility/Include/Tactility/lvgl/KeyboardDeviceListener.h new file mode 100644 index 000000000..59c250a84 --- /dev/null +++ b/Tactility/Include/Tactility/lvgl/KeyboardDeviceListener.h @@ -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 diff --git a/Tactility/Private/Tactility/app/apphub/AppHubEntry.h b/Tactility/Private/Tactility/app/apphub/AppHubEntry.h index 4ec80e1c2..e498d52c6 100644 --- a/Tactility/Private/Tactility/app/apphub/AppHubEntry.h +++ b/Tactility/Private/Tactility/app/apphub/AppHubEntry.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,6 +18,10 @@ struct AppHubEntry { std::string file; }; -bool parseJson(const std::string& filePath, std::vector& 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>; + +bool parseJson(const std::string& filePath, AppHubEntryList& entries); } \ No newline at end of file diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 5c1181dde..d2e239edd 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/Tactility/Source/app/addgps/AddGps.cpp b/Tactility/Source/app/addgps/AddGps.cpp index 51979c57c..4d6cee6ab 100644 --- a/Tactility/Source/app/addgps/AddGps.cpp +++ b/Tactility/Source/app/addgps/AddGps.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/alertdialog/AlertDialog.cpp b/Tactility/Source/app/alertdialog/AlertDialog.cpp index eb8082ff5..6f143eddc 100644 --- a/Tactility/Source/app/alertdialog/AlertDialog.cpp +++ b/Tactility/Source/app/alertdialog/AlertDialog.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/appdetails/AppDetails.cpp b/Tactility/Source/app/appdetails/AppDetails.cpp index 34d810f43..e6feb3eb0 100644 --- a/Tactility/Source/app/appdetails/AppDetails.cpp +++ b/Tactility/Source/app/appdetails/AppDetails.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/apphub/AppHubApp.cpp b/Tactility/Source/app/apphub/AppHubApp.cpp index 8ede11b52..12257c888 100644 --- a/Tactility/Source/app/apphub/AppHubApp.cpp +++ b/Tactility/Source/app/apphub/AppHubApp.cpp @@ -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 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(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(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(appMain) } diff --git a/Tactility/Source/app/apphub/AppHubEntry.cpp b/Tactility/Source/app/apphub/AppHubEntry.cpp index a8dce05d4..441dbe6bb 100644 --- a/Tactility/Source/app/apphub/AppHubEntry.cpp +++ b/Tactility/Source/app/apphub/AppHubEntry.cpp @@ -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& entries) { +bool parseJson(const std::string& filePath, AppHubEntryList& entries) { file::FileMutexGuard guard(filePath); auto data = file::readString(filePath); diff --git a/Tactility/Source/app/apphubdetails/AppHubDetailsApp.cpp b/Tactility/Source/app/apphubdetails/AppHubDetailsApp.cpp index 6570798a7..4fd9117e1 100644 --- a/Tactility/Source/app/apphubdetails/AppHubDetailsApp.cpp +++ b/Tactility/Source/app/apphubdetails/AppHubDetailsApp.cpp @@ -1,7 +1,3 @@ -#include "../../../../Modules/app-module/private/app/private/app_ledger.h" -#include "app/metadata.h" - - #include #include #include @@ -12,6 +8,7 @@ #include #include +#include #include #include @@ -64,10 +61,6 @@ uint32_t showConfirmDialog(Context* ctx, const char* action) { void onBackPressed(lv_event_t* e) { auto* ctx = static_cast(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(appMain) }, diff --git a/Tactility/Source/app/applist/AppList.cpp b/Tactility/Source/app/applist/AppList.cpp index d0ea68901..53896836c 100644 --- a/Tactility/Source/app/applist/AppList.cpp +++ b/Tactility/Source/app/applist/AppList.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/appsettings/AppSettings.cpp b/Tactility/Source/app/appsettings/AppSettings.cpp index 8f2c26bba..de6bad0ef 100644 --- a/Tactility/Source/app/appsettings/AppSettings.cpp +++ b/Tactility/Source/app/appsettings/AppSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/apwebserver/ApWebServer.cpp b/Tactility/Source/app/apwebserver/ApWebServer.cpp index dd1087295..6ad5bc06f 100644 --- a/Tactility/Source/app/apwebserver/ApWebServer.cpp +++ b/Tactility/Source/app/apwebserver/ApWebServer.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/audiosettings/AudioSettings.cpp b/Tactility/Source/app/audiosettings/AudioSettings.cpp index 237e3f009..ebba08306 100644 --- a/Tactility/Source/app/audiosettings/AudioSettings.cpp +++ b/Tactility/Source/app/audiosettings/AudioSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 1f83331f6..f2bbaa84f 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/btmanage/BtManage.cpp b/Tactility/Source/app/btmanage/BtManage.cpp index 4735fd984..c8e88e8a6 100644 --- a/Tactility/Source/app/btmanage/BtManage.cpp +++ b/Tactility/Source/app/btmanage/BtManage.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/btpeersettings/BtPeerSettings.cpp b/Tactility/Source/app/btpeersettings/BtPeerSettings.cpp index 87c935ccd..b4f2c36c8 100644 --- a/Tactility/Source/app/btpeersettings/BtPeerSettings.cpp +++ b/Tactility/Source/app/btpeersettings/BtPeerSettings.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/chat/ChatApp.cpp b/Tactility/Source/app/chat/ChatApp.cpp index 722662c38..d9b2cff3d 100644 --- a/Tactility/Source/app/chat/ChatApp.cpp +++ b/Tactility/Source/app/chat/ChatApp.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/chat/ChatSettings.cpp b/Tactility/Source/app/chat/ChatSettings.cpp index 4cfe01a0f..0ea685fb2 100644 --- a/Tactility/Source/app/chat/ChatSettings.cpp +++ b/Tactility/Source/app/chat/ChatSettings.cpp @@ -7,10 +7,10 @@ #include #include -#include #include #include +#include #include #include @@ -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"; diff --git a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp index 1cb6a5371..b37dcb07e 100644 --- a/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp +++ b/Tactility/Source/app/crashdiagnostics/CrashDiagnostics.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/development/Development.cpp b/Tactility/Source/app/development/Development.cpp index acc4c0f63..60ed63e5b 100644 --- a/Tactility/Source/app/development/Development.cpp +++ b/Tactility/Source/app/development/Development.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/files/FilesApp.cpp b/Tactility/Source/app/files/FilesApp.cpp index 25594c2e0..12e39ae53 100644 --- a/Tactility/Source/app/files/FilesApp.cpp +++ b/Tactility/Source/app/files/FilesApp.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/fileselection/FileSelection.cpp b/Tactility/Source/app/fileselection/FileSelection.cpp index 6f231e427..0e789d66a 100644 --- a/Tactility/Source/app/fileselection/FileSelection.cpp +++ b/Tactility/Source/app/fileselection/FileSelection.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/gpssettings/GpsSettings.cpp b/Tactility/Source/app/gpssettings/GpsSettings.cpp index 538381364..a351c9b73 100644 --- a/Tactility/Source/app/gpssettings/GpsSettings.cpp +++ b/Tactility/Source/app/gpssettings/GpsSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/grovesettings/GroveSettings.cpp b/Tactility/Source/app/grovesettings/GroveSettings.cpp index 445fd1c5c..ef512a4ed 100644 --- a/Tactility/Source/app/grovesettings/GroveSettings.cpp +++ b/Tactility/Source/app/grovesettings/GroveSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/i2cscanner/I2cScanner.cpp b/Tactility/Source/app/i2cscanner/I2cScanner.cpp index 6510436ff..1ab9b84d9 100644 --- a/Tactility/Source/app/i2cscanner/I2cScanner.cpp +++ b/Tactility/Source/app/i2cscanner/I2cScanner.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/imageviewer/ImageViewer.cpp b/Tactility/Source/app/imageviewer/ImageViewer.cpp index b3d3f9ff7..e2a819165 100644 --- a/Tactility/Source/app/imageviewer/ImageViewer.cpp +++ b/Tactility/Source/app/imageviewer/ImageViewer.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/inputdialog/InputDialog.cpp b/Tactility/Source/app/inputdialog/InputDialog.cpp index a0f223853..dbbb8d9bf 100644 --- a/Tactility/Source/app/inputdialog/InputDialog.cpp +++ b/Tactility/Source/app/inputdialog/InputDialog.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/kerneldisplay/KernelDisplay.cpp b/Tactility/Source/app/kerneldisplay/KernelDisplay.cpp index efde0b130..d22ff4d68 100644 --- a/Tactility/Source/app/kerneldisplay/KernelDisplay.cpp +++ b/Tactility/Source/app/kerneldisplay/KernelDisplay.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/keyboard/KeyboardSettings.cpp b/Tactility/Source/app/keyboard/KeyboardSettings.cpp index 71f52a16f..40839908b 100644 --- a/Tactility/Source/app/keyboard/KeyboardSettings.cpp +++ b/Tactility/Source/app/keyboard/KeyboardSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/launcher/Launcher.cpp b/Tactility/Source/app/launcher/Launcher.cpp index ac83bcbe7..3b5f1fcba 100644 --- a/Tactility/Source/app/launcher/Launcher.cpp +++ b/Tactility/Source/app/launcher/Launcher.cpp @@ -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(appMain) }, diff --git a/Tactility/Source/app/localesettings/LocaleSettings.cpp b/Tactility/Source/app/localesettings/LocaleSettings.cpp index 3e5373ed0..ca55678f1 100644 --- a/Tactility/Source/app/localesettings/LocaleSettings.cpp +++ b/Tactility/Source/app/localesettings/LocaleSettings.cpp @@ -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(appMain) } diff --git a/Tactility/Source/app/notes/Notes.cpp b/Tactility/Source/app/notes/Notes.cpp index 5d8a80e49..a242f89d2 100644 --- a/Tactility/Source/app/notes/Notes.cpp +++ b/Tactility/Source/app/notes/Notes.cpp @@ -249,7 +249,7 @@ void start(const std::string& filePath) { } extern const ::AppManifest manifest = { - .id = "Notes", + .id = "tactility.notes", .name = "Notes", .category = APP_CATEGORY_USER, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/power/Power.cpp b/Tactility/Source/app/power/Power.cpp index a007ac4ea..ca6b61419 100644 --- a/Tactility/Source/app/power/Power.cpp +++ b/Tactility/Source/app/power/Power.cpp @@ -273,7 +273,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "Power", + .id = "tactility.power", .name = "Power", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/poweroff/PowerOff.cpp b/Tactility/Source/app/poweroff/PowerOff.cpp index 088aeb52f..d06df08f6 100644 --- a/Tactility/Source/app/poweroff/PowerOff.cpp +++ b/Tactility/Source/app/poweroff/PowerOff.cpp @@ -167,7 +167,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "PowerOff", + .id = "tactility.poweroff", .name = "Power Off", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/screenshot/Screenshot.cpp b/Tactility/Source/app/screenshot/Screenshot.cpp index 9f2377ec0..d832817d4 100644 --- a/Tactility/Source/app/screenshot/Screenshot.cpp +++ b/Tactility/Source/app/screenshot/Screenshot.cpp @@ -285,7 +285,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "Screenshot", + .id = "tactility.screenshot", .name = "Screenshot", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/selectiondialog/SelectionDialog.cpp b/Tactility/Source/app/selectiondialog/SelectionDialog.cpp index ebd446e63..802d7d4ed 100644 --- a/Tactility/Source/app/selectiondialog/SelectionDialog.cpp +++ b/Tactility/Source/app/selectiondialog/SelectionDialog.cpp @@ -150,7 +150,7 @@ AppInstanceId start(AppInstanceId callerAppInstanceId, const std::string& title, } extern const AppManifest manifest = { - .id = "SelectionDialog", + .id = "tactility.selectiondialog", .name = "Selection Dialog", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/settings/Settings.cpp b/Tactility/Source/app/settings/Settings.cpp index e1e69f866..736bd6b10 100644 --- a/Tactility/Source/app/settings/Settings.cpp +++ b/Tactility/Source/app/settings/Settings.cpp @@ -104,7 +104,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "Settings", + .id = "tactility.settings", .name = "Settings", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/setup/Setup.cpp b/Tactility/Source/app/setup/Setup.cpp index 1a0ca97e1..9bbf7c858 100644 --- a/Tactility/Source/app/setup/Setup.cpp +++ b/Tactility/Source/app/setup/Setup.cpp @@ -271,7 +271,7 @@ void start() { } extern const ::AppManifest manifest = { - .id = "Setup", + .id = "tactility.setup", .name = "Setup", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/systeminfo/SystemInfo.cpp b/Tactility/Source/app/systeminfo/SystemInfo.cpp index e63cf9105..81d84418a 100644 --- a/Tactility/Source/app/systeminfo/SystemInfo.cpp +++ b/Tactility/Source/app/systeminfo/SystemInfo.cpp @@ -452,7 +452,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "SystemInfo", + .id = "tactility.systeminfo", .name = "System Info", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp b/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp index 9df8bcbaf..9886f9253 100644 --- a/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp +++ b/Tactility/Source/app/timedatesettings/TimeDateSettings.cpp @@ -209,7 +209,7 @@ uint32_t start() { } extern const ::AppManifest manifest = { - .id = "TimeDateSettings", + .id = "tactility.timedatesettings", .name = "Time & Date", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/timezone/TimeZone.cpp b/Tactility/Source/app/timezone/TimeZone.cpp index 1429aac21..36e42e412 100644 --- a/Tactility/Source/app/timezone/TimeZone.cpp +++ b/Tactility/Source/app/timezone/TimeZone.cpp @@ -283,7 +283,7 @@ std::string getLastCode() { } extern const ::AppManifest manifest = { - .id = "TimeZone", + .id = "tactility.timezone", .name = "Select Time zone", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/touchcalibration/TouchCalibration.cpp b/Tactility/Source/app/touchcalibration/TouchCalibration.cpp index fba9994f2..8bbe4fd4f 100644 --- a/Tactility/Source/app/touchcalibration/TouchCalibration.cpp +++ b/Tactility/Source/app/touchcalibration/TouchCalibration.cpp @@ -288,7 +288,7 @@ uint32_t start(uint32_t callerAppInstanceId) { } extern const ::AppManifest manifest = { - .id = "TouchCalibration", + .id = "tactility.touchcalibration", .name = "Touch Calibration", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/trackball/TrackballSettings.cpp b/Tactility/Source/app/trackball/TrackballSettings.cpp index 56095db98..a01fd990c 100644 --- a/Tactility/Source/app/trackball/TrackballSettings.cpp +++ b/Tactility/Source/app/trackball/TrackballSettings.cpp @@ -304,7 +304,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "TrackballSettings", + .id = "tactility.trackballsettings", .name = "Trackball", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/usbsettings/UsbSettings.cpp b/Tactility/Source/app/usbsettings/UsbSettings.cpp index fcac088b6..f3dbee948 100644 --- a/Tactility/Source/app/usbsettings/UsbSettings.cpp +++ b/Tactility/Source/app/usbsettings/UsbSettings.cpp @@ -116,7 +116,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "UsbSettings", + .id = "tactility.usbsettings", .name = "USB", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/webserversettings/WebServerSettings.cpp b/Tactility/Source/app/webserversettings/WebServerSettings.cpp index c2fd0e184..66978733a 100644 --- a/Tactility/Source/app/webserversettings/WebServerSettings.cpp +++ b/Tactility/Source/app/webserversettings/WebServerSettings.cpp @@ -431,7 +431,7 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) { } // namespace extern const ::AppManifest manifest = { - .id = "WebServerSettings", + .id = "tactility.webserversettings", .name = "Web Server", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp b/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp index 7c5a81527..1d38449ff 100644 --- a/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp +++ b/Tactility/Source/app/wifiapsettings/WifiApSettings.cpp @@ -272,7 +272,7 @@ void start(const std::string& ssid) { } extern const ::AppManifest manifest = { - .id = "WifiApSettings", + .id = "tactility.wifiapsettings", .name = "Wi-Fi AP Settings", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/wificonnect/WifiConnect.cpp b/Tactility/Source/app/wificonnect/WifiConnect.cpp index 0b4c74c44..3ad15cded 100644 --- a/Tactility/Source/app/wificonnect/WifiConnect.cpp +++ b/Tactility/Source/app/wificonnect/WifiConnect.cpp @@ -360,7 +360,7 @@ void start(const std::string& ssid, const std::string& password) { } extern const ::AppManifest manifest = { - .id = "WifiConnect", + .id = "tactility.wificonnect", .name = "Wi-Fi Connect", .category = APP_CATEGORY_SYSTEM, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) }, diff --git a/Tactility/Source/app/wifimanage/WifiManage.cpp b/Tactility/Source/app/wifimanage/WifiManage.cpp index 006335146..5bae6c6b4 100644 --- a/Tactility/Source/app/wifimanage/WifiManage.cpp +++ b/Tactility/Source/app/wifimanage/WifiManage.cpp @@ -188,7 +188,7 @@ uint32_t start(uint32_t callerAppInstanceId) { } extern const ::AppManifest manifest = { - .id = "WifiManage", + .id = "tactility.wifimanage", .name = "Wi-Fi", .category = APP_CATEGORY_SETTINGS, .location = { APP_LOCATION_MEMORY, reinterpret_cast(appMain) } diff --git a/Tactility/Source/lvgl/KeyboardDeviceListener.cpp b/Tactility/Source/lvgl/KeyboardDeviceListener.cpp new file mode 100644 index 000000000..f017a366d --- /dev/null +++ b/Tactility/Source/lvgl/KeyboardDeviceListener.cpp @@ -0,0 +1,133 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +namespace tt::lvgl { + +constexpr auto* TAG = "KeyboardDeviceListener"; + +namespace { + +struct KeyboardBinding { + Device* device; + lv_indev_t* indev; +}; + +Mutex& bindingsMutex() { + static Mutex mutex; + return mutex; +} + +std::vector& bindings() { + static std::vector list; + return list; +} + +// Guards, under bindingsMutex, against onKeyboardDeviceStarted() registering a binding after +// stopKeyboardDeviceListener() has already drained bindings() and returned. +bool& listenerActive() { + static bool active = false; + return active; +} + +void onKeyboardDeviceStarted(Device* device) { + // Held for the whole add+register step so a same-device STOPPING can't observe the binding + // as neither-registered-nor-added: onKeyboardDeviceStopped() and shutdown's drain both take + // this same lock, so they see either the fully-registered binding or nothing at all. + auto lock = bindingsMutex().asScopedLock(); + lock.lock(); + if (!listenerActive()) { + return; + } + + lv_indev_t* indev = nullptr; + lvgl_lock(); + error_t error = lvgl_keyboard_add(device, lv_display_get_default(), &indev); + lvgl_unlock(); + if (error != ERROR_NONE) { + LOG_E(TAG, "failed to bind keyboard device %s to LVGL", device->name); + return; + } + bindings().push_back({ device, indev }); +} + +void onKeyboardDeviceStopped(Device* device) { + auto lock = bindingsMutex().asScopedLock(); + lock.lock(); + lv_indev_t* indev = nullptr; + auto& list = bindings(); + for (auto it = list.begin(); it != list.end(); ++it) { + if (it->device == device) { + indev = it->indev; + list.erase(it); + break; + } + } + if (indev == nullptr) { + return; + } + + lvgl_lock(); + lvgl_keyboard_remove(indev); + lvgl_unlock(); +} + +void onDeviceEvent(Device* device, DeviceEvent event, void* context) { + (void)context; + if (device_get_type(device) != &KEYBOARD_TYPE) { + return; + } + // Detach on STOPPING (before stop_device() frees the device's resources), not STOPPED (which + // only fires after stop_device() already ran) - see DEVICE_EVENT_STOPPING's doc comment. + if (event == DEVICE_EVENT_STARTED) { + onKeyboardDeviceStarted(device); + } else if (event == DEVICE_EVENT_STOPPING) { + onKeyboardDeviceStopped(device); + } +} + +} // namespace + +void startKeyboardDeviceListener() { + auto lock = bindingsMutex().asScopedLock(); + lock.lock(); + listenerActive() = true; + device_listener_add(onDeviceEvent, nullptr); +} + +void stopKeyboardDeviceListener() { + std::vector remaining; + { + // device_listener_remove() doesn't wait for an in-flight onDeviceEvent() to finish, so a + // STARTED callback already past this point can still land after we drain below; it takes + // this same lock and checks listenerActive() before registering, so it backs off instead + // of adding a binding nothing will ever remove. + auto lock = bindingsMutex().asScopedLock(); + lock.lock(); + listenerActive() = false; + device_listener_remove(onDeviceEvent); + remaining = std::move(bindings()); + bindings().clear(); + } + + if (remaining.empty()) { + return; + } + + lvgl_lock(); + for (auto& binding : remaining) { + lvgl_keyboard_remove(binding.indev); + } + lvgl_unlock(); +} + +} // namespace tt::lvgl diff --git a/Tactility/Source/lvgl/UsbHidInput.cpp b/Tactility/Source/lvgl/UsbHidInput.cpp index b5b55a4d9..997c64b28 100644 --- a/Tactility/Source/lvgl/UsbHidInput.cpp +++ b/Tactility/Source/lvgl/UsbHidInput.cpp @@ -18,6 +18,7 @@ #include #include +#include namespace tt::lvgl { @@ -286,12 +287,19 @@ static void usbHidInputTask(void* arg) { void startUsbHidInput() { if (s_ctx != nullptr) return; - auto* ctx = new UsbHidInputCtx(); + static constexpr MemoryPolicy CTX_POLICY = { 0, MEMORY_CAPABILITY_EXTERNAL, 0 }; + auto* ctx_mem = memory_alloc_with_policy(sizeof(UsbHidInputCtx), &CTX_POLICY); + if (!ctx_mem) { + LOG_E(TAG, "failed to allocate context"); + return; + } + auto* ctx = new (ctx_mem) UsbHidInputCtx(); ctx->hid_queue = xQueueCreate(HID_EVENT_QUEUE_SIZE, sizeof(UsbHidEvent)); if (!ctx->hid_queue) { LOG_E(TAG, "failed to create HID event queue"); - delete ctx; + ctx->~UsbHidInputCtx(); + memory_free(ctx); return; } @@ -299,7 +307,8 @@ void startUsbHidInput() { if (!ctx->key_queue) { LOG_E(TAG, "failed to create key event queue"); vQueueDelete(ctx->hid_queue); - delete ctx; + ctx->~UsbHidInputCtx(); + memory_free(ctx); return; } @@ -308,7 +317,8 @@ void startUsbHidInput() { LOG_E(TAG, "failed to create task done semaphore"); vQueueDelete(ctx->hid_queue); vQueueDelete(ctx->key_queue); - delete ctx; + ctx->~UsbHidInputCtx(); + memory_free(ctx); return; } @@ -371,7 +381,8 @@ void startUsbHidInput() { vQueueDelete(ctx->hid_queue); vQueueDelete(ctx->key_queue); vSemaphoreDelete(ctx->task_done); - delete ctx; + ctx->~UsbHidInputCtx(); + memory_free(ctx); return; } @@ -429,7 +440,8 @@ void stopUsbHidInput() { vQueueDelete(ctx->hid_queue); vQueueDelete(ctx->key_queue); vSemaphoreDelete(ctx->task_done); - delete ctx; + ctx->~UsbHidInputCtx(); + memory_free(ctx); LOG_I(TAG, "stopped"); } diff --git a/Tactility/Source/service/audio/AudioService.cpp b/Tactility/Source/service/audio/AudioService.cpp index b58c3c42e..65dea77fe 100644 --- a/Tactility/Source/service/audio/AudioService.cpp +++ b/Tactility/Source/service/audio/AudioService.cpp @@ -329,7 +329,7 @@ std::shared_ptr findAudioService() { } extern const ServiceManifest manifest = { - .id = "Audio", + .id = "tactility.audio", .createService = create }; diff --git a/Tactility/Source/service/development/DevelopmentService.cpp b/Tactility/Source/service/development/DevelopmentService.cpp index 3c0d0abba..833fcf714 100644 --- a/Tactility/Source/service/development/DevelopmentService.cpp +++ b/Tactility/Source/service/development/DevelopmentService.cpp @@ -252,7 +252,7 @@ std::shared_ptr findService() { } extern const ServiceManifest manifest = { - .id = "Development", + .id = "tactility.development", .createService = create }; diff --git a/Tactility/Source/service/development/DevelopmentSettings.cpp b/Tactility/Source/service/development/DevelopmentSettings.cpp index 676545130..13da6082b 100644 --- a/Tactility/Source/service/development/DevelopmentSettings.cpp +++ b/Tactility/Source/service/development/DevelopmentSettings.cpp @@ -1,11 +1,11 @@ #ifdef ESP_PLATFORM -#include #include #include #include #include #include +#include #include namespace tt::service::development { @@ -13,7 +13,11 @@ namespace tt::service::development { constexpr auto* TAG = "DevSettings"; static std::string getSettingsFilePath() { - return getUserDataPath() + "/settings/development.properties"; + char path[256]; + if (app_paths_get_user_data_path("tactility.development", "development.properties", path, sizeof(path)) != ERROR_NONE) { + return ""; + } + return path; } constexpr auto* SETTINGS_KEY_ENABLE_ON_BOOT = "enableOnBoot"; diff --git a/Tactility/Source/service/displayidle/DisplayIdle.cpp b/Tactility/Source/service/displayidle/DisplayIdle.cpp index f25c0c4ac..faeffab64 100644 --- a/Tactility/Source/service/displayidle/DisplayIdle.cpp +++ b/Tactility/Source/service/displayidle/DisplayIdle.cpp @@ -280,12 +280,12 @@ void DisplayIdleService::reloadSettings() { std::shared_ptr findService() { return std::static_pointer_cast( - findServiceById("DisplayIdle") + findServiceById("tactility.displayidle") ); } extern const ServiceManifest manifest = { - .id = "DisplayIdle", + .id = "tactility.displayidle", .createService = create }; diff --git a/Tactility/Source/service/espnow/EspNowService.cpp b/Tactility/Source/service/espnow/EspNowService.cpp index 7f19930c0..f9ec858b6 100644 --- a/Tactility/Source/service/espnow/EspNowService.cpp +++ b/Tactility/Source/service/espnow/EspNowService.cpp @@ -193,7 +193,7 @@ std::shared_ptr findService() { } extern const ServiceManifest manifest = { - .id = "EspNow", + .id = "tactility.espnow", .createService = create }; diff --git a/Tactility/Source/service/keyboardidle/KeyboardIdle.cpp b/Tactility/Source/service/keyboardidle/KeyboardIdle.cpp index 24a96c29e..fbcd0c278 100644 --- a/Tactility/Source/service/keyboardidle/KeyboardIdle.cpp +++ b/Tactility/Source/service/keyboardidle/KeyboardIdle.cpp @@ -113,7 +113,7 @@ class KeyboardIdleService final : public Service { }; extern const ServiceManifest manifest = { - .id = "KeyboardIdle", + .id = "tactility.keyboardidle", .createService = create }; diff --git a/Tactility/Source/service/memorychecker/MemoryCheckerService.cpp b/Tactility/Source/service/memorychecker/MemoryCheckerService.cpp index 738bbf556..2c907bac6 100644 --- a/Tactility/Source/service/memorychecker/MemoryCheckerService.cpp +++ b/Tactility/Source/service/memorychecker/MemoryCheckerService.cpp @@ -85,7 +85,7 @@ void MemoryCheckerService::onTimerUpdate() { } extern const ServiceManifest manifest = { - .id = "MemoryChecker", + .id = "tactility.memorychecker", .createService = create }; diff --git a/Tactility/Source/service/rtctime/RtcTimeService.cpp b/Tactility/Source/service/rtctime/RtcTimeService.cpp index 4f430b500..ca47e9048 100644 --- a/Tactility/Source/service/rtctime/RtcTimeService.cpp +++ b/Tactility/Source/service/rtctime/RtcTimeService.cpp @@ -140,7 +140,7 @@ void RtcTimeService::onStop(ServiceContext& serviceContext) { } extern const ServiceManifest manifest = { - .id = "RtcTime", + .id = "tactility.rtctime", .createService = create }; diff --git a/Tactility/Source/service/screenshot/Screenshot.cpp b/Tactility/Source/service/screenshot/Screenshot.cpp index a85e1540f..af79f8064 100644 --- a/Tactility/Source/service/screenshot/Screenshot.cpp +++ b/Tactility/Source/service/screenshot/Screenshot.cpp @@ -97,7 +97,7 @@ bool ScreenshotService::isTaskStarted() { } extern const ServiceManifest manifest = { - .id = "Screenshot", + .id = "tactility.screenshot", .createService = create }; diff --git a/Tactility/Source/service/statusbar/Statusbar.cpp b/Tactility/Source/service/statusbar/Statusbar.cpp index 3bbce017a..a42629ccd 100644 --- a/Tactility/Source/service/statusbar/Statusbar.cpp +++ b/Tactility/Source/service/statusbar/Statusbar.cpp @@ -359,7 +359,7 @@ class StatusbarService final : public Service { }; extern const ServiceManifest manifest = { - .id = "Statusbar", + .id = "tactility.statusbar", .createService = create }; diff --git a/Tactility/Source/service/webserver/WebServerService.cpp b/Tactility/Source/service/webserver/WebServerService.cpp index 8297386f2..f8b21de17 100644 --- a/Tactility/Source/service/webserver/WebServerService.cpp +++ b/Tactility/Source/service/webserver/WebServerService.cpp @@ -1797,7 +1797,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) { } extern const ServiceManifest manifest = { - .id = "WebServer", + .id = "tactility.webserver", .createService = create }; diff --git a/Tactility/Source/service/wifi/Wifi.cpp b/Tactility/Source/service/wifi/Wifi.cpp index 28e0f9d19..394f92c71 100644 --- a/Tactility/Source/service/wifi/Wifi.cpp +++ b/Tactility/Source/service/wifi/Wifi.cpp @@ -551,7 +551,7 @@ class WifiService final : public Service { } // namespace extern const ServiceManifest manifest = { - .id = "wifi", + .id = "tactility.wifi", .createService = create }; diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index e0ac8b4b5..dbcbd2667 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -2,7 +2,8 @@ #include #include -#include + +#include #include #include @@ -11,7 +12,11 @@ namespace tt::settings::display { static std::string getSettingsFilePath() { - return getUserDataPath() + "/settings/display.properties"; + char path[256]; + if (app_paths_get_user_data_path("tactility.display", "display.properties", path, sizeof(path)) != ERROR_NONE) { + return ""; + } + return path; } constexpr auto* SETTINGS_KEY_ORIENTATION = "orientation"; diff --git a/Tactility/Source/settings/TrackballSettings.cpp b/Tactility/Source/settings/TrackballSettings.cpp index 938127f5e..f992114cb 100644 --- a/Tactility/Source/settings/TrackballSettings.cpp +++ b/Tactility/Source/settings/TrackballSettings.cpp @@ -1,7 +1,8 @@ #include #include #include -#include + +#include #include #include @@ -10,7 +11,11 @@ namespace tt::settings::trackball { static std::string getSettingsFilePath() { - return getUserDataPath() + "/settings/trackball.properties"; + char path[256]; + if (app_paths_get_user_data_path("tactility.trackballsettings", "trackball.properties", path, sizeof(path)) != ERROR_NONE) { + return ""; + } + return path; } constexpr auto* KEY_TRACKBALL_ENABLED = "trackballEnabled"; diff --git a/Tactility/Source/settings/WebServerSettings.cpp b/Tactility/Source/settings/WebServerSettings.cpp index 3a3817a28..91560b169 100644 --- a/Tactility/Source/settings/WebServerSettings.cpp +++ b/Tactility/Source/settings/WebServerSettings.cpp @@ -1,8 +1,8 @@ -#include #include #include #include +#include #include #include @@ -22,7 +22,11 @@ namespace tt::settings::webserver { constexpr auto* TAG = "WebServerSettings"; static std::string getSettingsFilePath() { - return getUserDataPath() + "/settings/webserver.properties"; + char path[256]; + if (app_paths_get_user_data_path("tactility.webserversettings", "webserver.properties", path, sizeof(path)) != ERROR_NONE) { + return ""; + } + return path; } // Property keys diff --git a/TactilityFreeRtos/README.md b/TactilityFreeRtos/README.md index 3a2b82abe..a018e8fb3 100644 --- a/TactilityFreeRtos/README.md +++ b/TactilityFreeRtos/README.md @@ -4,4 +4,4 @@ A collection of FreeRTOS C++ wrappers. ## License -[GNU General Public License Version 3](LICENSE.md) +[Apache License v2.0](LICENSE-Apache-2.0.md) diff --git a/TactilityKernel/include/tactility/device_listener.h b/TactilityKernel/include/tactility/device_listener.h index 94001cb78..9fcd9098c 100644 --- a/TactilityKernel/include/tactility/device_listener.h +++ b/TactilityKernel/include/tactility/device_listener.h @@ -8,6 +8,7 @@ struct Device; enum DeviceEvent { DEVICE_EVENT_STARTED, + DEVICE_EVENT_STOPPING, DEVICE_EVENT_STOPPED, }; diff --git a/TactilityKernel/source/device.cpp b/TactilityKernel/source/device.cpp index baa4af77d..b852a68e6 100644 --- a/TactilityKernel/source/device.cpp +++ b/TactilityKernel/source/device.cpp @@ -256,6 +256,8 @@ error_t device_stop(Device* device) { internal->state.stopping = true; unlock_internal(internal); + device_listener_notify(device, DEVICE_EVENT_STOPPING); + error_t unbind_error = driver_unbind(internal->driver, device); lock_internal(internal); diff --git a/TactilityKernelCpp/CMakeLists.txt b/TactilityKernelCpp/CMakeLists.txt new file mode 100644 index 000000000..94d6d49bd --- /dev/null +++ b/TactilityKernelCpp/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.20) + +if (DEFINED ENV{ESP_IDF_VERSION}) + + idf_component_register( + INCLUDE_DIRS "Include/" + REQUIRES TactilityKernel + ) + +else() + + add_library(TactilityKernelCpp INTERFACE) + + target_include_directories(TactilityKernelCpp + INTERFACE Include/ + ) + + target_link_libraries(TactilityKernelCpp + INTERFACE TactilityKernel + ) +endif() diff --git a/TactilityKernelCpp/Include/TactilityCpp/Allocator.h b/TactilityKernelCpp/Include/TactilityCpp/Allocator.h new file mode 100644 index 000000000..52fbb5b7f --- /dev/null +++ b/TactilityKernelCpp/Include/TactilityCpp/Allocator.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include + +#include +#include +#include + +namespace tt { + +/** Allocator backed by tactility/memory.h's memory_alloc_with_policy(), with Required/Desired as + * its required/desired MemoryCapability flags (bitwise-OR'd, e.g. MEMORY_CAPABILITY_EXTERNAL). */ +template +struct Allocator { + using value_type = T; + + // libstdc++'s default rebind_alloc only pattern-matches allocator templates whose parameters + // are all types, which Required/Desired (non-type) breaks; spelling it out here restores it. + template struct rebind { using other = Allocator; }; + + Allocator() noexcept = default; + template constexpr Allocator(const Allocator&) noexcept {} + + T* allocate(std::size_t n) { + const MemoryPolicy policy { .required = Required, .desired = Desired, .alignment = alignof(T) }; + void* ptr = memory_alloc_with_policy(n * sizeof(T), &policy); + if (ptr == nullptr) { + std::abort(); // Exceptions are disabled project-wide, so OOM can't be signalled via std::bad_alloc. + } + return static_cast(ptr); + } + + void deallocate(T* ptr, std::size_t) noexcept { + memory_free(ptr); + } +}; + +template +bool operator==(const Allocator&, const Allocator&) noexcept { return true; } + +/** Prefers external memory, falling back to internal RAM when unavailable. */ +template +using OptExternalAllocator = Allocator; + +} // namespace tt diff --git a/TactilityKernelCpp/LICENSE-Apache-2.0.md b/TactilityKernelCpp/LICENSE-Apache-2.0.md new file mode 100644 index 000000000..f5f4b8b5e --- /dev/null +++ b/TactilityKernelCpp/LICENSE-Apache-2.0.md @@ -0,0 +1,195 @@ +Apache License +============== + +_Version 2.0, January 2004_ +_<>_ + +### Terms and Conditions for use, reproduction, and distribution + +#### 1. Definitions + +“License” shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +“Licensor” shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +“Legal Entity” shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, “control” means **(i)** the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the +outstanding shares, or **(iii)** beneficial ownership of such entity. + +“You” (or “Your”) shall mean an individual or Legal Entity exercising +permissions granted by this License. + +“Source” form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +“Object” form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +“Work” shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +“Derivative Works” shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +“Contribution” shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +“submitted” means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as “Not a Contribution.” + +“Contributor” shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +#### 2. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +#### 3. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +#### 4. Redistribution + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +* **(a)** You must give any other recipients of the Work or Derivative Works a copy of +this License; and +* **(b)** You must cause any modified files to carry prominent notices stating that You +changed the files; and +* **(c)** You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +#### 5. Submission of Contributions + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +#### 6. Trademarks + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +#### 7. Disclaimer of Warranty + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +#### 8. Limitation of Liability + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +#### 9. Accepting Warranty or Additional Liability + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +_END OF TERMS AND CONDITIONS_ + +### APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets `[]` replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same “printed page” as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/TactilityKernelCpp/README.md b/TactilityKernelCpp/README.md new file mode 100644 index 000000000..94cf48508 --- /dev/null +++ b/TactilityKernelCpp/README.md @@ -0,0 +1,7 @@ +# TactilityKernelCpp + +Headers-only C++ wrappers around TactilityKernel's C API. + +## License + +[Apache License 2.0](LICENSE-Apache-2.0.md)