
/**
  ******************************************************************************
  * @file    BLV_485_Dev_BLWLockFun.c
  * @author  BLW RCU  development Team
  * @version V1.0.0
  * @date    2021年11月02日
  * @brief   微信锁驱动总表         可以控制开锁关锁，以及得到锁的状态
	*          目前仅用于RF微信锁
	* 
  ******************************************************************************
  */

#include "includes.h"

#include "BLV_485_Dev_BLWLockFun.h"
#include "string.h"

#define RFLOCKCYCLEWAITTIMEOUT       5000    //无线锁轮询超时等待时间    控制结束后便进入轮询

void RF_Rs485_WxLock_Pro(Device_Public_Information_G *BUS_Public, uint8_t *Data, RS485_WxLock_INFO  *Rs485WxLockInfo);

uint8_t RF_Rs485_WxLock_CtrlCycle(uint32_t dev_addr); 
uint8_t RF_WxLock_Read(uint32_t dev_addr,uint32_t data_addr,uint16_t len);
void RF_WxLock_TimeSet(uint32_t dev_addr, uint32_t RfGatewayHostAddr);
void RF_WxLock_Ctrl(Device_Public_Information_G *BUS_Public, RS485_WxLock_INFOP Rs485WxLockInfo);
//void RF_WxLock_Ctrl(CFG_Dev_AddP CfgDevAdd, RS485_WxLock_INFOP Rs485WxLockInfo,uint32_t dev_addr);
void RFDevRecAsk(uint32_t CfgDevAddRfGatewayHost, Device_Public_Information_G *BUS_Public, uint8_t DevType);

/*******************************************************************************
* @Function Name  : BLW_RS485_BLWLockFun_Init 
* @Description    : 添加设备到链表 - 主动设备
* @Input          : 
	@type	: 添加的设备类型
	@addr	: 添加的设备地址
	@polling_cf		：设备的数据发送回调函数
	@processing_cf	：设备的数据处理回调函数
* @Return         : None
*******************************************************************************/
void BLW_RS485_WxLockFun_Init(Device_Public_Information_G *BUS_Public, RS485_WxLock_INFO *Rs485WxLockInfo)
{

	BUS_Public->polling_cf = (uint32_t)&RF_Rs485_WxLock_CtrlCycle;
	BUS_Public->processing_cf = (uint32_t)&RF_WxLock_Read;
	
	Rs485WxLockInfo->RfGatewayHostAddr = Find_Device_List_Information(DEV_RS485_RFGatewayHost, RFGATEWAYADDRDEFAULT);
	
}


