C++ conversions (#111)

* Remove version from artifact name
* Target C++ 20 and higher
* Use cpp string
* Better crash implementation
* String utils in cpp style
* Replace parameter methods with start() method
* MutexType to Mutex::Type
* Kernel c to cpp style
* Cleanup event flag
* More cpp conversions
* Test fixes
* Updated ideas docs
This commit is contained in:
Ken Van Hoeylandt 2024-12-07 12:24:28 +01:00 committed by GitHub
parent d52fe52d96
commit 42e843b463
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 272 additions and 258 deletions

View File

@ -4,9 +4,6 @@ inputs:
board-name: board-name:
description: The name of the board description: The name of the board
required: true required: true
version:
description: The name of the board
required: true
sdkconfig: sdkconfig:
description: The sdkconfig file to build description: The sdkconfig file to build
required: true required: true
@ -32,6 +29,6 @@ runs:
- name: 'Upload Artifact' - name: 'Upload Artifact'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: tactility-${{ inputs.board-name }}-${{ inputs.version }} name: tactility-${{ inputs.board-name }}
path: build/Tactility.bin path: build/Tactility.bin
retention-days: 5 retention-days: 5

View File

@ -12,7 +12,6 @@ jobs:
uses: ./.github/actions/build-firmware uses: ./.github/actions/build-firmware
with: with:
board-name: yellowboard board-name: yellowboard
version: snapshot
sdkconfig: sdkconfig.board.yellow_board sdkconfig: sdkconfig.board.yellow_board
arch: esp32 arch: esp32
lilygo-tdeck: lilygo-tdeck:
@ -23,7 +22,6 @@ jobs:
uses: ./.github/actions/build-firmware uses: ./.github/actions/build-firmware
with: with:
board-name: lilygotdeck board-name: lilygotdeck
version: snapshot
sdkconfig: sdkconfig.board.lilygo_tdeck sdkconfig: sdkconfig.board.lilygo_tdeck
arch: esp32s3 arch: esp32s3
m5stack-core2: m5stack-core2:
@ -34,7 +32,6 @@ jobs:
uses: ./.github/actions/build-firmware uses: ./.github/actions/build-firmware
with: with:
board-name: m5stackcore2 board-name: m5stackcore2
version: snapshot
sdkconfig: sdkconfig.board.m5stack_core2 sdkconfig: sdkconfig.board.m5stack_core2
arch: esp32 arch: esp32
m5stack-cores3: m5stack-cores3:
@ -45,6 +42,5 @@ jobs:
uses: ./.github/actions/build-firmware uses: ./.github/actions/build-firmware
with: with:
board-name: m5stackcores3 board-name: m5stackcores3
version: snapshot
sdkconfig: sdkconfig.board.m5stack_cores3 sdkconfig: sdkconfig.board.m5stack_cores3
arch: esp32s3 arch: esp32s3

View File

@ -22,7 +22,7 @@ void app_main() {
&hello_world_app, &hello_world_app,
}, },
.services = {}, .services = {},
.auto_start_app_id = nullptr .autoStartAppId = nullptr
}; };
tt::run(config); tt::run(config);

View File

@ -3,7 +3,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_lcd_touch_gt911.h" #include "esp_lcd_touch_gt911.h"
#include "Log.h" #include "Log.h"
#include "Kernel.h" #include "kernel/Kernel.h"
#include "esp_lvgl_port.h" #include "esp_lvgl_port.h"
#define TAG "tdeck_touch" #define TAG "tdeck_touch"

View File

@ -11,8 +11,8 @@
#define TAG "lvgl_task" #define TAG "lvgl_task"
// Mutex for LVGL drawing // Mutex for LVGL drawing
static tt::Mutex lvgl_mutex(tt::MutexTypeRecursive); static tt::Mutex lvgl_mutex(tt::Mutex::TypeRecursive);
static tt::Mutex task_mutex(tt::MutexTypeRecursive); static tt::Mutex task_mutex(tt::Mutex::TypeRecursive);
static uint32_t task_max_sleep_ms = 10; static uint32_t task_max_sleep_ms = 10;
// Mutex for LVGL task state (to modify task_running state) // Mutex for LVGL task state (to modify task_running state)

View File

@ -17,7 +17,7 @@ static bool initBoot() {
TT_UNUSED static void deinitPower() { TT_UNUSED static void deinitPower() {
lvgl_task_interrupt(); lvgl_task_interrupt();
while (lvgl_task_is_running()) { while (lvgl_task_is_running()) {
tt::delay_ms(10); tt::kernel::delayMillis(10);
} }
#if LV_ENABLE_GC || !LV_MEM_CUSTOM #if LV_ENABLE_GC || !LV_MEM_CUSTOM

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16)
add_definitions(-DTT_DEBUG) add_definitions(-DTT_DEBUG)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_CXX_COMPILER_TARGET}") set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_CXX_COMPILER_TARGET}")

View File

@ -1,4 +1,6 @@
# TODOs # TODOs
- Gpio: Use Timer instead of Thread
- I2cScannerThread: Use Timer instead of Thread
- Bug: I2C Scanner is on M5Stack devices is broken - Bug: I2C Scanner is on M5Stack devices is broken
- WiFi AP Connect app: add "Forget" option. - WiFi AP Connect app: add "Forget" option.
- T-Deck Plus: Implement battery status - T-Deck Plus: Implement battery status

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (DEFINED ENV{ESP_IDF_VERSION}) if (DEFINED ENV{ESP_IDF_VERSION})

View File

@ -37,7 +37,7 @@ class AppInstance : public AppContext {
private: private:
Mutex mutex = Mutex(MutexTypeNormal); Mutex mutex = Mutex(Mutex::TypeNormal);
const AppManifest& manifest; const AppManifest& manifest;
State state = StateInitial; State state = StateInitial;
Flags flags = { .showStatusbar = true }; Flags flags = { .showStatusbar = true };

View File

@ -143,7 +143,7 @@ struct Loader {
std::shared_ptr<PubSub> pubsub_internal = std::make_shared<PubSub>(); std::shared_ptr<PubSub> pubsub_internal = std::make_shared<PubSub>();
std::shared_ptr<PubSub> pubsub_external = std::make_shared<PubSub>(); std::shared_ptr<PubSub> pubsub_external = std::make_shared<PubSub>();
MessageQueue queue = MessageQueue(2, sizeof(LoaderMessage)); // 2 entries, so you can stop the current app while starting a new one without blocking MessageQueue queue = MessageQueue(2, sizeof(LoaderMessage)); // 2 entries, so you can stop the current app while starting a new one without blocking
Mutex mutex = Mutex(MutexTypeRecursive); Mutex mutex = Mutex(Mutex::TypeRecursive);
std::stack<app::AppInstance*> app_stack; std::stack<app::AppInstance*> app_stack;
}; };

View File

