#include <stdint.h>
#include <stm32f4xx.h>
#include <stdbool.h>

volatile bool flag = false;

void SysTick_Handler()
{
    flag = true;
}

enum STATE {
    STATE_GREEN,
    STATE_ORANGE,
    STATE_RED
};

int main(void)
{
    // GPIO Port D Clock Enable
    RCC->AHB1ENR = RCC_AHB1ENR_GPIODEN;
    // GPIO Port D Pin 15 down to 12 Push/Pull Output
    GPIOD->MODER = GPIO_MODER_MODER12_0
                   | GPIO_MODER_MODER13_0
                   | GPIO_MODER_MODER14_0
                   | GPIO_MODER_MODER15_0;
    // Set green and red LEDs
    GPIOD->ODR = GPIO_ODR_OD12;

    // SysTick enable with interupt and clk source to AHB/8
    SysTick->CTRL = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
    SysTick->LOAD = 1000000; // 0.5 sec / (8 MHz / 8)

    // time of each color in half seconds
    const uint32_t time_green = 10; // 5 seconds
    const uint32_t time_orange = 2; // 1 seconds
    const uint32_t time_red = 8; // 4 seconds

    uint32_t timer = time_green;
    enum STATE State = STATE_GREEN;

    // Do forever:
    while (1)
    {
        // Wait a moment
        while (!flag)
        {
            __asm__("    WFI"); // sleep until SysTick
        }
        flag = false;

        timer--;
        if (timer == 0)
        {
            // turn off all leds
            GPIOD->ODR &= ~(GPIO_ODR_OD12
                            | GPIO_ODR_OD13
                            | GPIO_ODR_OD14
                            | GPIO_ODR_OD15);
            switch (State) {
                case STATE_GREEN:
                    State = STATE_ORANGE;
                    GPIOD->ODR |= GPIO_ODR_OD13;
                    timer = time_orange;
                    break;
                case STATE_ORANGE:
                    State = STATE_RED;
                    GPIOD->ODR |= GPIO_ODR_OD14;
                    timer = time_red;
                    break;
                case STATE_RED:
                    State = STATE_GREEN;
                    GPIOD->ODR |= GPIO_ODR_OD12;
                    timer = time_green;
                    break;
            }
        }
    }
}
