#include "stm32g4xx.h"

#include <stdint.h>
#include "drill_safe_gpio.h"
#include "drill_pwm_stage.h"
#include "drill_spi_transport.h"
volatile uint32_t drill_debug_spi_available;
volatile uint32_t drill_debug_pwm_stage_available;

/* STM32G431CBT6 A32 PF1 pin map: only hard-off outputs are configured here.
 * TIM1 is configured stopped after boot; ADC/SPI/I2C/charger and motor run stay disabled. */
_Noreturn static void wait_safe(void) {
    for (;;) __WFI();
}

void drill_safe_boot(void) {
    /* PF1 is OSC_OUT: this image requires cold-reset HSI operation.
     * Reject HSE-enabled entry before changing the shared pad function. */
    if (RCC->CR & (RCC_CR_HSEON | RCC_CR_HSEBYP)) wait_safe();
    const uint16_t gpio_a_outputs =
        (1u << 5u) | (1u << 7u) | (1u << 8u) |
        (1u << 9u) | (1u << 10u) | (1u << 12u);
    const uint16_t gpio_b_outputs = (1u << 0u) | (1u << 1u);
    const uint16_t gpio_f_outputs = (1u << 1u);
    const drill_safe_gpio_set safe_pins = {{
        {&GPIOA->MODER, &GPIOA->OTYPER, &GPIOA->OSPEEDR,
         &GPIOA->PUPDR, &GPIOA->BSRR, gpio_a_outputs, (1u << 12u)},
        {&GPIOB->MODER, &GPIOB->OTYPER, &GPIOB->OSPEEDR,
         &GPIOB->PUPDR, &GPIOB->BSRR, gpio_b_outputs, 0u},
        {&GPIOF->MODER, &GPIOF->OTYPER, &GPIOF->OSPEEDR,
         &GPIOF->PUPDR, &GPIOF->BSRR, gpio_f_outputs, 0u}
    }};

    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN |
                    RCC_AHB2ENR_GPIOBEN |
                    RCC_AHB2ENR_GPIOFEN;
    (void)RCC->AHB2ENR;
    if (!drill_safe_gpio_validate(&safe_pins)) wait_safe();

    /* BSRR is written before MODER so no active pulse occurs on mode change. */
    if (!drill_safe_gpio_preload(&safe_pins)) wait_safe();
    __DSB();
    if (!drill_safe_gpio_configure_outputs(&safe_pins)) wait_safe();
    __DSB();
}

int main(void) {
    drill_safe_boot();
    drill_debug_pwm_stage_available=drill_pwm_stage_init()?1u:0u;
    drill_debug_spi_available=drill_debug_pwm_stage_available && drill_spi_init(0u)?1u:0u;
    wait_safe();
}
