#include "hal_pca8565.h"
#include "hc32_ll_gpio.h"
#include "FreeRTOS.h"
#include "task.h"

#define IIC_ERR  0
#define IIC_OK   1

 
#define READ_SDA2   GPIO_ReadInputPins(GPIO_PORT_B,GPIO_PIN_12)

#define IIC_SDA2(n) (n?GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_12):GPIO_ResetPins(GPIO_PORT_B, GPIO_PIN_12))
#define IIC_SCL2(n) (n?GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_13):GPIO_ResetPins(GPIO_PORT_B, GPIO_PIN_13))



#define pca8565_speed 5
//需要示波器调1us的时间
static void delay_us(uint16_t time)
{
	uint16_t i;

	for(i=time;i>0;i--)
	{
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();		
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	  __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
		__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
	}
}


void iicx_init(void)
{
	stc_gpio_init_t  pstcGpioInit1;
	GPIO_StructInit(&pstcGpioInit1);
	
	pstcGpioInit1.u16PinDir = PIN_DIR_OUT;
	pstcGpioInit1.u16PinState = PIN_STAT_RST;
	GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit1); 
  GPIO_Init(GPIO_PORT_B, GPIO_PIN_13,&pstcGpioInit1); 
	
	GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_12);
	GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_13);
}

 
 
static void SDA_IN2(void)
{
	 stc_gpio_init_t pstcGpioInit3;//iic的引脚
	 pstcGpioInit3.u16PinDir = PIN_DIR_IN;
	 GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit3);
}

static void SDA_OUT2(void)  
{
	stc_gpio_init_t pstcGpioInit3;
	pstcGpioInit3.u16PinDir = PIN_DIR_OUT;
	pstcGpioInit3.u16PinOutputType=PIN_OUT_TYPE_NMOS;
	GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit3);
}	
 
 

static void iic_start(void)
{
	SDA_OUT2();
	
	IIC_SDA2(1);
	IIC_SCL2(1);
	delay_us(pca8565_speed);
	
	IIC_SDA2(0);
	delay_us(pca8565_speed);
	IIC_SCL2(0);
}


static void iic_stop(void)
{
	SDA_OUT2();
	
	IIC_SCL2(0);
	IIC_SDA2(0);
	delay_us(pca8565_speed);
	
	IIC_SCL2(1);
	IIC_SDA2(1);
	delay_us(pca8565_speed);
}

static void iic_ack(void)
{
	SDA_OUT2();
	
	IIC_SCL2(0);
	IIC_SDA2(0);
	delay_us(pca8565_speed);
	
	IIC_SCL2(1);
	delay_us(pca8565_speed);
	IIC_SCL2(0);
}

static void iic_nack(void)
{
	SDA_OUT2();
	
	IIC_SCL2(0);
	IIC_SDA2(1);
	delay_us(pca8565_speed);
	
	IIC_SCL2(1);
	delay_us(pca8565_speed);
	IIC_SCL2(0);
}
 

static uint8_t iic_wait_ack(void)
{
	uint16_t t =200;
	SDA_OUT2();
	
	IIC_SDA2(1);delay_us(1);
	IIC_SCL2(1);delay_us(1);

	SDA_IN2();

	while(READ_SDA2) 
	{
		t--;
		
		if(t==0)
		{
			iic_stop();
			return 1;
		}
		delay_us(1);
	}
	IIC_SCL2(0);
		
	return 0;
}


static void iic_send_byte(uint8_t byte)
{
  uint8_t bit_cnt;
	SDA_OUT2();
	IIC_SCL2(0);
	 
	for(bit_cnt=0;bit_cnt<8;bit_cnt++)
	{	 
		if(byte&0x80)	
			IIC_SDA2(1); 
		else	
			IIC_SDA2(0);
		
		byte<<=1;
		delay_us(pca8565_speed);
		IIC_SCL2(1);
		delay_us(pca8565_speed);
		IIC_SCL2(0);
	}
}
 

static uint8_t iic_recive_byte(unsigned char ack)
{
  uint8_t retc = 0;
  uint8_t bit_cnt;

	SDA_IN2(); 

	for(bit_cnt=0;bit_cnt<8;bit_cnt++)
	{
		IIC_SCL2(0);
		delay_us(pca8565_speed);
		IIC_SCL2(1);
		
		retc=retc<<1;
		if(READ_SDA2)
			retc++;
		
		delay_us(pca8565_speed);
	}
	return(retc);
}


