Skip to content
37 changes: 21 additions & 16 deletions Platforms/PlatformEsp32/Source/drivers/esp32_gpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,28 @@
#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"

#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config)

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;
}

Expand All @@ -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,
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
16 changes: 5 additions & 11 deletions TactilityC/Include/tt_hal_gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 2 additions & 23 deletions TactilityC/Source/tt_hal_gpio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment on lines 10 to 16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Stubbed functions silently return incorrect values — callers will get wrong behavior with no indication.

Returning hardcoded false / 0 makes these functions silently broken rather than properly deprecated. Any existing caller will observe incorrect GPIO state without any signal that the API is non-functional. This is worse than a loud failure.

Consider at minimum one of:

  1. Adding a TT_LOG_W (or equivalent) so usage is visible at runtime.
  2. Using a compile-time deprecation attribute ([[deprecated("Use GpioDescriptor API")]]) on the declarations.
  3. Removing the functions entirely if no callers remain.
Example: add runtime warning
 bool tt_hal_gpio_get_level(GpioPin pin) {
+    TT_LOG_W("gpio", "tt_hal_gpio_get_level is deprecated and non-functional");
     return false;
 }

 int tt_hal_gpio_get_pin_count() {
+    TT_LOG_W("gpio", "tt_hal_gpio_get_pin_count is deprecated and non-functional");
     return 0;
 }


}
13 changes: 13 additions & 0 deletions TactilityKernel/Include/tactility/drivers/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
111 changes: 67 additions & 44 deletions TactilityKernel/Include/tactility/drivers/gpio_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines +82 to +88
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Function name mismatch: declaration vs implementation.

This declares gpio_descriptor_pin_number but the implementation in gpio_controller.cpp defines gpio_descriptor_get_pin_number. This will cause a linker error for callers using the header name.

Pick one name and use it consistently across the header, implementation, and symbol table.


/**
* @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);
Comment on lines 122 to +128
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading parameter name and documentation for init_descriptors.

The header declares the third parameter as void* owner_data and the doc says "pointer to store in the descriptor's owner_data field," but the implementation names it controller_context and stores it in descriptor->controller_context. This is confusing — the doc suggests per-owner data, while the implementation treats it as controller-level context.

Align the parameter name and doc with the implementation:

Proposed fix
 /**
- * `@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
+ * `@brief` Initializes GPIO descriptors for a controller.
+ * `@param`[in,out] device the GPIO controller device
+ * `@param`[in] pin_count number of GPIO pins to allocate descriptors for
+ * `@param`[in] controller_context implementation-specific context stored in each descriptor
+ * `@return` ERROR_NONE if successful
  */
-error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* owner_data);
+error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @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` Initializes GPIO descriptors for a controller.
* `@param`[in,out] device the GPIO controller device
* `@param`[in] pin_count number of GPIO pins to allocate descriptors for
* `@param`[in] controller_context implementation-specific context stored in each descriptor
* `@return` ERROR_NONE if successful
*/
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context);


/**
* @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;

Expand Down
20 changes: 20 additions & 0 deletions TactilityKernel/Include/tactility/drivers/gpio_descriptor.h
Original file line number Diff line number Diff line change
@@ -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;
};
Loading
Loading