zoukankan      html  css  js  c++  java
  • ESA2GJK1DH1K基础篇: 移植MQTT底层包到自己的项目(V1.0)

    前言

      代码中的运行流程已经在 

      https://www.cnblogs.com/yangfengwu/p/12539421.html

      文章的最后做了介绍

      其实咱学东西最主要的是学以致用,应用到自己的工程项目里面

      这节着重说一下如何把源码中的MQTT底层包移植到用户自己的工程

      这节代码只是讲解详细流程,并不可以使用

      这节代码使用的底层:

      https://www.cnblogs.com/yangfengwu/p/12536382.html

      这节代码是在底层又做了一层封装

      主要是加入了数据缓存发送,便于处理消息等级为1和2的消息

      

    准备一个空的工程

      1.注:请自行准备一个已经可以实现TCP连接的工程

      由于用的网络芯片不一样,连接方式不一样,本人就在工程中假设连接了TCP

      

      2.把以下文件放入自己的工程

      

      添加一个文件夹

      

      添加文件

      

      添加MQTT文件中的所有文件

      

      添加头文件路径

      

    包含mqtt.h 编译下

    错误原因

    这个是把数据发送给网络模块的函数

    这个函数需要根据自己的修改

    用户需要把数据发送给网络模块的函数放到此处

    就是模块作为TCP客户端,把TCP客户端发送数据给TCP服务器数据的函数放在这里

     

    如果发送完了数据需要设置一个变量为0

    这个根据自己的修改

    我使用的是以下函数发送数据

    如果自己的发送函数没有发送完成的地方

    用户必须修改下面的发送消息超时时间(Ms)

    如果自己发送的数据感觉10ms就可以发送完,

    那么修改为10就可以

    在1ms定时器中断函数中放入以下函数

    放到自己的1ms中断函数里面!

    #include "mqtt.h"

    mqtt_time_data(&mymqtt);

    连接MQTT

    1.用一些数组存储连接MQTT的信息

    注册连接和断开函数

    unsigned char MQTTid[50] = "123456789";//ClientID
    unsigned char MQTTUserName[20] = "yang";//用户名
    unsigned char MQTTPassWord[50] = "11223344";//密码
    unsigned char MQTTkeepAlive = 30;//心跳包时间
    unsigned char MQTTPublishTopic[30]="1111";//存储MQTT发布的主题
    unsigned char MQTTWillMessage[50] = "{"data":"status","status":"offline"}";//遗嘱消息
    unsigned char MQTTWillQos = 0;//消息等级
    unsigned char MQTTWillRetained = 1;//是否需要服务器记录
    /**连接上MQTT回调函数
    * @brief   连接上MQTT回调函数
    * @param   None
    * @retval  None
    * @warning None
    * @example
    **/
    void MqttConnect()
    {
        
    }
    
    /**MQTT断开连接回调
    * @brief   MQTT断开连接回调
    * @param   None
    * @retval  None
    * @warning None
    * @example
    **/
    void MqttDisConnect()
    {
        mqtt_init(&mymqtt);
    }
        mqtt_init(&mymqtt);
        mqtt_connect_reg(&mymqtt,MqttConnect);//注册连接回调函数
        mqtt_disconnect_reg(&mymqtt,MqttDisConnect);//注册断开连接回调函数

    注:如果不想使用遗嘱,可自行屏蔽

    2.实现具体的连接

    用户先用自己的模块用TCP连接上TCP服务器(MQTT服务器)

    然后发送连接MQTT指令

    最后判断下是否连接成功

    int len;//获取数据长度
    unsigned char *str;//打包的数据首地址
    char ConnectedMqttFlag;//1:连接上MQTT 0:未连接

     

    if(ConnectedMqttFlag == 0){//没有连接上MQTT
                //用户这里写上控制模块以TCP方式连接上MQTT服务器的程序
                //发送连接MQTT的指令
                mymqtt.mqtt_connect_info.client_id = MQTTid;//client_id
                mymqtt.mqtt_connect_info.keepalive = MQTTkeepAlive;//心跳包时间
                mymqtt.mqtt_connect_info.username = MQTTUserName;//用户名
                mymqtt.mqtt_connect_info.password = MQTTPassWord;///密码
                mymqtt.mqtt_connect_info.will_topic = MQTTPublishTopic;//遗嘱发布的主题
                mymqtt.mqtt_connect_info.will_message = MQTTWillMessage;//遗嘱的消息
                mymqtt.mqtt_connect_info.will_qos = MQTTWillQos;//遗嘱的消息等级
                mymqtt.mqtt_connect_info.will_retain = MQTTWillRetained;//是否需要服务器保留消息
                mymqtt.mqtt_connect_info.clean_session = 1;//清除连接信息
                
                len = mqtt_connect(&mymqtt,&str);//打包连接信息
                //打包的数据首地址 str 数据长度:len
                if(len>0){ 
                    UsartOutStr(str,len);//发送MQTT协议数据给网络模块,其实就是TCP客户端发送数据给服务器(请根据自己的替换)
                }
                //发送完连接指令以后,MQTT服务器会返回连接信息,请按照下面程序处理信息
                //判断模块是否连接上,假设模块返回的数据存入了Usart1ReadBuff数组
                if(mqtt_connect_ack(Usart1ReadBuff)==0)//连接上了MQTT
                {
                    ConnectedMqttFlag = 1;//连接上MQTT
                    if(mymqtt.connectCb){//调用连接回调函数
                        mymqtt.connectCb();
                    }
                }
            }

     

    3.如果断开连接,需要让模块重新连接MQTT,请在断开连接回调函数中

    ConnectedMqttFlag=0;//断开连接以后,重新配置模块连接

    接收处理通信过程中的各种数据

    1.后期的通信都是利用数据缓存实现,请先添加以下程序

            if(ConnectedMqttFlag)//配置模块成功(模块连接了MQTT)
            {
                mqtt_send_function(&mymqtt);//提取发送缓存的MQTT协议
                mqtt_keep_alive(&mymqtt);//处理发送心跳包
                
                //网络模块接收到了数据
                if(网络模块接收到了数据)//此处请根据自己的网络模块自行修改,
                {
                    //假设网络接收到的数据:Usart1ReadBuff  数据长度:Usart1ReadCntCopy
                    mqtt_read_function(&mymqtt,Usart1ReadBuff,Usart1ReadCntCopy);
                }
            }

    2.注册接收数据函数

    /**
    * @brief   MQTT接收数据回调
    * @param   topic:主题
    * @param   topic_len:主题长度
    * @param   data:接收的数据
    * @param   lengh:接收的数据长度
    * @retval  None
    * @warning None
    * @example
    **/
    void MqttReceive(const char* topic, uint32_t topic_len,const char *data, uint32_t lengh)//接收到数据回调
    {
        
    }
    mqtt_received_reg(&mymqtt,MqttReceive);//注册接收数据回调函数

    订阅主题

    1.一般可以在连接成功回调函数里面订阅主题

    当然只要连接上以后,可以在程序的任何地方执行订阅函数

    unsigned char MQTTSubscribeTopic[30]="2222";//存储MQTT订阅的主题
    /**订阅主题成功
    * @brief   订阅主题成功
    * @param   None
    * @retval  None
    * @warning None
    * @example
    **/
    void subscribedCb(int pdata)
    {
        
    }
    
    /**订阅主题失败
    * @brief   订阅主题失败
    * @param   None
    * @retval  None
    * @warning None
    * @example
    **/
    void failsubscribedCb(int pdata)
    {
        
    }
    mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,0,subscribedCb,failsubscribedCb);//订阅主题

    订阅的消息等级支持0,1,2

    mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,0,subscribedCb,failsubscribedCb);

    mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,1,subscribedCb,failsubscribedCb);

    mqtt_subscribe(&mymqtt, MQTTSubscribeTopic,2,subscribedCb,failsubscribedCb);

    发布消息

    1.列如:把接收的消息发布出去

    /**
    * @brief   发布成功
    * @param   None
    * @retval  None
    * @warning None
    * @example
    **/
    void PublishedCb()
    {
        
    }
    
    /**
    * @brief   MQTT接收数据回调
    * @param   topic:主题
    * @param   topic_len:主题长度
    * @param   data:接收的数据
    * @param   lengh:接收的数据长度
    * @retval  None
    * @warning None
    * @example
    **/
    void MqttReceive(const char* topic, uint32_t topic_len,const char *data, uint32_t lengh)//接收到数据回调
    {
        mqtt_publish(&mymqtt,MQTTPublishTopic,(unsigned char*)data,topic_len, 0, 1,PublishedCb);//发布消息
    }

    提示:只有发布的消息等级是1/2的时候,服务器才会有应答信息

    所以只有1/2的时候才会进入发布成功回调函数

    深入源码

    1.要想知道底层如何封装处理的,必须知道的基础知识

    https://www.cnblogs.com/yangfengwu/p/12228402.html

    2.订阅主题,发布消息,发送心跳包的数据都存储在了缓存里面

    程序中默认每隔20Ms提取一次

    注:特殊的地方会超过20Ms

    提取数据

    这个函数一开始让大家放在了1Ms定时器里面

    深入源码之-订阅主题0

    1.订阅主题

    2.提取到数据,发给服务器

    有些需要等待服务器返回的地方都会启用超时检测

    超时时间归零以后,才会把后面缓存的其它数据发送给服务器

    3.判断服务器的返回

    深入源码之-发布消息,消息等级0

    因为消息等级0不需要任何的应答,所以组合的消息直接用TCP发送出去

    深入源码之-发布消息,消息等级1

    深入源码之-发布消息,消息等级2

     

    深入源码之-接收消息,消息等级1

    深入源码之-接收消息,消息等级2

    深入源码之-心跳包

    1.心跳包内部自动处理,用户只需要调用以下函数

    mqtt_keep_alive(&mymqtt);

    2.处理思路

    到达发送心跳包时间,把心跳包数据插入缓存,

    如果超过5S服务器没有返回应答,则再发一次

    如果超过5S还是没有返回应答,则再发一次

    如果超过5S还是没有返回应答,则执行mqtt断开连接函数

     

    返回了心跳应答,清零所有关于心跳包的变量,重新开始计数

    注:鉴于如果MQTT服务器一直处于发送其余数据的状态,

    那么服务器会延迟发送过来心跳包应答

    所以,只要MQTT服务器返回其它数据,就清零心跳包变量

  • 相关阅读:
    C8051逆向电阻屏:头儿拍脑袋说电阻屏IC好赚钱3块钱成本能卖20几块。,一个月不分昼夜逆向成功后头儿说电阻屏已经被市场淘汰请放弃治疗。
    Google大数据三篇著名论文----中文版
    推荐相关博客
    基于hadoop的电影推荐结果可视化
    爬虫(heritrix框架)
    标准SVD和改进的SVD
    基于矩阵分解的隐因子模型
    SVD奇异值分解的几何物理意义资料汇总
    (大数据工程师学习路径)第五步 MySQL参考手册中文版----MySQL数据库管理
    (大数据工程师学习路径)第五步 MySQL参考手册中文版----MySQL视图
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/12540710.html
Copyright © 2011-2022 走看看