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(channelOpenTimer.get(), Q_FUNC_INFO,
"invalid timer (null)");
146 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
148 channelOpenTimer->stop();
149 if (error != kIOReturnSuccess) {
150 delegate->setChannelError(error);
151 delegate->channelClosed();
154 delegate->channelOpenComplete();
158- (
void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel*)rfcommChannel
160 Q_UNUSED(rfcommChannel);
162 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
163 delegate->channelClosed();
167- (
void)rfcommChannelControlSignalsChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
169 Q_UNUSED(rfcommChannel);
172- (
void)rfcommChannelFlowControlChanged:(IOBluetoothRFCOMMChannel*)rfcommChannel
174 Q_UNUSED(rfcommChannel);
177- (
void)rfcommChannelWriteComplete:(IOBluetoothRFCOMMChannel*)rfcommChannel
178 refcon:(
void*)refcon status:(IOReturn)error
180 Q_UNUSED(rfcommChannel);
183 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
185 if (error != kIOReturnSuccess)
186 delegate->setChannelError(error);
188 delegate->writeComplete();
191- (
void)rfcommChannelQueueSpaceAvailable:(IOBluetoothRFCOMMChannel*)rfcommChannel
193 Q_UNUSED(rfcommChannel);
196- (BluetoothRFCOMMChannelID)getChannelID
199 return [channel getChannelID];
204- (BluetoothDeviceAddress)peerAddress
206 const BluetoothDeviceAddress *
const addr = device ? [device getAddress]
211 return BluetoothDeviceAddress();
222- (BluetoothRFCOMMMTU)getMTU
225 return [channel getMTU];
230- (IOReturn) writeSync:(
void*)data length:(UInt16)length
232 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
233 Q_ASSERT_X(length, Q_FUNC_INFO,
"invalid data size");
234 Q_ASSERT_X(connected && channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
236 return [channel writeSync:data length:length];
239- (IOReturn) writeAsync:(
void*)data length:(UInt16)length
241 Q_ASSERT_X(data, Q_FUNC_INFO,
"invalid data (null)");
242 Q_ASSERT_X(length, Q_FUNC_INFO,
"invalid data size");
243 Q_ASSERT_X(connected && channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
245 return [channel writeAsync:data length:length refcon:
nullptr];
248- (
void)handleChannelOpenTimeout
250 Q_ASSERT_X(delegate, Q_FUNC_INFO,
"invalid delegate (null)");
251 Q_ASSERT_X(channel, Q_FUNC_INFO,
"invalid RFCOMM channel");
253 delegate->setChannelError(kIOReturnNotOpen);
254 [channel closeChannel];
255 delegate->channelClosed();
#define QT_BT_MAC_AUTORELEASEPOOL
static constexpr auto channelOpenTimeoutMs
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)