#ifndef LED_H
#define LED_H

// Include build configuration
#include "build.h"

// Includes
#include "system.h"

// ============================================================================
//                                   CONFIG
// ============================================================================

// Freq 800 kHz => Period 1.25 us
// -------------------------------------
// ns       SK6812      WS2812B     AVG
// -------------------------------------
// T0H      300         400         350     28%
// T0L      900         850
// T1H      600         800         700     56%
// T1L      600         450
// -------------------------------------

#define LED_TIM_FREQ                64000000        // Timer frequency

#define LED_BUS_FREQ                800000          // Led bus frequency
#define LED_T0H_NS                  350             // High duration for "0"
#define LED_T1H_NS                  700             // High duration for "1"


#define LED_TIM_PERIOD              (LED_TIM_FREQ/LED_BUS_FREQ)                         // Timer period for each DMA slot
#define LED_BIT_1                   (((LED_TIM_FREQ / 1000000) * LED_T1H_NS) / 1000)    // Slot value for "1"
#define LED_BIT_0                   (((LED_TIM_FREQ / 1000000) * LED_T0H_NS) / 1000)    // Slot value for "0"


// ============================================================================
//                                  CONSTANTS
// ============================================================================


#define LED_TIM_PRESCALER           ((HAL_RCC_GetPCLK1Freq() / LED_TIM_FREQ) - 1)
#define LED_DMA_BUFFER_SIZE         ((24 * BUILD_LED_COUNT) + 1)

// 0x00RRGGBB
#define LED_COLOR_OFF               LED_COLOR_WORD(0x00000000)
#define LED_COLOR_RED               LED_COLOR_WORD(0x00FF0000)
#define LED_COLOR_GREEN             LED_COLOR_WORD(0x0000FF00)
#define LED_COLOR_BLUE              LED_COLOR_WORD(0x000000FF)
#define LED_COLOR_YELLOW            LED_COLOR_WORD(0x00FFFF00)
#define LED_COLOR_CYAN              LED_COLOR_WORD(0x0000FFFF)
#define LED_COLOR_MAGENTA           LED_COLOR_WORD(0x00FF00FF)
#define LED_COLOR_WHITE             LED_COLOR_WORD(0x00FFFFFF)
#define LED_COLOR_PURPLE            LED_COLOR_WORD(0x00AD31F5)
#define LED_COLOR_ORANGE            LED_COLOR_WORD(0x00EB7A2A)
#define LED_COLOR_PINK              LED_COLOR_WORD(0x00EB2ADE)

// ============================================================================
//                                   TYPES
// ============================================================================

typedef struct led_color_t{
    union{
        uint32_t    word;
        struct{
            uint8_t b;  // LSB (0x.. .. .. BB)
            uint8_t g;  //     (0x.. .. GG ..)
            uint8_t r;  //     (0x.. RR .. ..)
            uint8_t a;  // MSB (0xAA .. .. ..)
        };
    }as;
}led_color_t;


#define LED_SEQ_TYPE_NONE       0
#define LED_SEQ_TYPE_BLINK      1
#define LED_SEQ_TYPE_GLOW       2
#define LED_SEQ_TYPE_BUFF       3


typedef struct led_seq_t{
    uint8_t     type;
    uint8_t     count;
}led_seq_t;

#define LED_SEQ_NONE() \
    (led_seq_t *)&((led_seq_t){         \
        .type = LED_SEQ_TYPE_NONE,      \
        .count = 0                      \
    })

typedef struct led_seq_blink_t{
    led_seq_t       head;
    led_color_t     on_color;
    uint32_t        on_ms;
    led_color_t     off_color;
    uint32_t        off_ms;
}led_seq_blink_t;

#define LED_SEQ_BLINK(_count, _on_color, _on_ms, _off_color, _off_ms) \
    (led_seq_t *)&((led_seq_blink_t){       \
        {                                   \
            .type = LED_SEQ_TYPE_BLINK,     \
            .count = _count                 \
        },                                  \
        .on_color   = _on_color,            \
        .on_ms      = _on_ms,               \
        .off_color  = _off_color,           \
        .off_ms     = _off_ms,              \
    })

typedef struct led_seq_glow_t{
    led_seq_t       head;
    led_color_t     a_color;
    led_color_t     b_color;
    uint32_t        a2b_ms;
    uint32_t        b2a_ms;
}led_seq_glow_t;

#define LED_SEQ_GLOW(_count, _a_color, _b_color, _a2b_ms, _b2a_ms) \
    (led_seq_t *)&((led_seq_glow_t){       \
        {                                   \
            .type = LED_SEQ_TYPE_GLOW,      \
            .count = _count                 \
        },                                  \
        .a_color    = _a_color,             \
        .b_color    = _b_color,             \
        .a2b_ms     = _a2b_ms,              \
        .b2a_ms     = _b2a_ms,              \
    })



#define LED_SEQ_BUFF_ROT_NONE       0
#define LED_SEQ_BUFF_ROT_CW         1
#define LED_SEQ_BUFF_ROT_CCW        2


typedef struct led_seq_buff_t{
    led_seq_t       head;
    led_color_t     *colors;
    uint8_t         rot;
    uint32_t        ms; // if ROT_NONE, it's on duration otherwise it's duration between rot
}led_seq_buff_t;

#define LED_SEQ_BUFF(_count, _rot, _ms, _colors) \
    (led_seq_t *)&((led_seq_buff_t){       \
        {                                   \
            .type = LED_SEQ_TYPE_BUFF,      \
            .count = _count                 \
        },                                  \
        .rot    = _rot,                     \
        .ms     = _ms,                      \
        .colors = _colors,                    \
    })

typedef union led_seq_u_t{
    led_seq_t           head;
    led_seq_blink_t     blink;
    led_seq_glow_t      glow;
    led_seq_buff_t      buff;
}led_seq_u_t;

typedef struct led_t{
    // Hw
    TIM_HandleTypeDef   tim;
    DMA_HandleTypeDef   dma;
    volatile uint32_t   dma_busy;
    uint16_t            dma_buffer[LED_DMA_BUFFER_SIZE];
    // Status
    uint8_t             led_used;
    uint8_t             brightness;
    led_color_t         led_status[BUILD_LED_COUNT];
    // Sequence
    led_seq_u_t         seq;
    uint32_t            seq_count;
    uint32_t            seq_step;
    uint32_t            seq_limit;
    uint32_t            seq_ts;
    //led_color_t         seq_prev_status[BUILD_LED_COUNT];
}led_t;

// ============================================================================
//                                   MACROS
// ============================================================================

#define LED_DATA_HIGH()             LED_DATA_PORT->BSRR  = (uint32_t)LED_DATA_PIN;
#define LED_DATA_LOW()              LED_DATA_PORT->BRR   = (uint32_t)LED_DATA_PIN;

#define LED_POWER_ON()              LED_EN_PORT->BRR   = (uint32_t)LED_EN_PIN;
#define LED_POWER_OFF()             LED_EN_PORT->BSRR  = (uint32_t)LED_EN_PIN;

#define LED_COLOR_WORD(w)           ((led_color_t){ .as.word = (w) })

#define LED_COLOR_RGB(r,g,b)        ((led_color_t){ .as.r=(r), .as.g=(g), .as.b=(b), .as.a=0 })

// ============================================================================
//                                   GLOBALS
// ============================================================================

extern led_t led;

// ============================================================================
//                                   PROTOTYPES
// ============================================================================

void led_init();

void led_task();

void led_set_seq(led_seq_t *seq);

void led_send();
void led_set_color(led_color_t color);

led_color_t led_get_rand_color(void);




#endif
