/*********************************************************************
 * 智能门锁设备的RS485转发设备
 * 时间		:2025-12-17
 * 
 * 主要功能	：
 * 		1、接收处理门锁设备的百分比电量，转发给RCU门锁设备的百分比电量
 * 		2、接收处理门锁设备上报的身份信息，转发给RCU门锁设备
 * 		3、接受处理门锁设备上报的门锁状态，包括要是开锁、假锁等
 * 
 * 
 * */

#include "includes.h"

SMTLOCK_t g_smtlock;

//样品MAC地址，2025-12-17
U8_T Lock_DefaultMAC[]={0xE4,0x66,0xE5,0xBC,0x68,0x6C};


/**********************************************************
 * @FunctionName: SmtLock_Init
 * @brief		: 门锁相关参数初始化
 * @param		: 无
 * @retval		: 无
 * @note		: 无
 * **********************************************************/
void SmtLock_Init(void)
{
	memset(&g_smtlock,0x00,sizeof(SMTLOCK_t));
	
}




//控制门锁开锁
void RS485_UNLOCK_Send(void)
{
	U8_T lens = 40;
	U8_T data[40];
	U8_T CMD = 0xD2;
	
	memset(data,0x00,sizeof(data));
	
	data[0] = 0xA1;
	data[1] = 0x00;	
	data[2] = 0x21;
	data[3] = 0x10;
	data[4] = 0x24;
	data[5] = CMD;
	data[6] = 0x02;	//开锁

	//中间保留32字节

	data[lens - 1]= EEPROM_CheckSum(data, lens-1);

	
	Dbg_Println(DBG_BIT_Debug_STATUS,"UnLock Send:");
//	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"Smt_Lock Report",data,lens);	
	
	Controller485_SendData(data,lens);
}




/**********************************************************
 * @FunctionName: LOCKID_Proc
 * @brief		: 门锁身份处理,暂时写死,将门锁上报身份转换为主机身份
 * @param		: 门锁输入身份
 * @retval		: 返回身份信息
 * @note		: 
 * **********************************************************/
U8_T LOCKID_Proc(U8_T Cardid)
{
	if(Cardid == 0x02){
		return 0x01;
	}else if(Cardid == 0x06){
		return 0x02;
	}else if(Cardid == 0x04){
		return 0x03;
	}else if(Cardid == 0x05){
		return 0x04;
	}else if(Cardid == 0x03){
		return 0x05;
	}else{
		return 0x00;
	}
	
	
	return 0x00;
}


/****************************************************************************************************
 * @FunctionName: RS485_SmtLock_DevState_Processing
 * @brief		: 新世界智能门锁的设备状态上报数据处理，包括电量百分比、网络状态、MAC地址等
 * @param		: RecvData: 接收数据缓存区
 * @param		: RecvLen ：接收数据长度
 * @retval		: 0x00:数据处理成功，其它：数据处理失败
 * @note		: 注意：
 * 					Data[6] 为新世界门锁应答码
 * 						E0H	：解析成功	告知报文解析并执行成功
 * 						E1H	：未知命令	主命令未找到
 * 						E2H	：参数错误	主命令附带子参数未知或错误
 * *****************************************************************************************************/
U8_T RS485_SmtLock_DevState_Processing(U8_T *Data, U16_T Len)
{	
	//应答码
	if(Data[6] == 0xE0)
	{
		g_smtlock.DevMAC[0] = Data[7];
		g_smtlock.DevMAC[1] = Data[8];
		g_smtlock.DevMAC[2] = Data[9];
		g_smtlock.DevMAC[3] = Data[10];
		g_smtlock.DevMAC[4] = Data[11];
		g_smtlock.DevMAC[5] = Data[12];
		
		//电量百分比
		g_smtlock.Dev_BatMon = Data[13];
		
		//网络质量
		g_smtlock.Dev_NetQult = Data[14];	
		
		
		g_smtlock.Dev_StaRpt_Flag = 0x01;
	
	#if DBG_LOG_EN
		Dbg_Println(DBG_BIT_Debug_STATUS,"MAC:%02x.%02x.%02x.%02x.%02x.%02x",g_smtlock.DevMAC[0],g_smtlock.DevMAC[1],g_smtlock.DevMAC[2],g_smtlock.DevMAC[3],g_smtlock.DevMAC[4],g_smtlock.DevMAC[5]);	
		Dbg_Println(DBG_BIT_Debug_STATUS,"BatMon:%d, NetSta:%d",g_smtlock.Dev_BatMon,g_smtlock.Dev_NetQult);	
	#endif
	
	}
	

	return 0x00;
}

