implemented service registry (#8)
+ implemented app and service context for data sharing
This commit is contained in:
committed by
GitHub
parent
051b1548ec
commit
83e226f696
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 {
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user