Various improvements (#461)
* **New Features** * Time and delay utilities added (ticks, ms, µs); SD card now uses an expansion-header CS pin; HTTP downloads warn when run on the GUI task and yield to avoid blocking. * **Bug Fixes / Reliability** * Many hard-crash paths converted to guarded checks to reduce abrupt termination and improve stability. * **Tests** * Unit tests added to validate time and delay accuracy. * **Chores** * License header and build/macro updates.
This commit is contained in:
committed by
GitHub
parent
619b5aa53b
commit
e6abd496f9
@@ -59,7 +59,7 @@ class DisplayIdleService final : public Service {
|
||||
}
|
||||
|
||||
public:
|
||||
bool onStart(TT_UNUSED ServiceContext& service) override {
|
||||
bool onStart(ServiceContext& service) override {
|
||||
// Load settings once at startup and cache them
|
||||
// This eliminates file I/O from timer callback (prevents watchdog timeout)
|
||||
cachedDisplaySettings = settings::display::loadOrGetDefault();
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(TT_UNUSED ServiceContext& service) override {
|
||||
void onStop(ServiceContext& service) override {
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
timer = nullptr;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <Tactility/service/gui/GuiService.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <Tactility/app/AppInstance.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
@@ -15,6 +17,15 @@ extern const ServiceManifest manifest;
|
||||
static const auto LOGGER = Logger("GuiService");
|
||||
using namespace loader;
|
||||
|
||||
constexpr auto* GUI_TASK_NAME = "gui";
|
||||
|
||||
void warnIfRunningOnGuiTask(const char* context) {
|
||||
const char* task_name = pcTaskGetName(nullptr);
|
||||
if (strcmp(GUI_TASK_NAME, task_name) == 0) {
|
||||
LOGGER.warn("{} shouldn't run on the GUI task", context);
|
||||
}
|
||||
}
|
||||
|
||||
// region AppManifest
|
||||
|
||||
void GuiService::onLoaderEvent(LoaderService::Event event) {
|
||||
@@ -114,7 +125,7 @@ void GuiService::redraw() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
bool GuiService::onStart(TT_UNUSED ServiceContext& service) {
|
||||
bool GuiService::onStart(ServiceContext& service) {
|
||||
auto* screen_root = lv_screen_active();
|
||||
if (screen_root == nullptr) {
|
||||
LOGGER.error("No display found");
|
||||
@@ -122,11 +133,13 @@ bool GuiService::onStart(TT_UNUSED ServiceContext& service) {
|
||||
}
|
||||
|
||||
thread = new Thread(
|
||||
"gui",
|
||||
GUI_TASK_NAME,
|
||||
4096, // Last known minimum was 2800 for launching desktop
|
||||
[]() { return guiMain(); }
|
||||
);
|
||||
|
||||
thread->setPriority(THREAD_PRIORITY_SERVICE);
|
||||
|
||||
const auto loader = findLoaderService();
|
||||
assert(loader != nullptr);
|
||||
loader_pubsub_subscription = loader->getPubsub()->subscribe([this](auto event) {
|
||||
@@ -169,7 +182,7 @@ bool GuiService::onStart(TT_UNUSED ServiceContext& service) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiService::onStop(TT_UNUSED ServiceContext& service) {
|
||||
void GuiService::onStop(ServiceContext& service) {
|
||||
lock();
|
||||
|
||||
const auto loader = findLoaderService();
|
||||
@@ -186,7 +199,7 @@ void GuiService::onStop(TT_UNUSED ServiceContext& service) {
|
||||
|
||||
unlock();
|
||||
|
||||
tt_check(lvgl::lock(1000 / portTICK_PERIOD_MS));
|
||||
check(lvgl::lock(1000 / portTICK_PERIOD_MS));
|
||||
lv_group_delete(keyboardGroup);
|
||||
lvgl::unlock();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ static void show_keyboard(lv_event_t* event) {
|
||||
}
|
||||
}
|
||||
|
||||
static void hide_keyboard(TT_UNUSED lv_event_t* event) {
|
||||
static void hide_keyboard(lv_event_t* event) {
|
||||
auto service = findService();
|
||||
if (service != nullptr) {
|
||||
service->softwareKeyboardHide();
|
||||
@@ -53,7 +53,7 @@ void GuiService::keyboardAddTextArea(lv_obj_t* textarea) {
|
||||
lock();
|
||||
|
||||
if (isStarted) {
|
||||
tt_check(lvgl::lock(0), "lvgl should already be locked before calling this method");
|
||||
check(lvgl::lock(0), "lvgl should already be locked before calling this method");
|
||||
|
||||
if (softwareKeyboardIsEnabled()) {
|
||||
lv_obj_add_event_cb(textarea, show_keyboard, LV_EVENT_FOCUSED, nullptr);
|
||||
|
||||
@@ -58,7 +58,7 @@ class KeyboardIdleService final : public Service {
|
||||
}
|
||||
|
||||
public:
|
||||
bool onStart(TT_UNUSED ServiceContext& service) override {
|
||||
bool onStart(ServiceContext& service) override {
|
||||
// Load settings once at startup and cache them
|
||||
// This eliminates file I/O from timer callback (prevents watchdog timeout)
|
||||
cachedKeyboardSettings = settings::keyboard::loadOrGetDefault();
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(TT_UNUSED ServiceContext& service) override {
|
||||
void onStop(ServiceContext& service) override {
|
||||
if (timer) {
|
||||
timer->stop();
|
||||
timer = nullptr;
|
||||
|
||||
@@ -245,7 +245,7 @@ void LoaderService::transitionAppToState(const std::shared_ptr<app::AppInstance>
|
||||
switch (state) {
|
||||
using enum app::State;
|
||||
case Initial:
|
||||
tt_crash(LOG_MESSAGE_ILLEGAL_STATE);
|
||||
check(false, LOG_MESSAGE_ILLEGAL_STATE);
|
||||
case Created:
|
||||
assert(app->getState() == app::State::Initial);
|
||||
app->getApp()->onCreate(*app);
|
||||
|
||||
@@ -107,7 +107,7 @@ void ScreenshotTask::taskStart() {
|
||||
return;
|
||||
}
|
||||
|
||||
tt_check(thread == nullptr);
|
||||
check(thread == nullptr);
|
||||
thread = new Thread(
|
||||
"screenshot",
|
||||
8192,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <Tactility/lvgl/Statusbar.h>
|
||||
|
||||
#include <Tactility/Check.h>
|
||||
#include <Tactility/hal/power/PowerDevice.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/Logger.h>
|
||||
@@ -71,7 +72,7 @@ static const char* getWifiStatusIcon(wifi::RadioState state, bool secure) {
|
||||
rssi = wifi::getRssi();
|
||||
return getWifiStatusIconForRssi(rssi);
|
||||
default:
|
||||
tt_crash("not implemented");
|
||||
check(false, "not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +86,7 @@ static const char* getSdCardStatusIcon(hal::sdcard::SdCardDevice::State state) {
|
||||
case Timeout:
|
||||
return STATUSBAR_ICON_SDCARD_ALERT;
|
||||
default:
|
||||
tt_crash("Unhandled SdCard state");
|
||||
check(false, "Unhandled SdCard state");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include <Tactility/Check.h>
|
||||
#include <Tactility/service/webserver/WebServerService.h>
|
||||
#include <Tactility/service/webserver/AssetVersion.h>
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
@@ -93,7 +94,7 @@ static void publish_event(WebServerService* webserver, WebServerEvent event) {
|
||||
std::shared_ptr<PubSub<WebServerEvent>> getPubsub() {
|
||||
WebServerService* webserver = g_webServerInstance.load();
|
||||
if (webserver == nullptr) {
|
||||
tt_crash("Service not running");
|
||||
check(false, "Service not running");
|
||||
}
|
||||
|
||||
return webserver->getPubsub();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <Tactility/service/wifi/Wifi.h>
|
||||
|
||||
#include <Tactility/Check.h>
|
||||
#include <Tactility/CoreDefines.h>
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
#include <Tactility/service/ServiceRegistration.h>
|
||||
|
||||
@@ -22,7 +23,7 @@ const char* radioStateToString(RadioState state) {
|
||||
case Off:
|
||||
return TT_STRINGIFY(Off);
|
||||
}
|
||||
tt_crash("not implemented");
|
||||
check(false, "not implemented");
|
||||
}
|
||||
|
||||
extern const ServiceManifest manifest;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <Tactility/service/wifi/Wifi.h>
|
||||
|
||||
#include <Tactility/Check.h>
|
||||
#include <Tactility/EventGroup.h>
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/LogMessages.h>
|
||||
@@ -140,7 +141,7 @@ static std::shared_ptr<Wifi> wifi_singleton;
|
||||
std::shared_ptr<PubSub<WifiEvent>> getPubsub() {
|
||||
auto wifi = wifi_singleton;
|
||||
if (wifi == nullptr) {
|
||||
tt_crash("Service not running");
|
||||
check(false, "Service not running");
|
||||
}
|
||||
|
||||
return wifi->pubsub;
|
||||
@@ -472,7 +473,7 @@ static void dispatchAutoConnect(std::shared_ptr<Wifi> wifi) {
|
||||
}
|
||||
}
|
||||
|
||||
static void eventHandler(TT_UNUSED void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||
static void eventHandler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||
auto wifi = wifi_singleton;
|
||||
if (wifi == nullptr) {
|
||||
LOGGER.error("eventHandler: no wifi instance");
|
||||
|
||||
@@ -76,7 +76,7 @@ void setScanRecords(uint16_t records) {
|
||||
}
|
||||
|
||||
std::vector<ApRecord> getScanResults() {
|
||||
tt_check(wifi);
|
||||
check(wifi);
|
||||
|
||||
std::vector<ApRecord> records;
|
||||
records.push_back((ApRecord) {
|
||||
@@ -145,14 +145,14 @@ class WifiService final : public Service {
|
||||
|
||||
public:
|
||||
|
||||
bool onStart(TT_UNUSED ServiceContext& service) override {
|
||||
tt_check(wifi == nullptr);
|
||||
bool onStart(ServiceContext& service) override {
|
||||
check(wifi == nullptr);
|
||||
wifi = new Wifi();
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(TT_UNUSED ServiceContext& service) override {
|
||||
tt_check(wifi != nullptr);
|
||||
void onStop(ServiceContext& service) override {
|
||||
check(wifi != nullptr);
|
||||
delete wifi;
|
||||
wifi = nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user