/********************************** (C) COPYRIGHT ******************************
* File Name          : MQTT_Sub.c
* Author             : WCH
* Version            : V1.0
* Date               : 2018/12/01
* Description        : 基于TCP/IP的MQTT协议通讯例程，实现以MQTT方式，通过百度、阿里云物联网服务器实现设备互通；使用前需设置帐号和密码
*					(1)、CH579 Examples by KEIL;
*					(2)、串口0输出监控信息,115200bps,打开或者关闭调试信息打印输出在IDE宏定义中设置;
*					(3)、本程序用于演示基于TCP/IP的MQTT协议通讯，
					     此程序演示SUB的过程
* log  202204211400    打印MQTT发起连接数据  发起订阅数据   连接回复   订阅回复		
*      202204231151    MQTT发送的数据，存储到日志
*******************************************************************************/



/******************************************************************************/
/* 头文件包含*/
#include <stdio.h>
#include <string.h>
#include "net.h"
#include "aLiYun.h"
#include "mqtt.h"
#include "SPI_SRAM.h"
#include "DBG.h"
#include "PC_DeviceTest_Fun.h"
#include "flash.h"
#include "rtc.h"

#include "includes.h"

#define KEEPLIVE_ENABLE                      1                                  /* 开启KEEPLIVE功能 */


/* 本演示程序的相关宏 */
#define RECE_BUF_LEN                          536                               /* 接收缓冲区的大小 */
/* CH57xNET库TCP的MSS长度为536字节，即一个TCP包里的数据部分最长为536字节 */
/* TCP协议栈采用滑动窗口进行流控，窗口最大值为socket的接收缓冲区长度。在设定 */
/* RX_QUEUE_ENTRIES时要考虑MSS和窗口之间的关系，例如窗口值为4*MSS，则远端一次会发送 */
/* 4个TCP包，如果RX_QUEUE_ENTRIES小于4，则必然会导致数据包丢失，从而导致通讯效率降低 */
/* 建议RX_QUEUE_ENTRIES要大于( 窗口/MSS ),如果多个socket同时进行大批量发送数据，则 */ 
/* 建议RX_QUEUE_ENTRIES要大于(( 窗口/MSS )*socket个数) 在多个socket同时进行大批数据收发时 */
/* 为了节约RAM，请将接收缓冲区的长度设置为MSS */
#if MQTT_EN
#define MQTT_NORMALDATA_UP_FLAG        0x01       
#endif
UINT16 aport=1000;											                   /* CH579源端口 */

#if MQTT_EN

/*本地函数申明开始*/
uint8_t MQTT_NoramlData_Up(void);
uint8_t MQTT_WxLock_Ctrl(uint8_t *buf);
void MQTT_Dev_Ctrl(uint8_t *buf);
void TimeSetUseStamp(uint32_t TimeStamp);

/*本地函数申明结束*/

MQTT_INFO mqtt_info = {
	.init_flag = 0,                 /*开启初始化标记*/
	.con_flag = 0,                 /* 已连接MQTT服务器标志位 */
	.pub_flag = 1,									/* 已发布会话消息标志位 */
	.sub_flag = 0,									/* 已订阅会话标志位 */
	.tout_flag = 0,									/* 超时标志位 */
	.domain_dns = 0,                //mqtt域名解析标志
	.reconnect = 3,                 //失败重连次数
	.keepAliveInterval = 60,        //保持在线时间
	.packetid = 0,									/* 包ID */
	.username = /*USER_NAME*/NULL,          /* 设备名，每个设备唯一，可用”/“做分级 */
	.password = /*PASSWORD*/NULL,						/* 服务器登陆密码 */
	.sub_topic = /*SUB_TOPIC*/NULL,					/* 订阅的会话名， */
	.pub_topic = /*PUB_TOPIC*/NULL,					/* 发布的会话*/
	.mqtt_socket = 0,               //存放mqtt 套接字
	.MyBuf = {0},
	.Sram_write_addr = SRAM_MQTT_RECEIVE_START,    //
	.Sram_read_addr = SRAM_MQTT_RECEIVE_START,    //
};


#endif

#if MQTT_EN

/*******************************************************************************
* Function Name	: Transport_Open
* Description	: 创建TCP连接
* Input			: UINT8* dis_ip：目的ip, 
							
							UINT32 sour_port：源端口
* Output		: None
* Return		: 创建的套接字索引
*******************************************************************************/
UINT8 Transport_Open(MQTT_INFO* Mqtt_info, UINT8* des_ip, UINT32 sour_port)
{
	UINT8 i,s;																														 
	SOCK_INF TmpSocketInf;									                            /* 创建临时socket变量 */
	if(Mqtt_info == NULL)   return 0xFF;
	memset((void *)&TmpSocketInf,0,sizeof(SOCK_INF));		                            /* 库内部会将此变量复制，所以最好将临时变量先全部清零 */
	memcpy((void *)TmpSocketInf.IPAddr, des_ip, 4);		                             	/* 设置目的IP地址 */
	TmpSocketInf.DesPort = 1883;							                            /* 设置目的端口 */
	TmpSocketInf.SourPort = /*aport++*/sour_port;					                              	/* 设置源端口 */
	TmpSocketInf.ProtoType = PROTO_TYPE_TCP;			                             	/* 设置socekt类型 */
	TmpSocketInf.RecvStartPoint = (UINT32)/*SocketRecvBuf*/&Mqtt_info->MyBuf[0];                               	/* 设置接收缓冲区的接收缓冲区 */
	TmpSocketInf.RecvBufLen = RECE_BUF_LEN ;				                            /* 设置接收缓冲区的接收长度 */
	i = CH57xNET_SocketCreat(&s, &TmpSocketInf);	                             	/* 创建socket，将返回的socket索引保存在SocketId中 */
	mStopIfError(i);									                               	/* 检查错误 */
	
	i = CH57xNET_SocketConnect(s);					                            /* TCP连接 */
	mStopIfError(i);									                               	/* 检查错误 */
	return s;
}


