All checks were successful
Build ESP32 BMC Firmware / build (push) Successful in 55s
247 lines
6.4 KiB
C
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_read(BMC_GPIO_POWER);
|
|
return (level == 1);
|
|
}
|