Create hal-device module, fix GPIO, fix tests, fix TactilityC (#471)
* **New Features** * Added a HAL device module providing device enumeration, type queries and a HAL↔kernel bridge. * **Improvements** * Integrated HAL module into startup; standardized module names, includes and lifecycle logging; safer file append behavior; broader build support. * **API Changes** * Driver lifecycle now uses explicit add/remove semantics; C and HAL device type/lookup APIs clarified. * **Chores** * Added module README and Apache‑2.0 license; updated build configuration to include the new module. * **Fixes** * Updated tests and object file handling to behave correctly.
This commit is contained in:
committed by
GitHub
parent
5993ceb232
commit
3fe1dc0312
@@ -37,6 +37,14 @@ error_t driver_construct(struct Driver* driver);
|
||||
|
||||
error_t driver_destruct(struct Driver* driver);
|
||||
|
||||
error_t driver_add(struct Driver* driver);
|
||||
|
||||
error_t driver_remove(struct Driver* driver);
|
||||
|
||||
error_t driver_construct_add(struct Driver* driver);
|
||||
|
||||
error_t driver_remove_destruct(struct Driver* driver);
|
||||
|
||||
error_t driver_bind(struct Driver* driver, struct Device* device);
|
||||
|
||||
error_t driver_unbind(struct Driver* driver, struct Device* device);
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
#include "freertos.h"
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
|
||||
// TactilityFreeRTOS co-existence check
|
||||
#ifndef xPortInIsrContext
|
||||
#define xPortInIsrContext() (pdFALSE)
|
||||
#endif
|
||||
|
||||
// TactilityFreeRTOS co-existence check
|
||||
#ifndef vPortAssertIfInISR
|
||||
#define vPortAssertIfInISR()
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,8 +11,8 @@ extern "C" {
|
||||
/**
|
||||
* Initialize the kernel with platform and device modules, and a device tree.
|
||||
* @param platform_module The platform module to start. This module should not be constructed yet.
|
||||
* @param device_module The device module to start. This module should not be constructed yet.
|
||||
* @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL }
|
||||
* @param device_module The device module to start. This module should not be constructed yet. This parameter can be NULL.
|
||||
* @param devicetree_devices The list of generated devices from the devicetree. The array must be terminated by an entry { NULL, NULL }. This parameter can be NULL.
|
||||
* @return ERROR_NONE on success, otherwise an error code
|
||||
*/
|
||||
error_t kernel_init(struct Module* platform_module, struct Module* device_module, struct CompatibleDevice devicetree_devices[]);
|
||||
|
||||
@@ -17,6 +17,8 @@ struct Module {
|
||||
/**
|
||||
* The name of the module, for logging/debugging purposes
|
||||
* Should never be NULL.
|
||||
* Characters allowed: a-z A-Z 0-9 - _ .
|
||||
* Desirable format "platform-esp32", "lilygo-tdeck", etc.
|
||||
*/
|
||||
const char* name;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <cstdlib>
|
||||
#include <tactility/freertos/task.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
@@ -31,7 +32,7 @@ __attribute__((noreturn)) void __crash(void) {
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_system_abort("System halted. Connect debugger for more info.");
|
||||
#else
|
||||
while (true) { /* Indefinite lock-up */ }
|
||||
exit(1);
|
||||
#endif
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ error_t device_construct(Device* device) {
|
||||
if (device->internal.device_private == nullptr) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
LOG_I(TAG, "construct %s", device->name);
|
||||
LOG_D(TAG, "construct %s", device->name);
|
||||
mutex_construct(&device->internal.mutex);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ error_t device_destruct(Device* device) {
|
||||
if (!get_device_private(device)->children.empty()) {
|
||||
return ERROR_INVALID_STATE;
|
||||
}
|
||||
LOG_I(TAG, "destruct %s", device->name);
|
||||
LOG_D(TAG, "destruct %s", device->name);
|
||||
mutex_destruct(&device->internal.mutex);
|
||||
delete get_device_private(device);
|
||||
device->internal.device_private = nullptr;
|
||||
@@ -88,7 +88,7 @@ static void device_remove_child(struct Device* device, struct Device* child) {
|
||||
}
|
||||
|
||||
error_t device_add(Device* device) {
|
||||
LOG_I(TAG, "add %s", device->name);
|
||||
LOG_D(TAG, "add %s", device->name);
|
||||
|
||||
// Already added
|
||||
if (device->internal.state.started || device->internal.state.added) {
|
||||
@@ -111,7 +111,7 @@ error_t device_add(Device* device) {
|
||||
}
|
||||
|
||||
error_t device_remove(Device* device) {
|
||||
LOG_I(TAG, "remove %s", device->name);
|
||||
LOG_D(TAG, "remove %s", device->name);
|
||||
|
||||
if (device->internal.state.started || !device->internal.state.added) {
|
||||
return ERROR_INVALID_STATE;
|
||||
|
||||
@@ -58,28 +58,6 @@ static DriverLedger& get_ledger() {
|
||||
#define driver_lock(driver) mutex_lock(&get_driver_private(driver)->mutex);
|
||||
#define driver_unlock(driver) mutex_unlock(&get_driver_private(driver)->mutex);
|
||||
|
||||
static void driver_add(Driver* driver) {
|
||||
LOG_I(TAG, "add %s", driver->name);
|
||||
ledger.lock();
|
||||
ledger.drivers.push_back(driver);
|
||||
ledger.unlock();
|
||||
}
|
||||
|
||||
static error_t driver_remove(Driver* driver) {
|
||||
LOG_I(TAG, "remove %s", driver->name);
|
||||
|
||||
ledger.lock();
|
||||
const auto iterator = std::ranges::find(ledger.drivers, driver);
|
||||
if (iterator == ledger.drivers.end()) {
|
||||
ledger.unlock();
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
ledger.drivers.erase(iterator);
|
||||
ledger.unlock();
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t driver_construct(Driver* driver) {
|
||||
@@ -87,7 +65,6 @@ error_t driver_construct(Driver* driver) {
|
||||
if (driver->driver_private == nullptr) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
driver_add(driver);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -104,10 +81,6 @@ error_t driver_destruct(Driver* driver) {
|
||||
}
|
||||
get_driver_private(driver)->destroying = true;
|
||||
|
||||
if (driver_remove(driver) != ERROR_NONE) {
|
||||
LOG_W(TAG, "Failed to remove driver from ledger: %s", driver->name);
|
||||
}
|
||||
|
||||
driver_unlock(driver);
|
||||
delete get_driver_private(driver);
|
||||
driver->driver_private = nullptr;
|
||||
@@ -115,6 +88,41 @@ error_t driver_destruct(Driver* driver) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t driver_add(Driver* driver) {
|
||||
LOG_I(TAG, "add %s", driver->name);
|
||||
ledger.lock();
|
||||
ledger.drivers.push_back(driver);
|
||||
ledger.unlock();
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t driver_remove(Driver* driver) {
|
||||
LOG_I(TAG, "remove %s", driver->name);
|
||||
|
||||
ledger.lock();
|
||||
const auto iterator = std::ranges::find(ledger.drivers, driver);
|
||||
if (iterator == ledger.drivers.end()) {
|
||||
ledger.unlock();
|
||||
return ERROR_NOT_FOUND;
|
||||
}
|
||||
ledger.drivers.erase(iterator);
|
||||
ledger.unlock();
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t driver_construct_add(struct Driver* driver) {
|
||||
if (driver_construct(driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
if (driver_add(driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t driver_remove_destruct(struct Driver* driver) {
|
||||
if (driver_remove(driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
if (driver_destruct(driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
bool driver_is_compatible(Driver* driver, const char* compatible) {
|
||||
if (compatible == nullptr || driver->compatible == nullptr) {
|
||||
return false;
|
||||
|
||||
@@ -14,7 +14,7 @@ struct ModuleParent kernel_module_parent = {
|
||||
|
||||
static error_t init_kernel_drivers() {
|
||||
extern Driver root_driver;
|
||||
if (driver_construct(&root_driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
if (driver_construct_add(&root_driver) != ERROR_NONE) return ERROR_RESOURCE;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -37,19 +37,23 @@ error_t kernel_init(struct Module* platform_module, struct Module* device_module
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
module_set_parent(device_module, &kernel_module_parent);
|
||||
if (module_start(device_module) != ERROR_NONE) {
|
||||
LOG_E(TAG, "init failed to start device module");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
CompatibleDevice* compatible_device = devicetree_devices;
|
||||
while (compatible_device->device != nullptr) {
|
||||
if (device_construct_add_start(compatible_device->device, compatible_device->compatible) != ERROR_NONE) {
|
||||
LOG_E(TAG, "kernel_init failed to construct device: %s (%s)", compatible_device->device->name, compatible_device->compatible);
|
||||
if (device_module != nullptr) {
|
||||
module_set_parent(device_module, &kernel_module_parent);
|
||||
if (module_start(device_module) != ERROR_NONE) {
|
||||
LOG_E(TAG, "init failed to start device module");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
compatible_device++;
|
||||
}
|
||||
|
||||
if (devicetree_devices) {
|
||||
CompatibleDevice* compatible_device = devicetree_devices;
|
||||
while (compatible_device->device != nullptr) {
|
||||
if (device_construct_add_start(compatible_device->device, compatible_device->compatible) != ERROR_NONE) {
|
||||
LOG_E(TAG, "kernel_init failed to construct device: %s (%s)", compatible_device->device->name, compatible_device->compatible);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
compatible_device++;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_I(TAG, "init done");
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <tactility/concurrent/mutex.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
#define TAG LOG_TAG(module)
|
||||
|
||||
struct ModuleParentPrivate {
|
||||
std::vector<struct Module*> modules;
|
||||
struct Mutex mutex = { 0 };
|
||||
@@ -72,6 +74,8 @@ error_t module_set_parent(struct Module* module, struct ModuleParent* parent) {
|
||||
}
|
||||
|
||||
error_t module_start(struct Module* module) {
|
||||
LOG_I(TAG, "start %s", module->name);
|
||||
|
||||
if (module->internal.started) return ERROR_NONE;
|
||||
if (!module->internal.parent) return ERROR_INVALID_STATE;
|
||||
|
||||
@@ -85,6 +89,8 @@ bool module_is_started(struct Module* module) {
|
||||
}
|
||||
|
||||
error_t module_stop(struct Module* module) {
|
||||
LOG_I(TAG, "stop %s", module->name);
|
||||
|
||||
if (!module->internal.started) return ERROR_NONE;
|
||||
|
||||
error_t error = module->stop();
|
||||
|
||||
Reference in New Issue
Block a user