#include "includes.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

/**
 * Bootload 串口使用情况
 * 	UART0 没有使用
 * 	UART2 用与调试信息输出 - 512000
 *  UART1 用于Bootload 升级使用
 * */

UART_t g_uart;		//目前该项目只使用串口2 进行双向通讯
MULIT_t m_send;

void UARTx_Init(UART_IDX uart_id, Uart_prt prt_cf) {
	switch(uart_id){

		case UART_1:
			memset(&g_uart,0,sizeof(UART_t));
			memset(&m_send,0,sizeof(MULIT_t));		
		
			//串口1-RX接收中断，用于串口1的通讯总线繁忙状态判断，2025-04-16
//			GPIO_PullHigh_Init(GPIOA0,15);		
//			GPIO_IntGroup_Set(PA0,15,Selete_EXI_PIN15); 					//EXI0 set PB0.2
//			GPIOA0_EXI_Init(EXI15); 										//PB0.2 as input
//			EXTI_trigger_CMD(ENABLE,EXI_PIN15,_EXIFT); 					//ENABLE falling edge
//			EXTI_trigger_CMD(ENABLE,EXI_PIN15,_EXIRT);
//			EXTI_interrupt_CMD(ENABLE,EXI_PIN15); 						//enable EXI
//			GPIO_EXTI_interrupt(GPIOA0,0b1000000000000000); 			//enable GPIOB02 as EXI
//			EXI4_Int_Enable(); 			
//		
//			UART1_DeInit();                                                 //clear all UART Register
//			UART_IO_Init(IO_UART1,2);                                    	//use PA0.13->RXD1, PB0.0->TXD1
//			UARTInitRxTxIntEn(UART1,20000,UART_PAR_NONE);					//baudrate=sysclock 48M/20000=2400 tx rx int enabled 
//			UART1_Int_Enable();
//
//			m_send.BusState_Tick = SysTick_1ms;
//			m_send.HighBit_Flag = 0x01;
//			
//			g_uart.RecvTimeout = Recv_2400_TimeOut;
//			g_uart.processing_cf = prt_cf;
//			
//			//485使能引脚初始化
//			GPIO_Init(GPIOA0,UART485_DR_PIN,Output);
//			GPIO_DriveStrength_EN(GPIOA0,UART485_DR_PIN);
//			WRITE_LOW_DR;
			break;

		case UART_2:
			//2026-02-06 使用串口2作为Bootload 升级使用
			
			memset(&g_uart,0,sizeof(UART_t));
			memset(&m_send,0,sizeof(MULIT_t));
			
			//串口RX接收中断
			GPIO_PullHigh_Init(GPIOB0,5);		

			GPIO_IntGroup_Set(PB0,5,Selete_EXI_PIN5); 					//EXI0 set PB0.5
			GPIOB0_EXI_Init(EXI5); 										//PB0.5 as input
			EXTI_trigger_CMD(ENABLE,EXI_PIN5,_EXIFT); 					//ENABLE falling edge
			EXTI_trigger_CMD(ENABLE,EXI_PIN5,_EXIRT);
			EXTI_interrupt_CMD(ENABLE,EXI_PIN5); 						//enable EXI
			GPIO_EXTI_interrupt(GPIOB0,0b0000000000100000); 			//enable GPIOB05 as EXI
			EXI3_Int_Enable(); 											//EXI4~EXI9 INT Vector
			
			UART2_DeInit();                                                 //clear all UART Register
			UART_IO_Init(IO_UART2,2);                                    	//use PA0.13->RXD1, PB0.0->TXD1
			
			UARTInitRxTxIntEn(UART2,20000,UART_PAR_NONE);					//baudrate=sysclock 48M/416=115200 tx rx int enabled 
			
			UART2_Int_Enable();
			
			m_send.BusState_Tick = SysTick_1ms;
			m_send.HighBit_Flag = 0x01;
			
			g_uart.RecvTimeout = Recv_2400_TimeOut;
			g_uart.processing_cf = prt_cf;
			
			//485使能引脚初始化
			GPIO_Init(GPIOB0,3,Output);
			GPIO_DriveStrength_EN(GPIOB0,3);
			WRITE_LOW_DR;

			break;
	}
}

