#include <stm32f0xx.h>
#include <cmsis/core_cm0.h>
#include <stdbool.h>

#define RING_MAX_LED	30u

enum ring_modes {
	RING_MODE_ALL,
	RING_MODE_RED,
	RING_MODE_GREEN,
	RING_MODE_BLUE,
	RING_MODE_WHITE,
	RING_MODE_ARC,
	RING_MODE_QUARTER,
	RING_MODE_IN_FARBE_UND_BUNT,
	RING_MODE_MAX
};

unsigned int i = 0x12345678;
unsigned char c = 2;

extern void sk6812_send_led(uint32_t rgbw);

volatile uint32_t wait_tick = 0;

static void wait_for_ticks(uint32_t ticks)
{
	wait_tick = 0;
	while (wait_tick < ticks);
}

int main(void)
{
	uint32_t led_val = 0x00UL;
	uint32_t led_calc_val[RING_MAX_LED] = {0x00UL};
	bool button_pressed = false;
	enum ring_modes mode = RING_MODE_ALL;

	RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
	RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

	GPIOA->MODER |= (2<<7*2)|(2<<6*2)|(1<<3*2);

	/* enable pullups on encoder inputs */
	GPIOA->PUPDR |= (1<<7*2)|(1<<6*2)|(1<<0*2);
	/* enable TIM3 on encoder inputs */
	GPIOA->AFR[0] |= (1<<7*4)|(1<<6*4);

	TIM3->ARR = 0xFFFF;
	TIM3->CNT = 0;
	TIM3->CR2 = 0;
	TIM3->SMCR = TIM_SMCR_SMS_0;
	TIM3->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1;
	TIM3->CCER = TIM_CCER_CC1P | TIM_CCER_CC2P;
	TIM3->PSC = 0;
	TIM3->CR1 = TIM_CR1_CEN;

	SysTick_Config(800000);
	while(1) {

		switch (mode)
		{
		case RING_MODE_ALL:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = (led_val << 24) + (led_val << 16) + (led_val << 8) + led_val; 
			}
			break;
		case RING_MODE_RED:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = led_val << 16;
			}
			break;
		case RING_MODE_GREEN:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = led_val << 24; 
			}
			break;
		case RING_MODE_BLUE:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = led_val << 8; 
			}
			break;
		case RING_MODE_WHITE:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = led_val; 
			}
			break;
		case RING_MODE_ARC:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				if(led_val > i*8) {
					led_calc_val[i] = 0xFFFFFFFFUL; 
				}
				else {
					led_calc_val[i] = 0x00000000UL;
				}
			}
			break;
		case RING_MODE_QUARTER:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				if((led_val / 7 > i) && (led_val / 7 < (i + 7))) {
					led_calc_val[i] = 0xFFFFFFFFUL; 
				}
				else {
					led_calc_val[i] = 0x00000000UL;
				}
			}
			break;
		case RING_MODE_IN_FARBE_UND_BUNT:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				switch ((led_val + (i / 3)) % 3)
				{
				case 0:
					led_calc_val[i] = 0x00FF0000UL;
					break;
				case 1:
					led_calc_val[i] = 0xFF000000UL;
					break;
				case 2:
					led_calc_val[i] = 0x0000FF00UL;
					break;
				
				default:
					break;
				}
			}
			break;
		default:
			for(int i = 0; i < RING_MAX_LED; i ++) {
				led_calc_val[i] = 0x00000000UL;
			}
			break;
		}
		__disable_irq();
		for(int i = 0; i < RING_MAX_LED; i ++) {
			sk6812_send_led(led_calc_val[i]);
		}
		__enable_irq();
		wait_for_ticks(5);

		if((int16_t)TIM3->CNT > (int16_t)led_val) {
			led_val = 0u;
		}
		else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) {
			led_val = 255u;
		}
		else {
			led_val = (int16_t)led_val - (int16_t)TIM3->CNT;
		}
		TIM3->CNT = 0u;

		if(button_pressed) {
			if(GPIOA->IDR & GPIO_IDR_0) {
				button_pressed = false;
			}
		}
		else if(!(GPIOA->IDR & GPIO_IDR_0)) {
			mode = (mode + 1) % RING_MODE_MAX;
			button_pressed = true;
		}
	}
}

void SysTick_Handler(void) {
	wait_tick++;
}