/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : i2c0_slave.c
 * Description : i2c0_slave source file
 * Author(s)   : Neil
 * version     : V1.0
 * Modify date : 2019-05-22
 ***********************************************************************/
#include  "i2c0_slave.h"


/************************************************************************
 * function   : i2c_get_int_status
 * Description: i2c_get_int_status
 * input : none
 * return: 1: IFLG status is 1, 0: IFLG status is 0
 ************************************************************************/
uint8_t i2c_get_int_status(void)
{
	if(REG_I2C_CR & I2C_CR_IFLG) 	
		return 1;
	else 							
		return 0;	
}

/************************************************************************
 * function   : i2c_get_status
 * Description: i2c_get_status
 * input : none
 * return: status_flag
 ************************************************************************/
uint8_t i2c_get_status(void)
{
	return REG_I2C_STAT;
}

/************************************************************************
 * function   : i2c_write_byte
 * Description: i2c_write_byte
 * input : 发送的数据（1 Byte）
 * return: rdata: send_result
 ************************************************************************/
static void i2c_write_byte(uint8_t data)
{
	REG_I2C_DATA = data;
}

/************************************************************************
 * function   : i2c_read_byte
 * Description: i2c_read_byte
 * input : none
 * return: rdata: 接收数据（1 Byte）
 ************************************************************************/
uint8_t i2c_read_byte(void)
{
	return REG_I2C_DATA;
}

/************************************************************************
 * function   : i2c_wait_state
 * Description: i2c_wait_state
 * input : 
			uint8_t status: expected status
			uint32_t wait_time: wait time
 * return: 0:TIMEOUT  1: expected status OK ，2：unexpected status OK   
 ************************************************************************/
static uint8_t i2c_wait_state(uint8_t status,uint32_t wait_time)
{
	uint8_t value;
	
	while(wait_time--)	
	{
		value = REG_I2C_STAT;
		if (value == status)   //状态匹配
		{	
			return 1;
		}	
		
		if ((value==I2C_STA_TX_ADDR_W_NAK)||
			  (value==I2C_STA_TX_DATA_NAK)  ||
		    (value==I2C_STA_TX_ADDR_R_NAK)||
		    (value==I2C_STA_SLAVE_TX_DATA_NAK))
		{
			return 2;
		}	
		
		if (value == I2C_STA_SLAVE_RX_STP_RSTA)
		{
			return 3;
		}			
	}
	return 0; 
}

/************************************************************************
 * function   : i2c_write_byte_wait_status
 * Description: i2c_write_byte_wait_status
 * input : byte
 * return:  result ，0 error， other：OK  
 ************************************************************************/
static uint8_t i2c_write_byte_wait_status(uint8_t byte,uint8_t status)
{
	uint8_t result = 0;

	i2c_write_byte(byte);   
	REG_I2C_CLR |= I2C_CR_IFLG;				//清中断标志 ，数据填好后清标志（slave下 释放时钟，master下开始发时钟）
	result = i2c_wait_state(status,I2C_TIMEOUT);
	
	return result;
}

/************************************************************************
 * function   : i2c_read_byte_wait_status
 * Description: i2c_read_byte_wait_status
 * input : byte
 * return: result, 0: error， other: OK  
 ************************************************************************/
static uint8_t i2c_read_byte_wait_status(uint8_t *byte, uint8_t status)
{
    uint8_t result = 0;
	
    result = i2c_wait_state(status,I2C_TIMEOUT);
    if(result==1)
    {
			*byte = i2c_read_byte();
			REG_I2C_CLR |= I2C_CR_IFLG;		//清中断标志 ，数据读走后清标志（slave下 释放时钟，master下开始发时钟）
    }
		
    return result;
}

/*----------------------------SLAVE MODE------------------------------------*/

volatile static uint8_t i2c_tx_flag=0;
void (*i2c_func[2])(void) = { 0 };

 /************************************************************************
 * function   : I2C_IRQHandler
 * Description: I2C_IRQHandler
 * input : I2C的中断处理函数
 * return: 
 ************************************************************************/
