//
// Created by enik on 15.07.22.
//

//#include "led_rgb.h"
#include "math.h"
#include "main.h"

extern TIM_HandleTypeDef htim2;

static TIM_HandleTypeDef *htim;

static void HSV2RGB(uint8_t hue, uint8_t sat, uint8_t val, uint8_t *_r, uint8_t *_g, uint8_t *_b);

/**
 * @brief Initialize LED Timer
 * @param[in] tmr Handler to HAL Timer
 * @param[in] ch_r Red Channel
 * @param[in] ch_g Green Channel
 * @param[in] ch_b Blue Channel
 */
void led_init(TIM_HandleTypeDef *tmr, uint32_t ch_r, uint32_t ch_g, uint32_t ch_b) {
//    htim = tmr;
    TIM2->PSC = 100 - 1;          // 32 MHz
    TIM2->ARR = 320 - 1;     // 32.000.000 / 32.000 = 1.000 Hz
    led_setRGB(0, 0, 0);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);
}

/**
 * @brief Set LED Color in RGB
 * @param[in] r Red component
 * @param[in] g Green component
 * @param[in] b Blue component
 */
void led_setRGB(uint8_t r, uint8_t g, uint8_t b) {
//    uint32_t r_val = 720 - (r * 320 / 256);
//    uint32_t g_val = 720 - (g * 320 / 256);
//    uint32_t b_val = 720 - (b * 320 / 256);
    uint32_t r_val = (r * 320 / 256);
    uint32_t g_val = (g * 320 / 256);
    uint32_t b_val = (b * 320 / 256);
//    TIM2->CCR1 = b_val;
//    TIM2->CCR2 = r_val;
//    TIM2->CCR3 = g_val;
    TIM2->CCR1 = r_val;
    TIM2->CCR2 = g_val;
    TIM2->CCR3 = b_val;
}

/**
 * @brief Set LED Color in HSV
 * @param hue
 * @param sat
 * @param val
 */
void led_setHSV(uint8_t hue, uint8_t sat, uint8_t val) {
    uint8_t r, g, b;
    HSV2RGB(hue, sat, val, &r, &g, &b);
    led_setRGB(r, g, b);
}

/**
 * @brief Convert color in HSV to RGB
 * @param[in] hue HUE (color) [0..255]
 * @param[in] sat Saturation  [0..255]
 * @param[in] val Value (brightness) [0..255]
 * @param[out] _r Pointer to RED component value
 * @param[out] _g Pointer to GREEN component value
 * @param[out] _b Pointer to BLUE component value
 */
static void HSV2RGB(uint8_t hue, uint8_t sat, uint8_t val, uint8_t *_r, uint8_t *_g, uint8_t *_b) {
    if (sat == 0) { // if white color
        *_r = *_g = *_b = val;
        return;
    }
    // Float is smoother but check for FPU (Floating point unit) in your MCU
    // Otherwise it will take longer time in the code
    // FPU is in: F3/L3 and greater
    // Src: https://github.com/Inseckto/HSV-to-RGB
    float h = (float) hue / 255;
    float s = (float) sat / 255;
    float v = (float) val / 255;

    int i = (int) floorf(h * 6);
    float f = h * 6 - (float) i;
    uint8_t p = (uint8_t) (v * (1 - s) * 255.0);
    uint8_t q = (uint8_t) (v * (1 - f * s) * 255.0);
    uint8_t t = (uint8_t) (v * (1 - (1 - f) * s) * 255.0);

    switch (i % 6) {
// Src: https://stackoverflow.com/questions/3018313
//    uint8_t reg = hue / 43;
//    uint8_t rem = (hue - (reg * 43)) * 6;
//    uint8_t p = (val * (255 - sat)) >> 8;
//    uint8_t q = (val * (255 - ((sat * rem) >> 8))) >> 8;
//    uint8_t t = (val * (255 - ((sat * (255 - rem)) >> 8))) >> 8;
//    switch (reg) {
        case 0:
            *_r = val, *_g = t, *_b = p;
            break;
        case 1:
            *_r = q, *_g = val, *_b = p;
            break;
        case 2:
            *_r = p, *_g = val, *_b = t;
            break;
        case 3:
            *_r = p, *_g = q, *_b = val;
            break;
        case 4:
            *_r = t, *_g = p, *_b = val;
            break;
        default:
            *_r = val, *_g = p, *_b = q;
            break;
    }
}

