/*
 * LEDC driver para 3 LEDs (R,G,B) controlados via ULN2003
 */

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"

#include "ledc_driver.h"

// Pode ser futuramente ligado a uma opção de Kconfig.
// Para o teu hardware (comum a 12 V via ULN2003), visto do ESP é ativo-alto.
#define IS_ACTIVE_HIGH 1

#define LEDC_LS_TIMER LEDC_TIMER_2
#define LEDC_LS_MODE LEDC_LOW_SPEED_MODE

// Canais usados: 2, 3, 4
#define LEDC_CH_RED LEDC_CHANNEL_2
#define LEDC_CH_GREEN LEDC_CHANNEL_3
#define LEDC_CH_BLUE LEDC_CHANNEL_4

#define LEDC_NUM_CHANNELS (3)
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT
#define LEDC_DUTY_MAX (8192 - 1)
#define LEDC_FREQUENCY (5000) // 5 kHz

static ledc_channel_config_t ledc_channel[LEDC_NUM_CHANNELS] = {
    {
        .channel = LEDC_CH_RED,
        .duty = 0,
        .gpio_num = -1, // preenchido em runtime
        .speed_mode = LEDC_LS_MODE,
        .hpoint = 0,
        .timer_sel = LEDC_LS_TIMER,
    },
    {
        .channel = LEDC_CH_GREEN,
        .duty = 0,
        .gpio_num = -1,
        .speed_mode = LEDC_LS_MODE,
        .hpoint = 0,
        .timer_sel = LEDC_LS_TIMER,
    },
    {
        .channel = LEDC_CH_BLUE,
        .duty = 0,
        .gpio_num = -1,
        .speed_mode = LEDC_LS_MODE,
        .hpoint = 0,
        .timer_sel = LEDC_LS_TIMER,
    },
};

esp_err_t ledc_init(gpio_num_t gpio_red,
                    gpio_num_t gpio_green,
                    gpio_num_t gpio_blue)
{
    // Configuração do timer
    ledc_timer_config_t ledc_timer = {
        .duty_resolution = LEDC_DUTY_RES,
        .freq_hz = LEDC_FREQUENCY,
        .speed_mode = LEDC_LS_MODE,
        .timer_num = LEDC_LS_TIMER,
        .clk_cfg = LEDC_AUTO_CLK,
    };

    esp_err_t err = ledc_timer_config(&ledc_timer);
    if (err != ESP_OK)
    {
        return err;
    }

    // Atribuir GPIOs aos canais
    ledc_channel[0].gpio_num = gpio_red;
    ledc_channel[1].gpio_num = gpio_green;
    ledc_channel[2].gpio_num = gpio_blue;

    // Configurar canais
    for (int ch = 0; ch < LEDC_NUM_CHANNELS; ch++)
    {
        err = ledc_channel_config(&ledc_channel[ch]);
        if (err != ESP_OK)
        {
            return err;
        }
    }

    return ESP_OK;
}

esp_err_t ledc_set_rgb(uint32_t red, uint32_t green, uint32_t blue)
{
    if (red > 255)
        red = 255;
    if (green > 255)
        green = 255;
    if (blue > 255)
        blue = 255;

    red = red * LEDC_DUTY_MAX / 255;
    green = green * LEDC_DUTY_MAX / 255;
    blue = blue * LEDC_DUTY_MAX / 255;

    if (!IS_ACTIVE_HIGH)
    {
        red = LEDC_DUTY_MAX - red;
        green = LEDC_DUTY_MAX - green;
        blue = LEDC_DUTY_MAX - blue;
    }

    ledc_set_duty(LEDC_LS_MODE, LEDC_CH_RED, red);
    ledc_update_duty(LEDC_LS_MODE, LEDC_CH_RED);

    ledc_set_duty(LEDC_LS_MODE, LEDC_CH_GREEN, green);
    ledc_update_duty(LEDC_LS_MODE, LEDC_CH_GREEN);

    ledc_set_duty(LEDC_LS_MODE, LEDC_CH_BLUE, blue);
    ledc_update_duty(LEDC_LS_MODE, LEDC_CH_BLUE);

    return ESP_OK;
}

esp_err_t ledc_clear(void)
{
    return ledc_set_rgb(0, 0, 0);
}
