/********************************************************************************
Copyright (C), Sinowealth Electronic. Ltd.
Author: 	Sino
Version: 	V0.0
Date: 		2020/04/26
History:
	V2.0	2020/04/26		 Preliminary
********************************************************************************/
#include "Main.h"

#ifdef TWI_Hardware_Module 

U8 code CRC8Table[256]=
{							//120424-1			CRC Table
	0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,
	0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,
	0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,
	0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,
	0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,
	0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,
	0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,
	0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,
	0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,
	0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4,
	0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,
	0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,
	0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,
	0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,
	0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,
	0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3
};
/*************************************************************************************************
* 函数名: CRC8cal
* 参  数: *p：数据指针；counter：所需计算的长度
* 返回值: 无
* 描  述: CRC8就散
*************************************************************************************************/
U8 CRC8cal(U8 *p, U8 counter)                   //look-up table calculte CRC 
{    
    U8 crc8 = 0;
    
	for( ; counter > 0; counter--)
	{
		crc8 = CRC8Table[crc8^*p];    
	    p++;    
    }    
    return(crc8);    
}   




/*************************************************************************************************
* 函数名: TWICheckStatus
* 参  数: Status：当前TWI的状态
* 返回值: 无
* 描  述: 检测TWI的各个状态是否正常
*************************************************************************************************/
BOOL TWICheckStatus(U8 Status)
{
	BOOL Result = 1;
    U16 timeoutcount = 48000;  //硬件IIC时timeoutcount大于100可正常通讯，软件IIC建议保持原值  （标准DEMO板）

	while((TWICON&0x08)==0)                     //等待TWI通讯结束
    {
		McuWDTClear();                          //清除看门狗
        if(timeoutcount)
        {
            timeoutcount--;
        }
        else
        {
            break;
        }
    }
	if((TWISTA&0xf8) != Status)
	{
		Result = 0;                             //Error
	}
	
	return Result;
}




/*************************************************************************************************
* 函数名: TwiWrite
* 参  数: SlaveID:	Slave ID
          WrAddr:	写入地址
          AddrType：地址长度，0：长度为1Byte；1：长度为2Bytes
          Length：	数据长度（不含CRC字节）
          CrcFlg：	Twi通讯是否支持CRC校验，0：不支持CRC，1：支持CRC
          *WrBuf：	写入数据存放地址
* 返回值: 无
* 描  述: Twi写入操作，包括写入AFE（支持CRC）、RTC和EEPROM（地址长度为2Bytes）
*************************************************************************************************/
BOOL TwiWrite(U8 SlaveID, U16 WrAddr, U8 AddrType, U8 Length, U8 CrcFlg, U8 xdata *WrBuf)
{
	U8 i;
    U8 TempBuf[4];
	BOOL Result = 1;
	U16 timeoutcount = 48000;
	
    TempBuf[0] = SlaveID;
    TempBuf[1] = (U8)WrAddr;
    TempBuf[2] = *WrBuf;
    TempBuf[3] = CRC8cal(TempBuf, 3);

	if(Length > 0)
	{
		HTimeoutChk();
		TWICON = 0x60;                          //Start
		if((!TWICheckStatus(0x08))&&(!TWICheckStatus(0x10)))
		{
			Result = 0;
			goto WrErr;
		}
		
		TWIDAT = SlaveID;                       //Slave地址
		TWICON = 0x40;
		if(!TWICheckStatus(0x18))
		{
			Result = 0;
			goto WrErr;
		}
		
		if(AddrType == TWI_ADDR_2B)
		{
			TWIDAT = (U8)(WrAddr>>8);           //写寄存器高字节地址-仅针对外挂EEPROM
			TWICON = 0x40;
			if(!TWICheckStatus(0x28))
			{
				Result = 0;
				goto WrErr;
			}
		}

		TWIDAT = (U8)WrAddr;                    //写寄存器地址
		TWICON = 0x40;
		if(!TWICheckStatus(0x28))
		{
			Result = 0;
			goto WrErr;
		}
		
		if(CrcFlg == TWI_CRC_YES)               //如果是写AFE寄存器，则固定写一个字节+CRC
		{
			TWIDAT = *WrBuf;                    //Write Data
			TWICON = 0x40;
			if(!TWICheckStatus(0x28))
			{
				Result = 0;
				goto WrErr;
			}
			
			TWIDAT = TempBuf[3];                //Write CRC
			TWICON = 0x40;
			if(!TWICheckStatus(0x28))
			{
				Result = 0;
				goto WrErr;
			}
		}
		else                                    //写EEPROM和RTC
		{
			for(i=0; i<Length; i++)
			{
				TWIDAT = *WrBuf;
				TWICON = 0x40;
				if(!TWICheckStatus(0x28))
				{
					Result = 0;
					goto WrErr;
				}
				WrBuf++;
			}
		}
WrErr:
		TWICON = 0x50;
		while((TWICON&0x10)!=0)
        {
			McuWDTClear();                      //清除看门狗
            if(timeoutcount)
            {
                timeoutcount--;
            }
            else
            {
                break;
            }
        }
	}
	
	return Result;
}


