implemented service registry (#8)

+ implemented app and service context for data sharing
This commit is contained in:
Ken Van Hoeylandt
2024-01-06 20:37:41 +01:00
committed by GitHub
parent 051b1548ec
commit 83e226f696
25 changed files with 282 additions and 101 deletions
+3 -7
View File
@@ -8,7 +8,9 @@
App* furi_app_alloc(const AppManifest* _Nonnull manifest) {
App app = {
.manifest = manifest,
.ep_thread_args = NULL
.context = {
.data = NULL
}
};
App* app_ptr = malloc(sizeof(App));
return memcpy(app_ptr, &app, sizeof(App));
@@ -16,11 +18,5 @@ App* furi_app_alloc(const AppManifest* _Nonnull manifest) {
void furi_app_free(App* app) {
furi_assert(app);
if (app->ep_thread_args) {
free(app->ep_thread_args);
app->ep_thread_args = NULL;
}
free(app);
}
+1 -3
View File
@@ -9,11 +9,9 @@ extern "C" {
typedef struct {
const AppManifest* manifest;
void* ep_thread_args;
Context context;
} App;
const char* furi_app_type_to_string(AppType type);
FuriThread* furi_app_alloc_thread(App* _Nonnull app, const char* args);
App* furi_app_alloc(const AppManifest* _Nonnull manifest);
void furi_app_free(App* _Nonnull app);
+6 -5
View File
@@ -1,5 +1,6 @@
#pragma once
#include "context.h"
#include <stdio.h>
#ifdef __cplusplus
@@ -15,20 +16,20 @@ typedef enum {
AppTypeUser
} AppType;
typedef void (*AppOnStart)(void _Nonnull* parameter);
typedef void (*AppOnStop)();
typedef void (*AppOnShow)(lv_obj_t* parent, void* context);
typedef void (*AppOnStart)(Context* context);
typedef void (*AppOnStop)(Context* context);
typedef void (*AppOnShow)(Context* context, lv_obj_t* parent);
typedef struct {
/**
* The identifier by which the app is launched by the system and other apps.
*/
const char* _Nonnull id;
const char* id;
/**
* The user-readable name of the app. Used in UI.
*/
const char* _Nonnull name;
const char* name;
/**
* Optional icon.
+11
View File
@@ -0,0 +1,11 @@
#pragma once
typedef struct {
/** 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.
*/
void* data;
} Context;
+3
View File
@@ -1,7 +1,9 @@
#include "furi.h"
#include "app_manifest_registry.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "service_registry.h"
#define TAG "furi"
@@ -22,6 +24,7 @@ void furi_init() {
NVIC_SetPriority(SVCall_IRQn, 0U);
#endif
service_registry_init();
app_manifest_registry_init();
FURI_LOG_I(TAG, "init complete");
}
+21
View File
@@ -0,0 +1,21 @@
#include "service_i.h"
#include "furi_core.h"
#include "log.h"
#define TAG "service"
Service* furi_service_alloc(const ServiceManifest* _Nonnull manifest) {
Service app = {
.manifest = manifest,
.context = {
.data = NULL
}
};
Service* app_ptr = malloc(sizeof(Service));
return memcpy(app_ptr, &app, sizeof(Service));
}
void furi_service_free(Service* app) {
furi_assert(app);
free(app);
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "service_manifest.h"
#include "context.h"
typedef struct {
const ServiceManifest* manifest;
Context context;
} Service;
Service* furi_service_alloc(const ServiceManifest* _Nonnull manifest);
void furi_service_free(Service* _Nonnull service);
+3 -2
View File
@@ -1,13 +1,14 @@
#pragma once
#include <stdio.h>
#include "context.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*ServiceOnStart)(void _Nonnull* parameter);
typedef void (*ServiceOnStop)();
typedef void (*ServiceOnStart)(Context* context);
typedef void (*ServiceOnStop)(Context* context);
typedef struct {
/**
+136
View File
@@ -0,0 +1,136 @@
#include "service_registry.h"
#include "furi_core.h"
#include "m-dict.h"
#include "m_cstr_dup.h"
#include "mutex.h"
#include "service_i.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 Service*, 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(); \
}
ServiceManifestDict_t service_manifest_dict;
ServiceInstanceDict_t service_instance_dict;
FuriMutex* manifest_mutex = NULL;
FuriMutex* instance_mutex = NULL;
void service_registry_init() {
furi_assert(manifest_mutex == NULL);
manifest_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
ServiceManifestDict_init(service_manifest_dict);
furi_assert(instance_mutex == NULL);
instance_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
ServiceInstanceDict_init(service_instance_dict);
}
void service_registry_instance_lock() {
furi_assert(instance_mutex != NULL);
furi_mutex_acquire(instance_mutex, FuriWaitForever);
}
void service_registry_instance_unlock() {
furi_assert(instance_mutex != NULL);
furi_mutex_release(instance_mutex);
}
void service_registry_manifest_lock() {
furi_assert(manifest_mutex != NULL);
furi_mutex_acquire(manifest_mutex, FuriWaitForever);
}
void service_registry_manifest_unlock() {
furi_assert(manifest_mutex != NULL);
furi_mutex_release(manifest_mutex);
}
void service_registry_add(const ServiceManifest _Nonnull* manifest) {
FURI_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 service_registry_remove(const ServiceManifest _Nonnull* manifest) {
FURI_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 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;
}
Service* _Nullable service_registry_find_instance_by_id(const char* id) {
service_registry_instance_lock();
const Service** _Nullable service_ptr = ServiceInstanceDict_get(service_instance_dict, id);
if (service_ptr == NULL) {
return NULL;
}
Service* service = (Service*) *service_ptr;
service_registry_instance_unlock();
return service;
}
void 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 service_registry_start(const char* service_id) {
FURI_LOG_I(TAG, "starting %s", service_id);
const ServiceManifest* manifest = service_registry_find_manifest_by_id(service_id);
if (manifest == NULL) {
FURI_LOG_I(TAG, "manifest not found for %s", service_id);
return false;
}
Service* service = furi_service_alloc(manifest);
service->manifest->on_start(&service->context);
service_registry_instance_lock();
ServiceInstanceDict_set_at(service_instance_dict, manifest->id, service);
service_registry_instance_unlock();
FURI_LOG_I(TAG, "started %s", service_id);
return true;
}
bool service_registry_stop(const char* service_id) {
FURI_LOG_I(TAG, "stopping %s", service_id);
Service* service = service_registry_find_instance_by_id(service_id);
if (service == NULL) {
FURI_LOG_I(TAG, "service not running: %s", service_id);
return false;
}
service->manifest->on_stop(&service->context);
furi_service_free(service);
service_registry_instance_lock();
ServiceInstanceDict_erase(service_instance_dict, service_id);
service_registry_instance_unlock();
FURI_LOG_I(TAG, "stopped %s", service_id);
return true;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "service_manifest.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
typedef void (*ServiceManifestCallback)(const ServiceManifest*, void* context);
void service_registry_init();
void service_registry_add(const ServiceManifest* manifest);
void service_registry_remove(const ServiceManifest* manifest);
const ServiceManifest _Nullable* service_registry_find_manifest_by_id(const char* id);
void service_registry_for_each_manifest(ServiceManifestCallback callback, void* _Nullable context);
bool service_registry_start(const char* service_id);
bool service_registry_stop(const char* service_id);
#ifdef __cplusplus
}
#endif