mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-23 08:55:04 +00:00
Compare commits
2 Commits
470e65e90f
...
75be23eca2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75be23eca2 | ||
|
|
c809cea6c8 |
@ -13,7 +13,6 @@
|
|||||||
- Mutex: Implement give/take from ISR support (works only for non-recursive ones)
|
- Mutex: Implement give/take from ISR support (works only for non-recursive ones)
|
||||||
- Extend unPhone power driver: add charging status, usb connection status, etc.
|
- Extend unPhone power driver: add charging status, usb connection status, etc.
|
||||||
- Expose app::Paths to TactilityC
|
- Expose app::Paths to TactilityC
|
||||||
- Make a ledger for setting CPU affinity of various services and tasks
|
|
||||||
- CrashHandler: use "corrupted" flag
|
- CrashHandler: use "corrupted" flag
|
||||||
- CrashHandler: process other types of crashes (WDT?)
|
- CrashHandler: process other types of crashes (WDT?)
|
||||||
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.
|
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include <Tactility/kernel/SystemEvents.h>
|
#include <Tactility/kernel/SystemEvents.h>
|
||||||
|
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
|
#include <Tactility/CpuAffinity.h>
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
#include "Tactility/app/crashdiagnostics/CrashDiagnostics.h"
|
#include "Tactility/app/crashdiagnostics/CrashDiagnostics.h"
|
||||||
@ -24,26 +25,25 @@
|
|||||||
|
|
||||||
namespace tt::app::boot {
|
namespace tt::app::boot {
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::display::DisplayDevice> getHalDisplay() {
|
static std::shared_ptr<hal::display::DisplayDevice> getHalDisplay() {
|
||||||
return hal::findFirstDevice<hal::display::DisplayDevice>(hal::Device::Type::Display);
|
return hal::findFirstDevice<hal::display::DisplayDevice>(hal::Device::Type::Display);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BootApp : public App {
|
class BootApp : public App {
|
||||||
|
|
||||||
private:
|
Thread thread = Thread(
|
||||||
|
"boot",
|
||||||
|
4096,
|
||||||
|
[] { return bootThreadCallback(); },
|
||||||
|
getCpuAffinityConfiguration().system
|
||||||
|
);
|
||||||
|
|
||||||
Thread thread = Thread("boot", 4096, [this]() { return bootThreadCallback(); });
|
static void setupDisplay() {
|
||||||
|
const auto hal_display = getHalDisplay();
|
||||||
int32_t bootThreadCallback() {
|
|
||||||
TickType_t start_time = kernel::getTicks();
|
|
||||||
|
|
||||||
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
|
|
||||||
|
|
||||||
auto hal_display = getHalDisplay();
|
|
||||||
assert(hal_display != nullptr);
|
assert(hal_display != nullptr);
|
||||||
if (hal_display->supportsBacklightDuty()) {
|
if (hal_display->supportsBacklightDuty()) {
|
||||||
uint8_t backlight_duty = 200;
|
uint8_t backlight_duty = 200;
|
||||||
app::display::getBacklightDuty(backlight_duty);
|
display::getBacklightDuty(backlight_duty);
|
||||||
TT_LOG_I(TAG, "backlight %du", backlight_duty);
|
TT_LOG_I(TAG, "backlight %du", backlight_duty);
|
||||||
hal_display->setBacklightDuty(backlight_duty);
|
hal_display->setBacklightDuty(backlight_duty);
|
||||||
} else {
|
} else {
|
||||||
@ -52,27 +52,45 @@ private:
|
|||||||
|
|
||||||
if (hal_display->getGammaCurveCount() > 0) {
|
if (hal_display->getGammaCurveCount() > 0) {
|
||||||
uint8_t gamma_curve;
|
uint8_t gamma_curve;
|
||||||
if (app::display::getGammaCurve(gamma_curve)) {
|
if (display::getGammaCurve(gamma_curve)) {
|
||||||
hal_display->setGammaCurve(gamma_curve);
|
hal_display->setGammaCurve(gamma_curve);
|
||||||
TT_LOG_I(TAG, "gamma %du", gamma_curve);
|
TT_LOG_I(TAG, "gamma %du", gamma_curve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupUsbBootMode() {
|
||||||
|
if (!hal::usb::isUsbBootMode()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (hal::usb::isUsbBootMode()) {
|
|
||||||
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
|
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
|
||||||
hal::usb::resetUsbBootMode();
|
hal::usb::resetUsbBootMode();
|
||||||
hal::usb::startMassStorageWithSdmmc();
|
hal::usb::startMassStorageWithSdmmc();
|
||||||
} else {
|
|
||||||
initFromBootApp();
|
|
||||||
|
|
||||||
TickType_t end_time = tt::kernel::getTicks();
|
return true;
|
||||||
TickType_t ticks_passed = end_time - start_time;
|
}
|
||||||
TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
|
|
||||||
|
static void waitForMinimalSplashDuration(TickType_t startTime) {
|
||||||
|
const auto end_time = kernel::getTicks();
|
||||||
|
const auto ticks_passed = end_time - startTime;
|
||||||
|
constexpr auto minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
|
||||||
if (minimum_ticks > ticks_passed) {
|
if (minimum_ticks > ticks_passed) {
|
||||||
kernel::delayTicks(minimum_ticks - ticks_passed);
|
kernel::delayTicks(minimum_ticks - ticks_passed);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tt::service::loader::stopApp();
|
static int32_t bootThreadCallback() {
|
||||||
|
const auto start_time = kernel::getTicks();
|
||||||
|
|
||||||
|
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
|
||||||
|
|
||||||
|
setupDisplay();
|
||||||
|
|
||||||
|
if (!setupUsbBootMode()) {
|
||||||
|
initFromBootApp();
|
||||||
|
waitForMinimalSplashDuration(start_time);
|
||||||
|
service::loader::stopApp();
|
||||||
startNextApp();
|
startNextApp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,16 +99,15 @@ private:
|
|||||||
|
|
||||||
static void startNextApp() {
|
static void startNextApp() {
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
esp_reset_reason_t reason = esp_reset_reason();
|
if (esp_reset_reason() == ESP_RST_PANIC) {
|
||||||
if (reason == ESP_RST_PANIC) {
|
crashdiagnostics::start();
|
||||||
app::crashdiagnostics::start();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto* config = tt::getConfiguration();
|
const auto* config = getConfiguration();
|
||||||
assert(!config->launcherAppId.empty());
|
assert(!config->launcherAppId.empty());
|
||||||
tt::service::loader::startApp(config->launcherAppId);
|
service::loader::startApp(config->launcherAppId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -99,9 +116,9 @@ public:
|
|||||||
auto* image = lv_image_create(parent);
|
auto* image = lv_image_create(parent);
|
||||||
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
|
||||||
|
|
||||||
auto paths = app.getPaths();
|
const auto paths = app.getPaths();
|
||||||
const char* logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo.png";
|
const char* logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo.png";
|
||||||
auto logo_path = paths->getSystemPathLvgl(logo);
|
const auto logo_path = paths->getSystemPathLvgl(logo);
|
||||||
TT_LOG_I(TAG, "%s", logo_path.c_str());
|
TT_LOG_I(TAG, "%s", logo_path.c_str());
|
||||||
lv_image_set_src(image, logo_path.c_str());
|
lv_image_set_src(image, logo_path.c_str());
|
||||||
|
|
||||||
|
|||||||
@ -24,8 +24,6 @@ extern const AppManifest manifest;
|
|||||||
|
|
||||||
class I2cScannerApp : public App {
|
class I2cScannerApp : public App {
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||||
std::unique_ptr<Timer> scanTimer = nullptr;
|
std::unique_ptr<Timer> scanTimer = nullptr;
|
||||||
@ -286,7 +284,7 @@ void I2cScannerApp::startScanning() {
|
|||||||
lv_obj_clean(scanListWidget);
|
lv_obj_clean(scanListWidget);
|
||||||
|
|
||||||
scanState = ScanStateScanning;
|
scanState = ScanStateScanning;
|
||||||
scanTimer = std::make_unique<Timer>(Timer::Type::Once, [](){
|
scanTimer = std::make_unique<Timer>(Timer::Type::Once, []{
|
||||||
onScanTimerCallback();
|
onScanTimerCallback();
|
||||||
});
|
});
|
||||||
scanTimer->start(10);
|
scanTimer->start(10);
|
||||||
|
|||||||
@ -2,23 +2,23 @@
|
|||||||
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <esp_lvgl_port.h>
|
#include <esp_lvgl_port.h>
|
||||||
|
#include <Tactility/CpuAffinity.h>
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
|
|
||||||
// LVGL
|
// LVGL
|
||||||
// The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios
|
// The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios
|
||||||
// At 8192, it sometimes crashes when wifi-auto enables and is busy connecting and then you open WifiManage
|
// At 8192, it sometimes crashes when wifi-auto enables and is busy connecting and then you open WifiManage
|
||||||
#define TDECK_LVGL_TASK_STACK_DEPTH 9216
|
#define TDECK_LVGL_TASK_STACK_DEPTH 9216
|
||||||
#define TAG "lvgl"
|
auto constexpr TAG = "lvgl";
|
||||||
|
|
||||||
namespace tt::lvgl {
|
namespace tt::lvgl {
|
||||||
|
|
||||||
bool initEspLvglPort() {
|
bool initEspLvglPort() {
|
||||||
TT_LOG_D(TAG, "Port init");
|
TT_LOG_D(TAG, "Port init");
|
||||||
static lv_disp_t* display = nullptr;
|
|
||||||
const lvgl_port_cfg_t lvgl_cfg = {
|
const lvgl_port_cfg_t lvgl_cfg = {
|
||||||
.task_priority = static_cast<UBaseType_t>(Thread::Priority::Critical),
|
.task_priority = static_cast<UBaseType_t>(Thread::Priority::Critical),
|
||||||
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
|
.task_stack = TDECK_LVGL_TASK_STACK_DEPTH,
|
||||||
.task_affinity = 1, // -1 = disabled, 0 = core 1, 1 = core 2
|
.task_affinity = getCpuAffinityConfiguration().graphics,
|
||||||
.task_max_sleep_ms = 500,
|
.task_max_sleep_ms = 500,
|
||||||
.timer_period_ms = 5
|
.timer_period_ms = 5
|
||||||
};
|
};
|
||||||
@ -28,7 +28,7 @@ bool initEspLvglPort() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock);
|
syncSet(&lvgl_port_lock, &lvgl_port_unlock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <lvgl.h>
|
#include <lvgl.h>
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/TactilityHeadless.h>
|
#include <Tactility/TactilityHeadless.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/service/ServiceRegistry.h>
|
#include <Tactility/service/ServiceRegistry.h>
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <Tactility/CpuAffinity.h>
|
||||||
|
|
||||||
namespace tt::service::screenshot {
|
namespace tt::service::screenshot {
|
||||||
|
|
||||||
@ -109,10 +110,11 @@ void ScreenshotTask::taskStart() {
|
|||||||
thread = new Thread(
|
thread = new Thread(
|
||||||
"screenshot",
|
"screenshot",
|
||||||
8192,
|
8192,
|
||||||
[this]() {
|
[this] {
|
||||||
this->taskMain();
|
this->taskMain();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
},
|
||||||
|
getCpuAffinityConfiguration().graphics
|
||||||
);
|
);
|
||||||
thread->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|||||||
27
TactilityCore/Include/Tactility/CpuAffinity.h
Normal file
27
TactilityCore/Include/Tactility/CpuAffinity.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RtosCompat.h"
|
||||||
|
|
||||||
|
namespace tt {
|
||||||
|
|
||||||
|
typedef portBASE_TYPE CpuAffinity;
|
||||||
|
|
||||||
|
constexpr static CpuAffinity None = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the preferred affinity for certain (sub)systems.
|
||||||
|
*/
|
||||||
|
struct CpuAffinityConfiguration {
|
||||||
|
CpuAffinity system;
|
||||||
|
CpuAffinity graphics; // Display, LVGL
|
||||||
|
CpuAffinity wifi;
|
||||||
|
CpuAffinity mainDispatcher;
|
||||||
|
CpuAffinity apps;
|
||||||
|
CpuAffinity timer; // Tactility Timer (based on FreeRTOS)
|
||||||
|
};
|
||||||
|
|
||||||
|
void setCpuAffinityConfiguration(const CpuAffinityConfiguration& config);
|
||||||
|
|
||||||
|
const CpuAffinityConfiguration& getCpuAffinityConfiguration();
|
||||||
|
|
||||||
|
}
|
||||||
@ -18,7 +18,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
struct TimerHandleDeleter {
|
struct TimerHandleDeleter {
|
||||||
void operator()(TimerHandle_t handleToDelete) {
|
void operator()(TimerHandle_t handleToDelete) const {
|
||||||
xTimerDelete(handleToDelete, portMAX_DELAY);
|
xTimerDelete(handleToDelete, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
85
TactilityCore/Source/CpuAffinity.cpp
Normal file
85
TactilityCore/Source/CpuAffinity.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "Tactility/CpuAffinity.h"
|
||||||
|
|
||||||
|
#include <Tactility/Check.h>
|
||||||
|
|
||||||
|
namespace tt {
|
||||||
|
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
static CpuAffinity getEspWifiAffinity() {
|
||||||
|
#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0
|
||||||
|
return 0;
|
||||||
|
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning: Must watch ESP WiFi, as this task is used by WiFi
|
||||||
|
static CpuAffinity getEspMainSchedulerAffinity() {
|
||||||
|
#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0
|
||||||
|
return 0;
|
||||||
|
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static CpuAffinity getFreeRtosTimerAffinity() {
|
||||||
|
#if defined(CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY)
|
||||||
|
return None;
|
||||||
|
#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0)
|
||||||
|
return 0;
|
||||||
|
#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1)
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
static_assert(false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_NUMBER_OF_CORES == 1
|
||||||
|
static const CpuAffinityConfiguration esp = {
|
||||||
|
.system = 0,
|
||||||
|
.graphics = 0,
|
||||||
|
.wifi = 0,
|
||||||
|
.mainDispatcher = 0,
|
||||||
|
.apps = 0,
|
||||||
|
.timer = getFreeRtosTimerAffinity()
|
||||||
|
};
|
||||||
|
#elif CONFIG_FREERTOS_NUMBER_OF_CORES == 2
|
||||||
|
static const CpuAffinityConfiguration esp = {
|
||||||
|
.system = 0,
|
||||||
|
.graphics = 1,
|
||||||
|
.wifi = getEspWifiAffinity(),
|
||||||
|
.mainDispatcher = getEspMainSchedulerAffinity(),
|
||||||
|
.apps = 1,
|
||||||
|
.timer = getFreeRtosTimerAffinity()
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const CpuAffinityConfiguration simulator = {
|
||||||
|
.system = None,
|
||||||
|
.graphics = None,
|
||||||
|
.wifi = None,
|
||||||
|
.mainDispatcher = 0,
|
||||||
|
.apps = None,
|
||||||
|
.timer = None
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const CpuAffinityConfiguration& getCpuAffinityConfiguration() {
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2
|
||||||
|
// WiFi uses the main dispatcher to defer operations in the background
|
||||||
|
assert(esp.wifi == esp.mainDispatcher);
|
||||||
|
#endif // CORES
|
||||||
|
return esp;
|
||||||
|
|
||||||
|
#else
|
||||||
|
return simulator;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ void Timer::onCallback(TimerHandle_t hTimer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) {
|
static TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) {
|
||||||
assert(timerId != nullptr);
|
assert(timerId != nullptr);
|
||||||
assert(callback != nullptr);
|
assert(callback != nullptr);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user