/**
  ******************************************************************************
  * @file    BLV_485_Dev_CLEDFreshAirFun.c
  * @author  BLW RCU  development Team	YHF
  * @version V1.0.0
  * @date    2023年7月28日
  * @brief   CLED地暖
  ******************************************************************************
  */

#include "includes.h"
#include "BLV_485_Dev_CLEDFloorHeatFun.h"

#define CLED_FLOORHEAT_MAX_SEND_CNT				0x03	//CLED地暖设备最大重发次数
#define CLED_FLOORHEAT_RECEIVE_MAX_DATA_LEN		0x0A	//CLED地暖设备最大数据长度

/*函数声明开始*/
void CLED_FloorHeat_Control(Device_Public_Information_G *BUS_Public,RS485_FloorHeat_INFO *FloorHeat_Info);	//CLED地暖控制函数
void CLED_FloorHeat_Change_Data(Device_Public_Information_G *BUS_Public,RS485_FloorHeat_INFO *FloorHeat_Info,uint8_t *data);	//CLED地暖数据变化函数
/*函数声明结束*/

/*******************************************************************************
  * @brief      添加CLED地暖设备到链表 - 轮询设备
  * @param  
  *		BUS_Public		设备共有属性指针
  *		FloorHeat_Info	485地暖设备私有属性指针
  * @retval     None
  * @attention	None
*******************************************************************************/
void CLED_RS485_FloorHeat_Init(Device_Public_Information_G *BUS_Public,RS485_FloorHeat_INFO *FloorHeat_Info)
{
	BUS_Public->polling_cf = (uint32_t)&CLED_FloorHeat_Polling_Ctrl;	    //CLED地暖轮询控制函数
	BUS_Public->processing_cf = (uint32_t)&CLED_FloorHeat_Data_Processing;	//CLED地暖接收处理函数
	
	Dbg_Println(DBG_BIT_LOGIC_STATUS_bit,"添加CLED地暖设备 %d 地址",BUS_Public->addr);
}

/*******************************************************************************
  * @brief      CLED地暖轮询控制函数
  * @param  
  *		dev_addr	设备信息地址
  * @retval     RS485OCCUPYTIME - 485发送函数会占用时间
				RS485OCCUPYNOTIME - 485发送函数不会占用时间
  * @attention	None
*******************************************************************************/
uint8_t CLED_FloorHeat_Polling_Ctrl(uint32_t dev_addr)
{
	uint8_t send_time = RS485OCCUPYNOTIME;	//发送时间（默认发送不占用时间）
	Device_Public_Information_G BUS_Public;	//地暖设备共有属性
	RS485_FloorHeat_INFO FloorHeat_Info;	//地暖设备私有属性
	
	SRAM_DMA_Read_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);	//读取共有属性
	SRAM_DMA_Read_Buff((uint8_t *)&FloorHeat_Info,sizeof(RS485_FloorHeat_INFO), dev_addr+Dev_Privately);	//读取私有属性
	if((FloorHeat_Info.ctrl_flag.on_off == 0x01) &&(FloorHeat_Info.ctrl_flag.set_oc == 0x01))	//控制开关机标志置1	
	{
		if(FloorHeat_Info.ctrl_cnt.on_off != 0x00)	//开关机控制次数不为0
		{
			FloorHeat_Info.ctrl_cnt.on_off--;	//控制次数减1
		}
		else	//开关机控制次数为0
		{
			FloorHeat_Info.ctrl_flag.on_off = 0x00;	//控制开关机标志清0
		}
		CLED_FloorHeat_Control(&BUS_Public,&FloorHeat_Info);	//地暖控制
		send_time = RS485OCCUPYTIME;	//发送占用时间
	}
	
	
	if(send_time == RS485OCCUPYTIME)	//如果发送占用时间
	{
		if(FloorHeat_Info.DevSendCnt > CLED_FLOORHEAT_MAX_SEND_CNT)	//发送次数大于重发次数
		{
			if(FloorHeat_Info.DevOffline != DEV_IS_OFFLINE)	//设备当前不是离线
			{
				Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"CLED地暖 %d 地址离线！！！",BUS_Public.addr);
				LOG_Device_Online_Record(DEV_RS485_HEATER, BUS_Public.addr, LogInfo_Device_Offline);	//记录设备离线
			}
			FloorHeat_Info.DevOffline = DEV_IS_OFFLINE;	//设备离线
			if(FloorHeat_Info.DevOffline != FloorHeat_Info.DevOfflineLast)	//当前在线状态不等于上一次在线状态
			{
				FloorHeat_Info.DevOfflineLast = FloorHeat_Info.DevOffline;	//更新上一次在线状态
				Write_Device_Fault_State(BUS_Public.type,BUS_Public.addr,In_ErrFun_LineState,DEV_IS_OFFLINE);	//保存设备在线状态到SRAM
			}
		}
		else	//发送次数小于等于重发
		{
			FloorHeat_Info.DevSendCnt++;	//发送次数增加
		}
		BLV_Communication_Record(&FloorHeat_Info.comm_record, 0x01, 0x00);	//通讯统计
		FloorHeat_Info.inquire_tick = SysTick_1ms;	//更新轮询时间戳
		
		BUS_Public.check = 0x00;	//检验清0
		BUS_Public.check = DoubleData_CheckSum((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), (uint8_t *)&FloorHeat_Info, sizeof(RS485_FloorHeat_INFO));	//计算校验
		SRAM_DMA_Write_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);	//保存共有数据
		SRAM_DMA_Write_Buff((uint8_t *)&FloorHeat_Info, sizeof(RS485_FloorHeat_INFO), dev_addr+Dev_Privately);	//保存新风私有数据
	}
	return send_time;
}

