#pragma once

#ifndef _BOARD_H
#define _BOARD_H

/* Includes */
#include "main.h"
#include "gpio.h"

/* Type Defs */
typedef enum {
  Tube_All = 0xf,
  Tube_C = 4,
  Tube_A = 3,
  Tube_B = 2,
  Tube_D = 1,
  Tube_E = 0
} tube_pos_t;

typedef enum {
  sym_None      = 0,
  sym_Pressure  = 0x1,
  sym_Plus      = 0x2,
  sym_Minus     = 0x4,
  sym_Percent   = 0x8,
  sym_Off       = 0xf << 16
} in15_pin_t;

typedef struct {
    uint8_t r;
    uint8_t g;
    uint8_t b;
} RGB_t;

typedef struct {
    uint8_t h;
    uint8_t s;
    uint8_t v;
} HSV_t;

typedef union {
  uint32_t u32;  /* element specifier for accessing whole u32 */
  uint8_t ar[4]; /* element specifier for accessing as array  */
  struct {
    uint8_t tE;  /* element specifier for accessing Tube_E(4) */
    uint8_t tD;  /* element specifier for accessing Tube_D(3) */
    uint8_t tB;  /* element specifier for accessing Tube_B(2) */
    uint8_t tA;  /* element specifier for accessing Tube_A(1) */
  } s8;         /* element spec. for acc. struct with tubes  */
} tube4_t;

/* Exported macros */
#define LATCH_DOWN      GPIOC->BRR = 0x40
#define LATCH_UP        GPIOC->BSRR = 0x40

#define TUBE_PWR_ON     GPIOA->BRR = 0x10
#define TUBE_PWR_OFF    GPIOA->BSRR = 0x10

#define TUBE_A_ON       TIM1->CCER |= (TIM_CCER_CC1E)
#define TUBE_B_ON       TIM3->CCER |= (TIM_CCER_CC4E)
#define TUBE_C_ON       TIM3->CCER |= (TIM_CCER_CC3E)
#define TUBE_D_ON       TIM3->CCER |= (TIM_CCER_CC2E)
#define TUBE_E_ON       TIM3->CCER |= (TIM_CCER_CC1E)
#define TUBE_BCDE_ON    TIM3->CCER |= (TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E)
#define TUBE_ALL_ON     TUBE_A_ON; TUBE_BCDE_ON

#define TUBE_A_OFF      TIM1->CCER &= ~(TIM_CCER_CC1E)
#define TUBE_B_OFF      TIM3->CCER &= ~(TIM_CCER_CC4E)
#define TUBE_C_OFF      TIM3->CCER &= ~(TIM_CCER_CC3E)
#define TUBE_D_OFF      TIM3->CCER &= ~(TIM_CCER_CC2E)
#define TUBE_E_OFF      TIM3->CCER &= ~(TIM_CCER_CC1E)
#define TUBE_BCDE_OFF   TIM3->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC4E)
#define TUBE_ALL_OFF    TUBE_A_OFF; TUBE_BCDE_OFF

#define IN15_P          GPIOA->BSRR = 0x1
#define IN15_Plus       GPIOA->BSRR = 0x2
#define IN15_Minus      GPIOA->BSRR = 0x4
#define IN15_Percent    GPIOA->BSRR = 0x8
#define IN15_OFF        GPIOA->BRR = 0xF

#define COLOR_R(x)      TIM1->CCR2 = x
#define COLOR_G(x)      TIM1->CCR3 = x
#define COLOR_B(x)      TIM1->CCR4 = x
#define LEDS_OFF        COLOR_R(0); COLOR_G(0); COLOR_B(0)

#define TUBE_A_BRIGHT(x)  TIM1->CCR1 = x
#define TUBE_B_BRIGHT(x)  TIM3->CCR4 = x
#define TUBE_C_BRIGHT(x)  TIM3->CCR3 = x
#define TUBE_D_BRIGHT(x)  TIM3->CCR2 = x
#define TUBE_E_BRIGHT(x)  TIM3->CCR1 = x
#define TUBES_BRIGHT(x)   TUBE_A_BRIGHT(x); TUBE_B_BRIGHT(x); TUBE_C_BRIGHT(x); TUBE_D_BRIGHT(x); TUBE_E_BRIGHT(x)

/* Constants */
/* PWM Timers for 250 Hz */
#define TIM1_PSC            (375 - 1)
#define TIM1_ARR            (256 - 1)
#define TIM3_PSC            (375 - 1)
#define TIM3_ARR            (256 - 1)
#define PWM_TUBE_INIT_VAL   127
#define PWM_LED_INIT_VAL    127
#define PWM_LED_MAX_VAL     TIM3_ARR