/*
************************************************************
*	函数名称：	Pcf8563_IIC_WriteByte
*
*	函数功能：	软件IIC读取一个字节
*
*	入口参数：	slaveAddr：从机地址
*				regAddr：寄存器地址
*				val：需要读取的数据缓存
*
*	返回参数：	1-成功		0-失败
*
*	说明：		
************************************************************
*/
void Pcf8563_IIC_ReadByte ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Val )
{
//	//起始信号
//	iic_start();							
//	//发送设备地址(写)
//	if(!iic_send_byte ( SlaveAddr ))		//等待应答
//		 return IIC_ERR;
//	//发送寄存器地址
//	if(!iic_send_byte ( RegAddr ))	  //等待应答
//		 return IIC_ERR;
//	iic_start();				   			//重启信号
//	//发送设备地址(读)
//	if(!iic_send_byte ( SlaveAddr + 1 ))	//等待应答
//		 return IIC_ERR;
//	*Val = iic_recive_byte (0);  			//产生一个非应答信号，代表读取接收
//	iic_stop();					   			//停止信号
//	return IIC_OK;
	
	iic_start();								 		 
  iic_send_byte(SlaveAddr); 
  iic_wait_ack();  						 		 
  iic_send_byte(RegAddr);   		 		 
  iic_wait_ack();	    				 		 
  iic_start();  	 	   				 		 
  iic_send_byte(SlaveAddr|0x01);    
  iic_wait_ack();	 						 		 	
  *Val = iic_recive_byte(0);	 		    
  iic_stop();	
}



/*
************************************************************
*	函数名称：	Pcf8563_IIC_WriteByte
*
*	函数功能：	软件IIC写一个字节
*
*	入口参数：	slaveAddr：从机地址
*				regAddr：寄存器地址
*				val：需要读取的数据缓存
*
*	返回参数：	1-成功		0-失败
*
*	说明：		
************************************************************
*/
void Pcf8563_IIC_WriteByte ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Val )
{
//	iic_start();						//起始信号
//	//发送设备地址(写)
//	if (!iic_send_byte ( SlaveAddr ))	//等待应答
//		return IIC_ERR;
//	//发送寄存器地址
//	if (!iic_send_byte ( RegAddr ) )		//等待应答
//		return IIC_ERR; 
//	if (!iic_send_byte ( *Val ) )	 
//		return IIC_ERR;
// 
//	iic_stop();							//停止信号
//	return IIC_OK;
	
	iic_start();								 		 
  iic_send_byte(SlaveAddr); 
  iic_wait_ack();							 		 	
  iic_send_byte(RegAddr);   		 		 
  iic_wait_ack(); 	 					 		 				  		   
  iic_send_byte(*Val);      		 				   
  iic_wait_ack();  		    	   		 		 
  iic_stop();	
}

/*
************************************************************
*	函数名称：	Pcf8563_IIC_WriteBytes
*
*	函数功能：	软件IIC写多个数据
*
*	入口参数：	slaveAddr：从机地址
*				regAddr：寄存器地址
*				buf：需要写入的数据缓存
*               num：数据长度
*
*	返回参数：	1-成功		0-失败
*
*	说明：		
************************************************************
*/
_Bool Pcf8563_IIC_WriteBytes ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Buf, unsigned char Num )
{
	iic_start();						//起始信号
	//发送设备地址(写)
	iic_send_byte ( SlaveAddr );	//等待应答
	iic_wait_ack(); 

	//发送寄存器地址
	iic_send_byte ( RegAddr ) ;	//等待应答
	iic_wait_ack(); 
	while ( Num-- )								//循环写入数据
	{
		//发送数据
		iic_send_byte ( *Buf );	//等待应答
		iic_wait_ack(); 
		Buf++;									//数据指针偏移到下一个
		delay_us(10);
	}
	iic_stop();							//停止信号
	return IIC_OK;
}