/*******************************************************************************
  * @brief      CLED地暖接收处理函数
  * @param  
  *		dev_addr		设备信息地址
  *		data_addr		485数据包地址
  *		DataLen			数据包长度
  * @retval     0-是CLED地暖数据，1-不是CLED地暖数据
  * @attention	None
*******************************************************************************/
uint8_t CLED_FloorHeat_Data_Processing(uint32_t dev_addr,uint32_t data_addr,uint16_t len)
{
	uint8_t rec = 0x01, data[CLED_FLOORHEAT_RECEIVE_MAX_DATA_LEN];	//返回值（默认不是CLED新风数据），接收的数据中间变量
	uint8_t tempflag = 0x00;
	Device_Public_Information_G BUS_Public;	//地暖设备共有属性
	RS485_FloorHeat_INFO FloorHeat_Info;	//地暖设备私有属性
	
	if(len!=5)
	{
		Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"接收数据长度和CLED地暖不符!!");
		return rec;
	}
	
	SRAM_DMA_Read_Buff(data, len, data_addr);	//读取新风设备的485数据
	SRAM_DMA_Read_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);	//读取共有属性
	
	if(data[4]!=SOR_CRC(data,4))
	{
		Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"CLED地暖和校验错误!!");
		return rec;
	}
	
	if(data[0]!=BUS_Public.addr)
	{
		Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"与CLED地暖地址不符!!");
		return rec;
	}
	
	if((data[1]!=0x83) && (data[1]!=0x86))
	{
		Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"与CLED地暖命令字不符!!");
		return rec;
	}
	
	
	rec = 0x00;	//是CLED新风数据
	SRAM_DMA_Read_Buff((uint8_t *)&FloorHeat_Info,sizeof(RS485_FloorHeat_INFO), dev_addr+Dev_Privately);	//读取私有属性
	
	if(FloorHeat_Info.DevOffline != DEV_IS_ONLINE)
	{
		Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"CLED地暖 %d 地址在线",BUS_Public.addr);
		LOG_Device_Online_Record(DEV_RS485_HEATER, BUS_Public.addr, LogInfo_Device_Online);	//记录设备在线
	}
	FloorHeat_Info.DevSendCnt = 0x00;	//计数清0
	FloorHeat_Info.DevOffline = DEV_IS_ONLINE;	//轮询回复，设备在线
	if(FloorHeat_Info.DevOffline != FloorHeat_Info.DevOfflineLast)	//当前在线状态不等于上一次在线状态
	{
		FloorHeat_Info.DevOfflineLast = FloorHeat_Info.DevOffline;	//更新上一次在线状态
		Write_Device_Fault_State(BUS_Public.type,BUS_Public.addr,In_ErrFun_LineState,DEV_IS_ONLINE);	//保存设备在线状态到SRAM
	}
	BLV_Communication_Record(&FloorHeat_Info.comm_record,0x02,0x01);	//记录通讯成功
	
	
	switch(data[1])
	{
		case 0x83:
			CLED_FloorHeat_Change_Data(&BUS_Public,&FloorHeat_Info,data);
			tempflag = 0x01;
			break;
		case 0x86:
			FloorHeat_Info.ctrl_flag.on_off = 0x00;	//控制开关机清0
			FloorHeat_Info.ctrl_flag.set_oc = 0x00;	//控制风速清0
			FloorHeat_Info.ctrl_cnt.on_off = 0x03;
			FloorHeat_Info.ctrl_cnt.set_oc = 0x03;		
			tempflag = 0x01;
			Dbg_Println(DBG_BIT_DEVICE_STATUS_bit,"CLED地暖 %d 地址设备收到控制回复，清开控制标志", BUS_Public.addr);
			break;
		default:
			break;
	}

	
	if(tempflag)
	{
		BUS_Public.check = 0x00;	//检验清0
		BUS_Public.check = DoubleData_CheckSum((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), (uint8_t *)&FloorHeat_Info, sizeof(RS485_FloorHeat_INFO));	//计算校验
		SRAM_DMA_Write_Buff((uint8_t *)&BUS_Public, sizeof(Device_Public_Information_G), dev_addr);	//保存共有数据
		SRAM_DMA_Write_Buff((uint8_t *)&FloorHeat_Info, sizeof(RS485_FloorHeat_INFO), dev_addr+Dev_Privately);	//保存地暖私有数据
	}
	
	return rec;
}

