Service logic moved to kernel (#554)

+ fix BT service file paths
This commit is contained in:
Ken Van Hoeylandt
2026-07-07 22:52:19 +02:00
committed by GitHub
parent cca7224252
commit f4f91f81d6
24 changed files with 1101 additions and 196 deletions
+24
View File
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <stddef.h>
#include <tactility/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the root path for user data. Survives OS upgrades.
* @param[out] out_path buffer to store the path (no trailing "/")
* @param[in] out_path_size size of the output buffer
* @retval ERROR_NOT_FOUND if the configured storage location isn't available (e.g. no SD card)
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
* @retval ERROR_NONE on success
*/
error_t paths_get_user_data_path(char* out_path, size_t out_path_size);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <tactility/error.h>
#include <tactility/service/service_manifest.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ServiceInstanceInternal;
/** The lifecycle state of a ServiceInstance. */
typedef enum {
SERVICE_STATE_STARTING,
SERVICE_STATE_STARTED,
SERVICE_STATE_STOPPING,
SERVICE_STATE_STOPPED,
} ServiceState;
/** Represents a running (or about-to-run) instance of a service. */
struct ServiceInstance {
/** The manifest that spawned this instance. */
const struct ServiceManifest* manifest;
/** Service-specific data, owned by the service implementation. Can be NULL. */
void* data;
/**
* Internal state managed by the kernel.
* ServiceInstance implementers should initialize this to NULL.
* Do not access or modify directly; use service_instance_* functions.
*/
struct ServiceInstanceInternal* internal;
};
/**
* @brief Construct a service instance.
* @details This calls manifest->create_service() to build the instance's data.
* @param[in,out] instance a service instance with manifest set and internal set to NULL
* @param[in] manifest non-null manifest to construct the instance from
* @retval ERROR_OUT_OF_MEMORY if internal data allocation failed
* @retval ERROR_NONE on success
*/
error_t service_instance_construct(struct ServiceInstance* instance, const struct ServiceManifest* manifest);
/**
* @brief Destruct a service instance.
* @details This calls manifest->destroy_service() on the instance's data.
* @param[in,out] instance non-null service instance pointer
* @retval ERROR_INVALID_STATE if the instance is not stopped
* @retval ERROR_NONE on success
*/
error_t service_instance_destruct(struct ServiceInstance* instance);
/**
* @brief Get the manifest of a service instance.
* @param[in] instance non-null service instance pointer
* @return the manifest
*/
const struct ServiceManifest* service_instance_get_manifest(struct ServiceInstance* instance);
/**
* @brief Get the data of a service instance.
* @param[in] instance non-null service instance pointer
* @return the data (can be NULL)
*/
void* service_instance_get_data(struct ServiceInstance* instance);
/**
* @brief Get the state of a service instance.
* @param[in] instance non-null service instance pointer
* @return the current state
*/
ServiceState service_instance_get_state(struct ServiceInstance* instance);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <stdbool.h>
#include <tactility/error.h>
#include <tactility/service/service_instance.h>
#include <tactility/service/service_manifest.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register a service manifest.
* @param[in] manifest non-null manifest to register
* @param[in] auto_start if true, the service is started immediately after registration
* @retval ERROR_INVALID_ARGUMENT if a manifest with the same id is already registered
* @retval ERROR_RESOURCE if auto_start is true and starting the service failed
* @retval ERROR_NONE on success
*/
error_t service_manager_add(const struct ServiceManifest* manifest, bool auto_start);
/**
* @brief Unregister a previously-added manifest.
* @param[in] id non-null service id
* @retval ERROR_INVALID_STATE if the service is still running
* @retval ERROR_NOT_FOUND if no manifest with this id is registered
* @retval ERROR_NONE on success
*/
error_t service_manager_remove(const char* id);
/**
* @brief Find a registered manifest by id.
* @param[in] id non-null service id
* @return the manifest, or NULL if not found
*/
const struct ServiceManifest* service_manager_find_manifest(const char* id);
/**
* @brief Start a registered service by id.
* @param[in] id non-null service id
* @retval ERROR_NOT_FOUND if no manifest with this id is registered
* @retval ERROR_INVALID_STATE if the service is already running
* @retval ERROR_RESOURCE if the service's on_start callback failed
* @retval ERROR_NONE on success
*/
error_t service_manager_start(const char* id);
/**
* @brief Stop a running service by id.
* @param[in] id non-null service id
* @retval ERROR_NOT_FOUND if no service with this id is running
* @retval ERROR_NONE on success
*/
error_t service_manager_stop(const char* id);
/**
* @brief Get the state of a service by id.
* @param[in] id non-null service id
* @return the current state, or SERVICE_STATE_STOPPED if the id is unknown
*/
ServiceState service_manager_get_state(const char* id);
/**
* @brief Find the service instance
* @param[in] id non-null service id
* @return the instance when found, otherwise return NULL
*/
struct ServiceInstance* service_manager_find_instance(const char* id);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <tactility/error.h>
#ifdef __cplusplus
extern "C" {
#endif
// ServiceContext (declared in service_context.h) is a typedef alias of ServiceInstance,
// so the callback types below are declared directly in terms of ServiceInstance to avoid
// a conflicting forward-declaration of an unrelated "ServiceContext" struct tag.
struct ServiceInstance;
/**
* Allocates and initializes the service's custom data.
* @param[in] manifest the manifest that owns this callback
* @return the service's custom data, or NULL if it has none
*/
typedef void* (*ServiceCreate)(const struct ServiceManifest* manifest);
/**
* Frees custom data that was set up by the matching ServiceCreate function.
* @param[in] data the custom data returned by create_service
* @param[in] manifest the manifest that owns this callback
*/
typedef void (*ServiceDestroy)(const struct ServiceManifest* manifest, void* data);
/**
* Called when a service instance is starting.
* Can be NULL, in which case starting always succeeds.
* @param[in,out] instance the starting service instance (also its own ServiceContext)
* @param[in] data the custom data returned by create_service
* @return ERROR_NONE if the service started successfully
*/
typedef error_t (*ServiceOnStart)(struct ServiceInstance* instance, void* data);
/**
* Called when a service instance is stopping.
* Can be NULL, in which case stopping is a no-op.
* @param[in,out] instance the stopping service instance (also its own ServiceContext)
* @param[in] data the custom data returned by create_service
*/
typedef void (*ServiceOnStop)(struct ServiceInstance* instance, void* data);
/**
* Describes a registrable service type.
* One manifest exists per service id, shared across start/stop cycles.
*/
struct ServiceManifest {
/** Unique service identifier. Should never be NULL. */
const char* id;
/** Allocates the service's custom data. Should never be NULL. */
ServiceCreate create_service;
/** Frees the service's custom data. Should never be NULL. */
ServiceDestroy destroy_service;
/** Called when a service instance starts. Can be NULL. */
ServiceOnStart on_start;
/** Called when a service instance stops. Can be NULL. */
ServiceOnStop on_stop;
};
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <stddef.h>
#include <tactility/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get the user data directory for a service. Survives OS upgrades. No trailing "/".
* @param[in] service_id non-null service id
* @param[out] out_path buffer to store the path
* @param[in] out_path_size size of the output buffer
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
* @retval ERROR_NONE on success
*/
error_t service_paths_get_user_data_directory(const char* service_id, char* out_path, size_t out_path_size);
/**
* @brief Get a path within the user data directory for a service.
* @param[in] service_id non-null service id
* @param[in] child_path path without a "/" prefix
* @param[out] out_path buffer to store the path
* @param[in] out_path_size size of the output buffer
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
* @retval ERROR_NONE on success
*/
error_t service_paths_get_user_data_path(const char* service_id, const char* child_path, char* out_path, size_t out_path_size);
/**
* @brief Get the assets directory for a service. Do not store configuration data here. No trailing "/".
* @param[in] service_id non-null service id
* @param[out] out_path buffer to store the path
* @param[in] out_path_size size of the output buffer
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
* @retval ERROR_NONE on success
*/
error_t service_paths_get_assets_directory(const char* service_id, char* out_path, size_t out_path_size);
/**
* @brief Get a path within the assets directory for a service.
* @param[in] service_id non-null service id
* @param[in] child_path path without a "/" prefix
* @param[out] out_path buffer to store the path
* @param[in] out_path_size size of the output buffer
* @retval ERROR_BUFFER_OVERFLOW if out_path_size is too small
* @retval ERROR_NONE on success
*/
error_t service_paths_get_assets_path(const char* service_id, const char* child_path, char* out_path, size_t out_path_size);
#ifdef __cplusplus
}
#endif