/*门锁轮询控制函数*/
uint8_t RF_Rs485_WxLock_CtrlCycle(uint32_t dev_addr)
{
//	static uint8_t CycleCnt = 0;
	uint8_t Ret = 0x00;
	Device_Public_Information_G BUS_Public;
	RS485_WxLock_INFO  Rs485WxLockInfo;
//	CFG_Dev_Add CfgDevAdd;
//	uint16_t DataLen;
//	uint8_t Crc_buf;
	
//	CfgDevAddRfGatewayHost = HostRunInfo.CfgDevAddRFGateway;
//	if(0x00 == dev_addr)
//	{
//		return Ret;
//	}
	

	SRAM_Read_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);  
	SRAM_Read_Buff((uint8_t *)&Rs485WxLockInfo, sizeof(RS485_WxLock_INFO), dev_addr+Dev_Privately);

	if((NULL == Rs485WxLockInfo.RfGatewayHostAddr))
	{
		return Ret;
	}	

	{
	//	if(DEV_IS_ONLINE == Rs485WxLockInfo.DevOffline)  //唯有在线，才会控制。意思就是先接收到锁的状态，才会在线
		{
			if(0x01 == Rs485WxLockInfo.WeixinTimeSetFlag)                       //设置微信锁睡眠时间
			{
				if(0x00 != Rs485WxLockInfo.WeixinTimeSetCnt)
				{
					Rs485WxLockInfo.WeixinTimeSetCnt--;   //递减
				}
				else if(0x00 == Rs485WxLockInfo.WeixinTimeSetCnt)
				{
					Rs485WxLockInfo.WeixinTimeSetFlag = 0;
				}
//				RF_WxLock_TimeSet(dev_addr, Rs485WxLockInfo.RfGatewayHostAddr);//控制开锁，控制开锁标志，在保证主机接收到微信锁的回复才会清0 控制微信开锁之后，到读取为锁关之前都是高速轮询
				Ret = 0x01;
			}
			else if(0x01 == Rs485WxLockInfo.WeixinCtrlFlag)  //微信锁控制标志位
			{
				if(SysTick_1ms >= Rs485WxLockInfo.WeixinCycleCnt)  //超过时间   
				{
					Rs485WxLockInfo.WeixinCycleCnt = SysTick_1ms + RFLOCKCYCLEWAITTIMEOUT;
					if(0x00 != Rs485WxLockInfo.WeixinCtrlSendCnt)
					{
						Rs485WxLockInfo.WeixinCtrlSendCnt--;   //递减
					}
					else if(0x00 == Rs485WxLockInfo.WeixinCtrlSendCnt)
					{
						Rs485WxLockInfo.WeixinCtrlFlag = 0;
					}
					RF_WxLock_Ctrl(&BUS_Public, &Rs485WxLockInfo);//控制开锁，控制开锁标志，在保证主机接收到微信锁的回复才会清0 控制微信开锁之后，到读取为锁关之前都是高速轮询
					Ret = 0x01;
				}
			}
		}
	}
	
	if(0x01 == Ret)
	{
		/*通讯统计*/
		BLV_Communication_Record(&Rs485WxLockInfo.comm_record,0x01,0x00);
		
		if(Rs485WxLockInfo.DevSendCnt > WxLockCtrlSendMax)
		{
			if(Rs485WxLockInfo.DevOffline != DEV_IS_OFFLINE)
			{
				Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"RFGatewayHostinfo DEV_IS_OFFLINE");
				LOG_Device_Online_Record(DEV_RS485_WxLock,SRAM_Read_Byte(dev_addr+Dev_Addr),LogInfo_Device_Offline);	//记录设备离线
			}
			Rs485WxLockInfo.DevOffline = DEV_IS_OFFLINE;   //判为离线
			if(Rs485WxLockInfo.DevOffline != Rs485WxLockInfo.DevOfflineLast)	//当前在线状态不等于上一次在线状态
			{
				Rs485WxLockInfo.DevOfflineLast = Rs485WxLockInfo.DevOffline;	//更新上一次在线状态
				Write_Device_Fault_State(BUS_Public.type,BUS_Public.addr,In_ErrFun_LineState,DEV_IS_OFFLINE);	//保存设备在线状态到SRAM
			}
		}
		else
		{
			Rs485WxLockInfo.DevSendCnt++;
		}
		
		BUS_Public.check = 0x00;
		BUS_Public.check = DoubleData_CheckSum((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), (uint8_t *)&Rs485WxLockInfo, sizeof(RS485_WxLock_INFO));
		SRAM_DMA_Write_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G),dev_addr);/*将数据保存*/
		SRAM_DMA_Write_Buff((uint8_t *)&Rs485WxLockInfo,sizeof(RS485_WxLock_INFO),dev_addr+Dev_Privately);
						
		
		
	}
	
	return Ret;
}

#define RFGatewayCTRLLEN     8         //微信锁控制报文

/**
  * @brief      门锁控制发送函数
  * @param  
  *    CfgDevAddOut        设备节点
  * @retval     无
  * @attention   只负责开锁
  */