/*******************************************************************************
  * @brief      CLED地暖控制函数
  * @param  
  *		BUS_Public		设备共有属性指针
  *		function		功能控制
  *		control			控制内容
  * @retval     None
  * @attention	None
*******************************************************************************/
void CLED_FloorHeat_Control(Device_Public_Information_G *BUS_Public,RS485_FloorHeat_INFO *FloorHeat_Info)
{
	uint8_t data[5] = {0};	//要发送的数据
	
	data[0] = BUS_Public->addr;	//设备地址赋值
	data[1] = 0x86;
	
	data[2] |= FloorHeat_Info->ctrl_content.set_oc;
	
	if(FloorHeat_Info->ctrl_content.on_off==0x01)
	{
		data[3] |= (0x01<<6);
	}
	else if(FloorHeat_Info->ctrl_content.on_off==0x00)
	{
		data[3] |= (0x02<<6);
	}
	
	
	data[4] = SOR_CRC(data,4);

	MCU485_SendString(BUS_Public->port, data, 5);	//使用485发送
	LOG_Device_COMM_Send_Control_Record(BUS_Public->port, BUS_Public->baud, data, 5);	//日志记录
}


/*******************************************************************************
  * @brief      CLED地暖数据变化函数
  * @param  
  *		FloorHeat_Info	485地暖设备私有属性指针
  *		data			接收数据指针
  * @retval     0 - 数据没变化
				1 - 数据有变化
  * @attention	None
*******************************************************************************/
void CLED_FloorHeat_Change_Data(Device_Public_Information_G *BUS_Public,RS485_FloorHeat_INFO *FloorHeat_Info,uint8_t *data)
{
	uint8_t tempdata = ((data[2]&0xE0)>>5)+((data[3]&0x03)<<3);
	
	FloorHeat_Info->new_state.on_off = (data[3]&0x80)>>7;	//当前开关机状态保存
	FloorHeat_Info->new_state.set_oc = tempdata;	     //当前设置温度状态保存
	if(tempdata == 0x00)	//温度转化
	{
		FloorHeat_Info->new_state.set_oc = 32;	//温度转换
	}
	if(((data[3] & 0x04) >> 2) == FLOORHEAT_VALVE_ON)	//阀门状态为开
	{
		FloorHeat_Info->new_state.valve = TEMP_VALVE_OPEN;	//阀开
	}
	else	//阀门状态为关
	{
		FloorHeat_Info->new_state.valve = TEMP_VALVE_CLOSE; //阀关
	}
	FloorHeat_Info->new_state.indoor_oc = data[2]&0x1F;	//当前室内温度状态保存
	if(FloorHeat_Info->ctrl_content.on_off != FloorHeat_Info->ctrl_content_last.on_off)	//状态同步
	{
		FloorHeat_Info->ctrl_content_last.on_off = FloorHeat_Info->ctrl_content.on_off;
	}
	if(FloorHeat_Info->ctrl_content.set_oc != FloorHeat_Info->ctrl_content_last.set_oc)
	{
		FloorHeat_Info->ctrl_content_last.set_oc = FloorHeat_Info->ctrl_content.set_oc;
	}
	if(FloorHeat_Info->ctrl_content.indoor_oc != FloorHeat_Info->ctrl_content_last.indoor_oc)
	{
		FloorHeat_Info->ctrl_content_last.indoor_oc = FloorHeat_Info->ctrl_content.indoor_oc;
	}
	if(FloorHeat_Info->ctrl_content.valve != FloorHeat_Info->ctrl_content_last.valve)
	{
		FloorHeat_Info->ctrl_content_last.valve = FloorHeat_Info->ctrl_content.valve;
	}
	
	MCU485_SendString(BUS_Public->port, data, 5);	//使用485发送
	LOG_Device_COMM_Send_Control_Record(BUS_Public->port, BUS_Public->baud, data, 10);	//日志记录
}
