Time & date, system events and much more (#152)
## Time & Date - Added time to statusbar widget - Added Time & Date Settings app - Added TimeZone app for selecting TimeZone - Added `tt::time` namespace with timezone code ## Other changes - Added `SystemEvent` to publish/subscribe to system wide (e.g. for init code, but also for time settings changes) - Changed the way the statusbar widget works: now there's only 1 that gets shown/hidden, instead of 1 instance per app instance. - Moved `lowercase()` function to new namespace: `tt::string` - Increased T-Deck flash & PSRAM SPI frequencies to 120 MHz (from 80 MHz) - Temporary work-around (+ TODO item) for LVGL stack size (issue with WiFi app) - Suppress T-Deck keystroke debugging to debug level (privacy issue) - Improved SDL dependency wiring in various `CMakeLists.txt` - `Loader` service had some variables renamed to the newer C++ style (from previous C style)
This commit is contained in:
committed by
GitHub
parent
4f360741a1
commit
bf91e7530d
@@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
list(APPEND REQUIRES_LIST TactilityCore esp_wifi nvs_flash driver spiffs vfs fatfs)
|
||||
list(APPEND REQUIRES_LIST TactilityCore esp_wifi nvs_flash driver spiffs vfs fatfs lwip)
|
||||
if("${IDF_TARGET}" STREQUAL "esp32s3")
|
||||
list(APPEND REQUIRES_LIST esp_tinyusb)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace tt::network::ntp {
|
||||
|
||||
void init();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace tt::time {
|
||||
|
||||
void init();
|
||||
|
||||
}
|
||||
@@ -14,3 +14,4 @@
|
||||
#define TT_ASSETS_APP_ICON_I2C_SETTINGS TT_ASSET("app_icon_i2c.png")
|
||||
#define TT_ASSETS_APP_ICON_SETTINGS TT_ASSET("app_icon_settings.png")
|
||||
#define TT_ASSETS_APP_ICON_SYSTEM_INFO TT_ASSET("app_icon_system_info.png")
|
||||
#define TT_ASSETS_APP_ICON_TIME_DATE_SETTINGS TT_ASSET("app_icon_time_date_settings.png")
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "hal/Hal_i.h"
|
||||
#include "service/ServiceManifest.h"
|
||||
#include "service/ServiceRegistry.h"
|
||||
#include "kernel/SystemEvents.h"
|
||||
#include "network/NtpPrivate.h"
|
||||
#include "time/TimePrivate.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "EspInit.h"
|
||||
@@ -39,7 +42,9 @@ void initHeadless(const hal::Configuration& config) {
|
||||
initEsp();
|
||||
#endif
|
||||
hardwareConfig = &config;
|
||||
time::init();
|
||||
hal::init(config);
|
||||
network::ntp::init();
|
||||
register_and_start_system_services();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ typedef bool (*InitBoot)();
|
||||
typedef bool (*InitHardware)();
|
||||
typedef bool (*InitLvgl)();
|
||||
|
||||
typedef void (*SetBacklightDuty)(uint8_t);
|
||||
|
||||
class Display;
|
||||
class Keyboard;
|
||||
typedef Display* (*CreateDisplay)();
|
||||
@@ -57,7 +55,7 @@ struct Configuration {
|
||||
const CreatePower _Nullable power = nullptr;
|
||||
|
||||
/**
|
||||
* A list of i2c devices (can be empty, but preferably accurately represents the device capabilities)
|
||||
* A list of i2c interfaces
|
||||
*/
|
||||
const std::vector<i2c::Configuration> i2c = {};
|
||||
};
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
#include "hal/Hal_i.h"
|
||||
#include "hal/i2c/I2c.h"
|
||||
#include "kernel/SystemEvents.h"
|
||||
|
||||
#define TAG "hal"
|
||||
|
||||
namespace tt::hal {
|
||||
|
||||
void init(const Configuration& configuration) {
|
||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitHalBegin);
|
||||
|
||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitI2cBegin);
|
||||
tt_check(i2c::init(configuration.i2c), "I2C init failed");
|
||||
if (configuration.initHardware != nullptr) {
|
||||
TT_LOG_I(TAG, "Init hardware");
|
||||
tt_check(configuration.initHardware(), "Hardware init failed");
|
||||
}
|
||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitI2cEnd);
|
||||
|
||||
if (configuration.initBoot != nullptr) {
|
||||
TT_LOG_I(TAG, "Init power");
|
||||
@@ -23,6 +28,8 @@ void init(const Configuration& configuration) {
|
||||
TT_LOG_W(TAG, "SD card mount failed (init can continue)");
|
||||
}
|
||||
}
|
||||
|
||||
kernel::systemEventPublish(kernel::SystemEvent::BootInitHalEnd);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "SystemEvents.h"
|
||||
#include "Mutex.h"
|
||||
#include "CoreExtraDefines.h"
|
||||
#include <list>
|
||||
|
||||
#define TAG "system_event"
|
||||
|
||||
namespace tt::kernel {
|
||||
|
||||
struct SubscriptionData {
|
||||
SystemEventSubscription id;
|
||||
SystemEvent event;
|
||||
OnSystemEvent handler;
|
||||
};
|
||||
|
||||
static Mutex mutex;
|
||||
static SystemEventSubscription subscriptionCounter = 0;
|
||||
static std::list<SubscriptionData> subscriptions;
|
||||
|
||||
static const char* getEventName(SystemEvent event) {
|
||||
switch (event) {
|
||||
case SystemEvent::BootInitHalBegin:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitHalBegin);
|
||||
case SystemEvent::BootInitHalEnd:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitHalEnd);
|
||||
case SystemEvent::BootInitI2cBegin:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitI2cBegin);
|
||||
case SystemEvent::BootInitI2cEnd:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitI2cEnd);
|
||||
case SystemEvent::BootInitLvglBegin:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitLvglBegin);
|
||||
case SystemEvent::BootInitLvglEnd:
|
||||
return TT_STRINGIFY(SystemEvent::BootInitLvglEnd);
|
||||
case SystemEvent::BootSplash:
|
||||
return TT_STRINGIFY(SystemEvent::BootSplash);
|
||||
case SystemEvent::NetworkConnected:
|
||||
return TT_STRINGIFY(SystemEvent::NetworkConnected);
|
||||
case SystemEvent::NetworkDisconnected:
|
||||
return TT_STRINGIFY(SystemEvent::NetworkDisconnected);
|
||||
case SystemEvent::Time:
|
||||
return TT_STRINGIFY(SystemEvent::Time);
|
||||
}
|
||||
|
||||
tt_crash(); // Missing case above
|
||||
}
|
||||
|
||||
void systemEventPublish(SystemEvent event) {
|
||||
TT_LOG_I(TAG, "%s", getEventName(event));
|
||||
|
||||
if (mutex.lock(portMAX_DELAY)) {
|
||||
for (auto& subscription : subscriptions) {
|
||||
if (subscription.event == event) {
|
||||
subscription.handler(event);
|
||||
}
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
SystemEventSubscription systemEventAddListener(SystemEvent event, OnSystemEvent handler) {
|
||||
if (mutex.lock(portMAX_DELAY)) {
|
||||
auto id = ++subscriptionCounter;
|
||||
|
||||
subscriptions.push_back({
|
||||
.id = id,
|
||||
.event = event,
|
||||
.handler = handler
|
||||
});
|
||||
|
||||
mutex.unlock();
|
||||
return id;
|
||||
} else {
|
||||
tt_crash();
|
||||
}
|
||||
}
|
||||
|
||||
void systemEventRemoveListener(SystemEventSubscription subscription) {
|
||||
if (mutex.lock(portMAX_DELAY)) {
|
||||
std::erase_if(subscriptions, [subscription](auto& item) {
|
||||
return (item.id == subscription);
|
||||
});
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::kernel {
|
||||
|
||||
enum class SystemEvent {
|
||||
BootInitHalBegin,
|
||||
BootInitHalEnd,
|
||||
BootInitI2cBegin,
|
||||
BootInitI2cEnd,
|
||||
BootInitLvglBegin,
|
||||
BootInitLvglEnd,
|
||||
BootSplash,
|
||||
/** Gained IP address */
|
||||
NetworkConnected,
|
||||
NetworkDisconnected,
|
||||
/** An important system time-related event, such as NTP update or time-zone change */
|
||||
Time,
|
||||
};
|
||||
|
||||
/** Value 0 mean "no subscription" */
|
||||
typedef uint32_t SystemEventSubscription;
|
||||
|
||||
typedef void (*OnSystemEvent)(SystemEvent event);
|
||||
|
||||
void systemEventPublish(SystemEvent event);
|
||||
SystemEventSubscription systemEventAddListener(SystemEvent event, OnSystemEvent handler);
|
||||
void systemEventRemoveListener(SystemEventSubscription subscription);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "network/NtpPrivate.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "kernel/SystemEvents.h"
|
||||
#include "TactilityCore.h"
|
||||
#include <esp_netif_sntp.h>
|
||||
#include <esp_sntp.h>
|
||||
#endif
|
||||
|
||||
#define TAG "ntp"
|
||||
|
||||
namespace tt::network::ntp {
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
static void onTimeSynced(struct timeval* tv) {
|
||||
TT_LOG_I(TAG, "Time synced (%llu)", tv->tv_sec);
|
||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
||||
}
|
||||
|
||||
void init() {
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("pool.ntp.org");
|
||||
config.sync_cb = onTimeSynced;
|
||||
esp_netif_sntp_init(&config);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void init() {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <ctime>
|
||||
#include "Time.h"
|
||||
#include "Preferences.h"
|
||||
#include "kernel/SystemEvents.h"
|
||||
|
||||
namespace tt::time {
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#define TIME_SETTINGS_NAMESPACE "time"
|
||||
|
||||
#define TIMEZONE_PREFERENCES_KEY_NAME "tz_name"
|
||||
#define TIMEZONE_PREFERENCES_KEY_CODE "tz_code"
|
||||
#define TIMEZONE_PREFERENCES_KEY_TIME24 "tz_time24"
|
||||
|
||||
void init() {
|
||||
auto code= getTimeZoneCode();
|
||||
if (!code.empty()) {
|
||||
setenv("TZ", code.c_str(), 1);
|
||||
tzset();
|
||||
}
|
||||
}
|
||||
|
||||
void setTimeZone(const std::string& name, const std::string& code) {
|
||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||
preferences.putString(TIMEZONE_PREFERENCES_KEY_NAME, name);
|
||||
preferences.putString(TIMEZONE_PREFERENCES_KEY_CODE, code);
|
||||
|
||||
setenv("TZ", code.c_str(), 1);
|
||||
tzset();
|
||||
|
||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
||||
}
|
||||
|
||||
std::string getTimeZoneName() {
|
||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||
std::string result;
|
||||
if (preferences.optString(TIMEZONE_PREFERENCES_KEY_NAME, result)) {
|
||||
return result;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::string getTimeZoneCode() {
|
||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||
std::string result;
|
||||
if (preferences.optString(TIMEZONE_PREFERENCES_KEY_CODE, result)) {
|
||||
return result;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool isTimeFormat24Hour() {
|
||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||
bool show24Hour = true;
|
||||
preferences.optBool(TIMEZONE_PREFERENCES_KEY_TIME24, show24Hour);
|
||||
return show24Hour;
|
||||
}
|
||||
|
||||
void setTimeFormat24Hour(bool show24Hour) {
|
||||
Preferences preferences(TIME_SETTINGS_NAMESPACE);
|
||||
preferences.putBool(TIMEZONE_PREFERENCES_KEY_TIME24, show24Hour);
|
||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static std::string timeZoneName;
|
||||
static std::string timeZoneCode;
|
||||
static bool show24Hour = true;
|
||||
|
||||
void init() {}
|
||||
|
||||
void setTimeZone(const std::string& name, const std::string& code) {
|
||||
timeZoneName = name;
|
||||
timeZoneCode = code;
|
||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
||||
}
|
||||
|
||||
std::string getTimeZoneName() {
|
||||
return timeZoneName;
|
||||
}
|
||||
|
||||
std::string getTimeZoneCode() {
|
||||
return timeZoneCode;
|
||||
}
|
||||
|
||||
bool isTimeFormat24Hour() {
|
||||
return show24Hour;
|
||||
}
|
||||
|
||||
void setTimeFormat24Hour(bool enabled) {
|
||||
show24Hour = enabled;
|
||||
kernel::systemEventPublish(kernel::SystemEvent::Time);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tt::time {
|
||||
|
||||
/**
|
||||
* Set the timezone
|
||||
* @param[in] name human-readable name
|
||||
* @param[in] code the technical code (from timezones.csv)
|
||||
*/
|
||||
void setTimeZone(const std::string& name, const std::string& code);
|
||||
|
||||
/**
|
||||
* Get the name of the timezone
|
||||
*/
|
||||
std::string getTimeZoneName();
|
||||
|
||||
/**
|
||||
* Get the code of the timezone (see timezones.csv)
|
||||
*/
|
||||
std::string getTimeZoneCode();
|
||||
|
||||
/** @return true when clocks should be shown as a 24 hours one instead of 12 hours */
|
||||
bool isTimeFormat24Hour();
|
||||
|
||||
/** Set whether clocks should be shown as a 24 hours instead of 12 hours
|
||||
* @param[in] show24Hour
|
||||
*/
|
||||
void setTimeFormat24Hour(bool show24Hour);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user