/*************************************************************************************************
* 函数名: TwiRead
* 参  数: SlaveID:	Slave ID
          RdAddr:	读取地址
          AddrType：地址长度，0：长度为1Byte；1：长度为2Bytes
          Length：	数据长度（不含CRC字节）
          CrcFlg：	Twi通讯是否支持CRC校验，0：不支持CRC，1：支持CRC
          *RdBuf：	读取数据存放地址
* 返回值: 无
* 描  述: Twi读取操作，包括读取AFE（支持CRC）、RTC和EEPROM（地址长度为2Bytes）
*************************************************************************************************/
BOOL TwiRead(U8 SlaveID, U16 RdAddr, U8 AddrType, U8 Length, U8 CrcFlg, U8 xdata *RdBuf)
{
	BOOL Result = 1;
	U8 i;
    U8 xdata TempBuf[46];                        //AFE一次性读取2Bytes+CRC
    U8 RdCrc = 0;
    U16 timeoutcount = 48000;
	
    TempBuf[0] = SlaveID;                       //缓存到TempBuf，主要是为了计算CRC，仅用于AFE读取
    TempBuf[1] = (U8)RdAddr;
    //TempBuf[2] = Length;
    TempBuf[2] = SlaveID | 0x01;
	
	if(Length > 0)
	{
		HTimeoutChk();
		TWICON = 0x60;                          //Start
		if((!TWICheckStatus(0x08))&&(!TWICheckStatus(0x10)))
		{
			Result = 0;
			goto RdErr;
		}
		
		TWIDAT = SlaveID;                       //发送Slave写地址
		TWICON = 0x40;
		if(!TWICheckStatus(0x18))
		{
			Result = 0;
			goto RdErr;
		}

		if(AddrType == TWI_ADDR_2B)             //地址为2Bytes
		{
			TWIDAT = (U8)(RdAddr>>8);           //读寄存器高字节地址-仅针对外挂EEPROM
			TWICON = 0x40;
			if(!TWICheckStatus(0x28))
			{
				Result = 0;
				goto RdErr;
			}
		}
		
		TWIDAT = (U8)RdAddr;                    //发送寄存器低字节地址
		TWICON = 0x40;
		if(!TWICheckStatus(0x28))
		{
			Result = 0;
			goto RdErr;
		}
				
//        if(SlaveID != AFE_ID)
//		{
//			TWIDAT = Length;                    //发送读取数据长度
//			TWICON = 0x40;
//			if(!TWICheckStatus(0x28))
//			{
//				Result = 0;
//				goto RdErr;
//			}
//		}
				
		TWICON = 0x60;                          //发送RStart
		if((!TWICheckStatus(0x08))&&(!TWICheckStatus(0x10)))
		{
			Result = 0;
			goto RdErr;
		}

		TWIDAT = SlaveID|0x01;                  //发送Slave读地址
		TWICON = 0x40;
		if(!TWICheckStatus(0x40))
		{
			Result = 0;
			goto RdErr;
		}
		
		for(i=0; i<Length; i++)
		{
			if((CrcFlg == TWI_CRC_NO))          //不支持CRC
			{
				if(i == Length-1)
				{
					TWICON = 0x40;              //发送NACK，最后一次读
					TWICheckStatus(0x58);
				}
				else
				{
					TWICON = 0x44;              //发送ACK，继续读
					TWICheckStatus(0x50);
				}
				*RdBuf = TWIDAT;
				RdBuf++;
			}
			else                                //支持CRC的，现将数据放在临时Buf
			{
				TWICON = 0x44;                  //ACK
				TWICheckStatus(0x50);
				TempBuf[3+i] = TWIDAT;
			}
		}
		
		if(CrcFlg == TWI_CRC_YES)
		{
			TWICON = 0x40;                      //No ACK
			TWICheckStatus(0x58);
			RdCrc = TWIDAT;
			if(RdCrc == CRC8cal(TempBuf, 3+Length))
			{
				for(i=0; i<Length; i++)
				{
					*RdBuf = TempBuf[3+i];
					RdBuf++;
				}
			}
			else
			{
				Result = 0;
				goto RdErr;
			}
		}
RdErr:
		TWICON = 0x50;                          //TWI Stop
		while((TWICON&0x10)!=0)
        {
			McuWDTClear();                      //清除看门狗
            if(timeoutcount)
            {
                timeoutcount--;
            }
            else
            {
                break;
            }
        }
	}
	
	return Result;
}


