#include <libopencm3/cm3/systick.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>

#include <string.h>

typedef unsigned char byte;

static void delay_ms(unsigned int ms)
{
	systick_clear();
	for (unsigned int i=0; i<ms; i++)
		while (!systick_get_countflag())
			;
}

static void wait(void)
{
	for (int i=0; i<7200; i++)
		asm volatile ("");
}

static void set_reg(int reg, int data)
{
	data |= reg << 8;

	gpio_clear(GPIOB, GPIO13);
	wait();

	for (int mask=0x8000; mask; mask >>= 1) {
		if (data & mask)
			gpio_set(GPIOB, GPIO12);
		else
			gpio_clear(GPIOB, GPIO12);
		wait();
		gpio_set(GPIOB, GPIO14);
		wait();
		gpio_clear(GPIOB, GPIO14);
		wait();
	}

	gpio_set(GPIOB, GPIO13);
	wait();
}

static byte display[8] = {
	0x66,	/* .##..##. */
	0x66,	/* .##..##. */
	0x00,	/* ........ */
	0x18,	/* ...##... */
	0x00,	/* ........ */
	0xc3,	/* ##....## */
	0x66,	/* .##..##. */
	0x3c,	/* ..####.. */
};

static void refresh_display(void)
{
	for (int i=1; i<=8; i++)
		set_reg(i, display[8-i]);
}

int main(void)
{
	rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
	rcc_periph_clock_enable(RCC_GPIOA);
	rcc_periph_clock_enable(RCC_GPIOB);
	rcc_periph_clock_enable(RCC_GPIOC);

	systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
	systick_set_reload(71999);
	systick_counter_enable();

	// PC13 = BluePill LED
	gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);

	// PB12 = display DIN
	// PB13 = display CS*
	// PB14 = display CLK
	gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO12 | GPIO13 | GPIO14);
	gpio_clear(GPIOB, GPIO12);
	gpio_set(GPIOB, GPIO13);
	gpio_clear(GPIOB, GPIO14);

#if 0
	// PA0 = left button
	// PA1 = right button
	gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO0 | GPIO1);
	gpio_set(GPIOA, GPIO0 | GPIO1);
#endif

	refresh_display();
	set_reg(9, 0);
	set_reg(10, 0);	// intensity
	set_reg(11, 7);
	set_reg(13, 0);	// test
	set_reg(12, 1);	// shutdown

	for (;;) {
		gpio_clear(GPIOC, GPIO13);
		delay_ms(100);
		gpio_set(GPIOC, GPIO13);
		delay_ms(500);
	}
}