/*******************************************************************************
* Function Name	: Transport_Close
* Description	: 关闭TCP连接
* Input			: UINT8 S：要关闭的TCP套接字
* Output		: None
* Return		: 错误码
*******************************************************************************/
UINT8 Transport_Close(UINT8 S)
{
	UINT8 i;
	i=CH57xNET_SocketClose(S,	TCP_CLOSE_NORMAL);
	mStopIfError(i);
	return i;
}


/*******************************************************************************
* Function Name	: Transport_SendPacket
* Description	: 以太网发送数据
* Input			: UINT8 S：套接字
							UINT8 *buf 发送数据的首字节地址
							UINT32 len 发送数据的长度
* Output		: None
* Return		: None
*******************************************************************************/
void Transport_SendPacket(UINT8 S, UINT8 *buf, UINT32 len)
{
	UINT32 totallen;
	UINT8 *p=buf;
	UINT8 ReNum=0;  //剩余数据重发次数  2022-07-07
	totallen=len;
	while(1)
	{
		len = totallen;
		CH57xNET_SocketSend(S, p, &len);				                         	/* 将MyBuf中的数据发送 */
		totallen -= len;					 				                          	/* 将总长度减去以及发送完毕的长度 */
		p += len;											                         	/* 将缓冲区指针偏移*/
		if(totallen)
		{
			Dbg_Print(DBG_BIT_NET_STATUS_bit,"剩余totallen：%d", totallen);
			ReNum++;
			if(ReNum>3){ break;}         //剩余数据重发次数超过3次跳出循环  2022-07-07
			continue;								                         	/* 如果数据未发送完毕，则继续发送*/
		}
		break;												                         	/* 发送完毕，退出 */
	}
}


/*******************************************************************************
* Function Name	: MQTT_Connect
* Description	: 创建MQTT连接
* Input			: UINT8 S：套接字
							char* clientID：clientID
							char *username 设备名
							char *password 服务器连接密码
							int keepAliveInterval :保持在线时间
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Connect(UINT8 S, char* clientID, char *username, char *password, int keepAliveInterval)
{
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
	if(clientID == NULL || username == NULL || password == NULL)
	{
		Dbg_Print(DBG_BIT_NET_STATUS_bit,"MQTT连接参数为空\r\n");
		return;
	}
	
	UINT32 len = strlen(clientID) + strlen(username) + strlen(password) + 25;
	UINT8* buf = malloc(len);
	if(buf == NULL)   return;
	
	//data.clientID.cstring = "11";
	data.clientID.cstring = clientID;
	data.keepAliveInterval = keepAliveInterval;
	data.cleansession = 1;
	data.username.cstring = username;																		
	data.password.cstring = password;
	 
	len=MQTTSerialize_connect(buf, len, &data);
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"发起连接长度：%d\r\n", len);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"Send Buff:",buf, len);  
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
	free(buf);
}


/*******************************************************************************
* Function Name	: MQTT_Subscribe
* Description	: MQTT订阅一个主题
* Input			: UINT8 S：套接字
							char *topic 订阅的主题名
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Subscribe(UINT8 S, char *topic)
{
	MQTTString topicString = MQTTString_initializer;
	if(topic == NULL)   return;
	
	UINT32 len = strlen(topic)+ 10;
	UINT8* buf = malloc(len);
	if(buf == NULL)   return;
	
	int req_qos=0;
	UINT32 msgid=1;
	
	topicString.cstring=topic;
	len=MQTTSerialize_subscribe(buf, len, 0, msgid, 1, &topicString, &req_qos);
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"发起订阅长度：%d\r\n SocketId:%d", len, S);
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
	free(buf);
}


/*******************************************************************************
* Function Name	: MQTT_Unsubscribe
* Description	: MQTT取消订阅一个主题
* Input			: UINT8 S：套接字
							char *topic 取消订阅的主题名
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Unsubscribe(UINT8 S, char *topic)
{
	MQTTString topicString = MQTTString_initializer;
	if(topic == NULL)   return;
	
	UINT32 len = strlen(topic)+ 20;
	UINT8* buf = malloc(len);
	if(buf == NULL)   return;
	UINT32 msgid=1;
	
	topicString.cstring=topic;
	len=MQTTSerialize_unsubscribe(buf, len, 0, msgid, 1, &topicString);
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"取消订阅长度：%d\r\n", len);
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
	free(buf);
}


/*******************************************************************************
* Function Name	: MQTT_Publish
* Description	: MQTT发布信息
* Input			: UINT8 S：套接字
							char *topic 发布的主题名
							int qos：消息等级
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Publish(UINT8 S, char *topic, UINT8 *payload, int payloadlen, int qos)
{
#if MQTT_EN


	MQTTString topicString = MQTTString_initializer;
	
	if(topic == NULL || payload == NULL)   return;
	
	UINT32 len = strlen(topic) + payloadlen + 10;
	UINT8* buf = malloc(len);
	if(buf == NULL)   return;
	
	topicString.cstring = topic; 
	len= MQTTSerialize_publish(buf, len, 0, qos, 0, mqtt_info.packetid++, topicString, payload, payloadlen);
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"发布消息长度：%d\r\n S:%d", len, S);
	Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"data :",buf,len);
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"发布数据结束\r\n");	
	free(buf);
#endif
}


/*******************************************************************************
* Function Name	: MQTT_Pingreq
* Description	: MQTT发送心跳包
* Input			: UINT8 S：套接字
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Pingreq(UINT8 S)
{
	UINT32 len;
	UINT8 buf[20];
	
	len=MQTTSerialize_pingreq(buf,sizeof(buf));
	Dbg_Print(DBG_BIT_NET_STATUS_bit,"心跳包长度：%d\r\n", len);
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
}


/*******************************************************************************
* Function Name	: MQTT_Disconnect
* Description	: 断开MQTT连接
* Input			: UINT8 S：套接字
* Output		: None
* Return		: None
*******************************************************************************/
void MQTT_Disconnect(UINT8 S)
{
	UINT32 len;
	UINT8 buf[50];
	len=MQTTSerialize_disconnect(buf,sizeof(buf));
	Transport_SendPacket(S, buf, len);
	LOG_NET_COMM_Send_Record(S,mqtt_info.des_ip,1883,&buf[0],len);
}