/*************************************************************************************************
* 函数名: TwiInit
* 参  数: FreqKHz: 设置TWI通讯频率
* 返回值: 无
* 描  述: 初始化TWI的映射IO及通讯频率等
//*************************************************************************************************/
//void TwiInit(void)
//{
//	TWICR = 0x32;                               //默认配置：SCL--P0.5；SDA--P0.4
//	TWITOUT = 0x00;                             //外部有上拉电阻，故芯片内部上拉不用使能
//	TWIBR = (24000/TWI_FREQ_KHz-16)/2/1;            //配置发送波特率，禁止总线超时判断，f=fsys/(16+2*CR*TWIBR)=24MHz/(16+2*16*TWIBR)=**KHz
//	TWISTA = 0x06;                              //16分频
//	TWICON = 0x40;                              //ENTWI ，禁止高电平超时
//	TWTFREE = 0xff;                             //最大超时配置
//	TWIDAT = 0x00;
//}

void TwiInit(void)
{	
	TWICR = 0x32;                               //默认配置：SCL--P0.5；SDA--P0.4
	TWITOUT = 0x00;                             //外部有上拉电阻，故芯片内部上拉不用使能
	TWISTA = 0x00;
	TWIBR = (8000/TWI_FREQ_KHz-16)/2/1;            //配置发送波特率，禁止总线超时判断，f=fsys/(16+2*CR*TWIBR)=24MHz/(16+2*16*TWIBR)=**KHz
	TWISTA = 0x02;                              //16分频
//	#if ((TWI_FREQ_KHz >= 10)&&(TWI_FREQ_KHz <= 400))
//	{
//		#if TWIBR1 < 256
//			TWIBR = TWIBR1;
//			TWISTA |= 0x06;
//		#elif TWIBR2 < 256
//			TWIBR = TWIBR2;
//			TWISTA |= 0x04;
//		#elif TWIBR3 < 256
//			TWIBR = TWIBR3;
//			TWISTA |= 0x02;
//		#elif TWIBR4 < 256
//			TWIBR = TWIBR4;
//			TWISTA |= 0x00;	
//		#endif
//	}
//	#else
//	{		
//		#error: "Please enter a number(TWI_FREQ_KHz) from 10 to 400!";
//	} 
//
//	#endif
	
	TWICON = 0x40;                              //ENTWI ，禁止高电平超时
	TWTFREE = 0xff;                             //最大超时配置
	TWIDAT = 0x00;
}


//void TwiInit(void)
//{
//	U16 i,k;
//	U8 j;
//	TWICR = 0x32;                               //默认配置：SCL--P0.5；SDA--P0.4
//	TWITOUT = 0x00;                             //外部有上拉电阻，故芯片内部上拉不用使能
//	i = (24000/TWI_FREQ_KHz-16)/2;            //配置发送波特率，禁止总线超时判断，f=fsys/(16+2*CR*TWIBR)=24MHz/(16+2*16*TWIBR)=**KHz
//	for(j=1;j<4;j++)
//	{
//		k =1<<(2*j-2);		
//		if(i / k <= 255)
//		{			
//			TWIBR = i / k;			
//			switch (j)
//			{
//				case 1:
//					TWISTA = 0x00;
//				break;
//				
//				case 2:
//					TWISTA = 0x02;
//				break;
//				
//				case 3:
//					TWISTA = 0x04;
//				break;
//				
//				case 4:
//					TWISTA = 0x06;
//				break;										
//			}	
//			goto loop;			
//		}					
//	}
//loop:
////	TWISTA = 0x06;                              //16分频
//	TWICON = 0x40;                              //ENTWI ，禁止高电平超时
//	TWTFREE = 0xff;                             //最大超时配置
//	TWIDAT = 0x00;
//}

#endif