嵌入式开发之移植MQTT到RK3568

嵌入式开发之移植MQTT到RK3568 thatk 2024-02-18 17:07:58 382

文章目录

前言

MQTT是一种基于发布/订阅模式的”轻量级”通讯协议。它最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,主要面向物联网、NVR存储、工控平板、工业检测、云终端、车载中控等行业定制市场。本人移植MQTT到RK3568的目的是将飞凌的RK3568开发板作为一个物联网的终端,来实时采集相关数据(例如:温度等)。

本次移植的软硬件环境如下:

开发环境操作系统: Ubuntu 18.04 64位
开发环境工具:Qt 5.14.2
交叉工具链:aarch64-linux-gnu
开发板芯片:飞凌 RK3568-C
开发板内核:linux-4.1.19
手机端工具:MQTT Dashboard

一、下载qmqtt源码

github官网下载qmqtt源码(地址GitHub - emqx/qmqtt: MQTT client for Qt)。

下载完成后, 解压qmqtt-master.zip到本地文件夹。

forlinx@ubuntu:~/3568/mqtt$ sudo unzip qmqtt-master.zip

forlinx@ubuntu:~/3568/mqtt/qmqtt-master$ ls
CMakeLists.txt  examples      qmqtt.pri  README.md     tests
edl-v10         LICENSE       qmqtt.pro  src
epl-v10         qmqtt-API.md  qmqtt.qbs  sync.profile

二、编译库文件

启动Qt-5.14.2,打开qmqtt.pro,配置为rk3568交叉编译环境,编译为Release下的message库。

修改qmqtt-master/src/mqtt/qmqtt.pro配置文件,设置设置库文件的输出目录为mqtt_lib。

# qmqtt-master/src/mqtt/qmqtt.pro

TARGET = QtQmqtt
QT = core network
qtHaveModule(websockets): QMQTT_WEBSOCKETS: QT += websockets

DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII

# CONFIG += QMQTT_NO_SSL

HEADERS += \
    $$PWD/qmqtt_global.h \
    $$PWD/qmqtt.h

include(qmqtt.pri)

HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS

load(qt_module)

# Set the output directory of library files
DESTDIR = $$MODULE_BASE_OUTDIR/../mqtt_lib

编译完成后,在mqtt_lib目录下生成库文件libQt5Qmqtt.so.1.0.2,详细查看如下:

root@ubuntu:/home/forlinx/3568/mqtt/mqtt_lib# ls -all
total 6540
drwxr-xr-x 3 root root    4096 Mar 11 18:19 .
drwx------ 4 root root    4096 Mar 11 18:26 ..
-rw-r--r-- 1 root root     809 Mar 11 18:26 libQt5Qmqtt.la
-rw-r--r-- 1 root root    1651 Mar 11 18:26 libQt5Qmqtt.prl
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so -> libQt5Qmqtt.so.1.0.2
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so.1 -> libQt5Qmqtt.so.1.0.2
lrwxrwxrwx 1 root root      20 Mar 11 18:19 libQt5Qmqtt.so.1.0 -> libQt5Qmqtt.so.1.0.2
-rwxr-xr-x 1 root root  285448 Mar 11 18:19 libQt5Qmqtt.so.1.0.2
-rw-r--r-- 1 root root 6388344 Mar 11 18:19 libQt5Qmqtt.so.1.0.2.debug
drwxr-xr-x 2 root root    4096 Mar 11 18:19 pkgconfig

三、移植到RK3568

3.1 移植动态库libQt5Qmqtt

复制Ubuntu18.04下交叉编译出的动态库libQt5Qmqtt.so.1.0.2,放到开发板/usr/lib目录下并对应的配置软链接。

cd /usr/lib
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so.1
sudo ln -s libQt5Qmqtt.so.1.0.2 libQt5Qmqtt.so.1.0

若未正确配置软链接,则启动app客户端时会出现错误:

./mqtt_demo: error while loading shared libraries: libQt5Qmqtt.so.1: cannot open shared object file: No such file or directory

四、联机测试

4.1 制作demo

4.1.1 创建demo新项目

创建一个Widget应用程序,其控件布局如下:

4.1.2 添加network模块支持

在mqtt_demo项目的pro文件中添加对网络模块的支持。

QT += network

4.1.3 添加qmqtt外部库

库文件位于mqtt_lib下,mqtt头文件位于源码的src/mqtt目录下,浏览到对应的目录,即可。

4.1.4 功能实现

演示工具的源码已上传到github,链接地址:GitHub - lingdan2008/mqtt_demo。

mqtt_demo.pro文件

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target



unix:!macx: LIBS += -L$$PWD/../../mqtt_lib/ -lQt5Qmqtt

INCLUDEPATH += $$PWD/../../qmqtt-master/src/mqtt
DEPENDPATH += $$PWD/../../qmqtt-master/src/mqtt

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

