Skip to content

Commit

Permalink
Fixed HCILEExtendedAdvertisingReport
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Mar 15, 2023
1 parent bab586d commit 614bdcf
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 30 deletions.
44 changes: 15 additions & 29 deletions Sources/BluetoothHCI/HCILEExtendedAdvertisingReport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {

public static let length = 2 + 1 + 6 + 1 + 1 + 1 + 1 + 1 + 2 + 1 + 6 + 1

public let eventType: EventType
public let eventType: BitMaskOptionSet<EventType>

public let addressType: AddressType

Expand All @@ -69,11 +69,11 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {

public let secondaryPHY: SecondaryPHY

public let advertisingSID: UInt8
public let advertisingSID: UInt8?

public let txPower: LowEnergyTxPower
public let txPower: LowEnergyTxPower?

public let rssi: RSSI
public let rssi: RSSI?

public let periodicAdvertisingInterval: PeriodicAdvertisingInterval

Expand All @@ -88,29 +88,29 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {
guard data.count >= Report.length
else { return nil }

guard let eventType = EventType(rawValue: UInt16(bytes: (data[0], data[1]))),
let addressType = AddressType(rawValue: data[2])
let eventType = BitMaskOptionSet<EventType>(rawValue: UInt16(littleEndian: UInt16(bytes: (data[0], data[1]))))

guard let addressType = AddressType(rawValue: data[2])
else { return nil }

let address = BluetoothAddress(littleEndian: BluetoothAddress(bytes: (data[3], data[4],
data[5], data[6],
data[7], data[8])))

guard let primaryPHY = PrimaryPHY(rawValue: data[9]),
let secondaryPHY = SecondaryPHY(rawValue: data[10])
let primaryPHY = PrimaryPHY(rawValue: data[9]) ?? .le1M

guard let secondaryPHY = SecondaryPHY(rawValue: data[10])
else { return nil }

let advertisingSID = data[11]
let advertisingSID = data[11] == 0xFF ? nil : data[11]

let txPowerByte = Int8(bitPattern: data[12])

guard let txPower = LowEnergyTxPower(rawValue: txPowerByte)
else { return nil }
let txPower = LowEnergyTxPower(rawValue: txPowerByte)

let rssiByte = Int8(bitPattern: data[13])

guard let rssi = RSSI(rawValue: rssiByte)
else { return nil }
let rssi = RSSI(rawValue: rssiByte)

let periodicAdvertisingInterval = PeriodicAdvertisingInterval(rawValue: UInt16(bytes: (data[14], data[15])))

Expand All @@ -124,7 +124,7 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {
let dataLength = Int(data[23])

let responseData = Data(data[24 ..< (24 + dataLength)])
assert(data.count == dataLength)
assert(responseData.count == dataLength)

self.eventType = eventType
self.addressType = addressType
Expand Down Expand Up @@ -173,7 +173,6 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {

// Comparable
public static func < (lhs: PeriodicAdvertisingInterval, rhs: PeriodicAdvertisingInterval) -> Bool {

return lhs.rawValue < rhs.rawValue
}
}
Expand Down Expand Up @@ -224,7 +223,7 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {
}

/// Event Type
public enum EventType: UInt16, BitMaskOption {
public enum EventType: UInt16, BitMaskOption, CaseIterable {

/// Connectable advertising
case connectableAdvertising = 0b0000000000000001
Expand Down Expand Up @@ -252,18 +251,5 @@ public struct HCILEExtendedAdvertisingReport: HCIEventParameter {

/// Data status: Reserved for future use
case dataStatusReserved = 0b0000000001100000

/// All enum cases
public static let allCases: [EventType] = [
.connectableAdvertising,
.scannableAdvertising,
.directedAdvertising,
.scanResponse,
.legacyAdvertisingPDU,
.dataStatusComplete,
.dataStatusIncompleteMoreData,
.dataStatusIncompleteTruncated,
.dataStatusReserved
]
}
}
57 changes: 56 additions & 1 deletion Tests/BluetoothTests/HCITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,61 @@ final class HCITests: XCTestCase {
}
}

func testExtendedAdvertisingReport() throws {

/*
Mar 15 10:52:55.671 HCI Event 0x0000 A4:C1:38:2D:7A:27
LE - Ext ADV - 1 Report - Normal - Public - A4:C1:38:2D:7A:27
-37 dBm - GVH5072_7A27 - Manufacturer Specific Data - Channel 38

Parameter Length: 57 (0x39)
Num Reports: 0X01
Report 0
Event Type: Connectable Advertising - Scannable Advertising - Legacy Advertising PDUs Used - Complete -
Address Type: Public
Peer Address: A4:C1:38:2D:7A:27
Primary PHY: 1M
Secondary PHY: No Packets
Advertising SID: Unavailable
Tx Power: Unavailable
RSSI: -37 dBm
Periodic Advertising Interval: 0.000000ms (0x0)
Direct Address Type: Public
Direct Address: 00:00:00:00:00:00
Data Length: 31
Local Name: GVH5072_7A27
16 Bit UUIDs: 0XEC88
Flags: 0x5
LE Limited Discoverable Mode
BR/EDR Not Supported
Data: 0D 09 47 56 48 35 30 37 32 5F 37 41 32 37 03 03 88 EC 02 01 05 09 FF 88 EC 00 03 94 90 64 00
*/

let data = Data([0x3E, 0x39, 0x0D, 0x01, 0x13, 0xA6, 0x00, 0x27, 0x7A, 0x2D, 0x38, 0xC1, 0xA4, 0x81, 0x00, 0xFF, 0x7F, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x0D, 0x09, 0x47, 0x56, 0x48, 0x35, 0x30, 0x37, 0x32, 0x5F, 0x37, 0x41, 0x32, 0x37, 0x03, 0x03, 0x88, 0xEC, 0x02, 0x01, 0x05, 0x09, 0xFF, 0x88, 0xEC, 0x00, 0x03, 0x94, 0x90, 0x64, 0x00])

guard let event = HCILowEnergyMetaEvent(data: data.advanced(by: 2)),
event.subevent == .extendedAdvertisingReport,
let reportEvent = HCILEExtendedAdvertisingReport(data: event.eventData),
let report = reportEvent.reports.first else {
XCTFail("Unable to parse event")
return
}

XCTAssertEqual(reportEvent.reports.count, 1)
XCTAssertEqual(report.eventType.map { $0 }, [.connectableAdvertising, .scannableAdvertising, .legacyAdvertisingPDU])
XCTAssertEqual(report.addressType, .publicDeviceAddress)
XCTAssertEqual(report.address.description, "A4:C1:38:2D:7A:27")
XCTAssertEqual(report.primaryPHY, .le1M)
XCTAssertEqual(report.secondaryPHY, .noPackets)
XCTAssertNil(report.advertisingSID)
XCTAssertNil(report.txPower)
XCTAssertEqual(report.rssi?.rawValue, -37)
XCTAssertEqual(report.periodicAdvertisingInterval.rawValue, 0)
XCTAssertEqual(report.directAddress.description, "00:00:00:00:00:00")
XCTAssertEqual(report.directAddressType, .publicDeviceAddress)
XCTAssertEqual(report.responseData, Data([0x0D, 0x09, 0x47, 0x56, 0x48, 0x35, 0x30, 0x37, 0x32, 0x5F, 0x37, 0x41, 0x32, 0x37, 0x03, 0x03, 0x88, 0xEC, 0x02, 0x01, 0x05, 0x09, 0xFF, 0x88, 0xEC, 0x00, 0x03, 0x94, 0x90, 0x64, 0x00]))
}

func testCommandStatusEvent() async throws {

func parseEvent(_ actualBytesRead: Int, _ eventBuffer: [UInt8]) -> HCICommandStatus? {
Expand Down Expand Up @@ -2842,4 +2897,4 @@ fileprivate func parseEvent <T: HCIEventParameter> (_ actualBytesRead: Int, _ ev

return event
}
#endif
#endif

0 comments on commit 614bdcf

Please sign in to comment.