void RF_WxLock_Ctrl(Device_Public_Information_G *BUS_Public, RS485_WxLock_INFOP Rs485WxLockInfo)
{
	                                  //网关地址  RFTy  RFAD  Sum   PLEN  CMD   保留  CTRL   
	uint8_t SendBuf[RFGatewayCTRLLEN];// = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x31, 0x00}; 
	
//	uint8_t RfDevAddr = SRAM_Read_Byte(RfGatewayHostAddr+Dev_Addr);   //设备地址	
//	uint8_t DevAddr = SRAM_Read_Byte(dev_addr+Dev_Addr);   //微信锁设备地址	
//	uint8_t port = SRAM_Read_Byte(dev_addr+Dev_port);      //通讯端口

	
//	SRAM_Read_Buff((uint8_t *)&Rs485WxLockInfo, sizeof(RS485_WxLock_INFO), dev_addr+Dev_Privately);   //将485数据拷贝出来 

	
	SendBuf[0] = RFGATEWAYADDRDEFAULT; //RfGatewayHostAddr->BUS_Public.addr;//网关地址CfgDevAdd->DevBaud;//BLV_SN_Get(&Rs485RFGatewaySwtInfo->SwtSn, RFGatewaySwtSnMin, RFGatewaySwtSnMax);
	SendBuf[1] = RFGATEWAYLOCKTYPE;//CfgDevAdd->Dev485Fre;    //
	SendBuf[2] = BUS_Public->addr;   
	SendBuf[4] = 0x02;//0x01 + Rs485RFGatewaySwtInfo->SwtOutputValidNum;
	SendBuf[5] = 0x06;
	SendBuf[6] = 0x31;
	
	
	switch(Rs485WxLockInfo->WeixinCtrlState)
	{
		case 0x01:   //打开
		case 0x02:   //关闭
			SendBuf[7] = Rs485WxLockInfo->WeixinCtrlState;//;
			break;
	}
	
	SendBuf[3] = CheckSum_Overlook_Check(SendBuf, RFGatewayCTRLLEN, 3);		
	
//	if(0x00 == Rs485WxLockInfo.WeixinCtrlFlag)   //控制结束，进入轮询
//	{
//		RS485_Port_SendFun(CfgDevAdd, SendBuf, RFGatewayTimeSetLEN, RFLOCKCYCLETIMEOUT); 
//	}
//	else  //进入控制，以及控制重发
	{	
		MCU485_SendString(BUS_Public->port,SendBuf,RFGatewayCTRLLEN);

		/*日志记录*/
		LOG_Device_COMM_Send_Control_Record(BUS_Public->port, BUS_Public->baud, SendBuf, RFGatewayCTRLLEN);
//		RS485_Port_SendFun(CfgDevAdd, SendBuf, RFGatewayCTRLLEN, RFLOCKCTRLTIMEOUT); 
	}		
}


//#define RFGatewayTimeSetLEN     8         //微信锁睡眠时间设置报文长度

/**
  * @brief      门锁控制发送函数
  * @param  
  *    dev_addr           设备节点
  *    RfGatewayHostAddr  网关节点
  * @retval     无
  * @attention   只负责开锁
  */
//void RF_WxLock_TimeSet(uint32_t dev_addr, uint32_t RfGatewayHostAddr)
//{
//																		//网关地址  RFTy  RFAD  Sum   PLEN  CMD   保留  CTRL   
//	uint8_t SendBuf[RFGatewayTimeSetLEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, 0x00}; 
//	RS485_WxLock_INFOP Rs485WxLockInfo;
//	
////	Rs485WxLockInfo = CfgDevAdd->DevDataStruct;
//	
//	SendBuf[0] = CfgDevAddRfGatewayHost->DevAddr;//网关地址CfgDevAdd->DevBaud;//BLV_SN_Get(&Rs485RFGatewaySwtInfo->SwtSn, RFGatewaySwtSnMin, RFGatewaySwtSnMax);
//	SendBuf[1] = RFGATEWAYLOCKTYPE;//CfgDevAdd->Dev485Fre;    //
//	SendBuf[2] = CfgDevAdd->DevAddr;   
//	SendBuf[4] = 0x02;//0x01 + Rs485RFGatewaySwtInfo->SwtOutputValidNum;
//	
//	switch(Rs485WxLockInfo.WeixinTimeSetValue)
//	{
//		case 0x01:   //睡眠时间为2秒
//		case 0x02:   //睡眠时间为4秒
//		case 0x03:   //睡眠时间为8秒
//		case 0x04:   //睡眠时间为16秒
//			SendBuf[7] = Rs485WxLockInfo->WeixinTimeSetValue;//;
//			break;
//	}
//	
//	SendBuf[3] = CheckSum_Overlook_Check(SendBuf, RFGatewayTimeSetLEN, 3);		
//	
//	if(0x00 == Rs485WxLockInfo->WeixinTimeSetFlag)   //设置结束，进入轮询
//	{
//		RS485_Port_SendFun(CfgDevAdd, SendBuf, RFGatewayTimeSetLEN, RFLOCKCYCLETIMEOUT); 
//	}
//	else
//	{	
//		RS485_Port_SendFun(CfgDevAdd, SendBuf, RFGatewayTimeSetLEN, RFLOCKSETTIMEOUT); 
//	}
//}

