Bluetooth について学ぶ
Bluetooth クラシックと Bluetooth Low Energy の違い
クラシック Bluetooth (Bluetooth Classic) : 2.4 GHz (ISM) 周波数帯域で、基本レート/拡張データ レート (BR/EDR)、79 チャネルに分割されます。ポイントツーポイントのデバイス通信をサポートし、主にワイヤレス オーディオ ストリーミングを可能にするために使用され、ワイヤレス スピーカー、ヘッドフォン、車載エンターテイメント システムの背後にある標準の無線プロトコルとなっています。Bluetooth Classic は、モバイル印刷などのデータ転送プログラムもサポートしています。
Bluetooth Low Energy : 低電力動作向けに設計されています。2.4GHz のライセンス不要の ISM 帯域で動作し、合計 40 チャネルでデータを送信します。Bluetooth LE は、ポイントツーポイント、ブロードキャスト、メッシュなどの複数の通信トポロジをサポートします。Bluetooth を有効にして、信頼性の高い大規模ネットワークの構築をサポートします。LE は、高精度屋内測位サービスのニーズを満たすデバイス測位技術にも広く使用されています。
クラシック Bluetooth と Bluetooth Low Energy の違い - Zhihu
Bluetooth のペアリングと接続確立のプロセス
taodudu.cc/news/show-3161112.html?action=onClick
Qt Bluetooth モジュール
サポートされているプラットフォーム
Qt 5.14 では、Windows 7 以降ではクラシック Bluetooth、Windows 8 以降では Bluetooth LE をサポートするネイティブ Win32 ポートが追加されています。これは、構成オプション -native-win32-bluetooth によってビルド時に有効にする必要があります。このオプションが設定されておらず、Win32 ターゲット プラットフォームが必要な UWP API をサポートしている場合、UWP バックエンドが既定で使用されます (最小要件は Windows 10 バージョン 1507 で、Windows 10 バージョン 1607 以降はサービス検出が若干改善されています)。
使用
環境
バージョン: Qt15.15.2
言語: C++
プラットフォーム: Android 11
Bluetoothタイプ:クラシックBluetooth(Bluetoothクラシック)
コードと手順
使用前にBluetoothモジュールをproファイルにロードしてください
QT += bluetooth
誰もがBluetoothを使用した経験があると思いますが、大まかな手順としては、Bluetoothの状態確認(オンかどうか)→近くのデバイスを探す→ペアリング→接続→データ送信という流れに沿ってコードを紹介していきます。
- Bluetooth ステータスを確認します (オンになっているかどうか)。
QBluetoothLocalDevice は、ローカル Bluetooth デバイスのステータスを取得および設定する機能を提供します。
アクセス可能な
QBluetoothLocalDevice::HostMode QBluetoothLocalDevice::hostMode() const
現在のホストのモードを取得するには、ここではオンになっているかどうかだけを判断します。オンになっていない場合は、powerOn() を使用して Bluetooth をオンにすることができます。ただし、呼び出した後、すぐに接続を作成するために呼び出します。失敗する可能性があり、ハードウェアの準備がまだ整っていない可能性があります。
QBluetoothLocalDevice* m_pLocalDev;
m_pLocalDev = new QBluetoothLocalDevice(this);
//检查蓝牙是否未打开
if(m_pLocalDev->hostMode()==QBluetoothLocalDevice::HostPoweredOff)
{
m_pLocalDev->powerOn(); //打开蓝牙
emit errorBTDevPowerOff();
return false;
}
- 近くの Bluetooth デバイスを探す
QBluetoothDeviceDiscoveryAgentクラスは近くの Bluetooth デバイスを検出します
void BluetoothDevice::BluetoothDevice()
{
...
//初始化
QBluetoothDeviceDiscoveryAgent* m_pDevDiscoveryAgent;
m_pDevDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(m_pDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &BluetoothDevice::onDeviceDiscovered);
connect(m_pDevDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &BluetoothDevice::onDiscoverFinished);
connect(m_pDevDiscoveryAgent, QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error),
this, &BluetoothDevice::onDiscoverFinished);
...
}
void BluetoothDevice::refreshBTDevices()
{
...
//开始查找附近蓝牙设备,根据需求这里限定为经典蓝牙
m_pDevDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
}
//查找到的蓝牙设备的信息
void BluetoothDevice::onDeviceDiscovered(const QBluetoothDeviceInfo &device)
{
//MAC地址
const QString& macAddr = device.address().toString();
//设备名称
const QString& name= device.name();
//判读检测到设备是否与本地设备配对
bool isPaired = false;
if (pairingStatus == QBluetoothLocalDevice::Paired || pairingStatus ==
QBluetoothLocalDevice::AuthorizedPaired )
isPaired =true;
}
//查找结束
void BluetoothDevice::onDiscoverFinished()
{
emit discoveryFinished();
}
上記の方法では、近くにある Bluetooth デバイスをいくつか取得しますが、すべてのデバイスを取得できないことがよくあります。状況は次のようなものです。私の携帯電話は開発対象のデバイス(以下、デバイス)の Bluetooth を見つけることができますが、デバイスは携帯電話の Bluetooth を見つけられないため、携帯電話を使用して積極的に開発します。ペアリングを開始すると、ペアリングが成功し、ファイルや情報を送受信できるようになります。ペアリングが成功すると、デバイスは私の電話機の名前と Bluetooth MAC アドレスを認識できるようになりますが、QBluetoothDeviceDiscoveryAgent クラスはまだ私の電話機を見つけることができません。
デバイスは見つかりますが、Qt では見つからないため、Java のメソッドを使用して、ペアになっているデバイスのリストを直接取得してみてください。この方法は可能です。
package org.qtproject.toolkit.bluetooth;
import android.bluetooth.*;
import java.util.ArrayList;
import java.util.Set;
import java.lang.String;
public class BluetoothInfo
{
public BluetoothInfo(){}
public String[] getBondedDevices(boolean isBLE)
{
BluetoothAdapter BTAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> bondedDevice = BTAdapter.getBondedDevices();
ArrayList<String> list = new ArrayList<String>();
for (BluetoothDevice bt : bondedDevice)
{
int deviceType = bt.getType();
if (!isBLE && (deviceType == BluetoothDevice.DEVICE_TYPE_CLASSIC || deviceType == BluetoothDevice.DEVICE_TYPE_DUAL))
list.add(bt.getAddress() + " " + bt.getName());
else if (isBLE && (deviceType == BluetoothDevice.DEVICE_TYPE_LE || deviceType == BluetoothDevice.DEVICE_TYPE_DUAL))
list.add(bt.getAddress() + " " + bt.getName());
}
String[] result = (String[]) list.toArray(new String[list.size()]);
return result;
}
};
C++で呼び出される
#ifdef Q_OS_ANDROID
void BluetoothDevice::getBondedTarget()
{
QAndroidJniEnvironment env;
QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION");
if(r == QtAndroid::PermissionResult::Denied)
{
QtAndroid::requestPermissionsSync(QStringList() << "android.permission.ACCESS_FINE_LOCATION");
r = QtAndroid::checkPermission("android.permission.ACCESS_FINE_LOCATION");
if(r == QtAndroid::PermissionResult::Denied)
{
qDebug() << "failed to request";
}
}
qDebug() << "has permission";
QAndroidJniObject javaClass("org.qtproject.toolkit.bluetooth/BluetoothInfo");
QAndroidJniObject array = javaClass.callObjectMethod("getBondedDevices", "(Z)[Ljava/lang/String;", false);
int arraylen = env->GetArrayLength(array.object<jarray>());
qDebug() << "arraylen:" << arraylen ;
m_bondedDevices.clear();
for(int i = 0; i < arraylen; i++)
{
QString info = QAndroidJniObject::fromLocalRef(env->GetObjectArrayElement(array.object<jobjectArray>(), i)).toString();
BTDeviceInfo devInfo;
devInfo.macAddr = info.left(info.indexOf(' '));
devInfo.name = info.right(info.length() - info.indexOf(' ') - 1);
devInfo.isPaired = true;
m_bondedDevices.append(devInfo);
}
}
#endif
- ペア
上記で、近くにある Bluetooth デバイスのペアリング状態を取得しました。ペアリングされている場合は、手動でペアリングするか、次の方法を試してください。ただし、テスト中、携帯電話の Bluetooth デバイスが見つからなかったので、ペアリングしましたペアリングを要求するコードを試行せずに手動で実行します。
void QBluetoothLocalDevice::requestPairing(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing ペアリング)
- 接続の作成
Qt は Bluetooth クライアント ( QBluetoothSocket ) と Bluetooth サーバー (QBluetoothServer) をカプセル化します。これは Tcp の使用と非常によく似ています。ソケットはサーバーへの接続を試行し、サーバーは接続を監視し、双方が読み書きできます。
QBluetoothSocket はクライアントとして、サーバーへの接続を要求します。サーバーは、以前にペアリングされた携帯電話またはその他のデバイスです。携帯電話で Bluetooth サーバー QBluetoothServer がオンになっている必要があることに注意してください。オンになっていないと、接続は成功しません。
- サーバーに接続する
ご覧のとおり、サーバー アドレス、uuid、オープン モードを渡す必要があります。サーバー アドレスは、ペアになっている Bluetooth MAC アドレスです。uuid には多くの値があり、関数ごとに異なる uuid があります。列挙enum QBluetoothUuid::ServiceClassUuidを確認して確認できます。オープニング モードについては言うまでもありません。
void QBluetoothSocket::connectToService(const QBluetoothAddress &address, const QBluetoothUuid &uuid, QIODevice::OpenMode openMode = ReadWrite)
コード例
//初始化
QBluetoothSocket* m_pSocket;
QByteArray m_buf;
QString m_strServerUUID;
QString m_strMACAddr;
m_pSocket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol,this);
m_strServerUUID = QBluetoothUuid(QBluetoothUuid::SerialPort).toString();
connect(m_pSocket,&QBluetoothSocket::connected,this,&BluetoothConnection::onConnected); connect(m_pSocket,&QBluetoothSocket::disconnected,this,&BluetoothConnection::onDisconnect);
connect(m_pSocket,&QBluetoothSocket::readyRead,this,&BluetoothConnection::onReadyRead);
connect(m_pSocket, QOverload<QBluetoothSocket::SocketError>::of(&QBluetoothSocket::error),
this, &BluetoothConnection::onErrorOccurred);
//连接服务器 (uuid 可传入,可默认)
void BluetoothConnection::connectToSerive(QString strAddr, QString strUuid)
{
if(m_pSocket->state() == QBluetoothSocket::ConnectedState)
{
if(strAddr == m_strMACAddr && strUuid == m_strServerUUID)
{
return;
}
else
disconnect();
}
if(strUuid != "")
m_strServerUUID = strUuid;
m_strMACAddr = strAddr;
m_pSocket->connectToService(QBluetoothAddress(strAddr), QBluetoothUuid(m_strServerUUID),QIODevice::ReadWrite);
}
- データ転送処理
データ送信および処理部分についてはコードは表示されませんが、要件が異なり、コードも異なります。
結論
これはおそらく Android の Bluetooth クライアントの場合に当てはまります。