QT Linux实现AT指令处理框架

本框架在QT4.8.6版本环境下编写。

一、业务逻辑的诞生

1.1 了解一下什么是AT指令

QT Linux实现AT指令处理框架_第1张图片

1.2 思考在QT上如何处理AT指令

看了下网上大多数人实现的在Linux下的4G模块AT指令收发控制,以及在QT上实现的,还有某些厂商实现的解析框架,其实就是在处理串口的收发,但未免做得有点糙,问题点也很多,比如很多人压根就没做指令回复的超时处理,万一要是发生了,那将给整个程序带来致命性的伤害。
最近的项目上需要在QT上处理AT指令的发送和回复,基于这样的环境,于是我决定实现两条线程,一条用于处理设备的初始化,一条用于处理在主进程指令的发送,由于AT指令收发存在延时,所以直接在主进程上延时,QT主进程就卡死了,这就是为什么我一定要用线程去处理的结果。

1.3 特别提醒

如果是在Linux操作串口设备,qt也要有相应的权限,使用如下指令即可。

sudo qtcreator &

二、移植通用串口框架到QT上

由于QT4.8.6版本未有操作串口相关的类库,于是就只能移植开源的qextserialbase库了。
参考:https://blog.csdn.net/g1036583997/article/details/44805217

三、Gobal_Item_flag.h

该文件主要是用于串口通信模块(支持AT指令)、以及一些全局参数的定义。

#ifndef GOBAL_ITEM_FLAG_H
#define GOBAL_ITEM_FLAG_H
#include "posix_qextserialport.h"

#define __NBIOT
#define DEV_NAME "/dev/ttyUSB0"
#define RECV_DATA_LEN 1024
extern char recv_buffer[RECV_DATA_LEN];

//AT_CMD_DEFINE  Start
#ifdef __NBIOT
#define AT_TEST_OK "AT"
#define GET_IMSI "AT+CIMI"
#define GET_SIGNAL "AT+CSQ"
#define GET_SUPPORT_NBAND "AT+NBAND=?"
#define GET_CURRENT_NBAND "AT+NBAND?"
#define SET_NBAND "AT+NBAND=5"
#define GET_CGATT "AT+CGATT"
#define CREATE_TCP_SOCKET "AT+NSOCR=STREAM,6,56000,1"
#define CONNECT_TCP_SERVER "AT+NSOCO=1,120.78.136.134,9002"
#define HARDWARE_RESET "AT+NRB"

#elif __ESP8266

#define AT_TEST_OK        "AT"
#define AT_SET_MODE       "AT+CWMODE=%d"
#define AT_CONNECT_ROUTER "AT+CWJAP=\"%s\",\"%s\""
#define AT_CONNECT_SERVER "AT+CIPSTART=\"%s\",\"%s\",%d"
#define AT_SET_CIP_MODE   "AT+CIPMODE=1"
#define AT_ENTER_CIP_MODE "AT+CIPSEND"

#elif __ME3630
#define AT_TEST_OK         "AT"
#define CREATE_TCP_SOCKET  "AT+ZIPCALL=1"
#define CONNECT_TCP_SERVER "AT+ZIPOPEN=1,0,120.78.136.134,9001"
#define AT_SEND_DATA       "AT+ZIPSEND=1,%s";

#endif

//AT_CMD_DEFINE  End


#endif // GOBAL_ITEM_FLAG_H

四、网络接口线程定义

头文件network_interface.h
#ifndef NETWORK_INTERFACE_H
#define NETWORK_INTERFACE_H

#include 
#include 
#include 
#include 
#include "Gobal_Item_flag.h"

class NetWork_Interface : public QThread
{
    Q_OBJECT
public:
    explicit NetWork_Interface(QObject *parent = 0);
    ~NetWork_Interface();
    //if Status is True,Thread is stop,else is Runing
    void NetWork_Thread_change(bool Status);
    int Send_AT_Cmd(QString cmd_buffer,const char *success_ack,const char *error_ack,int timeout);

private:
    Posix_QextSerialPort *NetWork_Port ;
    volatile bool Stop_flag ;
    int Uart_Init(const char *dev_name,BaudRateType BaudRate,DataBitsType DataBits,  \
                  ParityType ParityBits,StopBitsType StopBits,FlowType FlowControl,int TimeOut);

protected:
    void run();

signals:

public slots:

};

#endif // NETWORK_INTERFACE_H

这里实现了串口的初始化,线程状态的控制,线程函数执行以及AT指令的发送函数。

接口实现network_interface.cpp
#include "network_interface.h"
//全局串口数据接收缓存区
char recv_buffer[RECV_DATA_LEN] = {0};
//串口初始化
int NetWork_Interface::Uart_Init(const char *dev_name,BaudRateType BaudRate,DataBitsType DataBits,  \
                                 ParityType ParityBits,StopBitsType StopBits,FlowType FlowControl,int TimeOut)
{
    this->NetWork_Port = new Posix_QextSerialPort(dev_name,QextSerialBase::Polling);
    if(NetWork_Port->open(QIODevice::ReadWrite))
    {
        this->NetWork_Port->setBaudRate(BaudRate);
        this->NetWork_Port->setDataBits(DataBits);
        this->NetWork_Port->setParity(ParityBits);
        this->NetWork_Port->setStopBits(StopBits);
        this->NetWork_Port->setFlowControl(FlowControl);
        this->NetWork_Port->setTimeout(TimeOut);
        return 0 ;
    }
    return 1 ;
}