/****************************************************************************************************
 * @FunctionName: RS485_SmtLock_LogRpt_Processing
 * @brief		: 智能门锁的实时日志上报处理
 * @param		: RecvData: 接收数据缓存区
 * @param		: RecvLen ：接收数据长度
 * @retval		: 0x00:数据处理成功，其它：数据处理失败
 * @note		: 上报数据包括，刷卡身份、门锁钥匙开锁、假锁等
 * *****************************************************************************************************/
U8_T RS485_SmtLock_LogRpt_Processing(U8_T *Data, U16_T Len)
{
	U16_T EvtCd = ((Data[7]<<8) + Data[8]);		//门锁日志事件编码
	
	U8_T EvtType = Data[9];						//门锁日志上报事件，较多，具体见协议文档
	U8_T EvtAuth = Data[10];					//事件鉴权结果，较多，具体见协议文档
	
	if(EvtType <= 0x0E)								//身份卡上报
	{  
		if(EvtAuth == 0x01)
		{
			g_smtlock.Dev_ID = LOCKID_Proc(EvtType);//身份转换
			
			if(g_smtlock.Dev_ID != 0x00)
			{
				g_smtlock.Dev_IDRpt_Flag = 0x01;			//门锁产生身份标志
				g_smtlock.SendCnt = 0x00;
				
				g_smtlock.Dev_IDTime[0] = Data[11];
				g_smtlock.Dev_IDTime[1] = Data[12];
				g_smtlock.Dev_IDTime[2] = Data[13];
				g_smtlock.Dev_IDTime[3] = Data[14];		

				
				g_smtlock.Dev_LockStaRpt_Flag = 0x01;
			}

		#if DBG_LOG_EN
			Dbg_Println(DBG_BIT_Debug_STATUS,"LockID:%02x",g_smtlock.Dev_ID);	
		#endif				
			
		}
	}
	else if( (EvtType >= 0xE1)&&(EvtType <= 0xE6) )	//假锁等状态上报
	{
		if(EvtAuth == 0x01)
		{
			g_smtlock.Dev_LockAct = EvtType;
			g_smtlock.Dev_LockActRpt_Flag = 0x01;
			g_smtlock.SendCnt = 0x00;
			
			g_smtlock.Dev_ActTime[0] = Data[11];
			g_smtlock.Dev_ActTime[1] = Data[12];
			g_smtlock.Dev_ActTime[2] = Data[13];
			g_smtlock.Dev_ActTime[3] = Data[14];

			g_smtlock.Dev_LockStaRpt_Flag = 0x01;			
			
			#if DBG_LOG_EN
				Dbg_Println(DBG_BIT_Debug_STATUS,"LockAct:%02x",g_smtlock.Dev_LockAct);	
			#endif				
		}
	}
	
	
	
	return 0x00;
}

/****************************************************************************************************
 * @FunctionName: RS485_SmtLock_DevCtrl_Processing
 * @brief		: 控制门锁开锁指令的回复数据
 * @param		: RecvData: 接收数据缓存区
 * @param		: RecvLen ：接收数据长度
 * @retval		: 0x00:数据处理成功，其它：数据处理失败
 * @note		: 
 * *****************************************************************************************************/
U8_T RS485_SmtLock_DevCtrl_Processing(U8_T *Data, U16_T Len)
{
	if(Len != 47) return 0x01;
	
	if(Data[13] == 0x02)
	{
		g_smtlock.Dev_SetUnLock_Flag = 0x00;
		g_smtlock.LockSendCnt = 0x00;
	}
	
	
	return 0x00;
}


/****************************************************************************************************
 * @FunctionName: RS485_SmtLock_Processing
 * @brief		: 智能门锁的数据处理
 * @param		: RecvData: 接收数据缓存区
 * @param		: RecvLen ：接收数据长度
 * @retval		: 0x00:数据处理成功，其它：数据处理失败
 * @note		: 注意：1、0xD2命令字会定时上报批量日志内容，长度超过300字节，数据量太大，不做处理
 * *****************************************************************************************************/