#define IsMyData     0x00  
#define IsNotMyData  0x01

#define RECLENMAX    40   //超过40个字节，直接返回

/**
  * @name  			  无线微信锁接收处理函数
  * @param  
  *    dev_addr   设备信息地址
  *    data_addr  485数据包地址
  *    DataLen    数据包长度
  * @retval      1 是我的数据    2 不是我的数据
  * @attention   
	*              
  */
uint8_t RF_WxLock_Read(uint32_t dev_addr,uint32_t data_addr,uint16_t DataLen)
{
	uint8_t Crc_buf;
	RS485_WxLock_INFO  Rs485WxLockInfo;   //微信锁局部变量
	uint8_t Ret = IsNotMyData;
	uint8_t Data[RECLENMAX];     //局部变量，用于存储485数据
//	uint8_t DevAddr = SRAM_Read_Byte(dev_addr+Dev_Addr);   //设备地址	
//	CFG_Dev_Add CfgDevAdd;
	Device_Public_Information_G BUS_Public;
	
	if((NULL == dev_addr) || (DataLen > RECLENMAX))   //传的参数异常就直接返回
	{
		return Ret;
	}
	SRAM_Read_Buff(Data, DataLen, data_addr);   //将485数据拷贝出来 
	SRAM_Read_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);
	SRAM_Read_Buff((uint8_t *)&Rs485WxLockInfo, sizeof(RS485_WxLock_INFO), dev_addr+Dev_Privately);
	
	if((NULL == Rs485WxLockInfo.RfGatewayHostAddr) || ((Data[4]+0x06) != DataLen) || (RFGATEWAYLOCKTYPE != Data[1]) || (BUS_Public.addr != Data[2]))   //不是无线继电器类型  或者地址不对
	{
		return Ret;
	}
//	Rs485WxLockInfo = CfgDevAdd->DevDataStruct;   
	
	Crc_buf = CheckSum_Overlook_Check(Data, DataLen, 3);  //提前保存校验

	if(Crc_buf == Data[3])   //校验判断     是否是自己的类型
	{
		Ret = IsMyData;
		
		if(Rs485WxLockInfo.DevOffline != DEV_IS_ONLINE)
		{
			Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"Rs485WxLock DEV_IS_ONLINE");
			LOG_Device_Online_Record(BUS_Public.type, BUS_Public.addr,LogInfo_Device_Online);	//记录设备在线
		}
		
		Rs485WxLockInfo.DevSendCnt = 0x00;
		Rs485WxLockInfo.DevOffline = DEV_IS_ONLINE;    //设备在线
		BLV_Communication_Record(&Rs485WxLockInfo.comm_record,0x02,0x01);		//记录通讯成功
		if(Rs485WxLockInfo.DevOffline != Rs485WxLockInfo.DevOfflineLast)	//当前在线状态不等于上一次在线状态
		{
			Rs485WxLockInfo.DevOfflineLast = Rs485WxLockInfo.DevOffline;	//更新上一次在线状态
			Write_Device_Fault_State(BUS_Public.type,BUS_Public.addr,In_ErrFun_LineState,DEV_IS_ONLINE);	//保存设备在线状态到SRAM
		}
		switch(Data[5])
		{
			case 0x51:           
				switch(Data[4])
				{
					case 0x04: //微信锁状态主动上报   有5个字节
//						RFLockRecAsk(CfgDevAdd, CfgDevAddRfGatewayHost);  //RCU回复已收到
						RFDevRecAsk(Rs485WxLockInfo.RfGatewayHostAddr, &BUS_Public, RFGATEWAYLOCKTYPE);  //回复确认报文			
						RF_Rs485_WxLock_Pro(&BUS_Public, &Data[0], &Rs485WxLockInfo);					//校验通过，接收处理
						if(0x01 == Data[7])    //状态为锁开
						{
							Rs485WxLockInfo.WeixinCtrlFlag = 0;   //收到回复进行清0
							Rs485WxLockInfo.WeixinCycleCnt = 0;   //清计数，方便下次开锁，能及时发送报文
						}
						
						/*日志记录*/
						LOG_Device_COMM_Control_Reply_Record(BUS_Public.port, BUS_Public.baud,Data,DataLen);
						break;
				}
				break;
			case 0x16:   //设置锁休眠时间，锁回复
				if(0x02 == Data[4])
				{
//					RFLockRecAsk(CfgDevAdd, Rs485WxLockInfo.RfGatewayHostAddr);  //RCU回复已收到	
					RFDevRecAsk(Rs485WxLockInfo.RfGatewayHostAddr, &BUS_Public, RFGATEWAYLOCKTYPE);  //回复确认报文								
					Rs485WxLockInfo.WeixinTimeSetFlag = 0;
					
					/*日志记录*/
					LOG_Device_COMM_Control_Reply_Record(BUS_Public.port, BUS_Public.baud,Data,DataLen);
				}
				break;
		}
		
		
		BUS_Public.check = 0x00;
		BUS_Public.check = DoubleData_CheckSum((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), (uint8_t *)&Rs485WxLockInfo, sizeof(RS485_WxLock_INFO));
		SRAM_DMA_Write_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G),dev_addr);/*将数据保存*/
		SRAM_DMA_Write_Buff((uint8_t *)&Rs485WxLockInfo,sizeof(RS485_WxLock_INFO),dev_addr+Dev_Privately);
						
	}
	return Ret;
}

