10 _setupClassicSocket();
15 qCDebug(BluetoothLinkLog) <<
"Attempting to connect to" <<
_device.name() <<
"Mode: Classic";
19 _socket->disconnect();
20 _socket->deleteLater();
24 _setupClassicSocket();
31 _socket->connectToService(
_device.address(), SPP_UUID);
36 if (_classicDiscovery && _classicDiscovery->isActive()) {
37 _classicDiscovery->stop();
41 _socket->disconnectFromService();
47 _writeClassicData(data);
52 if (_classicDiscovery && _classicDiscovery->isActive()) {
53 _classicDiscovery->stop();
68 _socket->disconnect();
69 if (_socket->state() == QBluetoothSocket::SocketState::ConnectedState) {
70 _socket->disconnectFromService();
72 _socket->deleteLater();
76void BluetoothClassicWorker::_setupClassicSocket()
82 _socket =
new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol,
this);
84 (void) connect(_socket.data(), &QBluetoothSocket::connected,
this, &BluetoothClassicWorker::_onSocketConnected);
85 (void) connect(_socket.data(), &QBluetoothSocket::disconnected,
this, &BluetoothClassicWorker::_onSocketDisconnected);
86 (void) connect(_socket.data(), &QBluetoothSocket::readyRead,
this, &BluetoothClassicWorker::_onSocketReadyRead);
87 (void) connect(_socket.data(), &QBluetoothSocket::errorOccurred,
this, &BluetoothClassicWorker::_onSocketErrorOccurred);
89 if (BluetoothLinkLog().isDebugEnabled()) {
90 (void) connect(_socket.data(), &QBluetoothSocket::bytesWritten,
this, &BluetoothClassicWorker::_onSocketBytesWritten);
92 (void) connect(_socket.data(), &QBluetoothSocket::stateChanged,
this,
93 [](QBluetoothSocket::SocketState state) {
94 qCDebug(BluetoothLinkLog) <<
"Bluetooth Socket State Changed:" << state;
99void BluetoothClassicWorker::_writeClassicData(
const QByteArray &data)
101 if (!_socket || !_socket->isWritable()) {
106 qint64 totalBytesWritten = 0;
107 while (totalBytesWritten < data.size()) {
108 const qint64 bytesWritten = _socket->write(data.constData() + totalBytesWritten,
109 data.size() - totalBytesWritten);
110 if (bytesWritten == -1) {
111 emit
errorOccurred(tr(
"Write failed: %1").arg(_socket->errorString()));
113 }
else if (bytesWritten == 0) {
117 totalBytesWritten += bytesWritten;
120 emit
dataSent(data.first(totalBytesWritten));
123void BluetoothClassicWorker::_onSocketConnected()
125 qCDebug(BluetoothLinkLog) <<
"=== Classic Bluetooth Connection Established ===" <<
_device.name();
126 qCDebug(BluetoothLinkLog) <<
" Address:" <<
_device.address().toString();
127 qCDebug(BluetoothLinkLog) <<
" Protocol: RFCOMM (SPP)";
135void BluetoothClassicWorker::_onSocketDisconnected()
137 qCDebug(BluetoothLinkLog) <<
"Socket disconnected from device:" <<
_device.name();
142 qCDebug(BluetoothLinkLog) <<
"Starting reconnect timer";
147void BluetoothClassicWorker::_onSocketReadyRead()
153 const QByteArray data = _socket->readAll();
154 if (!data.isEmpty()) {
155 qCDebug(BluetoothLinkVerboseLog) <<
_device.name() <<
"Received" << data.size() <<
"bytes";
160void BluetoothClassicWorker::_onSocketBytesWritten(qint64 bytes)
162 qCDebug(BluetoothLinkVerboseLog) <<
_device.name() <<
"Wrote" << bytes <<
"bytes";
165void BluetoothClassicWorker::_onSocketErrorOccurred(QBluetoothSocket::SocketError socketError)
174 qCWarning(BluetoothLinkLog) <<
"Socket error:" << socketError <<
errorString;
181 qCDebug(BluetoothLinkLog) <<
"Connection attempt failed, emitting disconnected signal";
186 if ((socketError == QBluetoothSocket::SocketError::ServiceNotFoundError) ||
187 (socketError == QBluetoothSocket::SocketError::UnsupportedProtocolError)) {
188 qCDebug(BluetoothLinkLog) <<
"Service-related error, attempting fallback discovery";
189 _startClassicServiceDiscovery();
193void BluetoothClassicWorker::_startClassicServiceDiscovery()
195 if (_classicDiscovery && _classicDiscovery->isActive()) {
199 if (!_classicDiscovery) {
200 _classicDiscovery =
new QBluetoothServiceDiscoveryAgent(
_device.address(),
this);
201 (void) connect(_classicDiscovery.data(), &QBluetoothServiceDiscoveryAgent::serviceDiscovered,
202 this, &BluetoothClassicWorker::_onClassicServiceDiscovered);
203 (void) connect(_classicDiscovery.data(), &QBluetoothServiceDiscoveryAgent::finished,
204 this, &BluetoothClassicWorker::_onClassicServiceDiscoveryFinished);
205 (void) connect(_classicDiscovery.data(), &QBluetoothServiceDiscoveryAgent::canceled,
206 this, &BluetoothClassicWorker::_onClassicServiceDiscoveryCanceled);
207 (void) connect(_classicDiscovery.data(), &QBluetoothServiceDiscoveryAgent::errorOccurred,
208 this, &BluetoothClassicWorker::_onClassicServiceDiscoveryError);
211 qCDebug(BluetoothLinkLog) <<
"Starting classic service discovery on" <<
_device.name();
212 _classicDiscoveredService = QBluetoothServiceInfo();
213 _classicDiscovery->start(QBluetoothServiceDiscoveryAgent::FullDiscovery);
221void BluetoothClassicWorker::_onClassicServiceDiscovered(
const QBluetoothServiceInfo &serviceInfo)
223 qCDebug(BluetoothLinkLog) <<
"Classic service discovered: UUIDs=" << serviceInfo.serviceClassUuids()
224 <<
"RFCOMM channel=" << serviceInfo.serverChannel()
225 <<
"L2CAP PSM=" << serviceInfo.protocolServiceMultiplexer();
227 const QList<QBluetoothUuid> serviceUuids = serviceInfo.serviceClassUuids();
228 const bool isSerial = serviceUuids.contains(QBluetoothUuid(QBluetoothUuid::ServiceClassUuid::SerialPort));
229 const bool hasRfcommChannel = serviceInfo.serverChannel() > 0;
231 if (isSerial || (hasRfcommChannel && !_classicDiscoveredService.isValid())) {
232 _classicDiscoveredService = serviceInfo;
236void BluetoothClassicWorker::_onClassicServiceDiscoveryFinished()
242 if (!_classicDiscoveredService.isValid()) {
243 qCWarning(BluetoothLinkLog) <<
"No suitable classic service found";
248 _setupClassicSocket();
251 qCDebug(BluetoothLinkLog) <<
"Connecting using discovered service";
252 _socket->connectToService(_classicDiscoveredService);
255void BluetoothClassicWorker::_onClassicServiceDiscoveryCanceled()
261 qCDebug(BluetoothLinkLog) <<
"Classic service discovery canceled";
264void BluetoothClassicWorker::_onClassicServiceDiscoveryError(QBluetoothServiceDiscoveryAgent::Error
error)
270 const QString e = _classicDiscovery ? _classicDiscovery->errorString() : tr(
"Service discovery error: %1").arg(
error);
271 qCWarning(BluetoothLinkLog) << e;
void onSetupConnection() override
void onWriteData(const QByteArray &data) override
~BluetoothClassicWorker() override
BluetoothClassicWorker(const BluetoothConfiguration *config, QObject *parent=nullptr)
void onResetAfterConsecutiveFailures() override
void onServiceDiscoveryTimeout() override
void onConnectLink() override
void onDisconnectLink() override
void dataReceived(const QByteArray &data)
QPointer< QTimer > _serviceDiscoveryTimer
void dataSent(const QByteArray &data)
void errorOccurred(const QString &errorString)
QPointer< QTimer > _reconnectTimer
std::atomic< int > _reconnectAttempts
std::atomic< bool > _connected
const QBluetoothDeviceInfo _device
std::atomic< bool > _intentionalDisconnect