Skip to content

Commit cfabe93

Browse files
authored
Merge pull request #215 from PureSwift/feature/hci-6-3-roob
Add Bluetooth 6.3 Running Out of Bits support, fix LE event mask bit positions
2 parents c377868 + e3ae614 commit cfabe93

7 files changed

Lines changed: 526 additions & 25 deletions

File tree

Sources/BluetoothHCI/HCILESetEventMask.swift

Lines changed: 211 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -81,64 +81,172 @@ public extension HCILESetEventMask {
8181
enum Event: UInt64, BitMaskOption, CustomStringConvertible {
8282

8383
/// LE Connection Complete Event
84-
case connectionComplete = 0b00
84+
case connectionComplete = 0b1
8585

8686
/// LE Advertising Report Event
87-
case advertisingReport = 0b01
87+
case advertisingReport = 0b10
8888

8989
/// LE Connection Update Complete Event
90-
case connectionUpdateComplete = 0b10
90+
case connectionUpdateComplete = 0b100
9191

9292
/// LE Read Remote Features Complete Event
93-
case readRemoteFeaturesComplete = 0b100
93+
case readRemoteFeaturesComplete = 0b1000
9494

9595
/// LE Long Term Key Request Event
96-
case longTermKeyRequest = 0b1000
96+
case longTermKeyRequest = 0b10000
9797

9898
/// LE Remote Connection Parameter Request Event
99-
case remoteConnectionParameterRequest = 0b10000
99+
case remoteConnectionParameterRequest = 0b100000
100100

101101
/// LE Data Length Change Event
102-
case dataLengthChange = 0b100000
102+
case dataLengthChange = 0b1000000
103103

104104
/// LE Read Local P-256 Public Key Complete Event
105-
case readLocalP256PublicKeyComplete = 0b1000000
105+
case readLocalP256PublicKeyComplete = 0b10000000
106106

107107
/// LE Generate DHKey Complete Event
108-
case generateDHKeyComplete = 0b10000000
108+
case generateDHKeyComplete = 0b1_00000000
109109

110110
/// LE Enhanced Connection Complete Event
111-
case enhancedConnectionComplete = 0b100000000
111+
case enhancedConnectionComplete = 0b10_00000000
112112

113113
/// LE Directed Advertising Report Event
114-
case directedAdvertisingReport = 0b10_00000000
114+
case directedAdvertisingReport = 0b100_00000000
115115

116116
/// LE PHY Update Complete Event
117-
case phyUpdateComplete = 0b100_00000000
117+
case phyUpdateComplete = 0b1000_00000000
118118

119119
/// LE Extended Advertising Report Event
120-
case extendedAdvertisingReport = 0b1000_00000000
120+
case extendedAdvertisingReport = 0b10000_00000000
121121

122122
/// LE Periodic Advertising Sync Established Event
123-
case periodicAdvertisingSyncEstablished = 0b10000_00000000
123+
case periodicAdvertisingSyncEstablished = 0b100000_00000000
124124

125125
/// LE Periodic Advertising Report Event
126-
case periodicAdvertisingReport = 0b100000_00000000
126+
case periodicAdvertisingReport = 0b1000000_00000000
127127

128128
/// LE Periodic Advertising Sync Lost Event
129-
case periodicAdvertisingSyncLost = 0b1000000_00000000
129+
case periodicAdvertisingSyncLost = 0b10000000_00000000
130130

131131
/// LE Extended Scan Timeout Event
132-
case extendedScanTimeout = 0b10000000_00000000
132+
case extendedScanTimeout = 0b1_00000000_00000000
133133

134134
/// LE Extended Advertising Set Terminated Event
135-
case extendedAdvertisingSetTerminated = 0b1_00000000_00000000
135+
case extendedAdvertisingSetTerminated = 0b10_00000000_00000000
136136

137137
/// LE Scan Request Received Event
138-
case scanRequestReceived = 0b10_00000000_00000000
138+
case scanRequestReceived = 0b100_00000000_00000000
139139

140140
/// LE Channel Selection Algorithm Event
141-
case channelSelectionAlgorithm = 0b100_00000000_00000000
141+
case channelSelectionAlgorithm = 0b1000_00000000_00000000
142+
143+
/// LE Connectionless IQ Report Event
144+
case connectionlessIQReport = 0x10_0000
145+
146+
/// LE Connection IQ Report Event
147+
case connectionIQReport = 0x20_0000
148+
149+
/// LE CTE Request Failed Event
150+
case cteRequestFailed = 0x40_0000
151+
152+
/// LE Periodic Advertising Sync Transfer Received Event
153+
case periodicAdvertisingSyncTransferReceived = 0x80_0000
154+
155+
/// LE CIS Established Event
156+
case cisEstablished = 0x100_0000
157+
158+
/// LE CIS Request Event
159+
case cisRequest = 0x200_0000
160+
161+
/// LE Create BIG Complete Event
162+
case createBIGComplete = 0x400_0000
163+
164+
/// LE Terminate BIG Complete Event
165+
case terminateBIGComplete = 0x800_0000
166+
167+
/// LE BIG Sync Established Event
168+
case bigSyncEstablished = 0x1000_0000
169+
170+
/// LE BIG Sync Lost Event
171+
case bigSyncLost = 0x2000_0000
172+
173+
/// LE Request Peer SCA Complete Event
174+
case requestPeerSCAComplete = 0x4000_0000
175+
176+
/// LE Path Loss Threshold Event
177+
case pathLossThreshold = 0x8000_0000
178+
179+
/// LE Transmit Power Reporting Event
180+
case transmitPowerReporting = 0x1_0000_0000
181+
182+
/// LE BIGInfo Advertising Report Event
183+
case bigInfoAdvertisingReport = 0x2_0000_0000
184+
185+
/// LE Subrate Change Event
186+
case subrateChange = 0x4_0000_0000
187+
188+
/// LE Periodic Advertising Sync Established Event (v2)
189+
case periodicAdvertisingSyncEstablishedV2 = 0x8_0000_0000
190+
191+
/// LE Periodic Advertising Report Event (v2)
192+
case periodicAdvertisingReportV2 = 0x10_0000_0000
193+
194+
/// LE Periodic Advertising Sync Transfer Received Event (v2)
195+
case periodicAdvertisingSyncTransferReceivedV2 = 0x20_0000_0000
196+
197+
/// LE Periodic Advertising Subevent Data Request Event
198+
case periodicAdvertisingSubeventDataRequest = 0x40_0000_0000
199+
200+
/// LE Periodic Advertising Response Report Event
201+
case periodicAdvertisingResponseReport = 0x80_0000_0000
202+
203+
/// LE Enhanced Connection Complete Event (v2)
204+
case enhancedConnectionCompleteV2 = 0x100_0000_0000
205+
206+
/// LE CIS Established Event (v2)
207+
case cisEstablishedV2 = 0x200_0000_0000
208+
209+
/// LE Read All Remote Features Complete Event
210+
case readAllRemoteFeaturesComplete = 0x400_0000_0000
211+
212+
/// LE CS Read Remote Supported Capabilities Complete Event
213+
case csReadRemoteSupportedCapabilitiesComplete = 0x800_0000_0000
214+
215+
/// LE CS Read Remote FAE Table Complete Event
216+
case csReadRemoteFAETableComplete = 0x1000_0000_0000
217+
218+
/// LE CS Security Enable Complete Event
219+
case csSecurityEnableComplete = 0x2000_0000_0000
220+
221+
/// LE CS Config Complete Event
222+
case csConfigComplete = 0x4000_0000_0000
223+
224+
/// LE CS Procedure Enable Complete Event
225+
case csProcedureEnableComplete = 0x8000_0000_0000
226+
227+
/// LE CS Subevent Result Event
228+
case csSubeventResult = 0x1_0000_0000_0000
229+
230+
/// LE CS Subevent Result Continue Event
231+
case csSubeventResultContinue = 0x2_0000_0000_0000
232+
233+
/// LE CS Test End Complete Event
234+
case csTestEndComplete = 0x4_0000_0000_0000
235+
236+
/// LE Monitored Advertisers Report Event
237+
case monitoredAdvertisersReport = 0x8_0000_0000_0000
238+
239+
/// LE Frame Space Update Complete Event
240+
case frameSpaceUpdateComplete = 0x10_0000_0000_0000
241+
242+
/// LE UTP Receive Event
243+
case utpReceive = 0x20_0000_0000_0000
244+
245+
/// LE Connection Rate Change Event
246+
case connectionRateChange = 0x40_0000_0000_0000
247+
248+
/// LE CS Read Remote Supported Capabilities Complete Event (v2)
249+
case csReadRemoteSupportedCapabilitiesCompleteV2 = 0x80_0000_0000_0000
142250

143251
public static var allCases: [Event] {
144252
[
@@ -161,11 +269,48 @@ public extension HCILESetEventMask {
161269
.extendedScanTimeout,
162270
.extendedAdvertisingSetTerminated,
163271
.scanRequestReceived,
164-
.channelSelectionAlgorithm
272+
.channelSelectionAlgorithm,
273+
.connectionlessIQReport,
274+
.connectionIQReport,
275+
.cteRequestFailed,
276+
.periodicAdvertisingSyncTransferReceived,
277+
.cisEstablished,
278+
.cisRequest,
279+
.createBIGComplete,
280+
.terminateBIGComplete,
281+
.bigSyncEstablished,
282+
.bigSyncLost,
283+
.requestPeerSCAComplete,
284+
.pathLossThreshold,
285+
.transmitPowerReporting,
286+
.bigInfoAdvertisingReport,
287+
.subrateChange,
288+
.periodicAdvertisingSyncEstablishedV2,
289+
.periodicAdvertisingReportV2,
290+
.periodicAdvertisingSyncTransferReceivedV2,
291+
.periodicAdvertisingSubeventDataRequest,
292+
.periodicAdvertisingResponseReport,
293+
.enhancedConnectionCompleteV2,
294+
.cisEstablishedV2,
295+
.readAllRemoteFeaturesComplete,
296+
.csReadRemoteSupportedCapabilitiesComplete,
297+
.csReadRemoteFAETableComplete,
298+
.csSecurityEnableComplete,
299+
.csConfigComplete,
300+
.csProcedureEnableComplete,
301+
.csSubeventResult,
302+
.csSubeventResultContinue,
303+
.csTestEndComplete,
304+
.monitoredAdvertisersReport,
305+
.frameSpaceUpdateComplete,
306+
.utpReceive,
307+
.connectionRateChange,
308+
.csReadRemoteSupportedCapabilitiesCompleteV2
165309
]
166310
}
167311

168-
public var event: LowEnergyEvent {
312+
/// The equivalent `LowEnergyEvent`, if defined by this library.
313+
public var event: LowEnergyEvent? {
169314

170315
switch self {
171316

@@ -189,12 +334,55 @@ public extension HCILESetEventMask {
189334
case .extendedAdvertisingSetTerminated: return .advertisingSetTerminated
190335
case .scanRequestReceived: return .scanRequestReceived
191336
case .channelSelectionAlgorithm: return .channelSelectionAlgorithm
337+
case .periodicAdvertisingSyncTransferReceived: return .periodicAdvertisingSyncTransferReceived
338+
case .periodicAdvertisingSyncEstablishedV2: return .periodicAdvertisingSyncEstablishedV2
339+
case .periodicAdvertisingReportV2: return .periodicAdvertisingReportV2
340+
case .periodicAdvertisingSyncTransferReceivedV2: return .periodicAdvertisingSyncTransferReceivedV2
341+
case .periodicAdvertisingSubeventDataRequest: return .periodicAdvertisingSubeventDataRequest
342+
case .periodicAdvertisingResponseReport: return .periodicAdvertisingResponseReport
343+
case .enhancedConnectionCompleteV2: return .enhancedConnectionCompleteV2
344+
default: return nil
192345
}
193346
}
194347

195348
public var description: String {
196349

197-
return event.description
350+
if let event = self.event {
351+
return event.description
352+
}
353+
354+
switch self {
355+
case .connectionlessIQReport: return "LE Connectionless IQ Report Event"
356+
case .connectionIQReport: return "LE Connection IQ Report Event"
357+
case .cteRequestFailed: return "LE CTE Request Failed Event"
358+
case .cisEstablished: return "LE CIS Established Event"
359+
case .cisRequest: return "LE CIS Request Event"
360+
case .createBIGComplete: return "LE Create BIG Complete Event"
361+
case .terminateBIGComplete: return "LE Terminate BIG Complete Event"
362+
case .bigSyncEstablished: return "LE BIG Sync Established Event"
363+
case .bigSyncLost: return "LE BIG Sync Lost Event"
364+
case .requestPeerSCAComplete: return "LE Request Peer SCA Complete Event"
365+
case .pathLossThreshold: return "LE Path Loss Threshold Event"
366+
case .transmitPowerReporting: return "LE Transmit Power Reporting Event"
367+
case .bigInfoAdvertisingReport: return "LE BIGInfo Advertising Report Event"
368+
case .subrateChange: return "LE Subrate Change Event"
369+
case .cisEstablishedV2: return "LE CIS Established Event V2"
370+
case .readAllRemoteFeaturesComplete: return "LE Read All Remote Features Complete Event"
371+
case .csReadRemoteSupportedCapabilitiesComplete: return "LE CS Read Remote Supported Capabilities Complete Event"
372+
case .csReadRemoteFAETableComplete: return "LE CS Read Remote FAE Table Complete Event"
373+
case .csSecurityEnableComplete: return "LE CS Security Enable Complete Event"
374+
case .csConfigComplete: return "LE CS Config Complete Event"
375+
case .csProcedureEnableComplete: return "LE CS Procedure Enable Complete Event"
376+
case .csSubeventResult: return "LE CS Subevent Result Event"
377+
case .csSubeventResultContinue: return "LE CS Subevent Result Continue Event"
378+
case .csTestEndComplete: return "LE CS Test End Complete Event"
379+
case .monitoredAdvertisersReport: return "LE Monitored Advertisers Report Event"
380+
case .frameSpaceUpdateComplete: return "LE Frame Space Update Complete Event"
381+
case .utpReceive: return "LE UTP Receive Event"
382+
case .connectionRateChange: return "LE Connection Rate Change Event"
383+
case .csReadRemoteSupportedCapabilitiesCompleteV2: return "LE CS Read Remote Supported Capabilities Complete Event V2"
384+
default: return "LE Event (0x" + rawValue.toHexadecimal() + ")"
385+
}
198386
}
199387
}
200388
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// HCILESetEventMaskV2.swift
3+
// Bluetooth
4+
//
5+
// Created by Alsey Coleman Miller on 7/9/26.
6+
// Copyright © 2026 PureSwift. All rights reserved.
7+
//
8+
9+
// MARK: - BluetoothHostControllerInterface
10+
11+
public extension BluetoothHostControllerInterface {
12+
13+
/// LE Set Event Mask Command (v2)
14+
///
15+
/// The command is used to control which LE events are generated by the HCI for the Host.
16+
///
17+
/// Version 2 (Bluetooth 6.3, Running Out of Bits) widens the event mask from 8 octets
18+
/// to 255 octets and sets all bits of the mask, whereas the v1 command sets bits 0 to 63
19+
/// and leaves bits 64 and above unchanged.
20+
func setLowEnergyEventMaskV2(
21+
_ eventMask: HCILESetEventMask.EventMask,
22+
timeout: HCICommandTimeout = .default
23+
) async throws {
24+
25+
let parameter = HCILESetEventMaskV2(eventMask: eventMask)
26+
27+
try await deviceRequest(parameter, timeout: timeout)
28+
}
29+
}
30+
31+
// MARK: - HCI Command
32+
33+
/// LE Set Event Mask Command (v2)
34+
///
35+
/// The command is used to control which LE events are generated by the HCI for the Host.
36+
///
37+
/// Version 2 (Bluetooth 6.3, Running Out of Bits) widens the `LE_Event_Mask` parameter
38+
/// from 8 octets to 255 octets. The v1 command sets bits 0 to 63 of the event mask and
39+
/// leaves bits 64 and above unchanged; the v2 command sets all the bits of the event mask.
40+
///
41+
/// - Note: No LE events with a bit number of 64 or above have been assigned yet;
42+
/// bits 64 and above are encoded as zero.
43+
@frozen
44+
public struct HCILESetEventMaskV2: HCICommandParameter {
45+
46+
public typealias EventMask = HCILESetEventMask.EventMask
47+
48+
public static let command = HCILowEnergyCommand.setEventMaskV2 // 0x00A4
49+
50+
/// The length of the LE_Event_Mask parameter in octets.
51+
internal static let length = 255
52+
53+
/// The mask of LE events allowed to be generated by the HCI.
54+
public var eventMask: EventMask
55+
56+
/// The value with all bits set to 0 indicates that no events are specified.
57+
/// The default is for bits 0 to 4 inclusive (the value 0x0000 0000 0000 001F) to be set.
58+
public init(eventMask: EventMask = 0x0000_0000_0000_001F) {
59+
60+
self.eventMask = eventMask
61+
}
62+
63+
public func append<Data: DataContainer>(to data: inout Data) {
64+
65+
let eventMaskBytes = eventMask.rawValue.littleEndian.bytes
66+
67+
data += [
68+
eventMaskBytes.0,
69+
eventMaskBytes.1,
70+
eventMaskBytes.2,
71+
eventMaskBytes.3,
72+
eventMaskBytes.4,
73+
eventMaskBytes.5,
74+
eventMaskBytes.6,
75+
eventMaskBytes.7
76+
]
77+
78+
// bits 64 and above are not yet assigned
79+
data += repeatElement(0, count: Self.length - MemoryLayout<UInt64>.size)
80+
}
81+
}

0 commit comments

Comments
 (0)