9#include <QtCore/qtimer.h>
19@implementation DarwinBTRFCOMMChannel
21 QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
22 IOBluetoothDevice *device;
23 IOBluetoothRFCOMMChannel *channel;
25 std::unique_ptr<QTimer> channelOpenTimer;
28- (
id)initWithDelegate:(DarwinBluetooth::ChannelDelegate *)aDelegate
30 Q_ASSERT_X(aDelegate, Q_FUNC_INFO,
"invalid delegate (null)");
32 if (self = [super init]) {
42- (
id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::ChannelDelegate) *)aDelegate
43 channel:(IOBluetoothRFCOMMChannel *)aChannel
47 Q_ASSERT_X(aDelegate, Q_FUNC_INFO,
"invalid delegate (null)");
48 Q_ASSERT_X(aChannel, Q_FUNC_INFO,
"invalid channel (nil)");
50 if (self = [super init]) {
52 channel = [aChannel retain];
53 [channel setDelegate:self];
54 device = [[channel getDevice] retain];
64 [channel setDelegate:nil];
65 [channel closeChannel];
75- (IOReturn)connectAsyncToDevice:(
const QBluetoothAddress &)address
76 withChannelID:(BluetoothRFCOMMChannelID)channelID
78 if (address.isNull()) {
79 qCCritical(QT_BT_DARWIN) <<
"invalid peer address";
80 return kIOReturnNoDevice;
84 if (connected || device || channel) {
85 qCCritical(QT_BT_DARWIN) <<
"connection is already active";
86 return kIOReturnStillOpen;
91 const BluetoothDeviceAddress iobtAddress = DarwinBluetooth::iobluetooth_address(address);
92 device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
94 qCCritical(QT_BT_DARWIN) <<
"failed to create a device";
95 return kIOReturnNoDevice;
98 const IOReturn status = [device openRFCOMMChannelAsync:&channel
99 withChannelID:channelID delegate:self];
100 if (status != kIOReturnSuccess) {
101 qCCritical(QT_BT_DARWIN) <<
"failed to open RFCOMM channel";
107 if (!channelOpenTimer) {
108 channelOpenTimer.reset(
new QTimer);
109 QObject::connect(channelOpenTimer.get(), &QTimer::timeout,
110 channelOpenTimer.get(), [self]() {
111 qCDebug(QT_BT_DARWIN) <<
"Could not open the RFCOMM channel within the specified "
112 "timeout. Assuming that the remote device is not available.";
113 [self handleChannelOpenTimeout];
115 channelOpenTimer->setSingleShot(
true);
117 channelOpenTimer->start(channelOpenTimeoutMs);
122 return kIOReturnSuccess;
125- (
void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel
126 data:(
void *)dataPointer length:(size_t)dataLength
128 Q_UNUSED(rfcommChannel);
130 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
134 if (!dataPointer || !dataLength)
137 delegate->readChannelData(dataPointer, dataLength);
140- (
void)rfcommChannelOpenComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
141 status:(IOReturn)error
143 Q_UNUSED(rfcommChannel);
145 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
149 if (channelOpenTimer)
150 channelOpenTimer->stop();
151 if (error != kIOReturnSuccess) {
152 delegate->setChannelError(error);
153 delegate->channelClosed();
156 delegate->channelOpenComplete();
160- (
void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel
162 Q_UNUSED(rfcommChannel);
164 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
165 delegate->channelClosed();
169- (
void)rfcommChannelControlSignalsChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
171 Q_UNUSED(rfcommChannel);
174- (
void)rfcommChannelFlowControlChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
176 Q_UNUSED(rfcommChannel);
179- (
void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
180 refcon:(
void*)refcon status:(IOReturn)error
182 Q_UNUSED(rfcommChannel);
185 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
187 if (error != kIOReturnSuccess)
188 delegate->setChannelError(error);
190 delegate->writeComplete();
193- (
void)rfcommChannelQueueSpaceAvailable:(IOBluetoothRFCOMMChannel*)rfcommChannel
195 Q_UNUSED(rfcommChannel);
198- (BluetoothRFCOMMChannelID)getChannelID
201 return [channel getChannelID];
206- (BluetoothDeviceAddress)peerAddress
208 const BluetoothDeviceAddress *
const addr = device ? [device getAddress]
213 return BluetoothDeviceAddress();
224- (BluetoothRFCOMMMTU)getMTU
227 return [channel getMTU];
232- (IOReturn) writeSync:(
void*)data length:(UInt16)length
234 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
235 Q_ASSERT_X(length, Q_FUNC_INFO,
"invalid data size");
236 Q_ASSERT_X(connected && channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
238 return [channel writeSync:data length:length];
241- (IOReturn) writeAsync:(
void*)data length:(UInt16)length
243 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
244 Q_ASSERT_X(length, Q_FUNC_INFO,
"invalid data size");
245 Q_ASSERT_X(connected && channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
247 return [channel writeAsync:data length:length refcon:
nullptr];
250- (
void)handleChannelOpenTimeout
252 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
253 Q_ASSERT_X(channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
255 delegate->setChannelError(kIOReturnNotOpen);
256 [channel closeChannel];
257 delegate->channelClosed();
#define QT_BT_MAC_AUTORELEASEPOOL
static constexpr auto channelOpenTimeoutMs
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)