/*
************************************************************
*	函数名称：	Pcf8563_IIC_ReadBytes
*
*	函数功能：	软件IIC读多个数据
*
*	入口参数：	slaveAddr：从机地址
*				regAddr：寄存器地址
*				buf：需要写入的数据缓存
*               num：数据长度
*
*	返回参数：	1-成功		0-失败
*
*	说明：		
************************************************************
*/
_Bool Pcf8563_IIC_ReadBytes ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Buf, unsigned char Num )
{
	iic_start();							//起始信号
	//发送设备地址(写)
	iic_send_byte ( SlaveAddr );		//等待应答
	iic_wait_ack(); 
	//发送寄存器地址
	iic_send_byte ( RegAddr );			//等待应答
	iic_wait_ack(); 
	iic_start();				   			//重启信号
	//发送设备地址(读)
	iic_send_byte ( SlaveAddr + 1 );	//等待应答
	iic_wait_ack(); 
	while ( Num-- )
	{
		//偏移到下一个数据存储地址
		if ( Num == 0 )
		{
			*Buf = iic_recive_byte ( 0 );	//最后一个数据需要回NOACK
		}
		else
		{
			*Buf = iic_recive_byte ( 1 );	//回应ACK
		}
		Buf++;
	}
	iic_stop();
	return IIC_OK;
}




//常量定义
const char week_day[7][10]={"SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"};
const int8_t months[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
//变量定义
rtc_time_st rtc_time;

/*
************************************************************
*	函数名称：	Pcf8563_Rtc_Init
*
*	函数功能：	外置RTC初始化
*
*	入口参数：	无
*
*	返回参数：	无
*
*	说明： STATUS1:正常模式、POR disabled
*         STATUS2:INT is active when TF is active
*				   read: alarm flag inactive
*          write: alarm flag is cleared
*          read: timer flag inactive
*				   write: timer flag is cleared
*				   alarm interrupt disabled
*				   timer interrupt disabled
*		   		 CLKOUT：CLKOUT output is activated
*				   frequency output at pin CLKOUT is 1.024 kHz(为何设置为该值)
************************************************************
*/
void rtc_init(void)
{
	iicx_init();
}

void Pcf8563_Rtc_Init(void)
{
	DDL_DelayMS(20);
	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CONTROL_STATUS1,0x00);	//默认
	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CONTROL_STATUS2,0x00); //默认
	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CLKOUT,0x80);          //使能CLK输出，1024Hz
}
/*
************************************************************
*	函数名称：	Get_Pcf8563_Rtc_Time
*
*	函数功能：	获取外置RTC时间
*
*	入口参数：	rtc_time
*
*	返回参数：	无
*
*	说明： 读时间 年、月、日、时、分、日期  week为指针指向week_day数组
************************************************************
*/
void Get_Pcf8563_Rtc_Time(rtc_time_st *rtc_time)
{
	uint8_t time_buf[7]={0};
	
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x02,&time_buf[0]);//秒
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x03,&time_buf[1]);//分	
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x04,&time_buf[2]);//时
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x05,&time_buf[3]);//日
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x06,&time_buf[4]);//星期
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x07,&time_buf[5]);//月
	Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x08,&time_buf[6]);//年
	
	//将时间从BCD编码变成十进制
	rtc_time->sec=BCDToDec(time_buf[0] & 0X7F);   			//秒
	rtc_time->min=BCDToDec(time_buf[1] & 0X7F);   			//分
	rtc_time->hour=BCDToDec(time_buf[2] & 0X3F);   			//时
	rtc_time->date=BCDToDec(time_buf[3] & 0X3F);  			//日
//	rtc_time->week=(time_buf[4] & 0X07); 					//星期(值0为星期7  1为星期1)
	rtc_time->week=week_day[(time_buf[4] & 0X07)]; 			//星期(字符串指针)
	rtc_time->mon=BCDToDec(time_buf[5] & 0X1F);    			//月
	rtc_time->year=2000 + (uint16_t)BCDToDec(time_buf[6]);  //年
	
//	for(int i = 0;i < 7; i++)
//		printf("%x ",time_buf[i]);
}
/*
************************************************************
*	函数名称：	LogRtcTime
*
*	函数功能：	LogRtcTime
*
*	入口参数：	rtc_time
*
*	返回参数：	无
*
*	说明： 读时间 年、月、日、时、分、日期  week为指针指向week_day数组
************************************************************
*/
void LogRtcTime(rtc_time_st *rtc_time)
{
	printf("data:%4d-%02d-%02d %02d:%02d:%02d  week:%s\r\n",rtc_time->year,rtc_time->mon,rtc_time->date,rtc_time->hour,rtc_time->min,rtc_time->sec,rtc_time->week);
}
/*
************************************************************
*	函数名称：	Set_Pcf8563_Rtc_Time
*
*	函数功能：	获取外置RTC时间
*
*	入口参数：	year mon date hour min sec
*
*	返回参数：	无
*
*	说明： 设置RTC时间 week为0-7 0为星期7  1为星期1
************************************************************
*/
void Set_Pcf8563_Rtc_Time(uint16_t year,uint8_t mon,uint8_t date,uint8_t hour,uint8_t min,uint8_t sec,uint8_t week)
{
	//将时间从十进制变成BCD编码
	uint8_t time_buf[7]={0};
	
	time_buf[6] = DecToBCD((uint8_t)(year-2000));
	time_buf[5] = DecToBCD(mon);
	time_buf[4] = week;
	time_buf[3] = DecToBCD(date);
	time_buf[2] = DecToBCD(hour);
	time_buf[1] = DecToBCD(min);
	time_buf[0] = DecToBCD(sec);
//	for(int i = 0;i < 7; i++)
//		printf("%x ",time_buf[i]);
//	printf("\n");
	Pcf8563_IIC_WriteBytes(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_SEC,time_buf,7);
}