// add necessary includes here
#include <qmqtt.h>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_Connect_clicked();

    void on_pushButton_Subscribe_clicked();

    void on_pushButton_Publish_clicked();


    void slotConnectedMQTT();

    void slotDisconnectedMQTT();

    void slotSubscribedMQTT(QString sTopic, quint8 qos = 0);

    void slotReceivedMessageByMQTT(QMQTT::Message sMsg);

private:
    Ui::Widget *ui;

    // the mqtt client pointer
    QMQTT::Client *m_pMQTT = nullptr;
};
#endif // WIDGET_H

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setWindowTitle(tr("MQTT Demo"));

    ui->pushButton_Connect->setEnabled(true);
    ui->pushButton_Publish->setEnabled(false);
    ui->pushButton_Subscribe->setEnabled(false);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_Connect_clicked()
{
    if(tr("Connect") == ui->pushButton_Connect->text().trimmed()) {
        ui->pushButton_Publish->setEnabled(true);
        ui->pushButton_Subscribe->setEnabled(true);

        ui->pushButton_Connect->setText(tr("Disconnect"));

        QString sHost = ui->lineEdit_Host->text().trimmed();
        int nPort = ui->lineEdit_Port->text().trimmed().toInt();

        // Create a QMQTT client
        if(nullptr == m_pMQTT) {
            m_pMQTT = new QMQTT::Client(QHostAddress(sHost), nPort);
            Q_ASSERT(m_pMQTT);
        }

        // Signal-slot initialization
        std::vector<bool> vecConnect;

        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(connected()), this, SLOT(slotConnectedMQTT())));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(disconnected()), this, SLOT(slotDisconnectedMQTT())));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(subscribed(QString, quint8)), this, SLOT(slotSubscribedMQTT(QString, quint8))));
        vecConnect.push_back(QObject::connect(m_pMQTT, SIGNAL(received(QMQTT::Message)), this, SLOT(slotReceivedMessageByMQTT(QMQTT::Message))));

        for(int i=0; i<(int)vecConnect.size(); i++) {
            Q_ASSERT(vecConnect.at(i));
        }

        // Connect to host
        m_pMQTT->setCleanSession(true);
        m_pMQTT->connectToHost();
    }
    else {
        ui->pushButton_Publish->setEnabled(false);
        ui->pushButton_Subscribe->setEnabled(false);

        ui->pushButton_Connect->setText(tr("Connect"));
        m_pMQTT->disconnectFromHost();

        delete m_pMQTT;
        m_pMQTT = nullptr;
    }



}

void Widget::on_pushButton_Subscribe_clicked()
{
    // Subscribe a topic
    QString sTopic = ui->lineEdit_SubscribeTopic->text().trimmed();
    m_pMQTT->subscribe(sTopic, 1);
}

void Widget::on_pushButton_Publish_clicked()
{
    // Publish a topic
    QMQTT::Message sMsg;
    QString sTopic = ui->lineEdit_PublishTopic->text().trimmed();
    QString sContent = ui->lineEdit_PublishContent->text().trimmed();

    sMsg.setTopic(sTopic);
    sMsg.setPayload(sContent.toLocal8Bit());

    m_pMQTT->publish(sMsg);
}

void Widget::slotConnectedMQTT()
{
    ui->textBrowser_ReceivedMessage->append(tr("Connection succeeded"));
}

void Widget::slotDisconnectedMQTT()
{
    ui->textBrowser_ReceivedMessage->append(tr("Connection disconnected"));
}

void Widget::slotSubscribedMQTT(QString sTopic,quint8 qos)
{
    Q_UNUSED(sTopic);
    Q_UNUSED(qos);

    QString sMsg = "Subscribe Topic ";
    sMsg += ui->lineEdit_SubscribeTopic->text();
    sMsg += " Succeeded";
    ui->textBrowser_ReceivedMessage->append(sMsg);
}

void Widget::slotReceivedMessageByMQTT(QMQTT::Message sMsg)
{
    QString sPayload = sMsg.payload();
    QString sMsgTotal = "Topic:";

    sMsgTotal += sMsg.topic();
    sMsgTotal += " Payload:";
    sMsgTotal += sPayload;

    ui->textBrowser_ReceivedMessage->append(sMsgTotal);
}
4.1.5 编译与发布

使用3568 Kit交叉编译后得到mqtt_demo,并将其发布到开发板。

4.2 移植与测试

4.2.1 启动应用程序
cd /home/forlinx/work/example/mqtt
sudo ./mqtt_dem

4.2.2 联合测试

(1)搭建MQTT服务器,
启动MQTT服务器,可参阅我的博客linux下搭建MQTT服务。

(2)启动MQTT Dashboard
从Google Paly商店下载,安装到手机后,连接MQTT服务器后,即可在手机端监控开发板。

(3)连接网络

(4)运行demo
在demo上配置服务器IP、端口、订阅主题、发布主题和发布内容,执行连接、订阅和发布,演示效果如下图所示:

总结

至此,云服务器、RK3568和手机端通过了联合测试,它们组成了一个小型的物联网智能监控系统,通过MQTT轻松的实现了物联网,很有成就感!

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
thatk
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
thatk
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区