diff --git a/.github/workflows/build-simulator.yml b/.github/workflows/build-simulator.yml index c9f6ac80..b781524b 100644 --- a/.github/workflows/build-simulator.yml +++ b/.github/workflows/build-simulator.yml @@ -11,6 +11,8 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: "Build" uses: ./.github/actions/build-simulator with: @@ -21,6 +23,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: "Build" uses: ./.github/actions/build-simulator with: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b832709a..3390cb8d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,6 +23,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: "Build SDK" uses: ./.github/actions/build-sdk with: @@ -66,7 +68,6 @@ jobs: { id: m5stack-cores3, arch: esp32s3 }, { id: m5stack-papers3, arch: esp32s3 }, { id: m5stack-stackchan, arch: esp32s3 }, - { id: m5stack-stickc-plus, arch: esp32 }, { id: m5stack-stickc-plus2, arch: esp32 }, { id: m5stack-sticks3, arch: esp32s3 }, { id: m5stack-tab5, arch: esp32p4 }, @@ -82,6 +83,8 @@ jobs: needs: [ BuildSdk ] steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - name: "Build Firmware" uses: ./.github/actions/build-firmware with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 96631892..8a53dd96 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,8 +31,9 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout repo" - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: + persist-credentials: false submodules: recursive - name: "Install Python Dependencies" shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ebdb742..4054608f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ else () add_compile_definitions(CONFIG_TT_DEVICE_NAME_SIMPLE="Simulator") add_compile_definitions(CONFIG_TT_LAUNCHER_APP_ID="Launcher") add_compile_definitions(CONFIG_TT_AUTO_START_APP_ID="") + add_compile_definitions(CONFIG_TT_USER_DATA_LOCATION_INTERNAL) endif () project(Tactility) diff --git a/Data/data/service/bluetooth/settings.properties b/Data/data/tactility/service/bluetooth/settings.properties similarity index 100% rename from Data/data/service/bluetooth/settings.properties rename to Data/data/tactility/service/bluetooth/settings.properties diff --git a/Data/data/service/webserver/settings.properties b/Data/data/tactility/service/webserver/settings.properties similarity index 100% rename from Data/data/service/webserver/settings.properties rename to Data/data/tactility/service/webserver/settings.properties diff --git a/Data/data/service/wifi/settings.properties b/Data/data/tactility/service/wifi/settings.properties similarity index 100% rename from Data/data/service/wifi/settings.properties rename to Data/data/tactility/service/wifi/settings.properties diff --git a/Data/data/settings/development.properties b/Data/data/tactility/settings/development.properties similarity index 100% rename from Data/data/settings/development.properties rename to Data/data/tactility/settings/development.properties diff --git a/Data/data/settings/system.properties b/Data/data/tactility/settings/system.properties similarity index 100% rename from Data/data/settings/system.properties rename to Data/data/tactility/settings/system.properties diff --git a/Data/data/webserver/dashboard.html b/Data/system/app/WebServer/dashboard.html similarity index 99% rename from Data/data/webserver/dashboard.html rename to Data/system/app/WebServer/dashboard.html index 69553e72..d7e75ec5 100644 --- a/Data/data/webserver/dashboard.html +++ b/Data/system/app/WebServer/dashboard.html @@ -485,7 +485,7 @@
- +
@@ -739,7 +739,6 @@ function renderDashboard(data) {

Quick Actions

- ${data.features_enabled?.screenshot ? '' : ''}
diff --git a/Data/data/webserver/version.json b/Data/system/app/WebServer/version.json similarity index 100% rename from Data/data/webserver/version.json rename to Data/system/app/WebServer/version.json diff --git a/Data/webserver/default.html b/Data/webserver/default.html deleted file mode 100644 index fa4ab4c7..00000000 --- a/Data/webserver/default.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Tactility Dashboard - - - -

Tactility Default Dashboard

- -
-

Version 0 - Default Placeholder

-

This is the default dashboard bundled with firmware.

-

To customize this interface:

-
    -
  1. Create your custom dashboard HTML/CSS/JS files
  2. -
  3. Add them to /sdcard/tactility/webserver/
  4. -
  5. Create version.json with {"version": 1} or higher
  6. -
  7. Reboot or click "Sync Assets" on the Core Interface
  8. -
-

Your custom assets will automatically replace this page!

-
- - - - diff --git a/Data/webserver/version.json b/Data/webserver/version.json deleted file mode 100644 index 5dfe44db..00000000 --- a/Data/webserver/version.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": 0 -} diff --git a/Devices/btt-panda-touch/device.properties b/Devices/btt-panda-touch/device.properties index b34ee6e4..8e65fa6d 100644 --- a/Devices/btt-panda-touch/device.properties +++ b/Devices/btt-panda-touch/device.properties @@ -12,6 +12,8 @@ hardware.esptoolFlashFreq=120M hardware.bluetooth=true hardware.usbHostEnabled=true +storage.userDataLocation=Internal + display.size=5" display.shape=rectangle display.dpi=187 diff --git a/Devices/cyd-2432s024c/device.properties b/Devices/cyd-2432s024c/device.properties index 8c41c3e8..0f2a5c1d 100644 --- a/Devices/cyd-2432s024c/device.properties +++ b/Devices/cyd-2432s024c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.4" display.shape=rectangle display.dpi=167 diff --git a/Devices/cyd-2432s024r/device.properties b/Devices/cyd-2432s024r/device.properties index b54d29d5..b2e05d04 100644 --- a/Devices/cyd-2432s024r/device.properties +++ b/Devices/cyd-2432s024r/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.4" display.shape=rectangle display.dpi=167 diff --git a/Devices/cyd-2432s028r/device.properties b/Devices/cyd-2432s028r/device.properties index ff1db8b3..c0047a33 100644 --- a/Devices/cyd-2432s028r/device.properties +++ b/Devices/cyd-2432s028r/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/cyd-2432s028rv3/device.properties b/Devices/cyd-2432s028rv3/device.properties index c35b6414..ae3e926f 100644 --- a/Devices/cyd-2432s028rv3/device.properties +++ b/Devices/cyd-2432s028rv3/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/cyd-2432s032c/device.properties b/Devices/cyd-2432s032c/device.properties index 239afa35..e483bd8c 100644 --- a/Devices/cyd-2432s032c/device.properties +++ b/Devices/cyd-2432s032c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=3.2" display.shape=rectangle display.dpi=125 diff --git a/Devices/cyd-3248s035c/device.properties b/Devices/cyd-3248s035c/device.properties index fedfa096..c8fc929d 100644 --- a/Devices/cyd-3248s035c/device.properties +++ b/Devices/cyd-3248s035c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Devices/cyd-4848s040c/device.properties b/Devices/cyd-4848s040c/device.properties index 6dc01205..45c66c54 100644 --- a/Devices/cyd-4848s040c/device.properties +++ b/Devices/cyd-4848s040c/device.properties @@ -10,6 +10,8 @@ hardware.spiRamMode=OCT hardware.spiRamSpeed=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=4" display.shape=rectangle display.dpi=170 diff --git a/Devices/cyd-8048s043c/device.properties b/Devices/cyd-8048s043c/device.properties index 94659bab..8056421d 100644 --- a/Devices/cyd-8048s043c/device.properties +++ b/Devices/cyd-8048s043c/device.properties @@ -12,6 +12,8 @@ hardware.spiRamSpeed=80M hardware.esptoolFlashFreq=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=4.3" display.shape=rectangle display.dpi=217 diff --git a/Devices/cyd-e32r28t/device.properties b/Devices/cyd-e32r28t/device.properties index f9b582a9..0adcd93d 100644 --- a/Devices/cyd-e32r28t/device.properties +++ b/Devices/cyd-e32r28t/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/cyd-e32r32p/device.properties b/Devices/cyd-e32r32p/device.properties index 1895aa40..3c10c3e8 100644 --- a/Devices/cyd-e32r32p/device.properties +++ b/Devices/cyd-e32r32p/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=125 diff --git a/Devices/elecrow-crowpanel-advance-28/device.properties b/Devices/elecrow-crowpanel-advance-28/device.properties index 797e53f9..9d2fd794 100644 --- a/Devices/elecrow-crowpanel-advance-28/device.properties +++ b/Devices/elecrow-crowpanel-advance-28/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/elecrow-crowpanel-advance-35/device.properties b/Devices/elecrow-crowpanel-advance-35/device.properties index 0bc352e6..83374439 100644 --- a/Devices/elecrow-crowpanel-advance-35/device.properties +++ b/Devices/elecrow-crowpanel-advance-35/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Devices/elecrow-crowpanel-advance-50/device.properties b/Devices/elecrow-crowpanel-advance-50/device.properties index f1a00e28..9fa787d6 100644 --- a/Devices/elecrow-crowpanel-advance-50/device.properties +++ b/Devices/elecrow-crowpanel-advance-50/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=5" display.shape=rectangle display.dpi=187 diff --git a/Devices/elecrow-crowpanel-basic-28/device.properties b/Devices/elecrow-crowpanel-basic-28/device.properties index 7843d829..61b71556 100644 --- a/Devices/elecrow-crowpanel-basic-28/device.properties +++ b/Devices/elecrow-crowpanel-basic-28/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/elecrow-crowpanel-basic-35/device.properties b/Devices/elecrow-crowpanel-basic-35/device.properties index b768e157..c9bb6094 100644 --- a/Devices/elecrow-crowpanel-basic-35/device.properties +++ b/Devices/elecrow-crowpanel-basic-35/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Devices/elecrow-crowpanel-basic-50/device.properties b/Devices/elecrow-crowpanel-basic-50/device.properties index 5f71e02e..69633d2a 100644 --- a/Devices/elecrow-crowpanel-basic-50/device.properties +++ b/Devices/elecrow-crowpanel-basic-50/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=5.0" display.shape=rectangle display.dpi=187 diff --git a/Devices/generic-esp32/device.properties b/Devices/generic-esp32/device.properties index 4dd70ea6..8b803a84 100644 --- a/Devices/generic-esp32/device.properties +++ b/Devices/generic-esp32/device.properties @@ -4,6 +4,7 @@ general.name=ESP32 apps.launcherAppId=Launcher hardware.target=ESP32 -hardware.flashSize=4MB +hardware.flashSize=8MB hardware.spiRam=false +storage.userDataLocation=Internal diff --git a/Devices/generic-esp32c6/device.properties b/Devices/generic-esp32c6/device.properties index c8941ee3..bd332c25 100644 --- a/Devices/generic-esp32c6/device.properties +++ b/Devices/generic-esp32c6/device.properties @@ -4,6 +4,7 @@ general.name=ESP32-C6 apps.launcherAppId=Launcher hardware.target=ESP32C6 -hardware.flashSize=4MB +hardware.flashSize=8MB hardware.spiRam=false +storage.userDataLocation=Internal diff --git a/Devices/generic-esp32p4/device.properties b/Devices/generic-esp32p4/device.properties index d2fefc16..4a050b39 100644 --- a/Devices/generic-esp32p4/device.properties +++ b/Devices/generic-esp32p4/device.properties @@ -4,6 +4,7 @@ general.name=ESP32-P4 apps.launcherAppId=Launcher hardware.target=ESP32P4 -hardware.flashSize=4MB +hardware.flashSize=8MB hardware.spiRam=false +storage.userDataLocation=Internal diff --git a/Devices/generic-esp32s3/device.properties b/Devices/generic-esp32s3/device.properties index 3bb4a9d4..8512a450 100644 --- a/Devices/generic-esp32s3/device.properties +++ b/Devices/generic-esp32s3/device.properties @@ -4,6 +4,7 @@ general.name=ESP32-S3 apps.launcherAppId=Launcher hardware.target=ESP32S3 -hardware.flashSize=4MB +hardware.flashSize=8MB hardware.spiRam=false +storage.userDataLocation=Internal diff --git a/Devices/guition-jc1060p470ciwy/device.properties b/Devices/guition-jc1060p470ciwy/device.properties index 4ad803c6..fcc7421e 100644 --- a/Devices/guition-jc1060p470ciwy/device.properties +++ b/Devices/guition-jc1060p470ciwy/device.properties @@ -11,6 +11,8 @@ hardware.spiRamSpeed=200M hardware.esptoolFlashFreq=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=7" display.shape=rectangle display.dpi=187 diff --git a/Devices/guition-jc2432w328c/device.properties b/Devices/guition-jc2432w328c/device.properties index a938ef23..7ef40633 100644 --- a/Devices/guition-jc2432w328c/device.properties +++ b/Devices/guition-jc2432w328c/device.properties @@ -7,6 +7,8 @@ hardware.target=ESP32 hardware.flashSize=4MB hardware.spiRam=false +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/guition-jc3248w535c/device.properties b/Devices/guition-jc3248w535c/device.properties index dabe1b87..88497b41 100644 --- a/Devices/guition-jc3248w535c/device.properties +++ b/Devices/guition-jc3248w535c/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Devices/guition-jc8048w550c/device.properties b/Devices/guition-jc8048w550c/device.properties index 46c912bd..b0450a3c 100644 --- a/Devices/guition-jc8048w550c/device.properties +++ b/Devices/guition-jc8048w550c/device.properties @@ -11,6 +11,8 @@ hardware.spiRamSpeed=80M hardware.esptoolFlashFreq=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=5" display.shape=rectangle display.dpi=187 diff --git a/Devices/heltec-wifi-lora-32-v3/device.properties b/Devices/heltec-wifi-lora-32-v3/device.properties index 84afa8f0..729c4873 100644 --- a/Devices/heltec-wifi-lora-32-v3/device.properties +++ b/Devices/heltec-wifi-lora-32-v3/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=Internal + display.size=0.96" display.shape=rectangle display.dpi=149 diff --git a/Devices/lilygo-tdeck/device.properties b/Devices/lilygo-tdeck/device.properties index cba55320..04207e46 100644 --- a/Devices/lilygo-tdeck/device.properties +++ b/Devices/lilygo-tdeck/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=143 diff --git a/Devices/lilygo-tdisplay-s3/device.properties b/Devices/lilygo-tdisplay-s3/device.properties index 006ae739..759018c9 100644 --- a/Devices/lilygo-tdisplay-s3/device.properties +++ b/Devices/lilygo-tdisplay-s3/device.properties @@ -13,6 +13,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=Internal + display.size=1.9" display.shape=rectangle display.dpi=191 diff --git a/Devices/lilygo-tdisplay/device.properties b/Devices/lilygo-tdisplay/device.properties index 0dd37c33..59008613 100644 --- a/Devices/lilygo-tdisplay/device.properties +++ b/Devices/lilygo-tdisplay/device.properties @@ -10,6 +10,8 @@ hardware.flashSize=16MB hardware.spiRam=false hardware.esptoolFlashFreq=80M +storage.userDataLocation=Internal + display.size=1.14" display.shape=rectangle display.dpi=242 diff --git a/Devices/lilygo-tdongle-s3/device.properties b/Devices/lilygo-tdongle-s3/device.properties index 62d1e218..f92ed6eb 100644 --- a/Devices/lilygo-tdongle-s3/device.properties +++ b/Devices/lilygo-tdongle-s3/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=0.96" display.shape=rectangle display.dpi=186 diff --git a/Devices/lilygo-thmi/device.properties b/Devices/lilygo-thmi/device.properties index 4da5dd34..d58efc9f 100644 --- a/Devices/lilygo-thmi/device.properties +++ b/Devices/lilygo-thmi/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2.8" display.shape=rectangle display.dpi=125 diff --git a/Devices/lilygo-tlora-pager/device.properties b/Devices/lilygo-tlora-pager/device.properties index a74d00ca..1e363302 100644 --- a/Devices/lilygo-tlora-pager/device.properties +++ b/Devices/lilygo-tlora-pager/device.properties @@ -13,6 +13,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=40M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2.33" display.shape=rectangle display.dpi=227 diff --git a/Devices/m5stack-cardputer-adv/device.properties b/Devices/m5stack-cardputer-adv/device.properties index e500bcf0..ab63ce70 100644 --- a/Devices/m5stack-cardputer-adv/device.properties +++ b/Devices/m5stack-cardputer-adv/device.properties @@ -10,6 +10,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.14" display.shape=rectangle # TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced) diff --git a/Devices/m5stack-cardputer/device.properties b/Devices/m5stack-cardputer/device.properties index c2419c32..f2545fab 100644 --- a/Devices/m5stack-cardputer/device.properties +++ b/Devices/m5stack-cardputer/device.properties @@ -10,6 +10,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.14" display.shape=rectangle # TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced) diff --git a/Devices/m5stack-core2/device.properties b/Devices/m5stack-core2/device.properties index eafb7c19..17156143 100644 --- a/Devices/m5stack-core2/device.properties +++ b/Devices/m5stack-core2/device.properties @@ -10,6 +10,8 @@ hardware.spiRamMode=QUAD hardware.spiRamSpeed=80M hardware.esptoolFlashFreq=80M +storage.userDataLocation=SD + display.size=2" display.shape=rectangle display.dpi=200 diff --git a/Devices/m5stack-cores3/device.properties b/Devices/m5stack-cores3/device.properties index 8fbb6768..28e15bcd 100644 --- a/Devices/m5stack-cores3/device.properties +++ b/Devices/m5stack-cores3/device.properties @@ -12,8 +12,10 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2" display.shape=rectangle display.dpi=200 -lvgl.colorDepth=16 \ No newline at end of file +lvgl.colorDepth=16 diff --git a/Devices/m5stack-papers3/device.properties b/Devices/m5stack-papers3/device.properties index 80ce7247..91cc994f 100644 --- a/Devices/m5stack-papers3/device.properties +++ b/Devices/m5stack-papers3/device.properties @@ -13,6 +13,8 @@ hardware.esptoolFlashFreq=80M hardware.tinyUsb=true hardware.bluetooth=true +storage.userDataLocation=SD + display.size=4.7" display.shape=rectangle display.dpi=235 @@ -22,5 +24,3 @@ lvgl.fontSize=24 lvgl.theme=Mono sdkconfig.CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y - - diff --git a/Devices/m5stack-stackchan/device.properties b/Devices/m5stack-stackchan/device.properties index ad8c15c1..fa5fcaf9 100644 --- a/Devices/m5stack-stackchan/device.properties +++ b/Devices/m5stack-stackchan/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=2" display.shape=rectangle display.dpi=200 diff --git a/Devices/m5stack-stickc-plus/CMakeLists.txt b/Devices/m5stack-stickc-plus/CMakeLists.txt deleted file mode 100644 index b103142f..00000000 --- a/Devices/m5stack-stickc-plus/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) - -idf_component_register( - SRCS ${SOURCE_FILES} - INCLUDE_DIRS "Source" - REQUIRES Tactility esp_lvgl_port esp_lcd AXP192 ST7789 ButtonControl -) diff --git a/Devices/m5stack-stickc-plus/Source/Configuration.cpp b/Devices/m5stack-stickc-plus/Source/Configuration.cpp deleted file mode 100644 index 15e09bfd..00000000 --- a/Devices/m5stack-stickc-plus/Source/Configuration.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "devices/Display.h" -#include "devices/Power.h" - -#include -#include - -using namespace tt::hal; - -static bool initBoot() { - // CH552 applies 4 V to GPIO 0, which reduces Wi-Fi sensitivity - // Setting output to high adds a bias of 3.3 V and suppresses over-voltage: - gpio::configure(0, gpio::Mode::Output, false, false); - gpio::setLevel(0, true); - - return initAxp(); -} - -static DeviceVector createDevices() { - return { - getAxp192(), - ButtonControl::createTwoButtonControl(37, 39), - createDisplay() - }; -} - -extern const Configuration hardwareConfiguration = { - .initBoot = initBoot, - .createDevices = createDevices -}; diff --git a/Devices/m5stack-stickc-plus/Source/devices/Display.cpp b/Devices/m5stack-stickc-plus/Source/devices/Display.cpp deleted file mode 100644 index f6fba81a..00000000 --- a/Devices/m5stack-stickc-plus/Source/devices/Display.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "Display.h" -#include "Power.h" - -#include - -#include -#include - -static const auto LOGGER = tt::Logger("StickCPlus"); - -static void setBacklightOn(bool on) { - const auto axp = getAxp192(); - const auto* driver = axp->getAxp192(); - uint8_t state; - if (axp192_read(driver, AXP192_DCDC13_LDO23_CONTROL, &state) != AXP192_OK) { - LOGGER.info("Failed to read LCD brightness state"); - return; - } - std::bitset<8> new_state = state; - if (new_state[2] != on) { - new_state[2] = on; - const auto new_state_long = new_state.to_ulong(); - axp192_write(driver, AXP192_DCDC13_LDO23_CONTROL, static_cast(new_state_long)); // Display on/off - } -} - -static void setBrightness(uint8_t brightness) { - const auto axp = getAxp192(); - if (brightness) - { - brightness = (((brightness >> 1) + 8) / 13) + 5; - setBacklightOn(true); - axp192_write(axp->getAxp192(), AXP192_LDO23_VOLTAGE, brightness << 4); // Display brightness - } - else - { - setBacklightOn(false); - } -} - -std::shared_ptr createDisplay() { - St7789Display::Configuration panel_configuration = { - .horizontalResolution = LCD_HORIZONTAL_RESOLUTION, - .verticalResolution = LCD_VERTICAL_RESOLUTION, - .gapX = 52, - .gapY = 40, - .swapXY = false, - .mirrorX = false, - .mirrorY = false, - .invertColor = true, - .bufferSize = LCD_BUFFER_SIZE, - .touch = nullptr, - .backlightDutyFunction = setBrightness, - .resetPin = LCD_PIN_RESET, - .lvglSwapBytes = false - }; - - auto spi_configuration = std::make_shared(St7789Display::SpiConfiguration { - .spiHostDevice = LCD_SPI_HOST, - .csPin = LCD_PIN_CS, - .dcPin = LCD_PIN_DC, - .pixelClockFrequency = 40'000'000, - .transactionQueueDepth = 10 - }); - - return std::make_shared(panel_configuration, spi_configuration); -} diff --git a/Devices/m5stack-stickc-plus/Source/devices/Display.h b/Devices/m5stack-stickc-plus/Source/devices/Display.h deleted file mode 100644 index bcab89c0..00000000 --- a/Devices/m5stack-stickc-plus/Source/devices/Display.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -constexpr auto LCD_SPI_HOST = SPI2_HOST; -constexpr auto LCD_PIN_CS = GPIO_NUM_5; -constexpr auto LCD_PIN_DC = GPIO_NUM_23; -constexpr auto LCD_PIN_RESET = GPIO_NUM_18; -constexpr auto LCD_HORIZONTAL_RESOLUTION = 135; -constexpr auto LCD_VERTICAL_RESOLUTION = 240; -constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 3; -constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT; -constexpr auto LCD_SPI_TRANSFER_SIZE_LIMIT = LCD_BUFFER_SIZE * LV_COLOR_DEPTH / 8; - -std::shared_ptr createDisplay(); diff --git a/Devices/m5stack-stickc-plus/Source/devices/Power.cpp b/Devices/m5stack-stickc-plus/Source/devices/Power.cpp deleted file mode 100644 index 3efd322c..00000000 --- a/Devices/m5stack-stickc-plus/Source/devices/Power.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -static std::shared_ptr axp192 = nullptr; - -std::shared_ptr createAxp192() { - assert(axp192 == nullptr); - auto configuration = std::make_unique(device_find_by_name("i2c_internal")); - axp192 = std::make_shared(std::move(configuration)); - return axp192; -} - -std::shared_ptr getAxp192() { - assert(axp192 != nullptr); - return axp192; -} - -bool initAxp() { - const auto axp = createAxp192(); - return axp->init([](auto* driver) { - // Reference: https://github.com/pr3y/Bruce/blob/main/lib/utility/AXP192.cpp - axp192_ioctl(driver, AXP192_LDO23_VOLTAGE, 3300); // LCD backlight - axp192_ioctl(driver, AXP192_ADC_ENABLE_1, 0xff); // Set all ADC enabled - axp192_ioctl(driver, AXP192_CHARGE_CONTROL_1, 0xc0); // Battery charging at 4.2 V and 100 mA - axp192_ioctl(driver, AXP192_ADC_ENABLE_1, 0xff); // Enable battery, AC in, Vbus, APS ADC - uint8_t buffer; - axp192_read(driver, AXP192_DCDC13_LDO23_CONTROL, &buffer); - axp192_ioctl(driver, AXP192_DCDC13_LDO23_CONTROL, buffer | 0x4D); // Enable Ext, LDO2, LDO3, DCDC1 - axp192_ioctl(driver, AXP192_PEK, 0x0C); // 128 ms power on, 4 s power off - axp192_ioctl(driver, AXP192_GPIO0_LDOIO0_VOLTAGE, 0xF0); // 3.3 V RTC voltage - axp192_ioctl(driver, AXP192_GPIO0_CONTROL, 0x02); // Set GPIO0 to LDO - axp192_ioctl(driver, AXP192_VBUS_IPSOUT_CHANNEL, 0x80); // Disable Vbus hold limit - axp192_ioctl(driver, AXP192_BATTERY_CHARGE_HIGH_TEMP, 0xFC); // Set temperature protection - axp192_ioctl(driver, AXP192_BATTERY_CHARGE_CONTROL, 0xA2); // Enable RTC BAT charge - axp192_ioctl(driver, AXP192_SHUTDOWN_BATTERY_CHGLED_CONTROL, 0x46); // Enable bat detection - return true; - }); - -} diff --git a/Devices/m5stack-stickc-plus/Source/devices/Power.h b/Devices/m5stack-stickc-plus/Source/devices/Power.h deleted file mode 100644 index 14a00889..00000000 --- a/Devices/m5stack-stickc-plus/Source/devices/Power.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -bool initAxp(); - -// Must call initAxp() first before this returns a non-nullptr response -std::shared_ptr getAxp192(); - diff --git a/Devices/m5stack-stickc-plus/Source/module.cpp b/Devices/m5stack-stickc-plus/Source/module.cpp deleted file mode 100644 index caaf12df..00000000 --- a/Devices/m5stack-stickc-plus/Source/module.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - -extern "C" { - -static error_t start() { - // Empty for now - return ERROR_NONE; -} - -static error_t stop() { - // Empty for now - return ERROR_NONE; -} - -struct Module m5stack_stickc_plus_module = { - .name = "m5stack-stickc-plus", - .start = start, - .stop = stop, - .symbols = nullptr, - .internal = nullptr -}; - -} diff --git a/Devices/m5stack-stickc-plus/device.properties b/Devices/m5stack-stickc-plus/device.properties deleted file mode 100644 index 181cd242..00000000 --- a/Devices/m5stack-stickc-plus/device.properties +++ /dev/null @@ -1,18 +0,0 @@ -general.vendor=M5Stack -general.name=StickC Plus -general.incubating=true - -apps.launcherAppId=Launcher -apps.autoStartAppId=ApWebServer - -hardware.target=ESP32 -hardware.flashSize=4MB -hardware.spiRam=false -hardware.esptoolFlashFreq=80M - -display.size=1.14" -display.shape=rectangle -display.dpi=242 - -lvgl.colorDepth=16 -lvgl.uiDensity=compact diff --git a/Devices/m5stack-stickc-plus/devicetree.yaml b/Devices/m5stack-stickc-plus/devicetree.yaml deleted file mode 100644 index 287869e9..00000000 --- a/Devices/m5stack-stickc-plus/devicetree.yaml +++ /dev/null @@ -1,5 +0,0 @@ -dependencies: -- Platforms/platform-esp32 -- Drivers/mpu6886-module -- Drivers/bm8563-module -dts: m5stack,stickc-plus.dts diff --git a/Devices/m5stack-stickc-plus/m5stack,stickc-plus.dts b/Devices/m5stack-stickc-plus/m5stack,stickc-plus.dts deleted file mode 100644 index 4946efdc..00000000 --- a/Devices/m5stack-stickc-plus/m5stack,stickc-plus.dts +++ /dev/null @@ -1,66 +0,0 @@ -/dts-v1/; - -#include -#include -#include -#include -#include -#include -#include -#include - -/ { - compatible = "root"; - model = "M5Stack StickC Plus"; - - gpio0 { - compatible = "espressif,esp32-gpio"; - gpio-count = <40>; - }; - - i2c_internal { - compatible = "espressif,esp32-i2c"; - port = ; - clock-frequency = <400000>; - pin-sda = <&gpio0 21 GPIO_FLAG_NONE>; - pin-scl = <&gpio0 22 GPIO_FLAG_NONE>; - - mpu6886 { - compatible = "invensense,mpu6886"; - reg = <0x68>; - }; - - bm8563 { - compatible = "belling,bm8563"; - reg = <0x51>; - }; - }; - - i2c_grove { - compatible = "espressif,esp32-i2c"; - port = ; - clock-frequency = <400000>; - pin-sda = <&gpio0 32 GPIO_FLAG_NONE>; - pin-scl = <&gpio0 33 GPIO_FLAG_NONE>; - }; - - spi0 { - compatible = "espressif,esp32-spi"; - host = ; - cs-gpios = <&gpio0 5 GPIO_FLAG_NONE>; - pin-mosi = <&gpio0 15 GPIO_FLAG_NONE>; - pin-sclk = <&gpio0 13 GPIO_FLAG_NONE>; - - display { - compatible = "display-placeholder"; - }; - }; - - uart_grove: uart1 { - compatible = "espressif,esp32-uart"; - status = "disabled"; - port = ; - pin-tx = <&gpio0 33 GPIO_FLAG_NONE>; - pin-rx = <&gpio0 32 GPIO_FLAG_NONE>; - }; -}; diff --git a/Devices/m5stack-stickc-plus2/device.properties b/Devices/m5stack-stickc-plus2/device.properties index f763c2ff..0dddc076 100644 --- a/Devices/m5stack-stickc-plus2/device.properties +++ b/Devices/m5stack-stickc-plus2/device.properties @@ -12,6 +12,8 @@ hardware.spiRamMode=QUAD hardware.spiRamSpeed=80M hardware.esptoolFlashFreq=80M +storage.userDataLocation=Internal + display.size=1.14" display.shape=rectangle display.dpi=242 diff --git a/Devices/m5stack-sticks3/device.properties b/Devices/m5stack-sticks3/device.properties index a055ee35..685147d1 100644 --- a/Devices/m5stack-sticks3/device.properties +++ b/Devices/m5stack-sticks3/device.properties @@ -12,6 +12,8 @@ hardware.esptoolFlashFreq=80M hardware.tinyUsb=true hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.14" display.shape=rectangle display.dpi=242 diff --git a/Devices/m5stack-tab5/device.properties b/Devices/m5stack-tab5/device.properties index dbb15512..8c11c4b6 100644 --- a/Devices/m5stack-tab5/device.properties +++ b/Devices/m5stack-tab5/device.properties @@ -13,6 +13,8 @@ hardware.bluetooth=true hardware.usbHostEnabled=true hardware.tinyUsb=true +storage.userDataLocation=SD + display.size=5" display.shape=rectangle display.dpi=294 diff --git a/Devices/simulator/device.properties b/Devices/simulator/device.properties index 1c66595e..8406fffb 100644 --- a/Devices/simulator/device.properties +++ b/Devices/simulator/device.properties @@ -5,5 +5,7 @@ apps.launcherAppId=Launcher hardware.target=POSIX +storage.userDataLocation=Internal + lvgl.colorDepth=16 lvgl.fontSize=14 diff --git a/Devices/unphone/device.properties b/Devices/unphone/device.properties index 82ecc658..3b2f5c7a 100644 --- a/Devices/unphone/device.properties +++ b/Devices/unphone/device.properties @@ -10,6 +10,8 @@ hardware.spiRamMode=OCT hardware.spiRamSpeed=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Devices/waveshare-esp32-s3-geek/device.properties b/Devices/waveshare-esp32-s3-geek/device.properties index f17c7f40..19b06a31 100644 --- a/Devices/waveshare-esp32-s3-geek/device.properties +++ b/Devices/waveshare-esp32-s3-geek/device.properties @@ -14,6 +14,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.14" display.shape=rectangle display.dpi=143 diff --git a/Devices/waveshare-s3-lcd-13/device.properties b/Devices/waveshare-s3-lcd-13/device.properties index 6e7e5705..ed688994 100644 --- a/Devices/waveshare-s3-lcd-13/device.properties +++ b/Devices/waveshare-s3-lcd-13/device.properties @@ -14,6 +14,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.3" display.shape=rectangle display.dpi=261 diff --git a/Devices/waveshare-s3-touch-lcd-128/device.properties b/Devices/waveshare-s3-touch-lcd-128/device.properties index 5f03f80a..071fa9f9 100644 --- a/Devices/waveshare-s3-touch-lcd-128/device.properties +++ b/Devices/waveshare-s3-touch-lcd-128/device.properties @@ -14,6 +14,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.28" display.shape=circle display.dpi=265 @@ -24,4 +26,4 @@ lvgl.uiDensity=compact # Fix error "PSRAM space not enough for the Flash instructions" on boot: sdkconfig.CONFIG_SPIRAM_FETCH_INSTRUCTIONS=n sdkconfig.CONFIG_SPIRAM_RODATA=n -sdkconfig.CONFIG_SPIRAM_XIP_FROM_PSRAM=n \ No newline at end of file +sdkconfig.CONFIG_SPIRAM_XIP_FROM_PSRAM=n diff --git a/Devices/waveshare-s3-touch-lcd-147/device.properties b/Devices/waveshare-s3-touch-lcd-147/device.properties index c4f263b2..092fa342 100644 --- a/Devices/waveshare-s3-touch-lcd-147/device.properties +++ b/Devices/waveshare-s3-touch-lcd-147/device.properties @@ -14,6 +14,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=1.47" display.shape=rectangle display.dpi=247 diff --git a/Devices/waveshare-s3-touch-lcd-43/device.properties b/Devices/waveshare-s3-touch-lcd-43/device.properties index 5bf22b8c..c72986ac 100644 --- a/Devices/waveshare-s3-touch-lcd-43/device.properties +++ b/Devices/waveshare-s3-touch-lcd-43/device.properties @@ -4,7 +4,8 @@ general.name=S3 Touch LCD 4.3" apps.launcherAppId=Launcher hardware.target=ESP32S3 -hardware.flashSize=4MB +# Some models have 16MB flash, but some have 8MB. We only support the latter to avoid making more builds. +hardware.flashSize=8MB hardware.spiRam=true hardware.spiRamMode=OCT hardware.spiRamSpeed=120M @@ -12,6 +13,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=120M hardware.bluetooth=true +storage.userDataLocation=Internal + display.size=4.3" display.shape=rectangle display.dpi=217 diff --git a/Devices/wireless-tag-wt32-sc01-plus/device.properties b/Devices/wireless-tag-wt32-sc01-plus/device.properties index beecefe5..18f88ac7 100644 --- a/Devices/wireless-tag-wt32-sc01-plus/device.properties +++ b/Devices/wireless-tag-wt32-sc01-plus/device.properties @@ -12,6 +12,8 @@ hardware.tinyUsb=true hardware.esptoolFlashFreq=80M hardware.bluetooth=true +storage.userDataLocation=SD + display.size=3.5" display.shape=rectangle display.dpi=165 diff --git a/Firmware/Kconfig b/Firmware/Kconfig index 9ec78134..4ddbf8ef 100644 --- a/Firmware/Kconfig +++ b/Firmware/Kconfig @@ -77,6 +77,18 @@ menu "Tactility App" config TT_TDECK_WORKAROUND bool "Temporary work-around until we fix the T-Deck keyboard and trackball settings" default n + choice TT_USER_DATA_LOCATION + prompt "User Data Location" + default TT_USER_DATA_LOCATION_INTERNAL + help + Where user data is stored on this device. + "Internal Flash" assumes /data always exists. + "SD Card" looks for the first mounted SD card at runtime and requires one to be present. + config TT_USER_DATA_LOCATION_SD + bool "SD Card" + config TT_USER_DATA_LOCATION_INTERNAL + bool "Internal Flash" + endchoice config TT_SPLASH_DURATION int "Splash Duration (ms)" default 1000 diff --git a/Tactility/CMakeLists.txt b/Tactility/CMakeLists.txt index ace46103..af6a8bd2 100644 --- a/Tactility/CMakeLists.txt +++ b/Tactility/CMakeLists.txt @@ -67,8 +67,10 @@ if (DEFINED ENV{ESP_IDF_VERSION}) if (NOT DEFINED TACTILITY_SKIP_SPIFFS) # Read-only fatfs_create_rawflash_image(system "${CMAKE_CURRENT_SOURCE_DIR}/../Data/system" FLASH_IN_PROJECT PRESERVE_TIME) - # Read-write - fatfs_create_spiflash_image(data "${CMAKE_CURRENT_SOURCE_DIR}/../Data/data" FLASH_IN_PROJECT PRESERVE_TIME) + # Read-write (skipped when user data lives on the SD card instead of internal flash) + if (NOT CONFIG_TT_USER_DATA_LOCATION_SD) + fatfs_create_spiflash_image(data "${CMAKE_CURRENT_SOURCE_DIR}/../Data/data" FLASH_IN_PROJECT PRESERVE_TIME) + endif () endif () endif () diff --git a/Tactility/Include/Tactility/Paths.h b/Tactility/Include/Tactility/Paths.h index c3930db9..2d009327 100644 --- a/Tactility/Include/Tactility/Paths.h +++ b/Tactility/Include/Tactility/Paths.h @@ -11,7 +11,9 @@ bool findFirstMountedSdCardPath(std::string& path); FileSystem* findSdcardFileSystem(bool mustBeMounted); -std::string getSystemRootPath(); +std::string getUserDataRootPath(); + +std::string getUserDataPath(); std::string getTempPath(); @@ -19,7 +21,7 @@ std::string getAppInstallPath(); std::string getAppInstallPath(const std::string& appId); -std::string getUserPath(); +std::string getUserHomePath(); std::string getAppUserPath(const std::string& appId); diff --git a/Tactility/Private/Tactility/app/chat/ChatSettings.h b/Tactility/Private/Tactility/app/chat/ChatSettings.h index a504c9ac..f9e5ab07 100644 --- a/Tactility/Private/Tactility/app/chat/ChatSettings.h +++ b/Tactility/Private/Tactility/app/chat/ChatSettings.h @@ -14,8 +14,6 @@ namespace tt::app::chat { -constexpr auto* CHAT_SETTINGS_FILE = "/data/settings/chat.properties"; - struct ChatSettingsData { uint32_t senderId = 0; // Unique device ID (randomly generated on first launch) std::string nickname = "Device"; diff --git a/Tactility/Private/Tactility/service/webserver/WebServerService.h b/Tactility/Private/Tactility/service/webserver/WebServerService.h index a27dc525..058c1600 100644 --- a/Tactility/Private/Tactility/service/webserver/WebServerService.h +++ b/Tactility/Private/Tactility/service/webserver/WebServerService.h @@ -97,6 +97,9 @@ public: // Global accessor for controlling the WebServer service void setWebServerEnabled(bool enabled); +// Returns whether the HTTP server is actually running right now (not just the persisted setting) +bool isWebServerEnabled(); + // Get the pubsub for subscribing to WebServer events std::shared_ptr> getPubsub(); diff --git a/Tactility/Source/Paths.cpp b/Tactility/Source/Paths.cpp index 8affa3c0..6857f706 100644 --- a/Tactility/Source/Paths.cpp +++ b/Tactility/Source/Paths.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include namespace tt { @@ -20,14 +23,12 @@ bool findFirstMountedSdCardPath(std::string& path) { FileSystem* findSdcardFileSystem(bool mustBeMounted) { FileSystem* found = nullptr; file_system_for_each(&found, [](auto* fs, void* context) { - char path[128]; - if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true; - // TODO: Find a better way to identify SD card paths - if (std::string(path).starts_with("/sdcard")) { - *static_cast(context) = fs; - return false; + auto* owner = file_system_get_owner(fs); + if (owner == nullptr || device_get_type(owner) != &SDCARD_TYPE) { + return true; } - return true; + *static_cast(context) = fs; + return false; }); if (found && mustBeMounted && !file_system_is_mounted(found)) { return nullptr; @@ -35,24 +36,38 @@ FileSystem* findSdcardFileSystem(bool mustBeMounted) { return found; } -std::string getSystemRootPath() { - std::string root_path; - if (!findFirstMountedSdCardPath(root_path)) { - root_path = file::MOUNT_POINT_DATA; - } - return root_path; +std::string getUserDataRootPath() { +#ifdef CONFIG_TT_USER_DATA_LOCATION_INTERNAL + return file::MOUNT_POINT_DATA; +#elif CONFIG_TT_USER_DATA_LOCATION_SD + auto* fs = findSdcardFileSystem(false); + check(fs); + char fs_path[32]; + check(file_system_get_path(fs, fs_path, sizeof(fs_path)) == ERROR_NONE); + return std::string(fs_path); +#else +#error CONFIG_TT_USER_DATA_* not set or unsupported +#endif +} + +std::string getUserDataPath() { +#ifdef ESP_PLATFORM + return getUserDataRootPath() + "/tactility"; +#else + return "data"; +#endif } std::string getTempPath() { - return getSystemRootPath() + "/tmp"; + return getUserDataPath() + "/tmp"; } std::string getAppInstallPath() { - return getSystemRootPath() + "/app"; + return getUserDataPath() + "/app"; } -std::string getUserPath() { - return getSystemRootPath() + "/user"; +std::string getUserHomePath() { + return getUserDataPath() + "/user"; } std::string getAppInstallPath(const std::string& appId) { @@ -62,7 +77,7 @@ std::string getAppInstallPath(const std::string& appId) { std::string getAppUserPath(const std::string& appId) { assert(app::isValidId(appId)); - return std::format("{}/app/{}", getUserPath(), appId); + return std::format("{}/app/{}", getUserHomePath(), appId); } } \ No newline at end of file diff --git a/Tactility/Source/Tactility.cpp b/Tactility/Source/Tactility.cpp index 6907934c..2530b932 100644 --- a/Tactility/Source/Tactility.cpp +++ b/Tactility/Source/Tactility.cpp @@ -35,6 +35,9 @@ #include #endif +#include "Tactility/Paths.h" + + #include namespace tt { @@ -242,7 +245,7 @@ static void registerInstalledAppsFromFileSystems() { if (!file_system_is_mounted(fs)) return true; char path[128]; if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true; - const auto app_path = std::format("{}/app", path); + const auto app_path = std::format("{}/tactility/app", path); if (!app_path.starts_with(file::MOUNT_POINT_SYSTEM) && file::isDirectory(app_path)) { LOGGER.info("Registering apps from {}", app_path); registerInstalledApps(app_path); @@ -284,18 +287,21 @@ static void registerAndStartPrimaryServices() { #endif } -void createTempDirectory(const std::string& rootPath) { - auto temp_path = std::format("{}/tmp", rootPath); +void createTempDirectory() { + auto data_path = getUserDataPath(); + auto temp_path = std::format("{}/tmp", data_path); if (!file::isDirectory(temp_path)) { - auto lock = file::getLock(rootPath)->asScopedLock(); + auto lock = file::getLock(data_path)->asScopedLock(); if (lock.lock(1000 / portTICK_PERIOD_MS)) { - if (mkdir(temp_path.c_str(), 0777) == 0) { + if (!file::findOrCreateParentDirectory(temp_path, 0777)) { + LOGGER.error("Failed to create {}", data_path); + } else if (mkdir(temp_path.c_str(), 0777) == 0) { LOGGER.info("Created {}", temp_path); } else { LOGGER.error("Failed to create {}", temp_path); } } else { - LOGGER.error(LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, rootPath); + LOGGER.error(LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, data_path); } } else { LOGGER.info("Found existing {}", temp_path); @@ -303,14 +309,7 @@ void createTempDirectory(const std::string& rootPath) { } void prepareFileSystems() { - file_system_for_each(nullptr, [](auto* fs, void* context) { - if (!file_system_is_mounted(fs)) return true; - char path[128]; - if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true; - if (std::string(path) == file::MOUNT_POINT_SYSTEM) return true; - createTempDirectory(path); - return true; - }); + createTempDirectory(); } void registerApps() { diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 39a38c35..5dc0d958 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +46,10 @@ class BootApp : public App { // onShow() reads this instead of the live flag to avoid a race between the two. static std::atomic isUsbBootSplash; + // Set by bootThreadCallback() when CONFIG_TT_USER_DATA_LOCATION_SD is defined but no SD card is mounted. + // onShow() reads this to show an error instead of the normal splash, and boot halts instead of starting the launcher. + static std::atomic sdCardMissing; + Thread thread = Thread( "boot", 5120, @@ -122,11 +128,20 @@ class BootApp : public App { setupDisplay(); // Set backlight prepareFileSystems(); +#ifdef CONFIG_TT_USER_DATA_LOCATION_SD + std::string sd_path; + if (!findFirstMountedSdCardPath(sd_path)) { + LOGGER.error("SD card not found"); + sdCardMissing = true; + } +#endif + if (!setupUsbBootMode()) { LOGGER.info("initFromBootApp"); registerApps(); waitForMinimalSplashDuration(start_time); - stop(manifest.appId); + // When SD card is missing, wait for dialog result + if (!sdCardMissing) stop(manifest.appId); startNextApp(); } @@ -162,6 +177,11 @@ class BootApp : public App { } static void startNextApp() { + if (sdCardMissing) { + alertdialog::start("Error", "SD card not found.\nPlease insert one and reboot.", std::vector { "Reboot" }); + return; + } + #ifdef ESP_PLATFORM if (esp_reset_reason() == ESP_RST_PANIC) { crashdiagnostics::start(); @@ -195,6 +215,12 @@ public: thread.join(); } + void onResult(AppContext& /*app*/, LaunchId /*launchId*/, Result /*result*/, std::unique_ptr /*bundle*/) override { +#ifdef ESP_PLATFORM + esp_restart(); +#endif + } + void onShow(AppContext& app, lv_obj_t* parent) override { lvgl::obj_set_style_bg_blacken(parent); lv_obj_set_style_border_width(parent, 0, LV_STATE_DEFAULT); @@ -232,6 +258,7 @@ public: }; std::atomic BootApp::isUsbBootSplash = false; +std::atomic BootApp::sdCardMissing = false; extern const AppManifest manifest = { .appId = "Boot", diff --git a/Tactility/Source/app/chat/ChatSettings.cpp b/Tactility/Source/app/chat/ChatSettings.cpp index f4ac8417..b0502011 100644 --- a/Tactility/Source/app/chat/ChatSettings.cpp +++ b/Tactility/Source/app/chat/ChatSettings.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -24,6 +25,10 @@ namespace tt::app::chat { static const auto LOGGER = Logger("ChatSettings"); +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/chat.properties"; +} + constexpr auto* KEY_SENDER_ID = "senderId"; constexpr auto* KEY_NICKNAME = "nickname"; constexpr auto* KEY_ENCRYPTION_KEY = "encryptionKey"; @@ -120,7 +125,7 @@ ChatSettingsData loadSettings() { ChatSettingsData settings = getDefaultSettings(); std::map map; - if (!file::loadPropertiesFile(CHAT_SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { settings.senderId = generateSenderId(); return settings; } @@ -171,11 +176,11 @@ bool saveSettings(const ChatSettingsData& settings) { map[KEY_ENCRYPTION_KEY] = ""; } - return file::savePropertiesFile(CHAT_SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } bool settingsFileExists() { - return access(CHAT_SETTINGS_FILE, F_OK) == 0; + return access(getSettingsFilePath().c_str(), F_OK) == 0; } } // namespace tt::app::chat diff --git a/Tactility/Source/app/webserversettings/WebServerSettings.cpp b/Tactility/Source/app/webserversettings/WebServerSettings.cpp index 5fc63f99..b9ae51bb 100644 --- a/Tactility/Source/app/webserversettings/WebServerSettings.cpp +++ b/Tactility/Source/app/webserversettings/WebServerSettings.cpp @@ -29,7 +29,6 @@ class WebServerSettingsApp final : public App { settings::webserver::WebServerSettings originalSettings; bool updated = false; bool wifiSettingsChanged = false; - bool webServerEnabledChanged = false; lv_obj_t* dropdownWifiMode = nullptr; lv_obj_t* textAreaApPassword = nullptr; lv_obj_t* switchApOpenNetwork = nullptr; @@ -61,11 +60,19 @@ class WebServerSettingsApp final : public App { getMainDispatcher().dispatch([app, enabled] { app->wsSettings.webServerEnabled = enabled; app->updated = true; - app->webServerEnabledChanged = true; if (lvgl::lock(100)) { app->updateUrlDisplay(); lvgl::unlock(); } + + // Apply immediately instead of waiting for app exit + const auto copy = app->wsSettings; + if (!settings::webserver::save(copy)) { + LOGGER.warn("Failed to persist WebServer settings; changes may be lost on reboot"); + } + service::webserver::getPubsub()->publish(service::webserver::WebServerEvent::WebServerSettingsChanged); + LOGGER.info("WebServer {}", enabled ? "enabling..." : "disabling..."); + service::webserver::setWebServerEnabled(enabled); }); } @@ -131,30 +138,6 @@ class WebServerSettingsApp final : public App { }); } - static void onSyncAssets(lv_event_t* e) { - auto* app = static_cast(lv_event_get_user_data(e)); - auto* btn = static_cast(lv_event_get_target_obj(e)); - lv_obj_add_state(btn, LV_STATE_DISABLED); - LOGGER.info("Manual asset sync triggered"); - - getMainDispatcher().dispatch([app, btn]{ - bool success = service::webserver::syncAssets(); - if (success) { - LOGGER.info("Asset sync completed successfully"); - } else { - LOGGER.error("Asset sync failed"); - } - // Only re-enable if button still exists (user hasn't navigated away) - // Must acquire LVGL lock since we're not in an LVGL event callback context - if (lvgl::lock(1000)) { - if (lv_obj_is_valid(btn)) { - lv_obj_remove_state(btn, LV_STATE_DISABLED); - } - lvgl::unlock(); - } - }); - } - void updateUrlDisplay() { if (!labelUrlValue) return; @@ -197,6 +180,8 @@ class WebServerSettingsApp final : public App { public: void onCreate(AppContext& app) override { wsSettings = settings::webserver::loadOrGetDefault(); + // Reflect the server's actual running state, in case it differs from the persisted setting + wsSettings.webServerEnabled = service::webserver::isWebServerEnabled(); originalSettings = wsSettings; } @@ -341,32 +326,6 @@ public: updateUrlDisplay(); - // Sync Assets button - auto* sync_wrapper = lv_obj_create(main_wrapper); - lv_obj_set_size(sync_wrapper, LV_PCT(100), LV_SIZE_CONTENT); - lv_obj_set_style_pad_all(sync_wrapper, 10, LV_STATE_DEFAULT); - lv_obj_set_style_border_width(sync_wrapper, 1, LV_STATE_DEFAULT); - lv_obj_set_flex_flow(sync_wrapper, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_flex_cross_place(sync_wrapper, LV_FLEX_ALIGN_START, 0); - - auto* sync_label = lv_label_create(sync_wrapper); - lv_label_set_text(sync_label, "Asset Synchronization"); - - auto* sync_info = lv_label_create(sync_wrapper); - lv_label_set_long_mode(sync_info, LV_LABEL_LONG_WRAP); - lv_obj_set_width(sync_info, LV_PCT(95)); - if (lv_display_get_color_format(lv_obj_get_display(parent)) != LV_COLOR_FORMAT_L8) { - lv_obj_set_style_text_color(sync_info, lv_palette_main(LV_PALETTE_GREY), 0); - } - lv_label_set_text(sync_info, "Sync web assets between Data partition and SD card backup"); - - auto* sync_button = lv_btn_create(sync_wrapper); - lv_obj_set_width(sync_button, LV_SIZE_CONTENT); - auto* sync_button_label = lv_label_create(sync_button); - lv_label_set_text(sync_button_label, "Sync Assets Now"); - lv_obj_center(sync_button_label); - lv_obj_add_event_cb(sync_button, onSyncAssets, LV_EVENT_CLICKED, this); - // Info text auto* info_label = lv_label_create(main_wrapper); lv_label_set_long_mode(info_label, LV_LABEL_LONG_WRAP); @@ -394,11 +353,11 @@ public: } // Save to flash only (settings sync at boot handles SD restore) + // Note: the enable/disable toggle already saved and applied itself immediately const auto copy = wsSettings; const bool wifiChanged = wifiSettingsChanged; - const bool webServerChanged = webServerEnabledChanged; - getMainDispatcher().dispatch([copy, wifiChanged, webServerChanged]{ + getMainDispatcher().dispatch([copy, wifiChanged]{ // Save to flash (fast, low memory pressure) if (!settings::webserver::save(copy)) { LOGGER.warn("Failed to persist WebServer settings; changes may be lost on reboot"); @@ -411,12 +370,6 @@ public: if (wifiChanged) { LOGGER.info("WiFi mode changed to {}", copy.wifiMode == settings::webserver::WiFiMode::AccessPoint ? "AP" : "Station"); } - - // Control WebServer service immediately - if (webServerChanged) { - LOGGER.info("WebServer {}", copy.webServerEnabled ? "enabling..." : "disabling..."); - service::webserver::setWebServerEnabled(copy.webServerEnabled); - } }); } } diff --git a/Tactility/Source/bluetooth/BluetoothSettings.cpp b/Tactility/Source/bluetooth/BluetoothSettings.cpp index f9f23dc6..82237048 100644 --- a/Tactility/Source/bluetooth/BluetoothSettings.cpp +++ b/Tactility/Source/bluetooth/BluetoothSettings.cpp @@ -4,13 +4,16 @@ #include #include #include +#include namespace tt::bluetooth::settings { static const auto LOGGER = Logger("BluetoothSettings"); -// Use the same path as the old service so existing settings survive migration. -constexpr auto* SETTINGS_PATH = "/data/service/bluetooth/settings.properties"; +static std::string getSettingsPath() { + return getUserDataPath() + "/settings/bluetooth.settings"; +} + constexpr auto* KEY_ENABLE_ON_BOOT = "enableOnBoot"; constexpr auto* KEY_SPP_AUTO_START = "sppAutoStart"; constexpr auto* KEY_MIDI_AUTO_START = "midiAutoStart"; @@ -27,7 +30,7 @@ static bool cached_valid = false; static bool load(BluetoothSettings& out) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_PATH, map)) { + if (!file::loadPropertiesFile(getSettingsPath(), map)) { return false; } auto it = map.find(KEY_ENABLE_ON_BOOT); @@ -44,11 +47,11 @@ static bool load(BluetoothSettings& out) { static bool save(const BluetoothSettings& s) { std::map map; - file::loadPropertiesFile(SETTINGS_PATH, map); // ignore failure — may not exist yet + file::loadPropertiesFile(getSettingsPath(), map); // ignore failure — may not exist yet map[KEY_ENABLE_ON_BOOT] = s.enableOnBoot ? "true" : "false"; map[KEY_SPP_AUTO_START] = s.sppAutoStart ? "true" : "false"; map[KEY_MIDI_AUTO_START] = s.midiAutoStart ? "true" : "false"; - return file::savePropertiesFile(SETTINGS_PATH, map); + return file::savePropertiesFile(getSettingsPath(), map); } static BluetoothSettings getCachedOrLoad() { diff --git a/Tactility/Source/service/ServicePaths.cpp b/Tactility/Source/service/ServicePaths.cpp index eb5db903..0cf6d430 100644 --- a/Tactility/Source/service/ServicePaths.cpp +++ b/Tactility/Source/service/ServicePaths.cpp @@ -1,21 +1,15 @@ #include #include -#include +#include #include #include -#ifdef ESP_PLATFORM -constexpr auto PARTITION_PREFIX = std::string("/"); -#else -constexpr auto PARTITION_PREFIX = std::string(""); -#endif - namespace tt::service { std::string ServicePaths::getUserDataDirectory() const { - return std::format("{}{}/service/{}", PARTITION_PREFIX, file::DATA_PARTITION_NAME, manifest->id); + return std::format("{}/service/{}", tt::getUserDataPath(), manifest->id); } std::string ServicePaths::getUserDataPath(const std::string& childPath) const { @@ -24,7 +18,7 @@ std::string ServicePaths::getUserDataPath(const std::string& childPath) const { } std::string ServicePaths::getAssetsDirectory() const { - return std::format("{}{}/service/{}/assets", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, manifest->id); + return std::format("{}/service/{}/assets", tt::getUserDataPath(), manifest->id); } std::string ServicePaths::getAssetsPath(const std::string& childPath) const { diff --git a/Tactility/Source/service/development/DevelopmentSettings.cpp b/Tactility/Source/service/development/DevelopmentSettings.cpp index 04b2fccf..4cdcd89a 100644 --- a/Tactility/Source/service/development/DevelopmentSettings.cpp +++ b/Tactility/Source/service/development/DevelopmentSettings.cpp @@ -1,6 +1,7 @@ #ifdef ESP_PLATFORM #include #include +#include #include #include #include @@ -9,7 +10,10 @@ namespace tt::service::development { static const auto LOGGER = Logger("DevSettings"); -constexpr auto* SETTINGS_FILE = "/data/settings/development.properties"; +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/development.properties"; +} + constexpr auto* SETTINGS_KEY_ENABLE_ON_BOOT = "enableOnBoot"; struct DevelopmentSettings { @@ -18,7 +22,7 @@ struct DevelopmentSettings { static bool load(DevelopmentSettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -34,13 +38,13 @@ static bool load(DevelopmentSettings& settings) { static bool save(const DevelopmentSettings& settings) { std::map map; map[SETTINGS_KEY_ENABLE_ON_BOOT] = settings.enableOnBoot ? "true" : "false"; - return file::savePropertiesFile(SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } void setEnableOnBoot(bool enable) { DevelopmentSettings properties { .enableOnBoot = enable }; if (!save(properties)) { - LOGGER.error("Failed to save {}", SETTINGS_FILE); + LOGGER.error("Failed to save {}", getSettingsFilePath()); } } diff --git a/Tactility/Source/service/webserver/AssetVersion.cpp b/Tactility/Source/service/webserver/AssetVersion.cpp index e06d41e7..37cd4460 100644 --- a/Tactility/Source/service/webserver/AssetVersion.cpp +++ b/Tactility/Source/service/webserver/AssetVersion.cpp @@ -15,9 +15,9 @@ namespace tt::service::webserver { static const auto LOGGER = tt::Logger("AssetVersion"); -constexpr auto* DATA_VERSION_FILE = "/data/webserver/version.json"; +constexpr auto* DATA_VERSION_FILE = "/system/app/WebServer/version.json"; constexpr auto* SD_VERSION_FILE = "/sdcard/tactility/webserver/version.json"; -constexpr auto* DATA_ASSETS_DIR = "/data/webserver"; +constexpr auto* DATA_ASSETS_DIR = "/system/app/WebServer"; constexpr auto* SD_ASSETS_DIR = "/sdcard/tactility/webserver"; static bool loadVersionFromFile(const char* path, AssetVersion& version) { @@ -349,17 +349,6 @@ bool syncAssets() { return true; } - // POST-FLASH RECOVERY: Data empty but SD card exists - if (!dataExists) { - LOGGER.info("Data partition empty - copying from SD card (recovery mode)"); - if (!copyDirectory(SD_ASSETS_DIR, DATA_ASSETS_DIR)) { - LOGGER.error("Failed to copy assets from SD card to Data"); - return false; - } - LOGGER.info("Recovery complete - assets restored from SD card"); - return true; - } - // NORMAL OPERATION: Both exist - compare versions AssetVersion dataVersion, sdVersion; bool hasDataVer = loadDataVersion(dataVersion); diff --git a/Tactility/Source/service/webserver/WebServerService.cpp b/Tactility/Source/service/webserver/WebServerService.cpp index 5675f689..78b1416f 100644 --- a/Tactility/Source/service/webserver/WebServerService.cpp +++ b/Tactility/Source/service/webserver/WebServerService.cpp @@ -207,11 +207,6 @@ bool WebServerService::onStart(ServiceContext& service) { statusbarIconId = lvgl::statusbar_icon_add(); lvgl::statusbar_icon_set_visibility(statusbarIconId, false); - // Run asset synchronization on startup - if (!syncAssets()) { - LOGGER.warn("Asset sync failed, but continuing with available assets"); - } - // Load and cache settings once at boot bool serverEnabled; { @@ -619,7 +614,7 @@ static bool isAllowedBasePath(const std::string& path, bool allowRoot = false) { return false; } if (allowRoot && path == "/") return true; - return path == "/data" || path.starts_with("/data/") || path == "/sdcard" || path.starts_with("/sdcard/"); + return path.starts_with("/data") || path.starts_with("/system/app/WebServer") || path.starts_with("/sdcard"); } // Normalize client-supplied path: URL-decode, trim quotes/control chars, ensure leading slash, collapse duplicate slashes @@ -990,7 +985,6 @@ esp_err_t WebServerService::handleAdminPost(httpd_req_t* request) { } const char* uri = request->uri; - if (strncmp(uri, "/admin/sync", 11) == 0) return handleSync(request); if (strncmp(uri, "/admin/reboot", 13) == 0) return handleReboot(request); LOGGER.info("POST {} - not found in admin dispatcher", uri); httpd_resp_send_err(request, HTTPD_404_NOT_FOUND, "not found"); @@ -1460,10 +1454,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) { #if TT_FEATURE_SCREENSHOT_ENABLED // Determine save location: prefer SD card root if mounted, otherwise /data - std::string save_path; - if (!findFirstMountedSdCardPath(save_path)) { - save_path = file::MOUNT_POINT_DATA; - } + std::string save_path = getUserDataRootPath(); // Find next available filename with incrementing number std::string screenshot_path; @@ -1683,25 +1674,9 @@ esp_err_t WebServerService::handleFsRename(httpd_req_t* request) { // endregion -esp_err_t WebServerService::handleSync(httpd_req_t* request) { - - LOGGER.info("POST /sync"); - - bool success = syncAssets(); - - if (success) { - httpd_resp_sendstr(request, "Assets synchronized successfully"); - } else { - httpd_resp_send_err(request, HTTPD_500_INTERNAL_SERVER_ERROR, "Asset sync failed"); - } - - return success ? ESP_OK : ESP_FAIL; -} - esp_err_t WebServerService::handleReboot(httpd_req_t* request) { LOGGER.info("POST /reboot"); - httpd_resp_sendstr(request, "Rebooting..."); // Reboot after a short delay to allow response to be sent @@ -1724,7 +1699,7 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) { // Special case: serve favicon from system assets if (strcmp(uri, "/favicon.ico") == 0) { - const char* faviconPath = "/data/system/spinner.png"; + const char* faviconPath = "/system/spinner.png"; if (file::isFile(faviconPath)) { httpd_resp_set_type(request, "image/png"); httpd_resp_set_hdr(request, "Cache-Control", "public, max-age=86400"); @@ -1767,11 +1742,9 @@ esp_err_t WebServerService::handleAssets(httpd_req_t* request) { return ESP_FAIL; } - std::string dataPath = std::string("/data/webserver") + requestedPath; + std::string dataPath = std::string("/system/app/WebServer") + requestedPath; if (requestedPath == "/dashboard.html" && !file::isFile(dataPath.c_str())) { - // Dashboard doesn't exist, try default.html - dataPath = "/data/webserver/default.html"; LOGGER.info("dashboard.html not found, serving default.html"); } @@ -1854,6 +1827,11 @@ void setWebServerEnabled(bool enabled) { } } +bool isWebServerEnabled() { + WebServerService* instance = g_webServerInstance.load(); + return instance != nullptr && instance->isEnabled(); +} + } // namespace #endif // ESP_PLATFORM diff --git a/Tactility/Source/service/wifi/WifiApSettings.cpp b/Tactility/Source/service/wifi/WifiApSettings.cpp index 292062ad..c1c49270 100644 --- a/Tactility/Source/service/wifi/WifiApSettings.cpp +++ b/Tactility/Source/service/wifi/WifiApSettings.cpp @@ -181,6 +181,10 @@ bool save(const WifiApSettings& apSettings) { } const auto file_path = getApPropertiesFilePath(service_context->getPaths(), apSettings.ssid); + if (!file::findOrCreateParentDirectory(file_path, 0755)) { + LOGGER.error("Failed to create {}", file_path); + return false; + } std::map map; diff --git a/Tactility/Source/service/wifi/WifiBootSplashInit.cpp b/Tactility/Source/service/wifi/WifiBootSplashInit.cpp index d4ea00eb..23523e22 100644 --- a/Tactility/Source/service/wifi/WifiBootSplashInit.cpp +++ b/Tactility/Source/service/wifi/WifiBootSplashInit.cpp @@ -124,16 +124,9 @@ void bootSplashInit() { getMainDispatcher().dispatch([] { LOGGER.info("bootSplashInit dispatch begin"); // First import any provisioning files placed on the system data partition. - const std::string data_settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings"); + const std::string data_settings_path = file::getChildPath(getUserDataPath(), "provisioning"); importWifiApSettingsFromDir(data_settings_path); - // Then scan attached SD cards as before. - std::string sdcard_path; - if (findFirstMountedSdCardPath((sdcard_path))) { - const std::string sd_settings_path = file::getChildPath(sdcard_path, "settings"); - importWifiApSettingsFromDir(sd_settings_path); - } - if (settings::shouldEnableOnBoot()) { LOGGER.info("Auto-enabling due to setting"); getMainDispatcher().dispatch([] -> void { setEnabled(true); }); diff --git a/Tactility/Source/service/wifi/WifiSettings.cpp b/Tactility/Source/service/wifi/WifiSettings.cpp index e712ffc9..a39762e2 100644 --- a/Tactility/Source/service/wifi/WifiSettings.cpp +++ b/Tactility/Source/service/wifi/WifiSettings.cpp @@ -21,14 +21,14 @@ static WifiSettings cachedSettings { static bool cached = false; -static bool load(WifiSettings& settings) { - auto service_context = findServiceContext(); - if (service_context == nullptr) { - return false; - } +static bool hasWifiSettingsFile(std::shared_ptr context) { + std::string settings_path = context->getPaths()->getUserDataPath("settings.properties"); + return file::isFile(settings_path); +} +static bool load(std::shared_ptr context, WifiSettings& settings) { std::map map; - std::string settings_path = service_context->getPaths()->getUserDataPath("settings.properties"); + std::string settings_path = context->getPaths()->getUserDataPath("settings.properties"); if (!file::loadPropertiesFile(settings_path, map)) { return false; } @@ -42,23 +42,26 @@ static bool load(WifiSettings& settings) { return true; } -static bool save(const WifiSettings& settings) { - auto service_context = findServiceContext(); - if (service_context == nullptr) { - return false; - } +static bool save(std::shared_ptr context, const WifiSettings& settings) { std::map map; map[SETTINGS_KEY_ENABLE_ON_BOOT] = settings.enableOnBoot ? "true" : "false"; - std::string settings_path = service_context->getPaths()->getUserDataPath("settings.properties"); + std::string settings_path = context->getPaths()->getUserDataPath("settings.properties"); + if (!file::findOrCreateParentDirectory(settings_path, 0755)) { + LOGGER.error("Failed to create {}", settings_path); + return false; + } return file::savePropertiesFile(settings_path, map); } WifiSettings getCachedOrLoad() { if (!cached) { - if (!load(cachedSettings)) { - LOGGER.error("Failed to load"); - } else { - cached = true; + auto context = findServiceContext(); + if (context && hasWifiSettingsFile(context)) { + if (load(context, cachedSettings)) { + cached = true; + } else { + LOGGER.info("Failed to load settings, using defaults"); + } } } @@ -67,8 +70,9 @@ WifiSettings getCachedOrLoad() { void setEnableOnBoot(bool enable) { cachedSettings.enableOnBoot = enable; - if (!save(cachedSettings)) { - LOGGER.error("Failed to save"); + auto context = findServiceContext(); + if (context && !save(context, cachedSettings)) { + LOGGER.error("Failed to save settings"); } } diff --git a/Tactility/Source/settings/BootSettings.cpp b/Tactility/Source/settings/BootSettings.cpp index 061e3593..04201606 100644 --- a/Tactility/Source/settings/BootSettings.cpp +++ b/Tactility/Source/settings/BootSettings.cpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace tt::settings { @@ -18,14 +17,7 @@ constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId"; constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId"; static std::string getPropertiesFilePath() { - std::string sdcard_path; - if (findFirstMountedSdCardPath(sdcard_path)) { - std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard_path); - if (file::isFile(path)) { - return path; - } - } - return std::format(PROPERTIES_FILE_FORMAT, file::MOUNT_POINT_DATA); + return std::format(PROPERTIES_FILE_FORMAT, getUserDataPath()); } bool loadBootSettings(BootSettings& properties) { diff --git a/Tactility/Source/settings/DisplaySettings.cpp b/Tactility/Source/settings/DisplaySettings.cpp index ab3a9446..f00f3b7d 100644 --- a/Tactility/Source/settings/DisplaySettings.cpp +++ b/Tactility/Source/settings/DisplaySettings.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include @@ -10,7 +11,10 @@ namespace tt::settings::display { -constexpr auto* SETTINGS_FILE = "/data/settings/display.properties"; +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/display.properties"; +} + constexpr auto* SETTINGS_KEY_ORIENTATION = "orientation"; constexpr auto* SETTINGS_KEY_GAMMA_CURVE = "gammaCurve"; constexpr auto* SETTINGS_KEY_BACKLIGHT_DUTY = "backlightDuty"; @@ -106,7 +110,7 @@ static bool fromString(const std::string& str, ScreensaverType& type) { bool load(DisplaySettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -186,7 +190,7 @@ bool save(const DisplaySettings& settings) { map[SETTINGS_KEY_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0"; map[SETTINGS_KEY_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs); map[SETTINGS_KEY_SCREENSAVER_TYPE] = toString(settings.screensaverType); - return file::savePropertiesFile(SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) { diff --git a/Tactility/Source/settings/KeyboardSettings.cpp b/Tactility/Source/settings/KeyboardSettings.cpp index af2811a6..f900db2c 100644 --- a/Tactility/Source/settings/KeyboardSettings.cpp +++ b/Tactility/Source/settings/KeyboardSettings.cpp @@ -1,12 +1,16 @@ #include #include +#include #include #include namespace tt::settings::keyboard { -constexpr auto* SETTINGS_FILE = "/data/settings/keyboard.properties"; +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/keyboard.properties"; +} + constexpr auto* KEY_BACKLIGHT_ENABLED = "backlightEnabled"; constexpr auto* KEY_BACKLIGHT_BRIGHTNESS = "backlightBrightness"; constexpr auto* KEY_BACKLIGHT_TIMEOUT_ENABLED = "backlightTimeoutEnabled"; @@ -14,7 +18,7 @@ constexpr auto* KEY_BACKLIGHT_TIMEOUT_MS = "backlightTimeoutMs"; bool load(KeyboardSettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -54,7 +58,7 @@ bool save(const KeyboardSettings& settings) { map[KEY_BACKLIGHT_BRIGHTNESS] = std::to_string(settings.backlightBrightness); map[KEY_BACKLIGHT_TIMEOUT_ENABLED] = settings.backlightTimeoutEnabled ? "1" : "0"; map[KEY_BACKLIGHT_TIMEOUT_MS] = std::to_string(settings.backlightTimeoutMs); - return file::savePropertiesFile(SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } } diff --git a/Tactility/Source/settings/SystemSettings.cpp b/Tactility/Source/settings/SystemSettings.cpp index 77ec5b35..488c671b 100644 --- a/Tactility/Source/settings/SystemSettings.cpp +++ b/Tactility/Source/settings/SystemSettings.cpp @@ -1,11 +1,13 @@ #include -#include #include +#include #include #include #include #include +#include "Tactility/Paths.h" + #include namespace tt::settings { @@ -17,12 +19,16 @@ constexpr auto* FILE_PATH_FORMAT = "{}/settings/system.properties"; static bool cached = false; static SystemSettings cachedSettings; +static bool hasSystemSettingsFile() { + auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath()); + return file::isFile(file_path); +} + static bool loadSystemSettingsFromFile(SystemSettings& properties) { - auto file_path = std::format(FILE_PATH_FORMAT, file::MOUNT_POINT_DATA); + auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath()); LOGGER.info("System settings loading from {}", file_path); std::map map; if (!file::loadPropertiesFile(file_path, map)) { - LOGGER.error("Failed to load {}", file_path); return false; } @@ -55,11 +61,12 @@ static bool loadSystemSettingsFromFile(SystemSettings& properties) { } bool loadSystemSettings(SystemSettings& properties) { - if (!cached) { - if (!loadSystemSettingsFromFile(cachedSettings)) { - return false; + if (!cached && hasSystemSettingsFile()) { + if (loadSystemSettingsFromFile(cachedSettings)) { + cached = true; + } else { + LOGGER.error("Failed to load"); } - cached = true; } properties = cachedSettings; @@ -67,7 +74,7 @@ bool loadSystemSettings(SystemSettings& properties) { } bool saveSystemSettings(const SystemSettings& properties) { - auto file_path = std::format(FILE_PATH_FORMAT, file::MOUNT_POINT_DATA); + auto file_path = std::format(FILE_PATH_FORMAT, getUserDataPath()); std::map map; map["language"] = toString(properties.language); map["timeFormat24h"] = properties.timeFormat24h ? "true" : "false"; diff --git a/Tactility/Source/settings/TouchCalibrationSettings.cpp b/Tactility/Source/settings/TouchCalibrationSettings.cpp index 9621d163..1c1da3da 100644 --- a/Tactility/Source/settings/TouchCalibrationSettings.cpp +++ b/Tactility/Source/settings/TouchCalibrationSettings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -12,7 +13,10 @@ namespace tt::settings::touch { -constexpr auto* SETTINGS_FILE = "/data/settings/touch-calibration.properties"; +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/touch-calibration.properties"; +} + constexpr auto* SETTINGS_KEY_ENABLED = "enabled"; constexpr auto* SETTINGS_KEY_X_MIN = "xMin"; constexpr auto* SETTINGS_KEY_X_MAX = "xMax"; @@ -61,7 +65,7 @@ bool isValid(const TouchCalibrationSettings& settings) { bool load(TouchCalibrationSettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -112,7 +116,7 @@ bool save(const TouchCalibrationSettings& settings) { map[SETTINGS_KEY_Y_MIN] = std::to_string(settings.yMin); map[SETTINGS_KEY_Y_MAX] = std::to_string(settings.yMax); - if (!file::savePropertiesFile(SETTINGS_FILE, map)) { + if (!file::savePropertiesFile(getSettingsFilePath(), map)) { return false; } diff --git a/Tactility/Source/settings/TrackballSettings.cpp b/Tactility/Source/settings/TrackballSettings.cpp index 7478b948..1cb68d21 100644 --- a/Tactility/Source/settings/TrackballSettings.cpp +++ b/Tactility/Source/settings/TrackballSettings.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -7,7 +8,10 @@ namespace tt::settings::trackball { -constexpr auto* SETTINGS_FILE = "/data/settings/trackball.properties"; +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/trackball.properties"; +} + constexpr auto* KEY_TRACKBALL_ENABLED = "trackballEnabled"; constexpr auto* KEY_TRACKBALL_MODE = "trackballMode"; constexpr auto* KEY_ENCODER_SENSITIVITY = "encoderSensitivity"; @@ -20,7 +24,7 @@ constexpr uint8_t MAX_POINTER_SENSITIVITY = 10; bool load(TrackballSettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -80,7 +84,7 @@ bool save(const TrackballSettings& settings) { map[KEY_TRACKBALL_MODE] = (settings.trackballMode == TrackballMode::Pointer) ? "1" : "0"; map[KEY_ENCODER_SENSITIVITY] = std::to_string(std::clamp(settings.encoderSensitivity, MIN_ENCODER_SENSITIVITY, MAX_ENCODER_SENSITIVITY)); map[KEY_POINTER_SENSITIVITY] = std::to_string(std::clamp(settings.pointerSensitivity, MIN_POINTER_SENSITIVITY, MAX_POINTER_SENSITIVITY)); - return file::savePropertiesFile(SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } } diff --git a/Tactility/Source/settings/WebServerSettings.cpp b/Tactility/Source/settings/WebServerSettings.cpp index 6b9ecff8..eb8ab34d 100644 --- a/Tactility/Source/settings/WebServerSettings.cpp +++ b/Tactility/Source/settings/WebServerSettings.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -17,8 +18,11 @@ namespace tt::settings::webserver { -static const auto LOGGER = tt::Logger("WebServerSettings"); -constexpr auto* SETTINGS_FILE = "/data/service/webserver/settings.properties"; +static const auto LOGGER = Logger("WebServerSettings"); + +static std::string getSettingsFilePath() { + return getUserDataPath() + "/settings/webserver.properties"; +} // Property keys constexpr auto* KEY_WIFI_ENABLED = "wifiEnabled"; @@ -87,7 +91,7 @@ static bool isEmptyCredential(const std::string& value) { bool load(WebServerSettings& settings) { std::map map; - if (!file::loadPropertiesFile(SETTINGS_FILE, map)) { + if (!file::loadPropertiesFile(getSettingsFilePath(), map)) { return false; } @@ -146,7 +150,7 @@ bool load(WebServerSettings& settings) { // Persist the generated password immediately map[KEY_AP_PASSWORD] = settings.apPassword; - if (file::savePropertiesFile(SETTINGS_FILE, map)) { + if (file::savePropertiesFile(getSettingsFilePath(), map)) { LOGGER.info("Generated and saved new secure AP password"); } else { LOGGER.error("Failed to save generated AP password"); @@ -187,7 +191,7 @@ bool load(WebServerSettings& settings) { // We need to save these to the file so they're consistent across reboots map[KEY_WEBSERVER_USERNAME] = settings.webServerUsername; map[KEY_WEBSERVER_PASSWORD] = settings.webServerPassword; - if (file::savePropertiesFile(SETTINGS_FILE, map)) { + if (file::savePropertiesFile(getSettingsFilePath(), map)) { LOGGER.info("Generated and saved new secure credentials"); } else { LOGGER.error("Failed to save generated credentials - auth may be inconsistent across reboots"); @@ -253,8 +257,7 @@ bool save(const WebServerSettings& settings) { map[KEY_WEBSERVER_USERNAME] = settings.webServerUsername; map[KEY_WEBSERVER_PASSWORD] = settings.webServerPassword; - // Save to flash storage only (no SD backup - settings sync at boot handles restore) - return file::savePropertiesFile(SETTINGS_FILE, map); + return file::savePropertiesFile(getSettingsFilePath(), map); } } diff --git a/Tests/SdkIntegration/tactility.py b/Tests/SdkIntegration/tactility.py index 7fead72f..769de53a 100644 --- a/Tests/SdkIntegration/tactility.py +++ b/Tests/SdkIntegration/tactility.py @@ -12,7 +12,7 @@ import tarfile from urllib.parse import urlparse ttbuild_path = ".tactility" -ttbuild_version = "4.0.0" +ttbuild_version = "4.1.0" ttbuild_cdn = "https://cdn.tactilityproject.org" ttbuild_sdk_json_validity = 3600 # seconds ttport = 6666 @@ -192,7 +192,7 @@ def fetch_sdkconfig_files(platform_targets): for platform in platform_targets: sdkconfig_filename = f"sdkconfig.app.{platform}" target_path = os.path.join(ttbuild_path, sdkconfig_filename) - if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): + if not download_file(f"{ttbuild_cdn}/sdk/{sdkconfig_filename}", target_path): exit_with_error(f"Failed to download sdkconfig file for {platform}") #endregion SDK helpers diff --git a/device.py b/device.py index 93ccbbcc..df1698d3 100644 --- a/device.py +++ b/device.py @@ -94,18 +94,31 @@ def write_defaults(output_file): default_properties = read_file(default_properties_path) output_file.write(default_properties) +def get_user_data_location(device_properties: dict): + user_data_location = get_property_or_exit(device_properties, "storage", "userDataLocation") + if user_data_location not in ("SD", "Internal"): + exit_with_error(f"storage.userDataLocation must be 'SD' or 'Internal', but was: '{user_data_location}'") + return user_data_location + def write_partition_table(output_file, device_properties: dict, is_dev: bool): + flash_size = get_property_or_exit(device_properties, "hardware", "flashSize") + if not flash_size.endswith("MB"): + exit_with_error("Flash size should be written as xMB or xxMB (e.g. 4MB, 16MB)") + flash_size_number = flash_size[:-2] + user_data_location = get_user_data_location(device_properties) + if flash_size_number == "4" and user_data_location == "Internal": + exit_with_error("4MB devices must use storage.userDataLocation=SD; there is no internal-storage partition table for 4MB flash") + variant = "with-sd" if user_data_location == "SD" else "no-sd" + partition_filename = f"partitions-{flash_size_number}mb-{variant}.csv" if is_dev: - flash_size_number = 4 - else: - flash_size = get_property_or_exit(device_properties, "hardware", "flashSize") - if not flash_size.endswith("MB"): - exit_with_error("Flash size should be written as xMB or xxMB (e.g. 4MB, 16MB)") - flash_size_number = flash_size[:-2] + dev_partition_filename = f"partitions-{flash_size_number}mb-{variant}-dev.csv" + if os.path.isfile(dev_partition_filename): + partition_filename = dev_partition_filename + print(f"Using partition table: {partition_filename}") output_file.write("# Partition Table\n") output_file.write("CONFIG_PARTITION_TABLE_CUSTOM=y\n") - output_file.write(f"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions-{flash_size_number}mb.csv\"\n") - output_file.write(f"CONFIG_PARTITION_TABLE_FILENAME=\"partitions-{flash_size_number}mb.csv\"\n") + output_file.write(f"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"{partition_filename}\"\n") + output_file.write(f"CONFIG_PARTITION_TABLE_FILENAME=\"{partition_filename}\"\n") def write_tactility_variables(output_file, device_properties: dict, device_id: str): # Board and vendor @@ -128,6 +141,11 @@ def write_tactility_variables(output_file, device_properties: dict, device_id: s if auto_start_app_id is not None: safe_auto_start_app_id = auto_start_app_id.replace("\"", "\\\"") output_file.write(f"CONFIG_TT_AUTO_START_APP_ID=\"{safe_auto_start_app_id}\"\n") + # User data location + if get_user_data_location(device_properties) == "SD": + output_file.write("CONFIG_TT_USER_DATA_LOCATION_SD=y\n") + else: + output_file.write("CONFIG_TT_USER_DATA_LOCATION_INTERNAL=y\n") def write_core_variables(output_file, device_properties: dict): idf_target = get_property_or_exit(device_properties, "hardware", "target").lower() diff --git a/partitions-8mb.csv b/partitions-16mb-no-sd-dev.csv similarity index 76% rename from partitions-8mb.csv rename to partitions-16mb-no-sd-dev.csv index 6051c95d..497ffa1e 100644 --- a/partitions-8mb.csv +++ b/partitions-16mb-no-sd-dev.csv @@ -3,5 +3,5 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 4M, -system, data, fat, , 300k, -data, data, fat, , 3600k, +system, data, fat, , 100k, +data, data, fat, , 1000k, diff --git a/partitions-16mb.csv b/partitions-16mb-no-sd.csv similarity index 76% rename from partitions-16mb.csv rename to partitions-16mb-no-sd.csv index 89987213..daeee992 100644 --- a/partitions-16mb.csv +++ b/partitions-16mb-no-sd.csv @@ -3,5 +3,5 @@ nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 4M, -system, data, fat, , 300k, -data, data, fat, , 11600k, +system, data, fat, , 100k, +data, data, fat, , 11800k, diff --git a/partitions-4mb.csv b/partitions-16mb-with-sd.csv similarity index 66% rename from partitions-4mb.csv rename to partitions-16mb-with-sd.csv index 00c39a9b..262186df 100644 --- a/partitions-4mb.csv +++ b/partitions-16mb-with-sd.csv @@ -2,6 +2,5 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 3M, -system, data, fat, , 300k, -data, data, fat, , 600k, +factory, app, factory, 0x10000, 4M, +system, data, fat, , 100k, diff --git a/partitions-4mb-with-sd.csv b/partitions-4mb-with-sd.csv new file mode 100644 index 00000000..59d1243b --- /dev/null +++ b/partitions-4mb-with-sd.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 3800k, +system, data, fat, , 100k, diff --git a/partitions-8mb-no-sd-dev.csv b/partitions-8mb-no-sd-dev.csv new file mode 100644 index 00000000..497ffa1e --- /dev/null +++ b/partitions-8mb-no-sd-dev.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 4M, +system, data, fat, , 100k, +data, data, fat, , 1000k, diff --git a/partitions-8mb-no-sd.csv b/partitions-8mb-no-sd.csv new file mode 100644 index 00000000..79544b13 --- /dev/null +++ b/partitions-8mb-no-sd.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 4M, +system, data, fat, , 100k, +data, data, fat, , 3800k, diff --git a/partitions-8mb-with-sd.csv b/partitions-8mb-with-sd.csv new file mode 100644 index 00000000..262186df --- /dev/null +++ b/partitions-8mb-with-sd.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 4M, +system, data, fat, , 100k,