/*
************************************************************
*	函数名称：	DecToBCD
*
*	函数功能：	DecToBCD
*
*	入口参数：	unsigned char
*
*	返回参数：	unsigned char
*
*	说明： 十进制转BCD编码
************************************************************
*/
unsigned char DecToBCD(unsigned char _dec)
{
	unsigned char temp = 0;
	while (_dec >= 10)
	{
					temp++;
					_dec -= 10;
	}
	return ((unsigned char)(temp << 4) | _dec);
}


/*
************************************************************
*	函数名称：	BCDToDec
*
*	函数功能：	BCDToDec
*
*	入口参数：	unsigned char
*
*	返回参数：	unsigned char
*
*	说明： BCD编码转十进制
************************************************************
*/
unsigned char BCDToDec(unsigned char _BCD)
{
	unsigned char temp = 0;

	temp = ((unsigned char)(_BCD & (unsigned char)0xF0) >> (unsigned char)0x04) * 10;
	return (temp + (_BCD & (unsigned char)0x0F));
}

/*
************************************************************
*	函数名称：	Days_Count
*
*	函数功能：	计算日期之间的天数
*
*	入口参数：	rtc_time_st 起始和结束日期
*
*	返回参数：	天数
*
*	说明： 
************************************************************
*/
int Days_Count(rtc_time_st *start,rtc_time_st *stop)
{
  int day_start=0;
	int day_stop=0;
	uint8_t i=0;
	if(start->year==stop->year)					//同一年
	{
		if(ISLOOP(start->year))					//闰年
		{
			if(start->mon<=2)					//计算开始的天数
			{
				if(start->mon==1)
					day_start=0;
				else
				{
					day_start=day_start+months[0];
				}
				
			}	
			else
			{	
				for(i=1;i<start->mon;i++)
					day_start=day_start+months[i-1]+1;
			}
			
			if(stop->mon<=2)					//计算结束的的天数
			{
				if(stop->mon==1)
					day_stop=0;
				else
				{
					day_stop=day_stop+months[0];
				}
				
			}	
			else
			{	
				for(i=1;i<stop->mon;i++)
					day_stop=day_stop+months[i-1]+1;
			}
		}
		else									//平年
		{
			if(start->mon==1)					//计算开始的天数
				day_start=0;
			else
			{
				for(i=1;i<start->mon;i++)
					day_start=day_start+months[i-1];
			}
			
			if(stop->mon==1)					//计算结束的的天数
				day_stop=0;
			else
			{
				for(i=1;i<stop->mon;i++)
					day_stop=day_stop+months[i-1];
			}
		}
		return	day_stop-day_start;
	}
	else										//不同年（此时一定12月和1月）
	{
		return 31-start->date+stop->date;
	}
}

/*************************************RTC定时唤醒**********************************************/
void P8563_alarm(unsigned char min)
{
	min = DecToBCD(min);	

	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x9,min); /*分钟报警*/

	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x12); /*报警有效*/ //使能报警器和定时器发出中断请求
}
 
void clear_alarm(void)
{
  Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x02);//清中断标志
}

/******************关闭闹钟中断***************************/
void close_alarm(void)
{
	Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x00);//禁止中断
}
 

#include "string.h"
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "task.h"
void pca8565_task(void *argv)
{		
	Pcf8563_Rtc_Init();
  Set_Pcf8563_Rtc_Time(2023,5,19,15,11,33,5);//33 22 16 17 3 5 23 
	while(1)
	{
		Get_Pcf8563_Rtc_Time(&rtc_time);	
		LogRtcTime(&rtc_time);	 
 
		vTaskDelay(1000);
	}
}