/*******************************************************************************
* Function Name  : MQTT_Init
* Description    : 初始化MQTT
* Input          : domain_name：域名，使用域名需要把ip填写NULL	(动态分配，函数有free的操作)
*                	 des_ip: MQTT服务器ip，此参数用于直接使用IP地址连接的情况
*									 clientID: clientID	(动态分配，函数有free的操作)
*									 username: 设备名	(动态分配，函数有free的操作)
*									 password：密码	(动态分配，函数有free的操作)
									 sublish: 订阅地址 (动态分配，函数有free的操作)
*									 keepAliveInterval：保持在线时间
* Output         : None
* Return         : 返回0表示参数配置成功
*******************************************************************************/
UINT8 MQTT_Init(MQTT_INFO* Mqtt_info, char* domain_name, UINT8* des_ip, char* clientID, char *username, char *password, char* sublish, int keepAliveInterval)
{
#if MQTT_EN
	if(Mqtt_info == NULL || clientID ==NULL || username == NULL || password == NULL  || sublish == NULL)  return 1; //参数错误
	
	if(des_ip == NULL)    //目的ip为空
	{
		if(domain_name == NULL)  return 1; //域名也为空  参数错误
//		if(server_info.net_sta != NET_COMPLETE)   return 2;     //网络繁忙
		Mqtt_info->dns_en = 1;                //DNS解析MQTT域名
//		server_info.dns_sta = DNS_INIT;
//		server_info.net_sta = NET_DNS;           //状态置为 NET_DNS
		
		if(Mqtt_info->domain_name)
		{
			free(Mqtt_info->domain_name);
		}
		
		Mqtt_info->domain_name = domain_name;
//		server_info.dns_domian_name = domain_name;
	}
	else
	{
		memcpy(&Mqtt_info->des_ip, des_ip, 4);
//		if(server_info.net_sta != NET_COMPLETE)   return 1;
//		server_info.net_sta = NET_MQTT_INIT;           //状态置为,NET_MQTT_INIT
	}
	
	if(Mqtt_info->clientID)
	{
		free(Mqtt_info->clientID);
		
	}
	if(Mqtt_info->username)
	{
		free(Mqtt_info->username);
		
	}
	if(Mqtt_info->password)
	{
		free(Mqtt_info->password);
		
	}
	
	if(Mqtt_info->sub_topic)
	{
		free(Mqtt_info->sub_topic);
		
	}
	
	Mqtt_info->clientID    = clientID;
	Mqtt_info->username    = username;
	Mqtt_info->password    = password;
	Mqtt_info->sub_topic    = sublish;
	Mqtt_info->keepAliveInterval = keepAliveInterval;
	Mqtt_info->init_flag = 1;
	Mqtt_info->reconnect = 3;
	
#endif
	return 0;
}

/*******************************************************************************
* Function Name  : MQTT_SET_SUB_Topic
* Description    : 初始化MQTT_订阅参数
* Input          : topic：订阅参数
* Output         : None
* Return         : None
*******************************************************************************/
void MQTT_SET_SUB_Topic(MQTT_INFO* Mqtt_info, char* topic)
{
	if(topic != NULL)
	{
		Mqtt_info->sub_topic = topic;
	}
}

/*******************************************************************************
* Function Name  : MQTT_SET_PUB_Topic
* Description    : 初始化MQTT_订阅参数
* Input          : topic：订阅参数
* Output         : None
* Return         : None
*******************************************************************************/
void MQTT_SET_PUB_Topic(MQTT_INFO* Mqtt_info, char* topic)
{
	if(topic != NULL)
	{
		Mqtt_info->pub_topic = topic;
	}
}

