Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
btl2capchannel.mm
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
7#include "btutility_p.h"
8
9#include <QtCore/qloggingcategory.h>
10#include <QtCore/qdebug.h>
11
12QT_USE_NAMESPACE
13
14@implementation DarwinBTL2CAPChannel
15{
16 QT_PREPEND_NAMESPACE(DarwinBluetooth)::ChannelDelegate *delegate;
17 IOBluetoothDevice *device;
18 IOBluetoothL2CAPChannel *channel;
19 bool connected;
20}
21
22- (id)initWithDelegate:(DarwinBluetooth::ChannelDelegate *)aDelegate
23{
24 Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
25
26 if (self = [super init]) {
27 delegate = aDelegate;
28 device = nil;
29 channel = nil;
30 connected = false;
31 }
32
33 return self;
34}
35
36- (id)initWithDelegate:(QT_PREPEND_NAMESPACE(DarwinBluetooth::ChannelDelegate) *)aDelegate
37 channel:(IOBluetoothL2CAPChannel *)aChannel
38{
39 // This type of channel does not require connect, it's created with
40 // already open channel.
41 Q_ASSERT_X(aDelegate, Q_FUNC_INFO, "invalid delegate (null)");
42 Q_ASSERT_X(channel, Q_FUNC_INFO, "invalid channel (nil)");
43
44 if (self = [super init]) {
45 delegate = aDelegate;
46 channel = [aChannel retain];
47 [channel setDelegate:self];
48 device = [channel.device retain];
49 connected = true;
50 }
51
52 return self;
53}
54
55- (void)dealloc
56{
57 // TODO: test if this implementation works at all!
58 if (channel) {
59 [channel setDelegate:nil];
60 // From Apple's docs:
61 // "This method may only be called by the client that opened the channel
62 // in the first place. In the future asynchronous and synchronous versions
63 // will be provided that let the client know when the close process has been finished."
64 [channel closeChannel];
65 [channel release];
66 }
67
68 [device release];
69
70 [super dealloc];
71}
72
73- (IOReturn)connectAsyncToDevice:(const QBluetoothAddress &)address
74 withPSM:(BluetoothL2CAPChannelID)psm
75{
76 if (address.isNull()) {
77 qCCritical(QT_BT_DARWIN) << "invalid peer address";
78 return kIOReturnNoDevice;
79 }
80
81 // Can never be called twice.
82 if (connected || device || channel) {
83 qCCritical(QT_BT_DARWIN) << "connection is already active";
84 return kIOReturnStillOpen;
85 }
86
88
89 const BluetoothDeviceAddress iobtAddress = DarwinBluetooth::iobluetooth_address(address);
90 device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
91 if (!device) {
92 qCCritical(QT_BT_DARWIN) << "failed to create a device";
93 return kIOReturnNoDevice;
94 }
95
96 const IOReturn status = [device openL2CAPChannelAsync:&channel withPSM:psm delegate:self];
97 if (status != kIOReturnSuccess) {
98 qCCritical(QT_BT_DARWIN) << "failed to open L2CAP channel";
99 // device is still autoreleased.
100 device = nil;
101 return status;
102 }
103
104 [channel retain];// What if we're closed already?
105 [device retain];
106
107 return kIOReturnSuccess;
108}
109
110// IOBluetoothL2CAPChannelDelegate:
111
112- (void)l2capChannelData:(IOBluetoothL2CAPChannel*)l2capChannel
113 data:(void *)dataPointer length:(size_t)dataLength
114{
115 Q_UNUSED(l2capChannel);
116
117 Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
118
119 if (dataPointer && dataLength)
120 delegate->readChannelData(dataPointer, dataLength);
121}
122
123- (void)l2capChannelOpenComplete:(IOBluetoothL2CAPChannel*)
124 l2capChannel status:(IOReturn)error
125{
126 Q_UNUSED(l2capChannel);
127
128 Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
129
130 if (error != kIOReturnSuccess) {
131 delegate->setChannelError(error);
132 } else {
133 connected = true;
134 delegate->channelOpenComplete();
135 }
136}
137
138- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel*)l2capChannel
139{
140 Q_UNUSED(l2capChannel);
141
142 Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
143 delegate->channelClosed();
144 connected = false;
145}
146
147- (void)l2capChannelReconfigured:(IOBluetoothL2CAPChannel*)l2capChannel
148{
149 Q_UNUSED(l2capChannel);
150}
151
152- (void)l2capChannelWriteComplete:(IOBluetoothL2CAPChannel*)l2capChannel
153 refcon:(void*)refcon status:(IOReturn)error
154{
155 Q_UNUSED(l2capChannel);
156 Q_UNUSED(refcon);
157
158 Q_ASSERT_X(delegate, Q_FUNC_INFO, "invalid delegate (null)");
159
160 if (error != kIOReturnSuccess)
161 delegate->setChannelError(error);
162 else
163 delegate->writeComplete();
164}
165
166- (void)l2capChannelQueueSpaceAvailable:(IOBluetoothL2CAPChannel*)l2capChannel
167{
168 Q_UNUSED(l2capChannel);
169}
170
171// Aux. methods.
172- (BluetoothL2CAPPSM)getPSM
173{
174 if (channel)
175 return channel.PSM;
176
177 return 0;
178}
179
180- (BluetoothDeviceAddress)peerAddress
181{
182 const BluetoothDeviceAddress *const addr = device ? [device getAddress]
183 : nullptr;
184 if (addr)
185 return *addr;
186
187 return BluetoothDeviceAddress();
188}
189
190- (NSString *)peerName
191{
192 if (device)
193 return device.name;
194
195 return nil;
196}
197
198- (bool)isConnected
199{
200 return connected;
201}
202
203- (IOReturn) writeSync:(void*)data length:(UInt16)length
204{
205 Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
206 Q_ASSERT_X(length, Q_FUNC_INFO, "invalid data size");
207 Q_ASSERT_X(connected && channel, Q_FUNC_INFO, "invalid L2CAP channel");
208
209 return [channel writeSync:data length:length];
210}
211
212- (IOReturn) writeAsync:(void*)data length:(UInt16)length
213{
214 Q_ASSERT_X(data, Q_FUNC_INFO, "invalid data (null)");
215 Q_ASSERT_X(length, Q_FUNC_INFO, "invalid data size");
216 Q_ASSERT_X(connected && channel, Q_FUNC_INFO, "invalid L2CAP channel");
217
218 return [channel writeAsync:data length:length refcon:nullptr];
219}
220
221
222@end
#define QT_BT_MAC_AUTORELEASEPOOL
Definition btutility_p.h:78
Q_FORWARD_DECLARE_OBJC_CLASS(NSString)