Refactor services into classes (#183)
This commit is contained in:
parent
bb7e79886f
commit
3be251d8fb
@ -34,12 +34,6 @@ private:
|
|||||||
* Do not mutate after app creation.
|
* Do not mutate after app creation.
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<const tt::Bundle> _Nullable parameters;
|
std::shared_ptr<const tt::Bundle> _Nullable parameters;
|
||||||
/** @brief @brief Contextual data related to the running app's instance
|
|
||||||
* The app can attach its data to this.
|
|
||||||
* The lifecycle is determined by the on_start and on_stop methods in the AppManifest.
|
|
||||||
* These manifest methods can optionally allocate/free data that is attached here.
|
|
||||||
*/
|
|
||||||
std::shared_ptr<void> _Nullable data;
|
|
||||||
|
|
||||||
std::shared_ptr<App> app;
|
std::shared_ptr<App> app;
|
||||||
|
|
||||||
|
|||||||
@ -23,15 +23,6 @@ namespace service {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::vector<const service::ServiceManifest*> system_services = {
|
|
||||||
&service::loader::manifest,
|
|
||||||
&service::gui::manifest, // depends on loader service
|
|
||||||
&service::statusbar::manifest,
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
|
||||||
&service::screenshot::manifest
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Default apps
|
// region Default apps
|
||||||
@ -125,18 +116,19 @@ static void register_user_apps(const std::vector<const app::AppManifest*>& apps)
|
|||||||
|
|
||||||
static void register_and_start_system_services() {
|
static void register_and_start_system_services() {
|
||||||
TT_LOG_I(TAG, "Registering and starting system services");
|
TT_LOG_I(TAG, "Registering and starting system services");
|
||||||
for (const auto& service_manifest: system_services) {
|
addService(service::loader::manifest);
|
||||||
addService(service_manifest);
|
addService(service::gui::manifest);
|
||||||
tt_check(service::startService(service_manifest->id));
|
addService(service::statusbar::manifest);
|
||||||
}
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
|
addService(service::screenshot::manifest);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_and_start_user_services(const std::vector<const service::ServiceManifest*>& services) {
|
static void register_and_start_user_services(const std::vector<const service::ServiceManifest*>& manifests) {
|
||||||
TT_LOG_I(TAG, "Registering and starting user services");
|
TT_LOG_I(TAG, "Registering and starting user services");
|
||||||
for (auto* manifest : services) {
|
for (auto* manifest : manifests) {
|
||||||
assert(manifest != nullptr);
|
assert(manifest != nullptr);
|
||||||
addService(manifest);
|
addService(*manifest);
|
||||||
tt_check(service::startService(manifest->id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -142,14 +142,20 @@ static int32_t guiMain(TT_UNUSED void* p) {
|
|||||||
|
|
||||||
// region AppManifest
|
// region AppManifest
|
||||||
|
|
||||||
static void start(TT_UNUSED ServiceContext& service) {
|
class GuiService : public Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void onStart(TT_UNUSED ServiceContext& service) override {
|
||||||
|
tt_assert(gui == nullptr);
|
||||||
gui = gui_alloc();
|
gui = gui_alloc();
|
||||||
|
|
||||||
gui->thread->setPriority(THREAD_PRIORITY_SERVICE);
|
gui->thread->setPriority(THREAD_PRIORITY_SERVICE);
|
||||||
gui->thread->start();
|
gui->thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop(TT_UNUSED ServiceContext& service) {
|
void onStop(TT_UNUSED ServiceContext& service) override {
|
||||||
|
tt_assert(gui != nullptr);
|
||||||
lock();
|
lock();
|
||||||
|
|
||||||
ThreadId thread_id = gui->thread->getId();
|
ThreadId thread_id = gui->thread->getId();
|
||||||
@ -160,12 +166,12 @@ static void stop(TT_UNUSED ServiceContext& service) {
|
|||||||
unlock();
|
unlock();
|
||||||
|
|
||||||
gui_free(gui);
|
gui_free(gui);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Gui",
|
.id = "Gui",
|
||||||
.onStart = &start,
|
.createService = create<GuiService>
|
||||||
.onStop = &stop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
@ -295,13 +295,17 @@ static void stopAppInternal() {
|
|||||||
|
|
||||||
// region AppManifest
|
// region AppManifest
|
||||||
|
|
||||||
static void loader_start(TT_UNUSED ServiceContext& service) {
|
class LoaderService final : public Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void onStart(TT_UNUSED ServiceContext& service) final {
|
||||||
tt_check(loader_singleton == nullptr);
|
tt_check(loader_singleton == nullptr);
|
||||||
loader_singleton = loader_alloc();
|
loader_singleton = loader_alloc();
|
||||||
loader_singleton->dispatcherThread->start();
|
loader_singleton->dispatcherThread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_stop(TT_UNUSED ServiceContext& service) {
|
void onStop(TT_UNUSED ServiceContext& service) final {
|
||||||
tt_check(loader_singleton != nullptr);
|
tt_check(loader_singleton != nullptr);
|
||||||
|
|
||||||
// Send stop signal to thread and wait for thread to finish
|
// Send stop signal to thread and wait for thread to finish
|
||||||
@ -314,12 +318,12 @@ static void loader_stop(TT_UNUSED ServiceContext& service) {
|
|||||||
|
|
||||||
loader_free();
|
loader_free();
|
||||||
loader_singleton = nullptr;
|
loader_singleton = nullptr;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Loader",
|
.id = "Loader",
|
||||||
.onStart = &loader_start,
|
.createService = create<LoaderService>
|
||||||
.onStop = &loader_stop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
@ -15,12 +15,7 @@ namespace tt::service::screenshot {
|
|||||||
extern const ServiceManifest manifest;
|
extern const ServiceManifest manifest;
|
||||||
|
|
||||||
std::shared_ptr<ScreenshotService> _Nullable optScreenshotService() {
|
std::shared_ptr<ScreenshotService> _Nullable optScreenshotService() {
|
||||||
ServiceContext* context = service::findServiceById(manifest.id);
|
return service::findServiceById<ScreenshotService>(manifest.id);
|
||||||
if (context != nullptr) {
|
|
||||||
return std::static_pointer_cast<ScreenshotService>(context->getData());
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenshotService::startApps(const char* path) {
|
void ScreenshotService::startApps(const char* path) {
|
||||||
@ -89,14 +84,9 @@ bool ScreenshotService::isTaskStarted() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onStart(ServiceContext& serviceContext) {
|
|
||||||
auto service = std::make_shared<ScreenshotService>();
|
|
||||||
serviceContext.setData(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Screenshot",
|
.id = "Screenshot",
|
||||||
.onStart = onStart
|
.createService = create<ScreenshotService>
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Mutex.h"
|
|
||||||
#include "ScreenshotTask.h"
|
|
||||||
#include "TactilityConfig.h"
|
#include "TactilityConfig.h"
|
||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
|
|
||||||
|
#include "Mutex.h"
|
||||||
|
#include "ScreenshotTask.h"
|
||||||
|
#include "service/Service.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace tt::service::screenshot {
|
namespace tt::service::screenshot {
|
||||||
@ -16,7 +17,7 @@ enum class Mode {
|
|||||||
Apps
|
Apps
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScreenshotService {
|
class ScreenshotService final : public Service {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@ -41,35 +41,6 @@ namespace tt::service::statusbar {
|
|||||||
|
|
||||||
extern const ServiceManifest manifest;
|
extern const ServiceManifest manifest;
|
||||||
|
|
||||||
struct ServiceData {
|
|
||||||
Mutex mutex;
|
|
||||||
std::unique_ptr<Timer> updateTimer;
|
|
||||||
int8_t wifi_icon_id = lvgl::statusbar_icon_add();
|
|
||||||
const char* wifi_last_icon = nullptr;
|
|
||||||
int8_t sdcard_icon_id = lvgl::statusbar_icon_add();
|
|
||||||
const char* sdcard_last_icon = nullptr;
|
|
||||||
int8_t power_icon_id = lvgl::statusbar_icon_add();
|
|
||||||
const char* power_last_icon = nullptr;
|
|
||||||
|
|
||||||
std::unique_ptr<service::Paths> paths;
|
|
||||||
|
|
||||||
~ServiceData() {
|
|
||||||
lvgl::statusbar_icon_remove(wifi_icon_id);
|
|
||||||
lvgl::statusbar_icon_remove(sdcard_icon_id);
|
|
||||||
lvgl::statusbar_icon_remove(power_icon_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lock() const {
|
|
||||||
tt_check(mutex.acquire(TtWaitForever) == TtStatusOk);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const {
|
|
||||||
tt_check(mutex.release() == TtStatusOk);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// region wifi
|
|
||||||
|
|
||||||
const char* getWifiStatusIconForRssi(int rssi) {
|
const char* getWifiStatusIconForRssi(int rssi) {
|
||||||
if (rssi >= -60) {
|
if (rssi >= -60) {
|
||||||
return STATUSBAR_ICON_WIFI_SIGNAL_STRONG_WHITE;
|
return STATUSBAR_ICON_WIFI_SIGNAL_STRONG_WHITE;
|
||||||
@ -98,26 +69,6 @@ static const char* getWifiStatusIcon(wifi::RadioState state, bool secure) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateWifiIcon(const service::Paths* paths, const std::shared_ptr<ServiceData>& data) {
|
|
||||||
wifi::RadioState radio_state = wifi::getRadioState();
|
|
||||||
bool is_secure = wifi::isConnectionSecure();
|
|
||||||
const char* desired_icon = getWifiStatusIcon(radio_state, is_secure);
|
|
||||||
if (data->wifi_last_icon != desired_icon) {
|
|
||||||
if (desired_icon != nullptr) {
|
|
||||||
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
|
||||||
lvgl::statusbar_icon_set_image(data->wifi_icon_id, icon_path);
|
|
||||||
lvgl::statusbar_icon_set_visibility(data->wifi_icon_id, true);
|
|
||||||
} else {
|
|
||||||
lvgl::statusbar_icon_set_visibility(data->wifi_icon_id, false);
|
|
||||||
}
|
|
||||||
data->wifi_last_icon = desired_icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion wifi
|
|
||||||
|
|
||||||
// region sdcard
|
|
||||||
|
|
||||||
static const char* getSdCardStatusIcon(hal::SdCard::State state) {
|
static const char* getSdCardStatusIcon(hal::SdCard::State state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case hal::SdCard::State::Mounted:
|
case hal::SdCard::State::Mounted:
|
||||||
@ -131,27 +82,6 @@ static const char* getSdCardStatusIcon(hal::SdCard::State state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateSdCardIcon(const service::Paths* paths, const std::shared_ptr<ServiceData>& data) {
|
|
||||||
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
|
||||||
if (sdcard != nullptr) {
|
|
||||||
auto state = sdcard->getState();
|
|
||||||
if (state != hal::SdCard::State::Unknown) {
|
|
||||||
auto* desired_icon = getSdCardStatusIcon(state);
|
|
||||||
if (data->sdcard_last_icon != desired_icon) {
|
|
||||||
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
|
||||||
lvgl::statusbar_icon_set_image(data->sdcard_icon_id, icon_path);
|
|
||||||
lvgl::statusbar_icon_set_visibility(data->sdcard_icon_id, true);
|
|
||||||
data->sdcard_last_icon = desired_icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion sdcard
|
|
||||||
|
|
||||||
// region power
|
|
||||||
|
|
||||||
static _Nullable const char* getPowerStatusIcon() {
|
static _Nullable const char* getPowerStatusIcon() {
|
||||||
auto get_power = getConfiguration()->hardware->power;
|
auto get_power = getConfiguration()->hardware->power;
|
||||||
if (get_power == nullptr) {
|
if (get_power == nullptr) {
|
||||||
@ -192,69 +122,120 @@ static _Nullable const char* getPowerStatusIcon() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updatePowerStatusIcon(const service::Paths* paths, const std::shared_ptr<ServiceData>& data) {
|
class StatusbarService final : public Service {
|
||||||
const char* desired_icon = getPowerStatusIcon();
|
|
||||||
if (data->power_last_icon != desired_icon) {
|
private:
|
||||||
|
|
||||||
|
Mutex mutex;
|
||||||
|
std::unique_ptr<Timer> updateTimer;
|
||||||
|
int8_t wifi_icon_id = lvgl::statusbar_icon_add();
|
||||||
|
const char* wifi_last_icon = nullptr;
|
||||||
|
int8_t sdcard_icon_id = lvgl::statusbar_icon_add();
|
||||||
|
const char* sdcard_last_icon = nullptr;
|
||||||
|
int8_t power_icon_id = lvgl::statusbar_icon_add();
|
||||||
|
const char* power_last_icon = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<service::Paths> paths;
|
||||||
|
|
||||||
|
void lock() const {
|
||||||
|
tt_check(mutex.acquire(TtWaitForever) == TtStatusOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() const {
|
||||||
|
tt_check(mutex.release() == TtStatusOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateWifiIcon() {
|
||||||
|
wifi::RadioState radio_state = wifi::getRadioState();
|
||||||
|
bool is_secure = wifi::isConnectionSecure();
|
||||||
|
const char* desired_icon = getWifiStatusIcon(radio_state, is_secure);
|
||||||
|
if (wifi_last_icon != desired_icon) {
|
||||||
if (desired_icon != nullptr) {
|
if (desired_icon != nullptr) {
|
||||||
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
||||||
lvgl::statusbar_icon_set_image(data->power_icon_id, icon_path);
|
lvgl::statusbar_icon_set_image(wifi_icon_id, icon_path);
|
||||||
lvgl::statusbar_icon_set_visibility(data->power_icon_id, true);
|
lvgl::statusbar_icon_set_visibility(wifi_icon_id, true);
|
||||||
} else {
|
} else {
|
||||||
lvgl::statusbar_icon_set_visibility(data->power_icon_id, false);
|
lvgl::statusbar_icon_set_visibility(wifi_icon_id, false);
|
||||||
|
}
|
||||||
|
wifi_last_icon = desired_icon;
|
||||||
}
|
}
|
||||||
data->power_last_icon = desired_icon;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// endregion power
|
void updatePowerStatusIcon() {
|
||||||
|
const char* desired_icon = getPowerStatusIcon();
|
||||||
|
if (power_last_icon != desired_icon) {
|
||||||
|
if (desired_icon != nullptr) {
|
||||||
|
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
||||||
|
lvgl::statusbar_icon_set_image(power_icon_id, icon_path);
|
||||||
|
lvgl::statusbar_icon_set_visibility(power_icon_id, true);
|
||||||
|
} else {
|
||||||
|
lvgl::statusbar_icon_set_visibility(power_icon_id, false);
|
||||||
|
}
|
||||||
|
power_last_icon = desired_icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// region service
|
void updateSdCardIcon() {
|
||||||
|
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
||||||
|
if (sdcard != nullptr) {
|
||||||
|
auto state = sdcard->getState();
|
||||||
|
if (state != hal::SdCard::State::Unknown) {
|
||||||
|
auto* desired_icon = getSdCardStatusIcon(state);
|
||||||
|
if (sdcard_last_icon != desired_icon) {
|
||||||
|
auto icon_path = paths->getSystemPathLvgl(desired_icon);
|
||||||
|
lvgl::statusbar_icon_set_image(sdcard_icon_id, icon_path);
|
||||||
|
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||||
|
sdcard_last_icon = desired_icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void service_data_free(ServiceData* data) {
|
void update() {
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void onUpdate(std::shared_ptr<void> parameter) {
|
|
||||||
auto data = std::static_pointer_cast<ServiceData>(parameter);
|
|
||||||
// TODO: Make thread-safe for LVGL
|
// TODO: Make thread-safe for LVGL
|
||||||
auto* paths = data->paths.get();
|
updateWifiIcon();
|
||||||
updateWifiIcon(paths, data);
|
updateSdCardIcon();
|
||||||
updateSdCardIcon(paths, data);
|
updatePowerStatusIcon();
|
||||||
updatePowerStatusIcon(paths, data);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void onStart(ServiceContext& service) {
|
static void onUpdate(std::shared_ptr<void> parameter) {
|
||||||
lvgl::lock(TtWaitForever);
|
auto service = std::static_pointer_cast<StatusbarService>(parameter);
|
||||||
auto data = std::make_shared<ServiceData>();
|
service->update();
|
||||||
lvgl::unlock();
|
}
|
||||||
|
|
||||||
data->paths = service.getPaths();
|
public:
|
||||||
|
|
||||||
service.setData(data);
|
~StatusbarService() final {
|
||||||
|
lvgl::statusbar_icon_remove(wifi_icon_id);
|
||||||
|
lvgl::statusbar_icon_remove(sdcard_icon_id);
|
||||||
|
lvgl::statusbar_icon_remove(power_icon_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStart(ServiceContext& serviceContext) override {
|
||||||
|
paths = serviceContext.getPaths();
|
||||||
|
|
||||||
// TODO: Make thread-safe for LVGL
|
// TODO: Make thread-safe for LVGL
|
||||||
lvgl::statusbar_icon_set_visibility(data->wifi_icon_id, true);
|
lvgl::statusbar_icon_set_visibility(wifi_icon_id, true);
|
||||||
updateWifiIcon(data->paths.get(), data);
|
|
||||||
updateSdCardIcon(data->paths.get(), data); // also updates visibility
|
|
||||||
updatePowerStatusIcon(data->paths.get(), data);
|
|
||||||
|
|
||||||
data->updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, data);
|
auto service = findServiceById(manifest.id);
|
||||||
|
assert(service);
|
||||||
|
onUpdate(service);
|
||||||
|
|
||||||
|
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, service);
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
data->updateTimer->start(1000);
|
updateTimer->start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onStop(ServiceContext& service) {
|
void onStop(ServiceContext& service) override{
|
||||||
auto data = std::static_pointer_cast<ServiceData>(service.getData());
|
updateTimer->stop();
|
||||||
|
updateTimer = nullptr;
|
||||||
// Stop thread
|
}
|
||||||
data->updateTimer->stop();
|
};
|
||||||
data->updateTimer = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Statusbar",
|
.id = "Statusbar",
|
||||||
.onStart = onStart,
|
.createService = create<StatusbarService>
|
||||||
.onStop = onStop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// endregion service
|
// endregion service
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "service/ServiceContext.h"
|
#include "service/ServiceContext.h"
|
||||||
|
#include "service/Service.h"
|
||||||
|
|
||||||
namespace tt::service {
|
namespace tt::service {
|
||||||
|
|
||||||
@ -9,19 +10,21 @@ class ServiceInstance : public ServiceContext {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
Mutex mutex = Mutex(Mutex::Type::Normal);
|
Mutex mutex = Mutex(Mutex::Type::Normal);
|
||||||
const service::ServiceManifest& manifest;
|
std::shared_ptr<const ServiceManifest> manifest;
|
||||||
std::shared_ptr<void> data = nullptr;
|
std::shared_ptr<Service> service;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit ServiceInstance(const service::ServiceManifest& manifest);
|
explicit ServiceInstance(std::shared_ptr<const service::ServiceManifest> manifest);
|
||||||
~ServiceInstance() override = default;
|
~ServiceInstance() override = default;
|
||||||
|
|
||||||
|
/** @return a reference ot the service's manifest */
|
||||||
const service::ServiceManifest& getManifest() const override;
|
const service::ServiceManifest& getManifest() const override;
|
||||||
std::shared_ptr<void> getData() const override;
|
|
||||||
void setData(std::shared_ptr<void> newData) override;
|
|
||||||
|
|
||||||
|
/** Retrieve the paths that are relevant to this service */
|
||||||
std::unique_ptr<Paths> getPaths() const override;
|
std::unique_ptr<Paths> getPaths() const override;
|
||||||
|
|
||||||
|
std::shared_ptr<Service> getService() const { return service; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,11 @@ class ServiceInstancePaths final : public Paths {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const ServiceManifest& manifest;
|
std::shared_ptr<const ServiceManifest> manifest;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit ServiceInstancePaths(const ServiceManifest& manifest) : manifest(manifest) {}
|
explicit ServiceInstancePaths(std::shared_ptr<const ServiceManifest> manifest) : manifest(std::move(manifest)) {}
|
||||||
~ServiceInstancePaths() final = default;
|
~ServiceInstancePaths() final = default;
|
||||||
|
|
||||||
std::string getDataDirectory() const final;
|
std::string getDataDirectory() const final;
|
||||||
|
|||||||
@ -21,20 +21,12 @@ namespace service::sdcard { extern const ServiceManifest manifest; }
|
|||||||
|
|
||||||
static Dispatcher mainDispatcher;
|
static Dispatcher mainDispatcher;
|
||||||
|
|
||||||
static const service::ServiceManifest* const system_services[] = {
|
|
||||||
&service::sdcard::manifest,
|
|
||||||
&service::wifi::manifest
|
|
||||||
};
|
|
||||||
|
|
||||||
static const hal::Configuration* hardwareConfig = nullptr;
|
static const hal::Configuration* hardwareConfig = nullptr;
|
||||||
|
|
||||||
static void register_and_start_system_services() {
|
static void register_and_start_system_services() {
|
||||||
TT_LOG_I(TAG, "Registering and starting system services");
|
TT_LOG_I(TAG, "Registering and starting system services");
|
||||||
int app_count = sizeof(system_services) / sizeof(service::ServiceManifest*);
|
addService(service::sdcard::manifest);
|
||||||
for (int i = 0; i < app_count; ++i) {
|
addService(service::wifi::manifest);
|
||||||
addService(system_services[i]);
|
|
||||||
tt_check(service::startService(system_services[i]->id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initHeadless(const hal::Configuration& config) {
|
void initHeadless(const hal::Configuration& config) {
|
||||||
|
|||||||
24
TactilityHeadless/Source/service/Service.h
Normal file
24
TactilityHeadless/Source/service/Service.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace tt::service {
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class ServiceContext;
|
||||||
|
|
||||||
|
class Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Service() = default;
|
||||||
|
virtual ~Service() = default;
|
||||||
|
|
||||||
|
virtual void onStart(ServiceContext& serviceContext) {}
|
||||||
|
virtual void onStop(ServiceContext& serviceContext) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::shared_ptr<Service> create() { return std::shared_ptr<T>(new T); }
|
||||||
|
|
||||||
|
}
|
||||||
@ -22,10 +22,7 @@ public:
|
|||||||
|
|
||||||
/** @return a reference ot the service's manifest */
|
/** @return a reference ot the service's manifest */
|
||||||
virtual const service::ServiceManifest& getManifest() const = 0;
|
virtual const service::ServiceManifest& getManifest() const = 0;
|
||||||
/** @return a shared pointer to the data that is attached to the service */
|
|
||||||
virtual std::shared_ptr<void> _Nullable getData() const = 0;
|
|
||||||
/** Set the data for a service. */
|
|
||||||
virtual void setData(std::shared_ptr<void> newData) = 0;
|
|
||||||
/** Retrieve the paths that are relevant to this service */
|
/** Retrieve the paths that are relevant to this service */
|
||||||
virtual std::unique_ptr<Paths> getPaths() const = 0;
|
virtual std::unique_ptr<Paths> getPaths() const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,26 +1,14 @@
|
|||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "service/ServiceInstance.h"
|
#include "service/ServiceInstance.h"
|
||||||
#include "service/ServiceInstancePaths.h"
|
#include "service/ServiceInstancePaths.h"
|
||||||
|
|
||||||
namespace tt::service {
|
namespace tt::service {
|
||||||
|
|
||||||
ServiceInstance::ServiceInstance(const service::ServiceManifest&manifest) : manifest(manifest) {}
|
ServiceInstance::ServiceInstance(std::shared_ptr<const service::ServiceManifest> manifest) :
|
||||||
|
manifest(manifest),
|
||||||
|
service(manifest->createService())
|
||||||
|
{}
|
||||||
|
|
||||||
const service::ServiceManifest& ServiceInstance::getManifest() const { return manifest; }
|
const service::ServiceManifest& ServiceInstance::getManifest() const { return *manifest; }
|
||||||
|
|
||||||
std::shared_ptr<void> ServiceInstance::getData() const {
|
|
||||||
mutex.acquire(TtWaitForever);
|
|
||||||
std::shared_ptr<void> result = data;
|
|
||||||
mutex.release();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInstance::setData(std::shared_ptr<void> newData) {
|
|
||||||
mutex.acquire(TtWaitForever);
|
|
||||||
data = std::move(newData);
|
|
||||||
mutex.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Paths> ServiceInstance::getPaths() const {
|
std::unique_ptr<Paths> ServiceInstance::getPaths() const {
|
||||||
return std::make_unique<ServiceInstancePaths>(manifest);
|
return std::make_unique<ServiceInstancePaths>(manifest);
|
||||||
|
|||||||
@ -11,38 +11,38 @@
|
|||||||
namespace tt::service {
|
namespace tt::service {
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getDataDirectory() const {
|
std::string ServiceInstancePaths::getDataDirectory() const {
|
||||||
return PARTITION_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest.id;
|
return PARTITION_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getDataDirectoryLvgl() const {
|
std::string ServiceInstancePaths::getDataDirectoryLvgl() const {
|
||||||
return LVGL_PATH_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest.id;
|
return LVGL_PATH_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getDataPath(const std::string& childPath) const {
|
std::string ServiceInstancePaths::getDataPath(const std::string& childPath) const {
|
||||||
assert(!childPath.starts_with('/'));
|
assert(!childPath.starts_with('/'));
|
||||||
return PARTITION_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest.id + '/' + childPath;
|
return PARTITION_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getDataPathLvgl(const std::string& childPath) const {
|
std::string ServiceInstancePaths::getDataPathLvgl(const std::string& childPath) const {
|
||||||
assert(!childPath.starts_with('/'));
|
assert(!childPath.starts_with('/'));
|
||||||
return LVGL_PATH_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest.id + '/' + childPath;
|
return LVGL_PATH_PREFIX + DATA_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getSystemDirectory() const {
|
std::string ServiceInstancePaths::getSystemDirectory() const {
|
||||||
return PARTITION_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest.id;
|
return PARTITION_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getSystemDirectoryLvgl() const {
|
std::string ServiceInstancePaths::getSystemDirectoryLvgl() const {
|
||||||
return LVGL_PATH_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest.id;
|
return LVGL_PATH_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getSystemPath(const std::string& childPath) const {
|
std::string ServiceInstancePaths::getSystemPath(const std::string& childPath) const {
|
||||||
assert(!childPath.starts_with('/'));
|
assert(!childPath.starts_with('/'));
|
||||||
return PARTITION_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest.id + '/' + childPath;
|
return PARTITION_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServiceInstancePaths::getSystemPathLvgl(const std::string& childPath) const {
|
std::string ServiceInstancePaths::getSystemPathLvgl(const std::string& childPath) const {
|
||||||
return LVGL_PATH_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest.id + '/' + childPath;
|
return LVGL_PATH_PREFIX + SYSTEM_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "service/Service.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace tt::service {
|
namespace tt::service {
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
class ServiceContext;
|
class ServiceContext;
|
||||||
|
|
||||||
typedef void (*ServiceOnStart)(ServiceContext& service);
|
typedef std::shared_ptr<Service>(*CreateService)();
|
||||||
typedef void (*ServiceOnStop)(ServiceContext& service);
|
|
||||||
|
|
||||||
/** A ledger that describes the main parts of a service. */
|
/** A ledger that describes the main parts of a service. */
|
||||||
struct ServiceManifest {
|
struct ServiceManifest {
|
||||||
/** The identifier by which the app is launched by the system and other apps. */
|
/** The identifier by which the app is launched by the system and other apps. */
|
||||||
std::string id {};
|
std::string id {};
|
||||||
|
|
||||||
/** Non-blocking method to call when service is started. */
|
/** Create the instance of the app */
|
||||||
const ServiceOnStart onStart = nullptr;
|
CreateService createService = nullptr;
|
||||||
|
|
||||||
/** Non-blocking method to call when service is stopped. */
|
|
||||||
const ServiceOnStop onStop = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "service/ServiceInstance.h"
|
#include "service/ServiceInstance.h"
|
||||||
#include "service/ServiceManifest.h"
|
#include "service/ServiceManifest.h"
|
||||||
#include "TactilityCore.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@ -11,8 +10,8 @@ namespace tt::service {
|
|||||||
|
|
||||||
#define TAG "service_registry"
|
#define TAG "service_registry"
|
||||||
|
|
||||||
typedef std::unordered_map<std::string, const ServiceManifest*> ManifestMap;
|
typedef std::unordered_map<std::string, std::shared_ptr<const ServiceManifest>> ManifestMap;
|
||||||
typedef std::unordered_map<std::string, ServiceInstance*> ServiceInstanceMap;
|
typedef std::unordered_map<std::string, std::shared_ptr<ServiceInstance>> ServiceInstanceMap;
|
||||||
|
|
||||||
static ManifestMap service_manifest_map;
|
static ManifestMap service_manifest_map;
|
||||||
static ServiceInstanceMap service_instance_map;
|
static ServiceInstanceMap service_instance_map;
|
||||||
@ -20,30 +19,41 @@ static ServiceInstanceMap service_instance_map;
|
|||||||
static Mutex manifest_mutex(Mutex::Type::Normal);
|
static Mutex manifest_mutex(Mutex::Type::Normal);
|
||||||
static Mutex instance_mutex(Mutex::Type::Normal);
|
static Mutex instance_mutex(Mutex::Type::Normal);
|
||||||
|
|
||||||
void addService(const ServiceManifest* manifest) {
|
void addService(std::shared_ptr<const ServiceManifest> manifest, bool autoStart) {
|
||||||
TT_LOG_I(TAG, "Adding %s", manifest->id.c_str());
|
// We'll move the manifest pointer, but we'll need to id later
|
||||||
|
std::string id = manifest->id;
|
||||||
|
|
||||||
manifest_mutex.acquire(TtWaitForever);
|
TT_LOG_I(TAG, "Adding %s", id.c_str());
|
||||||
if (service_manifest_map[manifest->id] == nullptr) {
|
|
||||||
service_manifest_map[manifest->id] = manifest;
|
manifest_mutex.lock(TtWaitForever);
|
||||||
|
if (service_manifest_map[id] == nullptr) {
|
||||||
|
service_manifest_map[id] = std::move(manifest);
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_E(TAG, "Service id in use: %s", manifest->id.c_str());
|
TT_LOG_E(TAG, "Service id in use: %s", id.c_str());
|
||||||
|
}
|
||||||
|
manifest_mutex.unlock();
|
||||||
|
|
||||||
|
if (autoStart) {
|
||||||
|
startService(id);
|
||||||
}
|
}
|
||||||
manifest_mutex.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServiceManifest* _Nullable findManifestId(const std::string& id) {
|
void addService(const ServiceManifest& manifest, bool autoStart) {
|
||||||
|
addService(std::make_shared<const ServiceManifest>(manifest), autoStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const ServiceManifest> _Nullable findManifestId(const std::string& id) {
|
||||||
manifest_mutex.acquire(TtWaitForever);
|
manifest_mutex.acquire(TtWaitForever);
|
||||||
auto iterator = service_manifest_map.find(id);
|
auto iterator = service_manifest_map.find(id);
|
||||||
_Nullable const ServiceManifest * manifest = iterator != service_manifest_map.end() ? iterator->second : nullptr;
|
auto manifest = iterator != service_manifest_map.end() ? iterator->second : nullptr;
|
||||||
manifest_mutex.release();
|
manifest_mutex.release();
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ServiceInstance* _Nullable service_registry_find_instance_by_id(const std::string& id) {
|
static std::shared_ptr<ServiceInstance> _Nullable findServiceInstanceById(const std::string& id) {
|
||||||
manifest_mutex.acquire(TtWaitForever);
|
manifest_mutex.acquire(TtWaitForever);
|
||||||
auto iterator = service_instance_map.find(id);
|
auto iterator = service_instance_map.find(id);
|
||||||
_Nullable ServiceInstance* service = iterator != service_instance_map.end() ? iterator->second : nullptr;
|
auto service = iterator != service_instance_map.end() ? iterator->second : nullptr;
|
||||||
manifest_mutex.release();
|
manifest_mutex.release();
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
@ -51,42 +61,53 @@ static ServiceInstance* _Nullable service_registry_find_instance_by_id(const std
|
|||||||
// TODO: Return proper error/status instead of BOOL?
|
// TODO: Return proper error/status instead of BOOL?
|
||||||
bool startService(const std::string& id) {
|
bool startService(const std::string& id) {
|
||||||
TT_LOG_I(TAG, "Starting %s", id.c_str());
|
TT_LOG_I(TAG, "Starting %s", id.c_str());
|
||||||
const ServiceManifest* manifest = findManifestId(id);
|
auto manifest = findManifestId(id);
|
||||||
if (manifest == nullptr) {
|
if (manifest == nullptr) {
|
||||||
TT_LOG_E(TAG, "manifest not found for service %s", id.c_str());
|
TT_LOG_E(TAG, "manifest not found for service %s", id.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* service = new ServiceInstance(*manifest);
|
auto service_instance = std::make_shared<ServiceInstance>(manifest);
|
||||||
manifest->onStart(*service);
|
|
||||||
|
|
||||||
|
// Register first, so that a service can retrieve itself during onStart()
|
||||||
instance_mutex.acquire(TtWaitForever);
|
instance_mutex.acquire(TtWaitForever);
|
||||||
service_instance_map[manifest->id] = service;
|
service_instance_map[manifest->id] = service_instance;
|
||||||
instance_mutex.release();
|
instance_mutex.release();
|
||||||
|
|
||||||
|
service_instance->getService()->onStart(*service_instance);
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Started %s", id.c_str());
|
TT_LOG_I(TAG, "Started %s", id.c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Nullable ServiceContext* findServiceById(const std::string& service_id) {
|
std::shared_ptr<ServiceContext> _Nullable findServiceContextById(const std::string& id) {
|
||||||
return static_cast<ServiceInstance*>(service_registry_find_instance_by_id(service_id));
|
return findServiceInstanceById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Service> _Nullable findServiceById(const std::string& id) {
|
||||||
|
auto instance = findServiceInstanceById(id);
|
||||||
|
return instance != nullptr ? instance->getService() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool stopService(const std::string& id) {
|
bool stopService(const std::string& id) {
|
||||||
TT_LOG_I(TAG, "Stopping %s", id.c_str());
|
TT_LOG_I(TAG, "Stopping %s", id.c_str());
|
||||||
ServiceInstance* service = service_registry_find_instance_by_id(id);
|
auto service_instance = findServiceInstanceById(id);
|
||||||
if (service == nullptr) {
|
if (service_instance == nullptr) {
|
||||||
TT_LOG_W(TAG, "service not running: %s", id.c_str());
|
TT_LOG_W(TAG, "service not running: %s", id.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
service->getManifest().onStop(*service);
|
service_instance->getService()->onStop(*service_instance);
|
||||||
delete service;
|
|
||||||
|
|
||||||
instance_mutex.acquire(TtWaitForever);
|
instance_mutex.acquire(TtWaitForever);
|
||||||
service_instance_map.erase(id);
|
service_instance_map.erase(id);
|
||||||
instance_mutex.release();
|
instance_mutex.release();
|
||||||
|
|
||||||
|
if (service_instance.use_count() > 1) {
|
||||||
|
TT_LOG_W(TAG, "Possible memory leak: service %s still has %ld references", service_instance->getManifest().id.c_str(), service_instance.use_count() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
TT_LOG_I(TAG, "Stopped %s", id.c_str());
|
TT_LOG_I(TAG, "Stopped %s", id.c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "service/ServiceManifest.h"
|
#include "service/ServiceManifest.h"
|
||||||
|
#include "service/Service.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace tt::service {
|
namespace tt::service {
|
||||||
|
|
||||||
void initRegistry();
|
|
||||||
|
|
||||||
/** Register a service.
|
/** Register a service.
|
||||||
* @param[in] the service manifest
|
* @param[in] the service manifest
|
||||||
*/
|
*/
|
||||||
void addService(const ServiceManifest* manifest);
|
void addService(std::shared_ptr<const ServiceManifest> manifest, bool autoStart = true);
|
||||||
|
|
||||||
/** Unregister a service.
|
/** Register a service.
|
||||||
* @param[in] the service manifest
|
* @param[in] the service manifest
|
||||||
*/
|
*/
|
||||||
void removeService(const ServiceManifest* manifest);
|
void addService(const ServiceManifest& manifest, bool autoStart = true);
|
||||||
|
|
||||||
/** Start a service.
|
/** Start a service.
|
||||||
* @param[in] the service id as defined in its manifest
|
* @param[in] the service id as defined in its manifest
|
||||||
@ -32,12 +32,27 @@ bool stopService(const std::string& id);
|
|||||||
* @param[in] id the id as defined in the manifest
|
* @param[in] id the id as defined in the manifest
|
||||||
* @return the matching manifest or nullptr when it wasn't found
|
* @return the matching manifest or nullptr when it wasn't found
|
||||||
*/
|
*/
|
||||||
const ServiceManifest* _Nullable findManifestId(const std::string& id);
|
std::shared_ptr<const ServiceManifest> _Nullable findManifestId(const std::string& id);
|
||||||
|
|
||||||
/** Find a service by its manifest id.
|
/** Find a ServiceContext by its manifest id.
|
||||||
* @param[in] id the id as defined in the manifest
|
* @param[in] id the id as defined in the manifest
|
||||||
* @return the service context or nullptr when it wasn't found
|
* @return the service context or nullptr when it wasn't found
|
||||||
*/
|
*/
|
||||||
ServiceContext* _Nullable findServiceById(const std::string& id);
|
std::shared_ptr<ServiceContext> _Nullable findServiceContextById(const std::string& id);
|
||||||
|
|
||||||
|
/** Find a Service by its manifest id.
|
||||||
|
* @param[in] id the id as defined in the manifest
|
||||||
|
* @return the service context or nullptr when it wasn't found
|
||||||
|
*/
|
||||||
|
std::shared_ptr<Service> _Nullable findServiceById(const std::string& id);
|
||||||
|
|
||||||
|
/** Find a Service by its manifest id.
|
||||||
|
* @param[in] id the id as defined in the manifest
|
||||||
|
* @return the service context or nullptr when it wasn't found
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<T> _Nullable findServiceById(const std::string& id) {
|
||||||
|
return std::static_pointer_cast<T>(findServiceById(id));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -11,7 +11,10 @@ namespace tt::service::sdcard {
|
|||||||
|
|
||||||
extern const ServiceManifest manifest;
|
extern const ServiceManifest manifest;
|
||||||
|
|
||||||
struct ServiceData {
|
class SdCardService final : public Service {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
std::unique_ptr<Timer> updateTimer;
|
std::unique_ptr<Timer> updateTimer;
|
||||||
hal::SdCard::State lastState = hal::SdCard::State::Unmounted;
|
hal::SdCard::State lastState = hal::SdCard::State::Unmounted;
|
||||||
@ -23,21 +26,12 @@ struct ServiceData {
|
|||||||
void unlock() const {
|
void unlock() const {
|
||||||
tt_check(mutex.release() == TtStatusOk);
|
tt_check(mutex.release() == TtStatusOk);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
static void onUpdate(std::shared_ptr<void> context) {
|
void update() {
|
||||||
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
auto sdcard = tt::hal::getConfiguration()->sdcard;
|
||||||
if (sdcard == nullptr) {
|
tt_assert(sdcard);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = std::static_pointer_cast<ServiceData>(context);
|
|
||||||
|
|
||||||
if (!data->lock(50)) {
|
|
||||||
TT_LOG_W(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (lock(50)) {
|
||||||
auto new_state = sdcard->getState();
|
auto new_state = sdcard->getState();
|
||||||
|
|
||||||
if (new_state == hal::SdCard::State::Error) {
|
if (new_state == hal::SdCard::State::Error) {
|
||||||
@ -45,39 +39,46 @@ static void onUpdate(std::shared_ptr<void> context) {
|
|||||||
sdcard->unmount();
|
sdcard->unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_state != data->lastState) {
|
if (new_state != lastState) {
|
||||||
data->lastState = new_state;
|
lastState = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->unlock();
|
unlock();
|
||||||
}
|
|
||||||
|
|
||||||
static void onStart(ServiceContext& service) {
|
|
||||||
if (hal::getConfiguration()->sdcard != nullptr) {
|
|
||||||
auto data = std::make_shared<ServiceData>();
|
|
||||||
service.setData(data);
|
|
||||||
|
|
||||||
data->updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, data);
|
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
|
||||||
data->updateTimer->start(1000);
|
|
||||||
} else {
|
} else {
|
||||||
TT_LOG_I(TAG, "task not started due to config");
|
TT_LOG_W(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void onStop(ServiceContext& service) {
|
static void onUpdate(std::shared_ptr<void> context) {
|
||||||
auto data = std::static_pointer_cast<ServiceData>(service.getData());
|
auto service = std::static_pointer_cast<SdCardService>(context);
|
||||||
if (data->updateTimer != nullptr) {
|
service->update();
|
||||||
// Stop thread
|
|
||||||
data->updateTimer->stop();
|
|
||||||
data->updateTimer = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void onStart(ServiceContext& serviceContext) final {
|
||||||
|
if (hal::getConfiguration()->sdcard != nullptr) {
|
||||||
|
auto service = findServiceById(manifest.id);
|
||||||
|
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, onUpdate, service);
|
||||||
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
|
updateTimer->start(1000);
|
||||||
|
} else {
|
||||||
|
TT_LOG_I(TAG, "Timer not started: no SD card config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStop(ServiceContext& serviceContext) final {
|
||||||
|
if (updateTimer != nullptr) {
|
||||||
|
// Stop thread
|
||||||
|
updateTimer->stop();
|
||||||
|
updateTimer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "sdcard",
|
.id = "sdcard",
|
||||||
.onStart = onStart,
|
.createService = create<SdCardService>
|
||||||
.onStop = onStop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -936,12 +936,14 @@ void onAutoConnectTimer(std::shared_ptr<void> context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onStart(ServiceContext& service) {
|
class WifiService final : public Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void onStart(ServiceContext& service) override {
|
||||||
tt_assert(wifi_singleton == nullptr);
|
tt_assert(wifi_singleton == nullptr);
|
||||||
wifi_singleton = std::make_shared<Wifi>();
|
wifi_singleton = std::make_shared<Wifi>();
|
||||||
|
|
||||||
service.setData(wifi_singleton);
|
|
||||||
|
|
||||||
wifi_singleton->autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, onAutoConnectTimer, wifi_singleton);
|
wifi_singleton->autoConnectTimer = std::make_unique<Timer>(Timer::Type::Periodic, onAutoConnectTimer, wifi_singleton);
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
// We want to try and scan more often in case of startup or scan lock failure
|
||||||
wifi_singleton->autoConnectTimer->start(TT_MIN(2000, AUTO_SCAN_INTERVAL));
|
wifi_singleton->autoConnectTimer->start(TT_MIN(2000, AUTO_SCAN_INTERVAL));
|
||||||
@ -950,9 +952,9 @@ static void onStart(ServiceContext& service) {
|
|||||||
TT_LOG_I(TAG, "Auto-enabling due to setting");
|
TT_LOG_I(TAG, "Auto-enabling due to setting");
|
||||||
getMainDispatcher().dispatch(dispatchEnable, wifi_singleton);
|
getMainDispatcher().dispatch(dispatchEnable, wifi_singleton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onStop(ServiceContext& service) {
|
void onStop(ServiceContext& service) override {
|
||||||
auto wifi = wifi_singleton;
|
auto wifi = wifi_singleton;
|
||||||
tt_assert(wifi != nullptr);
|
tt_assert(wifi != nullptr);
|
||||||
|
|
||||||
@ -976,12 +978,12 @@ static void onStop(ServiceContext& service) {
|
|||||||
wifi->radioMutex.release();
|
wifi->radioMutex.release();
|
||||||
|
|
||||||
// Release (hopefully) last Wifi instance by scope
|
// Release (hopefully) last Wifi instance by scope
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Wifi",
|
.id = "Wifi",
|
||||||
.onStart = onStart,
|
.createService = create<WifiService>
|
||||||
.onStop = onStop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -137,25 +137,25 @@ int getRssi() {
|
|||||||
|
|
||||||
// endregion Public functions
|
// endregion Public functions
|
||||||
|
|
||||||
static void service_start(TT_UNUSED ServiceContext& service) {
|
class WifiService final : public Service {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void onStart(TT_UNUSED ServiceContext& service) final {
|
||||||
tt_check(wifi == nullptr);
|
tt_check(wifi == nullptr);
|
||||||
wifi = new Wifi();
|
wifi = new Wifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_stop(TT_UNUSED ServiceContext& service) {
|
void onStop(TT_UNUSED ServiceContext& service) final {
|
||||||
tt_check(wifi != nullptr);
|
tt_check(wifi != nullptr);
|
||||||
delete wifi;
|
delete wifi;
|
||||||
wifi = nullptr;
|
wifi = nullptr;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
void wifi_main(void*) {
|
|
||||||
// NO-OP
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
extern const ServiceManifest manifest = {
|
||||||
.id = "Wifi",
|
.id = "Wifi",
|
||||||
.onStart = &service_start,
|
.createService = create<WifiService>
|
||||||
.onStop = &service_stop
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user