#ifdef I2C_Rx_INT_MODE
void I2C0_IRQHandler(void)
{
	uint8_t temp;

	temp = REG_I2C_STAT;
	if( temp == I2C_STA_SLAVE_RX_DEVADDRW_ACK )      	// 60:接收到slave 地址+W
	{
		;
	}
	else if(temp == I2C_STA_SLAVE_LRX_ADDR_ACK)       	// 80: Rx int  //统一回ACK，不回NACK
	{
		if(i2c_func[0]!= 0)
		{
			((void(*)())(i2c_func[0]))();  				//接收处理回调函数
		}	
	}
	else if(temp == I2C_STA_SLAVE_RX_STP_RSTA)       	// A0:  STOP
	{
		;
	}	
	
#ifdef I2C_Tx_INT_MODE	//中断方式		
	else if( temp == I2C_STA_SLAVE_RX_ADDR_ACK )      // A8:接收到slave 地址+R
	{
		;
	}	
	else if( (temp ==I2C_STA_SLAVE_TX_DATA_ACK)||(temp ==I2C_STA_SLAVE_TX_DATA_NACK) )  //B8,C0： Tx int 发送中断
	{
		i2c_tx_flag=1;
	}	
#endif			
	else		//其他状态
	{		
		;
	}
	
	REG_I2C_CLR |= I2C_CR_IFLG;        //清除中断标志			
}

/************************************************************************
 * function   : i2c_irq_init
 * Description: i2c interrupt enable
 * input : 
 *         uint8_t irqstate: 0 interrupt diable ，1 interrupt enable
 * 		   *pfunc_rec)(): receive callback function
 *		   *pfunc_send)() send callback function
 * return: none
 ************************************************************************/
void i2c_irq_init(uint8_t irqstate, void (*pfunc_recv)(), void (*pfunc_send)())
{
	if(irqstate == I2C_IRQ_ENABLE)
	{
		i2c_func[0] = pfunc_recv;         
		i2c_func[1] = pfunc_send;   

		NVIC_ClearPendingIRQ(I2C0_IRQn);	
		NVIC_EnableIRQ(I2C0_IRQn);		
	} 
	else		
	{
		NVIC_ClearPendingIRQ(I2C0_IRQn);
		NVIC_DisableIRQ(I2C0_IRQn);
	} 
}
#endif

/************************************************************************
 * function   : i2c_init
 * Description: i2c pin init, config interruption
 * input : device type: slave or master
 * return: none
 ************************************************************************/
void i2c_slave_init(void)
{	
	REG_SCU_IOCTRLPROTECT = (uint32_t)0xA5A55A5A;       	// 关闭IO写保护
	
	REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<4)))|(0xF<<4);   //PF1复用为I2C0_SCL
	REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<12)))|(0x3<<12);	//PE3复用为I2C0_SDA			
	
    REG_SCU_IOCTRLPROTECT = (uint32_t)0xFFFFFFFF;       	// IO写保护 

	REG_SCU_PERICLKEN |= I2C_CLKEN; 						// 开启I2C时钟 
	REG_SCU_PERIRESET |= I2C_RESET;			 				// SCU复位控制寄存器 	
	REG_I2C_SRST = 1;							        	// i2c 复位   

#ifdef I2C_Rx_INT_MODE
	REG_I2C_CR = I2C_CR_ENAB|I2C_CR_AAK|I2C_CR_IEN ;    	// 从模式使能，AAK使能，中断使能   
#else
	REG_I2C_CR = I2C_CR_ENAB|I2C_CR_AAK ;       	        // 从模式使能，AAK使能
#endif

#ifdef I2C_7BIT_ADDR		
	REG_I2C_SAD0 = I2C_SLAVE_ADDR << 1;
	REG_I2C_SADM0= 0xfe;	
	REG_I2C_XSADM0 = (uint32_t)0x00;   				//屏蔽10bit地址
#else 
	REG_I2C_XSAD0 = I2C_SLAVE_ADDR << 1;		
	REG_I2C_XSADM0= 0x7fe;
	REG_I2C_SADM0 = (uint32_t)0x00;    				//屏蔽7bit地址
	REG_I2C_SADM1 = (uint32_t)0x00;    				//屏蔽7bit地址
	REG_I2C_SADM2 = (uint32_t)0x00;    				//屏蔽7bit地址
	REG_I2C_SADM3 = (uint32_t)0x00;    				//屏蔽7bit地址
#endif
}

/************************************************************************
 * function   : i2c_slave_send_data
 * Description: i2c从机发送处理函数
 * input      : 
			          uint8_t *buff  : data buffer
			          uint32_t length: send data length      
 * return     : status
 ************************************************************************/
