Files
esp32-bmc/main/gpio_controller.c
Valentin Haudiquet ccf4569969
All checks were successful
Build ESP32 BMC Firmware / build (push) Successful in 59s
gpio: update config to use only one gpio for ATX PSU
2026-03-12 15:28:20 +01:00

247 lines
6.4 KiB
C

#include "gpio_controller.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>
static const char *TAG = TAG_GPIO;
// Runtime GPIO state storage
static bmc_gpio_state_t gpio_states[BMC_GPIO_COUNT];
static bool gpio_initialized = false;
esp_err_t gpio_controller_init(void) {
ESP_LOGI(TAG, "Initializing GPIO controller");
// Initialize all GPIOs from default configuration
for (int i = 0; i < BMC_GPIO_COUNT; i++) {
const bmc_gpio_def_t *def = &bmc_gpio_defaults[i];
// Copy configuration to runtime state
gpio_states[i].pin = def->pin;
gpio_states[i].name = def->name;
gpio_states[i].mode = def->mode;
gpio_states[i].inverted = def->inverted;
gpio_states[i].is_input_only = def->is_input_only;
// Skip configuration for input-only pins when mode is output
if (def->is_input_only && def->mode == GPIO_MODE_OUTPUT) {
gpio_states[i].mode = GPIO_MODE_INPUT;
ESP_LOGW(TAG, "Pin %d (%s) is input-only, forcing input mode", def->pin, def->name);
}
// Configure GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << def->pin),
.mode = gpio_states[i].mode,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
// Enable pull-up for inputs by default
if (gpio_states[i].mode == GPIO_MODE_INPUT) {
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
}
esp_err_t ret = gpio_config(&io_conf);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure GPIO %d: %s", def->pin, esp_err_to_name(ret));
return ret;
}
// Set default value for outputs
if (gpio_states[i].mode == GPIO_MODE_OUTPUT) {
int value = def->default_value;
if (def->inverted) {
value = !value;
}
gpio_set_level(def->pin, value);
gpio_states[i].value = value;
} else {
// Read current input value
gpio_states[i].value = gpio_get_level(def->pin);
}
ESP_LOGI(TAG, "GPIO %d (%s) initialized: mode=%d, value=%d, inverted=%d", def->pin, def->name,
gpio_states[i].mode, gpio_states[i].value, gpio_states[i].inverted);
}
gpio_initialized = true;
ESP_LOGI(TAG, "GPIO controller initialized with %d pins", BMC_GPIO_COUNT);
return ESP_OK;
}
int gpio_find_index(gpio_num_t pin) {
for (int i = 0; i < BMC_GPIO_COUNT; i++) {
if (gpio_states[i].pin == pin) {
return i;
}
}
return -1;
}
const char *gpio_get_name(gpio_num_t pin) {
int idx = gpio_find_index(pin);
if (idx >= 0) {
return gpio_states[idx].name;
}
return NULL;
}
esp_err_t gpio_get_all_states(bmc_gpio_state_t *states) {
if (!gpio_initialized) {
return ESP_ERR_INVALID_STATE;
}
// Update input values
for (int i = 0; i < BMC_GPIO_COUNT; i++) {
if (gpio_states[i].mode == GPIO_MODE_INPUT || gpio_states[i].mode == GPIO_MODE_INPUT_OUTPUT) {
gpio_states[i].value = gpio_get_level(gpio_states[i].pin);
}
}
memcpy(states, gpio_states, sizeof(gpio_states));
return ESP_OK;
}
esp_err_t gpio_get_state(gpio_num_t pin, bmc_gpio_state_t *state) {
int idx = gpio_find_index(pin);
if (idx < 0) {
return ESP_ERR_NOT_FOUND;
}
// Update input value
if (gpio_states[idx].mode == GPIO_MODE_INPUT || gpio_states[idx].mode == GPIO_MODE_INPUT_OUTPUT) {
gpio_states[idx].value = gpio_get_level(pin);
}
memcpy(state, &gpio_states[idx], sizeof(bmc_gpio_state_t));
return ESP_OK;
}
int gpio_read(gpio_num_t pin) {
int idx = gpio_find_index(pin);
if (idx < 0) {
return -1;
}
int level = gpio_get_level(pin);
// Apply inverted logic for display
if (gpio_states[idx].inverted) {
level = !level;
}
gpio_states[idx].value = level;
return level;
}
esp_err_t gpio_write(gpio_num_t pin, int value) {
int idx = gpio_find_index(pin);
if (idx < 0) {
ESP_LOGW(TAG, "GPIO %d not found in configuration", pin);
return ESP_ERR_NOT_FOUND;
}
if (gpio_states[idx].is_input_only) {
ESP_LOGW(TAG, "GPIO %d (%s) is input-only", pin, gpio_states[idx].name);
return ESP_ERR_NOT_SUPPORTED;
}
// Ensure GPIO is configured as output
if (gpio_states[idx].mode != GPIO_MODE_OUTPUT && gpio_states[idx].mode != GPIO_MODE_INPUT_OUTPUT) {
ESP_LOGW(TAG, "GPIO %d (%s) is not configured as output", pin, gpio_states[idx].name);
return ESP_ERR_INVALID_STATE;
}
// Apply inverted logic
int actual_value = value;
if (gpio_states[idx].inverted) {
actual_value = !value;
}
esp_err_t ret = gpio_set_level(pin, actual_value);
if (ret == ESP_OK) {
gpio_states[idx].value = value;
ESP_LOGD(TAG, "GPIO %d (%s) set to %d (actual: %d)", pin, gpio_states[idx].name, value, actual_value);
} else {
ESP_LOGE(TAG, "Failed to set GPIO %d: %s", pin, esp_err_to_name(ret));
}
return ret;
}
esp_err_t gpio_configure(gpio_num_t pin, gpio_mode_t mode) {
int idx = gpio_find_index(pin);
if (idx < 0) {
return ESP_ERR_NOT_FOUND;
}
// Check if trying to set input-only pin as output
if (gpio_states[idx].is_input_only && mode == GPIO_MODE_OUTPUT) {
ESP_LOGW(TAG, "GPIO %d (%s) is input-only, cannot set as output", pin, gpio_states[idx].name);
return ESP_ERR_NOT_SUPPORTED;
}
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << pin),
.mode = mode,
.pull_up_en = (mode == GPIO_MODE_INPUT) ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
esp_err_t ret = gpio_config(&io_conf);
if (ret == ESP_OK) {
gpio_states[idx].mode = mode;
ESP_LOGI(TAG, "GPIO %d (%s) mode changed to %d", pin, gpio_states[idx].name, mode);
}
return ret;
}
esp_err_t gpio_toggle(gpio_num_t pin) {
int idx = gpio_find_index(pin);
if (idx < 0) {
return ESP_ERR_NOT_FOUND;
}
int current = gpio_states[idx].value;
return gpio_write(pin, !current);
}
// ============================================================================
// Power Control Functions
// ============================================================================
esp_err_t gpio_power_on(void) {
ESP_LOGI(TAG, "Power ON sequence initiated");
gpio_write(BMC_GPIO_POWER, 1);
return ESP_OK;
}
esp_err_t gpio_power_off(void) {
ESP_LOGI(TAG, "Power OFF sequence initiated");
gpio_write(BMC_GPIO_POWER, 0);
return ESP_OK;
}
esp_err_t gpio_reset(void) {
ESP_LOGI(TAG, "Reset sequence initiated");
// Pulse the POWER signal
gpio_write(BMC_GPIO_POWER, 0);
vTaskDelay(pdMS_TO_TICKS(BMC_RESET_PULSE_MS));
gpio_write(BMC_GPIO_POWER, 1);
ESP_LOGI(TAG, "Reset completed");
return ESP_OK;
}
bool gpio_power_status(void) {
int level = gpio_get_level(BMC_GPIO_POWER);
return (level == 1);
}