U8_T RS485_SmtLock_Processing(U8_T *RecData, U16_T RecvLen)
{
	U16_T Lens = 0x00;
	
	if( (RecvLen < 8)||(RecvLen > 48) )
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_Len1 Err:%d",RecvLen);
		return 0x01;
	}
	
	Lens = ((RecData[1]<<8)+ RecData[2]);
	if(Lens != (RecvLen - 8))
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_Len2 Err:%d,%d",Lens,RecvLen);
		return 0x01;
	}
	
	if(RecData[0] != 0xA1)
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_Head Err");
		return 0x02;		
	}
	
	
	if(RecData[RecvLen-1] != EEPROM_CheckSum(RecData,(RecvLen-1)))
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_SumCRC Err:%d, %d",RecData[5],EEPROM_CheckSum(RecData,(RecvLen-1)));
		return 0x03;	
	}
	
	Dbg_Println(DBG_BIT_Debug_STATUS,"Smt_Lock Report Ack:%02x",RecData[5]);
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"Smt_Lock Report",RecData,RecvLen);
	
	switch(RecData[5])
	{
		case 0x10:		//设备状态上报
			RS485_SmtLock_DevState_Processing(RecData,RecvLen);
		break;
		case 0xA0:		//日志实时上报
			RS485_SmtLock_LogRpt_Processing(RecData,RecvLen);
		break;
		case 0xD2:		//设备控制的回复
			RS485_SmtLock_DevCtrl_Processing(RecData,RecvLen);
		break;		
		default:
		break;
	}
	
	return 0x00;
}



/*****************************************************************
 * @FunctionName: SmtLock_FilACkPacket
 * @brief		: 发送打包函数
 * @param		: ackBuff: 发送缓冲
 * @param		: ackLen ：发送数据长度
 * @retval		: 
 * @note		: 
 * **************************************************************/
void SmtLock_FilACkPacket(U8_T *ackBuff,U8_T ackLen,U8_T cmd,U8_T sn)
{
	
    ackBuff[SmtLock_ADDR_TX] = g_Dip.DIP_addr;
    ackBuff[SmtLock_SN] = sn;
    ackBuff[SmtLock_DEV_TYPE] = Project_Type;
    ackBuff[SmtLock_ADDR_RX] = 0x00;
    ackBuff[SmtLock_LEN] = ackLen;
    ackBuff[SmtLock_CKS] = 0x00;
    ackBuff[SmtLock_CMD] = cmd;

    ackBuff[SmtLock_CKS] = EEPROM_CheckSum(ackBuff, ackLen);
	
	
}



//门锁身份信息、动作信息上报RCU
void MCU_SmtLock_IDRpt(void)
{
	U8_T lens = 18;
	U8_T data[18];
	U8_T CMD = DEV_IDSTATE_RPT;
	U8_T SN = 0x00;
	memset(data,0,sizeof(data));	
	
	if(g_smtlock.SendCnt == 0x00)
	{
		g_smtlock.SendSn++;
		if(g_smtlock.SendSn > 0x0F)	g_smtlock.SendSn = 0x01;
		SN |= (g_smtlock.SendSn & 0x0F);	//设置发送序号
	}else{	
		//本包数据为重发数据
		SN |= (g_smtlock.SendSn & 0x0F);
		SN |= PUBLIC_RETRY;
	}	
	
	if(g_smtlock.Dev_IDRpt_Flag != 0x00)
	{
		data[SmtLock_PARA] |= RPT_LOCKID_FLAG;
		
		data[SmtLock_PARA+1] = g_smtlock.Dev_ID;
		data[SmtLock_PARA+2] = g_smtlock.Dev_IDTime[0];
		data[SmtLock_PARA+3] = g_smtlock.Dev_IDTime[1];
		data[SmtLock_PARA+4] = g_smtlock.Dev_IDTime[2];
		data[SmtLock_PARA+5] = g_smtlock.Dev_IDTime[3];
	}
	
	if(g_smtlock.Dev_LockActRpt_Flag != 0x00)
	{
		data[SmtLock_PARA] |= RPT_LOCKACT_FLAG;
		data[SmtLock_PARA+6] = g_smtlock.Dev_LockAct;
		
		data[SmtLock_PARA+7] = g_smtlock.Dev_ActTime[0];
		data[SmtLock_PARA+8] = g_smtlock.Dev_ActTime[1];
		data[SmtLock_PARA+9] = g_smtlock.Dev_ActTime[2];
		data[SmtLock_PARA+10] = g_smtlock.Dev_ActTime[3];
	}
	
	
	SmtLock_FilACkPacket(data,lens,CMD,SN);			//组包
	Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_IDRpt:");
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"Smt_Lock Report",data,lens);	
	
	Set_GroupSend(data,lens,0x01,BUSSend_ValidTime3,BUSSend_Tick);	//组包
}



