点击上方蓝字关注我们
13.5 低功耗蓝牙设备的访问13.5.1 QLowEnergyController类介绍 QLowEnergyController类提供对低功耗蓝牙设备的访问。
QLowEnergyController充当蓝牙低功耗开发的入口点。
低功耗蓝牙定义了两种类型的设备: 外围设备角色和中央设备角色。
每个角色执行不同的任务。外围设备提供中央设备使用的数据。
一个例子: 可能外围设备是一个湿度传感器,它可以测量冬季花园的湿度。诸如移动电话之类的设备可以读取传感器的值,在这种情况下,传感器是外围设备,手机充当中央设备。
通过createCentral()方法创建中心角色的控制器,实现诸如服务发现和状态跟踪等功能。
在中心角色中创建控制器对象后,第一步是通过connectToDevice()建立连接。一旦建立连接,控制器的状态()将变为QLowEnergyController :: ConnectedState,并发出connected()信号。有一点很重要,例如基于BlueZ的Linux等平台无法将两个连接的QLowEnergyController实例维护到同一个远程设备。在这种情况下,对connectToDevice()的第二次调用可能会失败。这种限制可能在未来某个阶段消失。 disconnectFromDevice()函数用于中断现有连接。
建立连接后的第二步是发现远程外围设备提供的服务。此过程通过discoverServices()启动,并且一旦发现discoveryFinished()信号就完成了。发现的服务可以通过services()函数来枚举。
最后一步是创建服务对象。 createServiceObject()函数充当每个服务对象的工厂,并期望服务UUID作为参数。调用上下文应该拥有返回的QLowEnergyService实例的所有权。
一旦控制器从远程低功耗蓝牙设备断开,任何QLowEnergyService,QLowEnergyCharacteristic或QLowEnergyDescriptor实例(稍后由此控制器的连接创建)都将失效。
外设角色中的控制器是通过createPeripheral()工厂方法创建的。这样一个对象本身就是一个外围设备,可以实现广告服务等功能,并允许客户获得有关特征值更改的通知。
在外设角色中创建控制器对象后,第一步是通过调用addService()来填充提供给客户端设备的GATT服务集。之后,可以调用startAdvertising()让设备广播一些数据,并根据所做广告的类型来侦听来自GATT客户端的传入连接。
另请参阅QLowEnergyService,QLowEnergyCharacteristic,QLowEnergyDescriptor,QLowEnergyAdvertisingParameters
和QLowEnergyAdvertisingData。
13.5.2 常用的函数介绍(1) 连接到低功耗蓝牙设备 void QLowEnergyController::connectToDevice()
|
如果控制器的state()不等于UnconnectedState,则此函数不执行任何操作。 一旦连接成功建立,connected()信号就会发出。
(2) 断开连接 void QLowEnergyController::disconnectFromDevice()
|
断开与远程设备的连接。
当前连接断开,会导致QLowEnergyService,QLowEnergyCharacteristic或QLowEnergyDescriptor实例都会自动失效。 一旦这些对象中的任何一个变得无效,即使此控制器对象重新连接,它们仍然无效。
如果控制器处于未连接状态,此功能不执行任何操作。
(3) 创建目标服务 QLowEnergyService *QLowEnergyController::createServiceObject(const QBluetoothUuid &serviceUuid, QObject *parent = Q_NULLPTR)
|
创建由serviceUuid表示的服务的一个实例。 serviceUuid参数必须通过services()获得。
调用者获得返回指针的所有权,并可以传递父参数作为默认所有者。
如果在远程设备上没有找到serviceUuid的服务,或者控制器断开连接,则此函数返回空指针。
该函数也可以为二级服务返回实例。 服务之间的包含关系可以通过QLowEnergyService :: includedServices()来表示。
如果使用相同的服务UUID多次调用此函数,则返回的QLowEnergyService实例共享其内部数据。 因此,如果其中一个实例启动发现服务详细信息,则其他实例也会自动转换到发现状态。
(4) 返回远程设备的UUID列表 href="../qtcore/qlist.html" QList<QBluetoothUuid> QLowEnergyController::services() const
|
如果控制器位于CentralRole中,则返回远程设备提供的服务列表。 否则,结果未指定。
该列表包含所有主要和次要服务。
(5) 获取错误信息 Error error() const
QString errorString() const
|
错误枚举值:
QLowEnergyController::NoError
| 没有发生错误。
| QLowEnergyController::UnknownError
| 出现未知错误。
| QLowEnergyController::UnknownRemoteDeviceError
| 无法找到传递给此类构造函数的远程Bluetooth Low Energy设备。
| QLowEnergyController::NetworkError
| 尝试读取或写入远程设备失败。
| QLowEnergyController::InvalidBluetoothAdapterError
| 传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备。
| QLowEnergyController::ConnectionError
| 尝试连接到远程设备失败。 这个值是由Qt 5.5引入的。
| QLowEnergyController::AdvertisingError
| 尝试开始广告失败。 这个值是由Qt 5.7引入的。
|
(6) 获取本地蓝牙适配器地址 QBluetoothAddress QLowEnergyController::localAddress() const
|
返回用于通信的本地蓝牙适配器的地址。
如果请求此类实例使用默认适配器,但在创建此类实例时没有默认适配器,则返回的QBluetoothAddress将为空。
(7) 返回远程低功耗蓝牙的设备地址 QBluetoothAddress QLowEnergyController::remoteAddress() const
|
返回远程蓝牙低功耗设备的地址。
对于CentralRole中的控制器,此值始终是创建控制器对象时传入的值。 对于PeripheralRole中的控制器,此值是当前连接的客户端设备的地址。 特别是,如果控制器当前不在ConnectedState中,则该地址将无效。
(8) 返回远程蓝牙的名称 QString QLowEnergyController::remoteName() const
|
如果控制器位于CentralRole中,则返回远程Bluetooth Low Energy设备的名称。 否则结果是未指定的。
(9) 返回控制器的当前状态 ControllerState QLowEnergyController::state() const
|
状态枚举值:
QLowEnergyController::UnconnectedState
| 控制器未连接到远程设备。
| QLowEnergyController::ConnectingState
| 控制器正在尝试连接到远程设备。
| QLowEnergyController::ConnectedState
| 控制器连接到远程设备。
| QLowEnergyController::DiscoveringState
| 控制器正在检索远程设备提供的服务列表。
| QLowEnergyController::DiscoveredState
| 控制器已经发现了远程设备提供的所有服务。
| QLowEnergyController::ClosingState
| 控制器即将与远程设备断开连接。
| QLowEnergyController::AdvertisingState
| 控制器目前正在广告数据。 这个值是由Qt 5.7引入的。
|
(10) 创建中央角色的控制器 QLowEnergyController *QLowEnergyController::createCentral(const QBluetoothDeviceInfo &remoteDevice, QObject *parent = nullptr)
|
返回CentralRole中此类的新对象,并具有父对象。 remoteDevice指的是将来建立连接的设备。
控制器使用本地默认蓝牙适配器进行连接管理。
(11) 启动服务查找功能 void QLowEnergyController::discoverServices()
|
当设备连接成功之后才可以调用,用于查找设备的UUID服务列表。
13.5.3 常用的信号列表(1) 连接建立成功的通知信号 void QLowEnergyController::connected()
|
当控制器成功连接远程Low Energy设备(如果控制器处于CentralRole中)或连接到控制器的远程Low Energy设备(如果控制器位于PeripheralRole中),则会发出此信号。
(2) 连接参数发生改变 void QLowEnergyController::connectionUpdated(const QLowEnergyConnectionParameters &newParameters)
|
当连接参数改变时发出此信号。 这可能是由于调用requestConnectionUpdate()或由于其他原因而发生的,例如因为连接的另一端请求了新参数。 新值可以从newParameters中检索。
这个函数是在Qt 5.7中引入的。
(3) 断开连接参数 void QLowEnergyController::disconnected()
|
当控制器与远程低功耗设备断开连接时,该信号会发出。
(4) 发现新的服务 void QLowEnergyController::serviceDiscovered(const QBluetoothUuid &newService)
|
每次发现新服务时都会发出此信号。 newService参数包含找到的服务的UUID。
只有当控制器处于CentralRole中时才能发出此信号。
(5) 服务发现完成 void QLowEnergyController::discoveryFinished()
|
正在运行的服务发现完成时发出此信号。 如果发现过程发生错误,则不发射信号。
(6) 错误提示信号 void QLowEnergyController::error(QLowEnergyController::Error newError)
|
该信号在发生错误时发出。 newError参数描述发生的错误。
注意:此类中信号错误超载。 要使用函数指针语法连接到此函数,您必须在静态转换中指定信号类型,如下例所示:
connect(lowEnergyController, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
[=](QLowEnergyController::Error newError){ /* ... */ });
|
13.6 低功耗蓝牙设备的数据收发13.6.1 QLowEnergyService类介绍 QLowEnergyService类表示蓝牙低功耗设备上的单个服务。
QLowEnergyService可以访问蓝牙低功耗服务的详细信息。允许读取和写入所包含的数据并通知数据更改。
蓝牙低功耗外围设备可以包含多种服务。 每个服务又可能包括更多的服务。 该类代表外围设备的单个服务,并通过QLowEnergyController :: createServiceObject()创建。 type()指示此服务是主服务(顶级服务)还是服务是否是另一服务的一部分。 每个服务可能包含一个或多个特征,每个特征可能包含描述符。 最终的结构可能如下图所示:
13-6-1图
一旦服务对象首次被创建,其细节尚未被发现。这由它的当前state()为DiscoveryRequired来表示。只能检索serviceUuid()和serviceName()。
调用discoverDetails()时会触发其包含的服务,特性和描述符的发现。在发现期间,state()从DiscoveryRequired通过DiscoveringServices转换到其最终的ServiceDiscovered状态。该转换通过stateChanged()信号进行广告。一旦知道了详细信息,所有包含的特征,描述符和包含的服务都是已知的,并且可以读取或写入。
特性和描述符的值可分别通过QLowEnergyCharacteristic和QLowEnergyDescriptor检索。但是,直接读取或写入这些属性需要服务对象。 readCharacteristic()函数尝试重新读取特征的值。尽管最初的服务发现可能已经获得了一个值,但是如果特征值在没有提供任何通知的情况下不断发生变化,则可能需要此调用。
如果读取尝试成功,则发出characteristicRead()信号。未能读取该值会触发CharacteristicReadError。 writeCharacteristic()函数会尝试为给定特性写入新值。如果写入尝试成功,则发出characteristicWritten()信号。写入失败会触发CharacteristicWriteError。描述符的读写符合相同的模式。
13.6.2 常用函数介绍(1) 返回UUID的匹配特性 QLowEnergyCharacteristic QLowEnergyService::characteristic(const QBluetoothUuid &uuid) const
|
返回uuid的匹配特性; 否则为无效特征。
如果此服务discoverDetails()实例尚未调用或者没有与uuid匹配的特征,则返回的特征无效。
(2) 返回关联的所有特性 QList<QLowEnergyCharacteristic> QLowEnergyService::characteristics() const
|
返回与此QLowEnergyService实例关联的所有特征。
如果此服务discoverDetails()实例尚未调用或者没有已知特征,则返回的列表为空。
(3) 开始发现服务所包含的: 服务,特征和描述符 void QLowEnergyService::discoverDetails()
|
发现过程通过stateChanged()信号指示。
(4) 判断特征是否属于此服务 booQLowEnergyService::contains(const QLowEnergyCharacteristic &characteristic) const
boocontains(const QLowEnergyDescriptor &descriptor) const
|
如果特征属于此服务,则返回true; 否则为false。
如果characteristics()包含特征,则特征属于服务。
(5) 读取特征值 void QLowEnergyService::readCharacteristic(const QLowEnergyCharacteristic &characteristic)
|
读取特征的值。 如果操作成功,则发出characteristicRead()信号; 否则设置CharacteristicReadError。 一般来说,如果设置了QLowEnergyCharacteristic :: Read属性,则该特性是可读的。
(6) 读取描述符的值 void QLowEnergyService::readDescriptor(const QLowEnergyDescriptor &descriptor)
|
读取描述符的值,如果操作成功,则发射descriptorRead()信号; 否则设置DescriptorReadError。
(7) 返回服务的UUID的和名称 QString serviceName() const
QBluetoothUuid serviceUuid() const
|
(8) 写入新的特征值 void QLowEnergyService::writeCharacteristic(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue, WriteMode mode = WriteWithResponse)
|
写入newValue作为特性的值。如果操作成功,则发出characteristicWritten()信号;否则将设置CharacteristicWriteError。
(9) 写入新的描述符值 void QLowEnergyService::writeDescriptor(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue)
|
13.6.3 程序案例:BLE低功耗蓝牙调试助手 (配套代码CH13-02)
(1) mainwindow.cpp文件代码 #include "mainwindow.h"
#include "ui_mainwindow.h"
/*
* 设置QT界面的样式
*/
void MainWindow::SetStyle(const QString &qssFile) {
QFile file(qssFile);
if (file.open(QFile::ReadOnly)) {
QString qss = QLatin1String(file.readAll());
qApp->setStyleSheet(qss);
QString PaletteColor = qss.mid(20,7);
qApp->setPalette(QPalette(QColor(PaletteColor)));
file.close();
}
else
{
qApp->setStyleSheet("");
}
}
//#蓝牙串口服务
//SerialPortServiceClass_UUID = '{00001101-0000-1000-8000-00805F9B34FB}'
//Service UUID 0xFEE0 主服务
//static const QLatin1String serviceUuid("0000FEE0-0000-1000-8000-00805F9B34FB");
//这个字符串里面的内容就是串口模式的Uuid
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->SetStyle(":/qss/blue.css"); //设置样式表
this->setWindowTitle("串口调试助手"); //设置标题
this->setWindowIcon(QIcon(":/wbyq.ico")); //设置图标
/*1. 实例化蓝牙相关的对象*/
discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
localDevice = new QBluetoothLocalDevice();
/*2. 关联蓝牙设备相关的信号*/
/*2.1 关联发现设备的槽函数,当扫描发现周围的蓝牙设备时,会发出deviceDiscovered信号*/
connect(discoveryAgent,
SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
this,
SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo))
);
/*3. 检查蓝牙的状态,用于设置按钮的初始状态*/
/*3.1 检查蓝牙是否开启*/
if(localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff)
{
//如果蓝牙处于关闭状态
ui->pushButton_OpenBluetooth->setEnabled(true); //打开按钮
ui->pushButton_CloseBluetooth->setEnabled(false); //关闭按钮
}
else //如果蓝牙处于开启状态
{
ui->pushButton_OpenBluetooth->setEnabled(false);//打开按钮
ui->pushButton_CloseBluetooth->setEnabled(true);//关闭按钮
ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
}
/*3.2 设置标签显示本地蓝牙的名称*/
QString name_info("本机蓝牙:");
name_info+=localDevice->name();
ui->label_BluetoothName->setText(name_info);
ui->pushButton_StopScan->setEnabled(false); //设置停止扫描蓝牙的按钮不可用
ui->plainTextEdit_BluetoothInfiShow->setEnabled(false); //设置不可编辑
m_control=NULL; //初始值
m_service=NULL; //初始值
SendModeSelect=0;
SendMaxMode=0;
}
MainWindow::~MainWindow()
{
delete ui;
delete discoveryAgent;
delete localDevice;
}
void MainWindow::on_pushButton_OpenBluetooth_clicked()
{
/*请求打开蓝牙设备*/
localDevice->powerOn();
ui->pushButton_OpenBluetooth->setEnabled(false);//打开按钮
ui->pushButton_CloseBluetooth->setEnabled(true);//关闭按钮
ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
}
void MainWindow::on_pushButton_CloseBluetooth_clicked()
{
/*关闭蓝牙设备*/
localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
ui->pushButton_OpenBluetooth->setEnabled(true);//打开按钮
ui->pushButton_CloseBluetooth->setEnabled(false);//关闭按钮
ui->pushButton_BluetoothScan->setEnabled(false); //设置扫描按钮不可用
}
void MainWindow::on_pushButton_BluetoothScan_clicked()
{
/*开始扫描周围的蓝牙设备*/
discoveryAgent->start();
ui->comboBox_BluetoothDevice->clear(); //清除条目
ui->pushButton_BluetoothScan->setEnabled(false); //设置扫描按钮不可用
ui->pushButton_StopScan->setEnabled(true); //设置停止扫描按钮可用
}
void MainWindow::on_pushButton_DeviceVisible_clicked()
{
/*设置蓝牙可见,可以被周围的设备搜索到,在Android上,此模式最多只能运行5分钟。*/
localDevice->setHostMode( QBluetoothLocalDevice::HostDiscoverable);
}
void MainWindow::on_pushButton_StopScan_clicked()
{
/*停止扫描周围的蓝牙设备*/
discoveryAgent->stop();
ui->pushButton_StopScan->setEnabled(false); //设置停止扫描按钮不可用
ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
}
/*当扫描到周围的设备时会调用当前的槽函数*/
void MainWindow::addBlueToothDevicesToList(const QBluetoothDeviceInfo &info)
{
// QString labe= QString("%1 %2").arg(info.name()).arg(info.address().toString());
QString labe= QString("%1 %2").arg(info.address().toString()).arg(info.name());
ui->comboBox_BluetoothDevice->addItem(label); //添加字符串到comboBox上
}
/*
在说蓝牙设备连接之前,不得不提一个非常重要的概念,就是蓝牙的Uuid,引用一下百度的:
在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。
正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。
UUID类可表现为短整形(16或32位)和长整形(128位)UUID。
他提供了分别利用String和16位或32位数值来创建类的构造函数,提供了一个可以比较两个UUID(如果两个都是128位)的方法,还有一个可以转换一个UUID为一个字符串的方法。
UUID实例是不可改变的(immutable),只有被UUID标示的服务可以被发现。
在Linux下你用一个命令uuidgen -t可以生成一个UUID值;
在Windows下则执行命令uuidgen 。UUID看起来就像如下的这个形式:2d266186-01fb-47c2-8d9f-10b8ec891363。当使用生成的UUID去创建一个UUID对象,你可以去掉连字符。
*/
//发送数据
void MainWindow::on_pushButton_SendData_clicked()
{
QString text=ui->lineEdit_SendData->text();
QByteArray array=text.toLocal8Bit();
/*写入newValue作为特性的值。
如果操作成功,将发射characteristicWritten()信号;
低功耗设备: 每次最多写20个字节
*/
m_service->writeCharacteristic(m_writeCharacteristic[SendModeSelect],array, m_writeMode);
}
//清空收到的数据
void MainWindow::on_pushButton_Clear_clicked()
{
ui->plainTextEdit_BluetoothInfiShow->setPlainText("");
}
//连接蓝牙
void MainWindow::on_pushButton_ConnectDev_clicked()
{
QString text = ui->comboBox_BluetoothDevice->currentText();
int index = text.indexOf(' ');
if(index == -1) return;
QBluetoothAddress address(text.left(index));
QString connect_device="开始连接蓝牙设备:\n";
connect_device+=ui->comboBox_BluetoothDevice->currentText();
QMessageBox::information(this,tr("连接提示"),connect_device);
/*低功耗蓝牙设备*/
if(m_control!=NULL)
{
m_control->disconnectFromDevice(); //断开远程设备
delete m_control;
m_contro= NULL;
}
ui->comboBox_UUID->clear(); //清除显示UUID服务的列表框
QList<QBluetoothDeviceInfo> info_list=discoveryAgent->discoveredDevices(); //得到扫描的所有设备信息
for(int i=0;i<info_list.count();i++)
{
if(info_list.at(i).address().toString()==text.left(index))
{
remoteDevice=info_list.at(i);
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("连接设备:");
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(remoteDevice.name());
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n"); ui->plainTextEdit_BluetoothInfiShow->insertPlainText(remoteDevice.address().toString());
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
break;
}
}
//创建中央角色设备
m_contro= new QLowEnergyController(remoteDevice, this);
//m_control=QLowEnergyController::createCentral(remoteDevice,this);
if(m_control==0)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("创建中央角色设备失败!\n");
}
else
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("创建中央角色设备成功!\n");
}
//每次发现新的服务就会发送此信号
connect(m_control, SIGNAL(serviceDiscovered(QBluetoothUuid)),this, SLOT(BlueServiceDiscovered(QBluetoothUuid)));
//正在运行的服务发现完成时发出此信号。
connect(m_control, SIGNAL(discoveryFinished()),this, SLOT(BlueServiceScanDone()));
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
connect(m_control, SIGNAL(connected()),this, SLOT(BlueDeviceConnected()));
//当控制器从远程低功耗设备断开时发出此信号。
connect(m_control, SIGNAL(disconnected()),this, SLOT(BlueDeviceDisconnected()));
//该信号在发生错误时发出。
connect(m_control, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
[=](QLowEnergyController::Error error){
if(error==QLowEnergyController::NoError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有发生错误\n");
}
else if(error==QLowEnergyController::UnknownError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("出现未知错误。\n");
}
else if(error==QLowEnergyController::UnknownRemoteDeviceError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("无法找到传递给此类构造函数的远程Bluetooth Low Energy设备。\n");
}
else if(error==QLowEnergyController::NetworkError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取或写入远程设备失败\n");
}
else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备\n");
}
else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试连接到远程设备失败。\n");
}
else
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("*****未知错误!******\n");
});
//连接到远程蓝牙低功耗设备。
m_control->connectToDevice();
}
//每次发现新的服务,就会调用该槽函数
void MainWindow::BlueServiceDiscovered(const QBluetoothUuid &gatt)
{
ui->comboBox_UUID->addItem(gatt.toString()); //添加字符串到comboBox上
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(gatt.toString());
}
//帮助提示
void MainWindow::on_pushButton_help_clicked()
{
QMessageBox::information(this,tr("帮助提示"),"本软件用于BLE4.0蓝牙调试\n"
"不支持HC-05系列2.0版本蓝牙\n"
"软件下面按钮用于调整发送模式\n"
"软件作者:DS小龙哥\n"
"BUG反馈:1126626497@qq.com");
}
//默认指定UUID服务
static const QLatin1String serviceUuid("{0000FEE0-0000-1000-8000-00805F9B34FB}");
//正在运行的服务发现完成时发出此信号。
void MainWindow::BlueServiceScanDone()
{
// ui->plainTextEdit_BluetoothInfiShow->insertPlainText("正在运行的服务发现完成\n");
// QMessageBox::information(this,tr("帮助提示"),"服务发现完成\n"
// "请选择上方列表中的服务\n"
// "进行连接BLE低功耗蓝牙设备\n");
/*判断之前有没有连接过*/
if(m_service!=NULL)
{
delete m_service;
m_service=NULL;
}
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n选中的服务:");
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(serviceUuid);
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
/*与设备之间建立服务*/
m_service=m_control->createServiceObject(QBluetoothUuid(serviceUuid),this);
if(m_service==NULL)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务建立失败!\n");
return;
}
else
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务建立成功!\n");
}
/*服务状态改变时发出此信号。newState也可以通过state()。*/
connect(m_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)),
this, SLOT(BleServiceServiceStateChanged(QLowEnergyService::ServiceState)));
/*特性值由事件改变时发出此信号在外设上。 newValue参数包含更新后的值特性*/
connect(m_service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
this, SLOT(BleServiceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
/*当特征读取请求成功返回其值时,发出此信号。*/
connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)),
this, SLOT(BleServiceCharacteristicRead(QLowEnergyCharacteristic,QByteArray)));
/*当特性值成功更改为newValue时,会发出此信号。*/
connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),
this, SLOT(BleServiceCharacteristicWrite(QLowEnergyCharacteristic,QByteArray)));
/*错误信号*/
connect(m_service, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
[=](QLowEnergyService::ServiceError newErrorr)
{
if(QLowEnergyService::NoError == newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有发生错误。\n");
}
if(QLowEnergyService::OperationError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("错误: 当服务没有准备好时尝试进行操作!\n");
}
if(QLowEnergyService::CharacteristicReadError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取特征值失败!\n");
}
if(QLowEnergyService::CharacteristicWriteError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试为特性写入新值失败!\n");
}
if(QLowEnergyService::DescriptorReadError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取描述符值失败!\n");
}
if(QLowEnergyService::DescriptorWriteError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(" 尝试向描述符写入新值失败!\n");
}
if(QLowEnergyService::UnknownError==newErrorr)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("与服务交互时发生未知错误!\n");
}
});
if(m_service->state() == QLowEnergyService::DiscoveryRequired)
{
m_service->discoverDetails(); //启动服务发现扫描
}
else
searchCharacteristic();
}
//搜索特性
void MainWindow::searchCharacteristic()
{
if(m_service)
{
QList<QLowEnergyCharacteristic> list=m_service->characteristics();
qDebug()<<"list.count()="<<list.count();
//characteristics 获取详细特性
SendMaxMode=list.count(); //设置模式选择上限
for(int i=0;i<list.count();i++)
{
QLowEnergyCharacteristic c=list.at(i);
/*如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false*/
if(c.isValid())
{
// 返回特征的属性。
// 这些属性定义了特征的访问权限。
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
// if(c.properties() & QLowEnergyCharacteristic::Write)
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("具有写权限!\n");
m_writeCharacteristic[i] = c; //保存写权限特性
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
// 如果使用此模式写入特性,则远程外设不应发送写入确认。
// 无法确定操作的成功,并且有效负载不得超过20个字节。
// 一个特性必须设置QLowEnergyCharacteristic :: WriteNoResponse属性来支持这种写模式。
// 它的优点是更快的写入操作,因为它可能发生在其他设备交互之间。
m_writeMode = QLowEnergyService::WriteWithoutResponse;
else
m_writeMode = QLowEnergyService::WriteWithResponse;
//如果使用此模式写入特性,则外设应发送写入确认。
//如果操作成功,则通过characteristicWritten()信号发出确认。
//否则,发出CharacteristicWriteError。
//一个特性必须设置QLowEnergyCharacteristic :: Write属性来支持这种写模式。
}
if(c.properties() & QLowEnergyCharacteristic::Read)
{
m_readCharacteristic = c; //保存读权限特性
}
//描述符定义特征如何由特定客户端配置。
m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
//值为真
if(m_notificationDesc.isValid())
{
//写描述符
m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100"));
// m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("FEE1"));
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("写描述符!\n");
}
}
}
}
}
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
void MainWindow::BlueDeviceConnected()
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("成功连接设备!\n");
//启动发现服务Services
m_control->discoverServices();
// QList<QBluetoothUuid> uuid_list=m_control->services(); //获取已经查找成功的服务
// for(int i=0;i<uuid_list.count();i++)
// {
// ui->comboBox_UUID->addItem(uuid_list.at(i).toString()); //添加字符串到comboBox上
// }
// if(uuid_list.count()<=0)
// {
// ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有查找到UUID服务!\n");
// }
}
//当控制器从远程低功耗设备断开时发出此信号。
void MainWindow::BlueDeviceDisconnected()
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("成功断开!\n");
}
//当前选中的服务
void MainWindow::on_comboBox_UUID_currentIndexChanged(const QString &arg1)
{
}
void MainWindow::BleServiceServiceStateChanged(QLowEnergyService::ServiceState s)
{
//ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务状态改变时发出此信号!\n");
if(s == QLowEnergyService::ServiceDiscovered) //所有细节都已同步
{
ui->plainTextEdit_BluetoothInfiShow->insertPlainText("所有细节都已发现!\n");
searchCharacteristic();
}
}
//读取到数据
void MainWindow::BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c,
const QByteArray &value)
{
// ui->plainTextEdit_BluetoothInfiShow->insertPlainText("特性值由事件改变时发出此信号在外设上!\n");
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
//移动滚动条到底部
QScrollBar *scrollbar = ui->plainTextEdit_BluetoothInfiShow->verticalScrollBar();
if(scrollbar)
{
scrollbar->setSliderPosition(scrollbar->maximum());
}
}
void MainWindow::BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c,
const QByteArray &value)
{
// ui->plainTextEdit_BluetoothInfiShow->insertPlainText("当特征读取请求成功返回其值时\n");
//ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
}
void MainWindow::BleServiceCharacteristicWrite(const QLowEnergyCharacteristic &c,
const QByteArray &value)
{
//ui->plainTextEdit_BluetoothInfiShow->insertPlainText("当特性值成功更改为newValue时!\n");
ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
}
//发送模式
void MainWindow::on_pushButton_SendMode_clicked()
{
boook;
int data = QInputDialog::getInt(this, tr("获取输入模式"),tr("选择模式:"), 0, 0,SendMaxMode,1, &ok);
if(ok)
{
SendModeSelect=data;
}
}
|
(2) mainwindow.h文件代码 #ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QBluetoothLocalDevice>
#include <QBluetoothSocket>
#include "QListWidgetItem"
#include <QMessageBox>
#include <QBluetoothUuid>
#include <QLowEnergyController>
#include <QBluetoothUuid>
#include <QLowEnergyService>
#include <QScrollBar>
#include <QInputDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QBluetoothDeviceDiscoveryAgent *discoveryAgent; //这个是指扫描周围蓝牙设备!
QBluetoothLocalDevice *localDevice; //是指配置获取设备的蓝牙状态信息等!
QLowEnergyController *m_control;
QLowEnergyService *m_service;
QBluetoothDeviceInfo remoteDevice; //用于保存需要连接的设备的信息
QLowEnergyCharacteristic m_readCharacteristic; //读特性
QLowEnergyCharacteristic m_writeCharacteristic[5]; //写特性
QLowEnergyService::WriteMode m_writeMode;
QLowEnergyDescriptor m_notificationDesc;
void searchCharacteristic();
int SendMaxMode; //发送模式
int SendModeSelect;//选择发送模式
private slots:
void on_pushButton_OpenBluetooth_clicked();
void on_pushButton_CloseBluetooth_clicked();
void on_pushButton_BluetoothScan_clicked();
void addBlueToothDevicesToList(const QBluetoothDeviceInfo&); //发现蓝牙设备的槽函数
void on_pushButton_DeviceVisible_clicked();
void on_pushButton_StopScan_clicked();
void on_pushButton_SendData_clicked();
void on_pushButton_Clear_clicked();
void SetStyle(const QString &qssFile); //样式表设置函数
void on_pushButton_ConnectDev_clicked();
void on_pushButton_help_clicked();
void BlueServiceDiscovered(const QBluetoothUuid &gatt);
void BlueServiceScanDone(); //正在运行的服务发现完成时发出此信号。
void BlueDeviceConnected(); //当控制器成功连接到远程Low Energy设备时,会发出此信号。
void BlueDeviceDisconnected();//当控制器从远程低功耗设备断开时发出此信号。
void on_comboBox_UUID_currentIndexChanged(const QString &arg1); //选中的UUID服务
void BleServiceServiceStateChanged(QLowEnergyService::ServiceState s);//服务状态改变时发出此信号
void BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &value); //特性值由事件改变时发出此信号在外设上
void BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c, const QByteArray &value); //当特征读取请求成功返回其值时
void BleServiceCharacteristicWrite(const QLowEnergyCharacteristic &c, const QByteArray &value);//当特性值成功更改为newValue时
void on_pushButton_SendMode_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
|
(3) mainwindow.ui文件
13-6-2图
(4) 程序运行效果图
13-6-3图
技术合作与咨询
QQ:1126626497 关注我长按二维码可识别微信号:xl1126626497
---------------------------------------------------------------------------------------------------------------------- 我们尊 |