#include "i2c_master.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#define I2C_MASTER_NUM      1       //I2C_NUM_1
#define I2C_MASTER_SCL_IO   15
#define I2C_MASTER_SDA_IO   16
#define I2C_MASTER_FREQ_HZ  100000

static const char *TAG = "I2C_MASTER";

/**
 * @brief I2C总线恢复函数
 * @details 当I2C总线出现异常时，通过GPIO模拟时钟信号来恢复总线
 */
static esp_err_t i2c_bus_recovery(void)
{
    ESP_LOGW(TAG, "尝试I2C总线恢复...");
    
    // 1. 卸载I2C驱动
    i2c_driver_delete(I2C_MASTER_NUM);
    vTaskDelay(pdMS_TO_TICKS(50));
    
    // 2. 配置SCL为GPIO输出模式
    gpio_config_t scl_conf = {
        .pin_bit_mask = 1ULL << I2C_MASTER_SCL_IO,
        .mode = GPIO_MODE_OUTPUT_OD,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&scl_conf);
    
    // 3. 配置SDA为GPIO输入模式
    gpio_config_t sda_conf = {
        .pin_bit_mask = 1ULL << I2C_MASTER_SDA_IO,
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&sda_conf);
    
    // 4. 检查SDA是否被拉低（总线卡死的典型症状）
    if (gpio_get_level(I2C_MASTER_SDA_IO) == 0) {
        ESP_LOGW(TAG, "检测到SDA被拉低，执行总线恢复程序");
        
        // 5. 发送9个时钟脉冲来释放SDA
        for (int i = 0; i < 9; i++) {
            gpio_set_level(I2C_MASTER_SCL_IO, 0);
            vTaskDelay(pdMS_TO_TICKS(1));
            gpio_set_level(I2C_MASTER_SCL_IO, 1);
            vTaskDelay(pdMS_TO_TICKS(1));
        }
        
        // 6. 发送STOP条件
        gpio_set_level(I2C_MASTER_SDA_IO, 0);
        vTaskDelay(pdMS_TO_TICKS(1));
        gpio_set_level(I2C_MASTER_SCL_IO, 1);
        vTaskDelay(pdMS_TO_TICKS(1));
        gpio_set_level(I2C_MASTER_SDA_IO, 1);
        vTaskDelay(pdMS_TO_TICKS(10));
        
        ESP_LOGI(TAG, "I2C总线恢复程序执行完成");
    } else {
        ESP_LOGI(TAG, "SDA线正常，跳过总线恢复");
    }
    
    // 7. 延时确保总线稳定
    vTaskDelay(pdMS_TO_TICKS(100));
    
    return ESP_OK;
}

/**
 * @brief 增强的I2C主机初始化函数
 * @details 包含硬件稳定时间、总线恢复机制和多次重试
 */
esp_err_t i2c_master_init(void)
{
    esp_err_t ret;
    int retry_count = 0;
    const int max_retries = 3;
    
    ESP_LOGI(TAG, "开始I2C主机初始化...");
    
    // 上电稳定时间：等待硬件电源稳定
    ESP_LOGI(TAG, "等待硬件电源稳定...");
    vTaskDelay(pdMS_TO_TICKS(200));
    
    while (retry_count < max_retries) {
        // 如果不是第一次尝试，先执行总线恢复
        if (retry_count > 0) {
            ESP_LOGW(TAG, "第%d次重试，先执行总线恢复", retry_count + 1);
            i2c_bus_recovery();
        }
        
        // I2C配置
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };
        
        // 配置I2C参数
        ret = i2c_param_config(I2C_MASTER_NUM, &conf);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "I2C参数配置失败: %s", esp_err_to_name(ret));
            retry_count++;
            vTaskDelay(pdMS_TO_TICKS(100));
            continue;
        }
        
        // 安装I2C驱动
        ret = i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "I2C驱动安装失败: %s", esp_err_to_name(ret));
            retry_count++;
            vTaskDelay(pdMS_TO_TICKS(100));
            continue;
        }
        
        // 成功安装，进行简单的总线测试
        ESP_LOGI(TAG, "I2C驱动安装成功，等待总线稳定...");
        vTaskDelay(pdMS_TO_TICKS(100));
        
        // 执行简单的总线检测（尝试读取一个不存在的设备，应该返回NACK）
        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, 0x7F << 1 | I2C_MASTER_WRITE, true);  // 使用不存在的地址
        i2c_master_stop(cmd);
        esp_err_t test_ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(100));
        i2c_cmd_link_delete(cmd);
        
        if (test_ret == ESP_ERR_TIMEOUT) {
            ESP_LOGE(TAG, "I2C总线测试超时，可能总线异常");
            retry_count++;
            i2c_driver_delete(I2C_MASTER_NUM);
            vTaskDelay(pdMS_TO_TICKS(100));
            continue;
        }
        
        ESP_LOGI(TAG, "I2C主机初始化成功 (重试%d次)", retry_count);
        return ESP_OK;
    }
    
    ESP_LOGE(TAG, "I2C主机初始化最终失败，已重试%d次", max_retries);
    return ESP_FAIL;
} 