/*******************************************************************************
* Function Name  : Get_Uart_BaudCnt  
* Description    : Uart 获取串口波特率对于设置值 
*******************************************************************************/
U16_T Get_Uart_BaudCnt(U32_T baud)
{
	switch(baud){
		case 2400:
			return 20000;
		case 4800:
			return 10000;
		case 9600:
			return 5000;
		case 19200:
			return 2621;
		case 56000:
			return 898;
		case 115200:
			return 416;
		case 512000:
			return 98;
	}
	return 0x00;
}

/*******************************************************************************
* Function Name  : Get_Uart_Recv_Timeout  
* Description    : Uart 获取串口接收超时时间
*******************************************************************************/
U32_T Get_Uart_Recv_Timeout(U32_T baud)
{
	switch(baud){
		case 2400:
			return Recv_2400_TimeOut;
		case 4800:
			return Recv_2400_TimeOut;
		case 9600:
			return Recv_9600_TimeOut;
		case 19200:
			return Recv_9600_TimeOut;
		case 56000:
			return Recv_9600_TimeOut;
		case 115200:
			return Recv_115200_TimeOut;
		case 512000:
			return Recv_115200_TimeOut;
	}
	return Recv_115200_TimeOut;
	
}

/*******************************************************************************
* Function Name  : UARTx_ChangeBaud  
* Description    : Uart 切换串口波特率 
*******************************************************************************/
U8_T UARTx_ChangeBaud(uint8_t uart_id,uint32_t baud)
{
	U16_T set_para = Get_Uart_BaudCnt(baud);
	
	if(set_para == 0x00)	return 0x01;			//设置的波特率不支持
	
	switch(uart_id){
		
		case UART_1:
#if DBG_LOG_EN
			Dbg_Println(DBG_BIT_SYS_STATUS, "UART ID %d", uart_id);
			Dbg_Println(DBG_BIT_SYS_STATUS,"UART baud %d",baud);
#endif
			UARTClose(UART1);
			UART1_Int_Disable();
			
			UART1_DeInit();                                                 //clear all UART Register
			UART_IO_Init(IO_UART1,2);                                    	//use PA0.13->RXD1, PB0.0->TXD1
			
			UARTInitRxTxIntEn(UART1,set_para,UART_PAR_NONE);					//baudrate=sysclock 48M/416=115200 tx rx int enabled 
			
			UART1_Int_Enable();
			
			g_uart.RecvTimeout = Get_Uart_Recv_Timeout(baud);
			break;
		case UART_2:
			UARTClose(UART2);
			UART2_Int_Disable();
			
			UART2_DeInit();                                                 //clear all UART Register
			UART_IO_Init(IO_UART2,2);                                    	//use PA0.13->RXD1, PB0.0->TXD1
			
			UARTInitRxTxIntEn(UART2,set_para,UART_PAR_NONE);				//baudrate=sysclock 48M/416=115200 tx rx int enabled 
			
			UART2_Int_Enable();
			
			g_uart.RecvTimeout = Get_Uart_Recv_Timeout(baud);
			break;
	}
	
}

