#include "lamp_board_inputs.h"
#include "lamp_ir_filter.h"
#include "stm32g0xx.h"
static lamp_ir_filter ir_filter;
static bool ir_initialized;
static bool clock_allows_ir(void) {
    return (RCC->BDCR & (RCC_BDCR_LSEON|RCC_BDCR_LSERDY|RCC_BDCR_LSEBYP))==0u;
}
static bool configuration_allows_ir(void) {
    return (RCC->IOPENR & RCC_IOPENR_GPIOCEN)!=0u && clock_allows_ir() &&
           (GPIOC->LCKR & ((1u<<16u)|(1u<<15u)))!=((1u<<16u)|(1u<<15u)) &&
           (GPIOC->MODER & (3u<<30u))==0u &&
           (GPIOC->PUPDR & (3u<<30u))==0u &&
           (GPIOC->AFR[1] & (15u<<28u))==0u;
}
bool lamp_board_ir_init(void) {
    ir_initialized=false;ir_filter=(lamp_ir_filter){0};
    if (!clock_allows_ir()) return false;
    RCC->IOPENR |= RCC_IOPENR_GPIOCEN;
    (void)RCC->IOPENR;
    if ((GPIOC->LCKR & ((1u<<16u)|(1u<<15u)))==((1u<<16u)|(1u<<15u))) return false;
    GPIOC->MODER &= ~(3u<<30u);
    GPIOC->PUPDR &= ~(3u<<30u); /* Use A39 external 47k pulldown. */
    GPIOC->AFR[1] &= ~(15u<<28u);
    __DSB();
    ir_initialized=configuration_allows_ir();
    return ir_initialized;
}
static bool input_pin(GPIO_TypeDef *p,unsigned n,unsigned pull){
    return ((p->MODER>>(n*2u))&3u)==0u && ((p->PUPDR>>(n*2u))&3u)==pull;
}
static bool unused_alias(GPIO_TypeDef *p,unsigned n){
    return ((p->MODER>>(n*2u))&3u)==3u && ((p->PUPDR>>(n*2u))&3u)==0u;
}
lamp_board_input_snapshot lamp_board_inputs_read(uint32_t now_ms) {
    lamp_board_input_snapshot snapshot={0};
    const bool a_clock=(RCC->IOPENR&RCC_IOPENR_GPIOAEN)!=0u;
    const bool b_clock=(RCC->IOPENR&RCC_IOPENR_GPIOBEN)!=0u;
    snapshot.interlock_gpio_available=a_clock && input_pin(GPIOA,0u,2u);
    snapshot.thermal_gpio_available=a_clock && (RCC->APBENR2&RCC_APBENR2_SYSCFGEN)!=0u &&
        (SYSCFG->CFGR1&SYSCFG_CFGR1_PA12_RMP)==0u && input_pin(GPIOA,12u,2u);
    snapshot.key_gpio_available=a_clock && b_clock && input_pin(GPIOB,0u,1u) &&
        unused_alias(GPIOB,1u) && unused_alias(GPIOB,2u) && unused_alias(GPIOA,8u);
    const uint32_t pa=a_clock?GPIOA->IDR:0u;
    const uint32_t pb=b_clock?GPIOB->IDR:0u;
    snapshot.thermal_contact_closed=snapshot.thermal_gpio_available && (pa & (1u<<12u))!=0u;
    snapshot.hardware_interlock_closed=snapshot.interlock_gpio_available && (pa & (1u<<0u))!=0u;
    snapshot.user_key_pressed=snapshot.key_gpio_available && (pb & (1u<<0u))==0u;
    snapshot.infrared_gpio_available=ir_initialized && configuration_allows_ir();
    snapshot.infrared_raw_high=snapshot.infrared_gpio_available && (GPIOC->IDR & (1u<<15u))!=0u;
    snapshot.guard_inputs.hardware_interlock_ok=snapshot.hardware_interlock_closed;
    snapshot.guard_inputs.infrared_hand_present=lamp_ir_filter_update(&ir_filter,
        snapshot.infrared_gpio_available,snapshot.infrared_raw_high,now_ms);
    /* NTC/rail calibration and driver health are not bound yet; those fields
       deliberately remain false. A closed thermal contact is raw evidence. */
    return snapshot;
}
