I have an application, running on MacOs, that communicates with a Bluetooth LE peripheral. I’m able to establish a L2CAP channel and after the channel is established, the peripheral sends a first (quite small) SDU on that channel to the application. The PSM is 0x80 and was chosen by the peripherals BLE stack. The application receives the PSM via GATT.
I can see the SDU being send in a single LL PDU with wireshark:
Frame 569: 44 bytes on wire (352 bits), 44 bytes captured (352 bits) on interface /dev/cu.usbmodem0006832334881-4.2, id 0
nRF Sniffer for Bluetooth LE
Bluetooth Low Energy Link Layer
Access Address: 0x50657518
[Master Address: Apple_7a:a5:d6 (f4:d4:88:7a:a5:d6)]
[Slave Address: c4:ed:78:ac:5b:31 (c4:ed:78:ac:5b:31)]
Data Header
.... ..10 = LLID: Start of an L2CAP message or a complete L2CAP message with no fragmentation (0x2)
.... .0.. = Next Expected Sequence Number: 0 [ACK]
.... 1... = Sequence Number: 1 [OK]
...1 .... = More Data: True
..0. .... = CTE Info: Not Present
00.. .... = RFU: 0
Length: 18
[L2CAP Index: 30]
[Connection Parameters in: 473]
CRC: 0x9850ef
Bluetooth L2CAP Protocol
Length: 14
CID: Dynamically Allocated Channel (0x004e)
[Connect in frame: 562]
[PSM: Unknown (0x0080)]
SDU Length: 12
Payload: 000509040401053c4c6f7600
I can also see the SDU being received in Apples PacketLogger. But I miss the corresponding call to a stream event handler.
The same BLE code ran in a different project without problems on MacOS and iOS. Now, I moved the code to an other project. Discovery and GATT communication works without any problem, yet the reception of L2CAP messages causes a problem.
The code creates a dispatch queue and passes it to the CBCentralManager
:
dispatch_queue = dispatch_queue_create("de.torrox.ble_event_queue", NULL);
manager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_queue options:nil];
When the L2CAP channel is established, the didOpenL2CAPChannel
callback gets called from a thread within the dispatch_queue
(has been verified with lldb):
- (void)peripheral:(CBPeripheral *)peripheral
didOpenL2CAPChannel:(CBL2CAPChannel *)channel
error:(NSError *)error
{
[channel inputStream].delegate = self;
[channel outputStream].delegate = self;
[[channel inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[channel outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[[channel inputStream] open];
[[channel outputStream] open];
...
// a reference to the channel is stored in the outside channel object
[channel retain];
...
}
Yet, not a single stream event is generated:
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)event_code
{
Log( @"stream:handleEvent %@, %lu", stream, event_code );
...
}
What could be the problem here? How could I get further informations to track this down? Is there a chance, that received data is not stored until it is picked up by a call to read?