#include "AI8051U_I2C.h"
#include "AI8051U.h"

#define		I2C_Function(n)		(n==0?(I2CCFG &= ~0x80):(I2CCFG |= 0x80))	//0：禁止 I2C 功能；1：使能 I2C 功能
#define		I2C_ENABLE()		I2CCFG |= 0x80		/* 使能 I2C 功能 */
#define		I2C_DISABLE()		I2CCFG &= ~0x80		/* 禁止 I2C 功能 */
#define		I2C_Master()		I2CCFG |=  0x40		/* 1: 设为主机	*/
#define		I2C_Slave()			I2CCFG &= ~0x40		/* 0: 设为从机	*/
#define		I2C_SetSpeed(n)		I2CCFG = (I2CCFG & ~0x3f) | (n & 0x3f)	/* 总线速度=Fosc/2/(Speed*2+4) */

#define		I2C_WDTA_EN()		I2CMSAUX |= 0x01		/* 使能自动发送 */
#define		I2C_WDTA_DIS()		I2CMSAUX &= ~0x01		/* 禁止自动发送 */

#define		I2C_Address(n)		I2CSLADR = (I2CSLADR & 0x01) | (n << 1)	/* 从机地址 */
#define		I2C_MATCH_EN()		I2CSLADR &= ~0x01	/* 使能从机地址比较功能，只接受相匹配地址 */
#define		I2C_MATCH_DIS()		I2CSLADR |= 0x01	/* 禁止从机地址比较功能，接受所有设备地址 */

#define		I2C_ESTAI_EN(n)		I2CSLCR = (I2CSLCR & ~0x40) | (n << 6)		/* 使能从机接收START信号中断 */
#define		I2C_ERXI_EN(n)		I2CSLCR = (I2CSLCR & ~0x20) | (n << 5)		/* 使能从机接收1字节数据中断 */
#define		I2C_ETXI_EN(n)		I2CSLCR = (I2CSLCR & ~0x10) | (n << 4)		/* 使能从机发送1字节数据中断 */
#define		I2C_ESTOI_EN(n)		I2CSLCR = (I2CSLCR & ~0x08) | (n << 3)		/* 使能从机接收STOP信号中断 */
#define		I2C_SLRET()			I2CSLCR |= 0x01			/* 复位从机模式 */

#define		I2C_MSCMD(n)		I2CMSCR = (n)		/* 主机命令 */

//bit busy;

//void I2C_isr() interrupt 24
//{
//	if(I2CMSST & 0x40)
//	{
//		I2CMSST &= ~0x40;
//		busy = 0;
//	}
//}

void i2c_init()
{
	I2C_S1 = 0;
	I2C_S0 = 0;
//	P2SR &= ~0x18; 
//	P2NCS &= ~0x18; 

	I2C_Master();
	I2CMSST = 0x00;		//清除I2C主机状态寄存器

	/*  总线速度 =Fosc/2/(MSSPEED*2+4)在40M的F0sc中，此处总线速度设置为100k */
	I2CCFG = 0xE2;
	I2CPSCR = 0x01;
	
	I2C_WDTA_EN();
	I2C_Function(1);
	
}

/**
 * @brief 等待主机模式I2C控制器执行完成I2CMSCR.
 * @param  None.
 * @return None.
 */
static void i2c_wait()
{
	while (!(I2CMSST & 0x40));
	I2CMSST &= ~0x40;
}

/**
 * @brief I2C总线起始函数.
 * 
 * @param  None.
 * @return None.
 */
static void i2c_start()
{
	I2CMSCR = 0x01;                         //发送START命令
	i2c_wait();
//	busy = 1;
//	while(busy);
}

/**
 * @brief I2C发送一个字节数据函数.
 * @param  byte 需要发送的字节
 * @return None.
 */
static void i2c_write_byte(uint8_t byte)
{
	I2CTXD = byte;                           //写数据到数据缓冲区
	I2CMSCR = 0x02;                         //发送SEND命令
	i2c_wait();
}

///**
// * @brief I2C获取ACK函数.
// * @param  None.
// * @return None.
// */
//static void i2c_rec_ack()
//{
//	I2CMSCR = 0x03;                         //发送读ACK命令
//	i2c_wait();
//}

/**
 * @brief I2C读取一个字节数据函数.
 * @param  None.
 * @return I2CRXD寄存器储存的数据.
 */
static uint8_t i2c_read_byte()
{
	I2CMSCR = 0x04;                         //发送RECV命令
	i2c_wait();
	return I2CRXD;
}

/**
 * @brief I2C发送ACK函数.
 * @param  None.
 * @return None.
 */
static void i2c_send_ack()
{
	I2CMSST = 0x00;                         //设置ACK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	i2c_wait();
}

/**
 * @brief I2C发送NACK函数.
 * @param  None.
 * @return None.
 */
static void i2c_send_nack()
{
	I2CMSST = 0x01;                         //设置NAK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	i2c_wait();
}

/**
 * @brief I2C总线停止函数.
 * @param  None.
 * @return None.
 */
static void i2c_stop()
{
	I2CMSCR = 0x06;                         //发送STOP命令
	i2c_wait();
//		busy = 1;
//	while(busy);
}

/**
 * @brief 写入数据
 * @param  指向I2CObjectTypeDef类型的指针
 * @return None.
 */
void i2c_write_data(uint8_t dev_addr, uint8_t reg, uint8_t* _pdata, uint16_t len)
{
	uint8_t i;
	i2c_start();
	i2c_write_byte(dev_addr);
//	I2C_rec_ack();
	i2c_write_byte(reg);
//	I2C_rec_ack();
	for(i = 0; i < len; i++)
	{
		i2c_write_byte(_pdata[i]);
//		I2C_rec_ack();
	}
	i2c_stop();
}

/**
 * @brief 读出数据
 * @param  指向I2CObjectTypeDef类型的指针
 * @return None.
 * @attention 使用了I2C_write_byte函数后不需要手动再给个ACK信号,将数据写入到
 */
void i2c_read_data(uint8_t dev_addr, uint8_t reg, uint8_t* _pdata, uint16_t len)
{
	uint8_t i;
	i2c_start();
	i2c_write_byte(dev_addr);
//	I2C_rec_ack();
	i2c_write_byte(reg);
	i2c_stop();
//	I2C_rec_ack();
	i2c_start();
	i2c_write_byte(dev_addr | 1);
//	I2C_rec_ack();
	for(i = 0; i < len; i++)
	{
		_pdata[i] =  i2c_read_byte();
		if(i < len - 1)
		{
			i2c_send_ack();
		}
		else
		{
			i2c_send_nack();
		}
	}
	i2c_stop();
}


