「Qtの基礎 - Bluetooth Low Energy」の版間の差分

ナビゲーションに移動 検索に移動
356行目: 356行目:
* discoveryFinishedシグナルで探索完了を検知する
* discoveryFinishedシグナルで探索完了を検知する
* createServiceObjectメソッドを使用して、サービスオブジェクトを生成する
* createServiceObjectメソッドを使用して、サービスオブジェクトを生成する
<br>
==== 使用例 ====
<syntaxhighlight lang="c++">
#include <QObject>
#include <QLowEnergyController>
#include <QLowEnergyService>
#include <QTimer>
#include <memory>
#include <QDebug>
class BLEServiceDiscovery : public QObject
{
    Q_OBJECT
private:
    std::unique_ptr<QLowEnergyController> controller;
    std::unique_ptr<QTimer>              discoveryTimeout;
    void connectControllerSignals()
    {
      connect(controller.get(), &QLowEnergyController::connected, this, &BLEServiceDiscovery::onConnected);
      connect(controller.get(), &QLowEnergyController::disconnected, this, &BLEServiceDiscovery::onDisconnected);
      connect(controller.get(), &QLowEnergyController::serviceDiscovered, this, &BLEServiceDiscovery::onServiceDiscovered);
      connect(controller.get(), &QLowEnergyController::discoveryFinished, this, &BLEServiceDiscovery::onDiscoveryFinished);
      connect(controller.get(), static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error), this, &BLEServiceDiscovery::onError);
      connect(controller.get(), &QLowEnergyController::stateChanged, this, &BLEServiceDiscovery::onStateChanged);
    }
    void connectServiceSignals(QLowEnergyService *service)
    {
      connect(service, &QLowEnergyService::stateChanged, this, [this, service](QLowEnergyService::ServiceState newState) {
          qDebug() << "サービス状態が変更: " << getServiceStateMessage(newState);
      });
      connect(service, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error), this, [this](QLowEnergyService::ServiceError error) {
          qDebug() << "サービスエラー: " << getServiceErrorMessage(error);
      });
    }
    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 "予期せぬサービスエラー";
      }
    }
public:
    explicit BLEServiceDiscovery(QObject* parent = nullptr) : QObject(parent)
    {
      // タイムアウトタイマの初期化
      discoveryTimeout = std::make_unique<QTimer>(this);
      discoveryTimeout->setInterval(10000);  // 10秒のタイムアウト
      discoveryTimeout->setSingleShot(true);
      connect(discoveryTimeout.get(), &QTimer::timeout, this, &BLEServiceDiscovery::onDiscoveryTimeout);
    }
    // デバイスへの接続とサービス探索の開始
    void startDiscovery(const QBluetoothDeviceInfo& device)
    {
      try {
          qDebug() << "サービス探索を開始: " << device.name();
          // コントローラの初期化
          controller = std::make_unique<QLowEnergyController>(device, this);
          connectControllerSignals();
          // 接続開始
          controller->connectToDevice();
          discoveryTimeout->start();
      }
      catch (const std::exception &e) {
          QString errorMsg = QString("探索開始エラー: %1").arg(e.what());
          qDebug() << errorMsg;
          emit errorOccurred(errorMsg);
      }
    }
    // 探索を停止
    void stopDiscovery()
    {
      try {
          if (controller) {
            controller->disconnectFromDevice();
            discoveryTimeout->stop();
          }
      }
      catch (const std::exception &e) {
          QString errorMsg = QString("探索停止エラー: %1").arg(e.what());
          qDebug() << errorMsg;
          emit errorOccurred(errorMsg);
      }
    }
signals:
    void serviceDiscovered(QLowEnergyService *service);
    void discoveryComplete();
    void errorOccurred(const QString &error);
    void connectionStateChanged(QLowEnergyController::ControllerState state);
private slots:
    void onConnected()
    {
      qDebug() << "デバイスに接続";
      discoveryTimeout->stop();
      // サービス探索の開始
      controller->discoverServices();
    }
    void onDisconnected()
    {
      qDebug() << "デバイスから切断";
      discoveryTimeout->stop();
    }
    void onServiceDiscovered(const QBluetoothUuid& uuid)
    {
      qDebug() << "サービスを発見:" << uuid.toString();
      // サービスオブジェクトの作成
      QLowEnergyService* service = controller->createServiceObject(uuid, this);
      if (service) {
          connectServiceSignals(service);
          emit serviceDiscovered(service);
      }
    }
    void onDiscoveryFinished()
    {
      qDebug() << "サービス探索が完了";
      discoveryTimeout->stop();
      emit discoveryComplete();
    }
    void onError(QLowEnergyController::Error error)
    {
      QString errorMessage = getErrorMessage(error);
      qDebug() << "エラーが発生: " << errorMessage;
      emit errorOccurred(errorMessage);
    }
    void onDiscoveryTimeout()
    {
      qDebug() << "サービス探索がタイムアウト";
      stopDiscovery();
      emit errorOccurred("探索タイムアウト");
    }
    void onStateChanged(QLowEnergyController::ControllerState state)
    {
      qDebug() << "接続状態が変更: " << getStateMessage(state);
      emit connectionStateChanged(state);
    }
};
</syntaxhighlight>
<br><br>
<br><br>


案内メニュー