/*******************************************************************************
* Function Name  : MQTT_Flash_Parameter_Init
* Description    : 从flash获取参数初始化mqtt
* Input          : topic：订阅参数
* Output         : None
* Return         : None
*******************************************************************************/
UINT8 MQTT_Flash_Parameter_Init(MQTT_INFO* Mqtt_info)
{
	if(Mqtt_info == NULL)  return 1;
	
	/*分配内存*/
	MQTT_DATA mqtt_data;
	
	mqtt_data.mqtt_basic_info = malloc(sizeof(MQTT_BASIC_INFO));
	if(mqtt_data.mqtt_basic_info == NULL)
	{
		return 2;
	}
	
	UINT8 ret = 0; 
	UINT16 keepAlive = 0;
	char* domain_name = NULL; 
	char* clientID = NULL; 		
	char* userName = NULL; 		
	char* passWord = NULL;   
	char* sublish = NULL; 
	char* publish = NULL; 
	
	Flash_Read((UINT8*)&mqtt_data ,sizeof(MQTT_DATA)-4, FLASH_MCU_MQTT_START_ADDRESS + sizeof(ALIYUN_INFO) -4-2);
	Flash_Read((UINT8*)mqtt_data.mqtt_basic_info ,sizeof(MQTT_BASIC_INFO), FLASH_MCU_MQTT_START_ADDRESS + sizeof(ALIYUN_INFO)-4);
	
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"keepAliveInterval:%d", mqtt_data.keepAliveInterval);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"sublish:%s", mqtt_data.mqtt_basic_info->mqtt_theme.sublish);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"publish:%s", mqtt_data.mqtt_basic_info->mqtt_theme.publish);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"domain_name:%s", mqtt_data.mqtt_basic_info->domain_name);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"clientID:%s", mqtt_data.mqtt_basic_info->clientID);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"username:%s", mqtt_data.mqtt_basic_info->username);
	Dbg_Println(DBG_BIT_Debug_STATUS_bit,"password:%s", mqtt_data.mqtt_basic_info->password);
	
	if(mqtt_data.keepAliveInterval < 0xFFFF)
	{
		keepAlive = mqtt_data.keepAliveInterval;
	}
	else     //参数不合法，使用默认值
	{
		keepAlive = 120;
	}
	
	if(mqtt_data.mqtt_basic_info->mqtt_theme.sublish[0] != 0xFF && mqtt_data.mqtt_basic_info->mqtt_theme.sublish[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->mqtt_theme.sublish)+1;
		sublish = malloc(len);
		if(sublish == NULL)
		{
			ret = 2;
			goto reault;
		}
		memset(sublish, 0, len);
		strcpy(sublish, (char*)mqtt_data.mqtt_basic_info->mqtt_theme.sublish);
	}
	else     //参数不合法，返回
	{
		ret = 3;
		
		goto reault;
	}
	
	if(mqtt_data.mqtt_basic_info->domain_name[0] != 0xFF && mqtt_data.mqtt_basic_info->domain_name[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->domain_name)+1;
		domain_name = malloc(len);
		if(domain_name == NULL)
		{
			ret = 2;
			goto reault;
		}
		memset(domain_name, 0, len);
		strcpy(domain_name, (char*)mqtt_data.mqtt_basic_info->domain_name);
		
	}
	else     //参数不合法，返回
	{
		ret = 3;
		
		goto reault;
	}
	
	if(mqtt_data.mqtt_basic_info->clientID[0] != 0xFF && mqtt_data.mqtt_basic_info->clientID[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->clientID)+1;
		clientID = malloc(len);
		if(clientID == NULL)
		{
			ret = 2;
			goto reault;
		}
		memset(clientID, 0, len);
		strcpy(clientID, (char*)mqtt_data.mqtt_basic_info->clientID);
	}
	else     //参数不合法，返回
	{
		ret = 3;
		
		goto reault;
	}
	
	if(mqtt_data.mqtt_basic_info->username[0] != 0xFF && mqtt_data.mqtt_basic_info->username[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->username)+1;
		userName = malloc(len);
		if(userName == NULL)
		{
			ret = 2;
			goto reault;
		}
		memset(userName, 0, len);
		strcpy(userName, (char*)mqtt_data.mqtt_basic_info->username);
	}
	else     //参数不合法，返回
	{
		ret = 3;
		
		goto reault;
	}
	
	if(mqtt_data.mqtt_basic_info->password[0] != 0xFF && mqtt_data.mqtt_basic_info->password[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->password)+1;
		passWord = malloc(len);
		if(passWord == NULL)
		{
			ret = 2;
			goto reault;
		}
		memset(passWord, 0, len);
		strcpy(passWord, (char*)mqtt_data.mqtt_basic_info->password);
	}
	else     //参数不合法，返回
	{
		ret = 3;
		goto reault;
	}
	
	if(mqtt_data.mqtt_basic_info->mqtt_theme.publish[0] != 0xFF && mqtt_data.mqtt_basic_info->mqtt_theme.publish[0] != 0x00)
	{
		UINT8 len = strlen((char*)mqtt_data.mqtt_basic_info->mqtt_theme.publish)+1;
		publish = malloc(len);
		if(publish == NULL)
		{
			ret = 4;
			goto reault;
		}
		memset(publish, 0, len);
		strcpy(publish, (char*)mqtt_data.mqtt_basic_info->mqtt_theme.publish);
		
		if(Mqtt_info->pub_topic)
		{
			free(Mqtt_info->pub_topic);
		}
		Mqtt_info->pub_topic = publish;
	}
	
	reault:
		switch(ret)
		{
			case 0:     //无错误
			case 4:     //publish错误不影响初始化
				free(mqtt_data.mqtt_basic_info);    //释放内存
				return MQTT_Init(Mqtt_info, domain_name, NULL, clientID, userName, passWord, sublish, keepAlive);   //初始化MQTT
			
			default:    //有错误
				Dbg_Println(DBG_BIT_Debug_STATUS_bit,"MQTT_Flash_Parameter err");
				free(mqtt_data.mqtt_basic_info);
				if(domain_name)   free(domain_name);
				if(clientID)   free(clientID);
				if(userName)   free(userName);
				if(passWord)   free(passWord);
				if(sublish)   free(sublish);
				if(publish)   free(publish);
				return ret;
			
		}
}



