Add TactilityFreeRtos to TactilitySDK (#441)
- TactlitySDK updates fro TactilityFreeRtos - Enable auto-uploading of SDKs to the CDN when merging code
This commit is contained in:
committed by
GitHub
parent
7283920def
commit
524b197105
@@ -0,0 +1,230 @@
|
||||
import subprocess
|
||||
from datetime import datetime, UTC
|
||||
import os
|
||||
import sys
|
||||
import configparser
|
||||
from dataclasses import dataclass, asdict
|
||||
import json
|
||||
import shutil
|
||||
from configparser import RawConfigParser
|
||||
|
||||
VERBOSE = False
|
||||
DEVICES_FOLDER = "Devices"
|
||||
|
||||
@dataclass
|
||||
class IndexEntry:
|
||||
id: str
|
||||
name: str
|
||||
vendor: str
|
||||
incubating: bool
|
||||
warningMessage: str
|
||||
infoMessage: str
|
||||
|
||||
@dataclass
|
||||
class Manifest:
|
||||
name: str
|
||||
version: str
|
||||
new_install_prompt_erase: str
|
||||
funding_url: str
|
||||
builds: list
|
||||
|
||||
@dataclass
|
||||
class ManifestBuild:
|
||||
chipFamily: str
|
||||
parts: list
|
||||
|
||||
@dataclass
|
||||
class ManifestBuildPart:
|
||||
path: str
|
||||
offset: int
|
||||
|
||||
@dataclass
|
||||
class DeviceIndex:
|
||||
version: str
|
||||
created: str
|
||||
gitCommit: str
|
||||
devices: list
|
||||
|
||||
shell_color_red = "\033[91m"
|
||||
shell_color_orange = "\033[93m"
|
||||
shell_color_reset = "\033[m"
|
||||
|
||||
def print_warning(message):
|
||||
print(f"{shell_color_orange}WARNING: {message}{shell_color_reset}")
|
||||
|
||||
def print_error(message):
|
||||
print(f"{shell_color_red}ERROR: {message}{shell_color_reset}")
|
||||
|
||||
def print_help():
|
||||
print("Usage: python generate-firmware-files.py [inPath] [outPath] [version]")
|
||||
print(" inPath path with the extracted release files")
|
||||
print(" outPath path where the CDN files will become available")
|
||||
print(" version technical version name (e.g. 1.2.0)")
|
||||
print("Options:")
|
||||
print(" --verbose Show extra console output")
|
||||
|
||||
def exit_with_error(message):
|
||||
print_error(message)
|
||||
sys.exit(1)
|
||||
|
||||
def read_properties_file(path):
|
||||
config = configparser.RawConfigParser()
|
||||
# Don't convert keys to lowercase
|
||||
config.optionxform = str
|
||||
config.read(path)
|
||||
return config
|
||||
|
||||
def get_property_or_none(properties: RawConfigParser, group: str, key: str):
|
||||
if group not in properties.sections():
|
||||
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):
|
||||
if group not in properties.sections():
|
||||
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):
|
||||
if group not in properties.sections():
|
||||
exit_with_error(f"Device properties does not contain group: {group}")
|
||||
if key not in properties[group].keys():
|
||||
exit_with_error(f"Device properties does not contain key: {key}")
|
||||
return properties[group][key]
|
||||
|
||||
def read_device_properties(device_id):
|
||||
mapping_file_path = os.path.join(DEVICES_FOLDER, device_id, "device.properties")
|
||||
if not os.path.isfile(mapping_file_path):
|
||||
exit_with_error(f"Mapping file not found: {mapping_file_path}")
|
||||
return read_properties_file(mapping_file_path)
|
||||
|
||||
def to_manifest_chip_name(name):
|
||||
if name == "esp32":
|
||||
return "ESP32"
|
||||
elif name == "esp32s2":
|
||||
return "ESP32-S2"
|
||||
elif name == "esp32s3":
|
||||
return "ESP32-S3"
|
||||
elif name == "esp32c2":
|
||||
return "ESP32-C2"
|
||||
elif name == "esp32c3":
|
||||
return "ESP32-C3"
|
||||
elif name == "esp32c5":
|
||||
return "ESP32-C5"
|
||||
elif name == "esp32c6":
|
||||
return "ESP32-C6"
|
||||
elif name == "esp32c61":
|
||||
return "ESP32-C61"
|
||||
elif name == "esp32h2":
|
||||
return "ESP32-H2"
|
||||
elif name == "esp32h4":
|
||||
return "ESP32-H4"
|
||||
elif name == "esp32p4":
|
||||
return "ESP32-P4"
|
||||
else:
|
||||
exit_with_error(f"to_manifest_chip_name() doesn't support {name} yet")
|
||||
return ""
|
||||
|
||||
|
||||
def process_device(in_path: str, out_path: str, device_directory: str, device_id: str, device_properties: RawConfigParser, version: str):
|
||||
in_device_path = os.path.join(in_path, device_directory)
|
||||
in_device_binaries_path = os.path.join(in_device_path, "Binaries")
|
||||
if not os.path.isdir(in_device_binaries_path):
|
||||
exit_with_error(f"Could not find directory {in_device_binaries_path}")
|
||||
flasher_args_path = os.path.join(in_device_binaries_path, "flasher_args.json")
|
||||
if not os.path.isfile(flasher_args_path):
|
||||
exit_with_error(f"Could not find flasher arguments path {flasher_args_path}")
|
||||
with open(flasher_args_path) as json_data:
|
||||
flasher_args = json.load(json_data)
|
||||
flash_files = flasher_args["flash_files"]
|
||||
device_vendor = get_property_or_exit(device_properties, "general", "vendor")
|
||||
device_name = get_property_or_exit(device_properties, "general", "name")
|
||||
manifest = Manifest(
|
||||
name=f"Tactility for {device_vendor} {device_name}",
|
||||
version=version,
|
||||
new_install_prompt_erase="true",
|
||||
funding_url="https://github.com/sponsors/ByteWelder",
|
||||
builds=[
|
||||
ManifestBuild(
|
||||
chipFamily=to_manifest_chip_name(flasher_args["extra_esptool_args"]["chip"]),
|
||||
parts=[]
|
||||
)
|
||||
]
|
||||
)
|
||||
for offset in flash_files:
|
||||
flash_file_entry = flash_files[offset]
|
||||
flash_file_entry_name = os.path.basename(flash_file_entry)
|
||||
in_flash_file_path = os.path.join(in_device_binaries_path, flash_file_entry)
|
||||
out_flash_file_name = f"{device_id}-{flash_file_entry_name}"
|
||||
out_flash_file_path = os.path.join(out_path, out_flash_file_name)
|
||||
if VERBOSE:
|
||||
print(f"Copying {in_flash_file_path} -> {out_flash_file_path}")
|
||||
shutil.copy(in_flash_file_path, out_flash_file_path)
|
||||
manifest.builds[0].parts.append(
|
||||
ManifestBuildPart(
|
||||
path=out_flash_file_name,
|
||||
offset=int(offset, 16)
|
||||
)
|
||||
)
|
||||
json_manifest_path = os.path.join(out_path, f"{device_id}.json")
|
||||
with open(json_manifest_path, 'w') as json_manifest_file:
|
||||
json.dump(asdict(manifest), json_manifest_file, indent=2)
|
||||
|
||||
|
||||
def get_git_commit_hash():
|
||||
return subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('ascii').strip()
|
||||
|
||||
def main(in_path: str, out_path: str, version: str):
|
||||
if not os.path.exists(in_path):
|
||||
exit_with_error(f"Input path not found: {in_path}")
|
||||
if os.path.exists(out_path):
|
||||
shutil.rmtree(out_path)
|
||||
os.mkdir(out_path)
|
||||
artifact_directories = os.listdir(in_path)
|
||||
device_index = DeviceIndex(
|
||||
version=version,
|
||||
created=datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%S'),
|
||||
gitCommit=get_git_commit_hash(),
|
||||
devices=[]
|
||||
)
|
||||
for artifact_directory in artifact_directories:
|
||||
if artifact_directory.endswith("-symbols") or artifact_directory.startswith("TactilitySDK-"):
|
||||
continue
|
||||
device_id = artifact_directory.removeprefix("Tactility-")
|
||||
if not device_id:
|
||||
exit_with_error(f"Cannot derive device id from directory: {artifact_directory}")
|
||||
device_properties = read_device_properties(device_id)
|
||||
process_device(in_path, out_path, artifact_directory, device_id, device_properties, version)
|
||||
warning_message = get_property_or_none(device_properties, "cdn", "warningMessage")
|
||||
info_message = get_property_or_none(device_properties, "cdn", "infoMessage")
|
||||
incubating = get_boolean_property_or_false(device_properties, "general", "incubating")
|
||||
device_names = get_property_or_exit(device_properties, "general", "name").split(',')
|
||||
for device_name in device_names:
|
||||
device_index.devices.append(asdict(IndexEntry(
|
||||
id=device_id,
|
||||
name=device_name.strip(),
|
||||
vendor=get_property_or_exit(device_properties, "general", "vendor"),
|
||||
incubating=incubating,
|
||||
warningMessage=warning_message,
|
||||
infoMessage=info_message
|
||||
)))
|
||||
index_file_path = os.path.join(out_path, "index.json")
|
||||
with open(index_file_path, "w") as index_file:
|
||||
json.dump(asdict(device_index), index_file, indent=2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Tactility CDN File Generator")
|
||||
if "--help" in sys.argv:
|
||||
print_help()
|
||||
sys.exit()
|
||||
# Argument validation
|
||||
if len(sys.argv) < 4:
|
||||
print_help()
|
||||
sys.exit(1)
|
||||
if "--verbose" in sys.argv:
|
||||
VERBOSE = True
|
||||
sys.argv.remove("--verbose")
|
||||
main(in_path=sys.argv[1], out_path=sys.argv[2], version=sys.argv[3])
|
||||
Reference in New Issue
Block a user