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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 282 additions and 101 deletions

View File

@ -8,7 +8,9 @@
App* furi_app_alloc(const AppManifest* _Nonnull manifest) { App* furi_app_alloc(const AppManifest* _Nonnull manifest) {
App app = { App app = {
.manifest = manifest, .manifest = manifest,
.ep_thread_args = NULL .context = {
.data = NULL
}
}; };
App* app_ptr = malloc(sizeof(App)); App* app_ptr = malloc(sizeof(App));
return memcpy(app_ptr, &app, 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) { void furi_app_free(App* app) {
furi_assert(app); furi_assert(app);
if (app->ep_thread_args) {
free(app->ep_thread_args);
app->ep_thread_args = NULL;
}
free(app); free(app);
} }

View File

@ -9,11 +9,9 @@ extern "C" {
typedef struct { typedef struct {
const AppManifest* manifest; const AppManifest* manifest;
void* ep_thread_args; Context context;
} App; } 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); App* furi_app_alloc(const AppManifest* _Nonnull manifest);
void furi_app_free(App* _Nonnull app); void furi_app_free(App* _Nonnull app);

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "context.h"
#include <stdio.h> #include <stdio.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -15,20 +16,20 @@ typedef enum {
AppTypeUser AppTypeUser
} AppType; } AppType;
typedef void (*AppOnStart)(void _Nonnull* parameter); typedef void (*AppOnStart)(Context* context);
typedef void (*AppOnStop)(); typedef void (*AppOnStop)(Context* context);
typedef void (*AppOnShow)(lv_obj_t* parent, void* context); typedef void (*AppOnShow)(Context* context, lv_obj_t* parent);
typedef struct { typedef struct {
/** /**
* 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.
*/ */
const char* _Nonnull id; const char* id;
/** /**
* The user-readable name of the app. Used in UI. * The user-readable name of the app. Used in UI.
*/ */
const char* _Nonnull name; const char* name;
/** /**
* Optional icon. * Optional icon.

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;

View File

@ -1,7 +1,9 @@
#include "furi.h" #include "furi.h"
#include "app_manifest_registry.h" #include "app_manifest_registry.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "service_registry.h"
#define TAG "furi" #define TAG "furi"
@ -22,6 +24,7 @@ void furi_init() {
NVIC_SetPriority(SVCall_IRQn, 0U); NVIC_SetPriority(SVCall_IRQn, 0U);
#endif #endif
service_registry_init();
app_manifest_registry_init(); app_manifest_registry_init();
FURI_LOG_I(TAG, "init complete"); FURI_LOG_I(TAG, "init complete");
} }

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

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

View File

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <stdio.h> #include <stdio.h>
#include "context.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef void (*ServiceOnStart)(void _Nonnull* parameter); typedef void (*ServiceOnStart)(Context* context);
typedef void (*ServiceOnStop)(); typedef void (*ServiceOnStop)(Context* context);
typedef struct { typedef struct {
/** /**

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

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

View File

@ -5,8 +5,19 @@ idf_component_register(
"src/services/loader" "src/services/loader"
"src/services/gui" "src/services/gui"
"src/services/gui/widgets" "src/services/gui/widgets"
INCLUDE_DIRS "src" INCLUDE_DIRS "src"
REQUIRES esp_lvgl_port esp_lcd esp_lcd_touch driver mlib cmsis_core furi nvs_flash spiffs fatfs
REQUIRES cmsis_core
esp_lcd
esp_lcd_touch
esp_lvgl_port
driver
fatfs
furi
mlib
nvs_flash
spiffs
) )
set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets") set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets")

View File

@ -1,9 +1,9 @@
#include "system_info.h" #include "app_manifest.h"
#include "furi_extra_defines.h" #include "furi_extra_defines.h"
#include "thread.h" #include "thread.h"
#include "lvgl.h" #include "lvgl.h"
static void app_show(lv_obj_t* parent, void* context) { static void app_show(Context* context, lv_obj_t* parent) {
UNUSED(context); UNUSED(context);
lv_obj_t* heap_info = lv_label_create(parent); lv_obj_t* heap_info = lv_label_create(parent);
@ -38,5 +38,5 @@ AppManifest system_info_app = {
.type = AppTypeSystem, .type = AppTypeSystem,
.on_start = NULL, .on_start = NULL,
.on_stop = NULL, .on_stop = NULL,
.on_show = app_show .on_show = &app_show
}; };

View File

@ -1,13 +0,0 @@
#pragma once
#include "app_manifest.h"
#ifdef __cplusplus
extern "C" {
#endif
extern AppManifest system_info_app;
#ifdef __cplusplus
}
#endif

View File

@ -9,7 +9,7 @@ static void on_open_app(lv_event_t* e) {
lv_event_code_t code = lv_event_get_code(e); lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_CLICKED) { if (code == LV_EVENT_CLICKED) {
const AppManifest* manifest = lv_event_get_user_data(e); const AppManifest* manifest = lv_event_get_user_data(e);
loader_start_app_nonblocking(manifest->id, NULL); loader_start_app_nonblocking(manifest->id);
} }
} }
@ -20,7 +20,7 @@ static void add_app_to_list(const AppManifest* manifest, void* _Nullable parent)
lv_obj_add_event_cb(btn, &on_open_app, LV_EVENT_CLICKED, (void*)manifest); lv_obj_add_event_cb(btn, &on_open_app, LV_EVENT_CLICKED, (void*)manifest);
} }
static void desktop_show(lv_obj_t* parent, void* context) { static void desktop_show(Context* context, lv_obj_t* parent) {
lv_obj_t* list = lv_list_create(parent); lv_obj_t* list = lv_list_create(parent);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100)); lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
lv_obj_center(list); lv_obj_center(list);

View File

@ -143,8 +143,8 @@ static int32_t gui_main(void* p) {
// region AppManifest // region AppManifest
static void gui_start(void* parameter) { static void gui_start(Context* context) {
UNUSED(parameter); UNUSED(context);
gui = gui_alloc(); gui = gui_alloc();
@ -152,7 +152,9 @@ static void gui_start(void* parameter) {
furi_thread_start(gui->thread); furi_thread_start(gui->thread);
} }
static void gui_stop() { static void gui_stop(Context* context) {
UNUSED(context);
gui_lock(); gui_lock();
FuriThreadId thread_id = furi_thread_get_id(gui->thread); FuriThreadId thread_id = furi_thread_get_id(gui->thread);

View File

@ -21,7 +21,6 @@ typedef struct Gui Gui;
* *
* @remark thread safe * @remark thread safe
* *
* @param gui Gui instance
* @param view_port ViewPort instance * @param view_port ViewPort instance
* @param[in] layer GuiLayer where to place view_port * @param[in] layer GuiLayer where to place view_port
*/ */
@ -31,7 +30,6 @@ void gui_add_view_port(ViewPort* view_port, GuiLayer layer);
* *
* @remark thread safe * @remark thread safe
* *
* @param gui Gui instance
* @param view_port ViewPort instance * @param view_port ViewPort instance
*/ */
void gui_remove_view_port(ViewPort* view_port); void gui_remove_view_port(ViewPort* view_port);

View File

@ -33,8 +33,6 @@ struct Gui {
}; };
/** Update GUI, request redraw /** Update GUI, request redraw
*
* @param gui Gui instance
*/ */
void gui_request_draw(); void gui_request_draw();
@ -48,13 +46,9 @@ void gui_request_draw();
//void gui_input_events_callback(const void* value, void* ctx); //void gui_input_events_callback(const void* value, void* ctx);
/** Lock GUI /** Lock GUI
*
* @param gui The Gui instance
*/ */
void gui_lock(); void gui_lock();
/** Unlock GUI /** Unlock GUI
*
* @param gui The Gui instance
*/ */
void gui_unlock(); void gui_unlock();

View File

@ -48,7 +48,7 @@ bool view_port_is_enabled(const ViewPort* view_port) {
return is_enabled; return is_enabled;
} }
void view_port_draw_callback_set(ViewPort* view_port, ViewPortDrawCallback callback, void* context) { void view_port_draw_callback_set(ViewPort* view_port, ViewPortDrawCallback callback, Context* context) {
furi_assert(view_port); furi_assert(view_port);
furi_check(furi_mutex_acquire(view_port->mutex, FuriWaitForever) == FuriStatusOk); furi_check(furi_mutex_acquire(view_port->mutex, FuriWaitForever) == FuriStatusOk);
view_port->draw_callback = callback; view_port->draw_callback = callback;
@ -91,7 +91,7 @@ void view_port_draw(ViewPort* view_port, lv_obj_t* parent) {
if (view_port->draw_callback) { if (view_port->draw_callback) {
lv_obj_clean(parent); lv_obj_clean(parent);
lv_obj_set_style_no_padding(parent); lv_obj_set_style_no_padding(parent);
view_port->draw_callback(parent, view_port->draw_callback_context); view_port->draw_callback(view_port->draw_callback_context, parent);
} }
furi_mutex_release(view_port->mutex); furi_mutex_release(view_port->mutex);

View File

@ -5,6 +5,7 @@ extern "C" {
#endif #endif
#include "lvgl.h" #include "lvgl.h"
#include "context.h"
typedef struct ViewPort ViewPort; typedef struct ViewPort ViewPort;
@ -19,7 +20,7 @@ typedef enum {
/** ViewPort Draw callback /** ViewPort Draw callback
* @warning called from GUI thread * @warning called from GUI thread
*/ */
typedef void (*ViewPortDrawCallback)(lv_obj_t* parent, void* context); typedef void (*ViewPortDrawCallback)(Context* context, lv_obj_t* parent);
/** ViewPort allocator /** ViewPort allocator
* *
@ -52,7 +53,7 @@ bool view_port_is_enabled(const ViewPort* view_port);
* @param callback appropriate callback function * @param callback appropriate callback function
* @param context context to pass to callback * @param context context to pass to callback
*/ */
void view_port_draw_callback_set(ViewPort* view_port, ViewPortDrawCallback callback, void* context); void view_port_draw_callback_set(ViewPort* view_port, ViewPortDrawCallback callback, Context* context);
/** Emit update signal to GUI system. /** Emit update signal to GUI system.
* *
* Rendering will happen later after GUI system process signal. * Rendering will happen later after GUI system process signal.

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "context.h"
#include "gui_i.h" #include "gui_i.h"
#include "mutex.h" #include "mutex.h"
#include "view_port.h" #include "view_port.h"
@ -10,7 +11,7 @@ struct ViewPort {
bool is_enabled; bool is_enabled;
ViewPortDrawCallback draw_callback; ViewPortDrawCallback draw_callback;
void* draw_callback_context; Context* draw_callback_context;
/* /*
ViewPortInputCallback input_callback; ViewPortInputCallback input_callback;

View File

@ -27,7 +27,6 @@ static Loader* loader_alloc() {
&loader_main, &loader_main,
NULL NULL
); );
loader->app_data.args = NULL;
loader->app_data.app = NULL; loader->app_data.app = NULL;
loader->app_data.view_port = NULL; loader->app_data.view_port = NULL;
loader->mutex = xSemaphoreCreateRecursiveMutex(); loader->mutex = xSemaphoreCreateRecursiveMutex();
@ -55,13 +54,12 @@ void loader_unlock() {
furi_check(xSemaphoreGiveRecursive(loader->mutex) == pdPASS); furi_check(xSemaphoreGiveRecursive(loader->mutex) == pdPASS);
} }
LoaderStatus loader_start_app(const char* id, const char* args, FuriString* error_message) { LoaderStatus loader_start_app(const char* id, FuriString* error_message) {
LoaderMessage message; LoaderMessage message;
LoaderMessageLoaderStatusResult result; LoaderMessageLoaderStatusResult result;
message.type = LoaderMessageTypeAppStart; message.type = LoaderMessageTypeAppStart;
message.start.id = id; message.start.id = id;
message.start.args = args;
message.start.error_message = error_message; message.start.error_message = error_message;
message.api_lock = api_lock_alloc_locked(); message.api_lock = api_lock_alloc_locked();
message.status_value = &result; message.status_value = &result;
@ -70,13 +68,12 @@ LoaderStatus loader_start_app(const char* id, const char* args, FuriString* erro
return result.value; return result.value;
} }
void loader_start_app_nonblocking(const char* id, const char* args) { void loader_start_app_nonblocking(const char* id) {
LoaderMessage message; LoaderMessage message;
LoaderMessageLoaderStatusResult result; LoaderMessageLoaderStatusResult result;
message.type = LoaderMessageTypeAppStart; message.type = LoaderMessageTypeAppStart;
message.start.id = id; message.start.id = id;
message.start.args = args;
message.start.error_message = NULL; message.start.error_message = NULL;
message.api_lock = NULL; message.api_lock = NULL;
message.status_value = &result; message.status_value = &result;
@ -142,8 +139,7 @@ static LoaderStatus loader_make_success_status(FuriString* error_message) {
} }
static void loader_start_app_with_manifest( static void loader_start_app_with_manifest(
const AppManifest* _Nonnull manifest, const AppManifest* _Nonnull manifest
const char* args
) { ) {
FURI_LOG_I(TAG, "start with manifest %s", manifest->id); FURI_LOG_I(TAG, "start with manifest %s", manifest->id);
@ -156,17 +152,19 @@ static void loader_start_app_with_manifest(
loader_lock(); loader_lock();
loader->app_data.app = app; loader->app_data.app = app;
loader->app_data.args = (void*)args;
if (manifest->on_start != NULL) { if (manifest->on_start != NULL) {
manifest->on_start((void*)args); manifest->on_start(&loader->app_data.app->context);
} }
if (manifest->on_show != NULL) { if (manifest->on_show != NULL) {
ViewPort* view_port = view_port_alloc(); ViewPort* view_port = view_port_alloc();
loader->app_data.view_port = view_port; loader->app_data.view_port = view_port;
view_port_draw_callback_set(view_port, manifest->on_show, NULL); view_port_draw_callback_set(
view_port,
manifest->on_show,
&loader->app_data.app->context
);
gui_add_view_port(view_port, GuiLayerWindow); gui_add_view_port(view_port, GuiLayerWindow);
} else { } else {
loader->app_data.view_port = NULL; loader->app_data.view_port = NULL;
@ -182,7 +180,6 @@ static void loader_start_app_with_manifest(
static LoaderStatus loader_do_start_by_id( static LoaderStatus loader_do_start_by_id(
const char* id, const char* id,
const char* args,
FuriString* _Nullable error_message FuriString* _Nullable error_message
) { ) {
FURI_LOG_I(TAG, "Start by id %s", id); FURI_LOG_I(TAG, "Start by id %s", id);
@ -197,7 +194,7 @@ static LoaderStatus loader_do_start_by_id(
); );
} }
loader_start_app_with_manifest(manifest, args); loader_start_app_with_manifest(manifest);
return loader_make_success_status(error_message); return loader_make_success_status(error_message);
} }
@ -220,12 +217,7 @@ static void loader_do_stop_app() {
} }
if (app->manifest->on_stop) { if (app->manifest->on_stop) {
app->manifest->on_stop(); app->manifest->on_stop(&app->context);
}
if (loader->app_data.args) {
free(loader->app_data.args);
loader->app_data.args = NULL;
} }
furi_app_free(loader->app_data.app); furi_app_free(loader->app_data.app);
@ -268,7 +260,6 @@ static int32_t loader_main(void* p) {
} }
message.status_value->value = loader_do_start_by_id( message.status_value->value = loader_do_start_by_id(
message.start.id, message.start.id,
message.start.args,
message.start.error_message message.start.error_message
); );
if (message.api_lock) { if (message.api_lock) {
@ -290,8 +281,8 @@ static int32_t loader_main(void* p) {
// region AppManifest // region AppManifest
static void loader_start(void* parameter) { static void loader_start(Context* context) {
UNUSED(parameter); UNUSED(context);
furi_check(loader == NULL); furi_check(loader == NULL);
loader = loader_alloc(); loader = loader_alloc();
@ -299,7 +290,8 @@ static void loader_start(void* parameter) {
furi_thread_start(loader->thread); furi_thread_start(loader->thread);
} }
static void loader_stop() { static void loader_stop(Context* context) {
UNUSED(context);
furi_check(loader != NULL); furi_check(loader != NULL);
LoaderMessage message = { LoaderMessage message = {
.api_lock = NULL, .api_lock = NULL,

View File

@ -29,21 +29,19 @@ typedef struct {
/** /**
* @brief Close any running app, then start new one. Blocking. * @brief Close any running app, then start new one. Blocking.
* @param[in] loader loader instance
* @param[in] id application name or id * @param[in] id application name or id
* @param[in] args application arguments * @param[in] args application arguments
* @param[out] error_message detailed error message, can be NULL * @param[out] error_message detailed error message, can be NULL
* @return LoaderStatus * @return LoaderStatus
*/ */
LoaderStatus loader_start_app(const char* id, const char* args, FuriString* error_message); LoaderStatus loader_start_app(const char* id, FuriString* error_message);
/** /**
* @brief Close any running app, then start new one. Non-blocking. * @brief Close any running app, then start new one. Non-blocking.
* @param[in] loader loader instance
* @param[in] id application name or id * @param[in] id application name or id
* @param[in] args application arguments * @param[in] args application arguments
*/ */
void loader_start_app_nonblocking(const char* id, const char* args); void loader_start_app_nonblocking(const char* id);
void loader_stop_app(); void loader_stop_app();
@ -52,7 +50,6 @@ bool loader_is_app_running();
const AppManifest* _Nullable loader_get_current_app(); const AppManifest* _Nullable loader_get_current_app();
/** /**
* @brief Start application with GUI error message * @brief Start application with GUI error message
* @param[in] instance loader instance
* @param[in] name application name or id * @param[in] name application name or id
* @param[in] args application arguments * @param[in] args application arguments
* @return LoaderStatus * @return LoaderStatus
@ -61,13 +58,11 @@ const AppManifest* _Nullable loader_get_current_app();
/** /**
* @brief Show loader menu * @brief Show loader menu
* @param[in] instance loader instance
*/ */
void loader_show_menu(); void loader_show_menu();
/** /**
* @brief Get loader pubsub * @brief Get loader pubsub
* @param[in] instance loader instance
* @return FuriPubSub* * @return FuriPubSub*
*/ */
FuriPubSub* loader_get_pubsub(); FuriPubSub* loader_get_pubsub();

View File

@ -11,7 +11,6 @@
#include "thread.h" #include "thread.h"
typedef struct { typedef struct {
char* args;
App* app; App* app;
ViewPort* view_port; ViewPort* view_port;
} LoaderAppData; } LoaderAppData;
@ -32,7 +31,6 @@ typedef enum {
typedef struct { typedef struct {
const char* id; const char* id;
const char* args;
FuriString* error_message; FuriString* error_message;
} LoaderMessageAppStart; } LoaderMessageAppStart;

View File

@ -1,15 +1,14 @@
#include "tactility.h"
#include "app_manifest_registry.h" #include "app_manifest_registry.h"
#include "devices_i.h" #include "devices_i.h"
#include "furi.h" #include "furi.h"
#include "graphics_i.h" #include "graphics_i.h"
#include "partitions.h" #include "partitions.h"
#include "services/gui/gui.h" #include "service_registry.h"
#include "tactility.h"
#define TAG "tactility" #define TAG "tactility"
Gui* gui_alloc();
// System services // System services
extern const ServiceManifest gui_service; extern const ServiceManifest gui_service;
extern const ServiceManifest loader_service; extern const ServiceManifest loader_service;
@ -18,13 +17,6 @@ extern const ServiceManifest desktop_service;
// System apps // System apps
extern const AppManifest system_info_app; extern const AppManifest system_info_app;
void start_service(const ServiceManifest* _Nonnull manifest) {
FURI_LOG_I(TAG, "Starting service %s", manifest->id);
furi_check(manifest->on_start, "service must define on_start");
manifest->on_start(NULL);
// TODO: keep track of running services
}
static void register_system_apps() { static void register_system_apps() {
FURI_LOG_I(TAG, "Registering default apps"); FURI_LOG_I(TAG, "Registering default apps");
app_manifest_registry_add(&system_info_app); app_manifest_registry_add(&system_info_app);
@ -43,12 +35,18 @@ static void register_user_apps(const Config* _Nonnull config) {
} }
} }
static void register_system_services() {
FURI_LOG_I(TAG, "Registering system services");
service_registry_add(&gui_service);
service_registry_add(&loader_service);
service_registry_add(&desktop_service);
}
static void start_system_services() { static void start_system_services() {
FURI_LOG_I(TAG, "Starting system services"); FURI_LOG_I(TAG, "Starting system services");
start_service(&gui_service); service_registry_start(gui_service.id);
start_service(&loader_service); service_registry_start(loader_service.id);
start_service(&desktop_service); service_registry_start(desktop_service.id);
FURI_LOG_I(TAG, "System services started");
} }
static void start_user_services(const Config* _Nonnull config) { static void start_user_services(const Config* _Nonnull config) {
@ -63,7 +61,6 @@ static void start_user_services(const Config* _Nonnull config) {
break; break;
} }
} }
FURI_LOG_I(TAG, "User services started");
} }
__attribute__((unused)) extern void tactility_start(const Config* _Nonnull config) { __attribute__((unused)) extern void tactility_start(const Config* _Nonnull config) {
@ -75,6 +72,7 @@ __attribute__((unused)) extern void tactility_start(const Config* _Nonnull confi
/*NbLvgl lvgl =*/tt_graphics_init(&hardware); /*NbLvgl lvgl =*/tt_graphics_init(&hardware);
// Register all apps // Register all apps
register_system_services();
register_system_apps(); register_system_apps();
register_user_apps(config); register_user_apps(config);

View File

@ -2,7 +2,7 @@
#include "services/gui/gui.h" #include "services/gui/gui.h"
#include "services/loader/loader.h" #include "services/loader/loader.h"
static void app_show(lv_obj_t* parent, void* context) { static void app_show(Context* context, lv_obj_t* parent) {
UNUSED(context); UNUSED(context);
lv_obj_t* label = lv_label_create(parent); lv_obj_t* label = lv_label_create(parent);