#include "lamp_measurement.h"
#include <stddef.h>
/* STM32G030 DS12991: VREFINT_CAL at3.0V, address0x1FFF75AA. */
#define ADC_FS 4095u
#define CAL_SUPPLY_UV UINT64_C(3000000)
#define MAX_FRAME_AGE_MS 20u
static uint32_t rounded(uint64_t numerator,uint32_t denominator) {
    return (uint32_t)((numerator+denominator/2u)/denominator);
}
enum lamp_measurement_status lamp_measurement_from_frame(
    const lamp_adc_frame *raw,uint16_t cal,uint32_t now,lamp_measurement *out) {
    if(raw==NULL || out==NULL) return LAMP_MEAS_ARGUMENT;
    /* Broad diagnostic credibility bounds, not ST factory acceptance limits. */
    if(cal<1000u || cal>2000u) return LAMP_MEAS_CALIBRATION;
    if(raw->ntc_raw>ADC_FS || raw->led_v_raw>=ADC_FS ||
       raw->led_i_raw>=ADC_FS || raw->vrefint_raw==0u ||
       raw->vrefint_raw>=ADC_FS) return LAMP_MEAS_RAW_RANGE;
    if(raw->sequence==0u || now-raw->first_sample_ms>MAX_FRAME_AGE_MS ||
       now-raw->completed_ms>MAX_FRAME_AGE_MS ||
       raw->completed_ms-raw->first_sample_ms>MAX_FRAME_AGE_MS)
        return LAMP_MEAS_STALE;
    const uint64_t reference=CAL_SUPPLY_UV*cal;
    const uint32_t vdda=rounded(reference,raw->vrefint_raw);
    /* INA180 also needs >=2.7V supply; this only bounds a diagnostic formula.
     * It never sets supply_ok in lamp_guard. */
    if(vdda<2700000u || vdda>3600000u) return LAMP_MEAS_SUPPLY_RANGE;
    const uint32_t denom=(uint32_t)raw->vrefint_raw*ADC_FS;
    lamp_measurement m={0};
    m.estimated_vdda_uv=vdda;
    /* A43 R7/R8=100k/100k => divider gain2; no board gain/offset trim. */
    m.nominal_led_uv=rounded(reference*raw->led_v_raw*2u,denom);
    /* A43 R6=10mR, INA180A1 gain20 => 0.2V/A, multiply uV by5. */
    m.nominal_led_current_ua=rounded(reference*raw->led_i_raw*5u,denom);
    /* Compare unrounded rational voltages to manufacturer gain-error window
     * 0.5V <= Vout <= VS-0.5V. Output below/above it remains diagnostic only. */
    const uint64_t current_out=reference*raw->led_i_raw;
    if(current_out<UINT64_C(500000)*denom ||
       current_out>reference*ADC_FS-UINT64_C(500000)*denom)
        m.quality_flags|=LAMP_MEAS_CURRENT_OUTSIDE_GAIN_WINDOW;
    /* Same CTRL_3V3 rail for10k pull-up and ADC. No B-value/temperature assumed.
     * Candidate16-count rail-proximity checks are not qualified fault limits. */
    if(raw->ntc_raw<=16u) m.quality_flags|=LAMP_MEAS_NTC_NEAR_SHORT;
    else if(raw->ntc_raw>=4079u) m.quality_flags|=LAMP_MEAS_NTC_NEAR_OPEN;
    else m.nominal_ntc_ohm=rounded(UINT64_C(10000)*raw->ntc_raw,ADC_FS-raw->ntc_raw);
    m.first_sample_ms=raw->first_sample_ms;m.completed_ms=raw->completed_ms;
    m.sequence=raw->sequence;
    *out=m;return LAMP_MEAS_OK;
}
uint16_t lamp_read_factory_vrefint_cal(void) {
    return *(const volatile uint16_t *)(uintptr_t)0x1FFF75AAUL;
}
