/********************************** (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 #include #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 **********************************/