@ -155,9 +155,9 @@ void run(const Configuration& config) {
TT_LOG_I(TAG, "init starting desktop app"); TT_LOG_I(TAG, "init starting desktop app");
service::loader::startApp(app::boot::manifest.id, true); service::loader::startApp(app::boot::manifest.id, true);
if (config.auto_start_app_id) { if (config.autoStartAppId) {
TT_LOG_I(TAG, "init auto-starting %s", config.auto_start_app_id); TT_LOG_I(TAG, "init auto-starting %s", config.autoStartAppId);
service::loader::startApp(config.auto_start_app_id, true); service::loader::startApp(config.autoStartAppId, true);
} }
TT_LOG_I(TAG, "init complete"); TT_LOG_I(TAG, "init complete");

View File

@ -12,7 +12,7 @@ typedef struct {
// List of user applications // List of user applications
const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT]; const app::AppManifest* const apps[TT_CONFIG_APPS_LIMIT];
const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT]; const service::ServiceManifest* const services[TT_CONFIG_SERVICES_LIMIT];
const char* auto_start_app_id; const char* autoStartAppId;
} Configuration; } Configuration;
/** /**

View File

@ -10,7 +10,7 @@ namespace tt::app {
typedef std::unordered_map<std::string, const AppManifest*> AppManifestMap; typedef std::unordered_map<std::string, const AppManifest*> AppManifestMap;
static AppManifestMap app_manifest_map; static AppManifestMap app_manifest_map;
static Mutex hash_mutex(MutexTypeNormal); static Mutex hash_mutex(Mutex::TypeNormal);
void addApp(const AppManifest* manifest) { void addApp(const AppManifest* manifest) {
TT_LOG_I(TAG, "Registering manifest %s", manifest->id.c_str()); TT_LOG_I(TAG, "Registering manifest %s", manifest->id.c_str());

View File

@ -1,13 +1,13 @@
#include <Check.h>
#include <Thread.h>
#include <Kernel.h>
#include "Assets.h" #include "Assets.h"
#include "TactilityCore.h"
#include "app/AppContext.h" #include "app/AppContext.h"
#include "lvgl.h" #include "app/display/DisplaySettings.h"
#include "hal/Display.h" #include "hal/Display.h"
#include "service/loader/Loader.h" #include "service/loader/Loader.h"
#include "lvgl/Style.h" #include "lvgl/Style.h"
#include "app/display/DisplaySettings.h"
#include "lvgl.h"
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "sdkconfig.h" #include "sdkconfig.h"
@ -26,7 +26,7 @@ struct Data {
}; };
static int32_t threadCallback(TT_UNUSED void* context) { static int32_t threadCallback(TT_UNUSED void* context) {
TickType_t start_time = tt::get_ticks(); TickType_t start_time = tt::kernel::getTicks();
auto* lvgl_display = lv_display_get_default(); auto* lvgl_display = lv_display_get_default();
tt_assert(lvgl_display != nullptr); tt_assert(lvgl_display != nullptr);
@ -37,11 +37,11 @@ static int32_t threadCallback(TT_UNUSED void* context) {
hal_display->setBacklightDuty(backlight_duty); hal_display->setBacklightDuty(backlight_duty);
} }
TickType_t end_time = tt::get_ticks(); TickType_t end_time = tt::kernel::getTicks();
TickType_t ticks_passed = end_time - start_time; TickType_t ticks_passed = end_time - start_time;
TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS); TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
if (minimum_ticks > ticks_passed) { if (minimum_ticks > ticks_passed) {
tt::delay_ticks(minimum_ticks - ticks_passed); tt::kernel::delayTicks(minimum_ticks - ticks_passed);
} }
tt::service::loader::stopApp(); tt::service::loader::stopApp();
tt::service::loader::startApp("Desktop"); tt::service::loader::startApp("Desktop");

View File

@ -81,7 +81,7 @@ static void onNavigateUpPressed(TT_UNUSED lv_event_t* event) {
if (strcmp(files_data->current_path, "/") != 0) { if (strcmp(files_data->current_path, "/") != 0) {
TT_LOG_I(TAG, "Navigating upwards"); TT_LOG_I(TAG, "Navigating upwards");
char new_absolute_path[MAX_PATH_LENGTH]; char new_absolute_path[MAX_PATH_LENGTH];
if (string_get_path_parent(files_data->current_path, new_absolute_path)) { if (string::getPathParent(files_data->current_path, new_absolute_path)) {
data_set_entries_for_path(files_data, new_absolute_path); data_set_entries_for_path(files_data, new_absolute_path);
} }
} }
@ -102,7 +102,7 @@ static void viewFile(const char* path, const char* filename) {
// For PC we need to make the path relative to the current work directory, // For PC we need to make the path relative to the current work directory,
// because that's how LVGL maps its 'drive letter' to the file system. // because that's how LVGL maps its 'drive letter' to the file system.
char* processed_filepath; char* processed_filepath;
if (get_platform() == PlatformSimulator) { if (kernel::getPlatform() == kernel::PlatformSimulator) {
char cwd[PATH_MAX]; char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) == nullptr) { if (getcwd(cwd, sizeof(cwd)) == nullptr) {
TT_LOG_E(TAG, "Failed to get current working directory"); TT_LOG_E(TAG, "Failed to get current working directory");
@ -126,7 +126,7 @@ static void viewFile(const char* path, const char* filename) {
service::loader::startApp("ImageViewer", false, bundle); service::loader::startApp("ImageViewer", false, bundle);
} else if (isSupportedTextFile(filename)) { } else if (isSupportedTextFile(filename)) {
auto bundle = std::make_shared<Bundle>(); auto bundle = std::make_shared<Bundle>();
if (get_platform() == PlatformEsp) { if (kernel::getPlatform() == kernel::PlatformEsp) {
bundle->putString(TEXT_VIEWER_FILE_ARGUMENT, processed_filepath); bundle->putString(TEXT_VIEWER_FILE_ARGUMENT, processed_filepath);
} else { } else {
// Remove forward slash, because we need a relative path // Remove forward slash, because we need a relative path
@ -220,7 +220,7 @@ static void onShow(AppContext& app, lv_obj_t* parent) {
static void onStart(AppContext& app) { static void onStart(AppContext& app) {
auto data = std::make_shared<Data>(); auto data = std::make_shared<Data>();
// PC platform is bound to current work directory because of the LVGL file system mapping // PC platform is bound to current work directory because of the LVGL file system mapping
if (get_platform() == PlatformSimulator) { if (kernel::getPlatform() == kernel::PlatformSimulator) {
char cwd[PATH_MAX]; char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != nullptr) { if (getcwd(cwd, sizeof(cwd)) != nullptr) {
data_set_entries_for_path(data, cwd); data_set_entries_for_path(data, cwd);

View File

@ -42,7 +42,7 @@ bool data_set_entries_for_path(std::shared_ptr<Data> data, const char* path) {
* ESP32 does not have a root directory, so we have to create it manually. * ESP32 does not have a root directory, so we have to create it manually.
* We'll add the NVS Flash partitions and the binding for the sdcard. * We'll add the NVS Flash partitions and the binding for the sdcard.
*/ */
if (get_platform() == PlatformEsp && strcmp(path, "/") == 0) { if (kernel::getPlatform() == kernel::PlatformEsp && strcmp(path, "/") == 0) {
int dir_entries_count = 3; int dir_entries_count = 3;
auto** dir_entries = static_cast<dirent**>(malloc(sizeof(struct dirent*) * 3)); auto** dir_entries = static_cast<dirent**>(malloc(sizeof(struct dirent*) * 3));

View File

@ -91,7 +91,7 @@ static int32_t taskMain(void* context) {
bool interrupted = false; bool interrupted = false;
while (!interrupted) { while (!interrupted) {
delay_ms(100); kernel::delayMillis(100);
gpio->updatePinStates(); gpio->updatePinStates();
gpio->updatePinWidgets(); gpio->updatePinWidgets();

View File

@ -27,7 +27,7 @@ std::string getPortNamesForDropdown() {
} }
port_index++; port_index++;
} }
return string_join(config_names, "\n"); return string::join(config_names, "\n");
} }
} }

View File

