//! Low-level helpers for reading the sensor's calibration EEPROM over I2C.
//!
//! The EEPROM is addressed in 16-bit words. Every read follows the same
//! read-only sequence described in the datasheet (section 11.4):
//! SET_ADDRESS -> NORMAL_READ -> GET_DATA -> ACTIVE. Nothing in this module
//! ever writes to the calibration area itself.

use crate::Bus;

const EEPROM_ADDR: u8 = 0x1B;

const SET_ADDRESS: u8 = 0x09;
const NORMAL_READ: u8 = 0x06;
const GET_DATA: u8 = 0x0B;
const ACTIVE: u8 = 0x01;

/// Read a single 16-bit word from the EEPROM at `addr`.
pub async fn read_word(i2c: &mut Bus, addr: u16) -> u16 {
    i2c.write(EEPROM_ADDR, &[SET_ADDRESS, (addr >> 8) as u8, addr as u8])
        .await
        .unwrap();
    i2c.write(EEPROM_ADDR, &[NORMAL_READ]).await.unwrap();
    let mut bytes = [0u8; 2];
    i2c.write_read(EEPROM_ADDR, &[GET_DATA], &mut bytes).await.unwrap();
    i2c.write(EEPROM_ADDR, &[ACTIVE]).await.unwrap();
    u16::from_le_bytes(bytes)
}

/// Reconstruct a little-endian `f32` stored across two consecutive EEPROM
/// words (low word first, matching how `PTATGrad`/`PTATOff`/`PixCmin`/
/// `PixCmax` etc. are stored).
pub async fn read_f32(i2c: &mut Bus, low_addr: u16, high_addr: u16) -> f32 {
    let low = read_word(i2c, low_addr).await as u32;
    let high = read_word(i2c, high_addr).await as u32;
    f32::from_bits(high << 16 | low)
}