/*******************************************************************************
* Function Name  : UART1_RecvINT_Processing 
* Description    : 串口1 接收中断处理函数 - 接收中断调用
*******************************************************************************/
//void UART1_RecvINT_Processing(char data){
//	if((g_uart.RecvLen + 1) >= USART_BUFFER_SIZE) g_uart.RecvLen = 0;
//	g_uart.RecvBuffer[g_uart.RecvLen++] = (U8_T)data;
//	
//	g_uart.RecvIdleTiming = SysTick_1ms;
//	g_uart.Receiving = 0x01;
//}
//
//
//void UART1_TASK(void){
//	U8_T ret = 0x00;
//	if(g_uart.Receiving == 0x01){
//		if(SysTick_1ms - g_uart.RecvIdleTiming > g_uart.RecvTimeout){
//			
//			SYSCON_Int_Disable();					
//			g_uart.RecvIdleTiming = SysTick_1ms;
//			memcpy(g_uart.DealBuffer,g_uart.RecvBuffer,g_uart.RecvLen);
//			g_uart.DealLen = g_uart.RecvLen;
//			g_uart.RecvLen = 0;
//			g_uart.Receiving = 0;
//			SYSCON_Int_Enable();
//			
//#if DBG_LOG_EN
//			Dbg_Println(DBG_BIT_SYS_STATUS, "UART recv Len %d", g_uart.DealLen);
//			Dbg_Print_Buff(DBG_BIT_SYS_STATUS,"UART buff",g_uart.DealBuffer,g_uart.DealLen);
//#endif
//
//			if(g_uart.processing_cf != NULL){
//                ret = g_uart.processing_cf(g_uart.DealBuffer,g_uart.DealLen);
//            }
//			
//		}
//	}
//}

/*******************************************************************************
* Function Name  : UART2_RecvINT_Processing 
* Description    : 串口2 接收中断处理函数 - 接收中断调用
*******************************************************************************/
void UART2_RecvINT_Processing(char data){
	if((g_uart.RecvLen + 1) >= USART_BUFFER_SIZE) g_uart.RecvLen = 0;
	g_uart.RecvBuffer[g_uart.RecvLen++] = (U8_T)data;
	
	g_uart.RecvIdleTiming = SysTick_1ms;
	g_uart.Receiving = 0x01;
}


void UART2_TASK(void){
	U8_T ret = 0x00;
	if(g_uart.Receiving == 0x01){
		if(SysTick_1ms - g_uart.RecvIdleTiming > g_uart.RecvTimeout){
			
			SYSCON_Int_Disable();					
			g_uart.RecvIdleTiming = SysTick_1ms;
			memcpy(g_uart.DealBuffer,g_uart.RecvBuffer,g_uart.RecvLen);
			g_uart.DealLen = g_uart.RecvLen;
			g_uart.RecvLen = 0;
			g_uart.Receiving = 0;
			SYSCON_Int_Enable();
			
#if DBG_LOG_EN
			Dbg_Println(DBG_BIT_SYS_STATUS, "UART recv Len %d", g_uart.DealLen);
			Dbg_Print_Buff(DBG_BIT_SYS_STATUS,"UART buff",g_uart.DealBuffer,g_uart.DealLen);
#endif

			if(g_uart.processing_cf != NULL){
                ret = g_uart.processing_cf(g_uart.DealBuffer,g_uart.DealLen);
            }
			
		}
	}
}

/*因为开启了UART_TX_DONE_S 中断，发送完成需要清楚该中断标志位，因此每次调用串口输出后，需调用该函数，否则会在中断出不来
 * 已取消
 * */
void UART_Waiting_For_Send(CSP_UART_T *uart){
	unsigned int Dataval = 0,delay_cnt = 0;
	
	do{
		Dataval = CSP_UART_GET_ISR(uart);
		
		Dataval = Dataval & UART_TX_DONE_S;
		delay_cnt ++;
		if(delay_cnt >= 50000){
			break;
		}
	}while(Dataval == 0x00);    //发送完成
	uart->ISR=UART_TX_DONE_S;
}