/**
  * @name  					无线设备数据确认收到回复函数 
  * @param  
  *    CfgDevAddRfGatewayHost       主网关设备节点
  *    CfgDevAdd                 无线设备设备节点
  *    DevType                    无线设备类型
  * @retval            无
  * @attention         回路状态函数和所有回路状态函数
  */
void RFDevRecAsk(uint32_t CfgDevAddRfGatewayHost, Device_Public_Information_G *BUS_Public, uint8_t DevType)
{
	uint8_t SendBuf[7];// = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	
	SendBuf[0] = RFGATEWAYADDRDEFAULT ;  // CfgDevAddRfGatewayHost->BUS_Public.addr;//网关地址 
	SendBuf[1] = DevType;    //无线设备类型
	SendBuf[2] = BUS_Public->addr;     //设备地址
	SendBuf[4] = 0x01;                //参数长度
	SendBuf[5] = 0x41;                      //命令	
	SendBuf[6] = 0x00; 
	SendBuf[3] = CheckSum_Overlook_Check(SendBuf, 0x07, 3);//[3] 整包	
	
	MCU485_SendString(BUS_Public->port, SendBuf, 0x07);  //CfgDevAddRfGatewayHost->BUS_Public.port

//	RS485_Port_SendFun(CfgDevAddRfGatewayHost, SendBuf, 0x07, RFDEVASKTIMEOUT);  

}

/*对门锁外设发过来的数据进行处理*/
void RF_Rs485_WxLock_Pro(Device_Public_Information_G *BUS_Public, uint8_t *Data, RS485_WxLock_INFO  *Rs485WxLockInfo)
{
//	RS485_WxLock_INFOP  Rs485WxLockInfo;
	
//	Rs485WxLockInfo = CfgDevAdd->DevDataStruct;
//	Service.food_plate = Data[1];  //同步微信锁
	switch(Data[7])
	{
		case 0x01:
			Rs485WxLockInfo->WeixinLockState = DEV_CTRLWAY_OPEN;      //锁状态同步
			break;
		case 0x02:
			Rs485WxLockInfo->WeixinLockState = DEV_CTRLWAY_CLOSE;
			break;
		default:
			Rs485WxLockInfo->WeixinLockState = DEV_CTRLWAY_INVALID; //无效的，未初始化的
			break;

	}
	if(Rs485WxLockInfo->WeixinLockStateLast != Rs485WxLockInfo->WeixinLockState)  //
	{
		Rs485WxLockInfo->WeixinLockStateLast = Rs485WxLockInfo->WeixinLockState;
		Rs485WxLockInfo->WeixinLockAction = Rs485WxLockInfo->WeixinLockState;   //微信锁动作
//		Rs485WxLockInfo->WeixinLockUpFlag = 0x01;   //微信锁状态上报标志
	}
  Rs485WxLockInfo->DoorLockVoltage = Data[8] + (Data[9]<<8);   
	Rs485WxLockInfo->WeixinLockUpVol = Rs485WxLockInfo->DoorLockVoltage*10/6;  //电量百分比
//	Rs485WxLockInfo->DoorLockVoltageL = Data[2];//;  //0x88
//	Rs485WxLockInfo->DoorLockVoltageH = Data[3];//;  //0x13
	
}




