Tactility/tactility-headless/src/service_registry.c
Ken Van Hoeylandt 27730260e0
Project restructuring: add tactility-headless (#55)
- 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
2024-08-31 17:56:28 +02:00

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;
}