Notes on Qt5BLE Bluetooth development under win32

Posted by nev25 on Sun, 30 Jan 2022 13:21:16 +0100

BLE introduction

BLE Bluetooth is a Bluetooth module above Bluetooth 2.0, and classic Bluetooth is Bluetooth below Bluetooth 2.0. Bluetooth is divided into client and server. Classic Bluetooth can communicate between client and server through socket programming (similar to network socket), but BLE Bluetooth cannot communicate in this way. There are services and eigenvalues under BLE Bluetooth. The so-called BLE Bluetooth communication is actually a read-write operation of eigenvalues. Microsoft's API under Windows, C++API for BLE Bluetooth is relatively few, and C # API will be relatively more. The demo I implemented this Bluetooth is a development using Qt.

It should be noted that Qt Used in development QBlueTooth Library in Windows Only supported under win10 The above systems, and need Qt Version 5.15 Above, the compiler must be used MSVC Compile, otherwise it cannot be supported Windows Platform.

Qt5BLE Bluetooth development

The environment of this paper is Qt5 fifteen point two
To use Bluetooth Library in Qt, you need to Add a sentence to the pro file

QT += bluetooth

BLE Bluetooth development process

First of all, let's talk about my understanding of BLE Bluetooth. BLE Bluetooth has a name and address. There is a service under the Bluetooth device. The service has a specific uuid, which can be understood as the identification code of the service. There are features under the service. BLE Bluetooth service can have 0-3 features, namely read, write and eigenvalue notification. If the service has a read feature, you can read messages from the service. If the service has a write feature, you can send messages to the service. If the service has a feature of feature value change notification, a message notification will be sent when the feature value of the service changes.

  1. Bluetooth permission problem (this problem does not exist under Windows platform and can be ignored. This problem needs to be considered under Android platform, whether Qt or Java)
  2. Search surrounding Bluetooth
  3. Connect Bluetooth
  4. Get service
  5. Get the features under the service. There are 0-3 features under each service, which correspond to reading, writing and whether to notify when the features change
  6. Communicating with BLE devices (actually reading and writing a service)

Bluetooth Class involved in Qt and Bluetooth header files and classes involved in APIQt

#include <QBluetoothLocalDevice>
#include <QBluetoothUuid>
#include <QBluetoothDeviceDiscoveryAgent>
#include <QLowEnergyService>
#include <QLowEnergyController>

stay windows Platform and ios Under platform QBluetoothLocalDevice Class cannot be used
 Because the platform will not disclose any information that may be available locally Bluetooth Data or information provided on the device API

QBluetoothDeviceDiscoveryAgent -- Bluetooth search class( BLE (both Bluetooth and classic Bluetooth use this for searching)
LowEnergyController -- BLE Bluetooth device access class
QLowEnergyService -- BLE Bluetooth service class

Concrete implementation

1. Realize the search of nearby BLE Bluetooth

	QBluetoothDeviceDiscoveryAgent *Discovery = new QBluetoothDeviceDiscoveryAgent;
	Discovery->setLowEnergyDiscoveryTimeout(30000);//Set the search time to 30000us
	
	//When the Bluetooth search is completed, [Signal]finished() will be sent
	connect(Discovery, SIGNAL(finished()), 
			this, SLOT(findFinish()));
	
	//When a Bluetooth device is found, it will send [signal] devicediscovered (qbluetooth DeviceInfo)
	connect(Discovery, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), 
			this, SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo)));
	
	//start starts the search. If the search is BLE, Bluetooth needs to write parameters		 	   
	//QBluetoothDeviceDiscoveryAgent::LowEnergyMethod
	Discovery->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);

2. Connect BLE Bluetooth

//void QLowEnergyController::creatCentral(const QBluetoothDeviceInfo &remotedevice,QObject *parent)
	//Parameters: remotedevice -- information of remote device parent -- parent class
	//Return value: None
	//Function: initialize the controller for remote Bluetooth access
	mController = QLowEnergyController::createCentral(currentDevice,this);
	
	connect(mController, &QLowEnergyController::serviceDiscovered,this, &MainWindow::serviceDiscovered);//Scan the target BLE service, and get it and trigger it once
	connect(mController, &QLowEnergyController::discoveryFinished,this, &MainWindow::serviceScanDone);  //This signal is triggered after the scan is completed
	
	connect(mController, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
	        this, [this](QLowEnergyController::Error error) {
	        Q_UNUSED(error);
	        QMessageBox::information(this,tr("Info"),tr("Cannot connect to remote device."));
	    });//link error 
	connect(mController, &QLowEnergyController::connected, this, [this]() {
	        QMessageBox::information(this,tr("Info"),tr("Controller connected. Search services..."));
	        mController->discoverServices();
	    });//Connection successful
	connect(mController, &QLowEnergyController::disconnected, this, [this]() {
	        QMessageBox::information(this,tr("Info"),tr("LowEnergy controller disconnected"));
	    });//Disconnect
	mController->connectToDevice();//Establish a connection. If there is no error in the connection, the service of the connected device will be automatically searched