uint8_t i2c_slave_send_data(uint8_t *buff, uint32_t length)
{
	uint32_t i=0;
	uint8_t status = 0;
	
	REG_I2C_CR  |= I2C_CR_AAK;   	//ACK
	REG_I2C_CLR |= I2C_CR_IEN ;     //中断屏蔽
	
#ifdef I2C_7BIT_ADDR	
//	status=i2c_wait_state(I2C_STA_SLAVE_RX_ADDR_ACK, 0xFFFFFFFF);   //A8;接收到自身地址+R ，死等master消息
	status=i2c_wait_state(I2C_STA_SLAVE_RX_ADDR_ACK, I2C_TIMEOUT);
    if(status !=1)	goto __ERROR;	
#else		
	status=i2c_wait_state(I2C_STA_SLAVE_RX_DEVADDRW_ACK,0xFFFFFFFF);   //60;接收到自身地址+W 
	if(status !=1)	goto __ERROR;	
	REG_I2C_CLR |= I2C_CR_IFLG;		//清中断标志 ， 释放时钟
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA,I2C_TIMEOUT);   //A0; restart
	if(status !=1)	goto __ERROR;	
	REG_I2C_CLR |= I2C_CR_IFLG;		//清中断标志 ， 释放时钟		
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_ADDR_ACK,I2C_TIMEOUT);   //A8;接收到自身地址+R 
	if(status !=1)	goto __ERROR;		
#endif

	for(i=0;i<length;i++)
	{ 	   
		status=i2c_write_byte_wait_status(buff[i], I2C_STA_SLAVE_TX_DATA_ACK);   //B8; 发data等ACK
		if( (status==0)||(status==3)) 	goto __ERROR;	 //超时或意外接收到stop		
		if(status==2)   break;				//收到NAK（到了master实际可接收的长度）		
	}
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA,I2C_TIMEOUT);   				//A0; 等待接收stop
	if(status==0) 	goto __ERROR;	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	REG_I2C_CR |= I2C_CR_IEN ;     	// 中断使能  	
	
	return 1;

__ERROR:
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	REG_I2C_CR |= I2C_CR_IEN ;     	// 中断使能 
 	
	return 0;
}

/************************************************************************
 * function   : i2c_slave_mixsend_data
 * Description: i2c从机发送处理函数 for (模拟EEPROM的角色示例)
 * input      : 
			          uint8_t *buff  : data buffer
			          uint32_t length: receive data length      
 * return     : status
 ************************************************************************/
uint8_t i2c_slave_mixsend_data(uint8_t addr_len, uint32_t data_len)
{
	uint8_t  status = 0;
	uint32_t i=0;
	uint32_t* perom_addr = 0;
	uint32_t  erom_addr = 0;
	uint8_t*  pbuff_addr = 0;
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_DEVADDRW_ACK, 0xFFFFFFFF);   //60;接收到自身地址+W ，死等master消息
	if(status !=1)	
    {
        goto __ERROR;
    }
		
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	perom_addr = &erom_addr;
	
//-- receive write address 4byte
	for( i=0; i<addr_len; i++)
	{
		status = i2c_read_byte_wait_status(((uint8_t *)perom_addr)+i, I2C_STA_SLAVE_LRX_ADDR_ACK); //80; 接收到数据，返回ACK
		if(status !=1)	
        {
            goto __ERROR;
        }	
	}
  
//-- restart	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA, I2C_TIMEOUT);   //A0; restart
	if(status !=1)	
    {
        goto __ERROR;
    }	
	REG_I2C_CLR |= I2C_CR_IFLG;				 //清中断标志 ， 释放时钟		
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_ADDR_ACK, I2C_TIMEOUT);   	//A8;接收到自身地址+R 
	if(status !=1)	
    {
        goto __ERROR;	
    }
	
	REG_I2C_CLR |= I2C_CR_IFLG;				 //清中断标志 ， 释放时钟
	pbuff_addr = (uint8_t*)erom_addr;  //msater transform the eeprom address
	
	for(i=0; i<data_len; i++)
	{ 
		status = i2c_write_byte_wait_status(pbuff_addr[i], I2C_STA_SLAVE_TX_DATA_ACK); //B8; 发data等ACK
		if(status==0 || status==3) 	
        {
            goto __ERROR;	
        }	
		if(status==2) 	break;    		//收到NAK（到了master实际可接收的长度）						
	}	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA, I2C_TIMEOUT);   	//A0; 等待接收stop
	if(status==0) 	
    {
        goto __ERROR;
    }	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
	
	return 1;
	
__ERROR:
		REG_I2C_CLR |= I2C_CR_IFLG;		//清中断标志 ， 释放时钟
	
	return 0;
}

#ifndef I2C_Rx_INT_MODE
/************************************************************************
 * function   : i2c_slave_recv_data_polling
 * Description: i2c从机接收处理函数,查询模式 ，如果不知道数据长度，可以输入一个很大的值，比如；256
 * input      : 
			           uint8_t *buff  : data buffer
			           uint32_t length: receive data length , （传入的length可能大于master实际发送的数据长度）
 * return     : 
                 0: error， 1: OK  
 ************************************************************************/