//门锁电量上报RCU
void MCU_SmtLock_BatMon(void)
{
	U8_T lens = 9;
	U8_T data[9];
	U8_T CMD = DEV_BATMON_RPT;
	U8_T SN = 0x00;
	memset(data,0,sizeof(data));	
	
	if(g_smtlock.SendCnt == 0x00)
	{
		g_smtlock.SendSn++;
		if(g_smtlock.SendSn > 0x0F)	g_smtlock.SendSn = 0x01;
		SN |= (g_smtlock.SendSn & 0x0F);	//设置发送序号
	}else{	
		//本包数据为重发数据
		SN |= (g_smtlock.SendSn & 0x0F);
		SN |= PUBLIC_RETRY;
	}	
	

	data[SmtLock_PARA] = g_smtlock.Dev_BatMon;
	data[SmtLock_PARA+1] = g_smtlock.Dev_NetQult;
	
	
	SmtLock_FilACkPacket(data,lens,CMD,SN);			//组包
	Dbg_Println(DBG_BIT_Debug_STATUS,"SmtLock_BatMon:");
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"BatMon Report",data,lens);	
	
	Set_GroupSend(data,lens,0x01,BUSSend_ValidTime3,BUSSend_Tick);	//组包
}


//查询版本号指令的回复
void MCU_SmtLock_Version(void)
{
	U8_T lens = 9;
	U8_T data[9];
	U8_T CMD = DEV_VERSON_RPT;
	U8_T SN = 0x00;
	memset(data,0,sizeof(data));	
	
	g_smtlock.RecvSn++;
	if(g_smtlock.RecvSn > 0x0F)	g_smtlock.RecvSn = 0x01;
	SN |= (g_smtlock.RecvSn & 0x0F);	//设置发送序号

	

	data[SmtLock_PARA] = Project_FW_Version;
	data[SmtLock_PARA+1] = Project_HW_Version;
	
	
	SmtLock_FilACkPacket(data,lens,CMD,SN);			//组包
	
	Dbg_Println(DBG_BIT_Debug_STATUS,"Version:");
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"Version",data,lens);	
	
	Set_GroupSend(data,lens,0x01,BUSSend_ValidTime3,BUSSend_Tick);	//组包
}


//开锁指令的回复
void MCU_SmtLock_UnLock(void)
{
	U8_T lens = 8;
	U8_T data[8];
	U8_T CMD = DEV_UNLOCK_RPT;
	U8_T SN = 0x00;
	memset(data,0,sizeof(data));	
	

	g_smtlock.RecvSn++;
	if(g_smtlock.RecvSn > 0x0F)	g_smtlock.RecvSn = 0x01;
	SN |= (g_smtlock.RecvSn & 0x0F);	//设置发送序号

	
	data[SmtLock_PARA] = 0x01;
	
	SmtLock_FilACkPacket(data,lens,CMD,SN);			//组包
	
	Dbg_Println(DBG_BIT_Debug_STATUS,"UnLock:");
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"UnLock",data,lens);	
	
	Set_GroupSend(data,lens,0x01,BUSSend_ValidTime3,BUSSend_Tick);	//组包
}


//MCU主动上报任务
void SmtLock_Task(void)
{
	static U32_T SmtLock_tick = 0x00;	//MCU上报时间戳
	static U32_T MCU_Set_SmtLock_tick = 0x00;
	
	
	
	//下发门锁
	if(SysTick_1ms - MCU_Set_SmtLock_tick >= 1000)		
	{
		MCU_Set_SmtLock_tick = SysTick_1ms;
		
		//发送门锁开锁命令
		if(g_smtlock.Dev_SetUnLock_Flag != 0x00)
		{
			if(g_smtlock.LockSendCnt >= 3)
			{
				g_smtlock.LockSendCnt = 0x00;
				g_smtlock.Dev_SetUnLock_Flag = 0x00;
			}
			else 
			{
				RS485_UNLOCK_Send();
				g_smtlock.LockSendCnt++;
			}			
		}	
		
	}
	
	
	//上报RCU时间间隔
	if(SysTick_1ms - SmtLock_tick >= REPORT_TIMEOUT)		
	{
		SmtLock_tick = SysTick_1ms;
		
		if(g_smtlock.Dev_LockStaRpt_Flag != 0x00)
		{
			if(g_smtlock.SendCnt >= RETRY_TIME)
			{
				g_smtlock.SendCnt = 0x00;
				g_smtlock.Dev_LockStaRpt_Flag = 0x00;
				g_smtlock.Dev_LockActRpt_Flag = 0x00;
				g_smtlock.Dev_IDRpt_Flag = 0x00;
			}
			else 
			{
				MCU_SmtLock_IDRpt();
				g_smtlock.SendCnt++;
			}			
		}
		else if(g_smtlock.Dev_StaRpt_Flag != 0x00)
		{
			if(g_smtlock.SendCnt >= RETRY_TIME)
			{
				g_smtlock.SendCnt = 0x00;
				g_smtlock.Dev_StaRpt_Flag = 0x00;
			}
			else 
			{
				MCU_SmtLock_BatMon();
				g_smtlock.SendCnt++;
			}			
		}else{
			
		}
	}
}



