12,796
回編集
806行目: | 806行目: | ||
*: Notifyと同様、確認応答あり | *: Notifyと同様、確認応答あり | ||
<br> | <br> | ||
Classic | ==== Classic Bluetoothとの違い ==== | ||
* キャラクタリスティックの操作が基本 | * キャラクタリスティックの操作が基本 | ||
* 読み取り | * 読み取り | ||
814行目: | 814行目: | ||
* 通知 | * 通知 | ||
*: characteristicChangedシグナルで受信 | *: characteristicChangedシグナルで受信 | ||
<br> | |||
==== 使用例 ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QObject> | |||
#include <QLowEnergyController> | |||
#include <QLowEnergyService> | |||
#include <QLowEnergyCharacteristic> | |||
#include <QTimer> | |||
#include <memory> | |||
#include <QDebug> | |||
class BLEConnection : public QObject | |||
{ | |||
Q_OBJECT | |||
private: | |||
std::unique_ptr<QLowEnergyController> controller; | |||
std::unique_ptr<QTimer> reconnectTimer; | |||
QBluetoothDeviceInfo currentDevice; | |||
bool autoReconnect = false; | |||
void connectControllerSignals() | |||
{ | |||
connect(controller.get(), &QLowEnergyController::connected, this, &BLEConnection::onConnected); | |||
connect(controller.get(), &QLowEnergyController::disconnected, this, &BLEConnection::onDisconnected); | |||
connect(controller.get(), &QLowEnergyController::serviceDiscovered, this, &BLEConnection::onServiceDiscovered); | |||
connect(controller.get(), static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error), this, &BLEConnection::onError); | |||
connect(controller.get(), &QLowEnergyController::stateChanged, this, &BLEConnection::onStateChanged); | |||
} | |||
void connectServiceSignals(QLowEnergyService *service) | |||
{ | |||
connect(service, &QLowEnergyService::stateChanged, this, [this, service](QLowEnergyService::ServiceState newState) { | |||
qDebug() << "サービス状態が変更: " << getServiceStateMessage(newState); | |||
if (newState == QLowEnergyService::ServiceDiscovered) { | |||
// キャラクタリスティックの処理 | |||
const QList<QLowEnergyCharacteristic> chars = service->characteristics(); | |||
for (const QLowEnergyCharacteristic& ch : chars) { | |||
qDebug() << "キャラクタリスティック発見:"; | |||
qDebug() << " UUID: " << ch. | |||
qDebug() << "キャラクタリスティック発見:"; | |||
qDebug() << " UUID: " << ch.uuid().toString(); | |||
qDebug() << " プロパティ: " << getCharacteristicPropertiesString(ch.properties()); | |||
// Notify対応のキャラクタリスティックの場合 | |||
if (ch.properties() & QLowEnergyCharacteristic::Notify) { | |||
QLowEnergyDescriptor notifyDesc = ch.descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration); | |||
if (notifyDesc.isValid()) { | |||
service->writeDescriptor(notifyDesc, QByteArray::fromHex("0100")); | |||
} | |||
} | |||
} | |||
} | |||
}); | |||
connect(service, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error), this, | |||
[this](QLowEnergyService::ServiceError error) { | |||
qDebug() << "サービスエラー:" << getServiceErrorMessage(error); | |||
}); | |||
connect(service, &QLowEnergyService::characteristicChanged, this, | |||
[](const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) { | |||
qDebug() << "キャラクタリスティック値が変更:"; | |||
qDebug() << " UUID:" << characteristic.uuid().toString(); | |||
qDebug() << " 新しい値:" << newValue.toHex(); | |||
}); | |||
} | |||
QString getErrorMessage(QLowEnergyController::Error error) | |||
{ | |||
switch (error) { | |||
case QLowEnergyController::NoError: return "エラーなし"; | |||
case QLowEnergyController::UnknownError: return "不明なエラー"; | |||
case QLowEnergyController::UnknownRemoteDeviceError: return "リモートデバイスが見つかりません"; | |||
case QLowEnergyController::NetworkError: return "ネットワークエラー"; | |||
case QLowEnergyController::InvalidBluetoothAdapterError: return "無効なBluetoothアダプタ"; | |||
case QLowEnergyController::ConnectionError: return "接続エラー"; | |||
default: return "予期せぬエラー"; | |||
} | |||
} | |||
QString getStateMessage(QLowEnergyController::ControllerState state) | |||
{ | |||
switch (state) { | |||
case QLowEnergyController::UnconnectedState: return "未接続"; | |||
case QLowEnergyController::ConnectingState: return "接続中"; | |||
case QLowEnergyController::ConnectedState: return "接続済み"; | |||
case QLowEnergyController::DiscoveringState: return "探索中"; | |||
case QLowEnergyController::DiscoveredState: return "探索完了"; | |||
case QLowEnergyController::ClosingState: return "切断中"; | |||
case QLowEnergyController::AdvertisingState: return "アドバタイジング中"; | |||
default: return "不明な状態"; | |||
} | |||
} | |||
QString getServiceStateMessage(QLowEnergyService::ServiceState state) | |||
{ | |||
switch (state) { | |||
case QLowEnergyService::InvalidService: return "無効なサービス"; | |||
case QLowEnergyService::DiscoveryRequired: return "探索が必要"; | |||
case QLowEnergyService::DiscoveringServices: return "サービス探索中"; | |||
case QLowEnergyService::ServiceDiscovered: return "サービス探索完了"; | |||
default: return "不明なサービス状態"; | |||
} | |||
} | |||
QString getServiceErrorMessage(QLowEnergyService::ServiceError error) | |||
{ | |||
switch (error) { | |||
case QLowEnergyService::NoError: return "エラーなし"; | |||
case QLowEnergyService::OperationError: return "操作エラー"; | |||
case QLowEnergyService::CharacteristicReadError: return "キャラクタリスティック読み取りエラー"; | |||
case QLowEnergyService::CharacteristicWriteError: return "キャラクタリスティック書き込みエラー"; | |||
case QLowEnergyService::DescriptorReadError: return "ディスクリプタ読み取りエラー"; | |||
case QLowEnergyService::DescriptorWriteError: return "ディスクリプタ書き込みエラー"; | |||
case QLowEnergyService::UnknownError: return "不明なエラー"; | |||
default: return "予期せぬサービスエラー"; | |||
} | |||
} | |||
QString getCharacteristicPropertiesString(QLowEnergyCharacteristic::PropertyTypes properties) | |||
{ | |||
QStringList props; | |||
if (properties & QLowEnergyCharacteristic::Read) props << "Read"; | |||
if (properties & QLowEnergyCharacteristic::Write) props << "Write"; | |||
if (properties & QLowEnergyCharacteristic::Notify) props << "Notify"; | |||
if (properties & QLowEnergyCharacteristic::Indicate) props << "Indicate"; | |||
if (properties & QLowEnergyCharacteristic::WriteSigned) props << "WriteSigned"; | |||
if (properties & QLowEnergyCharacteristic::WriteNoResponse) props << "WriteNoResponse"; | |||
return props.join(", "); | |||
} | |||
public: | |||
explicit BLEConnection(QObject* parent = nullptr) : QObject(parent) | |||
{ | |||
// 再接続タイマの初期化 | |||
reconnectTimer = std::make_unique<QTimer>(this); | |||
reconnectTimer->setInterval(5000); // 5秒間隔で再接続 | |||
reconnectTimer->setSingleShot(true); | |||
connect(reconnectTimer.get(), &QTimer::timeout, this, &BLEConnection::onReconnectTimeout); | |||
} | |||
// デバイスへの接続 | |||
void connectToDevice(const QBluetoothDeviceInfo &device) | |||
{ | |||
try { | |||
qDebug() << "デバイスへの接続を開始:" << device.name(); | |||
// コントローラの初期化 | |||
controller = std::make_unique<QLowEnergyController>(device, this); | |||
connectControllerSignals(); | |||
// 接続パラメータの設定 | |||
controller->setRemoteAddressType(QLowEnergyController::PublicAddress); | |||
// 接続開始 | |||
controller->connectToDevice(); | |||
currentDevice = device; | |||
} | |||
catch (const std::exception &e) { | |||
QString errorMsg = QString("接続エラー: %1").arg(e.what()); | |||
qDebug() << errorMsg; | |||
emit errorOccurred(errorMsg); | |||
} | |||
} | |||
// 切断 | |||
void disconnect() | |||
{ | |||
try { | |||
if (controller) { | |||
controller->disconnectFromDevice(); | |||
reconnectTimer->stop(); | |||
} | |||
} | |||
catch (const std::exception &e) { | |||
QString errorMsg = QString("切断エラー: %1").arg(e.what()); | |||
qDebug() << errorMsg; | |||
emit errorOccurred(errorMsg); | |||
} | |||
} | |||
// 自動再接続の設定 | |||
void setAutoReconnect(bool enable) | |||
{ | |||
autoReconnect = enable; | |||
if (!enable) { | |||
reconnectTimer->stop(); | |||
} | |||
} | |||
signals: | |||
void connected(); | |||
void disconnected(); | |||
void errorOccurred(const QString& error); | |||
void connectionStateChanged(QLowEnergyController::ControllerState state); | |||
void serviceDiscovered(QLowEnergyService* service); | |||
private slots: | |||
void onConnected() | |||
{ | |||
qDebug() << "デバイスに接続"; | |||
reconnectTimer->stop(); | |||
emit connected(); | |||
// サービスの探索を開始 | |||
controller->discoverServices(); | |||
} | |||
void onDisconnected() | |||
{ | |||
qDebug() << "デバイスから切断"; | |||
emit disconnected(); | |||
// 自動再接続が有効な場合 | |||
if (autoReconnect) { | |||
qDebug() << "再接続を試行..."; | |||
reconnectTimer->start(); | |||
} | |||
} | |||
void onServiceDiscovered(const QBluetoothUuid& uuid) | |||
{ | |||
qDebug() << "サービスを発見: " << uuid.toString(); | |||
QLowEnergyService* service = controller->createServiceObject(uuid, this); | |||
if (service) { | |||
connectServiceSignals(service); | |||
emit serviceDiscovered(service); | |||
} | |||
} | |||
void onError(QLowEnergyController::Error error) | |||
{ | |||
QString errorMessage = getErrorMessage(error); | |||
qDebug() << "エラーが発生: " << errorMessage; | |||
emit errorOccurred(errorMessage); | |||
if (autoReconnect && error != QLowEnergyController::InvalidBluetoothAdapterError) reconnectTimer->start(); | |||
} | |||
void onStateChanged(QLowEnergyController::ControllerState state) | |||
{ | |||
qDebug() << "接続状態が変更: " << getStateMessage(state); | |||
emit connectionStateChanged(state); | |||
} | |||
void onReconnectTimeout() | |||
{ | |||
if (autoReconnect && currentDevice.isValid()) { | |||
qDebug() << "再接続を試行..."; | |||
controller->connectToDevice(); | |||
} | |||
} | |||
}; | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||