/*------------------------------------------------------------*/
/*                   MQTT上报命令                              */
/*------------------------------------------------------------*/

void MQTT_CMD_A5(UINT8 S, char* topic, UINT8 cmdhead, UINT8* cmdID, UINT8 result)   //形参为命令头和执行结果
{
	#if MQTT_EN
	uint32_t timetemp;	
	UINT8 Cmd_buff[19] = {0}; 

	timetemp = RTC_Conversion_To_Unix(&RTC_Raw_Data);   

  Cmd_buff[0] = 0xA5;    //固定A5命令
  Cmd_buff[1] = cmdhead;
  memcpy(&Cmd_buff[2],cmdID,CmdID_LEN);         //加命令
  memcpy(&Cmd_buff[2+CmdID_LEN], MACAddr, DeviceID_LEN); //加设备MAC地址
	HtolCpy((&Cmd_buff[2+CmdID_LEN+DeviceID_LEN]), timetemp);

  Cmd_buff[17] = result;
	MQTT_Publish(S, topic, Cmd_buff, 19, 0);
	#endif
}


#if MQTT_NORMALDATA_UP_FLAG

/**
  * @name  			门锁透传数据上报
  * @param      无
  * @retval     1，有门锁透传数据上报   0，无门锁透传数据上报
  * @attention  找到福瑞狗的蓝牙锁，判断蓝牙锁的全局变量是否置透传标志位，请求开锁标志位
  */
uint8_t MQTT_CMD_A6(void)            //u8* cmdID, u8 * DeviceID,u8* UTCTime
{	
	uint8_t Ret = 0x00;
#if	MQTT_EN
	uint32_t timetemp = RTC_Conversion_To_Unix(&RTC_Raw_Data);  //TIMESTAMP
	Device_Public_Information_G BUS_Public;		
  RS485_WxLock_INFO  Rs485WxLockInfo;
  uint8_t Cmd_buff[200];   
	uint8_t KeepFlag = 0x00;
	uint32_t dev_addr;
	
	if(NULL == DevActionGlobal.DevLockAddr)   //HostRunInfo.CfgDevAddWxLock
	{
		return Ret;            //
	}
	dev_addr = DevActionGlobal.DevLockAddr;
//	Rs485WxLockInfo = HostRunInfo.CfgDevAddWxLock->DevDataStruct;
	SRAM_DMA_Read_Buff((uint8_t *)&BUS_Public,sizeof(Device_Public_Information_G),dev_addr);			
	SRAM_DMA_Read_Buff((uint8_t *)&Rs485WxLockInfo,sizeof(RS485_WxLock_INFO),dev_addr+Dev_Privately);
	


	if(0x01 == Rs485WxLockInfo.WeixinUpSendFlag)  //透传标志
	{
		Rs485WxLockInfo.WeixinUpSendFlag = 0x00;
		KeepFlag = 0x01;
		
		Cmd_buff[1+DeviceID_LEN+UTCTime_LEN] = Rs485WxLockInfo.WeixinUpMessageLen;//
		memcpy(&Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+0x01], Rs485WxLockInfo.WeixinUpMessage, Rs485WxLockInfo.WeixinUpMessageLen);
		Ret = 0x01;
		Cmd_buff[0] = 0xA6;		
//		MacAddrCpy(&Cmd_buff[1]);                                //拷贝设备ID，即mac地址 6个字节
		memcpy(&Cmd_buff[1], MACAddr, DeviceID_LEN); //加设备MAC地址
		
		HtolCpy((&Cmd_buff[1+DeviceID_LEN]), timetemp);
		MQTT_Publish(mqtt_info.mqtt_socket, mqtt_info.pub_topic, Cmd_buff, 1+Rs485WxLockInfo.WeixinUpMessageLen+1+DeviceID_LEN+UTCTime_LEN, 0);
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"发送A6 透传发送命令\r\n");	
		Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"A6 透传 Send Buff:",Cmd_buff,1+Rs485WxLockInfo.WeixinUpMessageLen+1+DeviceID_LEN+UTCTime_LEN);

//		MQTT_PublishQs0(PTopicName,(char *)Cmd_buff ,1+Rs485WxLockInfo->WeixinUpMessageLen+1+DeviceID_LEN+UTCTime_LEN);
	}
	else if(0x01 == Rs485WxLockInfo.WeixinAskLockFlag)
	{
		Rs485WxLockInfo.WeixinAskLockFlag = 0x00;
		KeepFlag = 0x01;
		Cmd_buff[0] = 0xAA;
		Ret = 0x01;
		memcpy(&Cmd_buff[1], MACAddr, DeviceID_LEN); //加设备MAC地址		
//		MacAddrCpy(&Cmd_buff[1]);                                //拷贝设备ID，即mac地址 6个字节
		HtolCpy((&Cmd_buff[1+DeviceID_LEN]), timetemp);
		Cmd_buff[1+DeviceID_LEN+UTCTime_LEN] = 0x01;   //请求开锁
		MQTT_Publish(mqtt_info.mqtt_socket, mqtt_info.pub_topic, Cmd_buff, 0x01+1+DeviceID_LEN+UTCTime_LEN, 0);
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"发送AA请求开锁命令\r\n");	
		Dbg_Print_Buff(DBG_BIT_NET_STATUS_bit,"AA 开锁Send Buff:",Cmd_buff,0x01+1+DeviceID_LEN+UTCTime_LEN);