volatile int RS485_Comm_Flag = 0,RS485_Comm_Start = 0,RS485_Comm_End = 0,RS485_Comming = 0;
void MCU485_SendData(U8_T *buff,U16_T len){
	unsigned int Dataval = 0,delay_cnt = 0;

	//等待通讯发送完成
	while(RS485_Comming == 0x01){
		delay_nus(100);
		
		delay_cnt ++;
		if(delay_cnt >= 100){
			break;
		}
		REVERISE_DR;//GPIO_Reverse(GPIOB0,3);
	}
	
	WRITE_HIGH_DR;//GPIO_Write_High(GPIOB0,3);
	
	RS485_Comm_Flag = 0x01;
	RS485_Comm_Start = 0x00;
	RS485_Comm_End = 0x00;
	
	UARTTransmit(UART2,buff,len);
	
	do{
		delay_nus(100);
		
		delay_cnt ++;
		if(delay_cnt >= 100){
			break;
		}
		
	}while((RS485_Comm_Start < len) || (RS485_Comm_End < len));    //发送完成

	WRITE_LOW_DR;//GPIO_Write_Low(GPIOB0,3);
	
	RS485_Comm_Flag = 0x00;
}

/**********************************************************
 * @brief	BUS485 数据发生函数 - 检测总线是否繁忙，空闲状态下，才发生数据；繁忙状态下，直接退出
 * @retval 	None
 * */
U8_T BUS485_Send(U8_T *buff,U16_T len)
{
	unsigned int Dataval = 0,delay_cnt = 0;

	//等待通讯发送完成
	while(RS485_Comming == 0x01){
		delay_nus(100);
		
		delay_cnt ++;
		if(delay_cnt >= 100){
			break;
		}
		REVERISE_DR;//GPIO_Reverse(GPIOB0,3);
	}

	if(m_send.BusState_Flag == UART_BUSIDLE){		//总线空闲
		
		CK_CPU_DisAllNormalIrq();	
		
		
		WRITE_HIGH_DR;//GPIO_Write_High(GPIOB0,3);
		
		RS485_Comm_Flag = 0x01;
		RS485_Comm_Start = 0x00;
		RS485_Comm_End = 0x00;		
		
		m_send.BusState_Flag = UART_BUSBUSY;//发送前总线置位繁忙
		m_send.BUSBUSY_LOCK = 0x01;			//锁定总线状态

		CK_CPU_EnAllNormalIrq();		
		
		UARTTransmit(UART2,buff,len);
		do{
			delay_nus(100);
			delay_cnt ++;
			if(delay_cnt >= 100){
				break;
			}
			
		}while((RS485_Comm_Start < len) || (RS485_Comm_End < len));    //发送完成

		CK_CPU_DisAllNormalIrq();	
		
		WRITE_LOW_DR;//GPIO_Write_Low(GPIOB0,3);
		RS485_Comm_Flag = 0x00;			
		
		m_send.BusState_Tick = SysTick_1ms;
		m_send.BUSBUSY_LOCK = 0x00;			//解锁总线状态
		
		CK_CPU_EnAllNormalIrq();			

		return UART_BUSIDLE;	//发送成功
	}
	else{ 				//总线繁忙
		return UART_BUSBUSY;	//发送失败
	}	
	
	return 0x02;		//传入状态无效
}

/**********************************************************
 * @brief	重发、数据有效期、超时发送判断，2025-03-25
 * 			buff:发送数据
 * 			len：数据长度
 * 			DatSd：发送标记,0x00:无发送，0x01：有数据发送
 * 
 * @retval 	0x00:发送成功	0x01:等待发送	0x02:数据无效
 * */
U8_T MultSend_Task(U8_T *buff,U16_T len,U8_T DatSd)
{
	if( (len == 0)||(len > USART_BUFFER_SIZE) ) return LEN_ERR;
	
	if(DatSd == 0x01)	
	{
		if( m_send.ResendCnt < m_send.TotalCnt)	//判断数据是否还在有效期，是否还有发送次数
		{
			if(SysTick_1ms - m_send.BusbusyTimeout < m_send.DataValid_Time)
			{
				if( (m_send.ResendCnt == 0x00) || (SysTick_1ms - m_send.ASend_Tick >= m_send.DataWait_Time) ){//数据发送间隔
					
					if(BUS485_Send(buff,len) == UART_BUSIDLE){	//发送数据
						m_send.ASend_Tick = SysTick_1ms;
						m_send.ResendCnt++;
#if DBG_LOG_EN
						Dbg_Println(DBG_BIT_Debug_STATUS,"SendCnt:%d success",m_send.ResendCnt);
#endif
						return BUSSEND_SUCC;//数据发送成功
					}
				}
			}else{
#if DBG_LOG_EN
				Dbg_Println(DBG_BIT_Debug_STATUS,"data end");
#endif
				return DATA_END;//数据有效期结束
			}
		}else{
#if DBG_LOG_EN
			Dbg_Println(DBG_BIT_Debug_STATUS,"retry end,%d",m_send.ResendCnt );
#endif
			return RETRY_END;//没有重发次数
		}
	}
	return BUSSEND_WAIT;//等待
}