NetWork_Interface::NetWork_Interface(QObject *parent) :
    QThread(parent)
{
    int ret = Uart_Init(DEV_NAME,BAUD9600,DATA_8,PAR_NONE,STOP_1,FLOW_OFF,200);
    if(0 != ret)
    {
        qDebug() << "Open Device Fail..." ;
        this->NetWork_Thread_change(true);
        return ;
    }
    //改变线程的状态为执行
    this->NetWork_Thread_change(false);
}

NetWork_Interface::~NetWork_Interface()
{
    this->NetWork_Port->close();
    delete this->NetWork_Port;
}

//Change Thread Status
void NetWork_Interface::NetWork_Thread_change(bool Status)
{
    Stop_flag = Status ;
}

//Runing Init Thread
void NetWork_Interface::run()
{
    qDebug() << "Open Device Success....Start Uart_Recv Thread";
    //Init Device
    while(!Stop_flag)
    {
        QThread::msleep(200);
    }
}

/AT指令收发
/*
   cmd_buffer:要发送的AT指令,不需要带\r\n
   success_ack:成功的预言字符串
   error_ack:错误的语言字符串
   timeout:超时,意思是如果发送超过timeout定义的,即返回超时失败。
   return : 0 成功 1失败 -1超时
*/
int NetWork_Interface::Send_AT_Cmd(QString cmd_buffer,const char *success_ack,const char *error_ack,int timeout)
{
    char *cmd = NULL;
    char *send_cmd = NULL ;
    QByteArray Byte_Data,temp;
    temp.clear();
    memset(recv_buffer,0,1024);
    cmd_buffer.append("\r\n");
    Byte_Data = cmd_buffer.toLatin1();
    send_cmd = Byte_Data.data();
    this->NetWork_Port->write(send_cmd);
    while(timeout--)
    {
        temp.clear();
        memset(recv_buffer,0,1024);
        temp = this->NetWork_Port->readAll();
        cmd = temp.data();
        strcpy(recv_buffer,cmd);
        if(strstr(recv_buffer,error_ack) != NULL)
        {
            qDebug() << "ackerror:" << recv_buffer ;
            return 1 ;
        }
        if(strstr(recv_buffer,success_ack) != NULL)
        {
            qDebug() << "acksuccess:" << recv_buffer ;
            return 0 ;
        }
        QThread::msleep(1);
    }
    qDebug() << "ackerror:AT cmd recv TimeOut";
    return -1 ;
}

五、网络控制线程定义

网络控制线程头文件
#ifndef NETWORK_CONTROL_THREAD_H
#define NETWORK_CONTROL_THREAD_H

#include 
#include "network_interface.h"

class NetWork_Control_Thread : public QThread
{
    Q_OBJECT
public:
    explicit NetWork_Control_Thread(QObject *parent = 0);
    ~NetWork_Control_Thread();
    void NetWork_Thread_change(bool Status);

private:
    volatile bool Stop_flag ;
    NetWork_Interface *netWork_Ptr ;

protected:
    void run();

signals:

public slots:

};

#endif // NETWORK_CONTROL_THREAD_H
网络控制线程接口实现
#include "network_control_thread.h"

NetWork_Control_Thread::NetWork_Control_Thread(QObject *parent) :
    QThread(parent)
{
    this->NetWork_Thread_change(false);
    //在这里实例化网络接口线程
    this->netWork_Ptr = new NetWork_Interface ;
    //启动网络接口线程
    this->netWork_Ptr->start();
}

NetWork_Control_Thread::~NetWork_Control_Thread()
{
    this->NetWork_Thread_change(true);
    delete this->netWork_Ptr ;
}
//改变线程的状态
void NetWork_Control_Thread::NetWork_Thread_change(bool Status)
{
    this->Stop_flag = Status ;
}
//线程执行函数
void NetWork_Control_Thread::run()
{
    //发送AT测试指令
    this->netWork_Ptr->Send_AT_Cmd(AT_TEST_OK,"OK","ERROR",200);
    while(!this->Stop_flag)
    {
        qDebug() << "NetWork_Control_Thread is Runing....";
        QThread::msleep(1000);
    }
}

六、AT指令框架测试

mainwindown.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include "network_control_thread.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    NetWork_Control_Thread *network_control_ptr ;
};

#endif // MAINWINDOW_H

mainwindown.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //实例化网络控制线程
    this->network_control_ptr = new NetWork_Control_Thread ;
    //启动网络控制线程===>启动后将会自动启动网络接口线程
    this->network_control_ptr->start();
}

MainWindow::~MainWindow()
{
    delete this->network_control_ptr;
    delete ui;
}

运行结果,这里我用的是NBIOT的BC28模块进行测试,本例程只提供测试框架,开发者需自行添加自己的业务逻辑处理。
QT Linux实现AT指令处理框架_第2张图片
以下是我利用这个框架写的一个类似上位机的软件,可以读取模块的基本信息:
QT Linux实现AT指令处理框架_第3张图片

你可能感兴趣的:(QT软件开发)