/****************************************************************************************************
 * @FunctionName: RS485_RCU_Control_Processing
 * @brief		: 转发设备对RCU主机的接收处理
 * @param		: RecvData: 接收数据缓存区
 * @param		: RecvLen ：接收数据长度
 * @retval		: 0x00:数据处理成功，其它：数据处理失败
 * @note		: 
 * *****************************************************************************************************/
U8_T RS485_RCU_Control_Processing(U8_T *RecData, U16_T RecvLen)
{
	if(RecvLen < 8)
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"MCU_MinLen Err:%d",RecvLen);
		return 0x01;
	}

	if(RecData[2] != Project_Type)
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"MCU_Type Err:%d",RecData[2]);
		return 0x02;
	}
	
	if(RecData[3] != g_Dip.DIP_addr)
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"MCU_Addr Err:%d",RecData[3]);
		return 0x03;
	}
	
	if(RecData[4] != RecvLen)
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"MCU_Len Err:%d",RecData[4]);
		return 0x04;
	}
	

	if(RecData[5] != CheckSum_Overlook_Check(RecData,RecvLen,5))
	{
		Dbg_Println(DBG_BIT_Debug_STATUS,"MCU_SumCRC Err:%d, %d",RecData[5],CheckSum_Overlook_Check(RecData,(RecvLen-1),5));
		return 0x05;	
	}	
	
	Dbg_Println(DBG_BIT_Debug_STATUS,"MCU Report Ack:%02x",RecData[6]);
	Dbg_Print_Buff(DBG_BIT_Debug_STATUS,"MCU Report",RecData,RecvLen);
	
	g_smtlock.SendCnt = 0x00;//有回复清发送次数，主动上报会重新发送
	
	switch(RecData[6])
	{
		case DEV_IDSTATE_RPT:		//门锁身份、动作
			if( (RecData[1]&0x0F) != g_smtlock.SendSn)
			{
				g_smtlock.SendSn = (RecData[1]&0x0F);
				
				if(RecData[7] == 0x01)
				{
					Clear_SendFlag();
					g_smtlock.Dev_LockStaRpt_Flag = 0x00;
					g_smtlock.Dev_LockActRpt_Flag = 0x00;
					g_smtlock.Dev_IDRpt_Flag = 0x00;					
				}				
			}
		break;
		case DEV_BATMON_RPT:		//门锁电量
			if( (RecData[1]&0x0F) != g_smtlock.SendSn)
			{
				g_smtlock.SendSn = (RecData[1]&0x0F);
				
				if(RecData[7] == 0x01)
				{
					Clear_SendFlag();
					g_smtlock.Dev_StaRpt_Flag = 0x00;					
				}				
			}
		break;
		case DEV_VERSON_RPT:		//版本号
			if( (RecData[1]&0x0F) != g_smtlock.RecvSn)
			{
				g_smtlock.RecvSn = (RecData[1]&0x0F);			
				MCU_SmtLock_Version();
			}
			else if( (RecData[1]&0x40) == 0x40){
				MCU_SmtLock_Version();
			}				
		break;	
		case DEV_UNLOCK_RPT:		//开锁命令
			if( (RecData[1]&0x0F) != g_smtlock.RecvSn)
			{
				g_smtlock.RecvSn = (RecData[1]&0x0F);
			
				if(RecData[7] == 0x01)
				{
					g_smtlock.Dev_SetUnLock_Flag = 0x01;
					g_smtlock.LockSendCnt = 0x00;
					
					Dbg_Println(DBG_BIT_Debug_STATUS,"RCU Set UnLock");
					
					MCU_SmtLock_UnLock();
				}
			}else if( (RecData[1]&0x40) == 0x40){
				if(RecData[7] == 0x01)
				{
					MCU_SmtLock_UnLock();
				}				
			}		
		break;	
		default:
		break;
	}		


	return 0x00;
}