/**********************************************************
 * @brief	设置发送标志、组包、选择数据有效期档位，2025-03-25
 * 			data: 		发送数据
 * 			sled：		数据长度
 * 			SCnt:		设置数据发送次数
 * 			indate：	设置数据有效期
 * 			tim_val:	发送时间间隔
 * @retval 	None
 * */
void Set_GroupSend(U8_T *data,U16_T sled,U8_T SCnt,U32_T indate,U32_T tim_val)
{
	if((sled == 0x00)|| (sled > USART_BUFFER_SIZE)) return;
	
	memset(m_send.SendBuffer,0, USART_BUFFER_SIZE);
	memcpy(m_send.SendBuffer,data,sled);
	m_send.SendLen = sled;
	
	m_send.DataValid_Time = indate;//数据有效期
	m_send.TotalCnt = SCnt;			//数据发送次数
	m_send.DataWait_Time = tim_val;//发送数据间隔
	
	m_send.ASend_Flag = 0x01;
	m_send.ResendCnt = 0x00;
	m_send.BusbusyTimeout = SysTick_1ms;
}

//清除发送标志
//void Clear_SendFlag(void)
//{
//	m_send.ASend_Flag = 0x00;
//}

void BUS485_SetBaud(U32_T baud)
{
	m_send.SetBaudFlag = 0x01;
	m_send.SetBaud = baud;
}

/**********************************************************
 * @brief	检测总线空闲，在While(1)里调用		2025-03-25
 * @retval 	None
 * */
void BUS485Send_Task(void)	//2025-03-29
{	
	U8_T ret = 0xFF;
	//空闲等待
	if(m_send.ASend_Flag == 0x01)//初始化发送
	{
		ret = MultSend_Task(m_send.SendBuffer,m_send.SendLen,m_send.ASend_Flag);
		
		if( (ret == DATA_END)||(ret == RETRY_END) )//判断发送数据是否有效
		{
#if DBG_LOG_EN
			Dbg_Println(DBG_BIT_Debug_STATUS,"send end");
#endif
			m_send.ASend_Flag = 0x00;
			
			/*设置波特率*/
			if( m_send.SetBaudFlag == 0x01 ){
				
				UARTx_ChangeBaud(UART_2,m_send.SetBaud);
				m_send.SetBaudFlag = 0x00;
				m_send.SetBaud = 0x00;
			}
		}
	}
}

/**********************************************************
 * @brief	检测总线空闲，在定时器中断里调用
 * @retval 	None
 * */
void BusIdle_Task(void)
{
	if(m_send.BusState_Flag != UART_BUSIDLE && m_send.BUSBUSY_LOCK != 0x01)
	{
		CK_CPU_DisAllNormalIrq();
		if( ( m_send.HighBit_Flag == 0x01 )&&( ( SysTick_1ms - m_send.BusState_Tick ) >= ( g_uart.RecvTimeout + m_send.Bus_DelayTime )) )
		{
			m_send.BusState_Flag = UART_BUSIDLE;
		}	
		CK_CPU_EnAllNormalIrq();
	}
}
/*******************************************************************
 * @brief	检测总线繁忙，在串口接收RX引脚的外部中断服务函数里调用
 * @retval 	None
 * */
