📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
| (同じ利用者による、間の2版が非表示) | |||
| 893行目: | 893行目: | ||
Classic Bluetoothでは、<code>QBluetoothSocket</code>クラスを使用して、<br> | Classic Bluetoothでは、<code>QBluetoothSocket</code>クラスを使用して、<br> | ||
<code>connect</code>メソッドでソケット接続、<code>write</code>メソッド / <code>read</code>メソッドでデータの送受信を行う。<br> | <code>connect</code>メソッドでソケット接続、<code>write</code>メソッド / <code>read</code>メソッドでデータの送受信を行う。<br> | ||
<br> | |||
接続の確立と維持を行う処理は、全ての操作が非同期で行われる。<br> | |||
そのため、各段階でのシグナル / スロット接続による状態管理が重要になる。<br> | |||
<br> | |||
==== 接続の確立 ==== | |||
<code>QBluetoothSocket</code>クラスのインスタンスを生成する。<br> | |||
この時、RFCOMMプロトコルを指定する。<br> | |||
<br> | |||
デバイスのMACアドレスとポート番号を指定して、<code>QBluetoothSocket::connectToService</code>メソッドを実行する。<br> | |||
接続状態の変化を監視するためのシグナル / スロット接続を設定する。<br> | |||
<br> | <br> | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
#include <QBluetoothSocket> | #include <QBluetoothSocket> | ||
#include <QDebug> | #include <QDebug> | ||
#include < | |||
QBluetoothSocket socket(QBluetoothServiceInfo::RfcommProtocol); | |||
connect(&socket, &QBluetoothSocket::connected, []() { | |||
qDebug() << "接続成功"; | |||
}); | |||
connect(&socket, &QBluetoothSocket::stateChanged, [](QBluetoothSocket::SocketState state) { | |||
qDebug() << "状態変更:" << state; | |||
}); | |||
connect(&socket, &QBluetoothSocket::errorOccurred, [](QBluetoothSocket::SocketError error) { | |||
qDebug() << "エラー発生:" << error; | |||
}); | |||
</syntaxhighlight> | |||
<br> | |||
RFCOMM (Radio Frequency Communication) とは、Bluetooth Classicで使用される重要なプロトコルの1つである。<br> | |||
RFCOMMプロトコルの特徴を以下に示す。<br> | |||
* シリアルポート通信をエミュレートするプロトコル | |||
* RS-232C通信の代替として設計 | |||
* 信頼性の高い双方向通信を提供 | |||
* 最大60個の同時接続をサポート | |||
<br> | |||
Qtで使用可能な他のBluetoothプロトコルを以下に示す。<br> | |||
* L2CAP (Logical Link Control and Adaptation Protocol) | |||
*: 低レイヤーのプロトコル | |||
*: RFCOMMの基盤となるプロトコル | |||
*: より高速なデータ転送が可能 | |||
*: 生のデータパケット送受信に使用 | |||
*: <br> | |||
* RFCOMM | |||
*: 最も使用される。 | |||
*: シリアルポートエミュレーション | |||
*: 多くのBluetooth機器で採用されている。 | |||
*: 多くのBluetooth通信では、使いやすさと互換性の高さからRFCOMMが選択される。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// RFCOMMプロトコルを指定する場合 | |||
// シリアル通信が必要な場合 あるいは 安定性が重要な場合 | |||
QBluetoothSocket socket(QBluetoothServiceInfo::RfcommProtocol); | |||
// L2CAPプロトコルを指定する場合 | |||
// 高速な通信が必要な場合 あるいは 低レベルの制御が必要な場合 | |||
QBluetoothSocket socket(QBluetoothServiceInfo::L2capProtocol); | |||
</syntaxhighlight> | |||
<br> | |||
==== 接続の維持 ==== | |||
<code>QBluetoothSocket::connected</code>シグナルを受信して、接続成功を確認する。<br> | |||
<br> | |||
<code>QBluetoothSocket::stateChanged</code>シグナルを監視して、接続状態の変化を検知する。<br> | |||
<br> | |||
<code>QBluetoothSocket::errorOccurred</code>シグナルを監視してエラーを検知する。<br> | |||
<br> | |||
また、必要に応じて定期的なキープアライブメッセージを送信する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
QBluetoothAddress address("XX:XX:XX:XX:XX:XX"); | |||
socket.connectToService(address, <ポート番号 例: 1>); | |||
</syntaxhighlight> | |||
<br> | |||
==== データの送信 ==== | |||
<code>QBluetoothSocket::write</code>メソッドを使用してデータを送信する。<br> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
QByteArray sendData = "Hello"; | |||
socket.write(sendData); | |||
</syntaxhighlight> | |||
<br> | |||
==== データの受信 ==== | |||
# <code>QBluetoothSocket::readyRead</code>シグナルを受信してデータの到着を検知する。 | |||
# <code>QBluetoothSocket::readAll</code>メソッド、あるいは、<code>QBluetoothSocket::read</code>メソッドでデータを読む。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
connect(&socket, &QBluetoothSocket::readyRead, []() { | |||
QByteArray data = socket.readAll(); | |||
qDebug() << "受信データ: " << data; | |||
}); | |||
</syntaxhighlight> | |||
<br> | |||
==== 切断処理 ==== | |||
# <code>QBluetoothSocket::disconnectFromService</code>メソッドを実行して、接続を終了する。 | |||
# <code>QBluetoothSocket::disconnected</code>シグナルを受信して切断完了を確認する。 | |||
# 必要に応じて、リソースの解放を実施する。 | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
connect(&socket, &QBluetoothSocket::disconnected, []() { | |||
qDebug() << "切断完了"; | |||
}); | |||
// 切断を実行 | |||
socket.disconnectFromService(); | |||
</syntaxhighlight> | |||
<br> | |||
==== 組み合わせ ==== | |||
<syntaxhighlight lang="c++"> | |||
#include <QBluetoothSocket> | |||
#include <QDebug> | |||
class BluetoothConnection : public QObject | class BluetoothConnection : public QObject | ||
| 904行目: | 1,010行目: | ||
private: | private: | ||
QBluetoothSocket socket; | |||
// | // エラーコード | ||
QString errorToString(QBluetoothSocket::SocketError error) | QString errorToString(QBluetoothSocket::SocketError error) | ||
{ | { | ||
| 920行目: | 1,026行目: | ||
} | } | ||
// | // 接続状態 | ||
QString stateToString(QBluetoothSocket::SocketState state) | QString stateToString(QBluetoothSocket::SocketState state) | ||
{ | { | ||
| 935行目: | 1,041行目: | ||
public: | public: | ||
explicit BluetoothConnection(QObject* parent = nullptr) : QObject(parent) | explicit BluetoothConnection(QObject *parent = nullptr) : QObject(parent), socket(QBluetoothServiceInfo::RfcommProtocol, this) | ||
{ | { | ||
// 各種シグナルとスロットの接続 | |||
connect(&socket, &QBluetoothSocket::connected, this, &BluetoothConnection::onConnected); | |||
connect(&socket, &QBluetoothSocket::disconnected, this, &BluetoothConnection::onDisconnected); | |||
connect(&socket, &QBluetoothSocket::errorOccurred, this, &BluetoothConnection::onError); | |||
connect(&socket, &QBluetoothSocket::readyRead, this, &BluetoothConnection::onDataReceived); | |||
connect(&socket, &QBluetoothSocket::stateChanged, this, &BluetoothConnection::onStateChanged); | |||
} | |||
~BluetoothConnection() | |||
{ | |||
disconnect(); | |||
} | } | ||
| 957行目: | 1,059行目: | ||
void connectToDevice(const QBluetoothAddress &address, quint16 port) | void connectToDevice(const QBluetoothAddress &address, quint16 port) | ||
{ | { | ||
if (socket.state() == QBluetoothSocket::ConnectedState) { | |||
qDebug() << "既に接続済み"; | |||
return; | |||
} | |||
qDebug() << "デバイスに接続します: " << address.toString(); | |||
qDebug() << "ポート: " << port; | |||
socket.connectToService(address, port); | |||
} | } | ||
| 976行目: | 1,072行目: | ||
void disconnect() | void disconnect() | ||
{ | { | ||
if (socket.state() != QBluetoothSocket::UnconnectedState) { | |||
qDebug() << "接続を切断..."; | |||
socket.disconnectFromService(); | |||
} | } | ||
} | } | ||
| 991行目: | 1,081行目: | ||
bool sendData(const QByteArray &data) | bool sendData(const QByteArray &data) | ||
{ | { | ||
if (socket.state() != QBluetoothSocket::ConnectedState) { | |||
qDebug() << "送信エラー: 接続されていません"; | |||
return false; | |||
} | |||
qint64 bytesWritten = socket.write(data); | |||
if (bytesWritten == -1) { | |||
qDebug() << "送信エラー: データの書き込みに失敗"; | |||
return false; | |||
} | |||
qDebug() << bytesWritten << "バイトデータの送信完了"; | |||
return true; | |||
} | } | ||
private slots: | private slots: | ||
// | // 接続確立時 | ||
void onConnected() | void onConnected() | ||
{ | { | ||
qDebug() << "接続が確立"; | qDebug() << "接続が確立"; | ||
qDebug() << " ローカルアドレス:" << socket | qDebug() << " ローカルアドレス:" << socket.localAddress().toString(); | ||
qDebug() << " リモートアドレス:" << socket | qDebug() << " リモートアドレス:" << socket.peerAddress().toString(); | ||
} | } | ||
// | // 切断時 | ||
void onDisconnected() | void onDisconnected() | ||
{ | { | ||
| 1,027行目: | 1,111行目: | ||
} | } | ||
// | // エラー発生時 | ||
void onError(QBluetoothSocket::SocketError error) | void onError(QBluetoothSocket::SocketError error) | ||
{ | { | ||
| 1,033行目: | 1,117行目: | ||
} | } | ||
// | // データ受信時 | ||
void onDataReceived() | void onDataReceived() | ||
{ | { | ||
QByteArray data = socket | QByteArray data = socket.readAll(); | ||
qDebug() << "データを受信: " << data.size() << "バイト"; | qDebug() << "データを受信: " << data.size() << "バイト"; | ||
| 1,043行目: | 1,127行目: | ||
} | } | ||
// | // 接続状態変更時 | ||
void onStateChanged(QBluetoothSocket::SocketState state) | void onStateChanged(QBluetoothSocket::SocketState state) | ||
{ | { | ||