目录
点击这里查看所有博文
本系列博客所述资料均来自合宙官方
,并不是本人原创(只有博客是自己写的),csdk只是得到了口头的允许公开授权
。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法
。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。
本系列博客基于紫光展锐的RDA8910 LTE Cat 1
bis芯片平台开发。理论上适用于合宙的Air720U、Air724U、广和通L610以及安信可的cat-01模块。
各个厂家的部分配置文件可能不一样,也许会导致设备出现奇怪的问题,其他的模块我也不确定能不能用,自行测试。但是有一点编译下载和监视流程基本一样
,可供参考。
先不管支不支持,如果你用的模块是是紫光展锐的RDA8910,那都不妨一试,也许会有意外收获(也有可能变砖,慎重!!!
)。
我使用的是Air724UG
开发板,如果在其他模块上不能用,那也不要强怼,也许是开发包不兼容吧。这里的代码是没有问题的。例程仅供参考!
一、前言
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
物联网应用中都离不开MQTT。玩物联网的人不会用MQTT那就是没有灵魂。目前官方提供的CSDK也是没有
MQTT库的,所以为了大家,在下花了一点时间移植了一套开源的用于嵌入式领域的MQTT库。
有人讲你那个HTTP库都自己写了,这个MQTT库怎么不自己写。这里声明一下HTTP的库不是我想自己写的,是因为我没找到合适的开源的HTTP库,移植起来很困难。被逼无奈自己写了一个简单的请求库,用在嵌入式平台正常情况下也够用了。
闲话少说,开始干正事。
二、编写测试程序
2.1、了解本例程所用到的函数
使用MQTT服务需要包含#include "MQTTClient.h""
头文件,我们这里只用到了7个函数,分别是:
/**新的网络设置
@param n:指向网络结构的指针,包含网络的配置信息。
*@return 无
*/
void NewNetwork
(Network *n)
/***@简短连接网络功能
@param n:指向网络结构的指针
包含网络的配置信息。
ip:服务器IP。
port:服务器端口。
*/
int ConnectNetwork
(Network *n, char *ip, int port)
/*创建一个MQTT客户端对象
@参数客户端
*@参数网络
*@param command_timeout_ms
*@参数
*/
/MQTT Connect-在网络上发送MQTT连接数据包并等待Connack
*调用此对象之前,必须将nework对象连接到网络端点
*@param选项-连接选项
*@返回成功代码
*/
- DLLExport int
MQTTConnect
(MQTTClient* client, MQTTPacket_connectData* options);
/*MQTT订阅-发送MQTT订阅数据包,并在返回之前等待suback。
@param client-要使用的客户端对象
*@param topicFilter-要订阅的主题过滤器
*@param消息-要发送的消息
*@返回成功代码
*/
- DLLExport int
MQTTSubscribe
(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler);
/*MQTT发布-发送MQTT发布数据包,并等待所有ack完成所有QoS
@param client-要使用的客户端对象
*@param主题-要发布到的主题
*@param消息-要发送的消息
*@返回成功代码
*/
- DLLExport int
MQTTPublish
(MQTTClient* client, const char*, MQTTMessage*);
/需要死循环调用,这个函数负责库内部一些事件处理。
*@param client-要使用的客户端对象
*@param time-产生的时间(以毫秒为单位)
*@返回成功代码
*/
- DLLExport int
MQTTYield
(MQTTClient* client, int time);
2.2、编写初始化程序
初始化程序负责建立socket套接字、连接网络、初始化MQTT对象、连接MQTT服务这几件事
1 2 3 4 5 6 7 8 9 10 11 12
| NewNetwork(&myNet); ConnectNetwork(&myNet, MQTT_IP, MQTT_PORT); MQTTClientInit(&myclient, &myNet, 1000, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf)); MQTTPacket_connectData data = MQTTPacket_connectData_initializer; data.willFlag = 0; data.MQTTVersion = 3; data.clientID.cstring = (char *)"RDA8910 MQTT Test"; data.username.cstring = "Air724UG"; data.password.cstring = NULL; data.keepAliveInterval = 120; data.cleansession = 1; int rc = MQTTConnect(&myclient, &data);
|
2.3、编写订阅消息程序
订阅程序分成两块。第一块是向服务器发送订阅消息。
1 2
| rc = MQTTSubscribe(&myclient, "FX", QOS1, MQTT_CB); iot_debug_print("[MQTT_Test] Subscribed %d\r\n", rc);
|
第二块是根据服务器下发的订阅消息,解析报文。
1 2 3 4 5 6 7 8 9 10
| void MQTT_CB(MessageData *md) { MQTTMessage *message = md->message; uint32 datalen = (int)message->payloadlen;
uint8 data[20] = {0}; memcpy(data, (char *)message->payload, datalen);
iot_debug_print("[MQTT_Test] topicName:%s,data:%s,datalen:%d", md->topicName, data, datalen); }
|
2.4、编写发布消息程序
在任务内循环发布不同的消息,5s发一次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static void Publish(void *param) { char PubData[20] = {0}; uint8 num = 0; uint8 datalen = 0; MQTTMessage message = {0}; message.qos = QOS0; while (1) { datalen = sprintf(PubData, "RDA8910 Sent:%d", num); PubData[datalen] = '\0'; message.payload = PubData; message.payloadlen = datalen; MQTTPublish(&myclient, "RDA8910", &message); num += 1; iot_os_sleep(5000); } }
|
三、编译并下载程序
完整代码中上线会订阅FX
这个主题,紧接着直接向RDA8910
这个主题发送一条RDA8910 Online!
,随后会定时发送其他的消息。
完整代码在这,自取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
#include "string.h"
#include "osi_log.h" #include "osi_api.h"
#include "am_openat.h" #include "am_openat_vat.h" #include "am_openat_common.h"
#include "iot_debug.h" #include "iot_uart.h" #include "iot_os.h" #include "iot_gpio.h" #include "iot_pmd.h" #include "iot_adc.h" #include "iot_vat.h" #include "iot_network.h" #include "iot_socket.h"
#include "MQTTClient.h"
HANDLE TestTask_HANDLE = NULL; uint8 NetWorkCbMessage = 0;
#define MQTT_IP "换成自己的ip" #define MQTT_PORT 1883
Network myNet; MQTTClient myclient; unsigned char sendbuf[1024] = {0}; unsigned char recvbuf[1024] = {0};
void MQTT_CB(MessageData *md) { MQTTMessage *message = md->message; uint32 datalen = (int)message->payloadlen;
uint8 data[20] = {0}; memcpy(data, (char *)message->payload, datalen);
iot_debug_print("[MQTT_Test] topicName:%s,data:%s,datalen:%d", md->topicName, data, datalen); } static void Publish(void *param) { char PubData[20] = {0}; uint8 num = 0; uint8 datalen = 0; MQTTMessage message = {0}; message.qos = QOS0; while (1) { datalen = sprintf(PubData, "RDA8910 Sent:%d", num); PubData[datalen] = '\0'; message.payload = PubData; message.payloadlen = datalen; MQTTPublish(&myclient, "RDA8910", &message); num += 1; iot_os_sleep(5000); } } static void TestTask(void *param) { bool NetLink = FALSE; while (NetLink == FALSE) { T_OPENAT_NETWORK_CONNECT networkparam = {0}; switch (NetWorkCbMessage) { case OPENAT_NETWORK_DISCONNECT: iot_debug_print("[socket] OPENAT_NETWORK_DISCONNECT"); iot_os_sleep(10000); break; case OPENAT_NETWORK_READY: iot_debug_print("[socket] OPENAT_NETWORK_READY"); memcpy(networkparam.apn, "CMNET", strlen("CMNET")); iot_network_connect(&networkparam); iot_os_sleep(500); break; case OPENAT_NETWORK_LINKED: iot_debug_print("[socket] OPENAT_NETWORK_LINKED"); NetLink = TRUE; break; } } if (NetLink == TRUE) { NewNetwork(&myNet); ConnectNetwork(&myNet, MQTT_IP, MQTT_PORT); MQTTClientInit(&myclient, &myNet, 1000, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf)); MQTTPacket_connectData data = MQTTPacket_connectData_initializer; data.willFlag = 0; data.MQTTVersion = 3; data.clientID.cstring = (char *)"RDA8910 MQTT Test"; data.username.cstring = "Air724UG"; data.password.cstring = NULL; data.keepAliveInterval = 120; data.cleansession = 1; int rc = MQTTConnect(&myclient, &data); iot_debug_print("[MQTT_Test] Connected %d\r\n", rc); rc = MQTTSubscribe(&myclient, "FX", QOS1, MQTT_CB); iot_debug_print("[MQTT_Test] Subscribed %d\r\n", rc);
MQTTMessage message = {0}; message.qos = QOS0; message.payload = "RDA8910 Online!"; message.payloadlen = sizeof("RDA8910 Online!"); MQTTPublish(&myclient, "RDA8910", &message); iot_os_create_task(Publish, NULL, 2048, 10, OPENAT_OS_CREATE_DEFAULT, "Publish"); while (1) { MQTTYield(&myclient, 500); iot_os_sleep(500); } } iot_os_delete_task(TestTask_HANDLE); } static void NetWorkCb(E_OPENAT_NETWORK_STATE state) { NetWorkCbMessage = state; }
int appimg_enter(void *param) { iot_os_sleep(10000); iot_network_set_cb(NetWorkCb); TestTask_HANDLE = iot_os_create_task(TestTask, NULL, 2048, 10, OPENAT_OS_CREATE_DEFAULT, "TestTask"); return 0; }
void appimg_exit(void) { OSI_LOGI(0, "application image exit"); }
|
四、分析结果
我这里使用MQTT.fx
测试。使用MQTT.fx订阅RDA8910
这个主题,并且随机向FX这个主题发布消息。
可以看到MQTT.fx收到了开发板发布的消息。
开发板也能收到MQTT.fx发布的消息。
通过EMQ的控制台,看到开发板11:01
开始上线。现在时间看右小角是11:55
,运行了接近一个小时。也没出现掉线现象。稳定性也还是可以的。
五、总结
除了上面我们使用的函数外。MQTT还具有以下其他的库。这里做简略介绍
/MQTT Connect-在网络上发送MQTT连接数据包并等待Connack
*调用此对象之前,必须将nework对象连接到网络端点
*@param选项-连接选项
*@返回成功代码
*/
- DLLExport int
MQTTConnectWithResults
(MQTTClient* client, MQTTPacket_connectData* options,
MQTTConnackData* data);
/*MQTT SetMessageHandler-设置或删除每个主题的消息处理程序
@param client-要使用的客户端对象
*@param topicFilter-主题过滤器为设置消息处理程序
*@param messageHandler-指向消息处理程序函数的指针或要删除的NULL
*@返回成功代码
*/
- DLLExport int
MQTTSetMessageHandler
(MQTTClient* c, const char* topicFilter, messageHandler messageHandler);
/MQTT订阅-发送MQTT订阅数据包,并在返回之前等待suback。
*@param client-要使用的客户端对象
*@param topicFilter-要订阅的主题过滤器
*@param消息-要发送的消息
*@param数据-子包授予的QoS返回
*@返回成功代码
*/
- DLLExport int
MQTTSubscribeWithResults
(MQTTClient* client, const char* topicFilter, enum QoS, messageHandler, MQTTSubackData* data);
/MQTT订阅-发送MQTT取消订阅数据包并等待取消回复,然后再返回。
*@param client-要使用的客户端对象
*@param topicFilter-要取消订阅的主题过滤器
*@返回成功代码
*/
DLLExport int MQTTUnsubscribe
(MQTTClient* client, const char* topicFilter);
/*MQTT断开连接-发送MQTT断开连接数据包并关闭连接
@param client-要使用的客户端对象
@返回成功代码
*/
DLLExport int MQTTDisconnect
(MQTTClient* client);
/*MQTT已连接
@param client-要使用的客户端对象
@return真值,指示客户端是否连接到服务器
*/
DLLExport int MQTTIsConnected
(MQTTClient* client);
不会下载的点击这里,进去查看我的RDA8910 CSDK二次开发入门教程
专题第一篇博文1、RDA8910CSDK二次开发:环境搭建
里面讲了怎么下载
这里只是我的学习笔记,拿出来给大家分享,欢迎大家批评指正,本篇教程到此结束