//		MQTT_PublishQs0(PTopicName,(char *)Cmd_buff ,0x01+1+DeviceID_LEN+UTCTime_LEN);
	}
	if(0x01 == KeepFlag)
	{
		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);
		
	}
#endif	
	return Ret;
}
#endif

//#define MqttDevNumMax       50              //设备数量上限
#define Cmd_Buff_LEN        (CFG_Dev_Freego_Map_MAX*24+20)
/*上报设备列表*/
void MQTT_CMD_A7(UINT8 S, char* topic)              //上报设备启用(uint8_t *)
{	
#if MQTT_EN

	uint16_t len = 0;
	uint32_t timetemp;
	UINT8 Cmd_buff[Cmd_Buff_LEN];
	timetemp = RTC_Conversion_To_Unix(&RTC_Raw_Data); //+ -8*3600
	
	memset(Cmd_buff, 0x00, Cmd_Buff_LEN);      //清0
	len = MQTT_DevList_Get(&Cmd_buff[1+DeviceID_LEN+UTCTime_LEN]);   //分配内存并读取设备列表
	if(len == 0)   return;
	Cmd_buff[0] = 0xA7;
	memcpy(&Cmd_buff[1], MACAddr, DeviceID_LEN);  
	HtolCpy((&Cmd_buff[1+DeviceID_LEN]), timetemp);
	
	MQTT_Publish(S, topic, Cmd_buff, len+1+DeviceID_LEN+UTCTime_LEN, 0);
//	free(Cmd_buff);
  Dbg_Println(DBG_BIT_NET_STATUS_bit,"发送A7数据");
	
//  memset(test_buff,0,sizeof(test_buff));
//	HexToStr(test_buff,Cmd_buff,len+1+DeviceID_LEN+UTCTime_LEN);
//	printf("%s\n",(char *)Cmd_buff);
//	printf("\r\n发送A7结束\r\n ");
#endif
}

/**
  * @name  			MQTT核心设备状态得到
  * @param  
  *    p       数组
  * @retval     核心设备的个数
  * @attention  遍历所有的设备，将需要上报的设备填入
  */
uint16_t MQTT_DevCoreStateGet(uint8_t *p)
{
	
	return 0x00; 
}
/**
  * @name  			MQTT核心设备状态定期上报
  * @param  
  *    buf      上报数据用到的数组，每次只上报一个信息，如果有多个信息，就上报多条消息指令
  * @retval     数组填充数据长度  非0，有设备状态变化     0，无设备状态变化
  * @attention  内容固定 (FreegoDevStateLen*DevSum+1)个字节   不包括 消息ID（4B）设备ID（6B）和UTC时间（4B）
  *   消息个数        消息详情               
  *     [0]       [1][2][3][4][5][6]           
  */
uint16_t MQTT_CoreDev_Up(uint8_t *buf)
{
//	Service_INFOP ServiceInfo;
//	uint8_t i;                      //用于遍历所有的服务信息
	uint16_t Ret = 0x00;
	uint16_t DevSum = 0x00;
	{
		DevSum = MQTT_DevCoreStateGet(&buf[1]);  //设备个数已经被限制
	}
	buf[0] = DevSum;
	if(0x00 != DevSum)      //
	{
		Ret = DevSum*0x06+0x01;    //固定
	}
	
	return Ret;
}
/*MQTT核心数据上报,数据结构跟A8上报指令完全一样*/
uint8_t MQTT_CoreData_Up(void)
{  
	#if MQTT_EN

	uint32_t timetemp;        //指令时间
//	uint16_t MqttDevContLen;
	uint8_t Cmd_buff[50];            //
	static uint32_t CoreDataUpTick;
	
	if( SysTick_1ms - CoreDataUpTick > 60*1000)		//1分钟执行一次
	{
		CoreDataUpTick = SysTick_1ms;
	}
	else
	{
		return 0x00;
	}
//	MqttDevContLen = MQTT_CoreDev_Up(&Cmd_buff[1+DeviceID_LEN+UTCTime_LEN]);//MQTT_Dev_Up(&Cmd_buff[1+DeviceID_LEN+UTCTime_LEN]);
//	if(0x00 == MqttDevContLen)
//	{
//		return 0x00;         //没有核心设备存在直接返回
//	}
	timetemp = RTC_Conversion_To_Unix(&RTC_Raw_Data) ;  // TIMESTAMP;  
	


	
	Cmd_buff[0] = 0xA8;    //固定A8命令
//  Cmd_buff[1] = cmdhead;
//  memcpy(&Cmd_buff[2],cmdID,CmdID_LEN);         //加命令
  memcpy(&Cmd_buff[1], MACAddr, DeviceID_LEN); //加设备MAC地址
	HtolCpy((&Cmd_buff[1+DeviceID_LEN]), timetemp);
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN] = 0x01;   //上报1个设备
	
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+1] = 0x04;   //服务信息
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+2] = 0x00;
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+3] = 0x00;     //取电服务信息回路地址
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+4] = 0x00;     
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+5] = DevActionGlobal.DevActionU64Cond.EleState;     //状态
	Cmd_buff[1+DeviceID_LEN+UTCTime_LEN+6] = 0x00;
	
	MQTT_Publish(mqtt_info.mqtt_socket, mqtt_info.pub_topic, Cmd_buff, 20, 0);
	
	Dbg_Println(DBG_BIT_NET_STATUS_bit,"发送A8定期数据开始\r\n");	
//  memset(test_buff,0,sizeof(test_buff));
//	HexToStr(test_buff,Cmd_buff,MqttDevContLen+1+DeviceID_LEN+UTCTime_LEN);

	Dbg_Println(DBG_BIT_NET_STATUS_bit,"发送A8定期结束\r\n");
