/*************************************************
Copyright (c) 2025, 成都赛联科技有限责任公司
All rights reserved.
@file        drv_i2c.C
@brief       drv_i2c驱动程序

@details
@note
@author      dufresne
@date        2025/09/24

@version		v1.0 2025/09/24 初始版本
*************************************************/

#include "drv_i2c.h"


void i2c_init(void)
{
    i2c_gpio_config();

    #ifdef  HARDWARE_I2C
    i2c_config();
    #endif
}

/*
  @ brief  初始化i2c的GPIO引脚
  @ param
  @ return
  @ note  2025-09-15 
*/
void i2c_gpio_config(void)
{
	// 配置引脚时钟
	rcu_periph_clock_enable(RCU_GPIOB);

    #ifdef  HARDWARE_I2C
    gpio_af_set(GPIOB, GPIO_AF_4, I2C_SCL_PIN | I2C_SDA_PIN);
    /* 初始化GPIO复用功能模式 */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SCL_PIN | I2C_SDA_PIN);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN | I2C_SDA_PIN);
    #endif

    #ifdef  SOFTWARE_I2C
	// 设置引脚为输出模式:PB6
	gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I2C_SCL_PIN | I2C_SDA_PIN);
	gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SCL_PIN | I2C_SDA_PIN);
	I2C_SCL_HIGH;
	I2C_SDA_HIGH;
    #endif
}

#ifdef  HARDWARE_I2C
void i2c_config(void)
{
    // 启用 I2C 外设的时钟
	rcu_periph_clock_enable(RCU_I2C0);

  	i2c_deinit(I2C_PERIPH);

    // 配置 I2C 的时钟参数：
    // I2C_PERIPH：这里使用的I2C1
    // I2C_SPEED：通信速率（单位为 Hz，常用为 100000 或 400000），这里使用100000
    i2c_clock_config(I2C_PERIPH, I2C_SPEED, I2C_DTCY_2);
 
    // 配置 I2C 工作模式和地址：
    // I2C_ADDFORMAT_7BITS：使用 7 位地址模式
    i2c_mode_addr_config(I2C_PERIPH, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);//作为从机时的地址，随意设置即可

    // 使能 ACK 应答功能，确保在接收数据后自动发送 ACK
    i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);

    // 启用 I2C 外设
    i2c_enable(I2C_PERIPH);

}



void i2c_write(uint8_t *buff, int len, uint8_t device_address)
{
    /* 等待总线空闲 */
    while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY));
    /* 发送起始条件 */
    i2c_start_on_bus(I2C_PERIPH);
    /* 等待起始条件已发送标志 */
    while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));
    /* 发送从机地址（写模式） */
    i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_TRANSMITTER);
    /* 等待地址已发送标志 */
    while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
    /* 清除地址发送标志 */
    i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
    
    for(int i = 0; i < len; i++)
    {
        /* 等待发送数据缓冲区为空 */
        while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_TBE));
        /* 发送一个字节数据 */
        i2c_data_transmit(I2C_PERIPH, buff[i]);
    }
    /* 等待数据传输完成 */
    while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_TBE));
    /* 发送停止条件 */
    i2c_stop_on_bus(I2C_PERIPH);
    /* 等待停止条件发送完成 */
    while(I2C_CTL0(I2C_PERIPH) & I2C_CTL0_STOP); // 检查STPDET位或类似标志
}


//接收1字节数据
void i2c_read(uint8_t *buff, uint16_t len, uint8_t device_address)
{
	/* 等待I2C总线空闲 */
    while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY));

    /* 向I2C总线发送启动信号 */
    i2c_start_on_bus(I2C_PERIPH);
    /* 等待，直到设置SBSEND位 */
	while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));//设置主机发送启动条件
	
	/* 将从机地址发送到I2C总线 */
    i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_RECEIVER);//设置主机接收
	/* 等待地址位被设置 */
    while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
    /* 清除地址位 */
    i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
	/* 使能ACK（多个字节接收时需要应答） */
	i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);

    /* 5. 接收数据 */
    if(len > 1)
    {
        /* 使能ACK（多个字节接收时需要应答） */
        i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
        
        for(int i = 0; i < len; i++)
        {
            if(i == (len - 1))
            {
                /* 最后一个字节前禁用ACK */
                i2c_ack_config(I2C_PERIPH, I2C_ACK_DISABLE);
            }
            
            /* 等待RBNE标志（接收缓冲区非空） */
            while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_RBNE));
            
            /* 读取数据 */
            buff[i] = i2c_data_receive(I2C_PERIPH);
        }
    }
    else
    {
        /* 单字节接收：直接禁用ACK */
        i2c_ack_config(I2C_PERIPH, I2C_ACK_DISABLE);
        
        /* 等待RBNE标志 */
        while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_RBNE));
        
        /* 读取数据 */
        buff[0] = i2c_data_receive(I2C_PERIPH);
    }

		/* 发送停止信号 */
    i2c_stop_on_bus(I2C_PERIPH);
    /* 等待停止信号完成 */
    while(I2C_CTL0(I2C_PERIPH) & I2C_CTL0_STOP);
}

#endif