mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-19 23:15:05 +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)
|
||||
- Extend unPhone power driver: add charging status, usb connection status, etc.
|
||||
- Expose app::Paths to TactilityC
|
||||
- Make a ledger for setting CPU affinity of various services and tasks
|
||||
- CrashHandler: use "corrupted" flag
|
||||
- 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.
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <Tactility/kernel/SystemEvents.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <Tactility/CpuAffinity.h>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "Tactility/app/crashdiagnostics/CrashDiagnostics.h"
|
||||
@ -24,26 +25,25 @@
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
class BootApp : public App {
|
||||
|
||||
private:
|
||||
Thread thread = Thread(
|
||||
"boot",
|
||||
4096,
|
||||
[] { return bootThreadCallback(); },
|
||||
getCpuAffinityConfiguration().system
|
||||
);
|
||||
|
||||
Thread thread = Thread("boot", 4096, [this]() { return bootThreadCallback(); });
|
||||
|
||||
int32_t bootThreadCallback() {
|
||||
TickType_t start_time = kernel::getTicks();
|
||||
|
||||
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
|
||||
|
||||
auto hal_display = getHalDisplay();
|
||||
static void setupDisplay() {
|
||||
const auto hal_display = getHalDisplay();
|
||||
assert(hal_display != nullptr);
|
||||
if (hal_display->supportsBacklightDuty()) {
|
||||
uint8_t backlight_duty = 200;
|
||||
app::display::getBacklightDuty(backlight_duty);
|
||||
display::getBacklightDuty(backlight_duty);
|
||||
TT_LOG_I(TAG, "backlight %du", backlight_duty);
|
||||
hal_display->setBacklightDuty(backlight_duty);
|
||||
} else {
|
||||
@ -52,27 +52,45 @@ private:
|
||||
|
||||
if (hal_display->getGammaCurveCount() > 0) {
|
||||
uint8_t gamma_curve;
|
||||
if (app::display::getGammaCurve(gamma_curve)) {
|
||||
if (display::getGammaCurve(gamma_curve)) {
|
||||
hal_display->setGammaCurve(gamma_curve);
|
||||
TT_LOG_I(TAG, "gamma %du", gamma_curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hal::usb::isUsbBootMode()) {
|
||||
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
|
||||
hal::usb::resetUsbBootMode();
|
||||
hal::usb::startMassStorageWithSdmmc();
|
||||
} else {
|
||||
static bool setupUsbBootMode() {
|
||||
if (!hal::usb::isUsbBootMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "Rebooting into mass storage device mode");
|
||||
hal::usb::resetUsbBootMode();
|
||||
hal::usb::startMassStorageWithSdmmc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
kernel::delayTicks(minimum_ticks - ticks_passed);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t bootThreadCallback() {
|
||||
const auto start_time = kernel::getTicks();
|
||||
|
||||
kernel::publishSystemEvent(kernel::SystemEvent::BootSplash);
|
||||
|
||||
setupDisplay();
|
||||
|
||||
if (!setupUsbBootMode()) {
|
||||
initFromBootApp();
|
||||
|
||||
TickType_t end_time = tt::kernel::getTicks();
|
||||
TickType_t ticks_passed = end_time - start_time;
|
||||
TickType_t minimum_ticks = (CONFIG_TT_SPLASH_DURATION / portTICK_PERIOD_MS);
|
||||
if (minimum_ticks > ticks_passed) {
|
||||
kernel::delayTicks(minimum_ticks - ticks_passed);
|
||||
}
|
||||
|
||||
tt::service::loader::stopApp();
|
||||
waitForMinimalSplashDuration(start_time);
|
||||
service::loader::stopApp();
|
||||
startNextApp();
|
||||
}
|
||||
|
||||
@ -81,16 +99,15 @@ private:
|
||||
|
||||
static void startNextApp() {
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_reset_reason_t reason = esp_reset_reason();
|
||||
if (reason == ESP_RST_PANIC) {
|
||||
app::crashdiagnostics::start();
|
||||
if (esp_reset_reason() == ESP_RST_PANIC) {
|
||||
crashdiagnostics::start();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto* config = tt::getConfiguration();
|
||||
const auto* config = getConfiguration();
|
||||
assert(!config->launcherAppId.empty());
|
||||
tt::service::loader::startApp(config->launcherAppId);
|
||||
service::loader::startApp(config->launcherAppId);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -99,9 +116,9 @@ public:
|
||||
auto* image = lv_image_create(parent);
|
||||
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";
|
||||
auto logo_path = paths->getSystemPathLvgl(logo);
|
||||
const auto logo_path = paths->getSystemPathLvgl(logo);
|
||||
TT_LOG_I(TAG, "%s", 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 {
|
||||
|
||||
private:
|
||||
|
||||
// Core
|
||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||
std::unique_ptr<Timer> scanTimer = nullptr;
|
||||
@ -286,7 +284,7 @@ void I2cScannerApp::startScanning() {
|
||||
lv_obj_clean(scanListWidget);
|
||||
|
||||
scanState = ScanStateScanning;
|
||||
scanTimer = std::make_unique<Timer>(Timer::Type::Once, [](){
|
||||
scanTimer = std::make_unique<Timer>(Timer::Type::Once, []{
|
||||
onScanTimerCallback();
|
||||
});
|
||||
scanTimer->start(10);
|
||||
|
||||
@ -2,23 +2,23 @@
|
||||
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
#include <Tactility/CpuAffinity.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
|
||||
// LVGL
|
||||
// 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
|
||||
#define TDECK_LVGL_TASK_STACK_DEPTH 9216
|
||||
#define TAG "lvgl"
|
||||
auto constexpr TAG = "lvgl";
|
||||
|
||||
namespace tt::lvgl {
|
||||
|
||||
bool initEspLvglPort() {
|
||||
TT_LOG_D(TAG, "Port init");
|
||||
static lv_disp_t* display = nullptr;
|
||||
const lvgl_port_cfg_t lvgl_cfg = {
|
||||
.task_priority = static_cast<UBaseType_t>(Thread::Priority::Critical),
|
||||
.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,
|
||||
.timer_period_ms = 5
|
||||
};
|
||||
@ -28,7 +28,7 @@ bool initEspLvglPort() {
|
||||
return false;
|
||||
}
|
||||
|
||||
tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock);
|
||||
syncSet(&lvgl_port_lock, &lvgl_port_unlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#endif
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <Tactility/Tactility.h>
|
||||
#include <Tactility/TactilityHeadless.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/service/ServiceRegistry.h>
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <Tactility/TactilityCore.h>
|
||||
|
||||
#include <format>
|
||||
#include <Tactility/CpuAffinity.h>
|
||||
|
||||
namespace tt::service::screenshot {
|
||||
|
||||
@ -109,10 +110,11 @@ void ScreenshotTask::taskStart() {
|
||||
thread = new Thread(
|
||||
"screenshot",
|
||||
8192,
|
||||
[this]() {
|
||||
[this] {
|
||||
this->taskMain();
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
getCpuAffinityConfiguration().graphics
|
||||
);
|
||||
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:
|
||||
|
||||
struct TimerHandleDeleter {
|
||||
void operator()(TimerHandle_t handleToDelete) {
|
||||
void operator()(TimerHandle_t handleToDelete) const {
|
||||
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(callback != nullptr);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user