/*
 * SHT40 温湿度传感器驱动
 * 功能：通过I2C1读取SHT40传感器的温湿度数据
 * 依赖：STM32 HAL库
 * 跨平台：仅适用于STM32F4系列，使用HAL库的I2C接口
 */

#include "sht40.h"
#include "board.h"
#include "osal.h"

/* 外部I2C句柄 */
extern I2C_HandleTypeDef hi2c1;

/* CRC校验函数 */
static uint8_t sht40_crc8(const uint8_t *data, uint8_t len)
{
    const uint8_t POLYNOMIAL = 0x31;
    uint8_t crc = 0xFF;
    
    for (uint8_t i = 0; i < len; i++)
    {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++)
        {
            if (crc & 0x80)
            {
                crc = (crc << 1) ^ POLYNOMIAL;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return crc;
}

/**
 * @brief 初始化SHT40传感器
 * @return 0成功，-1失败
 */
int sht40_init(void)
{
    return sht40_reset();
}

/**
 * @brief 重置SHT40传感器
 * @return 0成功，-1失败
 */
int sht40_reset(void)
{
    uint8_t cmd = SHT40_CMD_RESET;
    osal_log_i("SHT40: Sending reset command 0x%02X", cmd);
    if (HAL_I2C_Master_Transmit(&hi2c1, SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_OK)
    {
        osal_log_e("SHT40 reset failed");
        return -1;
    }
    osal_thread_mdelay(1); // 重置需要<1ms
    osal_log_i("SHT40: Reset successful");
    return 0;
}

/**
 * @brief 读取SHT40传感器的序列号
 * @param serial 序列号（4字节）
 * @return 0成功，-1失败
 */
int sht40_read_serial(uint32_t *serial)
{
    uint8_t cmd = SHT40_CMD_READ_SERIAL;
    uint8_t data[6];
    
    //osal_log_i("SHT40: Sending read serial command 0x%02X", cmd);
    if (HAL_I2C_Master_Transmit(&hi2c1, SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_OK)
    {
        osal_log_e("SHT40 send read serial command failed");
        return -1;
    }
    
    osal_thread_mdelay(1);
    
    if (HAL_I2C_Master_Receive(&hi2c1, SHT40_I2C_ADDR << 1, data, 6, 1000) != HAL_OK)
    {
        osal_log_e("SHT40 read serial data failed");
        return -1;
    }
    
    /* 校验数据 */
    if (sht40_crc8(&data[0], 2) != data[2])
    {
        osal_log_e("SHT40 serial CRC error (bytes 0-2)");
        return -1;
    }
    if (sht40_crc8(&data[3], 2) != data[5])
    {
        osal_log_e("SHT40 serial CRC error (bytes 3-5)");
        return -1;
    }
    
    *serial = (uint32_t)(data[0] << 24) | (data[1] << 16) | (data[3] << 8) | data[4];
    //osal_log_i("SHT40: Serial number: 0x%08X", *serial);
    return 0;
}

/**
 * @brief 开启SHT40传感器的加热器
 * @param power_level 功率级别：0=低功率(20mW), 1=中功率(110mW), 2=高功率(200mW)
 * @return 0成功，-1失败
 */
int sht40_heater_enable(uint8_t power_level)
{
    uint8_t cmd;
    
    switch (power_level)
    {
        case 0:
            cmd = SHT40_CMD_HEATER_LOW;
            //osal_log_i("SHT40: Enabling heater (low power, 20mW)");
            break;
        case 1:
            cmd = SHT40_CMD_HEATER_MED;
            //osal_log_i("SHT40: Enabling heater (medium power, 110mW)");
            break;
        case 2:
            cmd = SHT40_CMD_HEATER_HIGH;
            //osal_log_i("SHT40: Enabling heater (high power, 200mW)");
            break;
        default:
            osal_log_e("SHT40: Invalid heater power level");
            return -1;
    }
    
    if (HAL_I2C_Master_Transmit(&hi2c1, SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_OK)
    {
        osal_log_e("SHT40 heater enable failed");
        return -1;
    }
    
    osal_thread_mdelay(1000); // 加热器持续1秒
    //osal_log_i("SHT40: Heater operation completed");
    return 0;
}

/**
 * @brief 读取SHT40传感器的温湿度数据（支持不同精度）
 * @param temperature 温度值（摄氏度）
 * @param humidity 湿度值（百分比）
 * @param precision 精度级别：0=低精度, 1=中精度, 2=高精度
 * @return 0成功，-1失败
 */
int sht40_read_temperature_humidity_with_precision(float *temperature, float *humidity, uint8_t precision)
{
    uint8_t cmd;
    uint16_t delay_ms;
    
    switch (precision)
    {
        case 0:
            cmd = SHT40_CMD_MEASURE_LOW_PRECISION;
            delay_ms = 2; // 1.8ms
            //osal_log_i("SHT40: Using low precision measurement");
            break;
        case 1:
            cmd = SHT40_CMD_MEASURE_MED_PRECISION;
            delay_ms = 5; // 4.5ms
            //osal_log_i("SHT40: Using medium precision measurement");
            break;
        case 2:
        default:
            cmd = SHT40_CMD_MEASURE_HIGH_PRECISION;
            delay_ms = 10; // 8.2ms
            //osal_log_i("SHT40: Using high precision measurement");
            break;
    }
    
    uint8_t data[6];
    
    //osal_log_i("SHT40: Sending measure command 0x%02X to address 0x%02X", cmd, SHT40_I2C_ADDR);
    /* 发送测量命令 */
    HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, SHT40_I2C_ADDR << 1, &cmd, 1, 1000);
    if (status != HAL_OK)
    {
        osal_log_e("SHT40 send measure command failed, status: %d", status);
        return -1;
    }
    //osal_log_i("SHT40: Measure command sent successfully");
    
    /* 等待测量完成 */
    osal_thread_mdelay(delay_ms);
    
    /* 读取测量结果 */
    //osal_log_i("SHT40: Reading 6 bytes of data");
    status = HAL_I2C_Master_Receive(&hi2c1, SHT40_I2C_ADDR << 1, data, 6, 1000);
    if (status != HAL_OK)
    {
        osal_log_e("SHT40 read data failed, status: %d", status);
        return -1;
    }
    //osal_log_i("SHT40: Data read successfully: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 
    //           data[0], data[1], data[2], data[3], data[4], data[5]);
    
    /* 校验温度数据 */
    if (sht40_crc8(&data[0], 2) != data[2])
    {
        osal_log_e("SHT40 temperature CRC error");
        return -1;
    }
    
    /* 校验湿度数据 */
    if (sht40_crc8(&data[3], 2) != data[5])
    {
        osal_log_e("SHT40 humidity CRC error");
        return -1;
    }
    
    /* 计算温度值 */
    uint16_t temp_raw = (data[0] << 8) | data[1];
    *temperature = -45.0f + 175.0f * (float)temp_raw / 65535.0f;
    
    /* 计算湿度值 */
    uint16_t hum_raw = (data[3] << 8) | data[4];
    *humidity = -6.0f + 125.0f * (float)hum_raw / 65535.0f;
    
    /* 湿度值范围限制 */
    if (*humidity < 0.0f) *humidity = 0.0f;
    if (*humidity > 100.0f) *humidity = 100.0f;
    
    return 0;
}

/**
 * @brief 读取SHT40传感器的温湿度数据（默认高精度）
 * @param temperature 温度值（摄氏度）
 * @param humidity 湿度值（百分比）
 * @return 0成功，-1失败
 */
int sht40_read_temperature_humidity(float *temperature, float *humidity)
{
    return sht40_read_temperature_humidity_with_precision(temperature, humidity, 2); // 默认使用高精度
}