Files
Ken Van Hoeylandt f4f91f81d6 Service logic moved to kernel (#554)
+ fix BT service file paths
2026-07-07 22:52:19 +02:00

120 lines
3.8 KiB
C++

#include <Tactility/service/ServiceRegistration.h>
#include <Tactility/service/ServiceContext.h>
#include <Tactility/service/ServiceManifest.h>
#include <tactility/error.h>
#include <tactility/log.h>
#include <tactility/service/service_manager.h>
#include <cassert>
#include <memory>
namespace tt::service {
constexpr auto* TAG = "ServiceRegistration";
// Bridges the kernel's C ServiceManifest/Service callbacks to the C++ Service
// instances they wrap. Declared extern "C" to match the linkage of the C
// function-pointer types they're assigned to (see e.g. gpio_controller.cpp).
extern "C" {
static void cppDestroyServiceTrampoline(const ::ServiceManifest* /*manifest*/, void* data) {
delete static_cast<std::shared_ptr<Service>*>(data);
}
static error_t cppOnStartTrampoline(::ServiceInstance* instance, void* data) {
auto& servicePtr = *static_cast<std::shared_ptr<Service>*>(data);
ServiceContext context(instance);
return servicePtr->onStart(context) ? ERROR_NONE : ERROR_RESOURCE;
}
static void cppOnStopTrampoline(::ServiceInstance* instance, void* data) {
auto& servicePtr = *static_cast<std::shared_ptr<Service>*>(data);
ServiceContext context(instance);
servicePtr->onStop(context);
}
} // extern "C"
void addService(std::shared_ptr<const ServiceManifest> manifest, bool autoStart) {
assert(manifest != nullptr);
const auto& id = manifest->id;
LOG_I(TAG, "Adding %s", id.c_str());
if (service_manager_find_manifest(id.c_str()) != nullptr) {
LOG_E(TAG, "Service id in use: %s", id.c_str());
return;
}
// Intentionally never freed: services are registered once and live for the
// process lifetime (there is no removeService()). Keeps id's backing string
// alive for cManifest.id below.
auto* persistentManifest = new std::shared_ptr(manifest);
auto* cManifest = new ::ServiceManifest {
.id = (*persistentManifest)->id.c_str(),
.create_service = (*persistentManifest)->createService,
.destroy_service = cppDestroyServiceTrampoline,
.on_start = cppOnStartTrampoline,
.on_stop = cppOnStopTrampoline,
};
error_t error = service_manager_add(cManifest, autoStart);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to add service %s: %s", id.c_str(), error_to_string(error));
}
}
void addService(const ServiceManifest& manifest, bool autoStart) {
addService(std::make_shared<const ServiceManifest>(manifest), autoStart);
}
const ::ServiceManifest* findManifestById(const std::string& id) {
return service_manager_find_manifest(id.c_str());
}
bool startService(const std::string& id) {
LOG_I(TAG, "Starting %s", id.c_str());
const error_t error = service_manager_start(id.c_str());
if (error != ERROR_NONE) {
LOG_E(TAG, "Starting %s failed: %s", id.c_str(), error_to_string(error));
return false;
}
LOG_I(TAG, "Started %s", id.c_str());
return true;
}
std::shared_ptr<ServiceContext> findServiceContextById(const std::string& id) {
auto* instance = service_manager_find_instance(id.c_str());
if (instance == nullptr) {
return nullptr;
}
return std::make_shared<ServiceContext>(instance);
}
std::shared_ptr<Service> findServiceById(const std::string& id) {
auto* instance = service_manager_find_instance(id.c_str());
if (instance == nullptr) {
return nullptr;
}
return *static_cast<std::shared_ptr<Service>*>(instance->data);
}
bool stopService(const std::string& id) {
LOG_I(TAG, "Stopping %s", id.c_str());
error_t error = service_manager_stop(id.c_str());
if (error != ERROR_NONE) {
LOG_W(TAG, "Service not running: %s", id.c_str());
return false;
}
LOG_I(TAG, "Stopped %s", id.c_str());
return true;
}
State getState(const std::string& id) {
return service_manager_get_state(id.c_str());
}
} // namespace