diff --git a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp index 816800182..274d1d995 100644 --- a/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp +++ b/Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #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(pin), high); +static error_t set_level(GpioDescriptor* descriptor, bool high) { + auto esp_error = gpio_set_level(static_cast(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(pin)) != 0; +static error_t get_level(GpioDescriptor* descriptor, bool* high) { + *high = gpio_get_level(static_cast(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(pin), &esp_config) != ESP_OK) { + if (gpio_get_io_config(static_cast(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; diff --git a/TactilityC/Include/tt_hal_gpio.h b/TactilityC/Include/tt_hal_gpio.h index 8776d3760..b80bd3ebb 100644 --- a/TactilityC/Include/tt_hal_gpio.h +++ b/TactilityC/Include/tt_hal_gpio.h @@ -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 diff --git a/TactilityC/Source/tt_hal_gpio.cpp b/TactilityC/Source/tt_hal_gpio.cpp index 5c533cc3c..114055a2b 100644 --- a/TactilityC/Source/tt_hal_gpio.cpp +++ b/TactilityC/Source/tt_hal_gpio.cpp @@ -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(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; } } diff --git a/TactilityKernel/Include/tactility/drivers/gpio.h b/TactilityKernel/Include/tactility/drivers/gpio.h index b42301f11..8ac772f6a 100644 --- a/TactilityKernel/Include/tactility/drivers/gpio.h +++ b/TactilityKernel/Include/tactility/drivers/gpio.h @@ -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 */ diff --git a/TactilityKernel/Include/tactility/drivers/gpio_controller.h b/TactilityKernel/Include/tactility/drivers/gpio_controller.h index cd15fe30e..674eb323a 100644 --- a/TactilityKernel/Include/tactility/drivers/gpio_controller.h +++ b/TactilityKernel/Include/tactility/drivers/gpio_controller.h @@ -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); }; +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 Sets 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] 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 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 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_controller_set_level(struct Device* device, gpio_pin_t pin, bool high); +error_t gpio_descriptor_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 gpio_controller_get_level(struct Device* device, gpio_pin_t pin, bool* high); +error_t gpio_descriptor_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] descriptor the pin descriptor * @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); +error_t gpio_descriptor_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 gpio_controller_get_options(struct Device* device, gpio_pin_t pin, gpio_flags_t* options); +error_t gpio_descriptor_get_options(struct GpioDescriptor* descriptor, 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 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 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 Deinitializes GPIO descriptors for a controller. + * @param[in,out] device the GPIO controller device * @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_controller_deinit_descriptors(struct Device* device); extern const struct DeviceType GPIO_CONTROLLER_TYPE; diff --git a/TactilityKernel/Include/tactility/drivers/gpio_descriptor.h b/TactilityKernel/Include/tactility/drivers/gpio_descriptor.h new file mode 100644 index 000000000..2f972c976 --- /dev/null +++ b/TactilityKernel/Include/tactility/drivers/gpio_descriptor.h @@ -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; +}; diff --git a/TactilityKernel/Source/drivers/gpio_controller.cpp b/TactilityKernel/Source/drivers/gpio_controller.cpp index 376409bdb..9ddba628d 100644 --- a/TactilityKernel/Source/drivers/gpio_controller.cpp +++ b/TactilityKernel/Source/drivers/gpio_controller.cpp @@ -3,33 +3,116 @@ #include #include -#define GPIO_DRIVER_API(driver) ((struct GpioControllerApi*)driver->api) +#include +#include + +#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 release_descriptor(struct GpioDescriptor* descriptor) { + descriptor->owner_type = GPIO_OWNER_NONE; + descriptor->owner_context = nullptr; + return ERROR_NONE; } -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_pin_count(struct Device* device, uint32_t* count) { + auto* data = (struct GpioControllerData*)device_get_driver_data(device); + *count = data->pin_count; + return ERROR_NONE; } -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 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_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); +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 { diff --git a/TactilityKernel/Source/kernel_symbols.c b/TactilityKernel/Source/kernel_symbols.c index 205383c57..8d1a1aec4 100644 --- a/TactilityKernel/Source/kernel_symbols.c +++ b/TactilityKernel/Source/kernel_symbols.c @@ -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),