void BusBusy_Task(void)
{
	CK_CPU_DisAllNormalIrq();
	
	m_send.BusState_Flag = UART_BUSBUSY;
	m_send.BusState_Tick = SysTick_1ms;
	m_send.Bus_DelayTime = (SysTick_1ms - m_send.ASend_Tick)%10;//随机延时

	if(READ_RXLEVEL_STATE == 0x01){
		m_send.HighBit_Flag = 0x01;			//高电平标志置位
	}else if(READ_RXLEVEL_STATE == 0x00){
		m_send.HighBit_Flag = 0x00;			//低电平
	}	
	CK_CPU_EnAllNormalIrq();
}

/*调试信息输出接口*/

U32_T Dbg_Switch = (DBG_OPT_Debug_STATUS << DBG_BIT_Debug_STATUS)
        + (DBG_OPT_DEVICE_STATUS << DBG_BIT_DEVICE_STATUS)
        + (DBG_OPT_SYS_STATUS << DBG_BIT_SYS_STATUS);
	
#if DBG_LOG_EN

char Dbg_Buffer[512] = {0};
U32_T SysTick_Now = 0, SysTick_Last = 0, SysTick_Diff = 0;

#endif

void Dbg_Print(int DbgOptBit, const char *cmd, ...){

#if DBG_LOG_EN
	U16_T str_offset = 0;

	if (Dbg_Switch & (1 << DbgOptBit)) {
        SysTick_Now = SysTick_1ms;
        SysTick_Diff = SysTick_Now - SysTick_Last;      //上一次打印时间差
        SysTick_Last = SysTick_Now;
        str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer),"%8d [%6d]: ", SysTick_Now, SysTick_Diff);
		DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
		
        va_list args;       	//定义一个va_list类型的变量，用来储存单个参数
        va_start(args, cmd); 	//使args指向可变参数的第一个参数
        str_offset = vsnprintf(Dbg_Buffer, sizeof(Dbg_Buffer) ,cmd, args);  //必须用vprintf等带V的
        va_end(args);       	//结束可变参数的获取
        
		DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
		
    }

#endif	
}

void Dbg_Println(int DbgOptBit, const char *cmd, ...){

#if DBG_LOG_EN
	U16_T str_offset = 0;

	if (Dbg_Switch & (1 << DbgOptBit)) {
        SysTick_Now = SysTick_1ms;
        SysTick_Diff = SysTick_Now - SysTick_Last;      //上一次打印时间差
        SysTick_Last = SysTick_Now;
        str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%8ld [%6ld]: ", SysTick_Now, SysTick_Diff);
		DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
		
        va_list args;       	//定义一个va_list类型的变量，用来储存单个参数
        va_start(args, cmd); 	//使args指向可变参数的第一个参数
        str_offset = vsnprintf(Dbg_Buffer, sizeof(Dbg_Buffer) ,cmd, args);  //必须用vprintf等带V的
        va_end(args);       	//结束可变参数的获取
        
		DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
		
		DBG_Printf((U8_T *)"\r\n",2);
		
		
    }

#endif	
}


void Dbg_Print_Buff(int DbgOptBit, const char *cmd, U8_T *buff,U16_T len){
#if DBG_LOG_EN
	U16_T str_offset = 0;

	if (Dbg_Switch & (1 << DbgOptBit)) {
        SysTick_Now = SysTick_1ms;
        SysTick_Diff = SysTick_Now - SysTick_Last;      //上一次打印时间差
        SysTick_Last = SysTick_Now;
        str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%8ld [%6ld]:%s ", SysTick_Now, SysTick_Diff,cmd);
		DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
		
        for (uint32_t i = 0; i < len; i++) {
			SYSCON_IWDCNT_Reload();
			str_offset = snprintf(Dbg_Buffer, sizeof(Dbg_Buffer) , "%02X ", buff[i]);
            DBG_Printf((U8_T *)Dbg_Buffer,str_offset);
        }
		
		DBG_Printf((U8_T *)"\r\n",2);
    }

#endif	
}








