Tactility.py 3.0.0 and SDK updates for 0.7.0-dev (#19)

- Remove `Libraries/Str`
- Replaced usage of `TactilityC` FreeRtos features with `TactilityFreeRtos` library
- Update `tactility.py`
- Removed redundant code from `TactilityCpp`
This commit is contained in:
Ken Van Hoeylandt
2026-01-04 02:20:06 +01:00
committed by GitHub
parent 3bc1e7a373
commit b6c27b64d4
41 changed files with 521 additions and 1329 deletions
-4
View File
@@ -1,15 +1,11 @@
file(GLOB_RECURSE SOURCE_FILES
Source/*.c*
# Library source files must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
../../../Libraries/Str/Source/*.c**
)
idf_component_register(
SRCS ${SOURCE_FILES}
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS ../../../Libraries/Str/Include
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
REQUIRES TactilitySDK
)
+11 -10
View File
@@ -4,6 +4,7 @@
#include <ctype.h>
#include <tt_lvgl_toolbar.h>
#include <stack>
#include <cstring>
constexpr auto* TAG = "Calculator";
@@ -45,10 +46,10 @@ void Calculator::handleInput(const char* txt) {
}
}
std::deque<Str> Calculator::infixToRPN(const Str& infix) {
std::deque<std::string> Calculator::infixToRPN(const std::string& infix) {
std::stack<char> opStack;
std::deque<Str> output;
Str token;
std::deque<std::string> output;
std::string token;
size_t i = 0;
while (i < infix.length()) {
@@ -56,20 +57,20 @@ std::deque<Str> Calculator::infixToRPN(const Str& infix) {
if (isdigit(ch)) {
token.clear();
while (i < infix.length() && (isdigit(infix[i]) || infix[i] == '.')) { token.append(infix[i++]); }
while (i < infix.length() && (isdigit(infix[i]) || infix[i] == '.')) { token += infix[i++]; }
output.push_back(token);
continue;
}
if (ch == '(') { opStack.push(ch); } else if (ch == ')') {
while (!opStack.empty() && opStack.top() != '(') {
output.push_back(Str(1, opStack.top()));
output.push_back(std::string(1, opStack.top()));
opStack.pop();
}
opStack.pop();
} else if (strchr("+-*/", ch)) {
while (!opStack.empty() && precedence(opStack.top()) >= precedence(ch)) {
output.push_back(Str(1, opStack.top()));
output.push_back(std::string(1, opStack.top()));
opStack.pop();
}
opStack.push(ch);
@@ -79,18 +80,18 @@ std::deque<Str> Calculator::infixToRPN(const Str& infix) {
}
while (!opStack.empty()) {
output.push_back(Str(1, opStack.top()));
output.push_back(std::string(1, opStack.top()));
opStack.pop();
}
return output;
}
double Calculator::evaluateRPN(std::deque<Str> rpnQueue) {
double Calculator::evaluateRPN(std::deque<std::string> rpnQueue) {
std::stack<double> values;
while (!rpnQueue.empty()) {
Str token = rpnQueue.front();
std::string token = rpnQueue.front();
rpnQueue.pop_front();
if (isdigit(token[0])) {
@@ -132,7 +133,7 @@ void Calculator::evaluateExpression() {
}
double Calculator::computeFormula() {
return evaluateRPN(infixToRPN(Str(formulaBuffer)));
return evaluateRPN(infixToRPN(std::string(formulaBuffer)));
}
void Calculator::resetCalculator() {
+3 -3
View File
@@ -4,7 +4,7 @@
#include <lvgl.h>
#include <deque>
#include <Str.h>
#include <string>
#include <TactilityCpp/App.h>
class Calculator final : public App {
@@ -18,8 +18,8 @@ class Calculator final : public App {
void handleInput(const char* txt);
void evaluateExpression();
double computeFormula();
static std::deque<Str> infixToRPN(const Str& infix);
static double evaluateRPN(std::deque<Str> rpnQueue);
static std::deque<std::string> infixToRPN(const std::string& infix);
static double evaluateRPN(std::deque<std::string> rpnQueue);
void resetCalculator();
public:
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.calculator
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=Calculator
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
-1
View File
@@ -14,4 +14,3 @@ set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH})
project(Diceware)
tactility_project(Diceware)
-4
View File
@@ -1,15 +1,11 @@
file(GLOB_RECURSE SOURCE_FILES
Source/*.c*
# Library source files must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
../../../Libraries/Str/Source/*.c**
)
idf_component_register(
SRCS ${SOURCE_FILES}
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS ../../../Libraries/Str/Include
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
REQUIRES TactilitySDK
)
+22 -19
View File
@@ -8,6 +8,8 @@
#include <esp_random.h>
#include <esp_log.h>
#include <Tactility/kernel/Kernel.h>
constexpr char* TAG = "Diceware";
static void skipNewlines(FILE* file, const int count) {
@@ -20,15 +22,15 @@ static void skipNewlines(FILE* file, const int count) {
}
}
static Str readWord(FILE* file) {
static std::string readWord(FILE* file) {
char c;
Str result;
std::string result;
// Read word until newline
while (fread(&c, 1, 1, file) && c != '\n') { result.append(c); }
while (fread(&c, 1, 1, file) && c != '\n') { result += c; }
return result;
}
static Str readWordAtLine(const AppHandle handle, const int lineIndex) {
static std::string readWordAtLine(const AppHandle handle, const int lineIndex) {
char path[256];
size_t size = 256;
tt_app_get_assets_child_path(handle, "eff_large_wordlist.txt", path, &size);
@@ -38,8 +40,8 @@ static Str readWordAtLine(const AppHandle handle, const int lineIndex) {
}
auto lock = tt_lock_alloc_for_path(path);
Str word;
if (tt_lock_acquire(lock, TT_MAX_TICKS)) {
std::string word;
if (tt_lock_acquire(lock, tt::kernel::MAX_TICKS)) {
FILE* file = fopen(path, "r");
if (file != nullptr) {
skipNewlines(file, lineIndex);
@@ -52,25 +54,24 @@ static Str readWordAtLine(const AppHandle handle, const int lineIndex) {
return word;
}
int32_t Diceware::jobMain(void* data) {
Diceware* application = static_cast<Diceware*>(data);
Str result;
for (int i = 0; i < application->wordCount; i++) {
int32_t Diceware::jobMain() {
std::string result;
for (int i = 0; i < wordCount; i++) {
constexpr int line_count = 7776;
const auto line_index = esp_random() % line_count;
auto word = readWordAtLine(application->handle, line_index);
result.appendf("%s ", word.c_str());
auto word = readWordAtLine(handle, line_index);
result += word;
result += " ";
}
application->onFinishJob(result);
onFinishJob(result);
return 0;
}
void Diceware::cleanupJob() {
if (jobThread != nullptr) {
tt_thread_join(jobThread, TT_MAX_TICKS);
tt_thread_free(jobThread);
jobThread->join();
jobThread = nullptr;
}
}
@@ -79,12 +80,14 @@ void Diceware::startJob(uint32_t jobWordCount) {
cleanupJob();
wordCount = jobWordCount;
jobThread = tt_thread_alloc_ext("Diceware", 4096, jobMain, this);
tt_thread_start(jobThread);
jobThread = std::make_unique<tt::Thread>("Diceware", 4096, [this] {
return jobMain();
});
jobThread->start();
}
void Diceware::onFinishJob(Str result) {
tt_lvgl_lock(TT_MAX_TICKS);
void Diceware::onFinishJob(std::string result) {
tt_lvgl_lock(tt::kernel::MAX_TICKS);
lv_label_set_text(resultLabel, result.c_str());
tt_lvgl_unlock();
}
+8 -5
View File
@@ -1,18 +1,21 @@
#pragma once
#include "tt_app.h"
#include "tt_thread.h"
#include <Str.h>
#include <Tactility/Thread.h>
#include <string>
#include <lvgl.h>
#include <TactilityCpp/App.h>
#include <memory>
class Diceware final : public App {
AppHandle handle = nullptr;
lv_obj_t* spinbox = nullptr;
lv_obj_t* resultLabel = nullptr;
ThreadHandle jobThread = nullptr;
std::unique_ptr<tt::Thread> jobThread = nullptr;
uint32_t wordCount = 5;
static void onClickGenerate(lv_event_t* e);
@@ -20,10 +23,10 @@ class Diceware final : public App {
static void onSpinboxIncrement(lv_event_t* e);
static void onHelpClicked(lv_event_t* e);
static int32_t jobMain(void* data);
int32_t jobMain();
void startJob(uint32_t jobWordCount);
void onFinishJob(Str result);
void onFinishJob(std::string result);
void cleanupJob();
public:
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.diceware
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=Diceware
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
-5
View File
@@ -1,16 +1,11 @@
file(GLOB_RECURSE SOURCE_FILES
Source/*.c*
# Library source files must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
../../../Libraries/Str/Source/*.c**
../../../Libraries/TactilityCpp/Source/*.c**
)
idf_component_register(
SRCS ${SOURCE_FILES}
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS ../../../Libraries/Str/Include
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
REQUIRES TactilitySDK
)
+10 -16
View File
@@ -1,6 +1,7 @@
#include "Gpio.h"
#include <tt_app_alertdialog.h>
#include <Tactility/kernel/Kernel.h>
#include <tt_hal.h>
#include <tt_hal_gpio.h>
#include <tt_lvgl.h>
@@ -18,7 +19,7 @@ void Gpio::updatePinStates() {
}
void Gpio::updatePinWidgets() {
tt_lvgl_lock(TT_MAX_TICKS);
tt_lvgl_lock(tt::kernel::MAX_TICKS);
for (int j = 0; j < pinStates.size(); ++j) {
int level = pinStates[j];
lv_obj_t* label = pinWidgets[j];
@@ -46,28 +47,21 @@ lv_obj_t* Gpio::createGpioRowWrapper(lv_obj_t* parent) {
// region Task
void Gpio::onTimer(void* context) {
Gpio* app = static_cast<Gpio*>(context);
app->mutex.lock();
app->updatePinStates();
app->updatePinWidgets();
app->mutex.unlock();
void Gpio::onTimer() {
mutex.lock();
updatePinStates();
updatePinWidgets();
mutex.unlock();
}
void Gpio::startTask() {
mutex.lock();
assert(timer == nullptr);
timer = tt_timer_alloc(TimerTypePeriodic, onTimer, this);
tt_timer_start(timer, 100 / portTICK_PERIOD_MS);
timer.start();
mutex.unlock();
}
void Gpio::stopTask() {
assert(timer);
tt_timer_stop(timer);
tt_timer_free(timer);
timer = nullptr;
timer.stop();
}
// endregion Task
+7 -5
View File
@@ -3,9 +3,9 @@
#include <TactilityCpp/App.h>
#include <tt_app.h>
#include <tt_timer.h>
#include <TactilityCpp/Mutex.h>
#include <Tactility/RecursiveMutex.h>
#include <Tactility/Timer.h>
#include <lvgl.h>
#include <vector>
@@ -14,11 +14,13 @@ class Gpio final : public App {
std::vector<lv_obj_t*> pinWidgets;
std::vector<bool> pinStates;
TimerHandle timer;
Mutex mutex = Mutex(MutexTypeRecursive);
tt::Timer timer = tt::Timer(tt::Timer::Type::Periodic, pdMS_TO_TICKS(100), [this]{
onTimer();
});
tt::RecursiveMutex mutex;
static lv_obj_t* createGpioRowWrapper(lv_obj_t* parent);
static void onTimer(void* parameter);
void onTimer();
public:
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.gpio
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=GPIO
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
+3 -1
View File
@@ -2,6 +2,8 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Include"
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS "Include" "../../../Libraries/TactilityCpp/Include"
REQUIRES TactilitySDK
)
@@ -2,6 +2,7 @@
#include <cassert>
#include <tt_hal_display.h>
#include <Tactility/kernel/Kernel.h>
/**
* Wrapper for tt_hal_display_driver_*
@@ -22,7 +23,7 @@ public:
tt_hal_display_driver_free(handle);
}
bool lock(TickType timeout = TT_MAX_TICKS) const {
bool lock(TickType_t timeout = tt::kernel::MAX_TICKS) const {
return tt_hal_display_driver_lock(handle, timeout);
}
@@ -2,7 +2,7 @@
#include "PixelBuffer.h"
#include "esp_log.h"
#include <tt_kernel.h>
#include <Tactility/kernel/Kernel.h>
constexpr auto TAG = "Application";
@@ -66,7 +66,7 @@ void runApplication(DisplayDriver* display, TouchDriver* touch) {
// Give other tasks space to breathe
// SPI displays would otherwise time out SPI SD card access
tt_kernel_delay_ticks(1);
tt::kernel::delayTicks(1);
} while (!isTouched(touch));
}
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.graphicsdemo
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=Graphics Demo
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.helloworld
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=Hello World
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
-5
View File
@@ -1,16 +1,11 @@
file(GLOB_RECURSE SOURCE_FILES
Source/*.c*
# Library source files must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
../../../Libraries/Str/Source/*.c**
../../../Libraries/TactilityCpp/Source/*.c**
)
idf_component_register(
SRCS ${SOURCE_FILES}
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS ../../../Libraries/Str/Include
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
REQUIRES TactilitySDK
)
+3 -4
View File
@@ -5,7 +5,6 @@
#include <string>
#include <vector>
#include <lvgl.h>
#include <Str.h>
#include <functional>
#include <memory>
@@ -21,7 +20,7 @@ class ConnectView final : public View {
public:
typedef std::function<void(std::unique_ptr<Uart>)> OnConnectedFunction;
std::vector<Str> uartNames;
std::vector<std::string> uartNames;
Preferences preferences = Preferences("SerialConsole");
LvglLock lvglLock;
@@ -31,8 +30,8 @@ private:
lv_obj_t* busDropdown = nullptr;
lv_obj_t* speedTextarea = nullptr;
Str join(const std::vector<Str>& list) {
Str output;
std::string join(const std::vector<std::string>& list) {
std::string output;
for (int i = list.size() - 1; i >= 0; i--) {
output.append(list[i].c_str());
if (i < list.size() - 1) {
+27 -43
View File
@@ -3,16 +3,15 @@
#include "View.h"
#include "esp_log.h"
#include <Str.h>
#include <string>
#include <sstream>
#include <lvgl.h>
#include <memory>
#include <tt_lvgl.h>
#include <tt_thread.h>
#include <TactilityCpp/Mutex.h>
#include <TactilityCpp/Thread.h>
#include <Tactility/RecursiveMutex.h>
#include <Tactility/Thread.h>
#include <TactilityCpp/LvglLock.h>
constexpr size_t receiveBufferSize = 512;
@@ -26,15 +25,15 @@ class ConsoleView final : public View {
lv_obj_t* _Nullable logTextarea = nullptr;
lv_obj_t* _Nullable inputTextarea = nullptr;
std::shared_ptr<Uart> _Nullable uart = nullptr;
std::shared_ptr<Thread> uartThread _Nullable = nullptr;
std::unique_ptr<tt::Thread> uartThread _Nullable = nullptr;
bool uartThreadInterrupted = false;
std::shared_ptr<Thread> viewThread _Nullable = nullptr;
std::unique_ptr<tt::Thread> viewThread _Nullable = nullptr;
bool viewThreadInterrupted = false;
Mutex mutex = Mutex(MutexTypeRecursive);
tt::RecursiveMutex mutex;
uint8_t receiveBuffer[receiveBufferSize];
uint8_t renderBuffer[renderBufferSize];
size_t receiveBufferPosition = 0;
Str terminatorString = "\n";
std::string terminatorString = "\n";
LvglLock lvglLock;
@@ -51,11 +50,6 @@ class ConsoleView final : public View {
}
void updateViews() {
auto scoped_lvgl_lock = lvglLock.asScopedLock();
if (!scoped_lvgl_lock.lock()) {
return;
}
if (parent == nullptr) {
return;
}
@@ -73,38 +67,35 @@ class ConsoleView final : public View {
mutex.unlock();
}
tt_lvgl_lock(TT_MAX_TICKS);
if (lvglLock.lock()) {
lv_textarea_set_text(logTextarea, (const char*)renderBuffer);
tt_lvgl_unlock();
lvglLock.unlock();
}
}
int32_t viewThreadMain() {
while (!isViewThreadInterrupted()) {
auto start_time = tt_kernel_get_ticks();
auto start_time = tt::kernel::getTicks();
updateViews();
auto end_time = tt_kernel_get_ticks();
auto end_time = tt::kernel::getTicks();
auto time_diff = end_time - start_time;
if (time_diff < 500U) {
tt_kernel_delay_ticks((500U - time_diff) / portTICK_PERIOD_MS);
auto target_delay = tt::kernel::millisToTicks(500U);
if (time_diff < target_delay) {
tt::kernel::delayTicks(target_delay - time_diff);
}
}
return 0;
}
static int32_t viewThreadMainStatic(void* context) {
auto* self = static_cast<ConsoleView*>(context);
return self->viewThreadMain();
}
int32_t uartThreadMain() {
char byte;
while (!isUartThreadInterrupted()) {
assert(uart != nullptr);
bool success = uart->readByte(&byte, 50 / portTICK_PERIOD_MS);
bool success = uart->readByte(&byte, tt::kernel::millisToTicks(50));
// Thread might've been interrupted in the meanwhile
if (isUartThreadInterrupted()) {
@@ -125,11 +116,6 @@ class ConsoleView final : public View {
return 0;
}
static int32_t uartThreadMainStatic(void* view) {
auto* self = static_cast<ConsoleView*>(view);
return self->uartThreadMain();
}
static void onSendClickedCallback(lv_event_t* event) {
auto* view = (ConsoleView*)lv_event_get_user_data(event);
view->onSendClicked();
@@ -156,9 +142,9 @@ class ConsoleView final : public View {
void onSendClicked() {
mutex.lock();
Str input_text = lv_textarea_get_text(inputTextarea);
Str to_send;
to_send.appendf("%s%s", input_text.c_str(), terminatorString.c_str());
std::string input_text = lv_textarea_get_text(inputTextarea);
std::string to_send;
to_send.append(input_text + terminatorString);
mutex.unlock();
if (uart != nullptr) {
@@ -181,13 +167,12 @@ public:
uart = std::move(newUart);
uartThreadInterrupted = false;
uartThread = std::make_unique<Thread>(
uartThread = std::make_unique<tt::Thread>(
"SerConsUart",
4096,
uartThreadMainStatic,
this
[this] { return uartThreadMain(); }
);
uartThread->setPriority(ThreadPriorityHigh);
uartThread->setPriority(tt::Thread::Priority::High);
uartThread->start();
}
@@ -228,13 +213,12 @@ public:
lv_obj_add_event_cb(button, onSendClickedCallback, LV_EVENT_SHORT_CLICKED, this);
viewThreadInterrupted = false;
viewThread = std::make_unique<Thread>(
viewThread = std::make_unique<tt::Thread>(
"SerConsView",
4096,
viewThreadMainStatic,
this
[this] { return viewThreadMain(); }
);
viewThread->setPriority(ThreadPriorityHigher);
viewThread->setPriority(tt::Thread::Priority::Higher);
viewThread->start();
}
@@ -249,7 +233,7 @@ public:
// Unlock so thread can lock
lock.unlock();
if (old_uart_thread->getState() != ThreadStateStopped) {
if (old_uart_thread->getState() != tt::Thread::State::Stopped) {
// Wait for thread to finish
old_uart_thread->join();
}
@@ -267,7 +251,7 @@ public:
// Unlock so thread can lock
lock.unlock();
if (old_view_thread->getState() != ThreadStateStopped) {
if (old_view_thread->getState() != tt::Thread::State::Stopped) {
// Wait for thread to finish
old_view_thread->join();
}
+4 -4
View File
@@ -1,10 +1,10 @@
[manifest]
version=0.1
[target]
sdk=0.6.0
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.serialconsole
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=Serial Console
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
-4
View File
@@ -1,15 +1,11 @@
file(GLOB_RECURSE SOURCE_FILES
Source/*.c*
# Library source files must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
../../../Libraries/Str/Source/*.c**
)
idf_component_register(
SRCS ${SOURCE_FILES}
# Library headers must be included directly,
# because all regular dependencies get stripped by elf_loader's cmake script
INCLUDE_DIRS ../../../Libraries/Str/Include
INCLUDE_DIRS ../../../Libraries/TactilityCpp/Include
REQUIRES TactilitySDK
)
+4 -4
View File
@@ -1,11 +1,11 @@
[manifest]
version=0.1
[target]
sdk=0.7.0-SNAPSHOT2
platforms=esp32,esp32s3
sdk=0.7.0-dev
platforms=esp32,esp32s3,esp32c6,esp32p4
[app]
id=one.tactility.twoeleven
versionName=0.2.0
versionCode=2
versionName=0.3.0
versionCode=3
name=2048
description=A fun, customizable 2048 sliding tile game for tactility!\nSlide tiles to combine numbers and reach 2048.\nChoose grid sizes: 3x3 (easy), 4x4 (classic), 5x5, or 6x6 (expert).
+46 -43
View File
@@ -12,7 +12,7 @@ import requests
import tarfile
ttbuild_path = ".tactility"
ttbuild_version = "2.5.0"
ttbuild_version = "3.1.0"
ttbuild_cdn = "https://cdn.tactility.one"
ttbuild_sdk_json_validity = 3600 # seconds
ttport = 6666
@@ -20,14 +20,6 @@ verbose = False
use_local_sdk = False
local_base_path = None
if sys.platform == "win32":
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
shell_color_purple = "\033[35m"
shell_color_cyan = "\033[36m"
shell_color_reset = "\033[m"
else:
shell_color_red = "\033[91m"
shell_color_orange = "\033[93m"
shell_color_green = "\033[32m"
@@ -115,8 +107,8 @@ def read_properties_file(path):
#region SDK helpers
def read_sdk_json():
json_file_path = os.path.join(ttbuild_path, "sdk.json")
json_file = open(json_file_path)
json_file_path = os.path.join(ttbuild_path, "tool.json")
with open(json_file_path) as json_file:
return json.load(json_file)
def get_sdk_dir(version, platform):
@@ -148,17 +140,17 @@ def get_sdk_root_dir(version, platform):
global ttbuild_cdn
return os.path.join(ttbuild_path, f"{version}-{platform}")
def get_sdk_url(version, platform):
def get_sdk_url(version, file):
global ttbuild_cdn
return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip"
return f"{ttbuild_cdn}/sdk/{version}/{file}"
def sdk_exists(version, platform):
sdk_dir = get_sdk_dir(version, platform)
return os.path.isdir(sdk_dir)
def should_update_sdk_json():
def should_update_tool_json():
global ttbuild_cdn
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_filepath = os.path.join(ttbuild_path, "tool.json")
if os.path.exists(json_filepath):
json_modification_time = os.path.getmtime(json_filepath)
now = time.time()
@@ -168,10 +160,10 @@ def should_update_sdk_json():
else:
return True
def update_sdk_json():
def update_tool_json():
global ttbuild_cdn, ttbuild_path
json_url = f"{ttbuild_cdn}/sdk.json"
json_filepath = os.path.join(ttbuild_path, "sdk.json")
json_url = f"{ttbuild_cdn}/sdk/tool.json"
json_filepath = os.path.join(ttbuild_path, "tool.json")
return download_file(json_url, json_filepath)
def should_fetch_sdkconfig_files(platform_targets):
@@ -206,16 +198,6 @@ def validate_environment():
elif use_local_sdk == True and os.environ.get("TACTILITY_SDK_PATH") is None:
exit_with_error("local build was requested, but TACTILITY_SDK_PATH environment variable is not set.")
def validate_version_and_platforms(sdk_json, sdk_version, platforms_to_build):
version_map = sdk_json["versions"]
if not sdk_version in version_map:
exit_with_error(f"Version not found: {sdk_version}")
version_data = version_map[sdk_version]
available_platforms = version_data["platforms"]
for desired_platform in platforms_to_build:
if not desired_platform in available_platforms:
exit_with_error(f"Platform {desired_platform} is not available. Available ones: {available_platforms}")
def validate_self(sdk_json):
if not "toolVersion" in sdk_json:
exit_with_error("Server returned invalid SDK data format (toolVersion not found)")
@@ -287,15 +269,32 @@ def get_manifest_target_platforms(manifest, requested_platform):
def sdk_download(version, platform):
sdk_root_dir = get_sdk_root_dir(version, platform)
os.makedirs(sdk_root_dir, exist_ok=True)
sdk_url = get_sdk_url(version, platform)
filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
sdk_index_url = get_sdk_url(version, "index.json")
print(f"Downloading SDK version {version} for {platform}")
if download_file(sdk_url, filepath):
with zipfile.ZipFile(filepath, "r") as zip_ref:
sdk_index_filepath = os.path.join(sdk_root_dir, "index.json")
if verbose:
print(f"Downloading {sdk_index_url} to {sdk_index_filepath}")
if not download_file(sdk_index_url, sdk_index_filepath):
# TODO: 404 check, print a more accurate error
print_error(f"Failed to download SDK version {version}. Check your internet connection and make sure this release exists.")
return False
with open(sdk_index_filepath) as sdk_index_json_file:
sdk_index_json = json.load(sdk_index_json_file)
sdk_platforms = sdk_index_json["platforms"]
if platform not in sdk_platforms:
print_error(f"Platform {platform} not found in {sdk_platforms} for version {version}")
return False
sdk_platform_file = sdk_platforms[platform]
sdk_zip_source_url = get_sdk_url(version, sdk_platform_file)
sdk_zip_target_filepath = os.path.join(sdk_root_dir, f"{version}-{platform}.zip")
if verbose:
print(f"Downloading {sdk_zip_source_url} to {sdk_zip_target_filepath}")
if not download_file(sdk_zip_source_url, sdk_zip_target_filepath):
print_error(f"Failed to download {sdk_zip_source_url} to {sdk_zip_target_filepath}")
return False
with zipfile.ZipFile(sdk_zip_target_filepath, "r") as zip_ref:
zip_ref.extractall(os.path.join(sdk_root_dir, "TactilitySDK"))
return True
else:
return False
def sdk_download_all(version, platforms):
for platform in platforms:
@@ -378,7 +377,10 @@ def build_first(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "build"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
# The return code is never expected to be 0 due to a bug in the elf cmake script, but we keep it just in case
if process.returncode == 0:
@@ -406,7 +408,10 @@ def build_consecutively(version, platform, skip_build):
cmake_path = get_cmake_path(platform)
print_status_busy(f"Building {platform} ELF")
shell_needed = sys.platform == "win32"
with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_command = ["idf.py", "-B", cmake_path, "elf"]
if verbose:
print(f"Running command: {" ".join(build_command)}")
with subprocess.Popen(build_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=shell_needed) as process:
build_output = wait_for_process(process)
if process.returncode == 0:
print_status_success(f"Building {platform} ELF")
@@ -494,12 +499,9 @@ def build_action(manifest, platform_arg):
if not use_local_sdk:
sdk_json = read_sdk_json()
validate_self(sdk_json)
if not "versions" in sdk_json:
exit_with_error("Version data not found in sdk.json")
# Build
sdk_version = manifest["target"]["sdk"]
if not use_local_sdk:
validate_version_and_platforms(sdk_json, 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")
if not build_all(sdk_version, platforms_to_build, skip_build): # Environment validation
@@ -613,7 +615,7 @@ if __name__ == "__main__":
# Argument validation
if len(sys.argv) == 1:
print_help()
sys.exit()
sys.exit(1)
if "--verbose" in sys.argv:
verbose = True
sys.argv.remove("--verbose")
@@ -633,8 +635,8 @@ if __name__ == "__main__":
manifest = read_manifest()
validate_manifest(manifest)
all_platform_targets = manifest["target"]["platforms"].split(",")
# Update SDK cache (sdk.json)
if should_update_sdk_json() and not update_sdk_json():
# Update SDK cache (tool.json)
if should_update_tool_json() and not update_tool_json():
exit_with_error("Failed to retrieve SDK info")
# Actions
if action_arg == "build":
@@ -644,7 +646,8 @@ if __name__ == "__main__":
platform = None
if len(sys.argv) > 2:
platform = sys.argv[2]
build_action(manifest, platform)
if not build_action(manifest, platform):
sys.exit(1)
elif action_arg == "clean":
clean_action()
elif action_arg == "clearcache":
-15
View File
@@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
file(GLOB SOURCES "Source/*.c*")
file(GLOB HEADERS "Include/*.h*")
add_library(Str STATIC)
target_sources(Str PRIVATE ${SOURCES})
include_directories(Str "Include/")
target_include_directories(Str PUBLIC "Include/")
-618
View File
@@ -1,618 +0,0 @@
// Str v0.33
// Simple C++ string type with an optional local buffer, by Omar Cornut
// https://github.com/ocornut/str
// LICENSE
// This software is in the public domain. Where that dedication is not
// recognized, you are granted a perpetual, irrevocable license to copy,
// distribute, and modify this file as you see fit.
// USAGE
// Include this file in whatever places need to refer to it.
// In ONE .cpp file, write '#define STR_IMPLEMENTATION' before the #include of this file.
// This expands out the actual implementation into that C/C++ file.
/*
- This isn't a fully featured string class.
- It is a simple, bearable replacement to std::string that isn't heap abusive nor bloated (can actually be debugged by humans).
- String are mutable. We don't maintain size so length() is not-constant time.
- Maximum string size currently limited to 2 MB (we allocate 21 bits to hold capacity).
- Local buffer size is currently limited to 1023 bytes (we allocate 10 bits to hold local buffer size).
- In "non-owned" mode for literals/reference we don't do any tracking/counting of references.
- Overhead is 8-bytes in 32-bits, 16-bytes in 64-bits (12 + alignment).
- This code hasn't been tested very much. it is probably incomplete or broken. Made it for my own use.
The idea is that you can provide an arbitrary sized local buffer if you expect string to fit
most of the time, and then you avoid using costly heap.
No local buffer, always use heap, sizeof()==8~16 (depends if your pointers are 32-bits or 64-bits)
Str s = "hey";
With a local buffer of 16 bytes, sizeof() == 8~16 + 16 bytes.
Str16 s = "filename.h"; // copy into local buffer
Str16 s = "long_filename_not_very_long_but_longer_than_expected.h"; // use heap
With a local buffer of 256 bytes, sizeof() == 8~16 + 256 bytes.
Str256 s = "long_filename_not_very_long_but_longer_than_expected.h"; // copy into local buffer
Common sizes are defined at the bottom of Str.h, you may define your own.
Functions:
Str256 s;
s.set("hello sailor"); // set (copy)
s.setf("%s/%s.tmp", folder, filename); // set (w/format)
s.append("hello"); // append. cost a length() calculation!
s.appendf("hello %d", 42); // append (w/format). cost a length() calculation!
s.set_ref("Hey!"); // set (literal/reference, just copy pointer, no tracking)
Constructor helper for format string: add a trailing 'f' to the type. Underlying type is the same.
Str256f filename("%s/%s.tmp", folder, filename); // construct (w/format)
fopen(Str256f("%s/%s.tmp, folder, filename).c_str(), "rb"); // construct (w/format), use as function param, destruct
Constructor helper for reference/literal:
StrRef ref("literal"); // copy pointer, no allocation, no string copy
StrRef ref2(GetDebugName()); // copy pointer. no tracking of anything whatsoever, know what you are doing!
All StrXXX types derives from Str and instance hold the local buffer capacity. So you can pass e.g. Str256* to a function taking base type Str* and it will be functional.
void MyFunc(Str& s) { s = "Hello"; } // will use local buffer if available in Str instance
(Using a template e.g. Str<N> we could remove the LocalBufSize storage but it would make passing typed Str<> to functions tricky.
Instead we don't use template so you can pass them around as the base type Str*. Also, templates are ugly.)
*/
/*
CHANGELOG
0.33 - fixed capacity() return value to match standard. e.g. a Str256's capacity() now returns 255, not 256.
0.32 - added owned() accessor.
0.31 - fixed various warnings.
0.30 - turned into a single header file, removed Str.cpp.
0.29 - fixed bug when calling reserve on non-owned strings (ie. when using StrRef or set_ref), and fixed <string> include.
0.28 - breaking change: replaced Str32 by Str30 to avoid collision with Str32 from MacTypes.h .
0.27 - added STR_API and basic .natvis file.
0.26 - fixed set(cont char* src, const char* src_end) writing null terminator to the wrong position.
0.25 - allow set(const char* NULL) or operator= NULL to clear the string. note that set() from range or other types are not allowed.
0.24 - allow set_ref(const char* NULL) to clear the string. include fixes for linux.
0.23 - added append(char). added append_from(int idx, XXX) functions. fixed some compilers warnings.
0.22 - documentation improvements, comments. fixes for some compilers.
0.21 - added StrXXXf() constructor to construct directly from a format string.
*/
/*
TODO
- Since we lose 4-bytes of padding on 64-bits architecture, perhaps just spread the header to 8-bytes and lift size limits?
- More functions/helpers.
*/
#ifndef STR_INCLUDED
#define STR_INCLUDED
//-------------------------------------------------------------------------
// CONFIGURATION
//-------------------------------------------------------------------------
#ifndef STR_MEMALLOC
#define STR_MEMALLOC malloc
#include <cstdio>
#endif
#ifndef STR_MEMFREE
#define STR_MEMFREE free
#include <cstdlib>
#endif
#ifndef STR_ASSERT
#define STR_ASSERT assert
#include <cassert>
#endif
#ifndef STR_API
#define STR_API
#endif
#include <cstdarg> // for va_list
#include <cstring> // for strlen, strcmp, memcpy, etc.
// Configuration: #define STR_DEFINE_STR32 1 to keep defining Str32/Str32f, but be warned: on macOS/iOS, MacTypes.h also defines a type named Str32.
#ifndef STR_DEFINE_STR32
#define STR_DEFINE_STR32 0
#endif
//-------------------------------------------------------------------------
// HEADERS
//-------------------------------------------------------------------------
// This is the base class that you can pass around
// Footprint is 8-bytes (32-bits arch) or 16-bytes (64-bits arch)
class STR_API Str
{
char* Data; // Point to LocalBuf() or heap allocated
int Capacity : 21; // Max 2 MB. Exclude zero terminator.
int LocalBufSize : 10; // Max 1023 bytes
unsigned int Owned : 1; // Set when we have ownership of the pointed data (most common, unless using set_ref() method or StrRef constructor)
public:
inline char* c_str() { return Data; }
inline const char* c_str() const { return Data; }
inline bool empty() const { return Data[0] == 0; }
inline int length() const { return (int)strlen(Data); } // by design, allow user to write into the buffer at any time
inline int capacity() const { return Capacity; }
inline bool owned() const { return Owned ? true : false; }
inline void set_ref(const char* src);
int setf(const char* fmt, ...);
int setfv(const char* fmt, va_list args);
int setf_nogrow(const char* fmt, ...);
int setfv_nogrow(const char* fmt, va_list args);
int append(char c);
int append(const char* s, const char* s_end = NULL);
int appendf(const char* fmt, ...);
int appendfv(const char* fmt, va_list args);
int append_from(int idx, char c);
int append_from(int idx, const char* s, const char* s_end = NULL); // If you know the string length or want to append from a certain point
int appendf_from(int idx, const char* fmt, ...);
int appendfv_from(int idx, const char* fmt, va_list args);
void clear();
void reserve(int cap);
void reserve_discard(int cap);
void shrink_to_fit();
inline char& operator[](size_t i) { return Data[i]; }
inline char operator[](size_t i) const { return Data[i]; }
//explicit operator const char*() const{ return Data; }
inline Str();
inline Str(const char* rhs);
inline void set(const char* src);
inline void set(const char* src, const char* src_end);
inline Str& operator=(const char* rhs) { set(rhs); return *this; }
inline bool operator==(const char* rhs) const { return strcmp(c_str(), rhs) == 0; }
inline Str(const Str& rhs);
inline void set(const Str& src);
inline void set(int count, char character);
inline Str& operator=(const Str& rhs) { set(rhs); return *this; }
inline bool operator==(const Str& rhs) const { return strcmp(c_str(), rhs.c_str()) == 0; }
inline Str(int amount, char character);
// Destructor for all variants
inline ~Str()
{
if (Owned && !is_using_local_buf())
STR_MEMFREE(Data);
}
static char* EmptyBuffer;
protected:
inline char* local_buf() { return (char*)this + sizeof(Str); }
inline const char* local_buf() const { return (char*)this + sizeof(Str); }
inline bool is_using_local_buf() const { return Data == local_buf() && LocalBufSize != 0; }
// Constructor for StrXXX variants with local buffer
Str(unsigned short local_buf_size)
{
STR_ASSERT(local_buf_size < 1024);
Data = local_buf();
Data[0] = '\0';
Capacity = local_buf_size ? local_buf_size - 1 : 0;
LocalBufSize = local_buf_size;
Owned = 1;
}
};
void Str::set(const char* src)
{
// We allow set(NULL) or via = operator to clear the string.
if (src == NULL)
{
clear();
return;
}
int buf_len = (int)strlen(src);
if (Capacity < buf_len)
reserve_discard(buf_len);
memcpy(Data, src, (size_t)(buf_len + 1));
Owned = 1;
}
void Str::set(const char* src, const char* src_end)
{
STR_ASSERT(src != NULL && src_end >= src);
int buf_len = (int)(src_end - src);
if ((int)Capacity < buf_len)
reserve_discard(buf_len);
memcpy(Data, src, (size_t)buf_len);
Data[buf_len] = 0;
Owned = 1;
}
void Str::set(const Str& src)
{
int buf_len = (int)strlen(src.c_str());
if ((int)Capacity < buf_len)
reserve_discard(buf_len);
memcpy(Data, src.c_str(), (size_t)(buf_len + 1));
Owned = 1;
}
void Str::set(int count, char character) {
int buf_len = count + 1;
if ((int)Capacity < buf_len)
reserve_discard(buf_len);
memset(Data, character, count);
Data[count] = 0;
Owned = 1;
}
inline void Str::set_ref(const char* src)
{
if (Owned && !is_using_local_buf())
STR_MEMFREE(Data);
Data = src ? (char*)src : EmptyBuffer;
Capacity = 0;
Owned = 0;
}
Str::Str()
{
Data = EmptyBuffer; // Shared READ-ONLY initial buffer for 0 capacity
Capacity = 0;
LocalBufSize = 0;
Owned = 0;
}
Str::Str(const Str& rhs) : Str()
{
set(rhs);
}
Str::Str(const char* rhs) : Str()
{
set(rhs);
}
Str::Str(int amount, char character) : Str() {
set(amount, character);
}
// Literal/reference string
class StrRef : public Str
{
public:
StrRef(const char* s) : Str() { set_ref(s); }
};
#define STR_DEFINETYPE(TYPENAME, LOCALBUFSIZE) \
class TYPENAME : public Str \
{ \
char local_buf[LOCALBUFSIZE]; \
public: \
TYPENAME() : Str(LOCALBUFSIZE) {} \
TYPENAME(const Str& rhs) : Str(LOCALBUFSIZE) { set(rhs); } \
TYPENAME(const char* rhs) : Str(LOCALBUFSIZE) { set(rhs); } \
TYPENAME(const TYPENAME& rhs) : Str(LOCALBUFSIZE) { set(rhs); } \
TYPENAME& operator=(const char* rhs) { set(rhs); return *this; } \
TYPENAME& operator=(const Str& rhs) { set(rhs); return *this; } \
TYPENAME& operator=(const TYPENAME& rhs) { set(rhs); return *this; } \
};
// Disable PVS-Studio warning V730: Not all members of a class are initialized inside the constructor (local_buf is not initialized and that is fine)
// -V:STR_DEFINETYPE:730
// Helper to define StrXXXf constructors
#define STR_DEFINETYPE_F(TYPENAME, TYPENAME_F) \
class TYPENAME_F : public TYPENAME \
{ \
public: \
TYPENAME_F(const char* fmt, ...) : TYPENAME() { va_list args; va_start(args, fmt); setfv(fmt, args); va_end(args); } \
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field" // warning : private field 'local_buf' is not used
#endif
// Declaring types for common sizes here
STR_DEFINETYPE(Str16, 16)
STR_DEFINETYPE(Str30, 30)
STR_DEFINETYPE(Str64, 64)
STR_DEFINETYPE(Str128, 128)
STR_DEFINETYPE(Str256, 256)
STR_DEFINETYPE(Str512, 512)
// Declaring helper constructors to pass in format strings in one statement
STR_DEFINETYPE_F(Str16, Str16f)
STR_DEFINETYPE_F(Str30, Str30f)
STR_DEFINETYPE_F(Str64, Str64f)
STR_DEFINETYPE_F(Str128, Str128f)
STR_DEFINETYPE_F(Str256, Str256f)
STR_DEFINETYPE_F(Str512, Str512f)
#if STR_DEFINE_STR32
STR_DEFINETYPE(Str32, 32)
STR_DEFINETYPE_F(Str32, Str32f)
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // #ifndef STR_INCLUDED
//-------------------------------------------------------------------------
// IMPLEMENTATION
//-------------------------------------------------------------------------
#ifdef STR_IMPLEMENTATION
#include <stdio.h> // for vsnprintf
// On some platform vsnprintf() takes va_list by reference and modifies it.
// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
#ifndef va_copy
#define va_copy(dest, src) (dest = src)
#endif
// Static empty buffer we can point to for empty strings
// Pointing to a literal increases the like-hood of getting a crash if someone attempts to write in the empty string buffer.
char* Str::EmptyBuffer = (char*)"\0NULL";
// Clear
void Str::clear()
{
if (Owned && !is_using_local_buf())
STR_MEMFREE(Data);
if (LocalBufSize)
{
Data = local_buf();
Data[0] = '\0';
Capacity = LocalBufSize - 1;
Owned = 1;
}
else
{
Data = EmptyBuffer;
Capacity = 0;
Owned = 0;
}
}
// Reserve memory, preserving the current of the buffer
// Capacity doesn't include the zero terminator, so reserve(5) is enough to store "hello".
void Str::reserve(int new_capacity)
{
if (new_capacity <= Capacity)
return;
char* new_data;
if (new_capacity <= LocalBufSize - 1)
{
// Disowned -> LocalBuf
new_data = local_buf();
new_capacity = LocalBufSize - 1;
}
else
{
// Disowned or LocalBuf -> Heap
new_data = (char*)STR_MEMALLOC((size_t)(new_capacity + 1) * sizeof(char));
}
// string in Data might be longer than new_capacity if it wasn't owned, don't copy too much
#ifdef _MSC_VER
strncpy_s(new_data, (size_t)new_capacity + 1, Data, (size_t)new_capacity);
#else
strncpy(new_data, Data, (size_t)new_capacity);
#endif
new_data[new_capacity] = 0;
if (Owned && !is_using_local_buf())
STR_MEMFREE(Data);
Data = new_data;
Capacity = new_capacity;
Owned = 1;
}
// Reserve memory, discarding the current of the buffer (if we expect to be fully rewritten)
void Str::reserve_discard(int new_capacity)
{
if (new_capacity <= Capacity)
return;
if (Owned && !is_using_local_buf())
STR_MEMFREE(Data);
if (new_capacity <= LocalBufSize - 1)
{
// Disowned -> LocalBuf
Data = local_buf();
Capacity = LocalBufSize - 1;
}
else
{
// Disowned or LocalBuf -> Heap
Data = (char*)STR_MEMALLOC((size_t)(new_capacity + 1) * sizeof(char));
Capacity = new_capacity;
}
Owned = 1;
}
void Str::shrink_to_fit()
{
if (!Owned || is_using_local_buf())
return;
int new_capacity = length();
if (Capacity <= new_capacity)
return;
char* new_data = (char*)STR_MEMALLOC((size_t)(new_capacity + 1) * sizeof(char));
memcpy(new_data, Data, (size_t)(new_capacity + 1));
STR_MEMFREE(Data);
Data = new_data;
Capacity = new_capacity;
}
// FIXME: merge setfv() and appendfv()?
int Str::setfv(const char* fmt, va_list args)
{
// Needed for portability on platforms where va_list are passed by reference and modified by functions
va_list args2;
va_copy(args2, args);
// MSVC returns -1 on overflow when writing, which forces us to do two passes
// FIXME-OPT: Find a way around that.
#ifdef _MSC_VER
int len = vsnprintf(NULL, 0, fmt, args);
STR_ASSERT(len >= 0);
if (Capacity < len)
reserve_discard(len);
len = vsnprintf(Data, (size_t)len + 1, fmt, args2);
#else
// First try
int len = vsnprintf(Owned ? Data : NULL, Owned ? (size_t)(Capacity + 1): 0, fmt, args);
STR_ASSERT(len >= 0);
if (Capacity < len)
{
reserve_discard(len);
len = vsnprintf(Data, (size_t)len + 1, fmt, args2);
}
#endif
STR_ASSERT(Owned);
return len;
}
int Str::setf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = setfv(fmt, args);
va_end(args);
return len;
}
int Str::setfv_nogrow(const char* fmt, va_list args)
{
STR_ASSERT(Owned);
if (Capacity == 0)
return 0;
int w = vsnprintf(Data, (size_t)(Capacity + 1), fmt, args);
Data[Capacity] = 0;
Owned = 1;
return (w == -1) ? Capacity : w;
}
int Str::setf_nogrow(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = setfv_nogrow(fmt, args);
va_end(args);
return len;
}
int Str::append_from(int idx, char c)
{
int add_len = 1;
if (Capacity < idx + add_len)
reserve(idx + add_len);
Data[idx] = c;
Data[idx + add_len] = 0;
STR_ASSERT(Owned);
return add_len;
}
int Str::append_from(int idx, const char* s, const char* s_end)
{
if (!s_end)
s_end = s + strlen(s);
int add_len = (int)(s_end - s);
if (Capacity < idx + add_len)
reserve(idx + add_len);
memcpy(Data + idx, (const void*)s, (size_t)add_len);
Data[idx + add_len] = 0; // Our source data isn't necessarily zero terminated
STR_ASSERT(Owned);
return add_len;
}
// FIXME: merge setfv() and appendfv()?
int Str::appendfv_from(int idx, const char* fmt, va_list args)
{
// Needed for portability on platforms where va_list are passed by reference and modified by functions
va_list args2;
va_copy(args2, args);
// MSVC returns -1 on overflow when writing, which forces us to do two passes
// FIXME-OPT: Find a way around that.
#ifdef _MSC_VER
int add_len = vsnprintf(NULL, 0, fmt, args);
STR_ASSERT(add_len >= 0);
if (Capacity < idx + add_len)
reserve(idx + add_len);
add_len = vsnprintf(Data + idx, add_len + 1, fmt, args2);
#else
// First try
int add_len = vsnprintf(Owned ? Data + idx : NULL, Owned ? (size_t)(Capacity + 1 - idx) : 0, fmt, args);
STR_ASSERT(add_len >= 0);
if (Capacity < idx + add_len)
{
reserve(idx + add_len);
add_len = vsnprintf(Data + idx, (size_t)add_len + 1, fmt, args2);
}
#endif
STR_ASSERT(Owned);
return add_len;
}
int Str::appendf_from(int idx, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = appendfv_from(idx, fmt, args);
va_end(args);
return len;
}
int Str::append(char c)
{
int cur_len = length();
return append_from(cur_len, c);
}
int Str::append(const char* s, const char* s_end)
{
int cur_len = length();
return append_from(cur_len, s, s_end);
}
int Str::appendfv(const char* fmt, va_list args)
{
int cur_len = length();
return appendfv_from(cur_len, fmt, args);
}
int Str::appendf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = appendfv(fmt, args);
va_end(args);
return len;
}
#endif // #define STR_IMPLEMENTATION
//-------------------------------------------------------------------------
-11
View File
@@ -1,11 +0,0 @@
# Str
Simple C++ string type with an optional local buffer, by Omar Cornut
https://github.com/ocornut/str
**LICENSE**
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit.
-2
View File
@@ -1,2 +0,0 @@
#define STR_IMPLEMENTATION
#include "Str.h"
@@ -1,51 +0,0 @@
#pragma once
#include <tt_lock.h>
class ScopedLock;
/** Represents a lock/mutex */
class Lock {
public:
virtual ~Lock() = default;
virtual bool lock(TickType timeout) const = 0;
bool lock() const { return lock(TT_MAX_TICKS); }
virtual bool unlock() const = 0;
ScopedLock asScopedLock() const;
};
/**
* Represents a lockable instance that is scoped to a specific lifecycle.
* Once the ScopedLock is destroyed, unlock() is called automatically.
*
* In other words:
* You have to lock() this object manually, but unlock() happens automatically on destruction.
*/
class ScopedLock final : public Lock {
const Lock& lockable;
public:
using Lock::lock;
explicit ScopedLock(const Lock& lockable) : lockable(lockable) {}
~ScopedLock() override {
lockable.unlock(); // We don't care whether it succeeded or not
}
bool lock(TickType timeout) const override {
return lockable.lock(timeout);
}
bool unlock() const override {
return lockable.unlock();
}
};
@@ -1,21 +1,19 @@
#pragma once
#include <TactilityCpp/Lock.h>
#include <Tactility/Lock.h>
#include <tt_lvgl.h>
class LvglLock final : public Lock {
class LvglLock final : public tt::Lock {
public:
bool lock(TickType timeout = TT_MAX_TICKS) const override {
tt_lvgl_lock(timeout);
return true;
bool lock(TickType_t timeout = tt::kernel::MAX_TICKS) const override {
return tt_lvgl_lock(timeout);
}
bool unlock() const override {
void unlock() const override {
tt_lvgl_unlock();
return true;
}
};
@@ -1,27 +0,0 @@
#pragma once
#include <tt_lock.h>
#include <TactilityCpp/Lock.h>
class Mutex final : public Lock {
LockHandle handle;
public:
explicit Mutex(TtMutexType type) : handle(tt_lock_alloc_mutex(type)) {};
~Mutex() override {
tt_lock_free(handle);
}
bool lock(TickType timeout = TT_MAX_TICKS) const override {
return tt_lock_acquire(handle, timeout);
}
bool unlock() const override {
return tt_lock_release(handle);
}
};
@@ -1,65 +0,0 @@
#pragma once
#include <tt_thread.h>
class Thread {
ThreadHandle handle;
public:
Thread() : handle(tt_thread_alloc()) {}
Thread(
const char* name,
uint32_t stackSize,
ThreadCallback callback,
void* _Nullable callbackContext
) : handle(tt_thread_alloc_ext(name, stackSize, callback, callbackContext)) {}
~Thread() {
tt_thread_free(handle);
}
void start() const {
tt_thread_start(handle);
}
bool join(TickType timeout = TT_MAX_TICKS) const {
return tt_thread_join(handle, timeout);
}
void setName(const char* name) const {
tt_thread_set_name(handle, name);
}
void setStackSize(size_t stackSize) const {
tt_thread_set_stack_size(handle, stackSize);
}
void setAffinity(int affinity) const {
tt_thread_set_affinity(handle, affinity);
}
void setCallback(ThreadCallback callback, void* _Nullable callbackContext) const {
tt_thread_set_callback(handle, callback, callbackContext);
}
void setPriority(ThreadPriority priority) const {
tt_thread_set_priority(handle, priority);
}
void setStateCallback(ThreadStateCallback callback, void* _Nullable callbackContext) const {
tt_thread_set_state_callback(handle, callback, callbackContext);
}
ThreadState getState() const {
return tt_thread_get_state(handle);
}
ThreadId getId() const {
return tt_thread_get_id(handle);
}
int32_t getReturnCode() const {
return tt_thread_get_return_code(handle);
}
};
@@ -1,8 +1,10 @@
#pragma once
#include <tt_hal_uart.h>
#include <Str.h>
#include <memory>
#include <string>
#include <vector>
#include <freertos/FreeRTOS.h>
class Uart {
UartHandle handle;
@@ -20,13 +22,13 @@ public:
return std::make_unique<Uart>(handle);
}
static std::vector<Str> getNames() {
std::vector<Str> names;
static std::vector<std::string> getNames() {
std::vector<std::string> names;
size_t count = tt_hal_uart_get_count();
for (size_t i = 0; i < count; i++) {
char buffer[64];
if (tt_hal_uart_get_name(i, buffer, sizeof(buffer))) {
names.push_back(Str(buffer));
names.push_back(std::string(buffer));
}
}
return names;
@@ -44,15 +46,15 @@ public:
return tt_hal_uart_stop(handle);
}
size_t readBytes(char* buffer, size_t bufferSize, TickType timeout) const {
size_t readBytes(char* buffer, size_t bufferSize, TickType_t timeout) const {
return tt_hal_uart_read_bytes(handle, buffer, bufferSize, timeout);
}
bool readByte(char* output, TickType timeout) const {
bool readByte(char* output, TickType_t timeout) const {
return tt_hal_uart_read_bytes(handle, output, 1, timeout);
}
size_t writeBytes(const char* buffer, size_t bufferSize, TickType timeout) const {
size_t writeBytes(const char* buffer, size_t bufferSize, TickType_t timeout) const {
return tt_hal_uart_write_bytes(handle, buffer, bufferSize, timeout);
}
-6
View File
@@ -1,6 +0,0 @@
#include <TactilityCpp/Lock.h>
ScopedLock Lock::asScopedLock() const {
return ScopedLock(*this);
}