Linux驱动实现AT指令,QT Linux实现AT指令处理框架
本框架在QT4.8.6版本环境下编写。
一、业务逻辑的诞生
1.1 了解一下什么是AT指令
1.2 思考在QT上如何处理AT指令
看了下网上大多数人实现的在Linux下的4G模块AT指令收发控制,以及在QT上实现的,还有某些厂商实现的解析框架,其实就是在处理串口的收发,但未免做得有点糙,问题点也很多,比如很多人压根就没做指令回复的超时处理,万一要是发生了,那将给整个程序带来致命性的伤害。
最近的项目上需要在QT上处理AT指令的发送和回复,基于这样的环境,于是我决定实现两条线程,一条用于处理设备的初始化,一条用于处理在主进程指令的发送,由于AT指令收发存在延时,所以直接在主进程上延时,QT主进程就卡死了,这就是为什么我一定要用线程去处理的结果。
1.3 特别提醒
如果是在Linux操作串口设备,qt也要有相应的权限,使用如下指令即可。
sudo qtcreator &
二、移植通用串口框架到QT上
三、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模块进行测试,本例程只提供测试框架,开发者需自行添加自己的业务逻辑处理。
以下是我利用这个框架写的一个类似上位机的软件,可以读取模块的基本信息:
本文同步分享在 博客“Engineer-Bruce_Yang”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
Linux驱动实现AT指令,QT Linux实现AT指令处理框架相关推荐
- 从串口驱动到Linux驱动模型,想转Linux的必会!
关注.星标公众号,直达精彩内容 ID:技术让梦想更伟大 整理:李肖遥 本文通过对Linux下串口驱动的分析.由最上层的C库.到操作系统系统调用层的封装.再到tty子系统的核心.再到一系列线路规程.再到 ...
- linux驱动日志格式,( 转)嵌入式Linux驱动Makefile
天气: 晴朗 心情: 高兴 ( 转)嵌入式Linux驱动开发笔记 1.1 模块的编译 Linux驱动一般以模块module的形式来加载,首先需要把驱动编译成模块的形式.简单的例子, Be ...
- linux驱动(一):linux驱动框架
编写linux驱动先看一下驱动框架是什么样子的. 驱动编写和应用层编写有什么区别呢? (一)首先 入口函数的问题.应用层编写我们的入口就是main函数,但在驱动编写时不是这样的,有两种情况, 1.缺省 ...
- 嵌入式linux驱动开发实战教程,嵌入式Linux驱动开发实战视频教程
嵌入式Linux驱动开发实战教程(内核驱动.看门狗技术.触摸屏.视频采集系统) 适合人群:高级 课时数量:109课时 用到技术:嵌入式 Linux 涉及项目:驱动开发.看门狗技术.触摸屏.视频采集 咨 ...
- mt7601u linux驱动编译,移植MT7601U AP Linux 驱动至Orangepi-PC2开发板
简单一下记录移植MT7601U AP Linux 驱动至Orangepi-PC2开发板的过程. 二 环境描述 1.Orangpi-PC2开发板(Linux Orangepi 3.10.65 #12 ...
- 华为笔记本linux驱动支持,华为笔记本电脑对Linux 5.5内核的支持得到改善
原标题:华为笔记本电脑对Linux 5.5内核的支持得到改善 随着即将到来的Linux 5.5内核周期,华为笔记本电脑将在支持方面有所改进. 作为X86平台驱动程序更新的一部分,Huawei WMI驱 ...
- linux驱动内核哪个文件夹,linux设备驱动归纳总结(一):内核的相关基础概念...
linux设备驱动归纳总结(一):内核的相关基础概念 1. 内核与 linux 设备驱动的作用与关系 内核:用于管理软硬件资源,并提供运行环境.如分配 4G 虚拟空间等. linux 设备驱动:是连接 ...
- exfat linux 驱动_(实例)Linux 内核添加exfat驱动
背景: 由于exfat是常用的文件系统格式,而Linux由于版权的问题,没有在官方中添加有关的驱动. 但是 微软也同意开源了,所以比较新的 Linux 会支持这一块. 为了支持exfat的驱动,我们需 ...
- linux驱动的中断函数,嵌入式Linux驱动开发(四)——字符设备驱动之中断方式以及中断方式获取按键值...
之前我们完成了关于通过查询的方式获取按键键值的驱动程序,可以参考:嵌入式Linux开发--裸板程序之中断控制器. 虽然读取键值没有什么问题,但是测试程序占用CPU过高,一直在不断的查询,资源消耗过大, ...
最新文章
- LayoutParams cannot be resolved to a type
- anki 新的卡片类型_梁宝川:这一类型Anki卡片,你做了吗?
- 电子科技大学计算机学院保研夏令营,电子科技大学计算机科学与工程学院网络空间安全保研夏令营...
- Angular Component之间的事件通知机制
- linux命令终极系列awk
- java 保留html_好程序员Java培训分享Java包是什么?
- java lang保_android – Gson中的RuntimeException解析JSON:无法调用受保护的java.lang.ClassLoader()而没有args...
- 最新安卓手机性价比榜公布:Redmi连夺三冠
- [PyTorch] 神经网络处理图像
- 微型计算机原理与接口技术综述论文,微型计算机原理接口与技术综述论文汇编.doc...
- 媒体选择与发布实践总结
- Java对接苹果账号授权登录
- android 音量调节不起作用,Android音量控制
- HTML+CSS静态页面网页设计作业——甜品奶茶店(19页) HTML5网页设计成品_学生DW静态网页设计_web课程设计网页制作
- 浅谈嵌入式MCU软件开发之S32K1xx系列MCU启动过程及重映射代码到RAM中运行方法详解
- 1.5.33 计算分数加减表达式的值
- 圣地亚哥分校 计算机,美国加州大学圣地亚哥分校计算机科学专业.pdf
- 小波系数等值线图和小波方差图绘制教学
- 18 -Flask构建弹幕微电影网站- 部署上线
- word如何设置上标形式_word怎样设置上标
热门文章
- [对比]Android的差异设计和iOS的统一设计规范
- 生物信息学入门 根据表达矩阵和差异表达基因列表制作差异表达矩阵
- 客户端计算机硬件需求,票据交易系统客户端安装配置手册一、客户端计算机硬件要求.PDF...
- 机器人碰撞检测几何模型设计
- 【DBSDFZOJ 4460】666(DP)
- MAC上Pycharm破解导致无法打开
- “智”和“慧”的区别是什么?
- 安科瑞ANet通信管理机在电力监控系统中的应用-Susie 周
- 计算机网络中常见的端口号整理
- 为什么Facebook无法取消QAnon