#endif
	return 0x01;
}
/**
  * @name  			MQTT设备控制，非空调类  
  * @param  
  *    buf      一次传7个字节过来
  * @retval     无
  * @attention   共3类   1，场景，窗帘，窗纱，不调光灯带，不调光射灯，排气扇。2，调光射灯。3，调光灯带
  *   设备分类  设备地址编码   开关控制   亮度控制    颜色控制
  *      [0]        [1]          [2]         [3]      [4][5][6]
  */
void MQTT_Dev_Ctrl(uint8_t *buf)
{
//	CFG_Freego_Map_AddP   CfgMapAdd;
//	uint8_t DevCtrl[6];	
	uint8_t i;                  //灯带控制的3路遍历
	
			
	for(i = 0; i < buf[0]; i++)
	{		
		switch(buf[1])
		{
			case Dev_Host_Invalid:  //场景
				break;
			default:           //其他设备，只要回路不为0，就减1
				if(0x00 != buf[3])  //回路不为0
				{
					buf[3]--;
				}
				break;
		}
		DevActionCtrl(&buf[1], 6);
	}
}

/*用时间戳进行时间设置*/
void TimeSetUseStamp(uint32_t TimeStamp)
{
//	uint32_t temp_unix;
	
	S_RTC write_rtc;
	memset(&write_rtc,0,sizeof(write_rtc));
	Unix_Conversion_To_RTC(&write_rtc,TimeStamp);
	RTC_WriteDate(write_rtc);
	DevActionGlobal.TimeGetFlag++;

	SRAM_Write_DW(TimeStamp,SRAM_Register_Start_ADDRESS + Register_CurrentUsageTime_OFFSET);
//	Retain_Flash_Register_Data();	
}
/*******************************************************************************
* Function Name  : FRG_Data_Processing
* Description    : 福瑞狗MQTT数据接收处理
* Input          : S: 套接字
									 topic：回复时的发布地址
									 data：接收数据
									 datalen：数据长度
									 qos: 消息发布等级
* Output         : None
* Return         : None
*******************************************************************************/
void FREEG_Data_Processing(UINT8 S, char* topic, UINT8* data, uint16_t datalen, int qos)
{
#if MQTT_EN
//	UINT8 crc168_val = 0; //用于保存CRC_168校验的值
	if(topic == NULL)  return;
	if((data[datalen-1] == CRC_168(data, datalen-1)) || (0xA4 == data[CMD_PKT]))
	{
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT_Revice_crc success");
		if(memcmp(MACAddr, &data[DEVICE_ID_PKT], 6) == 0)  //设备ID一致
		{
			switch(data[CMD_PKT])
			{
				case 0xA0:     //时间同步
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT_Time_Update");
					{
						uint32_t seccount=0;
						uint8_t DecUTCTime[4];   //下发的utc时间
						memcpy(DecUTCTime, &data[1+CmdID_LEN+DeviceID_LEN], 4);  
						seccount = (DecUTCTime[0]<<24) + (DecUTCTime[1]<<16) + (DecUTCTime[2]<<8) + DecUTCTime[3];
//						seccount += TIME_MISS;

						TimeSetUseStamp(seccount);  //用时间戳设置计数寄存器，并更新时间 	
					}
					MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_SUCCESS); //指令执行成功
				
				break;
				case 0xA1:   //平台配置设备工作参数等
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT_Config");
	
					switch(data[PRAM_PKT])
					{
						case 0x01:
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"授权可通电\r\n");
							break;
						case 0x02:
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"授权不可通电\r\n");
							break;
						case 0x03:
						{
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"远程立即开电\r\n");
//								MQTT_Ele_Ctrl_Open();
//							UINT8 control[6] = {0};
//							control[0] = 0x04;
//							control[1] = 0x00;
//							control[2] = LOOPCH01;
//							control[3] = 0x00;
//							control[4] = 0x01;
//							control[5] = 0x00;
//							DevActionCtrl(control, 6);			//取电 开
							Ele_Ctrl_OpenClose(0x01);//取电 开
						}
							break;
						case 0x04: 
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"远程立即断电\r\n");
//							SRAM_Write_Byte(0x02,SRAM_Service_Take_Electricity_State);			//取电 关
//							UINT8 control[6] = {0};
//							control[0] = 0x04;
//							control[1] = 0x00;
//							control[2] = LOOPCH01;
//							control[3] = 0x00;
//							control[4] = 0x02;
//							control[5] = 0x00;
//							DevActionCtrl(control, 6);			
							Ele_Ctrl_OpenClose(0x02);//取电 关