uint8_t i2c_slave_recv_data(uint8_t *buff, uint32_t length)
{
	uint8_t status = 0;
	uint32_t i=0;

	status=i2c_wait_state(I2C_STA_SLAVE_RX_DEVADDRW_ACK,I2C_TIMEOUT);   	//60;接收到自身地址+W 
	if(status !=1)	goto __ERROR;
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
	for(i=0;i<length;i++)
	{ 
#ifdef I2C_NACK					
		if(i==(length-1))							//最后一个字节回NAK
		{
			REG_I2C_CLR |= (1<<2);    	//NAK  
			status = i2c_read_byte_wait_status(buff++, I2C_STA_SLAVE_LRX_ADDR_NAK); //88; 接收到数据，返回NACK
			REG_I2C_CR |= I2C_CR_AAK;   //恢复ACK
			
			if(status==0) 	
				return 0;
			if(status==3) 	
				return 1;									//A0; 已收到stop（覆盖了NACK）	
			
			break;
		}	
#endif

		status = i2c_read_byte_wait_status(buff++, I2C_STA_SLAVE_LRX_ADDR_ACK); //80; 接收到数据，返回ACK
		if(status==0) 	goto __ERROR;
		
		if(status==3) 	//特殊情况：提前收到stop结束（针对length大于master实际发送的数据长度）
		{
			REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
			return 1;			//提前结束流程	
		}
	}	
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA,I2C_TIMEOUT);   	//A0; 等待接收stop
	if(status==0) 	goto __ERROR;	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
	
	return 1;
	
__ERROR:
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	
	return 0;
}

/************************************************************************
 * function   : i2c_slave_mixrecv_data_polling
 * Description: i2c从机接收处理函数,查询模式 ，如果不知道数据长度，可以输入一个很大的值，比如；256
 * input      : 
			           uint8_t *buff  : data buffer
			           uint32_t length: receive data length , （传入的length可能大于master实际发送的数据长度）
 * return     : 
                 0: error， 1: OK  
 ************************************************************************/
uint8_t i2c_slave_mixrecv_data(uint8_t addr_len,uint8_t * buff, uint32_t data_len)
{
	uint8_t  status = 0;
	uint32_t i=0;
	uint32_t* perom_addr = 0;
	uint32_t  erom_addr = 0;
	uint8_t*  pbuff_addr = 0;
			
	status=i2c_wait_state(I2C_STA_SLAVE_RX_DEVADDRW_ACK,I2C_TIMEOUT);   	//60;接收到自身地址+W 
	if(status !=1)	goto __ERROR;	

	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟

	perom_addr = &erom_addr;	
//-- receive write address 4byte
	for( i=0; i<addr_len; i++)
	{
		status = i2c_read_byte_wait_status(((uint8_t *)perom_addr)+i, I2C_STA_SLAVE_LRX_ADDR_ACK); //80; 接收到数据，返回ACK
		if(status !=1)	goto __ERROR;	
	}
  
//-- restart	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA,I2C_TIMEOUT);   //A0; restart
	if(status !=1)	goto __ERROR;	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟		
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_DEVADDRW_ACK,I2C_TIMEOUT);   	//60;接收到自身地址+W 
	if(status !=1)	goto __ERROR;	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	pbuff_addr = (uint8_t*)erom_addr;  //msater tranfrom the eeprom address
	
	for(i=0; i< data_len; i++)
	{ 
#ifdef I2C_NACK					
		if(i==(data_len - 1))	//最后一个字节回NAK
		{
			REG_I2C_CLR |= (1<<2);    	//NAK  
			status = i2c_read_byte_wait_status(pbuff_addr+i, I2C_STA_SLAVE_LRX_ADDR_NAK); //88; 接收到数据，返回NACK
			REG_I2C_CR |= I2C_CR_AAK;   //恢复ACK
			
			if(status==0) 	return 0;
			if(status==3) 	return 1;		//A0; 已收到stop（覆盖了NACK）	
			
			break;
		}			
#endif

		status = i2c_read_byte_wait_status(pbuff_addr+i, I2C_STA_SLAVE_LRX_ADDR_ACK); //80; 接收到数据，返回ACK
		if(status==0) 	goto __ERROR;
		
		if(status==3) 	//特殊情况：提前收到stop结束（针对length大于master实际发送的数据长度）
		{
			REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
			return 1;	//提前结束流程	
		}
	}	
	
	status=i2c_wait_state(I2C_STA_SLAVE_RX_STP_RSTA,I2C_TIMEOUT);   	//A0; 等待接收stop
	if(status==0) 	goto __ERROR;	
	
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟	
	
	return 1;
	
__ERROR:
	REG_I2C_CLR |= I2C_CR_IFLG;			//清中断标志 ， 释放时钟
	
	return 0;
}
#endif





