2.程序结构
3.程序代码汇总
#include "main.h" void setup() { System_Init(); } void loop() { System_main(); }
#include "main.h" void AT_ClearPara(void) { int ch; String strTemp=""; while(1) { if(Serial2.available()) { ch=Serial2.read(); strTemp=strTemp+(char)ch; } else { break; } } Serial.print(strTemp); } unsigned char g_ArrTemp[1024]; int AT_SendCmd ( char * atCmd, char * res, int timeout ) { int tt=0; int i=0; int status=1; String strTemp; AT_ClearPara(); Serial2.print((char *)atCmd); Serial.print((char *)atCmd); while(1) { delay(1); tt++; if(tt>timeout && timeout!=0)break; if(Serial2.available()) { delay(20);// strTemp=""; while(1) { if(!Serial2.available())break; if(i<1024) { g_ArrTemp[i]= Serial2.read(); strTemp=strTemp+(char)g_ArrTemp[i]; i++; } } Serial.print(strTemp); if(strstr((char *)g_ArrTemp,res)!=NULL) { status=0; break; } } } AT_ClearPara(); return status; } int AT_SendData ( unsigned char *data, unsigned int len ) { char cmdBuf[100]; AT_ClearPara(); sprintf( cmdBuf,"AT+CIPSEND=%d\r\n",len); if (AT_SendCmd ( cmdBuf, ">", 400)==0) { delay ( 10 ); Serial2.write ( data, len ); return 0; } return 1; }
#ifndef _ATCOMMAND_H_ #define _ATCOMMAND_H_ void AT_ClearPara ( void ); int AT_SendCmd ( char *atCmd, char * res, int timeout ); int AT_SendData ( unsigned char *data, unsigned int len ); #endif
/** ************************************************************ ************************************************************ ************************************************************ * 文件名: MqttKit.c * * 作者: 张继瑞 * * 日期: 2018-04-27 * * 版本: V1.4 * * 说明: MQTT协议 * * 修改记录: V1.1:解决MQTT_PacketSubscribe订阅不为2个topic * 个数时协议错误的bug * V1.2:修复MQTT_PacketCmdResp的bug * V1.3:将strncpy替换为memcpy,解决潜在bug * V1.4:修复 MQTT_PacketPublishAck * MQTT_PacketPublishRel * 函数封包错误的bug * V1.5:增加 MQTT_UnPacketCmd * MQTT_UnPacketPublish * 接口对消息内容长度的提取参数 ************************************************************ ************************************************************ ************************************************************ **/ //协议头文件 #include "MqttKit.h" #include "string.h" #define CMD_TOPIC_PREFIX "$creq" //========================================================== // 函数名称: EDP_NewBuffer // // 函数功能: 申请内存 // // 入口参数: edpPacket:包结构体 // size:大小 // // 返回参数: 无 // // 说明: 1.可使用动态分配来分配内存 // 2.可使用局部或全局数组来指定内存 //========================================================== void MQTT_NewBuffer ( MQTT_PACKET_STRUCTURE *mqttPacket, uint32 size ) { uint32 i = 0; if ( mqttPacket->_data == NULL ) { mqttPacket->_memFlag = MEM_FLAG_ALLOC; mqttPacket->_data = ( uint8 * ) MQTT_MallocBuffer ( size ); if ( mqttPacket->_data != NULL ) { mqttPacket->_len = 0; mqttPacket->_size = size; for ( ; i < mqttPacket->_size; i++ ) { mqttPacket->_data[i] = 0; } } } else { mqttPacket->_memFlag = MEM_FLAG_STATIC; for ( ; i < mqttPacket->_size; i++ ) { mqttPacket->_data[i] = 0; } mqttPacket->_len = 0; if ( mqttPacket->_size < size ) { mqttPacket->_data = NULL; } } } //========================================================== // 函数名称: MQTT_DeleteBuffer // // 函数功能: 释放数据内存 // // 入口参数: edpPacket:包结构体 // // 返回参数: 无 // // 说明: //========================================================== void MQTT_DeleteBuffer ( MQTT_PACKET_STRUCTURE *mqttPacket ) { if ( mqttPacket->_memFlag == MEM_FLAG_ALLOC ) { MQTT_FreeBuffer ( mqttPacket->_data ); } mqttPacket->_data = NULL; mqttPacket->_len = 0; mqttPacket->_size = 0; mqttPacket->_memFlag = MEM_FLAG_NULL; } int32 MQTT_DumpLength ( size_t len, uint8 *buf ) { int32 i = 0; for ( i = 1; i <= 4; ++i ) { *buf = len % 128; len >>= 7; if ( len > 0 ) { *buf |= 128; ++buf; } else { return i; } } return -1; } int32 MQTT_ReadLength ( const uint8 *stream, int32 size, uint32 *len ) { int32 i; const uint8 *in = stream; uint32 multiplier = 1; *len = 0; for ( i = 0; i < size; ++i ) { *len += ( in[i] & 0x7f ) * multiplier; if ( ! ( in[i] & 0x80 ) ) { return i + 1; } multiplier <<= 7; if ( multiplier >= 2097152 ) //128 * *128 * *128 { return -2; // error, out of range } } return -1; // not complete } //========================================================== // 函数名称: MQTT_UnPacketRecv // // 函数功能: MQTT数据接收类型判断 // // 入口参数: dataPtr:接收的数据指针 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketRecv ( uint8 *dataPtr ) { uint8 status = 255; uint8 type = dataPtr[0] >> 4; //类型检查 if ( type < 1 || type > 14 ) { return status; } if ( type == MQTT_PKT_PUBLISH ) { uint8 *msgPtr; uint32 remain_len = 0; msgPtr = dataPtr + MQTT_ReadLength ( dataPtr + 1, 4, &remain_len ) + 1; if ( remain_len < 2 || dataPtr[0] & 0x01 ) //retain { return 255; } if ( remain_len < ( ( uint16 ) msgPtr[0] << 8 | msgPtr[1] ) + 2 ) { return 255; } if ( strstr ( ( int8 * ) msgPtr + 2, CMD_TOPIC_PREFIX ) != NULL ) //如果是命令下发 { status = MQTT_PKT_CMD; } else { status = MQTT_PKT_PUBLISH; } } else { status = type; } return status; } //========================================================== // 函数名称: MQTT_PacketConnect // // 函数功能: 连接消息组包 // // 入口参数: user:用户名:产品ID // password:密码:鉴权信息或apikey // devid:设备ID // cTime:连接保持时间, Keep Alive????? // clean_session:离线消息清除标志 // qos:重发标志 // will_topic:异常离线topic // will_msg:异常离线消息 // will_retain:消息推送标志 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketConnect ( const int8 *user, const int8 *password, const int8 *devid, uint16 cTime, uint1 clean_session, uint1 qos, const int8 *will_topic, const int8 *will_msg, int32 will_retain, MQTT_PACKET_STRUCTURE *mqttPacket ) { uint8 flags = 0; uint8 will_topic_len = 0; uint16 total_len = 15; int16 len = 0, devid_len = strlen ( devid ); if ( !devid ) { return 1; } total_len += devid_len + 2; //断线后,是否清理离线消息:1-清理 0-不清理-------------------------------------------- if ( clean_session ) { flags |= MQTT_CONNECT_CLEAN_SESSION; } //异常掉线情况下,服务器发布的topic------------------------------------------------------ if ( will_topic ) { flags |= MQTT_CONNECT_WILL_FLAG; will_topic_len = strlen ( will_topic ); total_len += 4 + will_topic_len + strlen ( will_msg ); } //qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数----------------------------- switch ( ( unsigned char ) qos ) { case MQTT_QOS_LEVEL0: flags |= MQTT_CONNECT_WILL_QOS0; //最多一次 break; case MQTT_QOS_LEVEL1: flags |= ( MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1 ); //最少一次 break; case MQTT_QOS_LEVEL2: flags |= ( MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2 ); //只有一次 break; default: return 2; } //主要用于PUBLISH(发布态)的消息,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它。如果不设那么推送至当前订阅的就释放了 if ( will_retain ) { flags |= ( MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN ); } //账号为空 密码为空--------------------------------------------------------------------- if ( !user || !password ) { return 3; } flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD; total_len += strlen ( user ) + strlen ( password ) + 4; //分配内存----------------------------------------------------------------------------- MQTT_NewBuffer ( mqttPacket, total_len ); if ( mqttPacket->_data == NULL ) { return 4; } memset ( mqttPacket->_data, 0, total_len ); /*************************************固定头部***********************************************/ //固定头部----------------------连接请求类型--------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT << 4; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength ( total_len - 5, mqttPacket->_data + mqttPacket->_len ); if ( len < 0 ) { MQTT_DeleteBuffer ( mqttPacket ); return 5; } else { mqttPacket->_len += len; } /*************************************可变头部***********************************************/ //可变头部----------------------协议名长度 和 协议名-------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; mqttPacket->_data[mqttPacket->_len++] = 4; mqttPacket->_data[mqttPacket->_len++] = 'M'; mqttPacket->_data[mqttPacket->_len++] = 'Q'; mqttPacket->_data[mqttPacket->_len++] = 'T'; mqttPacket->_data[mqttPacket->_len++] = 'T'; //可变头部----------------------protocol level 4----------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 4; //可变头部----------------------连接标志(该函数开头处理的数据)----------------------------- mqttPacket->_data[mqttPacket->_len++] = flags; //可变头部----------------------保持连接的时间(秒)---------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( cTime ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( cTime ); /*************************************消息体************************************************/ //消息体----------------------------devid长度、devid------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( devid_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( devid_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, devid, devid_len ); mqttPacket->_len += devid_len; //消息体----------------------------will_flag 和 will_msg--------------------------------- if ( flags & MQTT_CONNECT_WILL_FLAG ) { unsigned short mLen = 0; if ( !will_msg ) { will_msg = ""; } mLen = strlen ( will_topic ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( mLen ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( mLen ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, will_topic, mLen ); mqttPacket->_len += mLen; mLen = strlen ( will_msg ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( mLen ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( mLen ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, will_msg, mLen ); mqttPacket->_len += mLen; } //消息体----------------------------use--------------------------------------------------- if ( flags & MQTT_CONNECT_USER_NAME ) { unsigned short user_len = strlen ( user ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( user_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( user_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, user, user_len ); mqttPacket->_len += user_len; } //消息体----------------------------password---------------------------------------------- if ( flags & MQTT_CONNECT_PASSORD ) { unsigned short psw_len = strlen ( password ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( psw_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( psw_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, password, psw_len ); mqttPacket->_len += psw_len; } return 0; } //========================================================== // 函数名称: MQTT_PacketDisConnect // // 函数功能: 断开连接消息组包 // // 入口参数: mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketDisConnect ( MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 2 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_DISCONNECT << 4; //固定头部----------------------剩余长度值----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; return 0; } //========================================================== // 函数名称: MQTT_UnPacketConnectAck // // 函数功能: 连接消息解包 // // 入口参数: rev_data:接收的数据 // // 返回参数: 1、255-失败 其他-平台的返回码 // // 说明: //========================================================== uint8 MQTT_UnPacketConnectAck ( uint8 *rev_data ) { if ( rev_data[1] != 2 ) { return 1; } if ( rev_data[2] == 0 || rev_data[2] == 1 ) { return rev_data[3]; } else { return 255; } } //========================================================== // 函数名称: MQTT_UnPacketCmd // // 函数功能: 命令下发解包 // // 入口参数: rev_data:接收的数据指针 // cmdid:cmdid-uuid // req:命令 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketCmd ( uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len ) { int8 *dataPtr = strchr ( ( int8 * ) rev_data + 6, '/' ); //加6是跳过头信息 uint32 remain_len = 0; if ( dataPtr == NULL ) //未找到'/' { return 1; } dataPtr++; //跳过'/' MQTT_ReadLength ( rev_data + 1, 4, &remain_len ); //读取剩余字节 *cmdid = ( int8 * ) MQTT_MallocBuffer ( 37 ); //cmdid固定36字节,多分配一个结束符的位置 if ( *cmdid == NULL ) { return 2; } memset ( *cmdid, 0, 37 ); //全部清零 memcpy ( *cmdid, ( const int8 * ) dataPtr, 36 ); //复制cmdid dataPtr += 36; *req_len = remain_len - 44; //命令长度 = 剩余长度(remain_len) - 2 - 5($creq) - 1(\) - cmdid长度 *req = ( int8 * ) MQTT_MallocBuffer ( *req_len + 1 ); //分配命令长度+1 if ( *req == NULL ) { MQTT_FreeBuffer ( *cmdid ); return 3; } memset ( *req, 0, *req_len + 1 ); //清零 memcpy ( *req, ( const int8 * ) dataPtr, *req_len ); //复制命令 return 0; } //========================================================== // 函数名称: MQTT_PacketCmdResp // // 函数功能: 命令回复组包 // // 入口参数: cmdid:cmdid // req:命令 // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketCmdResp ( const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket ) { uint16 cmdid_len = strlen ( cmdid ); uint16 req_len = strlen ( req ); int status = 0; int8 *payload = (char *)MQTT_MallocBuffer ( cmdid_len + 6 ); if ( payload == NULL ) { return 1; } memset ( payload, 0, cmdid_len + 6 ); memcpy ( payload, "$crsp/", 6 ); strncat ( payload, cmdid, cmdid_len ); if ( MQTT_PacketPublish ( MQTT_PUBLISH_ID, payload, req, strlen ( req ), MQTT_QOS_LEVEL0, 0, 1, mqttPacket ) == 0 ) { status = 0; } else { status = 1; } MQTT_FreeBuffer ( payload ); return status; } //========================================================== // 函数名称: MQTT_PacketSubscribe // // 函数功能: Subscribe消息组包 // // 入口参数: pkt_id:pkt_id // qos:消息重发次数 // topics:订阅的消息 // topics_cnt:订阅的消息个数 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketSubscribe ( uint16 pkt_id, enum MqttQosLevel qos, const char *topic, MQTT_PACKET_STRUCTURE *mqttPacket ) { uint32 topic_len = 0, remain_len = 0; int16 len = 0; // uint8 i = 0; if ( pkt_id == 0 ) { return 1; } //计算topic长度------------------------------------------------------------------------- topic_len += strlen ( topic ); //2 bytes packet id + topic filter(2 bytes topic + topic length + 1 byte reserve)------ remain_len = 2 + 3 + topic_len; //分配内存------------------------------------------------------------------------------ MQTT_NewBuffer ( mqttPacket, remain_len + 5 ); if ( mqttPacket->_data == NULL ) { return 3; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_SUBSCRIBE << 4 | 0x02; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength ( remain_len, mqttPacket->_data + mqttPacket->_len ); if ( len < 0 ) { MQTT_DeleteBuffer ( mqttPacket ); return 4; } else { mqttPacket->_len += len; } /*************************************payload***********************************************/ //payload----------------------pkt_id--------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( pkt_id ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( pkt_id ); //payload----------------------topic_name----------------------------------------------- topic_len = strlen ( topic ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( topic_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( topic_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, topic, topic_len ); mqttPacket->_len += topic_len; mqttPacket->_data[mqttPacket->_len++] = qos & 0xFF; return 0; } //========================================================== // 函数名称: MQTT_UnPacketSubscrebe // // 函数功能: Subscribe的回复消息解包 // // 入口参数: rev_data:接收到的信息 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_UnPacketSubscribe ( uint8 *rev_data ) { uint8 result = 255; if ( rev_data[2] == MOSQ_MSB ( MQTT_SUBSCRIBE_ID ) && rev_data[3] == MOSQ_LSB ( MQTT_SUBSCRIBE_ID ) ) { switch ( rev_data[4] ) { case 0x00: case 0x01: case 0x02: //MQTT Subscribe OK result = 0; break; case 0x80: //MQTT Subscribe Failed result = 1; break; default: //MQTT Subscribe UnKnown Err result = 2; break; } } return result; } //========================================================== // 函数名称: MQTT_PacketUnSubscribe // // 函数功能: UnSubscribe消息组包 // // 入口参数: pkt_id:pkt_id // qos:消息重发次数 // topics:订阅的消息 // topics_cnt:订阅的消息个数 // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketUnSubscribe ( uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket ) { uint32 topic_len = 0, remain_len = 0; int16 len = 0; uint8 i = 0; if ( pkt_id == 0 ) { return 1; } //计算topic长度------------------------------------------------------------------------- for ( ; i < topics_cnt; i++ ) { if ( topics[i] == NULL ) { return 2; } topic_len += strlen ( topics[i] ); } //2 bytes packet id, 2 bytes topic length + topic + 1 byte reserve--------------------- remain_len = 2 + ( topics_cnt << 1 ) + topic_len; //分配内存------------------------------------------------------------------------------ MQTT_NewBuffer ( mqttPacket, remain_len + 5 ); if ( mqttPacket->_data == NULL ) { return 3; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_UNSUBSCRIBE << 4 | 0x02; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength ( remain_len, mqttPacket->_data + mqttPacket->_len ); if ( len < 0 ) { MQTT_DeleteBuffer ( mqttPacket ); return 4; } else { mqttPacket->_len += len; } /*************************************payload***********************************************/ //payload----------------------pkt_id--------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( pkt_id ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( pkt_id ); //payload----------------------topic_name----------------------------------------------- for ( i = 0; i < topics_cnt; i++ ) { topic_len = strlen ( topics[i] ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( topic_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( topic_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, topics[i], topic_len ); mqttPacket->_len += topic_len; } return 0; } //========================================================== // 函数名称: MQTT_UnPacketUnSubscribe // // 函数功能: UnSubscribe的回复消息解包 // // 入口参数: rev_data:接收到的信息 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketUnSubscribe ( uint8 *rev_data ) { uint1 result = 1; if ( rev_data[2] == MOSQ_MSB ( MQTT_UNSUBSCRIBE_ID ) && rev_data[3] == MOSQ_LSB ( MQTT_UNSUBSCRIBE_ID ) ) { result = 0; } return result; } //========================================================== // 函数名称: MQTT_PacketPublish // // 函数功能: Pulish消息组包 // // 入口参数: pkt_id:pkt_id // topic:发布的topic // payload:消息体 // payload_len:消息体长度 // qos:重发次数 // retain:离线消息推送 // own: // mqttPacket:包指针 // // 返回参数: 0-成功 其他-失败 // // 说明: //========================================================== uint8 MQTT_PacketPublish ( uint16 pkt_id, const int8 *topic, const int8 *payload, uint32 payload_len, enum MqttQosLevel qos, int32 retain, int32 own, MQTT_PACKET_STRUCTURE *mqttPacket ) { uint32 total_len = 0, topic_len = 0; int32 len = 0; uint8 flags = 0; //pkt_id检查---------------------------------------------------------------------------- if ( pkt_id == 0 ) { return 1; } //$dp为系统上传数据点的指令-------------------------------------------------------------- for ( topic_len = 0; topic[topic_len] != '\0'; ++topic_len ) { if ( ( topic[topic_len] == '#' ) || ( topic[topic_len] == '+' ) ) { return 2; } } //Publish消息--------------------------------------------------------------------------- flags |= MQTT_PKT_PUBLISH << 4; //retain标志---------------------------------------------------------------------------- if ( retain ) { flags |= 0x01; } //总长度-------------------------------------------------------------------------------- total_len = topic_len + payload_len + 2; //qos级别--主要用于PUBLISH(发布态)消息的,保证消息传递的次数----------------------------- switch ( qos ) { case MQTT_QOS_LEVEL0: flags |= MQTT_CONNECT_WILL_QOS0; //最多一次 break; case MQTT_QOS_LEVEL1: flags |= 0x02; //最少一次 total_len += 2; break; case MQTT_QOS_LEVEL2: flags |= 0x04; //只有一次 total_len += 2; break; default: return 3; } //分配内存------------------------------------------------------------------------------ MQTT_NewBuffer ( mqttPacket, total_len + 3 ); if ( mqttPacket->_data == NULL ) { return 4; } memset ( mqttPacket->_data, 0, total_len + 3 ); /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = flags; //固定头部----------------------剩余长度值----------------------------------------------- len = MQTT_DumpLength ( total_len, mqttPacket->_data + mqttPacket->_len ); if ( len < 0 ) { MQTT_DeleteBuffer ( mqttPacket ); return 5; } else { mqttPacket->_len += len; } /*************************************可变头部***********************************************/ //可变头部----------------------写入topic长度、topic------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( topic_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( topic_len ); strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, topic, topic_len ); mqttPacket->_len += topic_len; if ( qos != MQTT_QOS_LEVEL0 ) { mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( pkt_id ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( pkt_id ); } //可变头部----------------------写入payload---------------------------------------------- if ( payload != NULL ) { strncat ( ( int8 * ) mqttPacket->_data + mqttPacket->_len, payload, payload_len ); mqttPacket->_len += payload_len; } return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublish // // 函数功能: Publish消息解包 // // 入口参数: flags:MQTT相关标志信息 // pkt:指向可变头部 // size:固定头部中的剩余长度信息 // // 返回参数: 0-成功 其他-失败原因 // // 说明: //========================================================== uint8 MQTT_UnPacketPublish ( uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id ) { const int8 flags = rev_data[0] & 0x0F; uint8 *msgPtr; uint32 remain_len = 0; const int8 dup = flags & 0x08; *qos = ( flags & 0x06 ) >> 1; msgPtr = rev_data + MQTT_ReadLength ( rev_data + 1, 4, &remain_len ) + 1; if ( remain_len < 2 || flags & 0x01 ) //retain { return 255; } *topic_len = ( uint16 ) msgPtr[0] << 8 | msgPtr[1]; if ( remain_len < *topic_len + 2 ) { return 255; } if ( strstr ( ( int8 * ) msgPtr + 2, CMD_TOPIC_PREFIX ) != NULL ) //如果是命令下发 { return MQTT_PKT_CMD; } switch ( *qos ) { case MQTT_QOS_LEVEL0: // qos0 have no packet identifier if ( 0 != dup ) { return 255; } *topic =(char *) MQTT_MallocBuffer ( *topic_len + 1 ); //为topic分配内存 if ( *topic == NULL ) { return 255; } memset ( *topic, 0, *topic_len + 1 ); memcpy ( *topic, ( int8 * ) msgPtr + 2, *topic_len ); //复制数据 *payload_len = remain_len - 2 - *topic_len; //为payload分配内存 *payload = (char *)MQTT_MallocBuffer ( *payload_len + 1 ); if ( *payload == NULL ) //如果失败 { MQTT_FreeBuffer ( *topic ); //则需要把topic的内存释放掉 return 255; } memset ( *payload, 0, *payload_len + 1 ); memcpy ( *payload, ( int8 * ) msgPtr + 2 + *topic_len, *payload_len ); break; case MQTT_QOS_LEVEL1: case MQTT_QOS_LEVEL2: if ( *topic_len + 2 > remain_len ) { return 255; } *pkt_id = ( uint16 ) msgPtr[*topic_len + 2] << 8 | msgPtr[*topic_len + 3]; if ( pkt_id == 0 ) { return 255; } *topic =(char *) MQTT_MallocBuffer ( *topic_len + 1 ); //为topic分配内存 if ( *topic == NULL ) { return 255; } memset ( *topic, 0, *topic_len + 1 ); memcpy ( *topic, ( int8 * ) msgPtr + 2, *topic_len ); //复制数据 *payload_len = remain_len - 4 - *topic_len; *payload =(char *) MQTT_MallocBuffer ( *payload_len + 1 ); //为payload分配内存 if ( *payload == NULL ) //如果失败 { MQTT_FreeBuffer ( *topic ); //则需要把topic的内存释放掉 return 255; } memset ( *payload, 0, *payload_len + 1 ); memcpy ( *payload, ( int8 * ) msgPtr + 4 + *topic_len, *payload_len ); break; default: return 255; } if ( strchr ( ( int8 * ) topic, '+' ) || strchr ( ( int8 * ) topic, '#' ) ) { return 255; } return 0; } //========================================================== // 函数名称: MQTT_PacketPublishAck // // 函数功能: Publish Ack消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为1时,需要Ack回复 //========================================================== uint1 MQTT_PacketPublishAck ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 4 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBACK << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishAck // // 函数功能: Publish Ack消息解包 // // 入口参数: rev_data:收到的数据 // // 返回参数: 0-成功 1-失败原因 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishAck ( uint8 *rev_data ) { if ( rev_data[1] != 2 ) { return 1; } if ( rev_data[2] == MOSQ_MSB ( MQTT_PUBLISH_ID ) && rev_data[3] == MOSQ_LSB ( MQTT_PUBLISH_ID ) ) { return 0; } else { return 1; } } //========================================================== // 函数名称: MQTT_PacketPublishRec // // 函数功能: Publish Rec消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec //========================================================== uint1 MQTT_PacketPublishRec ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 4 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREC << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishRec // // 函数功能: Publish Rec消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishRec ( uint8 *rev_data ) { if ( rev_data[1] != 2 ) { return 1; } if ( rev_data[2] == MOSQ_MSB ( MQTT_PUBLISH_ID ) && rev_data[3] == MOSQ_LSB ( MQTT_PUBLISH_ID ) ) { return 0; } else { return 1; } } //========================================================== // 函数名称: MQTT_PacketPublishRel // // 函数功能: Publish Rel消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel //========================================================== uint1 MQTT_PacketPublishRel ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 4 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBREL << 4 | 0x02; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishRel // // 函数功能: Publish Rel消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishRel ( uint8 *rev_data, uint16 pkt_id ) { if ( rev_data[1] != 2 ) { return 1; } if ( rev_data[2] == MOSQ_MSB ( pkt_id ) && rev_data[3] == MOSQ_LSB ( pkt_id ) ) { return 0; } else { return 1; } } //========================================================== // 函数名称: MQTT_PacketPublishComp // // 函数功能: Publish Comp消息组包 // // 入口参数: pkt_id:packet id // mqttPacket:包指针 // // 返回参数: 0-成功 1-失败原因 // // 说明: 当收到的Publish消息的QoS等级为2时,先收到rec,再回复rel //========================================================== uint1 MQTT_PacketPublishComp ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 4 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PUBCOMP << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 2; /*************************************可变头部***********************************************/ //可变头部----------------------pkt_id长度----------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = pkt_id >> 8; mqttPacket->_data[mqttPacket->_len++] = pkt_id & 0xff; return 0; } //========================================================== // 函数名称: MQTT_UnPacketPublishComp // // 函数功能: Publish Comp消息解包 // // 入口参数: rev_data:接收到的数据 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_UnPacketPublishComp ( uint8 *rev_data ) { if ( rev_data[1] != 2 ) { return 1; } if ( rev_data[2] == MOSQ_MSB ( MQTT_PUBLISH_ID ) && rev_data[3] == MOSQ_LSB ( MQTT_PUBLISH_ID ) ) { return 0; } else { return 1; } } //========================================================== // 函数名称: MQTT_PacketPing // // 函数功能: 心跳请求组包 // // 入口参数: mqttPacket:包指针 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketPing ( MQTT_PACKET_STRUCTURE *mqttPacket ) { MQTT_NewBuffer ( mqttPacket, 2 ); if ( mqttPacket->_data == NULL ) { return 1; } /*************************************固定头部***********************************************/ //固定头部----------------------头部消息------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_PINGREQ << 4; //固定头部----------------------剩余长度------------------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; return 0; }
#ifndef _MQTTKIT_H_ #define _MQTTKIT_H_ #include "types.h" //=============================配置============================== //===========可以提供RTOS的内存管理方案,也可以使用C库的========= //RTOS #include <stdlib.h> #define MQTT_MallocBuffer malloc #define MQTT_FreeBuffer free //========================================================== #define MOSQ_MSB(A) (uint8)((A & 0xFF00) >> 8) #define MOSQ_LSB(A) (uint8)(A & 0x00FF) /*--------------------------------内存分配方案标志--------------------------------*/ #define MEM_FLAG_NULL 0 #define MEM_FLAG_ALLOC 1 #define MEM_FLAG_STATIC 2 typedef struct Buffer { uint8 *_data; //协议数据 uint32 _len; //写入的数据长度 uint32 _size; //缓存总大小 uint8 _memFlag; //内存使用的方案:0-未分配 1-使用的动态分配 2-使用的固定内存 } MQTT_PACKET_STRUCTURE; /*--------------------------------固定头部消息类型--------------------------------*/ enum MqttPacketType { MQTT_PKT_CONNECT = 1, /**< 连接请求数据包 */ MQTT_PKT_CONNACK, /**< 连接确认数据包 */ MQTT_PKT_PUBLISH, /**< 发布数据数据包 */ MQTT_PKT_PUBACK, /**< 发布确认数据包 */ MQTT_PKT_PUBREC, /**< 发布数据已接收数据包,Qos 2时,回复MQTT_PKT_PUBLISH */ MQTT_PKT_PUBREL, /**< 发布数据释放数据包, Qos 2时,回复MQTT_PKT_PUBREC */ MQTT_PKT_PUBCOMP, /**< 发布完成数据包, Qos 2时,回复MQTT_PKT_PUBREL */ MQTT_PKT_SUBSCRIBE, /**< 订阅数据包 */ MQTT_PKT_SUBACK, /**< 订阅确认数据包 */ MQTT_PKT_UNSUBSCRIBE, /**< 取消订阅数据包 */ MQTT_PKT_UNSUBACK, /**< 取消订阅确认数据包 */ MQTT_PKT_PINGREQ, /**< ping 数据包 */ MQTT_PKT_PINGRESP, /**< ping 响应数据包 */ MQTT_PKT_DISCONNECT, /**< 断开连接数据包 */ //新增 MQTT_PKT_CMD /**< 命令下发数据包 */ }; /*--------------------------------MQTT QOS等级--------------------------------*/ enum MqttQosLevel { MQTT_QOS_LEVEL0, /**< 最多发送一次 */ MQTT_QOS_LEVEL1, /**< 最少发送一次 */ MQTT_QOS_LEVEL2 /**< 只发送一次 */ }; /*--------------------------------MQTT 连接请求标志位,内部使用--------------------------------*/ enum MqttConnectFlag { MQTT_CONNECT_CLEAN_SESSION = 0x02, MQTT_CONNECT_WILL_FLAG = 0x04, MQTT_CONNECT_WILL_QOS0 = 0x00, MQTT_CONNECT_WILL_QOS1 = 0x08, MQTT_CONNECT_WILL_QOS2 = 0x10, MQTT_CONNECT_WILL_RETAIN = 0x20, MQTT_CONNECT_PASSORD = 0x40, MQTT_CONNECT_USER_NAME = 0x80 }; /*--------------------------------消息的packet ID,可自定义--------------------------------*/ #define MQTT_PUBLISH_ID 12 #define MQTT_SUBSCRIBE_ID 1 #define MQTT_UNSUBSCRIBE_ID 30 /*--------------------------------删包--------------------------------*/ void MQTT_DeleteBuffer ( MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------解包--------------------------------*/ uint8 MQTT_UnPacketRecv ( uint8 *dataPtr ); /*--------------------------------登录组包--------------------------------*/ uint8 MQTT_PacketConnect ( const int8 *user, const int8 *password, const int8 *devid, uint16 cTime, uint1 clean_session, uint1 qos, const int8 *will_topic, const int8 *will_msg, int32 will_retain, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------断开连接组包--------------------------------*/ uint1 MQTT_PacketDisConnect ( MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------连接响应解包--------------------------------*/ uint8 MQTT_UnPacketConnectAck ( uint8 *rev_data ); /*--------------------------------命令下发解包--------------------------------*/ uint8 MQTT_UnPacketCmd ( uint8 *rev_data, int8 **cmdid, int8 **req, uint16 *req_len ); /*--------------------------------命令回复组包--------------------------------*/ uint1 MQTT_PacketCmdResp ( const int8 *cmdid, const int8 *req, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------订阅主题组包--------------------------------*/ uint8 MQTT_PacketSubscribe ( uint16 pkt_id, enum MqttQosLevel qos, const char *topic, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------订阅主题回复解包--------------------------------*/ uint8 MQTT_UnPacketSubscribe ( uint8 *rev_data ); /*--------------------------------取消订阅组包--------------------------------*/ uint8 MQTT_PacketUnSubscribe ( uint16 pkt_id, const int8 *topics[], uint8 topics_cnt, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------取消订阅回复解包--------------------------------*/ uint1 MQTT_UnPacketUnSubscribe ( uint8 *rev_data ); /*--------------------------------发布主题组包--------------------------------*/ uint8 MQTT_PacketPublish ( uint16 pkt_id, const int8 *topic, const int8 *payload, uint32 payload_len, enum MqttQosLevel qos, int32 retain, int32 own, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------发布消息回复解包--------------------------------*/ uint8 MQTT_UnPacketPublish ( uint8 *rev_data, int8 **topic, uint16 *topic_len, int8 **payload, uint16 *payload_len, uint8 *qos, uint16 *pkt_id ); /*--------------------------------发布消息的Ack组包--------------------------------*/ uint1 MQTT_PacketPublishAck ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------发布消息的Ack解包--------------------------------*/ uint1 MQTT_UnPacketPublishAck ( uint8 *rev_data ); /*--------------------------------发布消息的Rec组包--------------------------------*/ uint1 MQTT_PacketPublishRec ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------发布消息的Rec解包--------------------------------*/ uint1 MQTT_UnPacketPublishRec ( uint8 *rev_data ); /*--------------------------------发布消息的Rel组包--------------------------------*/ uint1 MQTT_PacketPublishRel ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------发布消息的Rel解包--------------------------------*/ uint1 MQTT_UnPacketPublishRel ( uint8 *rev_data, uint16 pkt_id ); /*--------------------------------发布消息的Comp组包--------------------------------*/ uint1 MQTT_PacketPublishComp ( uint16 pkt_id, MQTT_PACKET_STRUCTURE *mqttPacket ); /*--------------------------------发布消息的Comp解包--------------------------------*/ uint1 MQTT_UnPacketPublishComp ( uint8 *rev_data ); /*--------------------------------心跳请求组包--------------------------------*/ uint1 MQTT_PacketPing ( MQTT_PACKET_STRUCTURE *mqttPacket ); #endif
#include "main.h" int NetApi_SendData ( unsigned char *data, unsigned short len ) { if ( g_selchip == CHIP_W5500 ) { // W5500_SendData ( data, len ); } if ( g_selchip == CHIP_SIM900 ) { // Sim900_SendData( data, len ); } if ( g_selchip == CHIP_ESP8266 ) { Esp8266_SendData ( data, len ); } } int NetApi_AccessNetwork ( void ) { if ( g_selchip == CHIP_W5500 ) { //return W5500_AccessNetwork ( ); } if ( g_selchip == CHIP_SIM900 ) { //return Sim900_AccessNetwork ( ); } if ( g_selchip == CHIP_ESP8266 ) { return Esp8266_AccessNetwork ( ); } } unsigned char *NetApi_RecvData ( unsigned short timeOut ) { if ( g_selchip == CHIP_W5500 ) { //return W5500_RecvData ( timeOut ); } if ( g_selchip == CHIP_SIM900 ) { //return Sim900_RecvData (timeOut ); } if ( g_selchip == CHIP_ESP8266 ) { return Esp8266_RecvData ( timeOut ); } } int NetApi_TcpConnect ( void ) { if ( g_selchip == CHIP_W5500 ) { //return W5500_TcpConnect ( ); } if ( g_selchip == CHIP_SIM900 ) { //return Sim900_TcpConnect ( ); } if ( g_selchip == CHIP_ESP8266 ) { return Esp8266_TcpConnect ( ); } } void NetApi_InitAccessNetwork(void) { if ( g_selchip == CHIP_W5500 ) { // W5500_InitAccessNetwork ( ); } if ( g_selchip == CHIP_SIM900 ) { // Sim900_InitAccessNetwork ( ); } if ( g_selchip == CHIP_ESP8266 ) { Esp8266_InitAccessNetwork ( ); } } void NetApi_InitTcpConnect(void) { if ( g_selchip == CHIP_W5500 ) { // W5500_InitTcpConnect ( ); } if ( g_selchip == CHIP_SIM900 ) { // Sim900_InitTcpConnect ( ); } if ( g_selchip == CHIP_ESP8266 ) { Esp8266_InitTcpConnect ( ); } }
#ifndef _NETAPI_H_ #define _NETAPI_H_ int NetApi_SendData ( unsigned char *data, unsigned short len ); int NetApi_AccessNetwork ( void ); unsigned char *NetApi_RecvData ( unsigned short timeOut ); int NetApi_TcpConnect ( void ); void NetApi_InitAccessNetwork(void); void NetApi_InitTcpConnect(void); #endif
#include "main.h" void Esp8266_Rst(void) { pinMode(PB1, OUTPUT); digitalWrite(PB1,LOW); delay(10); digitalWrite(PB1,HIGH); delay(4000); //等待复位完成4second AT_ClearPara(); } int Esp8266_AccessNetwork ( void ) { char strTemp[100] = {0}; sprintf ( strTemp, "AT+CWJAP=\"%s\",\"%s\"\r\n",g_SysPara.wifi_ssid, g_SysPara.wifi_password); if ( AT_SendCmd ( "AT\r\n", "OK", 100 )!=0 ) { delay ( 1500 ); if ( AT_SendCmd ( "AT\r\n", "OK", 100 )!=0 ) { return 1; } } if ( AT_SendCmd ( "ATE0\r\n", "OK", 100 )!=0 ) { delay ( 1500 ); if ( AT_SendCmd ( "AT\r\n", "OK", 100 )!=0 ) { return 1; } } if ( AT_SendCmd ( "AT+CWMODE=1\r\n", "OK", 100 )!=0 ) // ?????station { return 1; } if ( AT_SendCmd ( "AT+CIPMODE=0\r\n", "OK", 100 ) !=0) // 0-??????? { return 1; } if ( AT_SendCmd ( strTemp, "CONNECTED", 13000 ) !=0) //?????·???? { if ( AT_SendCmd ( strTemp, "CONNECTED", 13000 )!=0 ) { return 1; } } return 0; } int Esp8266_TcpConnect ( void ) { char strTemp[200] = {0}; sprintf ( strTemp, "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", g_SysPara.host_ip, g_SysPara.host_port ); if ( AT_SendCmd ( strTemp, "CONNECT", 22500 )!=0 ) { delay ( 3500 ); if ( AT_SendCmd ( strTemp, "CONNECT", 22500 )!=0 ) { return 1; } } return 0; } void Esp8266_InitAccessNetwork(void) { } void Esp8266_InitTcpConnect(void) { } int Esp8266_SendData ( unsigned char *data, unsigned short len ) { return AT_SendData(data,len); } unsigned char g_Buffer[1024]; unsigned char *Esp8266_RecvData ( unsigned short timeOut ) { int tt=0; int i; unsigned long num = 0; String strTemp=""; char *ptrIPD = NULL; num = Serial2.available(); if((num==0) && (timeOut==0))return NULL; while(1) { delay ( 1 ); tt++; if(tt>timeOut) { //关闭连接,从头开始 ReSet_SystemStatus(); break; } num = Serial2.available(); if ( num > 0 ) { strTemp=""; for(i=0;i<1024;i++) { if(Serial2.available()) { g_Buffer[i]= Serial2.read(); strTemp=strTemp+(char)g_Buffer[i]; } else { delay ( 1000 ); if(!Serial2.available()) break; } } Serial.print(strTemp); //8266接收数据格式 ptrIPD = strstr ( ( char * ) g_Buffer, "IPD," ); if ( ptrIPD != NULL ) { ptrIPD = strchr ( ptrIPD, ':' ); if ( ptrIPD != NULL ) { ptrIPD++; return ( unsigned char * ) ( ptrIPD ); } } } } return NULL; }
#ifndef _ESP8266_H_ #define _ESP8266_H_ void Esp8266_Rst(void); int Esp8266_SendData ( unsigned char *data, unsigned short len ); int Esp8266_AccessNetwork ( void ); unsigned char *Esp8266_RecvData ( unsigned short timeOut ); int Esp8266_TcpConnect ( void ); void Esp8266_InitAccessNetwork(void); void Esp8266_InitTcpConnect(void); #endif
/** ****************************************************************************** * @file main.c * @author 重庆光明顶工作室:物联网应用创新中心 * @version V1.0 * @date 2015-02-14 * @brief 用3.5.0版本库建的工程模板 * @attention * * 内网测试,请适配版与路由器相接。并确认路由器的 * DHCP功能处于打开的状态。 ****************************************************************************** */ #include "main.h" //--------------------------------- //云服务选择:每种云的JSON格式数据不同。 #define CLOUD_ONENET 0//中移物联网 #define CLOUD_BAIDU 1//百度云 #define CLOUD_ALI 2//阿里云 #define CLOUD_TENCENT 3//腾讯云 #define CLOUD_TLINK 4//TLINK云 :数据直接上传到云服务。 int g_selcloud = CLOUD_ONENET; //--------------------------------- //网络选择 int g_selchip = USE_CHIP; //--------------------------------- //系统参数 SYS_PARA g_SysPara; void Net_DefPara ( void ); //-------------------------------- #define ST_MQTT_INIT 0 #define ST_MQTT_ACESSNET 1 #define ST_MQTT_TCP 2 #define ST_MQTT_CONNECTED 3 #define ST_MQTT_SUBSCRIBE 4 #define ST_MQTT_WORK 5 uint8 g_SysStatus; void ReSet_SystemStatus ( void ) { g_SysStatus = ST_MQTT_INIT; } //mqtt fun int OneNet_Connect ( void ); int OneNet_Subscribe ( const char *topic ); int OneNet_Publish ( char *topic, const char *msg ); void OneNet_HeartBeat ( void ); void OneNet_PollRecv ( void ); void Net_DefPara ( void ) { //wifi para strcpy ( g_SysPara.wifi_ssid, "yan" ); strcpy ( g_SysPara.wifi_password, "12345678" ); //server ip, port //不同的云,域名参数不同 if ( g_selcloud == CLOUD_ONENET ) { strcpy ( g_SysPara.host_ip, "183.230.40.39" );//固定,有线DNS解析"183.230.40.39" ,mqtt.heclouds.com strcpy ( g_SysPara.host_port, "6002" ); //mqtt login: clientid, username,passwd strcpy ( g_SysPara.mqtt_clientid, "833570179" );//deviceid strcpy ( g_SysPara.mqtt_username, "466095" );//produceid strcpy ( g_SysPara.mqtt_passwd, "devti" );//password } if ( g_selcloud == CLOUD_BAIDU ) { strcpy ( g_SysPara.host_ip, "apgvzfj.iot.bj.baidubce.com" );//变化 strcpy ( g_SysPara.host_port, "1883" ); //mqtt login: clientid, username,passwd strcpy ( g_SysPara.mqtt_clientid, "thingidp@apgvzfjlgate]1644332494|MD5" ); strcpy ( g_SysPara.mqtt_username, "thingidp@apgvzfjlgate]1644332494|MD5" ); strcpy ( g_SysPara.mqtt_passwd, "56df928bcb875e9a91eb9f47c476278c" ); } if ( g_selcloud == CLOUD_ALI ) { strcpy ( g_SysPara.host_ip, "a13lidNT5LV.iot-as-mqtt.cn-shanghai.aliyuncs.com" ); strcpy ( g_SysPara.host_port, "1883" ); //mqtt login: clientid, username,passwd strcpy ( g_SysPara.mqtt_clientid, "a13lidNT5LV.gatelsecuremode=2,signmethod=hmacsha256,timestamp=2524608000000|" );//变化 strcpy ( g_SysPara.mqtt_username, "gate&a13lidNT5LV" ); strcpy ( g_SysPara.mqtt_passwd, "f5a95cc2d99ca99c93708d21f6b00162f8f26d4b2e3bf584d62f2e65ac8d0b4d" ); } if ( g_selcloud == CLOUD_TENCENT ) { strcpy ( g_SysPara.host_ip, "iotcloud-mqtt.gz.tencentdevices.com" ); strcpy ( g_SysPara.host_port, "1883" ); //mqtt login: clientid, username,passwd strcpy ( g_SysPara.mqtt_clientid, "N4TX5JROKOsim" ); strcpy ( g_SysPara.mqtt_username, "N4TX5JROKOsim;12010126;N7MYl;1680383966" ); strcpy ( g_SysPara.mqtt_passwd, "aa1357ca2b8f40155ce977265131568926ef5f41acee6b097540508348fb7787;hmacsha256" ); } if ( g_selcloud == CLOUD_TLINK ) { strcpy ( g_SysPara.host_ip, "mq.tlink.io" ); strcpy ( g_SysPara.host_port, "1883" ); //mqtt login: clientid, username,passwd strcpy ( g_SysPara.mqtt_clientid, "373U788J8LZ16781" ); strcpy ( g_SysPara.mqtt_username, "15922524833" );//登录平台的用户名 strcpy ( g_SysPara.mqtt_passwd, "yan750924" );//登录平台的密码 } //?? strcpy ( g_SysPara.mqtt_subtopic1, "$crep" ); strcpy ( g_SysPara.mqtt_subtopic2, "cmd/#" ); strcpy ( g_SysPara.mqtt_pubtopic1, "$dp" ); strcpy ( g_SysPara.mqtt_pubtopic2, "data/devti" ); } //------------------------------------------------------------------ //状态机函数 //初始状态 void ST_MQTT_INITf ( void ) { NetApi_InitAccessNetwork(); g_SysStatus = ST_MQTT_ACESSNET; } //接入网络 void ST_MQTT_ACESSNETf ( void ) { int retcode = 0; retcode = NetApi_AccessNetwork(); if ( retcode == 0 ) { g_SysStatus = ST_MQTT_TCP; NetApi_InitTcpConnect(); } } //TCP连接 void ST_MQTT_TCPf ( void ) { int retcode = 0; retcode = NetApi_TcpConnect(); if ( retcode == 0 ) { g_SysStatus = ST_MQTT_CONNECTED; } } //登录 void ST_MQTT_CONNECTEDf ( void ) { int retcode = 0; retcode = OneNet_Connect(); if ( retcode == 0 ) { g_SysStatus = ST_MQTT_SUBSCRIBE; } else { g_SysStatus = ST_MQTT_TCP;//重新连接 } } //订阅主题 void ST_MQTT_SUBSCRIBEf ( void ) { if ( OneNet_Subscribe ( g_SysPara.mqtt_subtopic2 ) == 0 ) { if ( OneNet_Subscribe ( g_SysPara.mqtt_subtopic1 ) == 0 ) {;} //订阅 $crep 返回都不成功 { g_SysStatus = ST_MQTT_WORK; return; } } g_SysStatus = ST_MQTT_CONNECTED;//重新连接 } //工作状态 void ST_MQTT_WORKf ( void ) { static int t_heart = 0; static int t_data = 0; delay ( 1 ); //每3秒发布一个数据 t_data++; if ( t_data > 3000 ) { char msg[] = "{\"tmp\":27}"; t_data = 0; OneNet_Publish ( g_SysPara.mqtt_pubtopic1, msg ); delay ( 2000 ); OneNet_Publish ( g_SysPara.mqtt_pubtopic2, msg ); } //每10秒心跳包数据 t_heart++; if ( t_heart > 10000 ) { t_heart = 0; OneNet_HeartBeat(); t_data = 0; } OneNet_PollRecv(); } //------------------------------------------------------------ //MQTT封装 //如果已经连接登录,再次连接,则不返回登录成功,没有应答信息 int OneNet_Connect ( void ) { MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包 unsigned char *dataPtr ; int status = 1; //Keep Alive=256 秒= 4分钟 //最小数值为0,标识客户端不断开 if ( MQTT_PacketConnect ( g_SysPara.mqtt_username, g_SysPara.mqtt_passwd, g_SysPara.mqtt_clientid, 256, 0, MQTT_QOS_LEVEL0, NULL, NULL, 0, &mqttPacket ) == 0 ) { //25 (37) //10 23 00 04 4D 51 54 54 04 C0 01 00 00 09 36 32 32 39 32 33 36 39 35 00 06 33 36 38 37 36 33 00 04 67 61 74 65 printf ( "Tips: 登录云服务\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); //发送出去 dataPtr = NetApi_RecvData ( 5000 );//超时接收数据 if ( dataPtr != NULL ) { //对接收的数据进行分析 if ( MQTT_UnPacketRecv ( dataPtr ) == MQTT_PKT_CONNACK ) { switch ( MQTT_UnPacketConnectAck ( dataPtr ) ) { case 0: printf ( "Tips: 连接成功\r\n" ); status = 0; break; case 1: printf ( "WARN: 连接失败:协议错误\r\n" ); break; case 2: printf ( "WARN: 连接失败:非法的clientid\r\n" ); break; case 3: printf ( "WARN: 连接失败:服务器失败\r\n" ); break; case 4: printf ( "WARN: 连接失败:用户名或密码错误\r\n" ); break; case 5: printf ( "WARN: 连接失败:非法链接(比如token非法)\r\n" ); break; default: printf ( "ERR: 连接失败:未知错误\r\n" ); break; } } } MQTT_DeleteBuffer ( &mqttPacket ); //删包 } return status; } //========================================================== // 函数名称: OneNet_Subscribe // // 函数功能: 订阅 // // 入口参数: topic:订阅的topic // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== int OneNet_Subscribe ( const char *topic ) { unsigned char *dataPtr ; int status = 1; MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; printf ( "Subscribe:topic=%s\n", topic ); //-------------------------------------------步骤一:组包---------------------------------------------- if ( MQTT_PacketSubscribe ( MQTT_SUBSCRIBE_ID, MQTT_QOS_LEVEL1, topic, &mqttPacket ) == 0 ) { //82 0A 00 14 00 05 24 63 72 65 78 02 00 00 00 33 33 35 37 30 E0 //----------------------------------------------步骤二:发送数据----------------------------------------------- NetApi_SendData ( mqttPacket._data, mqttPacket._len ); //发送出去 dataPtr = NetApi_RecvData ( 5000 );//超时接收数据 //分析接收的数据 if ( dataPtr != NULL ) { if ( MQTT_UnPacketRecv ( dataPtr ) == MQTT_PKT_SUBACK ) //订阅应答 { if ( MQTT_UnPacketSubscribe ( dataPtr ) == 0 ) { status = 0; printf ( "Tips: MQTT Subscribe OK\r\n" ); } } } //---------------------------------------------步骤三:删包------------------------------------------------ MQTT_DeleteBuffer ( &mqttPacket ); } return status; } //========================================================== // 函数名称: OneNet_Publish // // 函数功能: 发布消息 // // 入口参数: topic:发布的主题 // msg:消息内容 // // 返回参数: 0-成功 1-失败 // // 说明: //========================================================== uint1 MQTT_PacketSaveData ( char *strTopic, int16 send_len, int8 *type_bin_head, MQTT_PACKET_STRUCTURE *mqttPacket ) { if ( strcmp ( strTopic, "$dp" ) == 0 ) //支持onenet上云,JSON格式 { //onenet特殊协议 "$dp", send_len + 3 if ( MQTT_PacketPublish ( MQTT_PUBLISH_ID, "$dp", NULL, send_len + 3, MQTT_QOS_LEVEL0, 0, 1, mqttPacket ) == 0 ) { mqttPacket->_data[mqttPacket->_len++] = 3; //json类型3 mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB ( send_len ); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB ( send_len ); return 0; } } else { //普通透明传输协议 strTopic, send_len if ( MQTT_PacketPublish ( MQTT_PUBLISH_ID, strTopic, NULL, send_len, MQTT_QOS_LEVEL0, 0, 1, mqttPacket ) == 0 ) { return 0; } } return 1; } int OneNet_Publish ( char *topic, const char *msg ) { short body_len = 0, i = 0; MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; printf ( "Publish Topic: %s, Msg: %s\r\n", topic, msg ); body_len = strlen ( msg ); if ( MQTT_PacketSaveData ( topic, body_len, NULL, &mqttPacket ) == 0 ) //?? { for ( i = 0; i < body_len; i++ ) { mqttPacket._data[mqttPacket._len++] = msg[i]; } NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); //?? } return 0; } //========================================================== // 函数名称: OneNet_HeartBeat // // 函数功能: 心跳检测 // // 入口参数: 无 // // 返回参数: 无 // // 说明: //========================================================== void OneNet_HeartBeat ( void ) { MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; // unsigned char sCount = 3, *dataPtr; //---------------------------------------------步骤一:组包--------------------------------------------- if ( MQTT_PacketPing ( &mqttPacket ) ) { return; } { //----------------------------------------------步骤二:发送数据------------------------------------------ NetApi_SendData ( mqttPacket._data, mqttPacket._len ); } //delay_ms(10); //---------------------------------------------???:??--------------------------------------------- MQTT_DeleteBuffer ( &mqttPacket ); } void OneNet_PollRecv ( void ) { MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0}; //协议包 char *req_payload = NULL; char *cmdid_topic = NULL; unsigned short topic_len; unsigned short req_len = 0; unsigned char type = 0; short result = 0; char *dataPtr = NULL; char numBuf[10]; int num = 0; uint8 qos; uint16 pkt_id; uint8 *cmd; cmd = NetApi_RecvData ( 0 ); //检查接收数据 if ( cmd == NULL ) { return; } type = MQTT_UnPacketRecv ( cmd ); switch ( type ) { case MQTT_PKT_PINGRESP://心跳响应 break; case MQTT_PKT_CMD: //命令下发 result = MQTT_UnPacketCmd ( cmd, &cmdid_topic, &req_payload, &req_len ); //解出topic和消息体 if ( result == 0 ) { printf ( "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len ); if ( MQTT_PacketCmdResp ( cmdid_topic, req_payload, &mqttPacket ) == 0 ) //命令回复组包 { printf ( "Tips: Send CmdResp\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); //删包 } } break; case MQTT_PKT_PUBLISH: //接收的Publish消息 result = MQTT_UnPacketPublish ( cmd, &cmdid_topic, &topic_len, &req_payload, &req_len, &qos, &pkt_id ); if ( result == 0 ) { // int num; printf ( "topic: %s\r\npayload: %s\r\n", cmdid_topic, req_payload ); //包的处理方法及分析,网关信息,命令包,进行转发处理 //去掉空格 //int i,m=0, num; num = strlen ( req_payload ); //通过串口发送出去-----命令的处理 // Usart3_SendString ( ( unsigned char * ) req_payload, num ); switch ( qos ) { case 1: //收到publish的qos为1,设备需要回复Ack if ( MQTT_PacketPublishAck ( pkt_id, &mqttPacket ) == 0 ) { printf ( "Tips: Send PublishAck\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); } break; case 2: //收到publish的qos为2,设备先回复Rec //平台回复Rel,设备再回复Comp if ( MQTT_PacketPublishRec ( pkt_id, &mqttPacket ) == 0 ) { printf ( "Tips: Send PublishRec\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); } break; default: break; } } break; case MQTT_PKT_PUBACK: //发送Publish消息,平台回复的Ack if ( MQTT_UnPacketPublishAck ( cmd ) == 0 ) { printf ( "Tips: MQTT Publish Send OK\r\n" ); } break; case MQTT_PKT_PUBREC: //发送Publish消息,平台回复的Rec,设备需回复Rel消息 if ( MQTT_UnPacketPublishRec ( cmd ) == 0 ) { printf ( "Tips: Rev PublishRec\r\n" ); if ( MQTT_PacketPublishRel ( MQTT_PUBLISH_ID, &mqttPacket ) == 0 ) { printf ( "Tips: Send PublishRel\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); } } break; case MQTT_PKT_PUBREL: //收到Publish消息,设备回复Rec后,平台回复的Rel,设备需再回复Comp if ( MQTT_UnPacketPublishRel ( cmd, pkt_id ) == 0 ) { printf ( "Tips: Rev PublishRel\r\n" ); if ( MQTT_PacketPublishComp ( MQTT_PUBLISH_ID, &mqttPacket ) == 0 ) { printf ( "Tips: Send PublishComp\r\n" ); NetApi_SendData ( mqttPacket._data, mqttPacket._len ); MQTT_DeleteBuffer ( &mqttPacket ); } } break; case MQTT_PKT_PUBCOMP: //发送Publish消息,平台返回Rec,设备回复Rel,平台再返回的Comp if ( MQTT_UnPacketPublishComp ( cmd ) == 0 ) { printf ( "Tips: Rev PublishComp\r\n" ); } break; case MQTT_PKT_SUBACK: //发送Subscribe消息的Ack if ( MQTT_UnPacketSubscribe ( cmd ) == 0 ) { printf ( "Tips: MQTT Subscribe OK\r\n" ); } else { printf ( "Tips: MQTT Subscribe Err\r\n" ); } break; case MQTT_PKT_UNSUBACK: //发送UnSubscribe消息的Ack if ( MQTT_UnPacketUnSubscribe ( cmd ) == 0 ) { printf ( "Tips: MQTT UnSubscribe OK\r\n" ); } else { printf ( "Tips: MQTT UnSubscribe Err\r\n" ); } break; default: result = -1; break; } if ( result == -1 ) { return; } dataPtr = strchr ( req_payload, '}' ); //搜索'}' if ( dataPtr != NULL && result != -1 ) //如果找到了 { dataPtr++; while ( *dataPtr >= '0' && *dataPtr <= '9' ) //判断是否是下发的命令控制数据 { numBuf[num++] = *dataPtr++; } num = atoi ( ( const char * ) numBuf ); //转为数值形式 } if ( type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH ) { MQTT_FreeBuffer ( cmdid_topic ); MQTT_FreeBuffer ( req_payload ); } } //---------------------------------------------- void System_Init(){ Esp8266_Rst(); Serial.begin(115200); //usb usart monitor Serial2.begin(115200);//at Net_DefPara();//参数初始化 g_SysStatus = ST_MQTT_INIT; } void System_main() { switch ( g_SysStatus ) { case ST_MQTT_INIT: //初始化参数 ST_MQTT_INITf(); break; case ST_MQTT_ACESSNET: //加入到网络DHCP,解析域名 ST_MQTT_ACESSNETf(); break; case ST_MQTT_TCP: //TCP连接云 183.230.40.39:6002 ST_MQTT_TCPf(); break; case ST_MQTT_CONNECTED://MQTT登录 produceID(user),auth(password),deviceID(clientID) ST_MQTT_CONNECTEDf(); break; case ST_MQTT_SUBSCRIBE://订阅主题 $crep, 其他cmd/# ST_MQTT_SUBSCRIBEf(); break; case ST_MQTT_WORK: //MQTT循环工作状态,publish ST_MQTT_WORKf(); break; } }
#ifndef MAIN_HEAD #define MAIN_HEAD //#include "arduino.h" #include <arduino.h> #include "stdio.h" #include "string.h" #include "AtCommand.h" #include "esp8266.h" #include "MqttKit.h" #include "netapi.h" //--------------------------------- //网络选择 #define CHIP_W5500 0 #define CHIP_SIM900 1 #define CHIP_ESP8266 2 //选择使用什么硬件 #define USE_CHIP CHIP_ESP8266 extern int g_selchip; typedef struct { char saveflag;//存储标志0x55 char wifi_ssid[50]; // = "yan1234"; char wifi_password[50]; // = "12345678"; char host_ip[50]; // = "mqtt.heclouds.com"; char host_port[10]; //"6002" char mqtt_clientid[20]; //"622913695":deviceID char mqtt_username[20]; //"368763":producei char mqtt_passwd[20]; // "gate":author char mqtt_subtopic1[50];// "$crep" //除onenet外,其他不支持$ char mqtt_subtopic2[50];// "cmd/#" char mqtt_pubtopic1[50];// "$dp" //除onenet外,其他不支持$ char mqtt_pubtopic2[50];// "data/gate" } SYS_PARA; extern SYS_PARA g_SysPara; void ReSet_SystemStatus ( void ); void System_Init(); void System_main(); #endif
#ifndef _TYPE_H_ #define _TYPE_H_ #define MAX_SOCK_NUM 8 /**< Maxmium number of socket */ #define int8 char #define vint8 volatile char #define uint8 unsigned char #define vuint8 volatile unsigned char #define int16 int #define uint16 unsigned short #define int32 long #define uint32 unsigned long #define u_char uint8 #define SOCKET uint8 /* typedef union _un_l2cval { u_long lVal; u_char cVal[4]; } un_l2cval; typedef union _un_i2cval { u_int iVal; u_char cVal[2]; } un_i2cval; */ #define uint1 unsigned char #endif /* _TYPE_H_ */