GPIO ownership WIP

This commit is contained in:
Ken Van Hoeylandt 2026-02-09 23:05:08 +01:00
parent adb23a0e66
commit 5605c3ce0a
9 changed files with 255 additions and 137 deletions

View File

@ -8,6 +8,7 @@
#include <tactility/log.h>
#include <tactility/drivers/gpio.h>
#include <tactility/drivers/gpio_controller.h>
#include <tactility/drivers/gpio_descriptor.h>
#define TAG "esp32_gpio"
@ -15,20 +16,20 @@
extern "C" {
static error_t set_level(Device* device, gpio_pin_t pin, bool high) {
auto esp_error = gpio_set_level(static_cast<gpio_num_t>(pin), high);
static error_t set_level(GpioDescriptor* descriptor, bool high) {
auto esp_error = gpio_set_level(static_cast<gpio_num_t>(descriptor->pin), high);
return esp_err_to_error(esp_error);
}
static error_t get_level(Device* device, gpio_pin_t pin, bool* high) {
*high = gpio_get_level(static_cast<gpio_num_t>(pin)) != 0;
static error_t get_level(GpioDescriptor* descriptor, bool* high) {
*high = gpio_get_level(static_cast<gpio_num_t>(descriptor->pin)) != 0;
return ERROR_NONE;
}
static error_t set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) {
const Esp32GpioConfig* config = GET_CONFIG(device);
static error_t set_options(GpioDescriptor* descriptor, gpio_flags_t options) {
const Esp32GpioConfig* config = GET_CONFIG(descriptor->controller);
if (pin >= config->gpioCount) {
if (descriptor->pin >= config->gpioCount) {
return ERROR_INVALID_ARGUMENT;
}
@ -44,7 +45,7 @@ static error_t set_options(Device* device, gpio_pin_t pin, gpio_flags_t options)
}
const gpio_config_t esp_config = {
.pin_bit_mask = 1ULL << pin,
.pin_bit_mask = 1ULL << descriptor->pin,
.mode = mode,
.pull_up_en = (options & GPIO_PULL_UP) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,
.pull_down_en = (options & GPIO_PULL_DOWN) ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE,
@ -58,9 +59,9 @@ static error_t set_options(Device* device, gpio_pin_t pin, gpio_flags_t options)
return esp_err_to_error(esp_error);
}
static int get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) {
static error_t get_options(GpioDescriptor* descriptor, gpio_flags_t* options) {
gpio_io_config_t esp_config;
if (gpio_get_io_config(static_cast<gpio_num_t>(pin), &esp_config) != ESP_OK) {
if (gpio_get_io_config(static_cast<gpio_num_t>(descriptor->pin), &esp_config) != ESP_OK) {
return ERROR_RESOURCE;
}
@ -90,27 +91,31 @@ static int get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) {
return ERROR_NONE;
}
error_t get_pin_count(struct Device* device, uint32_t* count) {
*count = GET_CONFIG(device)->gpioCount;
static error_t get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin) {
if (!descriptor) return ERROR_INVALID_ARGUMENT;
*pin = descriptor->pin;
return ERROR_NONE;
}
static error_t start(Device* device) {
ESP_LOGI(TAG, "start %s", device->name);
return ERROR_NONE;
auto pin_count = GET_CONFIG(device)->gpioCount;
return gpio_controller_init_descriptors(device, pin_count, nullptr);
}
static error_t stop(Device* device) {
ESP_LOGI(TAG, "stop %s", device->name);
return ERROR_NONE;
return gpio_controller_deinit_descriptors(device);
}
const static GpioControllerApi esp32_gpio_api = {
.acquire_descriptor = acquire_descriptor,
.release_descriptor = release_descriptor,
.get_pin_number = get_pin_number,
.set_level = set_level,
.get_level = get_level,
.set_options = set_options,
.get_options = get_options,
.get_pin_count = get_pin_count
.get_options = get_options
};
extern struct Module platform_module;

View File

@ -32,7 +32,6 @@
#include <tactility/lvgl_module.h>
#ifdef ESP_PLATFORM
#include "tactility/drivers/root.h"
#include <Tactility/InitEsp.h>
#endif

View File

@ -7,22 +7,16 @@
extern "C" {
#endif
/** Logical GPIO pin identifier used by the HAL. Typically maps to the SoC GPIO number. */
/** @deprecated NON-FUNCTIONAL - WILL BE REMOVED SOON */
typedef unsigned int GpioPin;
/** Value indicating that no GPIO pin is used/applicable. */
/** @deprecated NON-FUNCTIONAL - WILL BE REMOVED SOON */
#define GPIO_NO_PIN -1
/** Read the current logic level of a pin.
* The pin should be configured for input or input/output.
* @param[in] pin The pin to read.
* @return true if the level is high, false if low. If the pin is invalid, the
* behavior is implementation-defined and may return false.
*/
/** @deprecated NON-FUNCTIONAL - WILL BE REMOVED SOON */
bool tt_hal_gpio_get_level(GpioPin pin);
/** Get the number of GPIO pins available on this platform.
* @return The count of valid GPIO pins.
*/
/** @deprecated NON-FUNCTIONAL - WILL BE REMOVED SOON */
int tt_hal_gpio_get_pin_count();
#ifdef __cplusplus

View File

@ -7,33 +7,12 @@ extern "C" {
using namespace tt::hal;
static Device* find_first_gpio_controller() {
Device* device_result = nullptr;
device_for_each_of_type(&GPIO_CONTROLLER_TYPE, &device_result, [](Device* device, void* context) {
if (device_is_ready(device)) {
auto** device_result_ptr = static_cast<Device**>(context);
*device_result_ptr = device;
return false;
}
return true;
});
return device_result;
}
bool tt_hal_gpio_get_level(GpioPin pin) {
Device* device_result = find_first_gpio_controller();
if (device_result == nullptr) return false;
bool pin_state = false;
if (gpio_controller_get_level(device_result, pin, &pin_state) != ERROR_NONE) return false;
return pin_state;
return false;
}
int tt_hal_gpio_get_pin_count() {
Device* device_result = find_first_gpio_controller();
if (device_result == nullptr) return 0;
uint32_t pin_count = 0;
if (gpio_controller_get_pin_count(device_result, &pin_count) != ERROR_NONE) return 0;
return (int)pin_count;
return 0;
}
}

View File

@ -38,12 +38,25 @@ typedef enum {
GPIO__MAX,
} GpioInterruptType;
enum GpioOwnerType {
/** @brief Pin is unclaimed/free */
GPIO_OWNER_NONE,
/** @brief Pin is owned by a hog */
GPIO_OWNER_HOG,
/** @brief Pin is claimed by a regular consumer */
GPIO_OWNER_GPIO,
/** @brief Pin is owned by SPI. This is a special case because of CS pin transfer from hog to SPI controller. */
GPIO_OWNER_SPI
};
/** The index of a GPIO pin on a GPIO Controller */
typedef uint8_t gpio_pin_t;
/** Specifies the configuration flags for a GPIO pin (or set of pins) */
typedef uint16_t gpio_flags_t;
typedef uint8_t gpio_level_t;
/** A configuration for a single GPIO pin */
struct GpioPinConfig {
/** GPIO device controlling the pin */

View File

@ -12,104 +12,127 @@ extern "C" {
struct Device;
struct GpioControllerApi {
struct GpioDescriptor* (*acquire_descriptor)(
struct Device* controller,
gpio_pin_t pin_number,
enum GpioOwnerType owner,
void* owner_context
);
error_t (*release_descriptor)(struct GpioDescriptor* descriptor);
/**
* @brief Gets the pin number associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] pin pointer to store the pin number
* @return ERROR_NONE if successful
*/
error_t (*get_pin_number)(struct GpioDescriptor* descriptor, gpio_pin_t* pin);
/**
* @brief Sets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in,out] descriptor the pin descriptor
* @param[in] high true to set the pin high, false to set it low
* @return ERROR_NONE if successful
*/
error_t (*set_level)(struct Device* device, gpio_pin_t pin, bool high);
error_t (*set_level)(struct GpioDescriptor* descriptor, bool high);
/**
* @brief Gets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] descriptor the pin descriptor
* @param[out] high pointer to store the pin level
* @return ERROR_NONE if successful
*/
error_t (*get_level)(struct Device* device, gpio_pin_t pin, bool* high);
error_t (*get_level)(struct GpioDescriptor* descriptor, bool* high);
/**
* @brief Configures the options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in,out] descriptor the pin descriptor
* @param[in] options configuration flags (direction, pull-up/down, etc.)
* @return ERROR_NONE if successful
*/
error_t (*set_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t options);
error_t (*set_options)(struct GpioDescriptor* descriptor, gpio_flags_t options);
/**
* @brief Gets the configuration options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] descriptor the pin descriptor
* @param[out] options pointer to store the configuration flags
* @return ERROR_NONE if successful
*/
error_t (*get_options)(struct Device* device, gpio_pin_t pin, gpio_flags_t* options);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[out] count pointer to store the number of pins
* @return ERROR_NONE if successful
*/
error_t (*get_pin_count)(struct Device* device, uint32_t* count);
error_t (*get_options)(struct GpioDescriptor* descriptor, gpio_flags_t* options);
};
/**
* @brief Sets the logical level of a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] high true to set the pin high, false to set it low
* @return ERROR_NONE if successful
*/
error_t gpio_controller_set_level(struct Device* device, gpio_pin_t pin, bool high);
struct GpioDescriptor* acquire_descriptor(
struct Device* controller,
gpio_pin_t pin_number,
enum GpioOwnerType owner,
void* owner_context
);
error_t release_descriptor(struct GpioDescriptor* descriptor);
/**
* @brief Gets the logical level of a GPIO pin.
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[out] high pointer to store the pin level
* @param[out] count pointer to store the number of pins
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_level(struct Device* device, gpio_pin_t pin, bool* high);
/**
* @brief Configures the options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[in] options configuration flags (direction, pull-up/down, etc.)
* @return ERROR_NONE if successful
*/
error_t gpio_controller_set_options(struct Device* device, gpio_pin_t pin, gpio_flags_t options);
/**
* @brief Gets the configuration options for a GPIO pin.
* @param[in] device the GPIO controller device
* @param[in] pin the pin index
* @param[out] options pointer to store the configuration flags
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_options(struct Device* device, gpio_pin_t pin, gpio_flags_t* options);
/**
* @brief Gets the number of pins supported by the controller.
* @param[in] device the GPIO controller device
* @param[out] count pointer to store the number of pins
* @return ERROR_NONE if successful
*/
error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count);
/**
* @brief Configures the options for a GPIO pin using a pin configuration structure.
* @param[in] device the GPIO controller device
* @param[in] config the pin configuration structure
* @brief Gets the pin number associated with a descriptor.
* @param[in] descriptor the pin descriptor
* @param[out] pin pointer to store the pin number
* @return ERROR_NONE if successful
*/
static inline error_t gpio_set_options_config(struct Device* device, const struct GpioPinConfig* config) {
return gpio_controller_set_options(device, config->pin, config->flags);
}
error_t gpio_descriptor_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin);
/**
* @brief Sets the logical level of a GPIO pin.
* @param[in] descriptor the pin descriptor
* @param[in] high true to set the pin high, false to set it low
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high);
/**
* @brief Gets the logical level of a GPIO pin.
* @param[in] descriptor the pin descriptor
* @param[out] high pointer to store the pin level
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high);
/**
* @brief Configures the options for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @param[in] options configuration flags (direction, pull-up/down, etc.)
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_set_options(struct GpioDescriptor* descriptor, gpio_flags_t options);
/**
* @brief Gets the configuration options for a GPIO pin.
* @param[in] descriptor the pin descriptor
* @param[out] options pointer to store the configuration flags
* @return ERROR_NONE if successful
*/
error_t gpio_descriptor_get_options(struct GpioDescriptor* descriptor, gpio_flags_t* options);
/**
* @brief Initializes GPIO descriptors for a controller.
* @param[in,out] device the GPIO controller device
* @param[in] owner_data pointer to store in the descriptor's owner_data field
* @return ERROR_NONE if successful
*/
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* owner_data);
/**
* @brief Deinitializes GPIO descriptors for a controller.
* @param[in,out] device the GPIO controller device
* @return ERROR_NONE if successful
*/
error_t gpio_controller_deinit_descriptors(struct Device* device);
extern const struct DeviceType GPIO_CONTROLLER_TYPE;

View File

@ -0,0 +1,20 @@
#pragma once
#include "gpio.h"
struct GpioDescriptor {
/** @brief The controller that owns this pin */
struct Device* controller;
/** @brief Physical pin number */
gpio_pin_t pin;
/** @brief Current owner */
enum GpioOwnerType owner_type;
/** @brief Owner identity for validation */
void* owner_context;
/** @brief Pin level */
gpio_level_t level;
/** @brief Pin configuration flags */
gpio_flags_t flags;
/** @brief Implementation-specific context (e.g. from esp32 controller internally) */
void* controller_context;
};

View File

@ -3,33 +3,116 @@
#include <tactility/driver.h>
#include <tactility/drivers/gpio_controller.h>
#define GPIO_DRIVER_API(driver) ((struct GpioControllerApi*)driver->api)
#include <tactility/concurrent/mutex.h>
#include <tactility/drivers/gpio_descriptor.h>
#define GPIO_INTERNAL_API(driver) ((struct GpioControllerApi*)driver->api)
extern "C" {
error_t gpio_controller_set_level(Device* device, gpio_pin_t pin, bool high) {
const auto* driver = device_get_driver(device);
return GPIO_DRIVER_API(driver)->set_level(device, pin, high);
struct GpioControllerData {
struct Mutex mutex;
uint32_t pin_count;
struct GpioDescriptor* descriptors;
};
struct GpioDescriptor* acquire_descriptor(
struct Device* controller,
gpio_pin_t pin_number,
enum GpioOwnerType owner,
void* owner_context
) {
auto* data = (struct GpioControllerData*)device_get_driver_data(controller);
mutex_lock(&data->mutex);
if (pin_number >= data->pin_count) {
mutex_unlock(&data->mutex);
return nullptr;
}
struct GpioDescriptor* desc = &data->descriptors[pin_number];
if (desc->owner_type != GPIO_OWNER_NONE) {
mutex_unlock(&data->mutex);
return nullptr;
}
desc->owner_type = owner;
desc->owner_context = owner_context;
mutex_unlock(&data->mutex);
return desc;
}
error_t gpio_controller_get_level(Device* device, gpio_pin_t pin, bool* high) {
const auto* driver = device_get_driver(device);
return GPIO_DRIVER_API(driver)->get_level(device, pin, high);
}
error_t gpio_controller_set_options(Device* device, gpio_pin_t pin, gpio_flags_t options) {
const auto* driver = device_get_driver(device);
return GPIO_DRIVER_API(driver)->set_options(device, pin, options);
}
error_t gpio_controller_get_options(Device* device, gpio_pin_t pin, gpio_flags_t* options) {
const auto* driver = device_get_driver(device);
return GPIO_DRIVER_API(driver)->get_options(device, pin, options);
error_t release_descriptor(struct GpioDescriptor* descriptor) {
descriptor->owner_type = GPIO_OWNER_NONE;
descriptor->owner_context = nullptr;
return ERROR_NONE;
}
error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count) {
const auto* driver = device_get_driver(device);
return GPIO_DRIVER_API(driver)->get_pin_count(device, count);
auto* data = (struct GpioControllerData*)device_get_driver_data(device);
*count = data->pin_count;
return ERROR_NONE;
}
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context) {
auto* data = (struct GpioControllerData*)malloc(sizeof(struct GpioControllerData));
if (!data) return ERROR_OUT_OF_MEMORY;
data->pin_count = pin_count;
data->descriptors = (struct GpioDescriptor*)calloc(pin_count, sizeof(struct GpioDescriptor));
if (!data->descriptors) {
free(data);
return ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0; i < pin_count; ++i) {
data->descriptors[i].controller = device;
data->descriptors[i].pin = (gpio_pin_t)i;
data->descriptors[i].owner_type = GPIO_OWNER_NONE;
data->descriptors[i].controller_context = controller_context;
}
mutex_construct(&data->mutex);
device_set_driver_data(device, data);
return ERROR_NONE;
}
error_t gpio_controller_deinit_descriptors(struct Device* device) {
auto* data = (struct GpioControllerData*)device_get_driver_data(device);
free(data->descriptors);
mutex_destruct(&data->mutex);
free(data);
device_set_driver_data(device, nullptr);
return ERROR_NONE;
}
error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high) {
const auto* driver = device_get_driver(descriptor->controller);
return GPIO_INTERNAL_API(driver)->set_level(descriptor, high);
}
error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high) {
const auto* driver = device_get_driver(descriptor->controller);
return GPIO_INTERNAL_API(driver)->get_level(descriptor, high);
}
error_t gpio_descriptor_set_options(struct GpioDescriptor* descriptor, gpio_flags_t options) {
const auto* driver = device_get_driver(descriptor->controller);
return GPIO_INTERNAL_API(driver)->set_options(descriptor, options);
}
error_t gpio_descriptor_get_options(struct GpioDescriptor* descriptor, gpio_flags_t* options) {
const auto* driver = device_get_driver(descriptor->controller);
return GPIO_INTERNAL_API(driver)->get_options(descriptor, options);
}
error_t gpio_descriptor_get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin) {
const auto* driver = device_get_driver(descriptor->controller);
return GPIO_INTERNAL_API(driver)->get_pin_number(descriptor, pin);
}
const struct DeviceType GPIO_CONTROLLER_TYPE {

View File

@ -59,11 +59,13 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
DEFINE_MODULE_SYMBOL(driver_find_compatible),
DEFINE_MODULE_SYMBOL(driver_get_device_type),
// drivers/gpio_controller
DEFINE_MODULE_SYMBOL(gpio_controller_set_level),
DEFINE_MODULE_SYMBOL(gpio_controller_get_level),
DEFINE_MODULE_SYMBOL(gpio_controller_set_options),
DEFINE_MODULE_SYMBOL(gpio_controller_get_options),
DEFINE_MODULE_SYMBOL(gpio_descriptor_set_level),
DEFINE_MODULE_SYMBOL(gpio_descriptor_get_level),
DEFINE_MODULE_SYMBOL(gpio_descriptor_set_options),
DEFINE_MODULE_SYMBOL(gpio_descriptor_get_options),
DEFINE_MODULE_SYMBOL(gpio_controller_get_pin_count),
DEFINE_MODULE_SYMBOL(gpio_controller_init_descriptors),
DEFINE_MODULE_SYMBOL(gpio_controller_deinit_descriptors),
DEFINE_MODULE_SYMBOL(GPIO_CONTROLLER_TYPE),
// drivers/i2c_controller
DEFINE_MODULE_SYMBOL(i2c_controller_read),