//							Dbg_Println(DBG_BIT_NET_STATUS_bit,"远程立即断电:%d", DevAddrCtr(NULL, control, 6));			//取电 关
							break;
						case 0x05:        //清除设备缓存
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"清除设备缓存\r\n ");
							break;
						case 0x06:     //请求设备地址列表
							Dbg_Println(DBG_BIT_NET_STATUS_bit,"准备发送A7命令\r\n ");
							MQTT_CMD_A7(S, topic);
							return;
						case 0x07:  //请求上报控指令定义
							
							break;
					}
					MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_SUCCESS); //指令执行成功
				break;
				case 0xA3:    //RCU设备控制
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT_Device_Control");
					MQTT_Dev_Ctrl(&data[1+CmdID_LEN+DeviceID_LEN+UTCTime_LEN]);
					MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_SUCCESS); //指令执行成功
				break;
				case 0xA4:    //门锁透传控制
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT Door Lock transport");
					{
						uint8_t WxLockSendLen;
						WxLockSendLen = datalen - (1+CmdID_LEN+DeviceID_LEN+UTCTime_LEN)-0x01;
//														if(WxLockSendLen == Server_Datahex[1+CmdID_LEN+DeviceID_LEN+UTCTime_LEN])  //内容长度判断
						{
							data[1+CmdID_LEN+DeviceID_LEN+UTCTime_LEN] = WxLockSendLen;
							MQTT_WxLock_Ctrl(&data[1+CmdID_LEN+DeviceID_LEN+UTCTime_LEN]);//门锁赋值
						}
						
					 MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_SUCCESS); //指令执行成功

					}//
					break;
				default:
					Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT cmd err");
					MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_HEAD_ERROR); //指令错误
				break;
			}
		}
		else
		{
//			MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_DEC_ERROR);
			Dbg_Println(DBG_BIT_NET_STATUS_bit,"DeviceID err");
		}
	}
	else
	{
//		MQTT_CMD_A5(S, topic, data[CMD_PKT], &data[CMDID_PKT], CMD_CRC_ERROR);
		Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT crc ERR：%X CRC_168:%X", data[datalen-1], CRC_168(data, datalen-1));
	}
	
#endif	
}
/**
  * @name  			MQTT微信锁透传控制  
  * @param  
  *    buf      一次传4个字节过来
  * @retval     0x00 表示失败  0x01 表示成功
  * @attention   空调的没有单独的开机，发关机即关机，发其他模式即开机
  *   消息长度      消息内容
  *      [0]          N     
  */
uint8_t MQTT_WxLock_Ctrl(uint8_t *buf)
{
	uint8_t Ret = 0x00;
#if MQTT_EN
	Device_Public_Information_G BUS_Public;	
	RS485_WxLock_INFO  Rs485WxLockInfo;
	uint32_t dev_addr;

	
	if(buf[0] > WXLOCKDOWNMESSAGELEN)  //超过长度直接返回
	{
		return Ret;
	}
	if(NULL == DevActionGlobal.DevLockAddr)//定位蓝牙主机模块
	{
		return Ret;
	}
	Ret = 0x01;
	dev_addr = DevActionGlobal.DevLockAddr;
//	Rs485WxLockInfo = HostRunInfo.CfgDevAddWxLock->DevDataStruct;
	SRAM_DMA_Read_Buff((uint8_t *)&BUS_Public,sizeof(Device_Public_Information_G),dev_addr);			
	SRAM_DMA_Read_Buff((uint8_t *)&Rs485WxLockInfo,sizeof(RS485_WxLock_INFO),dev_addr+Dev_Privately);
	
	Rs485WxLockInfo.WeixinDownSendFlag = 0x01;    //下发标志置位	
	Rs485WxLockInfo.WeixinDownSendCnt = WxLockCtrlSendMax;
	Rs485WxLockInfo.WeixinDownMessageLen = buf[0];
	memcpy(Rs485WxLockInfo.WeixinDownMessage, &buf[1], Rs485WxLockInfo.WeixinDownMessageLen);   //拷贝透传数据

	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);
			
#endif	
	return Ret ;
}
/*******************************************************************************
* Function Name  : MQTT_Receive_Processing
* Description    : MQTT数据接收处理
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void MQTT_Receive_Processing(void)
{
#if MQTT_EN
	if(0x01 != mqtt_info.con_flag)
	{
//		Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT Con Faild");
		return ;
	}
	if(0x01 != mqtt_info.sub_flag)
	{
//		Dbg_Println(DBG_BIT_NET_STATUS_bit,"MQTT Sub Faild");		
		return ;
	}
	MQTT_CoreData_Up();     //里面自带时间间隔
	MQTT_NoramlData_Up();   //每次都会扫描判断，是否有上报
	if(mqtt_info.Sram_read_addr != mqtt_info.Sram_write_addr)
	{
		int DataLen = SRAM_Read_Word(mqtt_info.Sram_read_addr);
		uint8_t* Data = malloc(DataLen);
		if(Data == NULL)   return;
		SRAM_Read_Buff(Data, DataLen, mqtt_info.Sram_read_addr +2);
		
//		MQTT_Publish(mqtt_info.mqtt_socket, mqtt_info.pub_topic, Data, DataLen, 0);
		FREEG_Data_Processing(mqtt_info.mqtt_socket, mqtt_info.pub_topic, Data, DataLen, 0);
		free(Data);
		
		mqtt_info.Sram_read_addr += SRAM_MQTT_RECEIVE_LEN;
		if(mqtt_info.Sram_read_addr >= SRAM_MQTT_RECEIVE_END)
		{
			mqtt_info.Sram_read_addr = SRAM_MQTT_RECEIVE_START;
		}
	}		
#endif
}
#endif

#if MQTT_NORMALDATA_UP_FLAG
/**
	* @name  MQTT普通数据及时上报
	* @para  无
	* @return 无
	* @brief 每次只上报一个状态
  * @attention  在主循环里调用，最好1ms调用一次 
	*/
uint8_t MQTT_NoramlData_Up(void)
{
	uint8_t Ret = 0x00;
	
//	if(0x01 == MQTT_CMD_A8())
//	{
//		Ret = 0x01;
//	}else 
	if(0x01 == MQTT_CMD_A6())
	{
		Ret = 0x01;
	}
//	else if(0x01 == MQTT_CMD_A9())
//	{
//		Ret = 0x01;
//	}
	return Ret;
}
#endif
/*********************************** endfile **********************************/
