Update properties parsing for app manifest and device manifest files (#544)

This commit is contained in:
Ken Van Hoeylandt
2026-07-03 00:29:01 +02:00
committed by GitHub
parent 35fd7dd536
commit 90afba647e
65 changed files with 1139 additions and 1191 deletions
+21 -26
View File
@@ -2,11 +2,9 @@ import subprocess
from datetime import datetime, UTC from datetime import datetime, UTC
import os import os
import sys import sys
import configparser
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
import json import json
import shutil import shutil
from configparser import RawConfigParser
VERBOSE = False VERBOSE = False
DEVICES_FOLDER = "Devices" DEVICES_FOLDER = "Devices"
@@ -68,32 +66,29 @@ def exit_with_error(message):
sys.exit(1) sys.exit(1)
def read_properties_file(path): def read_properties_file(path):
config = configparser.RawConfigParser() properties = {}
# Don't convert keys to lowercase with open(path, "r") as file:
config.optionxform = str for line in file:
config.read(path) stripped = line.strip()
return config if not stripped or stripped.startswith("#"):
continue
key, sep, value = line.partition("=")
if not sep:
continue
properties[key.strip()] = value.strip()
return properties
def get_property_or_none(properties: RawConfigParser, group: str, key: str): def get_property_or_none(properties: dict, group: str, key: str):
if group not in properties.sections(): return properties.get(f"{group}.{key}")
return None
if key not in properties[group].keys():
return None
return properties[group][key]
def get_boolean_property_or_false(properties: RawConfigParser, group: str, key: str): def get_boolean_property_or_false(properties: dict, group: str, key: str):
if group not in properties.sections(): return properties.get(f"{group}.{key}") == "true"
return False
if key not in properties[group].keys():
return False
return properties[group][key] == "true"
def get_property_or_exit(properties: RawConfigParser, group: str, key: str): def get_property_or_exit(properties: dict, group: str, key: str):
if group not in properties.sections(): full_key = f"{group}.{key}"
exit_with_error(f"Device properties does not contain group: {group}") if full_key not in properties:
if key not in properties[group].keys(): exit_with_error(f"Device properties does not contain key: {full_key}")
exit_with_error(f"Device properties does not contain key: {key}") return properties[full_key]
return properties[group][key]
def read_device_properties(device_id): def read_device_properties(device_id):
mapping_file_path = os.path.join(DEVICES_FOLDER, device_id, "device.properties") mapping_file_path = os.path.join(DEVICES_FOLDER, device_id, "device.properties")
@@ -129,7 +124,7 @@ def to_manifest_chip_name(name):
return "" return ""
def process_device(in_path: str, out_path: str, device_directory: str, device_id: str, device_properties: RawConfigParser, version: str): def process_device(in_path: str, out_path: str, device_directory: str, device_id: str, device_properties: dict, version: str):
in_device_path = os.path.join(in_path, device_directory) in_device_path = os.path.join(in_path, device_directory)
in_device_binaries_path = os.path.join(in_device_path, "Binaries") in_device_binaries_path = os.path.join(in_device_path, "Binaries")
if not os.path.isdir(in_device_binaries_path): if not os.path.isdir(in_device_binaries_path):
+2 -5
View File
@@ -28,7 +28,6 @@ function(READ_PROPERTIES_TO_MAP PROPERTY_FILE RESULT_VAR)
endif () endif ()
file(STRINGS ${PROPERTY_FILE_ABS} lines) file(STRINGS ${PROPERTY_FILE_ABS} lines)
set(current_section "")
set(map_content "") set(map_content "")
foreach(line IN LISTS lines) foreach(line IN LISTS lines)
@@ -37,9 +36,7 @@ function(READ_PROPERTIES_TO_MAP PROPERTY_FILE RESULT_VAR)
continue() continue()
endif () endif ()
if (line MATCHES "^\\[.*\\]$") if (line MATCHES "^([^=]+)=(.*)$")
set(current_section "${line}")
elseif (line MATCHES "^([^=]+)=(.*)$")
set(key "${CMAKE_MATCH_1}") set(key "${CMAKE_MATCH_1}")
set(value "${CMAKE_MATCH_2}") set(value "${CMAKE_MATCH_2}")
string(STRIP "${key}" key) string(STRIP "${key}" key)
@@ -49,7 +46,7 @@ function(READ_PROPERTIES_TO_MAP PROPERTY_FILE RESULT_VAR)
set(value "${CMAKE_MATCH_1}") set(value "${CMAKE_MATCH_1}")
endif () endif ()
list(APPEND map_content "${current_section}${key}" "${value}") list(APPEND map_content "${key}" "${value}")
endif () endif ()
endforeach() endforeach()
+16 -21
View File
@@ -1,25 +1,20 @@
[general] general.vendor=BigTreeTech
vendor=BigTreeTech general.name=Panda Touch,K Touch
name=Panda Touch,K Touch
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true hardware.usbHostEnabled=true
usbHostEnabled=true
[display] display.size=5"
size=5" display.shape=rectangle
shape=rectangle display.dpi=187
dpi=187
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=2432S024C
name=2432S024C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.4"
size=2.4" display.shape=rectangle
shape=rectangle display.dpi=167
dpi=167
[lvgl] lvgl.colorDepth=16
colorDepth=16
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=2432S024R
name=2432S024R
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.4"
size=2.4" display.shape=rectangle
shape=rectangle display.dpi=167
dpi=167
[lvgl] lvgl.colorDepth=16
colorDepth=16
+11 -17
View File
@@ -1,22 +1,16 @@
[general] general.vendor=CYD
vendor=CYD general.name=2432S028R
name=2432S028R
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[cdn] cdn.warningMessage=There are 3 hardware variants of this board. This build works on the original variant only ("v1").
warningMessage=There are 3 hardware variants of this board. This build works on the original variant only ("v1").
[lvgl] lvgl.colorDepth=16
colorDepth=16
+11 -17
View File
@@ -1,22 +1,16 @@
[general] general.vendor=CYD
vendor=CYD general.name=2432S028R v3
name=2432S028R v3
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[cdn] cdn.warningMessage=There are 3 hardware variants of this board. This build only supports board version 3.
warningMessage=There are 3 hardware variants of this board. This build only supports board version 3.
[lvgl] lvgl.colorDepth=16
colorDepth=16
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=2432S032C
name=2432S032C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=3.2"
size=3.2" display.shape=rectangle
shape=rectangle display.dpi=125
dpi=125
[lvgl] lvgl.colorDepth=16
colorDepth=16
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=3248S035C
name=3248S035C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[lvgl] lvgl.colorDepth=16
colorDepth=16
+13 -18
View File
@@ -1,22 +1,17 @@
[general] general.vendor=CYD
vendor=CYD general.name=4848S040C
name=4848S040C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=4"
size=4" display.shape=rectangle
shape=rectangle display.dpi=170
dpi=170
[lvgl] lvgl.colorDepth=16
colorDepth=16
+19 -25
View File
@@ -1,30 +1,24 @@
[general] general.vendor=CYD
vendor=CYD general.name=8048S043C
name=8048S043C general.incubating=false
incubating=false
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=4.3"
size=4.3" display.shape=rectangle
shape=rectangle display.dpi=217
dpi=217
[cdn] cdn.infoMessage=
infoMessage= cdn.warningMessage=
warningMessage=
[lvgl] lvgl.theme=DefaultDark
theme=DefaultDark lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=E32R28T
name=E32R28T
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[lvgl] lvgl.colorDepth=16
colorDepth=16
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=CYD
vendor=CYD general.name=E32R32P
name=E32R32P
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=125
dpi=125
[lvgl] lvgl.colorDepth=16
colorDepth=16
@@ -1,24 +1,19 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Advance 2.8"
name=CrowPanel Advance 2.8"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[lvgl] lvgl.colorDepth=16
colorDepth=16
@@ -1,24 +1,19 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Advance 3.5"
name=CrowPanel Advance 3.5"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[lvgl] lvgl.colorDepth=16
colorDepth=16
@@ -1,25 +1,20 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Advance 5.0"
name=CrowPanel Advance 5.0"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=5"
size=5" display.shape=rectangle
shape=rectangle display.dpi=187
dpi=187
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
@@ -1,19 +1,14 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Basic 2.8"
name=CrowPanel Basic 2.8"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[lvgl] lvgl.colorDepth=16
colorDepth=16
@@ -1,19 +1,14 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Basic 3.5"
name=CrowPanel Basic 3.5"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[lvgl] lvgl.colorDepth=16
colorDepth=16
@@ -1,25 +1,20 @@
[general] general.vendor=Elecrow
vendor=Elecrow general.name=CrowPanel Basic 5.0"
name=CrowPanel Basic 5.0"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=5.0"
size=5.0" display.shape=rectangle
shape=rectangle display.dpi=187
dpi=187
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
+6 -9
View File
@@ -1,12 +1,9 @@
[general] general.vendor=Generic
vendor=Generic general.name=ESP32
name=ESP32
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
+6 -9
View File
@@ -1,12 +1,9 @@
[general] general.vendor=Generic
vendor=Generic general.name=ESP32-C6
name=ESP32-C6
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32C6
target=ESP32C6 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
+6 -9
View File
@@ -1,12 +1,9 @@
[general] general.vendor=Generic
vendor=Generic general.name=ESP32-P4
name=ESP32-P4
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32P4
target=ESP32P4 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
+6 -9
View File
@@ -1,12 +1,9 @@
[general] general.vendor=Generic
vendor=Generic general.name=ESP32-S3
name=ESP32-S3
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
@@ -1,33 +1,27 @@
[general] general.vendor=Guition
vendor=Guition general.name=JC1060P470C-I-W-Y
name=JC1060P470C-I-W-Y
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32P4
target=ESP32P4 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=200M
spiRamSpeed=200M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=7"
size=7" display.shape=rectangle
shape=rectangle display.dpi=187
dpi=187
[lvgl] lvgl.colorDepth=16
colorDepth=16
[sdkconfig] sdkconfig.CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 sdkconfig.CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 sdkconfig.CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y sdkconfig.CONFIG_ESP_HOSTED_ENABLED=y
CONFIG_ESP_HOSTED_ENABLED=y sdkconfig.CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y
CONFIG_ESP_HOSTED_P4_DEV_BOARD_FUNC_BOARD=y sdkconfig.CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y
CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y sdkconfig.CONFIG_SLAVE_IDF_TARGET_ESP32C6=y
CONFIG_SLAVE_IDF_TARGET_ESP32C6=y sdkconfig.CONFIG_ESP_HOSTED_USE_MEMPOOL=n
CONFIG_ESP_HOSTED_USE_MEMPOOL=n
+10 -15
View File
@@ -1,19 +1,14 @@
[general] general.vendor=Guition
vendor=Guition general.name=JC2432W328C
name=JC2432W328C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[lvgl] lvgl.colorDepth=16
colorDepth=16
+15 -20
View File
@@ -1,24 +1,19 @@
[general] general.vendor=Guition
vendor=Guition general.name=JC3248W535C
name=JC3248W535C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[lvgl] lvgl.colorDepth=16
colorDepth=16
+15 -20
View File
@@ -1,24 +1,19 @@
[general] general.vendor=Guition
vendor=Guition general.name=JC8048W550C
name=JC8048W550C
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=5"
size=5" display.shape=rectangle
shape=rectangle display.dpi=187
dpi=187
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
@@ -1,30 +1,24 @@
[general] general.vendor=Heltec
vendor=Heltec general.name=WiFi LoRa 32 v3
name=WiFi LoRa 32 v3 general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=false
spiRam=false hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=0.96"
size=0.96" display.shape=rectangle
shape=rectangle display.dpi=149
dpi=149
[cdn] cdn.infoMessage=Due to the small size of the screen, the icons don't render properly.
infoMessage=Due to the small size of the screen, the icons don't render properly.
[lvgl] lvgl.theme=Mono
theme=Mono lvgl.colorDepth=16
colorDepth=16 lvgl.uiScale=70
uiScale=70 lvgl.uiDensity=compact
uiDensity=compact
+16 -22
View File
@@ -1,27 +1,21 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-Deck,T-Deck Plus
name=T-Deck,T-Deck Plus
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[cdn] cdn.infoMessage=To put the device into bootloader mode: <br/>1. Press the trackball and then the reset button at the same time,<br/>2. Let go of the reset button, then the trackball.<br/><br/>When this website reports that flashing is finished, you likely have to press the reset button.
infoMessage=To put the device into bootloader mode: <br/>1. Press the trackball and then the reset button at the same time,<br/>2. Let go of the reset button, then the trackball.<br/><br/>When this website reports that flashing is finished, you likely have to press the reset button.
[lvgl] lvgl.colorDepth=16
colorDepth=16
+16 -21
View File
@@ -1,25 +1,20 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-Display S3
name=T-Display S3
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.9"
size=1.9" display.shape=rectangle
shape=rectangle display.dpi=191
dpi=191
[lvgl] lvgl.colorDepth=16
colorDepth=16
+14 -19
View File
@@ -1,23 +1,18 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-Display
name=T-Display general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=false
spiRam=false hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle display.dpi=242
dpi=242
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+17 -22
View File
@@ -1,26 +1,21 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-Dongle S3
name=T-Dongle S3 general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=false
spiRam=false hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=0.96"
size=0.96" display.shape=rectangle
shape=rectangle display.dpi=186
dpi=186
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact lvgl.fontSize=10
fontSize=10
+15 -20
View File
@@ -1,24 +1,19 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-HMI
name=T-HMI
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=2.8"
size=2.8" display.shape=rectangle
shape=rectangle display.dpi=125
dpi=125
[lvgl] lvgl.colorDepth=16
colorDepth=16
+17 -22
View File
@@ -1,26 +1,21 @@
[general] general.vendor=LilyGO
vendor=LilyGO general.name=T-Lora Pager
name=T-Lora Pager
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.flashMode=DIO
flashMode=DIO hardware.spiRam=true
spiRam=true hardware.spiRamMode=AUTO
spiRamMode=AUTO hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=40M
esptoolFlashFreq=40M hardware.bluetooth=true
bluetooth=true
[display] display.size=2.33"
size=2.33" display.shape=rectangle
shape=rectangle display.dpi=227
dpi=227
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.dpi=150
dpi=150
+14 -19
View File
@@ -1,24 +1,19 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=Cardputer Adv
name=Cardputer Adv
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=false
spiRam=false hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle
# TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced) # TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced)
dpi=139 display.dpi=139
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+14 -19
View File
@@ -1,24 +1,19 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=Cardputer,Cardputer v1.1
name=Cardputer,Cardputer v1.1
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=false
spiRam=false hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle
# TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced) # TODO: dps is actually 242, but this breaks UI (button selection becomes invisible and switch visibility is reduced)
dpi=139 display.dpi=139
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+14 -20
View File
@@ -1,25 +1,19 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=Core2
name=Core2
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M
[display] display.size=2"
size=2" display.shape=rectangle
shape=rectangle display.dpi=200
dpi=200
[cdn] cdn.warningMessage=This board implementation concerns the original Core2 hardware and **not** the v1.1 variant
warningMessage=This board implementation concerns the original Core2 hardware and **not** the v1.1 variant
[lvgl] lvgl.colorDepth=16
colorDepth=16
+15 -20
View File
@@ -1,24 +1,19 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=CoreS3
name=CoreS3
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=2"
size=2" display.shape=rectangle
shape=rectangle display.dpi=200
dpi=200
[lvgl] lvgl.colorDepth=16
colorDepth=16
+19 -25
View File
@@ -1,32 +1,26 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=PaperS3
name=PaperS3 general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=esp32s3
target=esp32s3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OPI
spiRamMode=OPI hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.tinyUsb=true
tinyUsb=true hardware.bluetooth=true
bluetooth=true
[display] display.size=4.7"
size=4.7" display.shape=rectangle
shape=rectangle display.dpi=235
dpi=235
[lvgl] lvgl.colorDepth=8
colorDepth=8 lvgl.fontSize=24
fontSize=24 lvgl.theme=Mono
theme=Mono
[sdkconfig] sdkconfig.CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y
CONFIG_EPD_DISPLAY_TYPE_ED047TC2=y
+15 -20
View File
@@ -1,24 +1,19 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=StackChan
name=StackChan
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=2"
size=2" display.shape=rectangle
shape=rectangle display.dpi=200
dpi=200
[lvgl] lvgl.colorDepth=16
colorDepth=16
+14 -19
View File
@@ -1,23 +1,18 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=StickC Plus
name=StickC Plus general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=false
spiRam=false hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle display.dpi=242
dpi=242
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+16 -21
View File
@@ -1,25 +1,20 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=StickC Plus2
name=StickC Plus2 general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32
target=ESP32 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle display.dpi=242
dpi=242
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+16 -21
View File
@@ -1,25 +1,20 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=StickS3
name=StickS3
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.tinyUsb=true
tinyUsb=true hardware.bluetooth=true
bluetooth=true
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle display.dpi=242
dpi=242
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
+37 -43
View File
@@ -1,51 +1,45 @@
[general] general.vendor=M5Stack
vendor=M5Stack general.name=Tab5
name=Tab5
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32P4
target=ESP32P4 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=HEX
spiRamMode=HEX hardware.spiRamSpeed=200M
spiRamSpeed=200M hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.bluetooth=true
bluetooth=true hardware.usbHostEnabled=true
usbHostEnabled=true hardware.tinyUsb=true
tinyUsb=true
[display] display.size=5"
size=5" display.shape=rectangle
shape=rectangle display.dpi=294
dpi=294
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=28
fontSize=28 lvgl.dpi=250
dpi=250
[sdkconfig] sdkconfig.CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 sdkconfig.CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 sdkconfig.CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y sdkconfig.CONFIG_SLAVE_IDF_TARGET_ESP32C6=y
CONFIG_SLAVE_IDF_TARGET_ESP32C6=y sdkconfig.CONFIG_ESP_HOSTED_ENABLED=y
CONFIG_ESP_HOSTED_ENABLED=y sdkconfig.CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y
CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y sdkconfig.CONFIG_ESP_HOSTED_SDIO_SLOT_1=y
CONFIG_ESP_HOSTED_SDIO_SLOT_1=y sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_1=13
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_1=13 sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_1=12
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_1=12 sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_1=11
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_1=11 sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_1=10
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_1=10 sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_1=9
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_1=9 sdkconfig.CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_1=8
CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_1=8 sdkconfig.CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE=15
CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE=15
# Fixes recent changes to esp_hosted # Fixes recent changes to esp_hosted
CONFIG_ESP_HOSTED_USE_MEMPOOL=n sdkconfig.CONFIG_ESP_HOSTED_USE_MEMPOOL=n
# Performance: larger L2 cache reduces PSRAM stalls for draw/DPI buffers # Performance: larger L2 cache reduces PSRAM stalls for draw/DPI buffers
CONFIG_CACHE_L2_CACHE_256KB=y sdkconfig.CONFIG_CACHE_L2_CACHE_256KB=y
# Performance: use P4's PPA (pixel processing accelerator for rotation) # Performance: use P4's PPA (pixel processing accelerator for rotation)
CONFIG_LVGL_PORT_ENABLE_PPA=y sdkconfig.CONFIG_LVGL_PORT_ENABLE_PPA=y
CONFIG_LV_DRAW_BUF_ALIGN=64 sdkconfig.CONFIG_LV_DRAW_BUF_ALIGN=64
CONFIG_LV_DEF_REFR_PERIOD=15 sdkconfig.CONFIG_LV_DEF_REFR_PERIOD=15
+6 -10
View File
@@ -1,13 +1,9 @@
[general] general.vendor=Simulator
vendor=Simulator general.name=Tab5Simulator
name=Tab5Simulator
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=POSIX
target=POSIX
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=14
fontSize=14
+14 -20
View File
@@ -1,25 +1,19 @@
[general] general.vendor=unPhone
vendor=unPhone general.name=unPhone
name=unPhone
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=8MB
flashSize=8MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[cdn] cdn.warningMessage=Put the device into bootloader mode by pressing the center nav button and reset for 2-3 seconds, then release reset, then release the nav button.<br/>After flashing is finished, press the reset button to reboot.
warningMessage=Put the device into bootloader mode by pressing the center nav button and reset for 2-3 seconds, then release reset, then release the nav button.<br/>After flashing is finished, press the reset button to reboot.
[lvgl] lvgl.colorDepth=24
colorDepth=24
@@ -1,33 +1,27 @@
[general] general.vendor=Waveshare
vendor=Waveshare general.name=ESP32 S3 GEEK
name=ESP32 S3 GEEK general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.14"
size=1.14" display.shape=rectangle
shape=rectangle display.dpi=143
dpi=143
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
[sdkconfig]
# Fix error "PSRAM space not enough for the Flash instructions" on boot: # Fix error "PSRAM space not enough for the Flash instructions" on boot:
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=n sdkconfig.CONFIG_SPIRAM_FETCH_INSTRUCTIONS=n
CONFIG_SPIRAM_RODATA=n sdkconfig.CONFIG_SPIRAM_RODATA=n
CONFIG_SPIRAM_XIP_FROM_PSRAM=n sdkconfig.CONFIG_SPIRAM_XIP_FROM_PSRAM=n
+18 -23
View File
@@ -1,27 +1,22 @@
[general] general.vendor=WaveShare
vendor=WaveShare general.name=S3 LCD 1.3"
name=S3 LCD 1.3" general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.3"
size=1.3" display.shape=rectangle
shape=rectangle display.dpi=261
dpi=261
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
@@ -1,33 +1,27 @@
[general] general.vendor=WaveShare
vendor=WaveShare general.name=S3 Touch LCD 1.28"
name=S3 Touch LCD 1.28" general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.28"
size=1.28" display.shape=circle
shape=circle display.dpi=265
dpi=265
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
[sdkconfig]
# Fix error "PSRAM space not enough for the Flash instructions" on boot: # Fix error "PSRAM space not enough for the Flash instructions" on boot:
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=n sdkconfig.CONFIG_SPIRAM_FETCH_INSTRUCTIONS=n
CONFIG_SPIRAM_RODATA=n sdkconfig.CONFIG_SPIRAM_RODATA=n
CONFIG_SPIRAM_XIP_FROM_PSRAM=n sdkconfig.CONFIG_SPIRAM_XIP_FROM_PSRAM=n
@@ -1,30 +1,24 @@
[general] general.vendor=WaveShare
vendor=WaveShare general.name=S3 Touch LCD 1.47"
name=S3 Touch LCD 1.47" general.incubating=true
incubating=true
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher apps.autoStartAppId=ApWebServer
autoStartAppId=ApWebServer
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=1.47"
size=1.47" display.shape=rectangle
shape=rectangle display.dpi=247
dpi=247
[cdn] cdn.warningMessage=Touch doesn't work yet
warningMessage=Touch doesn't work yet
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.uiDensity=compact
uiDensity=compact
@@ -1,25 +1,20 @@
[general] general.vendor=WaveShare
vendor=WaveShare general.name=S3 Touch LCD 4.3"
name=S3 Touch LCD 4.3"
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=4MB
flashSize=4MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=OCT
spiRamMode=OCT hardware.spiRamSpeed=120M
spiRamSpeed=120M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=120M
esptoolFlashFreq=120M hardware.bluetooth=true
bluetooth=true
[display] display.size=4.3"
size=4.3" display.shape=rectangle
shape=rectangle display.dpi=217
dpi=217
[lvgl] lvgl.colorDepth=16
colorDepth=16 lvgl.fontSize=18
fontSize=18
@@ -1,24 +1,19 @@
[general] general.vendor=Wireless Tag
vendor=Wireless Tag general.name=WT32 SC01 Plus
name=WT32 SC01 Plus
[apps] apps.launcherAppId=Launcher
launcherAppId=Launcher
[hardware] hardware.target=ESP32S3
target=ESP32S3 hardware.flashSize=16MB
flashSize=16MB hardware.spiRam=true
spiRam=true hardware.spiRamMode=QUAD
spiRamMode=QUAD hardware.spiRamSpeed=80M
spiRamSpeed=80M hardware.tinyUsb=true
tinyUsb=true hardware.esptoolFlashFreq=80M
esptoolFlashFreq=80M hardware.bluetooth=true
bluetooth=true
[display] display.size=3.5"
size=3.5" display.shape=rectangle
shape=rectangle display.dpi=165
dpi=165
[lvgl] lvgl.colorDepth=16
colorDepth=16
+1 -1
View File
@@ -22,7 +22,7 @@ set(DEVICETREE_LOCATION "${PROJECT_ROOT}/Devices/${TACTILITY_DEVICE_ID}")
# Fixes the sdkconfig bluetooth enable options from getting nuked on non-P4+C6 builds when idf build runs # Fixes the sdkconfig bluetooth enable options from getting nuked on non-P4+C6 builds when idf build runs
if (DEFINED ENV{ESP_IDF_VERSION}) if (DEFINED ENV{ESP_IDF_VERSION})
file(READ "${DEVICETREE_LOCATION}/device.properties" device_properties_content) file(READ "${DEVICETREE_LOCATION}/device.properties" device_properties_content)
if (device_properties_content MATCHES "bluetooth=true") if (device_properties_content MATCHES "hardware\\.bluetooth=true")
list(APPEND REQUIRES_LIST bt) list(APPEND REQUIRES_LIST bt)
endif() endif()
endif() endif()
+2 -2
View File
@@ -44,7 +44,7 @@ READ_PROPERTIES_TO_MAP(
device_properties device_properties
) )
# Read UI density # Read UI density
GET_VALUE_FROM_MAP(device_properties "[lvgl]uiDensity" ui_density) GET_VALUE_FROM_MAP(device_properties "lvgl.uiDensity" ui_density)
# Define UiDensity enum value # Define UiDensity enum value
if (ui_density) if (ui_density)
if (ui_density STREQUAL "default") if (ui_density STREQUAL "default")
@@ -52,7 +52,7 @@ if (ui_density)
elseif (ui_density STREQUAL "compact") elseif (ui_density STREQUAL "compact")
set(ui_density_variable "LVGL_UI_DENSITY_COMPACT") set(ui_density_variable "LVGL_UI_DENSITY_COMPACT")
else () else ()
message(FATAL_ERROR "Invalid [lvgl]uiDensity: '${ui_density}'. Must be either 'default' or 'compact'") message(FATAL_ERROR "Invalid lvgl.uiDensity: '${ui_density}'. Must be either 'default' or 'compact'")
endif () endif ()
message("UI density set to '${ui_density}' via properties") message("UI density set to '${ui_density}' via properties")
else () else ()
@@ -2,13 +2,13 @@
#include <Tactility/app/AppManifest.h> #include <Tactility/app/AppManifest.h>
#include <map>
#include <string> #include <string>
namespace tt::app { namespace tt::app {
bool isValidId(const std::string& id); bool isValidId(const std::string& id);
bool parseManifest(const std::map<std::string, std::string>& map, AppManifest& manifest); /** Parses a manifest.properties file, auto-detecting the V1 (sectioned) or V2 (flat) format from its first line. */
bool parseManifest(const std::string& filePath, AppManifest& manifest);
} }
@@ -0,0 +1,23 @@
#pragma once
#include <Tactility/app/AppManifest.h>
#include <map>
#include <string>
namespace tt::app {
bool getValueFromManifest(const std::map<std::string, std::string>& map, const std::string& key, std::string& output);
bool isValidManifestVersion(const std::string& version);
bool isValidAppVersionName(const std::string& version);
bool isValidAppVersionCode(const std::string& version);
bool isValidName(const std::string& name);
/** Parses a V1 (sectioned INI, e.g. "[app]versionName=...") manifest map. */
bool parseManifestV1(const std::map<std::string, std::string>& map, AppManifest& manifest);
/** Parses a V2 (flat dot-notation, e.g. "app.version.name=...") manifest map. */
bool parseManifestV2(const std::map<std::string, std::string>& map, AppManifest& manifest);
}
+1 -9
View File
@@ -3,7 +3,6 @@
#endif #endif
#include <format> #include <format>
#include <map>
#include <Tactility/Tactility.h> #include <Tactility/Tactility.h>
#include <Tactility/TactilityConfig.h> #include <Tactility/TactilityConfig.h>
@@ -17,7 +16,6 @@
#include <Tactility/app/AppRegistration.h> #include <Tactility/app/AppRegistration.h>
#include <Tactility/file/File.h> #include <Tactility/file/File.h>
#include <Tactility/file/FileLock.h> #include <Tactility/file/FileLock.h>
#include <Tactility/file/PropertiesFile.h>
#include <Tactility/hal/HalPrivate.h> #include <Tactility/hal/HalPrivate.h>
#include <Tactility/lvgl/LvglPrivate.h> #include <Tactility/lvgl/LvglPrivate.h>
#include <Tactility/network/NtpPrivate.h> #include <Tactility/network/NtpPrivate.h>
@@ -216,14 +214,8 @@ static void registerInstalledApp(std::string path) {
return; return;
} }
std::map<std::string, std::string> properties;
if (!file::loadPropertiesFile(manifest_path, properties)) {
LOGGER.error("Failed to load manifest at {}", manifest_path);
return;
}
app::AppManifest manifest; app::AppManifest manifest;
if (!app::parseManifest(properties, manifest)) { if (!app::parseManifest(manifest_path, manifest)) {
LOGGER.error("Failed to parse manifest at {}", manifest_path); LOGGER.error("Failed to parse manifest at {}", manifest_path);
return; return;
} }
+1 -9
View File
@@ -4,7 +4,6 @@
#include <Tactility/app/AppRegistration.h> #include <Tactility/app/AppRegistration.h>
#include <Tactility/file/File.h> #include <Tactility/file/File.h>
#include <Tactility/file/FileLock.h> #include <Tactility/file/FileLock.h>
#include <Tactility/file/PropertiesFile.h>
#include <tactility/hal/Device.h> #include <tactility/hal/Device.h>
#include <Tactility/Logger.h> #include <Tactility/Logger.h>
#include <Tactility/Paths.h> #include <Tactility/Paths.h>
@@ -138,15 +137,8 @@ bool install(const std::string& path) {
return false; return false;
} }
std::map<std::string, std::string> properties;
if (!file::loadPropertiesFile(manifest_path, properties)) {
LOGGER.error("Failed to load manifest at {}", manifest_path);
cleanupInstallDirectory(app_target_path);
return false;
}
AppManifest manifest; AppManifest manifest;
if (!parseManifest(properties, manifest)) { if (!parseManifest(manifest_path, manifest)) {
LOGGER.warn("Invalid manifest"); LOGGER.warn("Invalid manifest");
cleanupInstallDirectory(app_target_path); cleanupInstallDirectory(app_target_path);
return false; return false;
+34 -66
View File
@@ -1,8 +1,12 @@
#include <Tactility/app/AppManifestParsing.h> #include <Tactility/app/AppManifestParsing.h>
#include <Tactility/app/AppManifestParsingInternal.h>
#include <Tactility/Logger.h> #include <Tactility/Logger.h>
#include <Tactility/StringUtils.h>
#include <Tactility/file/File.h>
#include <Tactility/file/PropertiesFile.h>
#include <algorithm> #include <algorithm>
#include <regex>
namespace tt::app { namespace tt::app {
@@ -12,7 +16,7 @@ constexpr bool validateString(const std::string& value, const std::function<bool
return std::ranges::all_of(value, isValidChar); return std::ranges::all_of(value, isValidChar);
} }
static bool getValueFromManifest(const std::map<std::string, std::string>& map, const std::string& key, std::string& output) { bool getValueFromManifest(const std::map<std::string, std::string>& map, const std::string& key, std::string& output) {
const auto iterator = map.find(key); const auto iterator = map.find(key);
if (iterator == map.end()) { if (iterator == map.end()) {
LOGGER.error("Failed to find {} in manifest", key); LOGGER.error("Failed to find {} in manifest", key);
@@ -28,98 +32,62 @@ bool isValidId(const std::string& id) {
}); });
} }
static bool isValidManifestVersion(const std::string& version) { bool isValidManifestVersion(const std::string& version) {
return !version.empty() && validateString(version, [](const char c) { return !version.empty() && validateString(version, [](const char c) {
return std::isalnum(c) != 0 || c == '.'; return std::isalnum(c) != 0 || c == '.';
}); });
} }
static bool isValidAppVersionName(const std::string& version) { bool isValidAppVersionName(const std::string& version) {
return !version.empty() && validateString(version, [](const char c) { return !version.empty() && validateString(version, [](const char c) {
return std::isalnum(c) != 0 || c == '.' || c == '-' || c == '_'; return std::isalnum(c) != 0 || c == '.' || c == '-' || c == '_';
}); });
} }
static bool isValidAppVersionCode(const std::string& version) { bool isValidAppVersionCode(const std::string& version) {
return !version.empty() && validateString(version, [](const char c) { return !version.empty() && validateString(version, [](const char c) {
return std::isdigit(c) != 0; return std::isdigit(c) != 0;
}); });
} }
static bool isValidName(const std::string& name) { bool isValidName(const std::string& name) {
return name.size() >= 2 && validateString(name, [](const char c) { return name.size() >= 2 && validateString(name, [](const char c) {
return std::isalnum(c) != 0 || c == ' ' || c == '-'; return std::isalnum(c) != 0 || c == ' ' || c == '-';
}); });
} }
bool parseManifest(const std::map<std::string, std::string>& map, AppManifest& manifest) { /** The V1 format's first line is always the literal "[manifest]" section header; V2 files are flat from the first line onward. */
LOGGER.info("Parsing manifest"); static bool detectIsV1Format(const std::string& filePath) {
std::string first_line;
bool got_first_line = false;
file::readLines(filePath, true, [&first_line, &got_first_line](const char* line) {
if (!got_first_line) {
first_line = string::trim(std::string(line), " \t\r\n");
got_first_line = true;
}
});
return first_line == "[manifest]";
}
// [manifest] bool parseManifest(const std::string& filePath, AppManifest& manifest) {
LOGGER.info("Parsing manifest {}", filePath);
std::string manifest_version; bool is_v1_format = detectIsV1Format(filePath);
if (!getValueFromManifest(map, "[manifest]version", manifest_version)) {
std::map<std::string, std::string> properties;
if (!file::loadPropertiesFile(filePath, properties)) {
LOGGER.error("Failed to load manifest at {}", filePath);
return false; return false;
} }
if (!isValidManifestVersion(manifest_version)) { bool success = is_v1_format
LOGGER.error("Invalid version"); ? parseManifestV1(properties, manifest)
: parseManifestV2(properties, manifest);
if (!success) {
return false; return false;
} }
// [app]
if (!getValueFromManifest(map, "[app]id", manifest.appId)) {
return false;
}
if (!isValidId(manifest.appId)) {
LOGGER.error("Invalid app id");
return false;
}
if (!getValueFromManifest(map, "[app]name", manifest.appName)) {
return false;
}
if (!isValidName(manifest.appName)) {
LOGGER.error("Invalid app name");
return false;
}
if (!getValueFromManifest(map, "[app]versionName", manifest.appVersionName)) {
return false;
}
if (!isValidAppVersionName(manifest.appVersionName)) {
LOGGER.error("Invalid app version name");
return false;
}
std::string version_code_string;
if (!getValueFromManifest(map, "[app]versionCode", version_code_string)) {
return false;
}
if (!isValidAppVersionCode(version_code_string)) {
LOGGER.error("Invalid app version code");
return false;
}
manifest.appVersionCode = std::stoull(version_code_string);
// [target]
if (!getValueFromManifest(map, "[target]sdk", manifest.targetSdk)) {
return false;
}
if (!getValueFromManifest(map, "[target]platforms", manifest.targetPlatforms)) {
return false;
}
// Defaults
manifest.appCategory = Category::User; manifest.appCategory = Category::User;
manifest.appLocation = Location::external(""); manifest.appLocation = Location::external("");
@@ -0,0 +1,77 @@
#include <Tactility/app/AppManifestParsing.h>
#include <Tactility/app/AppManifestParsingInternal.h>
#include <Tactility/Logger.h>
namespace tt::app {
static const auto LOGGER = Logger("AppManifestV1");
bool parseManifestV1(const std::map<std::string, std::string>& map, AppManifest& manifest) {
// [manifest]
std::string manifest_version;
if (!getValueFromManifest(map, "[manifest]version", manifest_version)) {
return false;
}
if (!isValidManifestVersion(manifest_version)) {
LOGGER.error("Invalid version");
return false;
}
// [app]
if (!getValueFromManifest(map, "[app]id", manifest.appId)) {
return false;
}
if (!isValidId(manifest.appId)) {
LOGGER.error("Invalid app id");
return false;
}
if (!getValueFromManifest(map, "[app]name", manifest.appName)) {
return false;
}
if (!isValidName(manifest.appName)) {
LOGGER.error("Invalid app name");
return false;
}
if (!getValueFromManifest(map, "[app]versionName", manifest.appVersionName)) {
return false;
}
if (!isValidAppVersionName(manifest.appVersionName)) {
LOGGER.error("Invalid app version name");
return false;
}
std::string version_code_string;
if (!getValueFromManifest(map, "[app]versionCode", version_code_string)) {
return false;
}
if (!isValidAppVersionCode(version_code_string)) {
LOGGER.error("Invalid app version code");
return false;
}
manifest.appVersionCode = std::stoull(version_code_string);
// [target]
if (!getValueFromManifest(map, "[target]sdk", manifest.targetSdk)) {
return false;
}
if (!getValueFromManifest(map, "[target]platforms", manifest.targetPlatforms)) {
return false;
}
return true;
}
}
@@ -0,0 +1,77 @@
#include <Tactility/app/AppManifestParsing.h>
#include <Tactility/app/AppManifestParsingInternal.h>
#include <Tactility/Logger.h>
namespace tt::app {
static const auto LOGGER = Logger("AppManifestV2");
bool parseManifestV2(const std::map<std::string, std::string>& map, AppManifest& manifest) {
// manifest
std::string manifest_version;
if (!getValueFromManifest(map, "manifest.version", manifest_version)) {
return false;
}
if (!isValidManifestVersion(manifest_version)) {
LOGGER.error("Invalid version");
return false;
}
// app
if (!getValueFromManifest(map, "app.id", manifest.appId)) {
return false;
}
if (!isValidId(manifest.appId)) {
LOGGER.error("Invalid app id");
return false;
}
if (!getValueFromManifest(map, "app.name", manifest.appName)) {
return false;
}
if (!isValidName(manifest.appName)) {
LOGGER.error("Invalid app name");
return false;
}
if (!getValueFromManifest(map, "app.version.name", manifest.appVersionName)) {
return false;
}
if (!isValidAppVersionName(manifest.appVersionName)) {
LOGGER.error("Invalid app version name");
return false;
}
std::string version_code_string;
if (!getValueFromManifest(map, "app.version.code", version_code_string)) {
return false;
}
if (!isValidAppVersionCode(version_code_string)) {
LOGGER.error("Invalid app version code");
return false;
}
manifest.appVersionCode = std::stoull(version_code_string);
// target
if (!getValueFromManifest(map, "target.sdk", manifest.targetSdk)) {
return false;
}
if (!getValueFromManifest(map, "target.platforms", manifest.targetPlatforms)) {
return false;
}
return true;
}
}
+7 -10
View File
@@ -1,10 +1,7 @@
[manifest] manifest.version=0.2
version=0.1 target.sdk=0.0.0
[target] target.platforms=esp32,esp32s3,esp32c6,esp32p4
sdk=0.0.0 app.id=one.tactility.sdktest
platforms=esp32,esp32s3,esp32c6,esp32p4 app.version.name=0.1.0
[app] app.version.code=1
id=one.tactility.sdktest app.name=SDK Test
versionName=0.1.0
versionCode=1
name=SDK Test
+46 -42
View File
@@ -1,4 +1,3 @@
import configparser
import json import json
import os import os
import re import re
@@ -13,7 +12,7 @@ import tarfile
from urllib.parse import urlparse from urllib.parse import urlparse
ttbuild_path = ".tactility" ttbuild_path = ".tactility"
ttbuild_version = "3.3.0" ttbuild_version = "4.0.0"
ttbuild_cdn = "https://cdn.tactilityproject.org" ttbuild_cdn = "https://cdn.tactilityproject.org"
ttbuild_sdk_json_validity = 3600 # seconds ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666 ttport = 6666
@@ -30,10 +29,10 @@ shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m" shell_color_reset = "\033[m"
def print_help(): def print_help():
print("Usage: python tactility.py [action] [options]") print("Usage: python tactility.py [app_path] [action] [options]")
print("") print("")
print("Actions:") print("Actions:")
print(" build [platform] Build the app. Optionally specify a platform.") print(" build [platform] Build the app. Optionally specify a platform.")
print(" Supported platforms are lower case. Example: esp32s3") print(" Supported platforms are lower case. Example: esp32s3")
print(" Supported platforms are read from manifest.properties") print(" Supported platforms are read from manifest.properties")
print(" clean Clean the build folders") print(" clean Clean the build folders")
@@ -50,6 +49,10 @@ def print_help():
print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH with platform subfolders matching target platforms.") print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH with platform subfolders matching target platforms.")
print(" --skip-build Run everything except the idf.py/CMake commands") print(" --skip-build Run everything except the idf.py/CMake commands")
print(" --verbose Show extra console output") print(" --verbose Show extra console output")
print("")
print("Examples:")
print(" python tactility.py Apps/Snake build esp32s3 --verbose")
print(" python tactility.py Apps/Snake bir 192.168.1.50 esp32s3")
# region Core # region Core
@@ -102,9 +105,17 @@ def get_url(ip, path):
return f"http://{ip}:{ttport}{path}" return f"http://{ip}:{ttport}{path}"
def read_properties_file(path): def read_properties_file(path):
config = configparser.RawConfigParser() properties = {}
config.read(path) with open(path, "r") as file:
return config for line in file:
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
key, sep, value = line.partition("=")
if not sep:
continue
properties[key.strip()] = value.strip()
return properties
#endregion Core #endregion Core
@@ -227,32 +238,12 @@ def read_manifest():
return read_properties_file("manifest.properties") return read_properties_file("manifest.properties")
def validate_manifest(manifest): def validate_manifest(manifest):
# [manifest] for key in ("manifest.version", "target.sdk", "target.platforms", "app.id", "app.version.name", "app.version.code", "app.name"):
if not "manifest" in manifest: if key not in manifest:
exit_with_error("Invalid manifest format: [manifest] not found") exit_with_error(f"Invalid manifest format: {key} not found")
if not "version" in manifest["manifest"]:
exit_with_error("Invalid manifest format: [manifest] version not found")
# [target]
if not "target" in manifest:
exit_with_error("Invalid manifest format: [target] not found")
if not "sdk" in manifest["target"]:
exit_with_error("Invalid manifest format: [target] sdk not found")
if not "platforms" in manifest["target"]:
exit_with_error("Invalid manifest format: [target] platforms not found")
# [app]
if not "app" in manifest:
exit_with_error("Invalid manifest format: [app] not found")
if not "id" in manifest["app"]:
exit_with_error("Invalid manifest format: [app] id not found")
if not "versionName" in manifest["app"]:
exit_with_error("Invalid manifest format: [app] versionName not found")
if not "versionCode" in manifest["app"]:
exit_with_error("Invalid manifest format: [app] versionCode not found")
if not "name" in manifest["app"]:
exit_with_error("Invalid manifest format: [app] name not found")
def is_valid_manifest_platform(manifest, platform): def is_valid_manifest_platform(manifest, platform):
manifest_platforms = manifest["target"]["platforms"].split(",") manifest_platforms = manifest["target.platforms"].split(",")
return platform in manifest_platforms return platform in manifest_platforms
def validate_manifest_platform(manifest, platform): def validate_manifest_platform(manifest, platform):
@@ -261,7 +252,7 @@ def validate_manifest_platform(manifest, platform):
def get_manifest_target_platforms(manifest, requested_platform): def get_manifest_target_platforms(manifest, requested_platform):
if requested_platform == "" or requested_platform is None: if requested_platform == "" or requested_platform is None:
return manifest["target"]["platforms"].split(",") return manifest["target.platforms"].split(",")
else: else:
validate_manifest_platform(manifest, requested_platform) validate_manifest_platform(manifest, requested_platform)
return [requested_platform] return [requested_platform]
@@ -422,7 +413,7 @@ def build_consecutively(version, platform, skip_build):
shell_needed = sys.platform == "win32" shell_needed = sys.platform == "win32"
build_command = ["idf.py", "-B", cmake_path, "elf"] build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose: if verbose:
print(f"Running command: {" ".join(build_command)}") print(f"Running command: {' '.join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process: with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process) build_output = wait_for_process(process)
if process.returncode == 0: if process.returncode == 0:
@@ -451,7 +442,7 @@ def package_intermediate_binaries(target_path, platforms):
for platform in platforms: for platform in platforms:
elf_path = find_elf_file(platform) elf_path = find_elf_file(platform)
if elf_path is None: if elf_path is None:
print_error(f"ELF file not found at {elf_path}") print_error(f"ELF file not found for {platform}")
return False return False
shutil.copy(elf_path, os.path.join(elf_dir, f"{platform}.elf")) shutil.copy(elf_path, os.path.join(elf_dir, f"{platform}.elf"))
return True return True
@@ -486,9 +477,8 @@ def package_all(platforms):
# Create build/something.app # Create build/something.app
try: try:
tar_path = package_name(platforms) tar_path = package_name(platforms)
tar = tarfile.open(tar_path, mode="w", format=tarfile.USTAR_FORMAT) with tarfile.open(tar_path, mode="w", format=tarfile.USTAR_FORMAT) as tar:
tar.add(os.path.join("build", "package-intermediate"), arcname="") tar.add(os.path.join("build", "package-intermediate"), arcname="")
tar.close()
print_status_success(status) print_status_success(status)
return True return True
except Exception as e: except Exception as e:
@@ -509,7 +499,7 @@ def build_action(manifest, platform_arg, skip_build):
if use_local_sdk: if use_local_sdk:
global local_base_path global local_base_path
local_base_path = os.environ.get("TACTILITY_SDK_PATH") local_base_path = os.environ.get("TACTILITY_SDK_PATH")
validate_local_sdks(platforms_to_build, manifest["target"]["sdk"]) validate_local_sdks(platforms_to_build, manifest["target.sdk"])
if should_fetch_sdkconfig_files(platforms_to_build): if should_fetch_sdkconfig_files(platforms_to_build):
fetch_sdkconfig_files(platforms_to_build) fetch_sdkconfig_files(platforms_to_build)
@@ -518,7 +508,7 @@ def build_action(manifest, platform_arg, skip_build):
sdk_json = read_sdk_json() sdk_json = read_sdk_json()
validate_self(sdk_json) validate_self(sdk_json)
# Build # Build
sdk_version = manifest["target"]["sdk"] sdk_version = manifest["target.sdk"]
if not use_local_sdk: if not use_local_sdk:
if not sdk_download_all(sdk_version, platforms_to_build): if not sdk_download_all(sdk_version, platforms_to_build):
exit_with_error("Failed to download one or more SDKs") exit_with_error("Failed to download one or more SDKs")
@@ -567,7 +557,7 @@ def get_device_info(ip):
print_status_error(f"Device info request failed: {e}") print_status_error(f"Device info request failed: {e}")
def run_action(manifest, ip): def run_action(manifest, ip):
app_id = manifest["app"]["id"] app_id = manifest["app.id"]
print_status_busy("Running") print_status_busy("Running")
url = get_url(ip, "/app/run") url = get_url(ip, "/app/run")
params = {'id': app_id} params = {'id': app_id}
@@ -611,7 +601,7 @@ def install_action(ip, platforms):
return False return False
def uninstall_action(manifest, ip): def uninstall_action(manifest, ip):
app_id = manifest["app"]["id"] app_id = manifest["app.id"]
print_status_busy("Uninstalling") print_status_busy("Uninstalling")
url = get_url(ip, "/app/uninstall") url = get_url(ip, "/app/uninstall")
params = {'id': app_id} params = {'id': app_id}
@@ -645,6 +635,20 @@ if __name__ == "__main__":
if "--local-sdk" in sys.argv: if "--local-sdk" in sys.argv:
use_local_sdk = True use_local_sdk = True
sys.argv.remove("--local-sdk") sys.argv.remove("--local-sdk")
# Check if the first argument is a path to an app directory
if len(sys.argv) > 2:
potential_app_dir = sys.argv[1]
if os.path.isdir(potential_app_dir) and os.path.isfile(os.path.join(potential_app_dir, "manifest.properties")):
if verbose:
print_status_success(f"Switching to app directory: {potential_app_dir}")
os.chdir(potential_app_dir)
sys.argv = [sys.argv[0]] + sys.argv[2:]
if len(sys.argv) < 2:
print_help()
sys.exit(1)
action_arg = sys.argv[1] action_arg = sys.argv[1]
# Environment setup # Environment setup
@@ -653,7 +657,7 @@ if __name__ == "__main__":
exit_with_error("manifest.properties not found") exit_with_error("manifest.properties not found")
manifest = read_manifest() manifest = read_manifest()
validate_manifest(manifest) validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",") all_platform_targets = manifest["target.platforms"].split(",")
# Update SDK cache (tool.json) # Update SDK cache (tool.json)
if not use_local_sdk and should_update_tool_json() and not update_tool_json(): if not use_local_sdk and should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info") exit_with_error("Failed to retrieve SDK info")
@@ -0,0 +1,83 @@
#include "../../TactilityCore/Source/TestFile.h"
#include "../../Tactility/Private/Tactility/app/AppManifestParsing.h"
#include "../../Tactility/Private/Tactility/app/AppManifestParsingInternal.h"
#include "doctest.h"
using namespace tt;
using namespace tt::app;
TEST_CASE("parseManifest() should parse a V1 (sectioned) manifest.properties file") {
TestFile file("test-manifest-v1.properties");
file.writeData(
"[manifest]\n"
"version=0.1\n"
"[target]\n"
"sdk=0.0.0\n"
"platforms=esp32,esp32s3,esp32c6,esp32p4\n"
"[app]\n"
"id=one.tactility.sdktest\n"
"versionName=0.1.0\n"
"versionCode=1\n"
"name=SDK Test\n"
);
AppManifest manifest;
CHECK_EQ(parseManifest(file.getPath(), manifest), true);
CHECK_EQ(manifest.targetSdk, "0.0.0");
CHECK_EQ(manifest.targetPlatforms, "esp32,esp32s3,esp32c6,esp32p4");
CHECK_EQ(manifest.appId, "one.tactility.sdktest");
CHECK_EQ(manifest.appName, "SDK Test");
CHECK_EQ(manifest.appVersionName, "0.1.0");
CHECK_EQ(manifest.appVersionCode, 1);
}
TEST_CASE("parseManifest() should parse a V2 (flat) manifest.properties file") {
TestFile file("test-manifest-v2.properties");
file.writeData(
"manifest.version=0.1\n"
"target.sdk=0.0.0\n"
"target.platforms=esp32,esp32s3,esp32c6,esp32p4\n"
"app.id=one.tactility.sdktest\n"
"app.version.name=0.1.0\n"
"app.version.code=1\n"
"app.name=SDK Test\n"
);
AppManifest manifest;
CHECK_EQ(parseManifest(file.getPath(), manifest), true);
CHECK_EQ(manifest.targetSdk, "0.0.0");
CHECK_EQ(manifest.targetPlatforms, "esp32,esp32s3,esp32c6,esp32p4");
CHECK_EQ(manifest.appId, "one.tactility.sdktest");
CHECK_EQ(manifest.appName, "SDK Test");
CHECK_EQ(manifest.appVersionName, "0.1.0");
CHECK_EQ(manifest.appVersionCode, 1);
}
TEST_CASE("parseManifestV1() should fail when a required key is missing") {
std::map<std::string, std::string> properties = {
{"[manifest]version", "0.1"},
{"[app]id", "one.tactility.sdktest"},
{"[app]name", "SDK Test"},
{"[app]versionName", "0.1.0"},
{"[app]versionCode", "1"},
// Missing [target]sdk
{"[target]platforms", "esp32"},
};
AppManifest manifest;
CHECK_EQ(parseManifestV1(properties, manifest), false);
}
TEST_CASE("parseManifestV2() should fail when the app id is invalid") {
std::map<std::string, std::string> properties = {
{"manifest.version", "0.1"},
{"app.id", "abc"}, // too short (isValidId requires >= 5 chars)
{"app.name", "SDK Test"},
{"app.version.name", "0.1.0"},
{"app.version.code", "1"},
{"target.sdk", "0.0.0"},
{"target.platforms", "esp32"},
};
AppManifest manifest;
CHECK_EQ(parseManifestV2(properties, manifest), false);
}
+42 -45
View File
@@ -1,9 +1,7 @@
import configparser
import glob import glob
import os import os
import shutil import shutil
import sys import sys
from configparser import ConfigParser
if sys.platform == "win32": if sys.platform == "win32":
SHELL_COLOR_RED = "" SHELL_COLOR_RED = ""
@@ -42,11 +40,17 @@ def read_file(path: str):
return result return result
def read_properties_file(path): def read_properties_file(path):
config = configparser.RawConfigParser() properties = {}
# Don't convert keys to lowercase with open(path, "r") as file:
config.optionxform = str for line in file:
config.read(path) stripped = line.strip()
return config if not stripped or stripped.startswith("#"):
continue
key, sep, value = line.partition("=")
if not sep:
continue
properties[key.strip()] = value.strip()
return properties
def read_device_properties(device_id): def read_device_properties(device_id):
device_file_path = get_properties_file_path(device_id) device_file_path = get_properties_file_path(device_id)
@@ -54,32 +58,24 @@ def read_device_properties(device_id):
exit_with_error(f"Device file not found: {device_file_path}") exit_with_error(f"Device file not found: {device_file_path}")
return read_properties_file(device_file_path) return read_properties_file(device_file_path)
def has_group(properties: ConfigParser, group: str): def has_group(properties: dict, group: str):
return group in properties.sections() prefix = f"{group}."
return any(key.startswith(prefix) for key in properties)
def get_property_or_exit(properties: ConfigParser, group: str, key: str): def get_property_or_exit(properties: dict, group: str, key: str):
if group not in properties.sections(): full_key = f"{group}.{key}"
exit_with_error(f"Device properties does not contain group: {group}") if full_key not in properties:
if key not in properties[group].keys(): exit_with_error(f"Device properties does not contain key: {full_key}")
exit_with_error(f"Device properties does not contain key: {key}") return properties[full_key]
return properties[group][key]
def get_property_or_default(properties: ConfigParser, group: str, key: str, default): def get_property_or_default(properties: dict, group: str, key: str, default):
if group not in properties.sections(): return properties.get(f"{group}.{key}", default)
return default
if key not in properties[group].keys():
return default
return properties[group][key]
def get_property_or_none(properties: ConfigParser, group: str, key: str): def get_property_or_none(properties: dict, group: str, key: str):
return get_property_or_default(properties, group, key, None) return get_property_or_default(properties, group, key, None)
def get_boolean_property_or_false(properties: ConfigParser, group: str, key: str): def get_boolean_property_or_false(properties: dict, group: str, key: str):
if group not in properties.sections(): return properties.get(f"{group}.{key}") == "true"
return False
if key not in properties[group].keys():
return False
return properties[group][key] == "true"
def safe_int(value: str, error_message: str): def safe_int(value: str, error_message: str):
try: try:
@@ -98,7 +94,7 @@ def write_defaults(output_file):
default_properties = read_file(default_properties_path) default_properties = read_file(default_properties_path)
output_file.write(default_properties) output_file.write(default_properties)
def write_partition_table(output_file, device_properties: ConfigParser, is_dev: bool): def write_partition_table(output_file, device_properties: dict, is_dev: bool):
if is_dev: if is_dev:
flash_size_number = 4 flash_size_number = 4
else: else:
@@ -111,7 +107,7 @@ def write_partition_table(output_file, device_properties: ConfigParser, is_dev:
output_file.write(f"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions-{flash_size_number}mb.csv\"\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_FILENAME=\"partitions-{flash_size_number}mb.csv\"\n")
def write_tactility_variables(output_file, device_properties: ConfigParser, device_id: str): def write_tactility_variables(output_file, device_properties: dict, device_id: str):
# Board and vendor # Board and vendor
board_vendor = get_property_or_exit(device_properties, "general", "vendor").replace("\"", "\\\"") board_vendor = get_property_or_exit(device_properties, "general", "vendor").replace("\"", "\\\"")
board_name = get_property_or_exit(device_properties, "general", "name").replace("\"", "\\\"") board_name = get_property_or_exit(device_properties, "general", "name").replace("\"", "\\\"")
@@ -133,7 +129,7 @@ def write_tactility_variables(output_file, device_properties: ConfigParser, devi
safe_auto_start_app_id = auto_start_app_id.replace("\"", "\\\"") 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") output_file.write(f"CONFIG_TT_AUTO_START_APP_ID=\"{safe_auto_start_app_id}\"\n")
def write_core_variables(output_file, device_properties: ConfigParser): def write_core_variables(output_file, device_properties: dict):
idf_target = get_property_or_exit(device_properties, "hardware", "target").lower() idf_target = get_property_or_exit(device_properties, "hardware", "target").lower()
output_file.write("# Target\n") output_file.write("# Target\n")
output_file.write(f"CONFIG_IDF_TARGET=\"{idf_target}\"\n") output_file.write(f"CONFIG_IDF_TARGET=\"{idf_target}\"\n")
@@ -157,7 +153,7 @@ def write_core_variables(output_file, device_properties: ConfigParser):
output_file.write("CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH=y\n") output_file.write("CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH=y\n")
output_file.write("CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y\n") output_file.write("CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y\n")
def write_flash_variables(output_file, device_properties: ConfigParser): def write_flash_variables(output_file, device_properties: dict):
flash_size = get_property_or_exit(device_properties, "hardware", "flashSize") flash_size = get_property_or_exit(device_properties, "hardware", "flashSize")
if not flash_size.endswith("MB"): if not flash_size.endswith("MB"):
exit_with_error("Flash size should be written as xMB or xxMB (e.g. 4MB, 16MB)") exit_with_error("Flash size should be written as xMB or xxMB (e.g. 4MB, 16MB)")
@@ -170,7 +166,7 @@ def write_flash_variables(output_file, device_properties: ConfigParser):
if esptool_flash_freq is not None: if esptool_flash_freq is not None:
output_file.write(f"CONFIG_ESPTOOLPY_FLASHFREQ_{esptool_flash_freq}=y\n") output_file.write(f"CONFIG_ESPTOOLPY_FLASHFREQ_{esptool_flash_freq}=y\n")
def write_spiram_variables(output_file, device_properties: ConfigParser): def write_spiram_variables(output_file, device_properties: dict):
idf_target = get_property_or_exit(device_properties, "hardware", "target").lower() idf_target = get_property_or_exit(device_properties, "hardware", "target").lower()
has_spiram = get_property_or_exit(device_properties, "hardware", "spiRam") has_spiram = get_property_or_exit(device_properties, "hardware", "spiRam")
if has_spiram != "true": if has_spiram != "true":
@@ -202,7 +198,7 @@ def write_spiram_variables(output_file, device_properties: ConfigParser):
output_file.write("CONFIG_SPIRAM_RODATA=y\n") output_file.write("CONFIG_SPIRAM_RODATA=y\n")
output_file.write("CONFIG_SPIRAM_XIP_FROM_PSRAM=y\n") output_file.write("CONFIG_SPIRAM_XIP_FROM_PSRAM=y\n")
def write_performance_improvements(output_file, device_properties: ConfigParser): def write_performance_improvements(output_file, device_properties: dict):
idf_target = get_property_or_exit(device_properties, "hardware", "target").lower() idf_target = get_property_or_exit(device_properties, "hardware", "target").lower()
if idf_target == "esp32s3": if idf_target == "esp32s3":
output_file.write("# Performance improvement: Fixes glitches in the RGB display driver when rendering new screens/apps\n") output_file.write("# Performance improvement: Fixes glitches in the RGB display driver when rendering new screens/apps\n")
@@ -220,7 +216,7 @@ def write_lvgl_variable_placeholders(output_file):
output_file.write("CONFIG_TT_LVGL_LAUNCHER_ICON_SIZE=30\n") output_file.write("CONFIG_TT_LVGL_LAUNCHER_ICON_SIZE=30\n")
output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=12\n") output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=12\n")
def write_lvgl_variables(output_file, device_properties: ConfigParser): def write_lvgl_variables(output_file, device_properties: dict):
output_file.write("# LVGL\n") output_file.write("# LVGL\n")
if not has_group(device_properties, "lvgl") or not has_group(device_properties, "display"): if not has_group(device_properties, "lvgl") or not has_group(device_properties, "display"):
write_lvgl_variable_placeholders(output_file) write_lvgl_variable_placeholders(output_file)
@@ -314,7 +310,7 @@ def write_lvgl_variables(output_file, device_properties: ConfigParser):
output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=32\n") output_file.write("CONFIG_TT_LVGL_SHARED_ICON_SIZE=32\n")
def write_usb_variables(output_file, device_properties: ConfigParser): def write_usb_variables(output_file, device_properties: dict):
has_tiny_usb = get_boolean_property_or_false(device_properties, "hardware", "tinyUsb") has_tiny_usb = get_boolean_property_or_false(device_properties, "hardware", "tinyUsb")
if has_tiny_usb: if has_tiny_usb:
output_file.write("# TinyUSB\n") output_file.write("# TinyUSB\n")
@@ -328,7 +324,7 @@ def write_usb_variables(output_file, device_properties: ConfigParser):
# the FS/FSLS controller (USB-C OTG on Tab5), avoiding the conflict. # the FS/FSLS controller (USB-C OTG on Tab5), avoiding the conflict.
output_file.write("CONFIG_TINYUSB_RHPORT_FS=y\n") output_file.write("CONFIG_TINYUSB_RHPORT_FS=y\n")
def write_bluetooth_variables(output_file, device_properties: ConfigParser): def write_bluetooth_variables(output_file, device_properties: dict):
idf_target = get_property_or_exit(device_properties, "hardware", "target").lower() idf_target = get_property_or_exit(device_properties, "hardware", "target").lower()
has_bluetooth = get_boolean_property_or_false(device_properties, "hardware", "bluetooth") has_bluetooth = get_boolean_property_or_false(device_properties, "hardware", "bluetooth")
if has_bluetooth: if has_bluetooth:
@@ -361,7 +357,7 @@ def write_bluetooth_variables(output_file, device_properties: ConfigParser):
# rapid connect/disconnect/re-pair loop. # rapid connect/disconnect/re-pair loop.
output_file.write("CONFIG_BT_NIMBLE_NVS_PERSIST=y\n") output_file.write("CONFIG_BT_NIMBLE_NVS_PERSIST=y\n")
def write_usbhost_variables(output_file, device_properties: ConfigParser): def write_usbhost_variables(output_file, device_properties: dict):
has_usbhost = get_boolean_property_or_false(device_properties, "hardware", "usbHostEnabled") has_usbhost = get_boolean_property_or_false(device_properties, "hardware", "usbHostEnabled")
if has_usbhost: if has_usbhost:
output_file.write("# USB Host\n") output_file.write("# USB Host\n")
@@ -373,15 +369,16 @@ def write_usbhost_variables(output_file, device_properties: ConfigParser):
output_file.write("CONFIG_USB_HOST_RESET_RECOVERY_MS=100\n") output_file.write("CONFIG_USB_HOST_RESET_RECOVERY_MS=100\n")
output_file.write("CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=500\n") output_file.write("CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS=500\n")
def write_custom_sdkconfig(output_file, device_properties: ConfigParser): def write_custom_sdkconfig(output_file, device_properties: dict):
if "sdkconfig" in device_properties.sections(): prefix = "sdkconfig."
sdkconfig_items = [(key[len(prefix):], value) for key, value in device_properties.items() if key.startswith(prefix)]
if sdkconfig_items:
output_file.write("# Custom\n") output_file.write("# Custom\n")
section = device_properties["sdkconfig"] for key, value in sdkconfig_items:
for key in section.keys(): escaped_value = value.replace("\"", "\\\"")
value = section[key].replace("\"", "\\\"") output_file.write(f"{key}={escaped_value}\n")
output_file.write(f"{key}={value}\n")
def write_properties(output_file, device_properties: ConfigParser, device_id: str, is_dev: bool): def write_properties(output_file, device_properties: dict, device_id: str, is_dev: bool):
write_defaults(output_file) write_defaults(output_file)
output_file.write("\n\n") output_file.write("\n\n")
write_tactility_variables(output_file, device_properties, device_id) write_tactility_variables(output_file, device_properties, device_id)