@ -19,7 +19,7 @@ enum ScanState {
struct Data { struct Data {
// Core // Core
Mutex mutex = Mutex(MutexTypeRecursive); Mutex mutex = Mutex(Mutex::TypeRecursive);
Thread* _Nullable scanThread = nullptr; Thread* _Nullable scanThread = nullptr;
// State // State
ScanState scanState; ScanState scanState;

View File

@ -41,7 +41,7 @@ static void updateUi(std::shared_ptr<Data> data) {
uint16_t charge_level_scaled = (int16_t)charge_level * 100 / 255; uint16_t charge_level_scaled = (int16_t)charge_level * 100 / 255;
int32_t current = data->power->getCurrent(); int32_t current = data->power->getCurrent();
lvgl::lock(ms_to_ticks(1000)); lvgl::lock(kernel::millisToTicks(1000));
lv_obj_set_state(data->enable_switch, LV_STATE_CHECKED, charging_enabled); lv_obj_set_state(data->enable_switch, LV_STATE_CHECKED, charging_enabled);
lv_label_set_text_fmt(data->charge_state, "Charging: %s", charge_state); lv_label_set_text_fmt(data->charge_state, "Charging: %s", charge_state);
lv_label_set_text_fmt(data->charge_level, "Charge level: %d%%", charge_level_scaled); lv_label_set_text_fmt(data->charge_level, "Charge level: %d%%", charge_level_scaled);
@ -110,7 +110,7 @@ static void onShow(AppContext& app, lv_obj_t* parent) {
data->current = lv_label_create(wrapper); data->current = lv_label_create(wrapper);
updateUi(data); updateUi(data);
data->update_timer->start(ms_to_ticks(1000)); data->update_timer->start(kernel::millisToTicks(1000));
} }
static void onHide(TT_UNUSED AppContext& app) { static void onHide(TT_UNUSED AppContext& app) {

View File

@ -124,7 +124,7 @@ static void create_path_ui(std::shared_ptr<ScreenshotUi> ui, lv_obj_t* parent) {
lv_textarea_set_one_line(path_textarea, true); lv_textarea_set_one_line(path_textarea, true);
lv_obj_set_flex_grow(path_textarea, 1); lv_obj_set_flex_grow(path_textarea, 1);
ui->path_textarea = path_textarea; ui->path_textarea = path_textarea;
if (get_platform() == PlatformEsp) { if (kernel::getPlatform() == kernel::PlatformEsp) {
if (hal::sdcard::getState() == hal::sdcard::StateMounted) { if (hal::sdcard::getState() == hal::sdcard::StateMounted) {
lv_textarea_set_text(path_textarea, "A:/sdcard"); lv_textarea_set_text(path_textarea, "A:/sdcard");
} else { } else {

View File

@ -16,9 +16,14 @@ namespace tt::app::selectiondialog {
#define TAG "selection_dialog" #define TAG "selection_dialog"
void setItemsParameter(Bundle& bundle, const std::vector<std::string>& items) { extern const AppManifest manifest;
std::string result = string_join(items, PARAMETER_ITEM_CONCATENATION_TOKEN);
bundle.putString(PARAMETER_BUNDLE_KEY_ITEMS, result); void start(std::string title, const std::vector<std::string>& items) {
std::string items_joined = string::join(items, PARAMETER_ITEM_CONCATENATION_TOKEN);
auto bundle = std::make_shared<Bundle>();
bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title);
bundle->putString(PARAMETER_BUNDLE_KEY_ITEMS, items_joined);
service::loader::startApp(manifest.id, false, bundle);
} }
int32_t getResultIndex(const Bundle& bundle) { int32_t getResultIndex(const Bundle& bundle) {
@ -31,10 +36,6 @@ void setResultIndex(std::shared_ptr<Bundle> bundle, int32_t index) {
bundle->putInt32(RESULT_BUNDLE_KEY_INDEX, index); bundle->putInt32(RESULT_BUNDLE_KEY_INDEX, index);
} }
void setTitleParameter(std::shared_ptr<Bundle> bundle, const std::string& title) {
bundle->putString(PARAMETER_BUNDLE_KEY_TITLE, title);
}
static std::string getTitleParameter(std::shared_ptr<const Bundle> bundle) { static std::string getTitleParameter(std::shared_ptr<const Bundle> bundle) {
std::string result; std::string result;
if (bundle->optString(PARAMETER_BUNDLE_KEY_TITLE, result)) { if (bundle->optString(PARAMETER_BUNDLE_KEY_TITLE, result)) {
@ -76,7 +77,7 @@ static void onShow(AppContext& app, lv_obj_t* parent) {
tt_check(parameters != nullptr, "Parameters missing"); tt_check(parameters != nullptr, "Parameters missing");
std::string items_concatenated; std::string items_concatenated;
if (parameters->optString(PARAMETER_BUNDLE_KEY_ITEMS, items_concatenated)) { if (parameters->optString(PARAMETER_BUNDLE_KEY_ITEMS, items_concatenated)) {
std::vector<std::string> items = string_split(items_concatenated, PARAMETER_ITEM_CONCATENATION_TOKEN); std::vector<std::string> items = string::split(items_concatenated, PARAMETER_ITEM_CONCATENATION_TOKEN);
if (items.empty() || items.front().empty()) { if (items.empty() || items.front().empty()) {
TT_LOG_E(TAG, "No items provided"); TT_LOG_E(TAG, "No items provided");
app.setResult(ResultError); app.setResult(ResultError);

View File

@ -14,10 +14,7 @@
*/ */
namespace tt::app::selectiondialog { namespace tt::app::selectiondialog {
/** App startup parameters */ void start(std::string title, const std::vector<std::string>& items);
void setTitleParameter(Bundle& bundle, const std::string& title);
void setItemsParameter(Bundle& bundle, const std::vector<std::string>& items);
/** App result data */ /** App result data */

View File

@ -10,7 +10,7 @@ namespace tt::app::wifimanage {
*/ */
class State { class State {
Mutex mutex = Mutex(MutexTypeRecursive); Mutex mutex = Mutex(Mutex::TypeRecursive);
bool scanning; bool scanning;
service::wifi::WifiRadioState radioState; service::wifi::WifiRadioState radioState;
std::vector<service::wifi::WifiApRecord> apRecords; std::vector<service::wifi::WifiApRecord> apRecords;

View File

@ -39,7 +39,7 @@ typedef struct {
} Statusbar; } Statusbar;
static void statusbar_init() { static void statusbar_init() {
statusbar_data.mutex = tt_mutex_alloc(MutexTypeRecursive); statusbar_data.mutex = tt_mutex_alloc(Mutex::TypeRecursive);
statusbar_data.pubsub = std::make_shared<PubSub>(); statusbar_data.pubsub = std::make_shared<PubSub>();
for (int i = 0; i < STATUSBAR_ICON_LIMIT; i++) { for (int i = 0; i < STATUSBAR_ICON_LIMIT; i++) {
statusbar_data.icons[i].image = nullptr; statusbar_data.icons[i].image = nullptr;
@ -83,7 +83,7 @@ static const lv_obj_class_t statusbar_class = {
static void statusbar_pubsub_event(TT_UNUSED const void* message, void* obj) { static void statusbar_pubsub_event(TT_UNUSED const void* message, void* obj) {
TT_LOG_I(TAG, "event"); TT_LOG_I(TAG, "event");
auto* statusbar = static_cast<Statusbar*>(obj); auto* statusbar = static_cast<Statusbar*>(obj);
if (lock(ms_to_ticks(100))) { if (lock(kernel::millisToTicks(100))) {
update_main(statusbar); update_main(statusbar);
lv_obj_invalidate(&statusbar->obj); lv_obj_invalidate(&statusbar->obj);
unlock(); unlock();

View File

@ -36,7 +36,7 @@ Gui* gui_alloc() {
&gui_main, &gui_main,
nullptr nullptr
); );
instance->mutex = tt_mutex_alloc(MutexTypeRecursive); instance->mutex = tt_mutex_alloc(Mutex::TypeRecursive);
instance->keyboard = nullptr; instance->keyboard = nullptr;
instance->loader_pubsub_subscription = tt_pubsub_subscribe(loader::getPubsub(), &loader_callback, instance); instance->loader_pubsub_subscription = tt_pubsub_subscribe(loader::getPubsub(), &loader_callback, instance);
tt_check(lvgl::lock(1000 / portTICK_PERIOD_MS)); tt_check(lvgl::lock(1000 / portTICK_PERIOD_MS));

View File

@ -16,6 +16,7 @@
namespace tt::service::loader { namespace tt::service::loader {
#define TAG "loader" #define TAG "loader"
#define LOADER_EVENT_FLAG 1
typedef struct { typedef struct {
LoaderEventType type; LoaderEventType type;
@ -77,7 +78,7 @@ LoaderStatus startApp(const std::string& id, bool blocking, std::shared_ptr<cons
/* TODO: Check if task id is not the LVGL one, /* TODO: Check if task id is not the LVGL one,
because otherwise this fails as the apps starting logic will try to lock lvgl because otherwise this fails as the apps starting logic will try to lock lvgl
to update the UI and fail. */ to update the UI and fail. */
event_flag->wait(TT_API_LOCK_EVENT); event_flag->wait(LOADER_EVENT_FLAG);
delete event_flag; delete event_flag;
} }
@ -330,7 +331,7 @@ static int32_t loader_main(TT_UNUSED void* parameter) {
message.payload.start->parameters message.payload.start->parameters
); );
if (message.api_lock != nullptr) { if (message.api_lock != nullptr) {
message.api_lock->set(TT_API_LOCK_EVENT); message.api_lock->set(LOADER_EVENT_FLAG);
} }
message.cleanup(); message.cleanup();
break; break;

View File

@ -43,7 +43,7 @@ ScreenshotTask* alloc() {
auto* data = static_cast<ScreenshotTaskData*>(malloc(sizeof(ScreenshotTaskData))); auto* data = static_cast<ScreenshotTaskData*>(malloc(sizeof(ScreenshotTaskData)));
*data = (ScreenshotTaskData) { *data = (ScreenshotTaskData) {
.thread = nullptr, .thread = nullptr,
.mutex = tt_mutex_alloc(MutexTypeRecursive), .mutex = tt_mutex_alloc(Mutex::TypeRecursive),
.interrupted = false .interrupted = false
}; };
return data; return data;
@ -76,7 +76,7 @@ static int32_t screenshot_task(void* context) {
if (data->work.type == TASK_WORK_TYPE_DELAY) { if (data->work.type == TASK_WORK_TYPE_DELAY) {
// Splitting up the delays makes it easier to stop the service // Splitting up the delays makes it easier to stop the service
for (int i = 0; i < (data->work.delay_in_seconds * 10) && !is_interrupted(data); ++i){ for (int i = 0; i < (data->work.delay_in_seconds * 10) && !is_interrupted(data); ++i){
delay_ms(100); kernel::delayMillis(100);
} }
if (is_interrupted(data)) { if (is_interrupted(data)) {
@ -102,7 +102,7 @@ static int32_t screenshot_task(void* context) {
if (app) { if (app) {
const app::AppManifest& manifest = app->getManifest(); const app::AppManifest& manifest = app->getManifest();
if (manifest.id != last_app_id) { if (manifest.id != last_app_id) {
delay_ms(100); kernel::delayMillis(100);
last_app_id = manifest.id; last_app_id = manifest.id;
char filename[SCREENSHOT_PATH_LIMIT + 32]; char filename[SCREENSHOT_PATH_LIMIT + 32];
@ -116,7 +116,7 @@ static int32_t screenshot_task(void* context) {
lvgl::unlock(); lvgl::unlock();
} }
} }
delay_ms(250); kernel::delayMillis(250);
} }
} }

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
file(GLOB_RECURSE SOURCES "Source/*.c*") file(GLOB_RECURSE SOURCES "Source/*.c*")

View File

@ -23,7 +23,7 @@ private:
} Type; } Type;
typedef struct { typedef struct {
const char* key; std::string key;
Type type; Type type;
union { union {
bool value_bool; bool value_bool;

View File

@ -1,12 +1,11 @@
#include "Check.h" #include "Check.h"
#include "CoreDefines.h"
#include "Log.h" #include "Log.h"
#include "RtosCompatTask.h" #include "RtosCompatTask.h"
#define TAG "kernel" #define TAG "kernel"
static void tt_print_memory_info() { static void logMemoryInfo() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
TT_LOG_E(TAG, "default caps:"); TT_LOG_E(TAG, "default caps:");
TT_LOG_E(TAG, " total: %u", heap_caps_get_total_size(MALLOC_CAP_DEFAULT)); TT_LOG_E(TAG, " total: %u", heap_caps_get_total_size(MALLOC_CAP_DEFAULT));
@ -19,19 +18,23 @@ static void tt_print_memory_info() {
#endif #endif
} }
static void tt_print_task_info() { static void logTaskInfo() {
const char* name = pcTaskGetName(nullptr); const char* name = pcTaskGetName(nullptr);
const char* safe_name = name ? name : "main"; const char* safe_name = name ? name : "main";
TT_LOG_E(TAG, "Task: %s", safe_name); TT_LOG_E(TAG, "Task: %s", safe_name);
TT_LOG_E(TAG, "Stack watermark: %u", uxTaskGetStackHighWaterMark(NULL) * 4); TT_LOG_E(TAG, "Stack watermark: %u", uxTaskGetStackHighWaterMark(NULL) * 4);
} }
TT_NORETURN void tt_crash_implementation() { namespace tt {
tt_print_task_info();
tt_print_memory_info(); TT_NORETURN void _crash() {
logTaskInfo();
logMemoryInfo();
// TODO: Add breakpoint when debugger is attached. // TODO: Add breakpoint when debugger is attached.
#ifdef ESP_TARGET #ifdef ESP_TARGET
esp_system_abort("System halted. Connect debugger for more info."); esp_system_abort("System halted. Connect debugger for more info.");
#endif #endif
__builtin_unreachable(); __builtin_unreachable();
} }
}

View File

@ -15,17 +15,29 @@
#include "Log.h" #include "Log.h"
#include <cassert> #include <cassert>
#include "CoreDefines.h"
#define TT_NORETURN [[noreturn]] #define TT_NORETURN [[noreturn]]
/** Crash system */ /** Crash system */
TT_NORETURN void tt_crash_implementation(); namespace tt {
/**
* Don't call this directly. Use tt_crash() as it will trace info.
*/
TT_NORETURN void _crash();
}
/** Crash system with message. */ /** Crash system with message. */
#define tt_crash(message) \ #define tt_crash(...) TT_ARG_CAT(_tt_crash,TT_ARGCOUNT(__VA_ARGS__))(__VA_ARGS__)
do { \
TT_LOG_E("crash", "%s\n\tat %s:%d", ((message) ? (message) : ""), __FILE__, __LINE__); \ #define _tt_crash0() do { \
tt_crash_implementation(); \ TT_LOG_E("crash", "at %s:%d", __FILE__, __LINE__); \
tt::_crash(); \
} while (0)
#define _tt_crash1(message) do { \
TT_LOG_E("crash", "%s\n\tat %s:%d", message, __FILE__, __LINE__); \
tt::_crash(); \
} while (0) } while (0)
/** Halt system /** Halt system
@ -53,7 +65,7 @@ TT_NORETURN void tt_crash_implementation();
* @param optional message (const char*) * @param optional message (const char*)
*/ */
#define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt_crash_implementation(); } #define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt::_crash(); }
/** Only in debug build: Assert condition and crash if assert failed */ /** Only in debug build: Assert condition and crash if assert failed */
#ifdef TT_DEBUG #ifdef TT_DEBUG

View File

@ -31,3 +31,19 @@
#define TT_IS_ISR() (TT_IS_IRQ_MODE()) #define TT_IS_ISR() (TT_IS_IRQ_MODE())
#define TT_CHECK_RETURN __attribute__((__warn_unused_result__)) #define TT_CHECK_RETURN __attribute__((__warn_unused_result__))
// region Variable arguments support
// Adapted from https://stackoverflow.com/a/78848701/3848666
#define TT_ARG_IGNORE(X)
#define TT_ARG_CAT(X,Y) _TT_ARG_CAT(X,Y)
#define _TT_ARG_CAT(X,Y) X ## Y
#define TT_ARGCOUNT(...) _TT_ARGCOUNT ## __VA_OPT__(1(__VA_ARGS__) TT_ARG_IGNORE) (0)
#define _TT_ARGCOUNT1(X,...) _TT_ARGCOUNT ## __VA_OPT__(2(__VA_ARGS__) TT_ARG_IGNORE) (1)
#define _TT_ARGCOUNT2(X,...) _TT_ARGCOUNT ## __VA_OPT__(3(__VA_ARGS__) TT_ARG_IGNORE) (2)
#define _TT_ARGCOUNT3(X,...) _TT_ARGCOUNT ## __VA_OPT__(4(__VA_ARGS__) TT_ARG_IGNORE) (3)
#define _TT_ARGCOUNT4(X,...) _TT_ARGCOUNT ## __VA_OPT__(5(__VA_ARGS__) TT_ARG_IGNORE) (4)
#define _TT_ARGCOUNT5(X,...) 5
#define _TT_ARGCOUNT(X) X
// endregion

View File

@ -7,7 +7,7 @@ namespace tt {
#define BACKPRESSURE_WARNING_COUNT 100 #define BACKPRESSURE_WARNING_COUNT 100
Dispatcher::Dispatcher() : Dispatcher::Dispatcher() :
mutex(MutexTypeNormal) mutex(Mutex::TypeNormal)
{} {}
Dispatcher::~Dispatcher() { Dispatcher::~Dispatcher() {

View File

@ -5,8 +5,6 @@
namespace tt { namespace tt {
#define TT_API_LOCK_EVENT (1U << 0)
/** /**
* Wrapper for FreeRTOS xEventGroup. * Wrapper for FreeRTOS xEventGroup.
*/ */

View File

@ -1,17 +1,17 @@
#include "MessageQueue.h" #include "MessageQueue.h"
#include "Check.h" #include "Check.h"
#include "Kernel.h" #include "kernel/Kernel.h"
namespace tt { namespace tt {
MessageQueue::MessageQueue(uint32_t msg_count, uint32_t msg_size) { MessageQueue::MessageQueue(uint32_t msg_count, uint32_t msg_size) {
tt_assert((kernel_is_irq() == 0U) && (msg_count > 0U) && (msg_size > 0U)); tt_assert((kernel::isIrq() == 0U) && (msg_count > 0U) && (msg_size > 0U));
queue_handle = xQueueCreate(msg_count, msg_size); queue_handle = xQueueCreate(msg_count, msg_size);
tt_check(queue_handle); tt_check(queue_handle);
} }
MessageQueue::~MessageQueue() { MessageQueue::~MessageQueue() {
tt_assert(kernel_is_irq() == 0U); tt_assert(kernel::isIrq() == 0U);
vQueueDelete(queue_handle); vQueueDelete(queue_handle);
} }
@ -21,7 +21,7 @@ TtStatus MessageQueue::put(const void* msg_ptr, uint32_t timeout) {
stat = TtStatusOk; stat = TtStatusOk;
if (kernel_is_irq() != 0U) { if (kernel::isIrq() != 0U) {
if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout != 0U)) { if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout != 0U)) {
stat = TtStatusErrorParameter; stat = TtStatusErrorParameter;
} else { } else {
@ -57,7 +57,7 @@ TtStatus MessageQueue::get(void* msg_ptr, uint32_t timeout_ticks) {
stat = TtStatusOk; stat = TtStatusOk;
if (kernel_is_irq() != 0U) { if (kernel::isIrq() != 0U) {
if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout_ticks != 0U)) { if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout_ticks != 0U)) {
stat = TtStatusErrorParameter; stat = TtStatusErrorParameter;
} else { } else {
@ -122,7 +122,7 @@ uint32_t MessageQueue::getCount() const {
if (queue_handle == nullptr) { if (queue_handle == nullptr) {
count = 0U; count = 0U;
} else if (kernel_is_irq() != 0U) { } else if (kernel::isIrq() != 0U) {
count = uxQueueMessagesWaitingFromISR(queue_handle); count = uxQueueMessagesWaitingFromISR(queue_handle);
} else { } else {
count = uxQueueMessagesWaiting(queue_handle); count = uxQueueMessagesWaiting(queue_handle);
@ -139,7 +139,7 @@ uint32_t MessageQueue::getSpace() const {
if (mq == nullptr) { if (mq == nullptr) {
space = 0U; space = 0U;
} else if (kernel_is_irq() != 0U) { } else if (kernel::isIrq() != 0U) {
isrm = taskENTER_CRITICAL_FROM_ISR(); isrm = taskENTER_CRITICAL_FROM_ISR();
/* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */ /* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */
@ -157,7 +157,7 @@ uint32_t MessageQueue::getSpace() const {
TtStatus MessageQueue::reset() { TtStatus MessageQueue::reset() {
TtStatus stat; TtStatus stat;
if (kernel_is_irq() != 0U) { if (kernel::isIrq() != 0U) {
stat = TtStatusErrorISR; stat = TtStatusErrorISR;
} else if (queue_handle == nullptr) { } else if (queue_handle == nullptr) {
stat = TtStatusErrorParameter; stat = TtStatusErrorParameter;

View File

@ -22,13 +22,13 @@ namespace tt {
#define tt_mutex_info(mutex, text) #define tt_mutex_info(mutex, text)
#endif #endif
Mutex::Mutex(MutexType type) : type(type) { Mutex::Mutex(Type type) : type(type) {
tt_mutex_info(data, "alloc"); tt_mutex_info(data, "alloc");
switch (type) { switch (type) {
case MutexTypeNormal: case TypeNormal:
semaphore = xSemaphoreCreateMutex(); semaphore = xSemaphoreCreateMutex();
break; break;
case MutexTypeRecursive: case TypeRecursive:
semaphore = xSemaphoreCreateRecursiveMutex(); semaphore = xSemaphoreCreateRecursiveMutex();
break; break;
default: default:
@ -51,7 +51,7 @@ TtStatus Mutex::acquire(uint32_t timeout) const {
tt_mutex_info(mutex, "acquire"); tt_mutex_info(mutex, "acquire");
switch (type) { switch (type) {
case MutexTypeNormal: case TypeNormal:
if (xSemaphoreTake(semaphore, timeout) != pdPASS) { if (xSemaphoreTake(semaphore, timeout) != pdPASS) {
if (timeout != 0U) { if (timeout != 0U) {
return TtStatusErrorTimeout; return TtStatusErrorTimeout;
@ -62,7 +62,7 @@ TtStatus Mutex::acquire(uint32_t timeout) const {
return TtStatusOk; return TtStatusOk;
} }
break; break;
case MutexTypeRecursive: case TypeRecursive:
if (xSemaphoreTakeRecursive(semaphore, timeout) != pdPASS) { if (xSemaphoreTakeRecursive(semaphore, timeout) != pdPASS) {
if (timeout != 0U) { if (timeout != 0U) {
return TtStatusErrorTimeout; return TtStatusErrorTimeout;
@ -84,7 +84,7 @@ TtStatus Mutex::release() const {
tt_mutex_info(mutex, "release"); tt_mutex_info(mutex, "release");
switch (type) { switch (type) {
case MutexTypeNormal: { case TypeNormal: {
if (xSemaphoreGive(semaphore) != pdPASS) { if (xSemaphoreGive(semaphore) != pdPASS) {
return TtStatusErrorResource; return TtStatusErrorResource;
} else { } else {
@ -92,7 +92,7 @@ TtStatus Mutex::release() const {
} }
break; break;
} }
case MutexTypeRecursive: case TypeRecursive:
if (xSemaphoreGiveRecursive(semaphore) != pdPASS) { if (xSemaphoreGiveRecursive(semaphore) != pdPASS) {
return TtStatusErrorResource; return TtStatusErrorResource;
} else { } else {
@ -115,7 +115,7 @@ std::unique_ptr<ScopedMutexUsage> Mutex::scoped() const {
return std::move(std::make_unique<ScopedMutexUsage>(*this)); return std::move(std::make_unique<ScopedMutexUsage>(*this));
} }
Mutex* tt_mutex_alloc(MutexType type) { Mutex* tt_mutex_alloc(Mutex::Type type) {
return new Mutex(type); return new Mutex(type);
} }

View File

@ -14,21 +14,27 @@ namespace tt {
class ScopedMutexUsage; class ScopedMutexUsage;
typedef enum {
MutexTypeNormal,
MutexTypeRecursive,
} MutexType;
/** /**
* Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex * Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex
* Can be used in IRQ mode (within ISR context) * Can be used in IRQ mode (within ISR context)
*/ */
class Mutex { class Mutex {
private:
SemaphoreHandle_t semaphore;
MutexType type;
public: public:
explicit Mutex(MutexType type = MutexTypeNormal);
enum Type {
TypeNormal,
TypeRecursive,
};
private:
SemaphoreHandle_t semaphore;
Type type;
public:
explicit Mutex(Type type = TypeNormal);
~Mutex(); ~Mutex();
TtStatus acquire(uint32_t timeout) const; TtStatus acquire(uint32_t timeout) const;
@ -68,7 +74,7 @@ public:
*/ */
[[deprecated("use class")]] [[deprecated("use class")]]
Mutex* tt_mutex_alloc(MutexType type); Mutex* tt_mutex_alloc(Mutex::Type type);
/** Free Mutex /** Free Mutex
* *

View File

@ -3,9 +3,9 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
namespace tt { namespace tt::string {
int string_find_last_index(const char* text, size_t from_index, char find) { int findLastIndex(const char* text, size_t from_index, char find) {
for (size_t i = from_index; i >= 0; i--) { for (size_t i = from_index; i >= 0; i--) {
if (text[i] == find) { if (text[i] == find) {
return (int)i; return (int)i;
@ -14,8 +14,8 @@ int string_find_last_index(const char* text, size_t from_index, char find) {
return -1; return -1;
} }
bool string_get_path_parent(const char* path, char* output) { bool getPathParent(const char* path, char* output) {
int index = string_find_last_index(path, strlen(path) - 1, '/'); int index = findLastIndex(path, strlen(path) - 1, '/');
if (index == -1) { if (index == -1) {
return false; return false;
} else if (index == 0) { } else if (index == 0) {
@ -29,7 +29,7 @@ bool string_get_path_parent(const char* path, char* output) {
} }
} }
std::vector<std::string> string_split(const std::string&input, const std::string&delimiter) { std::vector<std::string> split(const std::string&input, const std::string&delimiter) {
size_t token_index = 0; size_t token_index = 0;
size_t delimiter_index; size_t delimiter_index;
const size_t delimiter_length = delimiter.length(); const size_t delimiter_length = delimiter.length();
@ -50,7 +50,7 @@ std::vector<std::string> string_split(const std::string&input, const std::string
return result; return result;
} }
std::string string_join(const std::vector<std::string>& input, const std::string& delimiter) { std::string join(const std::vector<std::string>& input, const std::string& delimiter) {
std::stringstream stream; std::stringstream stream;
size_t size = input.size(); size_t size = input.size();

View File

@ -4,7 +4,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace tt { namespace tt::string {
/** /**
* Find the last occurrence of a character. * Find the last occurrence of a character.
@ -13,7 +13,7 @@ namespace tt {
* @param[in] find the character to search for * @param[in] find the character to search for
* @return the index of the found character, or -1 if none found * @return the index of the found character, or -1 if none found
*/ */
int string_find_last_index(const char* text, size_t from_index, char find); int findLastIndex(const char* text, size_t from_index, char find);
/** /**
* Given a filesystem path as input, try and get the parent path. * Given a filesystem path as input, try and get the parent path.
@ -21,7 +21,7 @@ int string_find_last_index(const char* text, size_t from_index, char find);
* @param[out] output an output buffer that is allocated to at least the size of "current" * @param[out] output an output buffer that is allocated to at least the size of "current"
* @return true when successful * @return true when successful
*/ */
bool string_get_path_parent(const char* path, char* output); bool getPathParent(const char* path, char* output);
/** /**
* Splits the provided input into separate pieces with delimiter as separator text. * Splits the provided input into separate pieces with delimiter as separator text.
@ -30,7 +30,7 @@ bool string_get_path_parent(const char* path, char* output);
* @param input the input to split up * @param input the input to split up
* @param delimiter a non-empty string to recognize as separator * @param delimiter a non-empty string to recognize as separator
*/ */
std::vector<std::string> string_split(const std::string& input, const std::string& delimiter); std::vector<std::string> split(const std::string& input, const std::string& delimiter);
/** /**
* Join a set of tokens into a single string, given a delimiter (separator). * Join a set of tokens into a single string, given a delimiter (separator).
@ -40,6 +40,6 @@ std::vector<std::string> string_split(const std::string& input, const std::strin
* @param input the tokens to join together * @param input the tokens to join together
* @param delimiter the separator to join with * @param delimiter the separator to join with
*/ */
std::string string_join(const std::vector<std::string>& input, const std::string& delimiter); std::string join(const std::vector<std::string>& input, const std::string& delimiter);
} // namespace } // namespace

View File

@ -6,7 +6,10 @@
#include "CoreDefines.h" #include "CoreDefines.h"
#include "CoreExtraDefines.h" #include "CoreExtraDefines.h"
#include "CoreTypes.h" #include "CoreTypes.h"
#include "critical/Critical.h"
#include "EventFlag.h" #include "EventFlag.h"
#include "Kernel.h" #include "kernel/Kernel.h"
#include "kernel/critical/Critical.h"
#include "kernel/Kernel.h"
#include "Log.h" #include "Log.h"
#include "Mutex.h"
#include "Thread.h"

View File

@ -3,7 +3,7 @@
#include "Check.h" #include "Check.h"
#include "CoreDefines.h" #include "CoreDefines.h"
#include "Kernel.h" #include "kernel/Kernel.h"
#include "Log.h" #include "Log.h"
namespace tt { namespace tt {
@ -197,7 +197,7 @@ bool Thread::join() {
// If your thread exited, but your app stuck here: some other thread uses // If your thread exited, but your app stuck here: some other thread uses
// all cpu time, which delays kernel from releasing task handle // all cpu time, which delays kernel from releasing task handle
while (data.taskHandle) { while (data.taskHandle) {
delay_ms(10); kernel::delayMillis(10);
} }
return true; return true;

View File

@ -2,7 +2,7 @@
#include <utility> #include <utility>
#include "Check.h" #include "Check.h"
#include "Kernel.h" #include "kernel/Kernel.h"
#include "RtosCompat.h" #include "RtosCompat.h"
namespace tt { namespace tt {
@ -16,7 +16,7 @@ static void timer_callback(TimerHandle_t hTimer) {
} }
Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext) { Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext) {
tt_assert((kernel_is_irq() == 0U) && (callback != nullptr)); tt_assert((kernel::isIrq() == 0U) && (callback != nullptr));
this->callback = callback; this->callback = callback;
this->callbackContext = std::move(callbackContext); this->callbackContext = std::move(callbackContext);
@ -33,12 +33,12 @@ Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext
} }
Timer::~Timer() { Timer::~Timer() {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS); tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS);
} }
TtStatus Timer::start(uint32_t ticks) { TtStatus Timer::start(uint32_t ticks) {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
tt_assert(ticks < portMAX_DELAY); tt_assert(ticks < portMAX_DELAY);
if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS) { if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS) {
@ -49,7 +49,7 @@ TtStatus Timer::start(uint32_t ticks) {
} }
TtStatus Timer::restart(uint32_t ticks) { TtStatus Timer::restart(uint32_t ticks) {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
tt_assert(ticks < portMAX_DELAY); tt_assert(ticks < portMAX_DELAY);
if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS && if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS &&
@ -61,24 +61,24 @@ TtStatus Timer::restart(uint32_t ticks) {
} }
TtStatus Timer::stop() { TtStatus Timer::stop() {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
tt_check(xTimerStop(timerHandle, portMAX_DELAY) == pdPASS); tt_check(xTimerStop(timerHandle, portMAX_DELAY) == pdPASS);
return TtStatusOk; return TtStatusOk;
} }
bool Timer::isRunning() { bool Timer::isRunning() {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
return xTimerIsTimerActive(timerHandle) == pdTRUE; return xTimerIsTimerActive(timerHandle) == pdTRUE;
} }
uint32_t Timer::getExpireTime() { uint32_t Timer::getExpireTime() {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
return (uint32_t)xTimerGetExpiryTime(timerHandle); return (uint32_t)xTimerGetExpiryTime(timerHandle);
} }
void Timer::pendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) { void Timer::pendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) {
BaseType_t ret = pdFAIL; BaseType_t ret = pdFAIL;
if (kernel_is_irq()) { if (kernel::isIrq()) {
ret = xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr); ret = xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr);
} else { } else {
ret = xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever); ret = xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever);
@ -87,7 +87,7 @@ void Timer::pendingCallback(PendingCallback callback, void* callbackContext, uin
} }
void Timer::setThreadPriority(TimerThreadPriority priority) { void Timer::setThreadPriority(TimerThreadPriority priority) {
tt_assert(!kernel_is_irq()); tt_assert(!kernel::isIrq());
TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle(); TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle();
tt_assert(task_handle); // Don't call this method before timer task start tt_assert(task_handle); // Don't call this method before timer task start

View File

@ -4,6 +4,7 @@
#include "Log.h" #include "Log.h"
#include "mbedtls/aes.h" #include "mbedtls/aes.h"
#include <cstring> #include <cstring>
#include <cstdint>
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
#include "esp_cpu.h" #include "esp_cpu.h"
@ -95,7 +96,7 @@ static void get_nvs_key(uint8_t key[32]) {
* @param[out] out output buffer for result of XOR * @param[out] out output buffer for result of XOR
* @param[in] length data length (all buffers must be at least this size) * @param[in] length data length (all buffers must be at least this size)
*/ */
static void xor_key(const uint8_t* in_left, const uint8_t* in_right, uint8_t* out, size_t length) { static void xorKey(const uint8_t* in_left, const uint8_t* in_right, uint8_t* out, size_t length) {
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
out[i] = in_left[i] ^ in_right[i]; out[i] = in_left[i] ^ in_right[i];
} }
@ -105,7 +106,7 @@ static void xor_key(const uint8_t* in_left, const uint8_t* in_right, uint8_t* ou
* Combines a stored key and a hardware key into a single reliable key value. * Combines a stored key and a hardware key into a single reliable key value.
* @param[out] key the key output * @param[out] key the key output
*/ */
static void get_key(uint8_t key[32]) { static void getKey(uint8_t key[32]) {
#if !defined(CONFIG_SECURE_BOOT) || !defined(CONFIG_SECURE_FLASH_ENC_ENABLED) #if !defined(CONFIG_SECURE_BOOT) || !defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
TT_LOG_W(TAG, "Using tt_secure_* code with secure boot and/or flash encryption disabled."); TT_LOG_W(TAG, "Using tt_secure_* code with secure boot and/or flash encryption disabled.");
TT_LOG_W(TAG, "An attacker with physical access to your ESP32 can decrypt your secure data."); TT_LOG_W(TAG, "An attacker with physical access to your ESP32 can decrypt your secure data.");
@ -117,14 +118,14 @@ static void get_key(uint8_t key[32]) {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
get_hardware_key(hardware_key); get_hardware_key(hardware_key);
get_nvs_key(nvs_key); get_nvs_key(nvs_key);
xor_key(hardware_key, nvs_key, key, 32); xorKey(hardware_key, nvs_key, key, 32);
#else #else
TT_LOG_W(TAG, "Using unsafe key for debugging purposes."); TT_LOG_W(TAG, "Using unsafe key for debugging purposes.");
memset(key, 0, 32); memset(key, 0, 32);
#endif #endif
} }
void get_iv_from_data(const void* data, size_t data_length, uint8_t iv[16]) { void getIv(const void* data, size_t data_length, uint8_t iv[16]) {
memset((void*)iv, 0, 16); memset((void*)iv, 0, 16);
uint8_t* data_bytes = (uint8_t*)data; uint8_t* data_bytes = (uint8_t*)data;
for (int i = 0; i < data_length; ++i) { for (int i = 0; i < data_length; ++i) {
@ -133,11 +134,7 @@ void get_iv_from_data(const void* data, size_t data_length, uint8_t iv[16]) {
} }
} }
void get_iv_from_string(const char* input, uint8_t iv[16]) { static int aes256CryptCbc(
get_iv_from_data((const void*)input, strlen(input), iv);
}
static int aes256_crypt_cbc(
const uint8_t key[32], const uint8_t key[32],
int mode, int mode,
size_t length, size_t length,
@ -166,25 +163,25 @@ static int aes256_crypt_cbc(
int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) { int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) {
tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
uint8_t key[32]; uint8_t key[32];
get_key(key); getKey(key);
// TODO: Is this still needed after switching to regular AES functions? // TODO: Is this still needed after switching to regular AES functions?
uint8_t iv_copy[16]; uint8_t iv_copy[16];
memcpy(iv_copy, iv, sizeof(iv_copy)); memcpy(iv_copy, iv, sizeof(iv_copy));
return aes256_crypt_cbc(key, MBEDTLS_AES_ENCRYPT, length, iv_copy, in_data, out_data); return aes256CryptCbc(key, MBEDTLS_AES_ENCRYPT, length, iv_copy, in_data, out_data);
} }
int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) { int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) {
tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256"); tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
uint8_t key[32]; uint8_t key[32];
get_key(key); getKey(key);
// TODO: Is this still needed after switching to regular AES functions? // TODO: Is this still needed after switching to regular AES functions?
uint8_t iv_copy[16]; uint8_t iv_copy[16];
memcpy(iv_copy, iv, sizeof(iv_copy)); memcpy(iv_copy, iv, sizeof(iv_copy));
return aes256_crypt_cbc(key, MBEDTLS_AES_DECRYPT, length, iv_copy, in_data, out_data); return aes256CryptCbc(key, MBEDTLS_AES_DECRYPT, length, iv_copy, in_data, out_data);
} }
} // namespace } // namespace

View File

@ -20,6 +20,7 @@
#include <cstdio> #include <cstdio>
#include <cstdint> #include <cstdint>
#include <string>
namespace tt::crypt { namespace tt::crypt {
@ -29,14 +30,7 @@ namespace tt::crypt {
* @param data_length input data length * @param data_length input data length
* @param iv output IV * @param iv output IV
*/ */
void get_iv_from_data(const void* data, size_t data_length, uint8_t iv[16]); void getIv(const void* data, size_t data_length, uint8_t iv[16]);
/**
* @brief Fills the IV with zeros and then creates an IV based on the input data.
* @param input input text
* @param iv output IV
*/
void get_iv_from_string(const char* input, uint8_t iv[16]);
/** /**
* @brief Encrypt data. * @brief Encrypt data.

View File

@ -1,4 +1,4 @@
#include "Kernel.h" #include "kernel/Kernel.h"
#include "Check.h" #include "Check.h"
#include "CoreDefines.h" #include "CoreDefines.h"
#include "CoreTypes.h" #include "CoreTypes.h"
@ -10,18 +10,18 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
namespace tt { namespace tt::kernel {
bool kernel_is_irq() { bool isIrq() {
return TT_IS_IRQ_MODE(); return TT_IS_IRQ_MODE();
} }
bool kernel_is_running() { bool isRunning() {
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING; return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING;
} }
int32_t kernel_lock() { int32_t lock() {
tt_assert(!kernel_is_irq()); tt_assert(!isIrq());
int32_t lock; int32_t lock;
@ -45,8 +45,8 @@ int32_t kernel_lock() {
return (lock); return (lock);
} }
int32_t kernel_unlock() { int32_t unlock() {
tt_assert(!kernel_is_irq()); tt_assert(!isIrq());
int32_t lock; int32_t lock;
@ -75,8 +75,8 @@ int32_t kernel_unlock() {
return (lock); return (lock);
} }
int32_t kernel_restore_lock(int32_t lock) { int32_t restoreLock(int32_t lock) {
tt_assert(!kernel_is_irq()); tt_assert(!isIrq());
switch (xTaskGetSchedulerState()) { switch (xTaskGetSchedulerState()) {
case taskSCHEDULER_SUSPENDED: case taskSCHEDULER_SUSPENDED:
@ -106,13 +106,13 @@ int32_t kernel_restore_lock(int32_t lock) {
return (lock); return (lock);
} }
uint32_t kernel_get_tick_frequency() { uint32_t getTickFrequency() {
/* Return frequency in hertz */ /* Return frequency in hertz */
return (configTICK_RATE_HZ); return (configTICK_RATE_HZ);
} }
void delay_ticks(TickType_t ticks) { void delayTicks(TickType_t ticks) {
tt_assert(!kernel_is_irq()); tt_assert(!isIrq());
if (ticks == 0U) { if (ticks == 0U) {
taskYIELD(); taskYIELD();
} else { } else {
@ -120,8 +120,8 @@ void delay_ticks(TickType_t ticks) {
} }
} }
TtStatus delay_until_tick(TickType_t tick) { TtStatus delayUntilTick(TickType_t tick) {
tt_assert(!kernel_is_irq()); tt_assert(!isIrq());
TickType_t tcnt, delay; TickType_t tcnt, delay;
TtStatus stat; TtStatus stat;
@ -147,10 +147,10 @@ TtStatus delay_until_tick(TickType_t tick) {
return (stat); return (stat);
} }
TickType_t get_ticks() { TickType_t getTicks() {
TickType_t ticks; TickType_t ticks;
if (kernel_is_irq() != 0U) { if (isIrq() != 0U) {
ticks = xTaskGetTickCountFromISR(); ticks = xTaskGetTickCountFromISR();
} else { } else {
ticks = xTaskGetTickCount(); ticks = xTaskGetTickCount();
@ -159,7 +159,7 @@ TickType_t get_ticks() {
return ticks; return ticks;
} }
TickType_t ms_to_ticks(uint32_t milliseconds) { TickType_t millisToTicks(uint32_t milliseconds) {
#if configTICK_RATE_HZ == 1000 #if configTICK_RATE_HZ == 1000
return (TickType_t)milliseconds; return (TickType_t)milliseconds;
#else #else
@ -167,7 +167,7 @@ TickType_t ms_to_ticks(uint32_t milliseconds) {
#endif #endif
} }
void delay_ms(uint32_t milliseconds) { void delayMillis(uint32_t milliseconds) {
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) { if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
if (milliseconds > 0 && milliseconds < portMAX_DELAY - 1) { if (milliseconds > 0 && milliseconds < portMAX_DELAY - 1) {
milliseconds += 1; milliseconds += 1;
@ -175,14 +175,14 @@ void delay_ms(uint32_t milliseconds) {
#if configTICK_RATE_HZ_RAW == 1000 #if configTICK_RATE_HZ_RAW == 1000
tt_delay_tick(milliseconds); tt_delay_tick(milliseconds);
#else #else
delay_ticks(ms_to_ticks(milliseconds)); delayTicks(kernel::millisToTicks(milliseconds));
#endif #endif
} else if (milliseconds > 0) { } else if (milliseconds > 0) {
delay_us(milliseconds * 1000); kernel::delayMicros(milliseconds * 1000);
} }
} }
void delay_us(uint32_t microseconds) { void delayMicros(uint32_t microseconds) {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
ets_delay_us(microseconds); ets_delay_us(microseconds);
#else #else
@ -190,7 +190,7 @@ void delay_us(uint32_t microseconds) {
#endif #endif
} }
Platform get_platform() { Platform getPlatform() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
return PlatformEsp; return PlatformEsp;
#else #else

View File

@ -8,7 +8,7 @@
#include "FreeRTOS.h" #include "FreeRTOS.h"
#endif #endif
namespace tt { namespace tt::kernel {
typedef enum { typedef enum {
PlatformEsp, PlatformEsp,
@ -30,13 +30,13 @@ typedef enum {
* *
* @return true if CPU is in IRQ or kernel running and IRQ is masked * @return true if CPU is in IRQ or kernel running and IRQ is masked
*/ */
bool kernel_is_irq(); bool isIrq();
/** Check if kernel is running /** Check if kernel is running
* *
* @return true if running, false otherwise * @return true if running, false otherwise
*/ */
bool kernel_is_running(); bool isRunning();
/** Lock kernel, pause process scheduling /** Lock kernel, pause process scheduling
* *
@ -44,7 +44,7 @@ bool kernel_is_running();
* *
* @return previous lock state(0 - unlocked, 1 - locked) * @return previous lock state(0 - unlocked, 1 - locked)
*/ */
int32_t kernel_lock(); int32_t lock();
/** Unlock kernel, resume process scheduling /** Unlock kernel, resume process scheduling
* *
@ -52,7 +52,7 @@ int32_t kernel_lock();
* *
* @return previous lock state(0 - unlocked, 1 - locked) * @return previous lock state(0 - unlocked, 1 - locked)
*/ */
int32_t kernel_unlock(); int32_t unlock();
/** Restore kernel lock state /** Restore kernel lock state
* *
@ -62,15 +62,15 @@ int32_t kernel_unlock();
* *
* @return new lock state or error * @return new lock state or error
*/ */
int32_t kernel_restore_lock(int32_t lock); int32_t restoreLock(int32_t lock);
/** Get kernel systick frequency /** Get kernel systick frequency
* *
* @return systick counts per second * @return systick counts per second
*/ */
uint32_t kernel_get_tick_frequency(); uint32_t getTickFrequency();
TickType_t get_ticks(); TickType_t getTicks();
/** Delay execution /** Delay execution
* *
@ -80,7 +80,7 @@ TickType_t get_ticks();
* *
* @param[in] ticks The ticks count to pause * @param[in] ticks The ticks count to pause
*/ */
void delay_ticks(TickType_t ticks); void delayTicks(TickType_t ticks);
/** Delay until tick /** Delay until tick
* *
@ -90,14 +90,14 @@ void delay_ticks(TickType_t ticks);
* *
* @return The status. * @return The status.
*/ */
TtStatus delay_until_tick(uint32_t tick); TtStatus delayUntilTick(uint32_t tick);
/** Convert milliseconds to ticks /** Convert milliseconds to ticks
* *
* @param[in] milliseconds time in milliseconds * @param[in] milliSeconds time in milliseconds
* @return time in ticks * @return time in ticks
*/ */
TickType_t ms_to_ticks(uint32_t milliseconds); TickType_t millisToTicks(uint32_t milliSeconds);
/** Delay in milliseconds /** Delay in milliseconds
* *
@ -108,18 +108,18 @@ TickType_t ms_to_ticks(uint32_t milliseconds);
* *
* @warning Cannot be used from ISR * @warning Cannot be used from ISR
* *
* @param[in] milliseconds milliseconds to wait * @param[in] milliSeconds milliseconds to wait
*/ */
void delay_ms(uint32_t milliseconds); void delayMillis(uint32_t milliSeconds);
/** Delay in microseconds /** Delay in microseconds
* *
* Implemented using Cortex DWT counter. Blocking and non aliased. * Implemented using Cortex DWT counter. Blocking and non aliased.
* *
* @param[in] microseconds microseconds to wait * @param[in] microSeconds microseconds to wait
*/ */
void delay_us(uint32_t microseconds); void delayMicros(uint32_t microSeconds);
Platform get_platform(); Platform getPlatform();
} // namespace } // namespace

View File

@ -9,18 +9,18 @@ static portMUX_TYPE critical_mutex;
#define TT_ENTER_CRITICAL() taskENTER_CRITICAL() #define TT_ENTER_CRITICAL() taskENTER_CRITICAL()
#endif #endif
namespace tt::critical { namespace tt::kernel::critical {
TtCriticalInfo enter() { TtCriticalInfo enter() {
TtCriticalInfo info; TtCriticalInfo info = {
.isrm = 0,
.fromIsr = TT_IS_ISR(),
.kernelRunning = (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
};
info.isrm = 0; if (info.fromIsr) {
info.from_isr = TT_IS_ISR();
info.kernel_running = (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING);
if (info.from_isr) {
info.isrm = taskENTER_CRITICAL_FROM_ISR(); info.isrm = taskENTER_CRITICAL_FROM_ISR();
} else if (info.kernel_running) { } else if (info.kernelRunning) {
TT_ENTER_CRITICAL(); TT_ENTER_CRITICAL();
} else { } else {
portDISABLE_INTERRUPTS(); portDISABLE_INTERRUPTS();
@ -30,9 +30,9 @@ TtCriticalInfo enter() {
} }
void exit(TtCriticalInfo info) { void exit(TtCriticalInfo info) {
if (info.from_isr) { if (info.fromIsr) {
taskEXIT_CRITICAL_FROM_ISR(info.isrm); taskEXIT_CRITICAL_FROM_ISR(info.isrm);
} else if (info.kernel_running) { } else if (info.kernelRunning) {
TT_ENTER_CRITICAL(); TT_ENTER_CRITICAL();
} else { } else {
portENABLE_INTERRUPTS(); portENABLE_INTERRUPTS();

View File

@ -10,12 +10,12 @@
#define TT_CRITICAL_EXIT() __tt_critical_exit(__tt_critical_info); #define TT_CRITICAL_EXIT() __tt_critical_exit(__tt_critical_info);
#endif #endif
namespace tt::critical { namespace tt::kernel::critical {
typedef struct { typedef struct {
uint32_t isrm; uint32_t isrm;
bool from_isr; bool fromIsr;
bool kernel_running; bool kernelRunning;
} TtCriticalInfo; } TtCriticalInfo;
TtCriticalInfo enter(); TtCriticalInfo enter();

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (DEFINED ENV{ESP_IDF_VERSION}) if (DEFINED ENV{ESP_IDF_VERSION})

View File

@ -8,7 +8,7 @@ class ServiceInstance : public ServiceContext {
private: private:
Mutex mutex = Mutex(MutexTypeNormal); Mutex mutex = Mutex(Mutex::TypeNormal);
const service::ServiceManifest& manifest; const service::ServiceManifest& manifest;
std::shared_ptr<void> data = nullptr; std::shared_ptr<void> data = nullptr;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "TactilityCore.h"
#include "hal/Configuration.h" #include "hal/Configuration.h"
#include "TactilityHeadlessConfig.h" #include "TactilityHeadlessConfig.h"
#include "Dispatcher.h" #include "Dispatcher.h"

View File

@ -3,10 +3,8 @@
/** /**
* This code is based on i2c_manager from https://github.com/ropg/i2c_manager/blob/master/i2c_manager/i2c_manager.c (original has MIT license) * This code is based on i2c_manager from https://github.com/ropg/i2c_manager/blob/master/i2c_manager/i2c_manager.c (original has MIT license)
*/ */
#include <Kernel.h> #include "TactilityCore.h"
#include "I2c.h" #include "I2c.h"
#include "Log.h"
#include "Mutex.h"
namespace tt::hal::i2c { namespace tt::hal::i2c {

View File

@ -7,7 +7,7 @@ namespace tt::hal::sdcard {
#define TAG "sdcard" #define TAG "sdcard"
static Mutex mutex(MutexTypeRecursive); static Mutex mutex(Mutex::TypeRecursive);
typedef struct { typedef struct {
const SdCard* sdcard; const SdCard* sdcard;

View File

@ -17,8 +17,8 @@ typedef std::unordered_map<std::string, ServiceInstance*> ServiceInstanceMap;
static ManifestMap service_manifest_map; static ManifestMap service_manifest_map;
static ServiceInstanceMap service_instance_map; static ServiceInstanceMap service_instance_map;
static Mutex manifest_mutex(MutexTypeNormal); static Mutex manifest_mutex(Mutex::TypeNormal);
static Mutex instance_mutex(MutexTypeNormal); static Mutex instance_mutex(Mutex::TypeNormal);
void addService(const ServiceManifest* manifest) { void addService(const ServiceManifest* manifest) {
TT_LOG_I(TAG, "Adding %s", manifest->id.c_str()); TT_LOG_I(TAG, "Adding %s", manifest->id.c_str());

View File

@ -42,7 +42,7 @@ static void onUpdate(std::shared_ptr<void> context) {
if (new_state == hal::sdcard::StateError) { if (new_state == hal::sdcard::StateError) {
TT_LOG_W(TAG, "Sdcard error - unmounting. Did you eject the card in an unsafe manner?"); TT_LOG_W(TAG, "Sdcard error - unmounting. Did you eject the card in an unsafe manner?");
hal::sdcard::unmount(ms_to_ticks(1000)); hal::sdcard::unmount(kernel::millisToTicks(1000));
} }
if (new_state != data->lastState) { if (new_state != data->lastState) {

View File

@ -2,15 +2,10 @@
#include "Wifi.h" #include "Wifi.h"
#include "MessageQueue.h" #include "TactilityHeadless.h"
#include "Mutex.h"
#include "Check.h"
#include "Log.h"
#include "Timer.h" #include "Timer.h"
#include "service/ServiceContext.h" #include "service/ServiceContext.h"
#include "WifiSettings.h" #include "WifiSettings.h"
#include "TactilityCore.h"
#include "TactilityHeadless.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
@ -47,8 +42,8 @@ private:
public: public:
/** @brief Locking mechanism for modifying the Wifi instance */ /** @brief Locking mechanism for modifying the Wifi instance */
Mutex radioMutex = Mutex(MutexTypeRecursive); Mutex radioMutex = Mutex(Mutex::TypeRecursive);
Mutex dataMutex = Mutex(MutexTypeRecursive); Mutex dataMutex = Mutex(Mutex::TypeRecursive);
std::unique_ptr<Timer> autoConnectTimer; std::unique_ptr<Timer> autoConnectTimer;
/** @brief The public event bus */ /** @brief The public event bus */
std::shared_ptr<PubSub> pubsub = std::make_shared<PubSub>(); std::shared_ptr<PubSub> pubsub = std::make_shared<PubSub>();
@ -664,7 +659,7 @@ static void dispatchScan(std::shared_ptr<void> context) {
} }
// TODO: Thread safety // TODO: Thread safety
wifi->last_scan_time = tt::get_ticks(); wifi->last_scan_time = tt::kernel::getTicks();
if (esp_wifi_scan_start(nullptr, false) != ESP_OK) { if (esp_wifi_scan_start(nullptr, false) != ESP_OK) {
TT_LOG_I(TAG, "Can't start scan"); TT_LOG_I(TAG, "Can't start scan");
@ -872,7 +867,7 @@ static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
return false; return false;
} }
TickType_t current_time = tt::get_ticks(); TickType_t current_time = tt::kernel::getTicks();
bool scan_time_has_looped = (current_time < wifi->last_scan_time); bool scan_time_has_looped = (current_time < wifi->last_scan_time);
bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS); bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS);

View File

@ -49,7 +49,7 @@ static void publish_event_simple(Wifi* wifi, WifiEventType type) {
static Wifi* wifi_alloc() { static Wifi* wifi_alloc() {
auto* instance = static_cast<Wifi*>(malloc(sizeof(Wifi))); auto* instance = static_cast<Wifi*>(malloc(sizeof(Wifi)));
instance->mutex = tt_mutex_alloc(MutexTypeRecursive); instance->mutex = tt_mutex_alloc(Mutex::TypeRecursive);
instance->pubsub = std::make_shared<PubSub>(); instance->pubsub = std::make_shared<PubSub>();
instance->scan_active = false; instance->scan_active = false;
instance->radio_state = WIFI_RADIO_CONNECTION_ACTIVE; instance->radio_state = WIFI_RADIO_CONNECTION_ACTIVE;

View File

@ -54,7 +54,7 @@ bool load(const char* ssid, WifiApSettings* settings) {
result = nvs_get_blob(handle, ssid, &encrypted_settings, &length); result = nvs_get_blob(handle, ssid, &encrypted_settings, &length);
uint8_t iv[16]; uint8_t iv[16];
crypt::get_iv_from_string(ssid, iv); crypt::getIv(ssid, strlen(ssid), iv);
int decrypt_result = crypt::decrypt( int decrypt_result = crypt::decrypt(
iv, iv,
(uint8_t*)encrypted_settings.password, (uint8_t*)encrypted_settings.password,
@ -97,7 +97,7 @@ bool save(const WifiApSettings* settings) {
encrypted_settings.password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT] = 0; encrypted_settings.password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT] = 0;
uint8_t iv[16]; uint8_t iv[16];
crypt::get_iv_from_data(settings->ssid, strlen(settings->ssid), iv); crypt::getIv(settings->ssid, strlen(settings->ssid), iv);
int encrypt_result = crypt::encrypt( int encrypt_result = crypt::encrypt(
iv, iv,
(uint8_t*)settings->password, (uint8_t*)settings->password,

View File

@ -14,7 +14,7 @@ void increment_callback(TT_UNUSED std::shared_ptr<void> context) {
void value_checker(std::shared_ptr<void> context) { void value_checker(std::shared_ptr<void> context) {
auto value = std::static_pointer_cast<uint32_t>(context); auto value = std::static_pointer_cast<uint32_t>(context);
if (*value != value_chacker_expected) { if (*value != value_chacker_expected) {
tt_crash_implementation(); tt_crash("Test error");
} }
} }
@ -24,7 +24,7 @@ TEST_CASE("dispatcher should not call callback if consume isn't called") {
auto context = std::make_shared<uint32_t>(); auto context = std::make_shared<uint32_t>();
dispatcher.dispatch(&increment_callback, std::move(context)); dispatcher.dispatch(&increment_callback, std::move(context));
delay_ticks(10); kernel::delayTicks(10);
CHECK_EQ(counter, 0); CHECK_EQ(counter, 0);
} }

View File

@ -11,7 +11,7 @@ static int thread_with_mutex_parameter(void* parameter) {
} }
TEST_CASE("a mutex can block a thread") { TEST_CASE("a mutex can block a thread") {
auto* mutex = tt_mutex_alloc(MutexTypeNormal); auto* mutex = tt_mutex_alloc(Mutex::TypeNormal);
tt_mutex_acquire(mutex, TtWaitForever); tt_mutex_acquire(mutex, TtWaitForever);
Thread* thread = new Thread( Thread* thread = new Thread(
@ -22,12 +22,12 @@ TEST_CASE("a mutex can block a thread") {
); );
thread->start(); thread->start();
delay_ms(5); kernel::delayMillis(5);
CHECK_EQ(thread->getState(), Thread::StateRunning); CHECK_EQ(thread->getState(), Thread::StateRunning);
tt_mutex_release(mutex); tt_mutex_release(mutex);
delay_ms(5); kernel::delayMillis(5);
CHECK_EQ(thread->getState(), Thread::StateStopped); CHECK_EQ(thread->getState(), Thread::StateStopped);
thread->join(); thread->join();

View File

@ -1,66 +1,63 @@
#include "doctest.h" #include "doctest.h"
#include "StringUtils.h" #include "StringUtils.h"
using namespace tt; // region split
using namespace std;
// region string_split
TEST_CASE("splitting an empty string results in an empty vector") { TEST_CASE("splitting an empty string results in an empty vector") {
auto result = string_split("", "."); auto result = tt::string::split("", ".");
CHECK_EQ(result.empty(), true); CHECK_EQ(result.empty(), true);
} }
TEST_CASE("splitting a string with a single token results in a vector with that token") { TEST_CASE("splitting a string with a single token results in a vector with that token") {
auto result = string_split("token", "."); auto result = tt::string::split("token", ".");
CHECK_EQ(result.size(), 1); CHECK_EQ(result.size(), 1);
CHECK_EQ(result.front(), "token"); CHECK_EQ(result.front(), "token");
} }
TEST_CASE("splitting a string with multiple tokens results in a vector with those tokens") { TEST_CASE("splitting a string with multiple tokens results in a vector with those tokens") {
auto result = string_split("token1;token2;token3;", ";"); auto result = tt::string::split("token1;token2;token3;", ";");
CHECK_EQ(result.size(), 3); CHECK_EQ(result.size(), 3);
CHECK_EQ(result[0], "token1"); CHECK_EQ(result[0], "token1");
CHECK_EQ(result[1], "token2"); CHECK_EQ(result[1], "token2");
CHECK_EQ(result[2], "token3"); CHECK_EQ(result[2], "token3");
} }
// endregion string_split // endregion split
// region string_join // region join
TEST_CASE("joining an empty vector results in an empty string") { TEST_CASE("joining an empty vector results in an empty string") {
vector<string> tokens = {}; std::vector<std::string> tokens = {};
auto result = string_join(tokens, "."); auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, ""); CHECK_EQ(result, "");
} }
TEST_CASE("joining a single token results in a string with that value") { TEST_CASE("joining a single token results in a string with that value") {
vector<string> tokens = { std::vector<std::string> tokens = {
"token" "token"
}; };
auto result = string_join(tokens, "."); auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token"); CHECK_EQ(result, "token");
} }
TEST_CASE("joining multiple tokens results in a string with all the tokens and the delimiter") { TEST_CASE("joining multiple tokens results in a string with all the tokens and the delimiter") {
vector<string> tokens = { std::vector<std::string> tokens = {
"token1", "token1",
"token2", "token2",
"token3", "token3",
}; };
auto result = string_join(tokens, "."); auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token1.token2.token3"); CHECK_EQ(result, "token1.token2.token3");
} }
TEST_CASE("joining with empty tokens leads to an extra delimiter") { TEST_CASE("joining with empty tokens leads to an extra delimiter") {
vector<string> tokens = { std::vector<std::string> tokens = {
"token1", "token1",
"", "",
"token2", "token2",
}; };
auto result = string_join(tokens, "."); auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token1..token2"); CHECK_EQ(result, "token1..token2");
} }
// endregion string_join // endregion join

View File

@ -7,7 +7,7 @@ using namespace tt;
static int interruptable_thread(void* parameter) { static int interruptable_thread(void* parameter) {
bool* interrupted = (bool*)parameter; bool* interrupted = (bool*)parameter;
while (!*interrupted) { while (!*interrupted) {
delay_ms(5); kernel::delayMillis(5);
} }
return 0; return 0;
} }

View File

@ -20,7 +20,7 @@ TEST_CASE("a timer passes the context correctly") {
auto foo = std::make_shared<int>(1); auto foo = std::make_shared<int>(1);
auto* timer = new Timer(Timer::TypeOnce, &timer_callback_with_context, foo); auto* timer = new Timer(Timer::TypeOnce, &timer_callback_with_context, foo);
timer->start(1); timer->start(1);
delay_ticks(10); kernel::delayTicks(10);
timer->stop(); timer->stop();
delete timer; delete timer;
@ -31,10 +31,10 @@ TEST_CASE("TimerTypePeriodic timers can be stopped and restarted") {
auto counter = std::make_shared<int>(0); auto counter = std::make_shared<int>(0);
auto* timer = new Timer(Timer::TypePeriodic, &timer_callback_with_counter, counter); auto* timer = new Timer(Timer::TypePeriodic, &timer_callback_with_counter, counter);
timer->start(1); timer->start(1);
delay_ticks(10); kernel::delayTicks(10);
timer->stop(); timer->stop();
timer->start(1); timer->start(1);
delay_ticks(10); kernel::delayTicks(10);
timer->stop(); timer->stop();
delete timer; delete timer;
@ -46,7 +46,7 @@ TEST_CASE("TimerTypePeriodic calls the callback periodically") {
int ticks_to_run = 10; int ticks_to_run = 10;
auto* timer = new Timer(Timer::TypePeriodic, &timer_callback_with_counter, counter); auto* timer = new Timer(Timer::TypePeriodic, &timer_callback_with_counter, counter);
timer->start(1); timer->start(1);
delay_ticks(ticks_to_run); kernel::delayTicks(ticks_to_run);
timer->stop(); timer->stop();
delete timer; delete timer;
@ -57,10 +57,10 @@ TEST_CASE("restarting TimerTypeOnce timers calls the callback again") {
auto counter = std::make_shared<int>(0); auto counter = std::make_shared<int>(0);
auto* timer = new Timer(Timer::TypeOnce, &timer_callback_with_counter, counter); auto* timer = new Timer(Timer::TypeOnce, &timer_callback_with_counter, counter);
timer->start(1); timer->start(1);
delay_ticks(10); kernel::delayTicks(10);
timer->stop(); timer->stop();
timer->start(1); timer->start(1);
delay_ticks(10); kernel::delayTicks(10);
timer->stop(); timer->stop();
delete timer; delete timer;