MqttInfo接口说明
一、使用示例
1. 主站测试示例
连接MQTT服务器,订阅PD消息,推送MD消息
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include "mqtt_info.h"
#define MQTT_URL "tcp://mqtt.eclipse.org:1883"
#define CLIENT_ID "ExampleClientHost"
#define USER_NAME "user"
#define PASSWORD "password"
#define TOPIC_PDINFO "PDInfo"
#define TOPIC_MDINFO "MDInfo"
// 收到PD消息回调函数(参数,主题,数据段,长度)
void CallbackRecvPdData(void *arg, const char* topic, const uint8_t* data, const int len)
{
// 判定主题是否为PD消息
if(strcmp(topic, TOPIC_PDINFO) != 0) {
return;
}
// 解析数据段
DatavSegment dsv;
dsv.SetDataPacket(len, data);
DatavSegment::AddrValue_T da[32];
int num = dsv.GetDataPoint(32, da);
// 打印收到的PD消息
for(int i = 0; i < num; i++) {
printf("addr: %d, value: %d\n", da[i].addr, da[i].value);
}
}
uint64_t GetSysMs() // 获取系统毫秒时间戳
{
struct timeval tv;
gettimeofday(&tv, NULL); // 获取当前系统时间
uint64_t sec = tv.tv_sec;
uint64_t usec = tv.tv_usec;
return sec*1000 + usec/1000;
}
void HostTest()
{
// 创建MQTT客户端
MqttInfo *pmqtt =
new MqttInfo(MQTT_URL, CLIENT_ID, USER_NAME, PASSWORD);
// 设置接收PD消息回调函数
pmqtt->SetRecvPdDataCallback(CallbackRecvPdData, NULL);
pmqtt->Subscribe(TOPIC_PDINFO, 0);
// 循环推送MD写消息
while(1) {
// 数据段
DatavSegment ds;
ds.AddDataPoint(0x0000, 0x00); // 添加数据点 - 地址0x0000,值0x00
ds.AddDataPoint(0x0001, 0x01); // 添加数据点 - 地址0x0001,值0x01
ds.AddDataPoint(0x0002, 0x02); // 添加数据点 - 地址0x0002,值0x02
ds.AddDataPoint(0x0003, 0x03); // 添加数据点 - 地址0x0003,值0x03
ds.AddDataPoint(0x0004, 0x04); // 添加数据点 - 地址0x0004,值0x04
ds.AddDataPoint(0x1000, 0x05); // 添加数据点 - 地址0x1000,值0x05
ds.AddDataPoint(0x1001, 0x06); // 添加数据点 - 地址0x1001,值0x06
ds.AddDataPoint(0x1002, 0x07); // 添加数据点 - 地址0x1002,值0x07
ds.AddDataPoint(0x1003, 0x08); // 添加数据点 - 地址0x1003,值0x08
ds.AddDataPoint(0x1004, 0x09); // 添加数据点 - 地址0x1004,值0x09
ds.AddDataPoint(0x2000, 0x0A); // 添加数据点 - 地址0x2000,值0x0A
ds.AddDataPoint(0x2001, 0x0B); // 添加数据点 - 地址0x2001,值0x0B
ds.AddDataPoint(0x2002, 0x0C); // 添加数据点 - 地址0x2002,值0x0C
// 推送MD写消息
pmqtt->PublishMdWrInfo(TOPIC_MDINFO, GetSysMs(), &ds, 0);
sleep(10);
}
delete pmqtt;
}
int main()
{
HostTest();
return 0;
}
2. 从站测试示例
连接MQTT服务器,订阅MD消息,推送PD消息
#include <iostream>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include "mqtt_info.h"
#define MQTT_URL "tcp://mqtt.eclipse.org:1883"
#define CLIENT_ID "ExampleClientSlave"
#define USER_NAME "user"
#define PASSWORD "password"
#define TOPIC_PDINFO "PDInfo"
#define TOPIC_MDINFO "MDInfo"
// 收到MD消息回调函数指针(参数,主题,MD消息类别,,数据段,长度)
void CallbackRecvMdData(void *arg, const char* topic, const MDType_T type, const uint8_t* data, const int len)
{
// 判定主题是否为MD消息
if(strcmp(topic, TOPIC_MDINFO) != 0) {
return;
}
// MD读消息
if(type == MD_RE) {
// 解析数据段
DataSegment ds;
ds.SetDataPacket(len, data);
int addr[32];
int num = ds.GetDataPoint(32, addr);
// 打印收到的MD读消息
for(int i = 0; i < num; i++) {
printf("addr: %d\n", addr[i]);
}
}
// MD写消息
else if(type == MD_WR) {
// 解析数据段
DatavSegment dsv;
dsv.SetDataPacket(len, data);
DatavSegment::AddrValue_T da[32];
int num = dsv.GetDataPoint(32, da);
// 打印收到的MD写消息
for(int i = 0; i < num; i++) {
printf("addr: %d, value: %d\n", da[i].addr, da[i].value);
}
}
}
uint64_t GetSysMs() // 获取系统毫秒时间戳
{
struct timeval tv;
gettimeofday(&tv, NULL); // 获取当前系统时间
uint64_t sec = tv.tv_sec;
uint64_t usec = tv.tv_usec;
return sec*1000 + usec/1000;
}
void SlaveTest()
{
// 创建MQTT客户端
MqttInfo *pmqtt =
new MqttInfo(MQTT_URL, CLIENT_ID, USER_NAME, PASSWORD);
// 设置接收MD消息回调函数
pmqtt->SetRecvMdDataCallback(CallbackRecvMdData, NULL);
// 订阅MD消息
pmqtt->Subscribe(TOPIC_MDINFO, 0);
// 循环推送PD消息
while(1) {
// 数据段
DatavSegment ds;
ds.AddDataPoint(0x0000, 0x00); // 添加数据点 - 地址0x0000,值0x00
ds.AddDataPoint(0x0001, 0x01); // 添加数据点 - 地址0x0001,值0x01
ds.AddDataPoint(0x0002, 0x02); // 添加数据点 - 地址0x0002,值0x02
ds.AddDataPoint(0x0003, 0x03); // 添加数据点 - 地址0x0003,值0x03
ds.AddDataPoint(0x0014, 0x04); // 添加数据点 - 地址0x0014,值0x04
ds.AddDataPoint(0x0015, 0x05); // 添加数据点 - 地址0x0015,值0x05
ds.AddDataPoint(0x0016, 0x06); // 添加数据点 - 地址0x0016,值0x06
ds.AddDataPoint(0x0027, 0x07); // 添加数据点 - 地址0x0027,值0x07
ds.AddDataPoint(0x0028, 0x08); // 添加数据点 - 地址0x0028,值0x08
ds.AddDataPoint(0x0039, 0x09); // 添加数据点 - 地址0x0039,值0x09
// 推送PD消息
pmqtt->PublishPdInfo(TOPIC_PDINFO, GetSysMs(), &ds, 0);
sleep(1);
}
delete pmqtt;
}
int main()
{
SlaveTest();
return 0;
}
二、DatavSegment类
带数据字节的数据段类,该类用于处理带数据字节的数据段(MD写消息、PD消息),包括组包和解包
1. 数据对象结构体
// 数据对象结构体
typedef struct DatavObj_ {
int startaddr = 0; // 起始地址
int size = 0; // 数据长度
std::vector<uint16_t> data; // 数据
} DatavObj_T;
2. 地址值结构体
3. 构造函数
构造函数,用于创建带有数据字节的数据段
- 参数
- 无
4. 析构函数
5. 组包时-清空数据区
- 参数
- 无;
- 返回值
- 无
6. 组包时-添加数据点
/**
* @brief 添加数据点(组包时使用)
*
* @param addr 地址
* @param value 数据
* @param cover 是否覆盖(选择覆盖固定返回添加成功)
*
* @return 1添加成功;-1添加失败(数据点已存在)
*/
int AddDataPoint(const int addr, const uint16_t value, const bool cover = true);
- 参数
- addr 地址
- value 数据
- cover 是否覆盖(选择覆盖固定返回添加成功)
- 返回值
- 1添加成功;-1添加失败(数据点已存在)
7. 组包时-添加连续数据点
/**
* @brief 添加连续数据点(组包时使用)
*
* @param startaddr 起始地址
* @param num 数据点个数
* @param *value 数据指针
* @param cover 是否覆盖(选择覆盖固定返回添加成功)
*
* @return 1添加成功;-1添加失败(数据点已存在)
*/
int AddDataPoints(const int startaddr, const int num, const uint16_t *value, const bool cover = true);
- 参数
- startaddr 起始地址
- num 数据点个数
- *value 数据指针
- cover 是否覆盖(选择覆盖固定返回添加成功)
- 返回值
- 1添加成功;-1添加失败(数据点已存在)
8. 组包时-将数据点生成数据包
/**
* @brief 将数据点生成数据包(组包时使用)
*
* @param maxlen 允许的数据包最大长度
* @param *buf 输出参数,数据包存放的指针
*
* @return 数据包实际长度,-1表示数据包长度超过maxlen
*/
int MakeDataPacket(const int maxlen, uint8_t *buf);
- 参数
- maxlen 允许的数据包最大长度
- *buf 输出参数,数据包存放的指针
- 返回值
- 数据包实际长度,-1表示数据包长度超过maxlen
9. 解包时-设置数据包内容
/**
* @brief 设置数据包内容(解包时使用)
*
* @param len 数据包长度
* @param *buf 数据包指针
*
* @return -1设置失败包长度超范围;1设置成功
*/
int SetDataPacket(const int len, const uint8_t *buf);
- 参数
- len 数据包长度
- *buf 数据包指针
- 返回值
- -1设置失败包长度超范围;1设置成功
10. 解包时-获取数据点
/**
* @brief 获取数据点(解包时使用)
*
* @param maxnum 允许的最大数据点个数
* @param *addrvalue 输出参数,数据点地址值存放的指针
*
* @return 数据点实际个数,-1表示数据点个数超过maxnum
*/
int GetDataPoint(const int maxnum, AddrValue_T *addrvalue);
- 参数
- maxnum 允许的最大数据点个数
- *addrvalue 输出参数,数据点地址值存放的指针
- 返回值
- 数据点实际个数,-1表示数据点个数超过maxnum
11. 解包时-获取数据对象
/**
* @brief 获取数据对象(解包时使用)
*
* @param maxnum 允许的最大数据对象个数
* @param *dataobj 输出参数,数据对象存放的指针
*
* @return 数据对象实际个数,-1表示数据对象个数超过maxnum
*/
int GetDataObject(const int maxnum, DatavObj_T *dataobj);
- 参数
- maxnum 允许的最大数据对象个数
- *dataobj 输出参数,数据对象存放的指针
- 返回值
- 数据对象实际个数,-1表示数据对象个数超过maxnum
三、DataSegment类
不带数据字节的数据段类,该类用于处理不带数据字节的数据段(MD读消息),包括组包和解包
1. 数据对象结构体
2. 构造函数
构造函数,用于创建带有数据字节的数据段
- 参数
- 无
3. 析构函数
4. 组包时-清空数据区
- 参数
- 无;
- 返回值
- 无
5. 组包时-添加数据点
- 参数
- addr 地址
- 返回值
- 无
6. 组包时-添加连续数据点
/**
* @brief 添加连续数据点(组包时使用)
*
* @param startaddr 起始地址
* @param num 数据点个数
*
* @return 无
*/
void AddDataPoints(const int startaddr, const int num);
- 参数
- startaddr 起始地址
- num 数据点个数
- 返回值
- 无
7. 组包时-将数据点生成数据包
/**
* @brief 将数据点生成数据包(组包时使用)
*
* @param maxlen 允许的数据包最大长度
* @param *buf 输出参数,数据包存放的指针
*
* @return 数据包实际长度,-1表示数据包长度超过maxlen
*/
int MakeDataPacket(const int maxlen, uint8_t *buf);
- 参数
- maxlen 允许的数据包最大长度
- *buf 输出参数,数据包存放的指针
- 返回值
- 数据包实际长度,-1表示数据包长度超过maxlen
8. 解包时-设置数据包内容
/**
* @brief 设置数据包内容(解包时使用)
*
* @param len 数据包长度
* @param *buf 数据包指针
*
* @return -1设置失败包长度超范围;1设置成功
*/
int SetDataPacket(const int len, const uint8_t *buf);
- 参数
- len 数据包长度
- *buf 数据包指针
- 返回值
- -1设置失败包长度超范围;1设置成功
9. 解包时-获取数据点
/**
* @brief 获取数据点(解包时使用)
*
* @param maxnum 允许的最大数据点个数
* @param *addr 输出参数,数据点地址存放的指针
*
* @return 数据点实际个数,-1表示数据点个数超过maxnum
*/
int GetDataPoint(const int maxnum, int *addr);
- 参数
- maxnum 允许的最大数据点个数
- *addr 输出参数,数据点地址存放的指针
- 返回值
- 数据点实际个数,-1表示数据点个数超过maxnum
10. 解包时-获取数据对象
/**
* @brief 获取数据对象(解包时使用)
*
* @param maxnum 允许的最大数据对象个数
* @param *dataobj 输出参数,数据对象存放的指针
*
* @return 数据对象实际个数,-1表示数据对象个数超过maxnum
*/
int GetDataObject(const int maxnum, DataObj_T *dataobj);
- 参数
- maxnum 允许的最大数据对象个数
- *dataobj 输出参数,数据对象存放的指针
- 返回值
- 数据对象实际个数,-1表示数据对象个数超过maxnum
四、MqttInfo类
1. 构造函数
/**
* @brief 构造函数
*
* @param server_url MQTT服务器URL,例"tcp://123.456.789.123:1883";
* @param client_id 客户端ID;
* @param user_name 用户名;
* @param password 密码;
*/
MqttInfo(const char* server_url, const char* client_id,
const char* user_name, const char* password);
- 参数
- server_url MQTT服务器URL,例"tcp://123.456.789.123:1883";
- client_id 客户端ID;
- user_name 用户名;
- password 密码;
- 返回值
2. 析构函数
3. 自动重连时间间隔设置
- 参数
- ms 重连时间间隔(ms)
- 返回值
- 空
4. 设置订阅接收数据回调函数
/**
* @brief 设置订阅接收数据回调函数
*
* @param callback 回调函数指针
* @param arg 回调函数参数
*
* @return 无
*/
void SetRecvPdDataCallback(fpRecvPdData callback, void *arg);
void SetRecvMdDataCallback(fpRecvMdData callback, void *arg);
// 收到PD消息回调函数指针(参数,主题,数据段,长度)
typedef void (*fpRecvPdData)
(void *arg, const char* topic, const uint8_t* data, const int len);
// 收到MD消息回调函数指针(参数,主题,MD消息类别,数据段,长度)
typedef void (*fpRecvMdData)
(void *arg, const char* topic, const MDType_T type, const uint8_t* data, const int len);
- 参数
- callback 回调函数指针
- arg 回调函数参数
- 返回值
- 空
5. 订阅函数
/**
* @brief 订阅函数
*
* @param topic 订阅主题,可能包含通配符
* @param qos 订阅所请求的服务质量
*
* @return 无
*/
void Subscribe(const char* topic, int qos = 0);
- 参数
- topic 订阅主题,可能包含通配符
- qos 订阅所请求的服务质量
- 返回值
- 空
6. 推送PD消息函数
/**
* @brief 推送PD消息函数
*
* @param topic 推送主题
* @param time 时间戳(自1970年1月1日以来的毫秒时间戳)
* @param *datas 数据段
* @param qos 推送消息的服务质量
*
* @return 无
*/
void PublishPdInfo(const char* topic, const uint64_t time, const DatavSegment *datas, int qos = 0);
- 参数
- topic 订阅主题,可能包含通配符
- time 时间戳(自1970年1月1日以来的毫秒时间戳)
- *datas 数据段
- qos 推送消息的服务质量
- 返回值
- 空
7. 推送MD写消息函数
/**
* @brief 推送MD写消息函数
*
* @param topic 推送主题
* @param time 时间戳(自1970年1月1日以来的毫秒时间戳)
* @param *datas 数据段
* @param qos 推送消息的服务质量
*
* @return 无
*/
void PublishMdWrInfo(const char* topic, const uint64_t time, const DatavSegment *datas, int qos = 0);
- 参数
- topic 订阅主题,可能包含通配符
- time 时间戳(自1970年1月1日以来的毫秒时间戳)
- *datas 数据段
- qos 推送消息的服务质量
- 返回值
- 空
8. 推送MD读消息函数
/**
* @brief 推送MD读消息函数
*
* @param topic 推送主题
* @param time 时间戳(自1970年1月1日以来的毫秒时间戳)
* @param *datas 数据段
* @param qos 推送消息的服务质量
*
* @return 无
*/
void PublishMdReInfo(const char* topic, const uint64_t time, const DataSegment *datas, int qos = 0);
- 参数
- topic 订阅主题,可能包含通配符
- time 时间戳(自1970年1月1日以来的毫秒时间戳)
- *datas 数据段
- qos 推送消息的服务质量
- 返回值
- 空
9. 获取当前MQTT连接状态
- 参数
- 无
- 返回值
- 1已连接;-1未连接