/** * @file outputs.c * @brief Implementation of output control module. */ #include "outputs.h" #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" #include "esp_log.h" static const char *TAG = "outputs"; /** @brief Circulation pump GPIO pin (from Kconfig). */ static const uint8_t uCirculationPumpGpioPin = CONFIG_GPIO_CIRCULATION_PUMP; /** @brief Burner control GPIO pin (from Kconfig). */ static const uint8_t uBurnerGpioPin = CONFIG_GPIO_BURNER; /** @brief Safety contact GPIO pin (from Kconfig). */ static const uint8_t uSafetyContactGpioPin = CONFIG_GPIO_SAFETY_CONTACT; static SemaphoreHandle_t xMutexAccessOutputs = NULL; static eOutput sCirculationPumpState; static eOutput sBurnerState; static eOutput sSafetyContactState; esp_err_t initOutputs(void) { gpio_config_t ioConfCirculationPump = { .pin_bit_mask = (1ULL << uCirculationPumpGpioPin), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE}; gpio_config_t ioConfBurner = { .pin_bit_mask = (1ULL << uBurnerGpioPin), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE}; gpio_config_t ioConfSafetyContact = { .pin_bit_mask = (1ULL << uSafetyContactGpioPin), .mode = GPIO_MODE_OUTPUT, .pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE}; esp_err_t ret = gpio_config(&ioConfCirculationPump); if (ret != ESP_OK) { ESP_LOGE(TAG, "GPIO config failed for circulation pump: %s", esp_err_to_name(ret)); return ESP_FAIL; } ret = gpio_config(&ioConfBurner); if (ret != ESP_OK) { ESP_LOGE(TAG, "GPIO config failed for burner: %s", esp_err_to_name(ret)); return ESP_FAIL; } ret = gpio_config(&ioConfSafetyContact); if (ret != ESP_OK) { ESP_LOGE(TAG, "GPIO config failed for safety contact: %s", esp_err_to_name(ret)); return ESP_FAIL; } xMutexAccessOutputs = xSemaphoreCreateRecursiveMutex(); if (xMutexAccessOutputs == NULL) { ESP_LOGE(TAG, "Failed to create mutex"); return ESP_FAIL; } xSemaphoreGiveRecursive(xMutexAccessOutputs); ESP_LOGI(TAG, "Initialized successfully"); return ESP_OK; } eOutput getCirculationPumpState(void) { eOutput ret = ENABLED; if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { ret = sCirculationPumpState; xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: getCirculationPumpState()"); } return ret; } void setCirculationPumpState(eOutput in) { if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { sCirculationPumpState = in; switch (sCirculationPumpState) { case ENABLED: gpio_set_level(uCirculationPumpGpioPin, 0U); // Switch on Circulation Pump break; case DISABLED: gpio_set_level(uCirculationPumpGpioPin, 1U); // Switch off Circulation Pump break; default: break; } xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: setCirculationPumpState()"); } } eOutput getBurnerState(void) { eOutput ret = ENABLED; if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { ret = sBurnerState; xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: getBurnerState()"); } return ret; } void setBurnerState(eOutput in) { if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { sBurnerState = in; switch (sBurnerState) { case ENABLED: gpio_set_level(uBurnerGpioPin, 0U); // Switch on Burner break; case DISABLED: gpio_set_level(uBurnerGpioPin, 1U); // Switch off Burner break; default: break; } xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: setBurnerState()"); } } eOutput getSafetyControlState(void) { eOutput ret = ENABLED; if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { ret = sSafetyContactState; xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: getSafetyControlState()"); } return ret; } void setSafetyControlState(eOutput in) { if (xSemaphoreTakeRecursive(xMutexAccessOutputs, pdMS_TO_TICKS(5000)) == pdTRUE) { sSafetyContactState = in; switch (sSafetyContactState) { case ENABLED: gpio_set_level(uSafetyContactGpioPin, 0U); // Switch on power for Burner break; case DISABLED: gpio_set_level(uSafetyContactGpioPin, 1U); // Switch off power for Burner break; default: break; } xSemaphoreGiveRecursive(xMutexAccessOutputs); } else { ESP_LOGE(TAG, "Unable to take mutex: setSafetyControlState()"); } }