3. Access to services

//mController->connectToDevice(); If there is no error after the connection is established, the service scan of the remote device will be carried out automatically
//This slot function is triggered when the service is found

//Service found
void MainWindow::serviceDiscovered(const QBluetoothUuid & serviceUuid)
{
    QLowEnergyService *service = mController->createServiceObject(serviceUuid);
//Synchronization service
    if (!service)
    {
        QMessageBox::information(NULL,"error","Cannot create service for uuid");
        return;
    }

    connect(service, &QLowEnergyService::stateChanged, this,&MainWindow::serviceStateChanged);
//Service status value changed
    connect(service, &QLowEnergyService::characteristicChanged, this,&MainWindow::BleServiceCharacteristicChanged);
//Eigenvalue changes
    connect(service, &QLowEnergyService::characteristicRead, this,&MainWindow::BleServiceCharacteristicRead);
//Read information successfully
    connect(service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),this, SLOT(BleServiceCharacteristicWrite(QLowEnergyCharacteristic,QByteArray)));
//Write message succeeded

    if(service->state() == QLowEnergyService::DiscoveryRequired)
        service->discoverDetails();
//Scan eigenvalue

    serviceList.append(service);
}

//This slot function is triggered when the service status value changes
//When the Bluetooth service is scanned, the status value will change to QLowEnergyService::ServiceDiscovered
void MainWindow::serviceStateChanged(QLowEnergyService::ServiceState s)
{
    if(s == QLowEnergyService::ServiceDiscovered)
    {
        //QMessageBox::information(NULL,"tips",QObject::tr("Service synchronization"));
        //TODO....
    }
}

4. Scan service characteristic value

void MainWindow::searchCharacteristic()
{
    if(currentService)
    {
        memset(m_Characteristic,0,sizeof(m_Characteristic));
        QList<QLowEnergyCharacteristic> list = currentService->characteristics();
        //Characteristics get detailed characteristics
        foreach(QLowEnergyCharacteristic c,list)
        {
            /*Returns true if the QLowEnergyCharacteristic object is valid, otherwise false*/
            if(c.isValid())
            {
                //Returns the properties of the feature.
                //These attributes define the access rights of the feature.
				//Save properties (notify when reading, writing and changing)
                if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)//write
                // if(c.properties() & QLowEnergyCharacteristic::Write)
                {
                    ui->checkBox_write->setChecked(true);
                    m_Characteristic[0] = c;
                }
                else
                    ui->checkBox_write->setChecked(false);
                if(c.properties() & QLowEnergyCharacteristic::Read)//read
                {
                    ui->checkBox_read->setChecked(true);
                    m_Characteristic[1] = c;
                }
                else
                    ui->checkBox_read->setChecked(true);
                if(c.properties() & QLowEnergyCharacteristic::Notify)//Is it notified when the characteristics change
                {
                    ui->checkBox_notify->setChecked(true);
                    m_Characteristic[2] = c;
                }
                else
                    ui->checkBox_notify->setChecked(false);
            }
        }
    }
}

5. Read and write operation of ble Bluetooth

//void QLowEnergyService::writeCharacteristic(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue, QLowEnergyService::WriteMode mode = WriteWithResponse)
//Parameters: Characteristic -- a characteristic value of the current service newValue -- write data WriteMode mode -- write mode
//Return value: None
//Function: send information to BLE
currentService->writeCharacteristic(m_Characteristic[0], QByteArray(text.toUtf8()));
//This slot function is triggered successfully after sending a message
void MainWindow::BleServiceCharacteristicWrite(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    QString str(c.uuid().toString());
    QString str2("instructions %1 send to success!");
    QString str3 = str + QString(":") + str2.arg(QString(value));
    QMessageBox::information(NULL,"tips",str3);
}
//void QLowEnergyService::readCharacteristic(const QLowEnergyCharacteristic &characteristic)
//Parameter: Characteristic -- a characteristic value of the current service
//Return value: None
//Function: read information from BLE
currentService->readCharacteristic(m_Characteristic[1]);
//This slot function is triggered when a message is read
void MainWindow::BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
    QTextCodec *codec = QTextCodec::codecForName("GBK");//Specifies how QString is encoded
    QString showMsg = c.uuid().toString() + codec->toUnicode(value);//Output information in Unicode encoding format
    QString valuetoHexString = value.toHex();//Hexadecimal output information

    qDebug()<<value;
    qDebug()<<valuetoHexString;
    ui->listWidget_recv->addItem(showMsg);
    ui->listWidget_recv->setCurrentRow(ui->listWidget_recv->count()-1);
}

Topics: Qt Qt5 bluetooth BLE