From 9cc58099b428d8ff87923ca015a3040a9bec79a0 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Tue, 23 Sep 2025 23:21:58 +0200 Subject: [PATCH] Remove external apps (#346) --- ExternalApps/Calculator/.gitignore | 2 - ExternalApps/Calculator/CMakeLists.txt | 16 - ExternalApps/Calculator/main/CMakeLists.txt | 6 - .../Calculator/main/Source/Calculator.cpp | 204 ------ .../Calculator/main/Source/Calculator.h | 27 - ExternalApps/Calculator/main/Source/Dequeue.h | 95 --- ExternalApps/Calculator/main/Source/Stack.h | 21 - ExternalApps/Calculator/main/Source/Str.cpp | 2 - ExternalApps/Calculator/main/Source/Str.h | 618 ----------------- ExternalApps/Calculator/main/Source/main.cpp | 29 - ExternalApps/Calculator/manifest.properties | 10 - ExternalApps/Calculator/tactility.py | 630 ------------------ ExternalApps/GraphicsDemo/.gitignore | 2 - ExternalApps/GraphicsDemo/CMakeLists.txt | 16 - ExternalApps/GraphicsDemo/main/CMakeLists.txt | 7 - .../GraphicsDemo/main/Include/Application.h | 6 - .../GraphicsDemo/main/Include/PixelBuffer.h | 125 ---- .../main/Include/drivers/Colors.h | 35 - .../main/Include/drivers/DisplayDriver.h | 48 -- .../main/Include/drivers/TouchDriver.h | 28 - .../GraphicsDemo/main/Source/Application.cpp | 72 -- .../GraphicsDemo/main/Source/Main.cpp | 103 --- ExternalApps/GraphicsDemo/manifest.properties | 10 - ExternalApps/GraphicsDemo/tactility.py | 630 ------------------ ExternalApps/HelloWorld/.gitignore | 2 - ExternalApps/HelloWorld/CMakeLists.txt | 16 - ExternalApps/HelloWorld/assets/message.txt | 1 - ExternalApps/HelloWorld/main/CMakeLists.txt | 6 - ExternalApps/HelloWorld/main/Source/main.c | 24 - ExternalApps/HelloWorld/manifest.properties | 10 - ExternalApps/HelloWorld/tactility.py | 630 ------------------ Tactility/Source/app/ElfApp.cpp | 2 +- 32 files changed, 1 insertion(+), 3432 deletions(-) delete mode 100644 ExternalApps/Calculator/.gitignore delete mode 100644 ExternalApps/Calculator/CMakeLists.txt delete mode 100644 ExternalApps/Calculator/main/CMakeLists.txt delete mode 100644 ExternalApps/Calculator/main/Source/Calculator.cpp delete mode 100644 ExternalApps/Calculator/main/Source/Calculator.h delete mode 100644 ExternalApps/Calculator/main/Source/Dequeue.h delete mode 100644 ExternalApps/Calculator/main/Source/Stack.h delete mode 100644 ExternalApps/Calculator/main/Source/Str.cpp delete mode 100644 ExternalApps/Calculator/main/Source/Str.h delete mode 100644 ExternalApps/Calculator/main/Source/main.cpp delete mode 100644 ExternalApps/Calculator/manifest.properties delete mode 100644 ExternalApps/Calculator/tactility.py delete mode 100644 ExternalApps/GraphicsDemo/.gitignore delete mode 100644 ExternalApps/GraphicsDemo/CMakeLists.txt delete mode 100644 ExternalApps/GraphicsDemo/main/CMakeLists.txt delete mode 100644 ExternalApps/GraphicsDemo/main/Include/Application.h delete mode 100644 ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h delete mode 100644 ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h delete mode 100644 ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h delete mode 100644 ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h delete mode 100644 ExternalApps/GraphicsDemo/main/Source/Application.cpp delete mode 100644 ExternalApps/GraphicsDemo/main/Source/Main.cpp delete mode 100644 ExternalApps/GraphicsDemo/manifest.properties delete mode 100644 ExternalApps/GraphicsDemo/tactility.py delete mode 100644 ExternalApps/HelloWorld/.gitignore delete mode 100644 ExternalApps/HelloWorld/CMakeLists.txt delete mode 100644 ExternalApps/HelloWorld/assets/message.txt delete mode 100644 ExternalApps/HelloWorld/main/CMakeLists.txt delete mode 100644 ExternalApps/HelloWorld/main/Source/main.c delete mode 100644 ExternalApps/HelloWorld/manifest.properties delete mode 100644 ExternalApps/HelloWorld/tactility.py diff --git a/ExternalApps/Calculator/.gitignore b/ExternalApps/Calculator/.gitignore deleted file mode 100644 index 89baa26e..00000000 --- a/ExternalApps/Calculator/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build*/ -.tactility/ diff --git a/ExternalApps/Calculator/CMakeLists.txt b/ExternalApps/Calculator/CMakeLists.txt deleted file mode 100644 index 01bfb4b5..00000000 --- a/ExternalApps/Calculator/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -if (DEFINED ENV{TACTILITY_SDK_PATH}) - set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH}) -else() - set(TACTILITY_SDK_PATH "../../release/TactilitySDK") - message(WARNING "⚠️ TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}") -endif() - -include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake") -set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH}) - -project(Calculator) -tactility_project(Calculator) diff --git a/ExternalApps/Calculator/main/CMakeLists.txt b/ExternalApps/Calculator/main/CMakeLists.txt deleted file mode 100644 index 62c36897..00000000 --- a/ExternalApps/Calculator/main/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) - -idf_component_register( - SRCS ${SOURCE_FILES} - REQUIRES TactilitySDK -) diff --git a/ExternalApps/Calculator/main/Source/Calculator.cpp b/ExternalApps/Calculator/main/Source/Calculator.cpp deleted file mode 100644 index 9a0c161c..00000000 --- a/ExternalApps/Calculator/main/Source/Calculator.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "Calculator.h" -#include "Stack.h" - -#include -#include -#include - -constexpr const char* TAG = "Calculator"; - -static int precedence(char op) { - if (op == '+' || op == '-') return 1; - if (op == '*' || op == '/') return 2; - return 0; -} - -void Calculator::button_event_cb(lv_event_t* e) { - Calculator* self = static_cast(lv_event_get_user_data(e)); - lv_obj_t* buttonmatrix = lv_event_get_current_target_obj(e); - lv_event_code_t event_code = lv_event_get_code(e); - uint32_t button_id = lv_buttonmatrix_get_selected_button(buttonmatrix); - const char* button_text = lv_buttonmatrix_get_button_text(buttonmatrix, button_id); - if (event_code == LV_EVENT_VALUE_CHANGED) { - self->handleInput(button_text); - } -} - -void Calculator::handleInput(const char* txt) { - if (strcmp(txt, "C") == 0) { - resetCalculator(); - return; - } - - if (strcmp(txt, "=") == 0) { - evaluateExpression(); - return; - } - - if (strlen(formulaBuffer) + strlen(txt) < sizeof(formulaBuffer) - 1) { - if (newInput) { - memset(formulaBuffer, 0, sizeof(formulaBuffer)); - newInput = false; - } - strcat(formulaBuffer, txt); - lv_label_set_text(displayLabel, formulaBuffer); - } -} - -Dequeue Calculator::infixToRPN(const Str& infix) { - Stack opStack; - Dequeue output; - Str token; - size_t i = 0; - - while (i < infix.length()) { - char ch = infix[i]; - - if (isdigit(ch)) { - token.clear(); - while (i < infix.length() && (isdigit(infix[i]) || infix[i] == '.')) { token.append(infix[i++]); } - output.pushBack(token); - continue; - } - - if (ch == '(') { opStack.push(ch); } else if (ch == ')') { - while (!opStack.empty() && opStack.top() != '(') { - output.pushBack(Str(1, opStack.top())); - opStack.pop(); - } - opStack.pop(); - } else if (strchr("+-*/", ch)) { - while (!opStack.empty() && precedence(opStack.top()) >= precedence(ch)) { - output.pushBack(Str(1, opStack.top())); - opStack.pop(); - } - opStack.push(ch); - } - - i++; - } - - while (!opStack.empty()) { - output.pushBack(Str(1, opStack.top())); - opStack.pop(); - } - - return output; -} - -double Calculator::evaluateRPN(Dequeue rpnQueue) { - Stack values; - - while (!rpnQueue.empty()) { - Str token = rpnQueue.front(); - rpnQueue.popFront(); - - if (isdigit(token[0])) { - double d; - sscanf(token.c_str(), "%lf", &d); - values.push(d); - } else if (strchr("+-*/", token[0])) { - if (values.size() < 2) return 0; - - double b = values.top(); - values.pop(); - double a = values.top(); - values.pop(); - - if (token[0] == '+') values.push(a + b); - else if (token[0] == '-') values.push(a - b); - else if (token[0] == '*') values.push(a * b); - else if (token[0] == '/' && b != 0) values.push(a / b); - } - } - - return values.empty() ? 0 : values.top(); -} -void Calculator::evaluateExpression() { - double result = computeFormula(); - - size_t formulaLen = strlen(formulaBuffer); - size_t maxAvailable = sizeof(formulaBuffer) - formulaLen - 1; - - if (maxAvailable > 10) { - char resultBuffer[32]; - snprintf(resultBuffer, sizeof(resultBuffer), " = %.8g", result); - strncat(formulaBuffer, resultBuffer, maxAvailable); - } else { snprintf(formulaBuffer, sizeof(formulaBuffer), "%.8g", result); } - - lv_label_set_text(displayLabel, "0"); - lv_label_set_text(resultLabel, formulaBuffer); - newInput = true; -} - -double Calculator::computeFormula() { - return evaluateRPN(infixToRPN(Str(formulaBuffer))); -} - -void Calculator::resetCalculator() { - memset(formulaBuffer, 0, sizeof(formulaBuffer)); - lv_label_set_text(displayLabel, "0"); - lv_label_set_text(resultLabel, ""); - newInput = true; -} - -void Calculator::onShow(AppHandle appHandle, lv_obj_t* parent) { - lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE); - lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); - lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT); - - lv_obj_t* toolbar = tt_lvgl_toolbar_create_for_app(parent, appHandle); - lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); - - lv_obj_t* wrapper = lv_obj_create(parent); - lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(wrapper, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START); - lv_obj_set_width(wrapper, LV_PCT(100)); - lv_obj_set_height(wrapper, LV_SIZE_CONTENT); - lv_obj_set_flex_grow(wrapper, 0); - lv_obj_set_style_pad_top(wrapper, 4, LV_PART_MAIN); - lv_obj_set_style_pad_bottom(wrapper, 4, LV_PART_MAIN); - lv_obj_set_style_pad_left(wrapper, 10, LV_PART_MAIN); - lv_obj_set_style_pad_right(wrapper, 10, LV_PART_MAIN); - lv_obj_set_style_pad_column(wrapper, 40, LV_PART_MAIN); - lv_obj_set_style_border_width(wrapper, 0, 0); - lv_obj_remove_flag(wrapper, LV_OBJ_FLAG_SCROLLABLE); - - displayLabel = lv_label_create(wrapper); - lv_label_set_text(displayLabel, "0"); - lv_obj_set_width(displayLabel, LV_SIZE_CONTENT); - lv_obj_set_align(displayLabel, LV_ALIGN_LEFT_MID); - - resultLabel = lv_label_create(wrapper); - lv_label_set_text(resultLabel, ""); - lv_obj_set_width(resultLabel, LV_SIZE_CONTENT); - lv_obj_set_align(resultLabel, LV_ALIGN_RIGHT_MID); - - static const char* btn_map[] = { - "(", ")", "C", "/", "\n", - "7", "8", "9", "*", "\n", - "4", "5", "6", "-", "\n", - "1", "2", "3", "+", "\n", - "0", "=", "", "", "" - }; - - lv_obj_t* buttonmatrix = lv_buttonmatrix_create(parent); - lv_buttonmatrix_set_map(buttonmatrix, btn_map); - - lv_obj_set_style_pad_all(buttonmatrix, 5, LV_PART_MAIN); - lv_obj_set_style_pad_row(buttonmatrix, 10, LV_PART_MAIN); - lv_obj_set_style_pad_column(buttonmatrix, 5, LV_PART_MAIN); - lv_obj_set_style_border_width(buttonmatrix, 2, LV_PART_MAIN); - lv_obj_set_style_bg_color(buttonmatrix, lv_palette_main(LV_PALETTE_BLUE), LV_PART_ITEMS); - - if (lv_display_get_horizontal_resolution(nullptr) <= 240 || lv_display_get_vertical_resolution(nullptr) <= 240) { - //small screens - lv_obj_set_size(buttonmatrix, lv_pct(100), lv_pct(60)); - } else { - //large screens - lv_obj_set_size(buttonmatrix, lv_pct(100), lv_pct(80)); - } - lv_obj_align(buttonmatrix, LV_ALIGN_BOTTOM_MID, 0, -5); - - lv_obj_add_event_cb(buttonmatrix, button_event_cb, LV_EVENT_VALUE_CHANGED, this); -} \ No newline at end of file diff --git a/ExternalApps/Calculator/main/Source/Calculator.h b/ExternalApps/Calculator/main/Source/Calculator.h deleted file mode 100644 index 9149d912..00000000 --- a/ExternalApps/Calculator/main/Source/Calculator.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "tt_app.h" - -#include -#include "Str.h" -#include "Dequeue.h" - -class Calculator { - - lv_obj_t* displayLabel; - lv_obj_t* resultLabel; - char formulaBuffer[128] = {0}; // Stores the full input expression - bool newInput = true; - - static void button_event_cb(lv_event_t* e); - void handleInput(const char* txt); - void evaluateExpression(); - double computeFormula(); - static Dequeue infixToRPN(const Str& infix); - static double evaluateRPN(Dequeue rpnQueue); - void resetCalculator(); - -public: - - void onShow(AppHandle context, lv_obj_t* parent); -}; \ No newline at end of file diff --git a/ExternalApps/Calculator/main/Source/Dequeue.h b/ExternalApps/Calculator/main/Source/Dequeue.h deleted file mode 100644 index 9d3f2d53..00000000 --- a/ExternalApps/Calculator/main/Source/Dequeue.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -template -class Dequeue { - - struct Node { - DataType data; - Node* next; - Node* previous; - - Node(DataType data, Node* next, Node* previous): - data(data), - next(next), - previous(previous) - {} - }; - - int count = 0; - Node* head = nullptr; - Node* tail = nullptr; - -public: - - void pushFront(DataType data) { - auto* new_node = new Node(data, head, nullptr); - - if (head != nullptr) { - head->previous = new_node; - } - - if (tail == nullptr) { - tail = new_node; - } - - head = new_node; - count++; - } - - void pushBack(DataType data) { - auto* new_node = new Node(data, nullptr, tail); - - if (head == nullptr) { - head = new_node; - } - - if (tail != nullptr) { - tail->next = new_node; - } - - tail = new_node; - count++; - } - - void popFront() { - if (head != nullptr) { - bool is_last_node = (head == tail); - Node* node_to_delete = head; - head = node_to_delete->next; - if (is_last_node) { - tail = nullptr; - } - delete node_to_delete; - count--; - } - } - - void popBack() { - if (tail != nullptr) { - bool is_last_node = (head == tail); - Node* node_to_delete = tail; - tail = node_to_delete->previous; - if (is_last_node) { - head = nullptr; - } - delete node_to_delete; - count--; - } - } - - DataType back() const { - assert(tail != nullptr); - return tail->data; - } - - DataType front() const { - assert(head != nullptr); - return head->data; - } - - bool empty() const { - return head == nullptr; - } - - int size() const { return count; } -}; \ No newline at end of file diff --git a/ExternalApps/Calculator/main/Source/Stack.h b/ExternalApps/Calculator/main/Source/Stack.h deleted file mode 100644 index 0382b4ec..00000000 --- a/ExternalApps/Calculator/main/Source/Stack.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "Dequeue.h" - -template -class Stack { - - Dequeue dequeue; - -public: - - void push(DataType data) { dequeue.pushFront(data); } - - void pop() { dequeue.popFront(); } - - DataType top() const { return dequeue.front(); } - - bool empty() const { return dequeue.empty(); } - - int size() const { return dequeue.size(); } -}; diff --git a/ExternalApps/Calculator/main/Source/Str.cpp b/ExternalApps/Calculator/main/Source/Str.cpp deleted file mode 100644 index 78bcabea..00000000 --- a/ExternalApps/Calculator/main/Source/Str.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define STR_IMPLEMENTATION -#include "Str.h" diff --git a/ExternalApps/Calculator/main/Source/Str.h b/ExternalApps/Calculator/main/Source/Str.h deleted file mode 100644 index c5c022ae..00000000 --- a/ExternalApps/Calculator/main/Source/Str.h +++ /dev/null @@ -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 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 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 -#endif -#ifndef STR_MEMFREE -#define STR_MEMFREE free -#include -#endif -#ifndef STR_ASSERT -#define STR_ASSERT assert -#include -#endif -#ifndef STR_API -#define STR_API -#endif -#include // for va_list -#include // 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 // 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 - -//------------------------------------------------------------------------- diff --git a/ExternalApps/Calculator/main/Source/main.cpp b/ExternalApps/Calculator/main/Source/main.cpp deleted file mode 100644 index 6dc187d3..00000000 --- a/ExternalApps/Calculator/main/Source/main.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include "Calculator.h" - -static void onShow(AppHandle appHandle, void* data, lv_obj_t* parent) { - static_cast(data)->onShow(appHandle, parent); -} - -static void* createApp() { - return new Calculator(); -} - -static void destroyApp(void* app) { - delete static_cast(app); -} - -ExternalAppManifest manifest = { - .createData = createApp, - .destroyData = destroyApp, - .onShow = onShow, -}; - -extern "C" { - -int main(int argc, char* argv[]) { - tt_app_register(&manifest); - return 0; -} - -} diff --git a/ExternalApps/Calculator/manifest.properties b/ExternalApps/Calculator/manifest.properties deleted file mode 100644 index 83001b50..00000000 --- a/ExternalApps/Calculator/manifest.properties +++ /dev/null @@ -1,10 +0,0 @@ -[manifest] -version=0.1 -[target] -sdk=0.6.0-SNAPSHOT1 -platforms=esp32,esp32s3 -[app] -id=one.tactility.calculator -versionName=0.1.0 -versionCode=1 -name=Calculator diff --git a/ExternalApps/Calculator/tactility.py b/ExternalApps/Calculator/tactility.py deleted file mode 100644 index faa4dfba..00000000 --- a/ExternalApps/Calculator/tactility.py +++ /dev/null @@ -1,630 +0,0 @@ -import configparser -import json -import os -import re -import shutil -import sys -import subprocess -import time -import urllib.request -import zipfile -import requests -import tarfile -import shutil -import configparser - -ttbuild_path = ".tactility" -ttbuild_version = "2.2.0" -ttbuild_cdn = "https://cdn.tactility.one" -ttbuild_sdk_json_validity = 3600 # seconds -ttport = 6666 -verbose = False -use_local_sdk = False -valid_platforms = ["esp32", "esp32s3"] - -spinner_pattern = [ - "⠋", - "⠙", - "⠹", - "⠸", - "⠼", - "⠴", - "⠦", - "⠧", - "⠇", - "⠏" -] - -if sys.platform == "win32": - shell_color_red = "" - shell_color_orange = "" - shell_color_green = "" - shell_color_purple = "" - shell_color_cyan = "" - shell_color_reset = "" -else: - 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" - -def print_help(): - print("Usage: python tactility.py [action] [options]") - print("") - print("Actions:") - print(" build [esp32,esp32s3] Build the app. Optionally specify a platform.") - print(" esp32: ESP32") - print(" esp32s3: ESP32 S3") - print(" clean Clean the build folders") - print(" clearcache Clear the SDK cache") - print(" updateself Update this tool") - print(" run [ip] Run the application") - print(" install [ip] Install the application") - print(" uninstall [ip] Uninstall the application") - print(" bir [ip] [esp32,esp32s3] Build, install then run. Optionally specify a platform.") - print(" brrr [ip] [esp32,esp32s3] Functionally the same as \"bir\", but \"app goes brrr\" meme variant.") - print("") - print("Options:") - print(" --help Show this commandline info") - print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH") - print(" --skip-build Run everything except the idf.py/CMake commands") - print(" --verbose Show extra console output") - -# region Core - -def download_file(url, filepath): - global verbose - if verbose: - print(f"Downloading from {url} to {filepath}") - request = urllib.request.Request( - url, - data=None, - headers={ - "User-Agent": f"Tactility Build Tool {ttbuild_version}" - } - ) - try: - response = urllib.request.urlopen(request) - file = open(filepath, mode="wb") - file.write(response.read()) - file.close() - return True - except OSError as error: - if verbose: - print_error(f"Failed to fetch URL {url}\n{error}") - return False - -def print_warning(message): - print(f"{shell_color_orange}WARNING: {message}{shell_color_reset}") - -def print_error(message): - print(f"{shell_color_red}ERROR: {message}{shell_color_reset}") - -def exit_with_error(message): - print_error(message) - sys.exit(1) - -def get_url(ip, path): - return f"http://{ip}:{ttport}{path}" - -def read_properties_file(path): - config = configparser.RawConfigParser() - config.read(path) - return config - -#endregion Core - -#region SDK helpers - -def read_sdk_json(): - json_file_path = os.path.join(ttbuild_path, "sdk.json") - json_file = open(json_file_path) - return json.load(json_file) - -def get_sdk_dir(version, platform): - global use_local_sdk - if use_local_sdk: - return os.environ.get("TACTILITY_SDK_PATH") - else: - global ttbuild_cdn - return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK") - -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): - global ttbuild_cdn - return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip" - -def sdk_exists(version, platform): - sdk_dir = get_sdk_dir(version, platform) - return os.path.isdir(sdk_dir) - -def should_update_sdk_json(): - global ttbuild_cdn - json_filepath = os.path.join(ttbuild_path, "sdk.json") - if os.path.exists(json_filepath): - json_modification_time = os.path.getmtime(json_filepath) - now = time.time() - global ttbuild_sdk_json_validity - minimum_seconds_difference = ttbuild_sdk_json_validity - return (now - json_modification_time) > minimum_seconds_difference - else: - return True - -def update_sdk_json(): - global ttbuild_cdn, ttbuild_path - json_url = f"{ttbuild_cdn}/sdk.json" - json_filepath = os.path.join(ttbuild_path, "sdk.json") - return download_file(json_url, json_filepath) - -def should_fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)): - return True - return False - -def fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - target_path = os.path.join(ttbuild_path, sdkconfig_filename) - if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): - exit_with_error(f"Failed to download sdkconfig file for {platform}") - -#endregion SDK helpers - -#region Validation - -def validate_environment(): - if os.environ.get("IDF_PATH") is None: - exit_with_error("Cannot find the Espressif IDF SDK. Ensure it is installed and that it is activated via $PATH_TO_IDF_SDK/export.sh") - if not os.path.exists("manifest.properties"): - exit_with_error("manifest.properties not found") - if use_local_sdk == False and os.environ.get("TACTILITY_SDK_PATH") is not None: - print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command.") - print_warning("If you want to use it, use the 'build local' parameters.") - 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)") - if not "toolCompatibility" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolCompatibility not found)") - if not "toolDownloadUrl" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolDownloadUrl not found)") - tool_version = sdk_json["toolVersion"] - tool_compatibility = sdk_json["toolCompatibility"] - if tool_version != ttbuild_version: - print_warning(f"New version available: {tool_version} (currently using {ttbuild_version})") - print_warning(f"Run 'tactility.py updateself' to update.") - if re.search(tool_compatibility, ttbuild_version) is None: - print_error("The tool is not compatible anymore.") - print_error("Run 'tactility.py updateself' to update.") - sys.exit(1) - -#endregion Validation - -#region Manifest - -def read_manifest(): - return read_properties_file("manifest.properties") - -def validate_manifest(manifest): - # [manifest] - if not "manifest" in manifest: - exit_with_error("Invalid manifest format: [manifest] not found") - if not "version" in manifest["manifest"]: - exit_with_error("Invalid manifest format: [manifest] version not found") - # [target] - if not "target" in manifest: - exit_with_error("Invalid manifest format: [target] not found") - if not "sdk" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] sdk not found") - if not "platforms" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] platforms not found") - # [app] - if not "app" in manifest: - exit_with_error("Invalid manifest format: [app] not found") - if not "id" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] id not found") - if not "versionName" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionName not found") - if not "versionCode" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionCode not found") - if not "name" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] name not found") - -def is_valid_manifest_platform(manifest, platform): - manifest_platforms = manifest["target"]["platforms"].split(",") - return platform in manifest_platforms - -def validate_manifest_platform(manifest, platform): - if not is_valid_manifest_platform(manifest, platform): - exit_with_error(f"Platform {platform} is not available in the manifest.") - -def get_manifest_target_platforms(manifest, requested_platform): - if requested_platform == "" or requested_platform is None: - return manifest["target"]["platforms"].split(",") - else: - validate_manifest_platform(manifest, requested_platform) - return [requested_platform] - -#endregion Manifest - -#region SDK download - -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") - print(f"Downloading SDK version {version} for {platform}") - if download_file(sdk_url, filepath): - with zipfile.ZipFile(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: - if not sdk_exists(version, platform): - if not sdk_download(version, platform): - return False - else: - if verbose: - print(f"Using cached download for SDK version {version} and platform {platform}") - return True - -#endregion SDK download - -#region Building - -def get_cmake_path(platform): - return os.path.join("build", f"cmake-build-{platform}") - -def find_elf_file(platform): - cmake_dir = get_cmake_path(platform) - if os.path.exists(cmake_dir): - for file in os.listdir(cmake_dir): - if file.endswith(".app.elf"): - return os.path.join(cmake_dir, file) - return None - -def build_all(version, platforms, skip_build): - for platform in platforms: - # First build command must be "idf.py build", otherwise it fails to execute "idf.py elf" - # We check if the ELF file exists and run the correct command - # This can lead to code caching issues, so sometimes a clean build is required - if find_elf_file(platform) is None: - if not build_first(version, platform, skip_build): - break - else: - if not build_consecutively(version, platform, skip_build): - break - -def wait_for_build(process, platform): - buffer = [] - os.set_blocking(process.stdout.fileno(), False) - while process.poll() is None: - for i in spinner_pattern: - time.sleep(0.1) - progress_text = f"Building for {platform} {shell_color_cyan}" + str(i) + shell_color_reset - sys.stdout.write(progress_text + "\r") - while True: - line = process.stdout.readline() - decoded_line = line.decode("UTF-8") - if decoded_line != "": - buffer.append(decoded_line) - else: - break - return buffer - -# The first build must call "idf.py build" and consecutive builds must call "idf.py elf" as it finishes faster. -# The problem is that the "idf.py build" always results in an error, even though the elf file is created. -# The solution is to suppress the error if we find that the elf file was created. -def build_first(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - elf_path = find_elf_file(platform) - # Remove previous elf file: re-creation of the file is used to measure if the build succeeded, - # as the actual build job will always fail due to technical issues with the elf cmake script - if elf_path is not None: - os.remove(elf_path) - if skip_build: - return True - print("Building first build") - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - # 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: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - if find_elf_file(platform) is None: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - else: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - -def build_consecutively(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - if skip_build: - return True - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - if process.returncode == 0: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - -#endregion Building - -#region Packaging - -def package_intermediate_manifest(target_path): - if not os.path.isfile("manifest.properties"): - print_error("manifest.properties not found") - return - shutil.copy("manifest.properties", os.path.join(target_path, "manifest.properties")) - -def package_intermediate_binaries(target_path, platforms): - elf_dir = os.path.join(target_path, "elf") - os.makedirs(elf_dir, exist_ok=True) - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - print_error(f"ELF file not found at {elf_path}") - return - shutil.copy(elf_path, os.path.join(elf_dir, f"{platform}.elf")) - -def package_intermediate_assets(target_path): - if os.path.isdir("assets"): - shutil.copytree("assets", os.path.join(target_path, "assets"), dirs_exist_ok=True) - -def package_intermediate(platforms): - target_path = os.path.join("build", "package-intermediate") - if os.path.isdir(target_path): - shutil.rmtree(target_path) - os.makedirs(target_path, exist_ok=True) - package_intermediate_manifest(target_path) - package_intermediate_binaries(target_path, platforms) - package_intermediate_assets(target_path) - -def package_name(platforms): - elf_path = find_elf_file(platforms[0]) - elf_base_name = os.path.basename(elf_path).removesuffix(".app.elf") - return os.path.join("build", f"{elf_base_name}.app") - -def package_all(platforms): - print("Packaging app") - package_intermediate(platforms) - # Create build/something.app - tar_path = package_name(platforms) - tar = tarfile.open(tar_path, mode="w", format=tarfile.USTAR_FORMAT) - tar.add(os.path.join("build", "package-intermediate"), arcname="") - tar.close() - -#endregion Packaging - -def setup_environment(): - global ttbuild_path - os.makedirs(ttbuild_path, exist_ok=True) - -def build_action(manifest, platform_arg): - # Environment validation - validate_environment() - platforms_to_build = get_manifest_target_platforms(manifest, platform_arg) - if not use_local_sdk: - if should_fetch_sdkconfig_files(platforms_to_build): - fetch_sdkconfig_files(platforms_to_build) - 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") - build_all(sdk_version, platforms_to_build, skip_build) # Environment validation - if not skip_build: - package_all(platforms_to_build) - -def clean_action(): - if os.path.exists("build"): - print(f"Removing build/") - shutil.rmtree("build") - else: - print("Nothing to clean") - -def clear_cache_action(): - if os.path.exists(ttbuild_path): - print(f"Removing {ttbuild_path}/") - shutil.rmtree(ttbuild_path) - else: - print("Nothing to clear") - -def update_self_action(): - sdk_json = read_sdk_json() - tool_download_url = sdk_json["toolDownloadUrl"] - if download_file(tool_download_url, "tactility.py"): - print("Updated") - else: - exit_with_error("Update failed") - -def get_device_info(ip): - print(f"Getting device info from {ip}") - url = get_url(ip, "/info") - try: - response = requests.get(url) - if response.status_code != 200: - print_error("Run failed") - else: - print(response.json()) - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def run_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Running {app_id} on {ip}") - url = get_url(ip, "/app/run") - params = {'id': app_id} - try: - response = requests.post(url, params=params) - if response.status_code != 200: - print_error("Run failed") - else: - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def install_action(ip, platforms): - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - exit_with_error(f"ELF file not built for {platform}") - package_path = package_name(platforms) - print(f"Installing {package_path} to {ip}") - url = get_url(ip, "/app/install") - try: - # Prepare multipart form data - with open(package_path, 'rb') as file: - files = { - 'elf': file - } - response = requests.put(url, files=files) - if response.status_code != 200: - print_error("Install failed") - else: - print(f"{shell_color_green}Installation successful ✅{shell_color_reset}") - except requests.RequestException as e: - print_error(f"Installation failed: {e}") - except IOError as e: - print_error(f"File error: {e}") - -def uninstall_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Uninstalling {app_id} on {ip}") - url = get_url(ip, "/app/uninstall") - params = {'id': app_id} - try: - response = requests.put(url, params=params) - if response.status_code != 200: - print_error("Uninstall failed") - else: - print(f"{shell_color_green}Uninstall successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") -#region Main - -if __name__ == "__main__": - print(f"Tactility Build System v{ttbuild_version}") - if "--help" in sys.argv: - print_help() - sys.exit() - # Argument validation - if len(sys.argv) == 1: - print_help() - sys.exit() - action_arg = sys.argv[1] - verbose = "--verbose" in sys.argv - skip_build = "--skip-build" in sys.argv - use_local_sdk = "--local-sdk" in sys.argv - # Environment setup - setup_environment() - if not os.path.isfile("manifest.properties"): - exit_with_error("manifest.properties not found") - 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(): - exit_with_error("Failed to retrieve SDK info") - # Actions - if action_arg == "build": - if len(sys.argv) < 2: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - if len(sys.argv) > 2: - platform = sys.argv[2] - build_action(manifest, platform) - elif action_arg == "clean": - clean_action() - elif action_arg == "clearcache": - clear_cache_action() - elif action_arg == "updateself": - update_self_action() - elif action_arg == "run": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - run_action(manifest, sys.argv[2]) - elif action_arg == "install": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - install_action(sys.argv[2], platforms_to_install) - elif action_arg == "uninstall": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - uninstall_action(manifest, sys.argv[2]) - elif action_arg == "bir" or action_arg == "brrr": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - build_action(manifest, platform) - install_action(sys.argv[2], platforms_to_install) - run_action(manifest, sys.argv[2]) - else: - print_help() - exit_with_error("Unknown commandline parameter") - -#endregion Main diff --git a/ExternalApps/GraphicsDemo/.gitignore b/ExternalApps/GraphicsDemo/.gitignore deleted file mode 100644 index 89baa26e..00000000 --- a/ExternalApps/GraphicsDemo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build*/ -.tactility/ diff --git a/ExternalApps/GraphicsDemo/CMakeLists.txt b/ExternalApps/GraphicsDemo/CMakeLists.txt deleted file mode 100644 index c9cfd749..00000000 --- a/ExternalApps/GraphicsDemo/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -if (DEFINED ENV{TACTILITY_SDK_PATH}) - set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH}) -else() - set(TACTILITY_SDK_PATH "../../release/TactilitySDK") - message(WARNING "⚠️ TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}") -endif() - -include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake") -set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH}) - -project(GraphicsDemo) -tactility_project(GraphicsDemo) diff --git a/ExternalApps/GraphicsDemo/main/CMakeLists.txt b/ExternalApps/GraphicsDemo/main/CMakeLists.txt deleted file mode 100644 index 759aed70..00000000 --- a/ExternalApps/GraphicsDemo/main/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c*) - -idf_component_register( - SRC_DIRS "Source" - INCLUDE_DIRS "Include" - REQUIRES TactilitySDK -) diff --git a/ExternalApps/GraphicsDemo/main/Include/Application.h b/ExternalApps/GraphicsDemo/main/Include/Application.h deleted file mode 100644 index 90bcf712..00000000 --- a/ExternalApps/GraphicsDemo/main/Include/Application.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "drivers/DisplayDriver.h" -#include "drivers/TouchDriver.h" - -void runApplication(DisplayDriver* display, TouchDriver* touch); diff --git a/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h b/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h deleted file mode 100644 index c13b47fb..00000000 --- a/ExternalApps/GraphicsDemo/main/Include/PixelBuffer.h +++ /dev/null @@ -1,125 +0,0 @@ -#pragma once - -#include -#include "drivers/Colors.h" - -#include -#include - -class PixelBuffer { - uint16_t pixelWidth; - uint16_t pixelHeight; - ColorFormat colorFormat; - uint8_t* data; - -public: - - PixelBuffer(uint16_t pixelWidth, uint16_t pixelHeight, ColorFormat colorFormat) : - pixelWidth(pixelWidth), - pixelHeight(pixelHeight), - colorFormat(colorFormat) - { - data = static_cast(malloc(pixelWidth * pixelHeight * getPixelSize())); - assert(data != nullptr); - } - - ~PixelBuffer() { - free(data); - } - - uint16_t getPixelWidth() const { - return pixelWidth; - } - - uint16_t getPixelHeight() const { - return pixelHeight; - } - - ColorFormat getColorFormat() const { - return colorFormat; - } - - void* getData() const { - return data; - } - - uint32_t getDataSize() const { - return pixelWidth * pixelHeight * getPixelSize(); - } - - void* getDataAtRow(uint16_t row) const { - auto address = reinterpret_cast(data) + (row * getRowDataSize()); - return reinterpret_cast(address); - } - - uint16_t getRowDataSize() const { - return pixelWidth * getPixelSize(); - } - - uint8_t getPixelSize() const { - switch (colorFormat) { - case COLOR_FORMAT_MONOCHROME: - return 1; - case COLOR_FORMAT_BGR565: - case COLOR_FORMAT_BGR565_SWAPPED: - case COLOR_FORMAT_RGB565: - case COLOR_FORMAT_RGB565_SWAPPED: - return 2; - case COLOR_FORMAT_RGB888: - return 3; - default: - // TODO: Crash with error - return 0; - } - } - - uint8_t* getPixelAddress(uint16_t x, uint16_t y) const { - uint32_t offset = ((y * getPixelWidth()) + x) * getPixelSize(); - uint32_t address = reinterpret_cast(data) + offset; - return reinterpret_cast(address); - } - - void setPixel(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b) const { - auto address = getPixelAddress(x, y); - switch (colorFormat) { - case COLOR_FORMAT_MONOCHROME: - *address = (uint8_t)((uint16_t)r + (uint16_t)g + (uint16_t)b / 3); - break; - case COLOR_FORMAT_BGR565: - Colors::rgb888ToBgr565(r, g, b, reinterpret_cast(address)); - break; - case COLOR_FORMAT_BGR565_SWAPPED: { - // TODO: Make proper conversion function - Colors::rgb888ToBgr565(r, g, b, reinterpret_cast(address)); - uint8_t temp = *address; - *address = *(address + 1); - *(address + 1) = temp; - break; - } - case COLOR_FORMAT_RGB565: { - Colors::rgb888ToRgb565(r, g, b, reinterpret_cast(address)); - break; - } - case COLOR_FORMAT_RGB565_SWAPPED: { - // TODO: Make proper conversion function - Colors::rgb888ToRgb565(r, g, b, reinterpret_cast(address)); - uint8_t temp = *address; - *address = *(address + 1); - *(address + 1) = temp; - break; - } - case COLOR_FORMAT_RGB888: { - uint8_t pixel[3] = { r, g, b }; - memcpy(address, pixel, 3); - break; - } - default: - // NO-OP - break; - } - } - - void clear(int value = 0) const { - memset(data, value, getDataSize()); - } -}; \ No newline at end of file diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h b/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h deleted file mode 100644 index d068574c..00000000 --- a/ExternalApps/GraphicsDemo/main/Include/drivers/Colors.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -class Colors { - -public: - - static void rgb888ToRgb565(uint8_t red, uint8_t green, uint8_t blue, uint16_t* rgb565) { - uint16_t _rgb565 = (red >> 3); - _rgb565 = (_rgb565 << 6) | (green >> 2); - _rgb565 = (_rgb565 << 5) | (blue >> 3); - *rgb565 = _rgb565; - } - - static void rgb888ToBgr565(uint8_t red, uint8_t green, uint8_t blue, uint16_t* bgr565) { - uint16_t _bgr565 = (blue >> 3); - _bgr565 = (_bgr565 << 6) | (green >> 2); - _bgr565 = (_bgr565 << 5) | (red >> 3); - *bgr565 = _bgr565; - } - - static void rgb565ToRgb888(uint16_t rgb565, uint32_t* rgb888) { - uint32_t _rgb565 = rgb565; - uint8_t b = (_rgb565 >> 8) & 0xF8; - uint8_t g = (_rgb565 >> 3) & 0xFC; - uint8_t r = (_rgb565 << 3) & 0xF8; - - uint8_t* r8p = reinterpret_cast(rgb888); - uint8_t* g8p = r8p + 1; - uint8_t* b8p = r8p + 2; - - *r8p = r | ((r >> 3) & 0x7); - *g8p = g | ((g >> 2) & 0x3); - *b8p = b | ((b >> 3) & 0x7); - } -}; \ No newline at end of file diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h b/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h deleted file mode 100644 index 1b4310cf..00000000 --- a/ExternalApps/GraphicsDemo/main/Include/drivers/DisplayDriver.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include - -/** - * Wrapper for tt_hal_display_driver_* - */ -class DisplayDriver { - - DisplayDriverHandle handle = nullptr; - -public: - - explicit DisplayDriver(DeviceId id) { - assert(tt_hal_display_driver_supported(id)); - handle = tt_hal_display_driver_alloc(id); - assert(handle != nullptr); - } - - ~DisplayDriver() { - tt_hal_display_driver_free(handle); - } - - bool lock(TickType timeout = TT_MAX_TICKS) const { - return tt_hal_display_driver_lock(handle, timeout); - } - - void unlock() const { - tt_hal_display_driver_unlock(handle); - } - - uint16_t getWidth() const { - return tt_hal_display_driver_get_pixel_width(handle); - } - - uint16_t getHeight() const { - return tt_hal_display_driver_get_pixel_height(handle); - } - - ColorFormat getColorFormat() const { - return tt_hal_display_driver_get_colorformat(handle); - } - - void drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) const { - tt_hal_display_driver_draw_bitmap(handle, xStart, yStart, xEnd, yEnd, pixelData); - } -}; diff --git a/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h b/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h deleted file mode 100644 index 622f1260..00000000 --- a/ExternalApps/GraphicsDemo/main/Include/drivers/TouchDriver.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include - -/** - * Wrapper for tt_hal_touch_driver_* - */ -class TouchDriver { - - TouchDriverHandle handle = nullptr; - -public: - - explicit TouchDriver(DeviceId id) { - assert(tt_hal_touch_driver_supported(id)); - handle = tt_hal_touch_driver_alloc(id); - assert(handle != nullptr); - } - - ~TouchDriver() { - tt_hal_touch_driver_free(handle); - } - - bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* count, uint8_t maxCount) const { - return tt_hal_touch_driver_get_touched_points(handle, x, y, strength, count, maxCount); - } -}; diff --git a/ExternalApps/GraphicsDemo/main/Source/Application.cpp b/ExternalApps/GraphicsDemo/main/Source/Application.cpp deleted file mode 100644 index 6594cf03..00000000 --- a/ExternalApps/GraphicsDemo/main/Source/Application.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "Application.h" -#include "PixelBuffer.h" -#include "esp_log.h" - -#include - -constexpr auto TAG = "Application"; - -static bool isTouched(TouchDriver* touch) { - uint16_t x, y, strength; - uint8_t pointCount = 0; - return touch->getTouchedPoints(&x, &y, &strength, &pointCount, 1); -} - -void createRgbRow(PixelBuffer& buffer) { - uint8_t offset = buffer.getPixelWidth() / 3; - for (int i = 0; i < buffer.getPixelWidth(); ++i) { - if (i < offset) { - buffer.setPixel(i, 0, 255, 0, 0); - } else if (i < offset * 2) { - buffer.setPixel(i, 0, 0, 255, 0); - } else { - buffer.setPixel(i, 0, 0, 0, 255); - } - } -} - -void createRgbFadingRow(PixelBuffer& buffer) { - uint8_t stroke = buffer.getPixelWidth() / 3; - for (int i = 0; i < buffer.getPixelWidth(); ++i) { - if (i < stroke) { - auto color = i * 255 / stroke; - buffer.setPixel(i, 0, color, 0, 0); - } else if (i < stroke * 2) { - auto color = (i - stroke) * 255 / stroke; - buffer.setPixel(i, 0, 0, color, 0); - } else { - auto color = (i - (2*stroke)) * 255 / stroke; - buffer.setPixel(i, 0, 0, 0, color); - } - } -} - -void runApplication(DisplayDriver* display, TouchDriver* touch) { - // Single row buffers - PixelBuffer line_clear_buffer(display->getWidth(), 1, display->getColorFormat()); - line_clear_buffer.clear(); - PixelBuffer line_buffer(display->getWidth(), 1, display->getColorFormat()); - line_buffer.clear(); - - do { - // Draw row by row - // This is placed in a loop to test the SPI locking mechanismss - for (int i = 0; i < display->getHeight(); i++) { - - if (i == 0) { - createRgbRow(line_buffer); - } else if (i == display->getHeight() / 2) { - createRgbFadingRow(line_buffer); - } - - display->lock(); - display->drawBitmap(0, i, display->getWidth(), i + 1, line_buffer.getData()); - display->unlock(); - } - - // Give other tasks space to breathe - // SPI displays would otherwise time out SPI SD card access - tt_kernel_delay_ticks(1); - } while (!isTouched(touch)); -} - diff --git a/ExternalApps/GraphicsDemo/main/Source/Main.cpp b/ExternalApps/GraphicsDemo/main/Source/Main.cpp deleted file mode 100644 index c8f994cc..00000000 --- a/ExternalApps/GraphicsDemo/main/Source/Main.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "Application.h" -#include "drivers/DisplayDriver.h" -#include "drivers/TouchDriver.h" - -#include - -#include -#include -#include - -constexpr auto TAG = "Main"; - -/** Find a DisplayDevice that supports the DisplayDriver interface */ -static bool findUsableDisplay(DeviceId& deviceId) { - uint16_t display_count = 0; - if (!tt_hal_device_find(DEVICE_TYPE_DISPLAY, &deviceId, &display_count, 1)) { - ESP_LOGE(TAG, "No display device found"); - return false; - } - - if (!tt_hal_display_driver_supported(deviceId)) { - ESP_LOGE(TAG, "Display doesn't support driver mode"); - return false; - } - - return true; -} - -/** Find a TouchDevice that supports the TouchDriver interface */ -static bool findUsableTouch(DeviceId& deviceId) { - uint16_t touch_count = 0; - if (!tt_hal_device_find(DEVICE_TYPE_TOUCH, &deviceId, &touch_count, 1)) { - ESP_LOGE(TAG, "No touch device found"); - return false; - } - - if (!tt_hal_touch_driver_supported(deviceId)) { - ESP_LOGE(TAG, "Touch doesn't support driver mode"); - return false; - } - - return true; -} - -static void onCreate(AppHandle appHandle, void* data) { - DeviceId display_id; - if (!findUsableDisplay(display_id)) { - tt_app_stop(); - tt_app_alertdialog_start("Error", "The display doesn't support the required features.", nullptr, 0); - return; - } - - DeviceId touch_id; - if (!findUsableTouch(touch_id)) { - tt_app_stop(); - tt_app_alertdialog_start("Error", "The touch driver doesn't support the required features.", nullptr, 0); - return; - } - - // Stop LVGL first (because it's currently using the drivers we want to use) - tt_lvgl_stop(); - - ESP_LOGI(TAG, "Creating display driver"); - auto display = new DisplayDriver(display_id); - - ESP_LOGI(TAG, "Creating touch driver"); - auto touch = new TouchDriver(touch_id); - - // Run the main logic - ESP_LOGI(TAG, "Running application"); - runApplication(display, touch); - - ESP_LOGI(TAG, "Cleanup display driver"); - delete display; - - ESP_LOGI(TAG, "Cleanup touch driver"); - delete touch; - - ESP_LOGI(TAG, "Stopping application"); - tt_app_stop(); -} - -static void onDestroy(AppHandle appHandle, void* data) { - // Restart LVGL to resume rendering of regular apps - if (!tt_lvgl_is_started()) { - ESP_LOGI(TAG, "Restarting LVGL"); - tt_lvgl_start(); - } -} - -ExternalAppManifest manifest = { - .onCreate = onCreate, - .onDestroy = onDestroy -}; - -extern "C" { - -int main(int argc, char* argv[]) { - tt_app_register(&manifest); - return 0; -} - -} diff --git a/ExternalApps/GraphicsDemo/manifest.properties b/ExternalApps/GraphicsDemo/manifest.properties deleted file mode 100644 index dc797514..00000000 --- a/ExternalApps/GraphicsDemo/manifest.properties +++ /dev/null @@ -1,10 +0,0 @@ -[manifest] -version=0.1 -[target] -sdk=0.6.0-SNAPSHOT1 -platforms=esp32,esp32s3 -[app] -id=one.tactility.graphicsdemo -versionName=0.1.0 -versionCode=1 -name=Graphics Demo diff --git a/ExternalApps/GraphicsDemo/tactility.py b/ExternalApps/GraphicsDemo/tactility.py deleted file mode 100644 index faa4dfba..00000000 --- a/ExternalApps/GraphicsDemo/tactility.py +++ /dev/null @@ -1,630 +0,0 @@ -import configparser -import json -import os -import re -import shutil -import sys -import subprocess -import time -import urllib.request -import zipfile -import requests -import tarfile -import shutil -import configparser - -ttbuild_path = ".tactility" -ttbuild_version = "2.2.0" -ttbuild_cdn = "https://cdn.tactility.one" -ttbuild_sdk_json_validity = 3600 # seconds -ttport = 6666 -verbose = False -use_local_sdk = False -valid_platforms = ["esp32", "esp32s3"] - -spinner_pattern = [ - "⠋", - "⠙", - "⠹", - "⠸", - "⠼", - "⠴", - "⠦", - "⠧", - "⠇", - "⠏" -] - -if sys.platform == "win32": - shell_color_red = "" - shell_color_orange = "" - shell_color_green = "" - shell_color_purple = "" - shell_color_cyan = "" - shell_color_reset = "" -else: - 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" - -def print_help(): - print("Usage: python tactility.py [action] [options]") - print("") - print("Actions:") - print(" build [esp32,esp32s3] Build the app. Optionally specify a platform.") - print(" esp32: ESP32") - print(" esp32s3: ESP32 S3") - print(" clean Clean the build folders") - print(" clearcache Clear the SDK cache") - print(" updateself Update this tool") - print(" run [ip] Run the application") - print(" install [ip] Install the application") - print(" uninstall [ip] Uninstall the application") - print(" bir [ip] [esp32,esp32s3] Build, install then run. Optionally specify a platform.") - print(" brrr [ip] [esp32,esp32s3] Functionally the same as \"bir\", but \"app goes brrr\" meme variant.") - print("") - print("Options:") - print(" --help Show this commandline info") - print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH") - print(" --skip-build Run everything except the idf.py/CMake commands") - print(" --verbose Show extra console output") - -# region Core - -def download_file(url, filepath): - global verbose - if verbose: - print(f"Downloading from {url} to {filepath}") - request = urllib.request.Request( - url, - data=None, - headers={ - "User-Agent": f"Tactility Build Tool {ttbuild_version}" - } - ) - try: - response = urllib.request.urlopen(request) - file = open(filepath, mode="wb") - file.write(response.read()) - file.close() - return True - except OSError as error: - if verbose: - print_error(f"Failed to fetch URL {url}\n{error}") - return False - -def print_warning(message): - print(f"{shell_color_orange}WARNING: {message}{shell_color_reset}") - -def print_error(message): - print(f"{shell_color_red}ERROR: {message}{shell_color_reset}") - -def exit_with_error(message): - print_error(message) - sys.exit(1) - -def get_url(ip, path): - return f"http://{ip}:{ttport}{path}" - -def read_properties_file(path): - config = configparser.RawConfigParser() - config.read(path) - return config - -#endregion Core - -#region SDK helpers - -def read_sdk_json(): - json_file_path = os.path.join(ttbuild_path, "sdk.json") - json_file = open(json_file_path) - return json.load(json_file) - -def get_sdk_dir(version, platform): - global use_local_sdk - if use_local_sdk: - return os.environ.get("TACTILITY_SDK_PATH") - else: - global ttbuild_cdn - return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK") - -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): - global ttbuild_cdn - return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip" - -def sdk_exists(version, platform): - sdk_dir = get_sdk_dir(version, platform) - return os.path.isdir(sdk_dir) - -def should_update_sdk_json(): - global ttbuild_cdn - json_filepath = os.path.join(ttbuild_path, "sdk.json") - if os.path.exists(json_filepath): - json_modification_time = os.path.getmtime(json_filepath) - now = time.time() - global ttbuild_sdk_json_validity - minimum_seconds_difference = ttbuild_sdk_json_validity - return (now - json_modification_time) > minimum_seconds_difference - else: - return True - -def update_sdk_json(): - global ttbuild_cdn, ttbuild_path - json_url = f"{ttbuild_cdn}/sdk.json" - json_filepath = os.path.join(ttbuild_path, "sdk.json") - return download_file(json_url, json_filepath) - -def should_fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)): - return True - return False - -def fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - target_path = os.path.join(ttbuild_path, sdkconfig_filename) - if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): - exit_with_error(f"Failed to download sdkconfig file for {platform}") - -#endregion SDK helpers - -#region Validation - -def validate_environment(): - if os.environ.get("IDF_PATH") is None: - exit_with_error("Cannot find the Espressif IDF SDK. Ensure it is installed and that it is activated via $PATH_TO_IDF_SDK/export.sh") - if not os.path.exists("manifest.properties"): - exit_with_error("manifest.properties not found") - if use_local_sdk == False and os.environ.get("TACTILITY_SDK_PATH") is not None: - print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command.") - print_warning("If you want to use it, use the 'build local' parameters.") - 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)") - if not "toolCompatibility" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolCompatibility not found)") - if not "toolDownloadUrl" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolDownloadUrl not found)") - tool_version = sdk_json["toolVersion"] - tool_compatibility = sdk_json["toolCompatibility"] - if tool_version != ttbuild_version: - print_warning(f"New version available: {tool_version} (currently using {ttbuild_version})") - print_warning(f"Run 'tactility.py updateself' to update.") - if re.search(tool_compatibility, ttbuild_version) is None: - print_error("The tool is not compatible anymore.") - print_error("Run 'tactility.py updateself' to update.") - sys.exit(1) - -#endregion Validation - -#region Manifest - -def read_manifest(): - return read_properties_file("manifest.properties") - -def validate_manifest(manifest): - # [manifest] - if not "manifest" in manifest: - exit_with_error("Invalid manifest format: [manifest] not found") - if not "version" in manifest["manifest"]: - exit_with_error("Invalid manifest format: [manifest] version not found") - # [target] - if not "target" in manifest: - exit_with_error("Invalid manifest format: [target] not found") - if not "sdk" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] sdk not found") - if not "platforms" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] platforms not found") - # [app] - if not "app" in manifest: - exit_with_error("Invalid manifest format: [app] not found") - if not "id" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] id not found") - if not "versionName" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionName not found") - if not "versionCode" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionCode not found") - if not "name" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] name not found") - -def is_valid_manifest_platform(manifest, platform): - manifest_platforms = manifest["target"]["platforms"].split(",") - return platform in manifest_platforms - -def validate_manifest_platform(manifest, platform): - if not is_valid_manifest_platform(manifest, platform): - exit_with_error(f"Platform {platform} is not available in the manifest.") - -def get_manifest_target_platforms(manifest, requested_platform): - if requested_platform == "" or requested_platform is None: - return manifest["target"]["platforms"].split(",") - else: - validate_manifest_platform(manifest, requested_platform) - return [requested_platform] - -#endregion Manifest - -#region SDK download - -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") - print(f"Downloading SDK version {version} for {platform}") - if download_file(sdk_url, filepath): - with zipfile.ZipFile(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: - if not sdk_exists(version, platform): - if not sdk_download(version, platform): - return False - else: - if verbose: - print(f"Using cached download for SDK version {version} and platform {platform}") - return True - -#endregion SDK download - -#region Building - -def get_cmake_path(platform): - return os.path.join("build", f"cmake-build-{platform}") - -def find_elf_file(platform): - cmake_dir = get_cmake_path(platform) - if os.path.exists(cmake_dir): - for file in os.listdir(cmake_dir): - if file.endswith(".app.elf"): - return os.path.join(cmake_dir, file) - return None - -def build_all(version, platforms, skip_build): - for platform in platforms: - # First build command must be "idf.py build", otherwise it fails to execute "idf.py elf" - # We check if the ELF file exists and run the correct command - # This can lead to code caching issues, so sometimes a clean build is required - if find_elf_file(platform) is None: - if not build_first(version, platform, skip_build): - break - else: - if not build_consecutively(version, platform, skip_build): - break - -def wait_for_build(process, platform): - buffer = [] - os.set_blocking(process.stdout.fileno(), False) - while process.poll() is None: - for i in spinner_pattern: - time.sleep(0.1) - progress_text = f"Building for {platform} {shell_color_cyan}" + str(i) + shell_color_reset - sys.stdout.write(progress_text + "\r") - while True: - line = process.stdout.readline() - decoded_line = line.decode("UTF-8") - if decoded_line != "": - buffer.append(decoded_line) - else: - break - return buffer - -# The first build must call "idf.py build" and consecutive builds must call "idf.py elf" as it finishes faster. -# The problem is that the "idf.py build" always results in an error, even though the elf file is created. -# The solution is to suppress the error if we find that the elf file was created. -def build_first(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - elf_path = find_elf_file(platform) - # Remove previous elf file: re-creation of the file is used to measure if the build succeeded, - # as the actual build job will always fail due to technical issues with the elf cmake script - if elf_path is not None: - os.remove(elf_path) - if skip_build: - return True - print("Building first build") - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - # 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: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - if find_elf_file(platform) is None: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - else: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - -def build_consecutively(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - if skip_build: - return True - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - if process.returncode == 0: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - -#endregion Building - -#region Packaging - -def package_intermediate_manifest(target_path): - if not os.path.isfile("manifest.properties"): - print_error("manifest.properties not found") - return - shutil.copy("manifest.properties", os.path.join(target_path, "manifest.properties")) - -def package_intermediate_binaries(target_path, platforms): - elf_dir = os.path.join(target_path, "elf") - os.makedirs(elf_dir, exist_ok=True) - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - print_error(f"ELF file not found at {elf_path}") - return - shutil.copy(elf_path, os.path.join(elf_dir, f"{platform}.elf")) - -def package_intermediate_assets(target_path): - if os.path.isdir("assets"): - shutil.copytree("assets", os.path.join(target_path, "assets"), dirs_exist_ok=True) - -def package_intermediate(platforms): - target_path = os.path.join("build", "package-intermediate") - if os.path.isdir(target_path): - shutil.rmtree(target_path) - os.makedirs(target_path, exist_ok=True) - package_intermediate_manifest(target_path) - package_intermediate_binaries(target_path, platforms) - package_intermediate_assets(target_path) - -def package_name(platforms): - elf_path = find_elf_file(platforms[0]) - elf_base_name = os.path.basename(elf_path).removesuffix(".app.elf") - return os.path.join("build", f"{elf_base_name}.app") - -def package_all(platforms): - print("Packaging app") - package_intermediate(platforms) - # Create build/something.app - tar_path = package_name(platforms) - tar = tarfile.open(tar_path, mode="w", format=tarfile.USTAR_FORMAT) - tar.add(os.path.join("build", "package-intermediate"), arcname="") - tar.close() - -#endregion Packaging - -def setup_environment(): - global ttbuild_path - os.makedirs(ttbuild_path, exist_ok=True) - -def build_action(manifest, platform_arg): - # Environment validation - validate_environment() - platforms_to_build = get_manifest_target_platforms(manifest, platform_arg) - if not use_local_sdk: - if should_fetch_sdkconfig_files(platforms_to_build): - fetch_sdkconfig_files(platforms_to_build) - 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") - build_all(sdk_version, platforms_to_build, skip_build) # Environment validation - if not skip_build: - package_all(platforms_to_build) - -def clean_action(): - if os.path.exists("build"): - print(f"Removing build/") - shutil.rmtree("build") - else: - print("Nothing to clean") - -def clear_cache_action(): - if os.path.exists(ttbuild_path): - print(f"Removing {ttbuild_path}/") - shutil.rmtree(ttbuild_path) - else: - print("Nothing to clear") - -def update_self_action(): - sdk_json = read_sdk_json() - tool_download_url = sdk_json["toolDownloadUrl"] - if download_file(tool_download_url, "tactility.py"): - print("Updated") - else: - exit_with_error("Update failed") - -def get_device_info(ip): - print(f"Getting device info from {ip}") - url = get_url(ip, "/info") - try: - response = requests.get(url) - if response.status_code != 200: - print_error("Run failed") - else: - print(response.json()) - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def run_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Running {app_id} on {ip}") - url = get_url(ip, "/app/run") - params = {'id': app_id} - try: - response = requests.post(url, params=params) - if response.status_code != 200: - print_error("Run failed") - else: - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def install_action(ip, platforms): - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - exit_with_error(f"ELF file not built for {platform}") - package_path = package_name(platforms) - print(f"Installing {package_path} to {ip}") - url = get_url(ip, "/app/install") - try: - # Prepare multipart form data - with open(package_path, 'rb') as file: - files = { - 'elf': file - } - response = requests.put(url, files=files) - if response.status_code != 200: - print_error("Install failed") - else: - print(f"{shell_color_green}Installation successful ✅{shell_color_reset}") - except requests.RequestException as e: - print_error(f"Installation failed: {e}") - except IOError as e: - print_error(f"File error: {e}") - -def uninstall_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Uninstalling {app_id} on {ip}") - url = get_url(ip, "/app/uninstall") - params = {'id': app_id} - try: - response = requests.put(url, params=params) - if response.status_code != 200: - print_error("Uninstall failed") - else: - print(f"{shell_color_green}Uninstall successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") -#region Main - -if __name__ == "__main__": - print(f"Tactility Build System v{ttbuild_version}") - if "--help" in sys.argv: - print_help() - sys.exit() - # Argument validation - if len(sys.argv) == 1: - print_help() - sys.exit() - action_arg = sys.argv[1] - verbose = "--verbose" in sys.argv - skip_build = "--skip-build" in sys.argv - use_local_sdk = "--local-sdk" in sys.argv - # Environment setup - setup_environment() - if not os.path.isfile("manifest.properties"): - exit_with_error("manifest.properties not found") - 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(): - exit_with_error("Failed to retrieve SDK info") - # Actions - if action_arg == "build": - if len(sys.argv) < 2: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - if len(sys.argv) > 2: - platform = sys.argv[2] - build_action(manifest, platform) - elif action_arg == "clean": - clean_action() - elif action_arg == "clearcache": - clear_cache_action() - elif action_arg == "updateself": - update_self_action() - elif action_arg == "run": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - run_action(manifest, sys.argv[2]) - elif action_arg == "install": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - install_action(sys.argv[2], platforms_to_install) - elif action_arg == "uninstall": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - uninstall_action(manifest, sys.argv[2]) - elif action_arg == "bir" or action_arg == "brrr": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - build_action(manifest, platform) - install_action(sys.argv[2], platforms_to_install) - run_action(manifest, sys.argv[2]) - else: - print_help() - exit_with_error("Unknown commandline parameter") - -#endregion Main diff --git a/ExternalApps/HelloWorld/.gitignore b/ExternalApps/HelloWorld/.gitignore deleted file mode 100644 index eac918a0..00000000 --- a/ExternalApps/HelloWorld/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -.tactility/ diff --git a/ExternalApps/HelloWorld/CMakeLists.txt b/ExternalApps/HelloWorld/CMakeLists.txt deleted file mode 100644 index 95d0cb2e..00000000 --- a/ExternalApps/HelloWorld/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) - -if (DEFINED ENV{TACTILITY_SDK_PATH}) - set(TACTILITY_SDK_PATH $ENV{TACTILITY_SDK_PATH}) -else() - set(TACTILITY_SDK_PATH "../../release/TactilitySDK") - message(WARNING "⚠️ TACTILITY_SDK_PATH environment variable is not set, defaulting to ${TACTILITY_SDK_PATH}") -endif() - -include("${TACTILITY_SDK_PATH}/TactilitySDK.cmake") -set(EXTRA_COMPONENT_DIRS ${TACTILITY_SDK_PATH}) - -project(HelloWorld) -tactility_project(HelloWorld) diff --git a/ExternalApps/HelloWorld/assets/message.txt b/ExternalApps/HelloWorld/assets/message.txt deleted file mode 100644 index af5626b4..00000000 --- a/ExternalApps/HelloWorld/assets/message.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! diff --git a/ExternalApps/HelloWorld/main/CMakeLists.txt b/ExternalApps/HelloWorld/main/CMakeLists.txt deleted file mode 100644 index db2068e9..00000000 --- a/ExternalApps/HelloWorld/main/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -file(GLOB_RECURSE SOURCE_FILES Source/*.c) - -idf_component_register( - SRCS ${SOURCE_FILES} - REQUIRES TactilitySDK -) diff --git a/ExternalApps/HelloWorld/main/Source/main.c b/ExternalApps/HelloWorld/main/Source/main.c deleted file mode 100644 index 4048adea..00000000 --- a/ExternalApps/HelloWorld/main/Source/main.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -/** - * Note: LVGL and Tactility methods need to be exposed manually from TactilityC/Source/tt_init.cpp - * Only C is supported for now (C++ symbols fail to link) - */ -static void onShow(AppHandle app, void* data, lv_obj_t* parent) { - lv_obj_t* toolbar = tt_lvgl_toolbar_create_for_app(parent, app); - lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); - - lv_obj_t* label = lv_label_create(parent); - lv_label_set_text(label, "Hello, world!"); - lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); -} - -ExternalAppManifest manifest = { - .onShow = onShow -}; - -int main(int argc, char* argv[]) { - tt_app_register(&manifest); - return 0; -} diff --git a/ExternalApps/HelloWorld/manifest.properties b/ExternalApps/HelloWorld/manifest.properties deleted file mode 100644 index ba386934..00000000 --- a/ExternalApps/HelloWorld/manifest.properties +++ /dev/null @@ -1,10 +0,0 @@ -[manifest] -version=0.1 -[target] -sdk=0.6.0-SNAPSHOT1 -platforms=esp32,esp32s3 -[app] -id=one.tactility.helloworld -versionName=0.1.0 -versionCode=1 -name=Hello World \ No newline at end of file diff --git a/ExternalApps/HelloWorld/tactility.py b/ExternalApps/HelloWorld/tactility.py deleted file mode 100644 index faa4dfba..00000000 --- a/ExternalApps/HelloWorld/tactility.py +++ /dev/null @@ -1,630 +0,0 @@ -import configparser -import json -import os -import re -import shutil -import sys -import subprocess -import time -import urllib.request -import zipfile -import requests -import tarfile -import shutil -import configparser - -ttbuild_path = ".tactility" -ttbuild_version = "2.2.0" -ttbuild_cdn = "https://cdn.tactility.one" -ttbuild_sdk_json_validity = 3600 # seconds -ttport = 6666 -verbose = False -use_local_sdk = False -valid_platforms = ["esp32", "esp32s3"] - -spinner_pattern = [ - "⠋", - "⠙", - "⠹", - "⠸", - "⠼", - "⠴", - "⠦", - "⠧", - "⠇", - "⠏" -] - -if sys.platform == "win32": - shell_color_red = "" - shell_color_orange = "" - shell_color_green = "" - shell_color_purple = "" - shell_color_cyan = "" - shell_color_reset = "" -else: - 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" - -def print_help(): - print("Usage: python tactility.py [action] [options]") - print("") - print("Actions:") - print(" build [esp32,esp32s3] Build the app. Optionally specify a platform.") - print(" esp32: ESP32") - print(" esp32s3: ESP32 S3") - print(" clean Clean the build folders") - print(" clearcache Clear the SDK cache") - print(" updateself Update this tool") - print(" run [ip] Run the application") - print(" install [ip] Install the application") - print(" uninstall [ip] Uninstall the application") - print(" bir [ip] [esp32,esp32s3] Build, install then run. Optionally specify a platform.") - print(" brrr [ip] [esp32,esp32s3] Functionally the same as \"bir\", but \"app goes brrr\" meme variant.") - print("") - print("Options:") - print(" --help Show this commandline info") - print(" --local-sdk Use SDK specified by environment variable TACTILITY_SDK_PATH") - print(" --skip-build Run everything except the idf.py/CMake commands") - print(" --verbose Show extra console output") - -# region Core - -def download_file(url, filepath): - global verbose - if verbose: - print(f"Downloading from {url} to {filepath}") - request = urllib.request.Request( - url, - data=None, - headers={ - "User-Agent": f"Tactility Build Tool {ttbuild_version}" - } - ) - try: - response = urllib.request.urlopen(request) - file = open(filepath, mode="wb") - file.write(response.read()) - file.close() - return True - except OSError as error: - if verbose: - print_error(f"Failed to fetch URL {url}\n{error}") - return False - -def print_warning(message): - print(f"{shell_color_orange}WARNING: {message}{shell_color_reset}") - -def print_error(message): - print(f"{shell_color_red}ERROR: {message}{shell_color_reset}") - -def exit_with_error(message): - print_error(message) - sys.exit(1) - -def get_url(ip, path): - return f"http://{ip}:{ttport}{path}" - -def read_properties_file(path): - config = configparser.RawConfigParser() - config.read(path) - return config - -#endregion Core - -#region SDK helpers - -def read_sdk_json(): - json_file_path = os.path.join(ttbuild_path, "sdk.json") - json_file = open(json_file_path) - return json.load(json_file) - -def get_sdk_dir(version, platform): - global use_local_sdk - if use_local_sdk: - return os.environ.get("TACTILITY_SDK_PATH") - else: - global ttbuild_cdn - return os.path.join(ttbuild_path, f"{version}-{platform}", "TactilitySDK") - -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): - global ttbuild_cdn - return f"{ttbuild_cdn}/TactilitySDK-{version}-{platform}.zip" - -def sdk_exists(version, platform): - sdk_dir = get_sdk_dir(version, platform) - return os.path.isdir(sdk_dir) - -def should_update_sdk_json(): - global ttbuild_cdn - json_filepath = os.path.join(ttbuild_path, "sdk.json") - if os.path.exists(json_filepath): - json_modification_time = os.path.getmtime(json_filepath) - now = time.time() - global ttbuild_sdk_json_validity - minimum_seconds_difference = ttbuild_sdk_json_validity - return (now - json_modification_time) > minimum_seconds_difference - else: - return True - -def update_sdk_json(): - global ttbuild_cdn, ttbuild_path - json_url = f"{ttbuild_cdn}/sdk.json" - json_filepath = os.path.join(ttbuild_path, "sdk.json") - return download_file(json_url, json_filepath) - -def should_fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - if not os.path.exists(os.path.join(ttbuild_path, sdkconfig_filename)): - return True - return False - -def fetch_sdkconfig_files(platform_targets): - for platform in platform_targets: - sdkconfig_filename = f"sdkconfig.app.{platform}" - target_path = os.path.join(ttbuild_path, sdkconfig_filename) - if not download_file(f"{ttbuild_cdn}/{sdkconfig_filename}", target_path): - exit_with_error(f"Failed to download sdkconfig file for {platform}") - -#endregion SDK helpers - -#region Validation - -def validate_environment(): - if os.environ.get("IDF_PATH") is None: - exit_with_error("Cannot find the Espressif IDF SDK. Ensure it is installed and that it is activated via $PATH_TO_IDF_SDK/export.sh") - if not os.path.exists("manifest.properties"): - exit_with_error("manifest.properties not found") - if use_local_sdk == False and os.environ.get("TACTILITY_SDK_PATH") is not None: - print_warning("TACTILITY_SDK_PATH is set, but will be ignored by this command.") - print_warning("If you want to use it, use the 'build local' parameters.") - 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)") - if not "toolCompatibility" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolCompatibility not found)") - if not "toolDownloadUrl" in sdk_json: - exit_with_error("Server returned invalid SDK data format (toolDownloadUrl not found)") - tool_version = sdk_json["toolVersion"] - tool_compatibility = sdk_json["toolCompatibility"] - if tool_version != ttbuild_version: - print_warning(f"New version available: {tool_version} (currently using {ttbuild_version})") - print_warning(f"Run 'tactility.py updateself' to update.") - if re.search(tool_compatibility, ttbuild_version) is None: - print_error("The tool is not compatible anymore.") - print_error("Run 'tactility.py updateself' to update.") - sys.exit(1) - -#endregion Validation - -#region Manifest - -def read_manifest(): - return read_properties_file("manifest.properties") - -def validate_manifest(manifest): - # [manifest] - if not "manifest" in manifest: - exit_with_error("Invalid manifest format: [manifest] not found") - if not "version" in manifest["manifest"]: - exit_with_error("Invalid manifest format: [manifest] version not found") - # [target] - if not "target" in manifest: - exit_with_error("Invalid manifest format: [target] not found") - if not "sdk" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] sdk not found") - if not "platforms" in manifest["target"]: - exit_with_error("Invalid manifest format: [target] platforms not found") - # [app] - if not "app" in manifest: - exit_with_error("Invalid manifest format: [app] not found") - if not "id" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] id not found") - if not "versionName" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionName not found") - if not "versionCode" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] versionCode not found") - if not "name" in manifest["app"]: - exit_with_error("Invalid manifest format: [app] name not found") - -def is_valid_manifest_platform(manifest, platform): - manifest_platforms = manifest["target"]["platforms"].split(",") - return platform in manifest_platforms - -def validate_manifest_platform(manifest, platform): - if not is_valid_manifest_platform(manifest, platform): - exit_with_error(f"Platform {platform} is not available in the manifest.") - -def get_manifest_target_platforms(manifest, requested_platform): - if requested_platform == "" or requested_platform is None: - return manifest["target"]["platforms"].split(",") - else: - validate_manifest_platform(manifest, requested_platform) - return [requested_platform] - -#endregion Manifest - -#region SDK download - -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") - print(f"Downloading SDK version {version} for {platform}") - if download_file(sdk_url, filepath): - with zipfile.ZipFile(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: - if not sdk_exists(version, platform): - if not sdk_download(version, platform): - return False - else: - if verbose: - print(f"Using cached download for SDK version {version} and platform {platform}") - return True - -#endregion SDK download - -#region Building - -def get_cmake_path(platform): - return os.path.join("build", f"cmake-build-{platform}") - -def find_elf_file(platform): - cmake_dir = get_cmake_path(platform) - if os.path.exists(cmake_dir): - for file in os.listdir(cmake_dir): - if file.endswith(".app.elf"): - return os.path.join(cmake_dir, file) - return None - -def build_all(version, platforms, skip_build): - for platform in platforms: - # First build command must be "idf.py build", otherwise it fails to execute "idf.py elf" - # We check if the ELF file exists and run the correct command - # This can lead to code caching issues, so sometimes a clean build is required - if find_elf_file(platform) is None: - if not build_first(version, platform, skip_build): - break - else: - if not build_consecutively(version, platform, skip_build): - break - -def wait_for_build(process, platform): - buffer = [] - os.set_blocking(process.stdout.fileno(), False) - while process.poll() is None: - for i in spinner_pattern: - time.sleep(0.1) - progress_text = f"Building for {platform} {shell_color_cyan}" + str(i) + shell_color_reset - sys.stdout.write(progress_text + "\r") - while True: - line = process.stdout.readline() - decoded_line = line.decode("UTF-8") - if decoded_line != "": - buffer.append(decoded_line) - else: - break - return buffer - -# The first build must call "idf.py build" and consecutive builds must call "idf.py elf" as it finishes faster. -# The problem is that the "idf.py build" always results in an error, even though the elf file is created. -# The solution is to suppress the error if we find that the elf file was created. -def build_first(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - elf_path = find_elf_file(platform) - # Remove previous elf file: re-creation of the file is used to measure if the build succeeded, - # as the actual build job will always fail due to technical issues with the elf cmake script - if elf_path is not None: - os.remove(elf_path) - if skip_build: - return True - print("Building first build") - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "build"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - # 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: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - if find_elf_file(platform) is None: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - else: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - -def build_consecutively(version, platform, skip_build): - sdk_dir = get_sdk_dir(version, platform) - if verbose: - print(f"Using SDK at {sdk_dir}") - os.environ["TACTILITY_SDK_PATH"] = sdk_dir - sdkconfig_path = os.path.join(ttbuild_path, f"sdkconfig.app.{platform}") - os.system(f"cp {sdkconfig_path} sdkconfig") - if skip_build: - return True - cmake_path = get_cmake_path(platform) - with subprocess.Popen(["idf.py", "-B", cmake_path, "elf"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as process: - build_output = wait_for_build(process, platform) - if process.returncode == 0: - print(f"{shell_color_green}Building for {platform} ✅{shell_color_reset}") - return True - else: - for line in build_output: - print(line, end="") - print(f"{shell_color_red}Building for {platform} failed ❌{shell_color_reset}") - return False - -#endregion Building - -#region Packaging - -def package_intermediate_manifest(target_path): - if not os.path.isfile("manifest.properties"): - print_error("manifest.properties not found") - return - shutil.copy("manifest.properties", os.path.join(target_path, "manifest.properties")) - -def package_intermediate_binaries(target_path, platforms): - elf_dir = os.path.join(target_path, "elf") - os.makedirs(elf_dir, exist_ok=True) - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - print_error(f"ELF file not found at {elf_path}") - return - shutil.copy(elf_path, os.path.join(elf_dir, f"{platform}.elf")) - -def package_intermediate_assets(target_path): - if os.path.isdir("assets"): - shutil.copytree("assets", os.path.join(target_path, "assets"), dirs_exist_ok=True) - -def package_intermediate(platforms): - target_path = os.path.join("build", "package-intermediate") - if os.path.isdir(target_path): - shutil.rmtree(target_path) - os.makedirs(target_path, exist_ok=True) - package_intermediate_manifest(target_path) - package_intermediate_binaries(target_path, platforms) - package_intermediate_assets(target_path) - -def package_name(platforms): - elf_path = find_elf_file(platforms[0]) - elf_base_name = os.path.basename(elf_path).removesuffix(".app.elf") - return os.path.join("build", f"{elf_base_name}.app") - -def package_all(platforms): - print("Packaging app") - package_intermediate(platforms) - # Create build/something.app - tar_path = package_name(platforms) - tar = tarfile.open(tar_path, mode="w", format=tarfile.USTAR_FORMAT) - tar.add(os.path.join("build", "package-intermediate"), arcname="") - tar.close() - -#endregion Packaging - -def setup_environment(): - global ttbuild_path - os.makedirs(ttbuild_path, exist_ok=True) - -def build_action(manifest, platform_arg): - # Environment validation - validate_environment() - platforms_to_build = get_manifest_target_platforms(manifest, platform_arg) - if not use_local_sdk: - if should_fetch_sdkconfig_files(platforms_to_build): - fetch_sdkconfig_files(platforms_to_build) - 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") - build_all(sdk_version, platforms_to_build, skip_build) # Environment validation - if not skip_build: - package_all(platforms_to_build) - -def clean_action(): - if os.path.exists("build"): - print(f"Removing build/") - shutil.rmtree("build") - else: - print("Nothing to clean") - -def clear_cache_action(): - if os.path.exists(ttbuild_path): - print(f"Removing {ttbuild_path}/") - shutil.rmtree(ttbuild_path) - else: - print("Nothing to clear") - -def update_self_action(): - sdk_json = read_sdk_json() - tool_download_url = sdk_json["toolDownloadUrl"] - if download_file(tool_download_url, "tactility.py"): - print("Updated") - else: - exit_with_error("Update failed") - -def get_device_info(ip): - print(f"Getting device info from {ip}") - url = get_url(ip, "/info") - try: - response = requests.get(url) - if response.status_code != 200: - print_error("Run failed") - else: - print(response.json()) - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def run_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Running {app_id} on {ip}") - url = get_url(ip, "/app/run") - params = {'id': app_id} - try: - response = requests.post(url, params=params) - if response.status_code != 200: - print_error("Run failed") - else: - print(f"{shell_color_green}Run successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") - -def install_action(ip, platforms): - for platform in platforms: - elf_path = find_elf_file(platform) - if elf_path is None: - exit_with_error(f"ELF file not built for {platform}") - package_path = package_name(platforms) - print(f"Installing {package_path} to {ip}") - url = get_url(ip, "/app/install") - try: - # Prepare multipart form data - with open(package_path, 'rb') as file: - files = { - 'elf': file - } - response = requests.put(url, files=files) - if response.status_code != 200: - print_error("Install failed") - else: - print(f"{shell_color_green}Installation successful ✅{shell_color_reset}") - except requests.RequestException as e: - print_error(f"Installation failed: {e}") - except IOError as e: - print_error(f"File error: {e}") - -def uninstall_action(manifest, ip): - app_id = manifest["app"]["id"] - print(f"Uninstalling {app_id} on {ip}") - url = get_url(ip, "/app/uninstall") - params = {'id': app_id} - try: - response = requests.put(url, params=params) - if response.status_code != 200: - print_error("Uninstall failed") - else: - print(f"{shell_color_green}Uninstall successful ✅{shell_color_reset}") - except requests.RequestException as e: - print(f"Request failed: {e}") -#region Main - -if __name__ == "__main__": - print(f"Tactility Build System v{ttbuild_version}") - if "--help" in sys.argv: - print_help() - sys.exit() - # Argument validation - if len(sys.argv) == 1: - print_help() - sys.exit() - action_arg = sys.argv[1] - verbose = "--verbose" in sys.argv - skip_build = "--skip-build" in sys.argv - use_local_sdk = "--local-sdk" in sys.argv - # Environment setup - setup_environment() - if not os.path.isfile("manifest.properties"): - exit_with_error("manifest.properties not found") - 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(): - exit_with_error("Failed to retrieve SDK info") - # Actions - if action_arg == "build": - if len(sys.argv) < 2: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - if len(sys.argv) > 2: - platform = sys.argv[2] - build_action(manifest, platform) - elif action_arg == "clean": - clean_action() - elif action_arg == "clearcache": - clear_cache_action() - elif action_arg == "updateself": - update_self_action() - elif action_arg == "run": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - run_action(manifest, sys.argv[2]) - elif action_arg == "install": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - install_action(sys.argv[2], platforms_to_install) - elif action_arg == "uninstall": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - uninstall_action(manifest, sys.argv[2]) - elif action_arg == "bir" or action_arg == "brrr": - if len(sys.argv) < 3: - print_help() - exit_with_error("Commandline parameter missing") - platform = None - platforms_to_install = all_platform_targets - if len(sys.argv) >= 4: - platform = sys.argv[3] - platforms_to_install = [platform] - build_action(manifest, platform) - install_action(sys.argv[2], platforms_to_install) - run_action(manifest, sys.argv[2]) - else: - print_help() - exit_with_error("Unknown commandline parameter") - -#endregion Main diff --git a/Tactility/Source/app/ElfApp.cpp b/Tactility/Source/app/ElfApp.cpp index cae0cf4a..8613f091 100644 --- a/Tactility/Source/app/ElfApp.cpp +++ b/Tactility/Source/app/ElfApp.cpp @@ -91,7 +91,7 @@ private: auto relocate_result = esp_elf_relocate(&elf, elfFileData.get()); if (relocate_result != 0) { - // Note: the result code mapes to values from cstdlib's errno.h + // Note: the result code maps to values from cstdlib's errno.h lastError = getErrorCodeString(-relocate_result); TT_LOG_E(TAG, "Application failed to load: %s", lastError.c_str()); elfFileData = nullptr;