#ifndef LED_H
#define LED_H

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

// Includes
#include "system.h"

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


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

#define LED_DMA_BUFFER_SIZE         (10 + (24 * BUILD_LED_COUNT) + 1)

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


typedef enum led_seq_mode_t{
    LED_SEQ_MODE_BLINK,
    LED_SEQ_MODE_FADE,
    LED_SEQ_MODE_BUFF,
}led_seq_mode_t;

typedef enum led_seq_rot_t{
    LED_SEQ_ROT_NONE,
    LED_SEQ_ROT_CW,
    LED_SEQ_ROT_CCW,
}led_seq_rot_t;


typedef struct led_seq_t{
    led_seq_mode_t          mode;
    uint16_t                count;
    uint16_t                ms;
    union{
        // Single
        struct{
            uint32_t        on_color;
            uint16_t        on_ms;
            uint32_t        off_color;
            uint16_t        off_ms;
        };
        // Fade
        struct{
            uint32_t        color;
            uint8_t         inc_r;
            uint8_t         inc_g;
            uint8_t         inc_b;
            uint16_t        inc_ms;
        };
        // Buff
        struct{
            const uint32_t *ptr;
            led_seq_rot_t  rot;
            uint16_t       rot_ms;
        };
    };
}led_seq_t;

#define LED_SEQ_MODE_BLINK(_count, _ms, _on_color, _on_ms, _off_color, _off_ms) (led_seq_t){ \
    .mode = LED_SEQ_MODE_BLINK, \
    .count = (_count), \
    .ms = (_ms), \
    .on_color = (_on_color), \
    .on_ms = (_on_ms), \
    .off_color = (_off_color), \
    .off_ms = (_off_ms) \
}

#define LED_SEQ_MODE_FADE(_count, _ms, _color, _inc_ms, _inc_b, _inc_g, _inc_r) (led_seq_t){ \
    .mode = LED_SEQ_MODE_FADE, \
    .count = (_count), \
    .ms = (_ms), \
    .color = (_color), \
    .inc_ms = (_inc_ms), \
    .inc_r = (_inc_r), \
    .inc_g = (_inc_g), \
    .inc_b = (_inc_b), \
}

#define LED_SEQ_MODE_BUFF(_count, _ms, _rot, _rot_ms, _ptr) (led_seq_t){ \
    .mode = LED_SEQ_MODE_BUFF, \
    .count = (_count), \
    .ms = (_ms), \
    .rot = (_rot), \
    .rot_ms = (_rot_ms), \
    .ptr = (_ptr), \
}


typedef struct led_t{
    TIM_HandleTypeDef   tim;
    DMA_HandleTypeDef   dma;
    volatile uint32_t   dma_busy;
    uint16_t            dma_buffer[LED_DMA_BUFFER_SIZE];
    uint32_t            color_buffer[5];

    const led_seq_t *seq;
    uint32_t        nseq;
    uint32_t        iseq;
    uint32_t        color;
    uint32_t        buffer[5];
    uint32_t        seq_step;
    uint32_t        seq_count;
    uint32_t        seq_wait_tick;
    uint32_t        seq_limit;
}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->BSRR  = (uint32_t)LED_EN_PIN;
#define LED_POWER_OFF()             LED_EN_PORT->BRR   = (uint32_t)LED_EN_PIN;

#define LED_MK_COLOR(_b, _g, _r)    (((uint32_t)(_b) << 16) | ((uint32_t)(_g) << 8) | ((uint32_t)(_r)))

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

extern led_t led;

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

void led_init();

void led_task();

void led_send();
void led_wait_busy();

void led_send_reset();
void led_send_bit_0();
void led_send_bit_1();
void led_send_pixel(const uint32_t color);
void led_send_npixel(const uint32_t color, uint32_t npx);
void led_send_buffer(const uint32_t *px, uint32_t npx);

void led_fill(uint32_t color, uint32_t *px, uint32_t npx);
void led_copy(uint32_t *dest, const uint32_t *src, uint32_t nb);
void led_rotate_cw(uint32_t *px, uint32_t npx);
void led_rotate_ccw(uint32_t *px, uint32_t npx);



#endif
