mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-04-18 17:35:05 +00:00
- Created `tactility-headless` to support ESP32 firmwares that don't require graphics - `tactility` subproject now contains both PC and ESP32 code (to avoid having to split up `tactility` and `tactility-headless` into separate projects, which would result in a very complex dependency tree) - `tactility` subproject is now defined as component for ESP32 and as regular module for PC - Improvements for dispatcher - Added `project-structure.puml` to docs - `Gui` service now depends on `Loader` service instead of the reverse - Added `statusbar_updater` service for updating Wi-Fi and SD card icons
146 lines
5.5 KiB
C
146 lines
5.5 KiB
C
#include "service_registry.h"
|
|
|
|
#include "m-dict.h"
|
|
#include "m_cstr_dup.h"
|
|
#include "mutex.h"
|
|
#include "service_i.h"
|
|
#include "service_manifest.h"
|
|
#include "tactility_core.h"
|
|
|
|
#define TAG "service_registry"
|
|
|
|
DICT_DEF2(ServiceManifestDict, const char*, M_CSTR_DUP_OPLIST, const ServiceManifest*, M_PTR_OPLIST)
|
|
DICT_DEF2(ServiceInstanceDict, const char*, M_CSTR_DUP_OPLIST, const ServiceData*, M_PTR_OPLIST)
|
|
|
|
#define APP_REGISTRY_FOR_EACH(manifest_var_name, code_to_execute) \
|
|
{ \
|
|
service_registry_manifest_lock(); \
|
|
ServiceManifestDict_it_t it; \
|
|
for (ServiceManifestDict_it(it, service_manifest_dict); !ServiceManifestDict_end_p(it); ServiceManifestDict_next(it)) { \
|
|
const ServiceManifest*(manifest_var_name) = ServiceManifestDict_cref(it)->value; \
|
|
code_to_execute; \
|
|
} \
|
|
service_registry_manifest_unlock(); \
|
|
}
|
|
|
|
static ServiceManifestDict_t service_manifest_dict;
|
|
static ServiceInstanceDict_t service_instance_dict;
|
|
static Mutex* manifest_mutex = NULL;
|
|
static Mutex* instance_mutex = NULL;
|
|
|
|
void tt_service_registry_init() {
|
|
tt_assert(manifest_mutex == NULL);
|
|
manifest_mutex = tt_mutex_alloc(MutexTypeNormal);
|
|
ServiceManifestDict_init(service_manifest_dict);
|
|
|
|
tt_assert(instance_mutex == NULL);
|
|
instance_mutex = tt_mutex_alloc(MutexTypeNormal);
|
|
ServiceInstanceDict_init(service_instance_dict);
|
|
}
|
|
|
|
void service_registry_instance_lock() {
|
|
tt_assert(instance_mutex != NULL);
|
|
tt_mutex_acquire(instance_mutex, TtWaitForever);
|
|
}
|
|
|
|
void service_registry_instance_unlock() {
|
|
tt_assert(instance_mutex != NULL);
|
|
tt_mutex_release(instance_mutex);
|
|
}
|
|
|
|
void service_registry_manifest_lock() {
|
|
tt_assert(manifest_mutex != NULL);
|
|
tt_mutex_acquire(manifest_mutex, TtWaitForever);
|
|
}
|
|
|
|
void service_registry_manifest_unlock() {
|
|
tt_assert(manifest_mutex != NULL);
|
|
tt_mutex_release(manifest_mutex);
|
|
}
|
|
void tt_service_registry_add(const ServiceManifest* manifest) {
|
|
TT_LOG_I(TAG, "adding %s", manifest->id);
|
|
|
|
service_registry_manifest_lock();
|
|
ServiceManifestDict_set_at(service_manifest_dict, manifest->id, manifest);
|
|
service_registry_manifest_unlock();
|
|
}
|
|
|
|
void tt_service_registry_remove(const ServiceManifest* manifest) {
|
|
TT_LOG_I(TAG, "removing %s", manifest->id);
|
|
service_registry_manifest_lock();
|
|
ServiceManifestDict_erase(service_manifest_dict, manifest->id);
|
|
service_registry_manifest_unlock();
|
|
}
|
|
|
|
const ServiceManifest* _Nullable tt_service_registry_find_manifest_by_id(const char* id) {
|
|
service_registry_manifest_lock();
|
|
const ServiceManifest** _Nullable manifest = ServiceManifestDict_get(service_manifest_dict, id);
|
|
service_registry_manifest_unlock();
|
|
return (manifest != NULL) ? *manifest : NULL;
|
|
}
|
|
|
|
ServiceData* _Nullable service_registry_find_instance_by_id(const char* id) {
|
|
service_registry_instance_lock();
|
|
const ServiceData** _Nullable service_ptr = ServiceInstanceDict_get(service_instance_dict, id);
|
|
if (service_ptr == NULL) {
|
|
return NULL;
|
|
}
|
|
ServiceData* service = (ServiceData*)*service_ptr;
|
|
service_registry_instance_unlock();
|
|
return service;
|
|
}
|
|
|
|
void tt_service_registry_for_each_manifest(ServiceManifestCallback callback, void* _Nullable context) {
|
|
APP_REGISTRY_FOR_EACH(manifest, {
|
|
callback(manifest, context);
|
|
});
|
|
}
|
|
|
|
// TODO: return proper error/status instead of BOOL
|
|
bool tt_service_registry_start(const char* service_id) {
|
|
TT_LOG_I(TAG, "starting %s", service_id);
|
|
const ServiceManifest* manifest = tt_service_registry_find_manifest_by_id(service_id);
|
|
if (manifest == NULL) {
|
|
TT_LOG_E(TAG, "manifest not found for service %s", service_id);
|
|
return false;
|
|
}
|
|
|
|
Service service = tt_service_alloc(manifest);
|
|
manifest->on_start(service);
|
|
|
|
service_registry_instance_lock();
|
|
ServiceInstanceDict_set_at(service_instance_dict, manifest->id, service);
|
|
service_registry_instance_unlock();
|
|
TT_LOG_I(TAG, "started %s", service_id);
|
|
|
|
return true;
|
|
}
|
|
|
|
Service _Nullable tt_service_find(const char* service_id) {
|
|
service_registry_instance_lock();
|
|
const ServiceData** _Nullable service_ptr = ServiceInstanceDict_get(service_instance_dict, service_id);
|
|
const ServiceData* service = service_ptr ? *service_ptr : NULL;
|
|
service_registry_instance_unlock();
|
|
return (Service)service;
|
|
}
|
|
|
|
bool tt_service_registry_stop(const char* service_id) {
|
|
TT_LOG_I(TAG, "stopping %s", service_id);
|
|
ServiceData* service = service_registry_find_instance_by_id(service_id);
|
|
if (service == NULL) {
|
|
TT_LOG_W(TAG, "service not running: %s", service_id);
|
|
return false;
|
|
}
|
|
|
|
service->manifest->on_stop(service);
|
|
tt_service_free(service);
|
|
|
|
service_registry_instance_lock();
|
|
ServiceInstanceDict_erase(service_instance_dict, service_id);
|
|
service_registry_instance_unlock();
|
|
|
|
TT_LOG_I(TAG, "stopped %s", service_id);
|
|
|
|
return true;
|
|
}
|