#define TIM14_PSC            (12000 - 1)
#define TIM14_ARR            (1000 - 1)
#define TIM14_PULSE_VAL      500

#define TIM16_PSC            (24 - 1)
#define TIM16_ARR            (1000 - 1)

#define TIM17_PSC            (24 - 1)
#define TIM17_ARR            (1000 - 1)

#define TUBE_BLANK            0xa

/* Defines */
#define BTN1_GPIO_Port GPIOB
#define BTN1_Pin GPIO_PIN_2
#define BTN2_GPIO_Port GPIOA
#define BTN2_Pin GPIO_PIN_12
#define BTN3_GPIO_Port GPIOB
#define BTN3_Pin GPIO_PIN_4
#define BTN4_GPIO_Port GPIOA
#define BTN4_Pin GPIO_PIN_5
#define IRQ_EXTI_IRQn EXTI4_15_IRQn
#define IRQ_GPIO_Port GPIOC
#define IRQ_Pin GPIO_PIN_14
#define Latch_GPIO_Port GPIOC
#define Latch_Pin GPIO_PIN_6
#define LC0_GPIO_Port GPIOA
#define LC0_Pin GPIO_PIN_0
#define LC1_GPIO_Port GPIOA
#define LC1_Pin GPIO_PIN_1
#define LC2_GPIO_Port GPIOA
#define LC2_Pin GPIO_PIN_2
#define LC3_GPIO_Port GPIOA
#define LC3_Pin GPIO_PIN_3
#define PWM_1_GPIO_Port GPIOA
#define PWM_1_Pin GPIO_PIN_8
#define PWM_2_GPIO_Port GPIOB
#define PWM_2_Pin GPIO_PIN_1
#define PWM_3_GPIO_Port GPIOB
#define PWM_3_Pin GPIO_PIN_0
#define PWM_4_GPIO_Port GPIOA
#define PWM_4_Pin GPIO_PIN_7
#define PWM_5_GPIO_Port GPIOA
#define PWM_5_Pin GPIO_PIN_6
#define PWM_B_GPIO_Port GPIOA
#define PWM_B_Pin GPIO_PIN_11
#define PWM_G_GPIO_Port GPIOA
#define PWM_G_Pin GPIO_PIN_10
#define PWM_R_GPIO_Port GPIOA
#define PWM_R_Pin GPIO_PIN_9
#define SHDN_GPIO_Port GPIOA
#define SHDN_Pin GPIO_PIN_4
#define SWCLK_GPIO_Port GPIOA
#define SWCLK_Pin GPIO_PIN_14
#define SWDIO_GPIO_Port GPIOA
#define SWDIO_Pin GPIO_PIN_13
#define UART_EN_GPIO_Port GPIOC
#define UART_EN_Pin GPIO_PIN_15
#define UART_ST_GPIO_Port GPIOA
#define UART_ST_Pin GPIO_PIN_15

/* BTNs */
#define BTN_NUM             4
#define BTN1_PIN            GPIO_IDR_ID2
#define BTN2_PIN            GPIO_IDR_ID12
#define BTN3_PIN            GPIO_IDR_ID4
#define BTN4_PIN            GPIO_IDR_ID5
#define BTN1_STATE          (BTN1_GPIO_Port->IDR & BTN1_PIN)
#define BTN2_STATE          (BTN2_GPIO_Port->IDR & BTN2_PIN)
#define BTN3_STATE          (BTN3_GPIO_Port->IDR & BTN3_PIN)
#define BTN4_STATE          (BTN4_GPIO_Port->IDR & BTN4_PIN)
#define BTNS1_STATE         (GPIOB->IDR & (BTN1_PIN | BTN3_PIN))
#define BTNS2_STATE         (GPIOA->IDR & (BTN2_PIN | BTN4_PIN))
#define BTNS_STATE          (BTNS1_STATE | BTNS2_STATE)

/* Variables */

/* Exported funcions */
void SystemClock_Config(void);
void Board_Init(void);
void Blink_Start(void);
void Blink_Stop(void);
void showDigits(tube4_t dig);
void tube_Refresh(void);
void lShiftDigits(const tube4_t old, const tube4_t dig);
void slideDigits(tube4_t dig);
void tube_PowerOn(tube_pos_t tube);
void tube_PowerOff(tube_pos_t tube);
void tube_BrightLevel(tube_pos_t tube, uint8_t bright);

#endif /* _BPARD_H */