Skip to content

Commit

Permalink
#161 Use DataContainer with GAPData
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Nov 5, 2024
1 parent ea0dd13 commit 80ba6bf
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 101 deletions.
17 changes: 5 additions & 12 deletions Sources/BluetoothGAP/GAPCompleteLocalName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
// Copyright © 2018 PureSwift. All rights reserved.
//

import Foundation

/**
GAP Complete Local Name

Expand All @@ -16,33 +14,30 @@ import Foundation
@frozen
public struct GAPCompleteLocalName: GAPData, Equatable, Hashable {

public static let dataType: GAPDataType = .completeLocalName
public static var dataType: GAPDataType { .completeLocalName }

public let name: String
public var name: String

public init(name: String) {

self.name = name
}
}

public extension GAPCompleteLocalName {

init?(data: Data) {
init?<Data: DataContainer>(data: Data) {

guard let rawValue = String(data: data, encoding: .utf8)
guard let rawValue = String(utf8: data)
else { return nil }

self.init(name: rawValue)
}

func append(to data: inout Data) {

func append<Data: DataContainer>(to data: inout Data) {
data += name.utf8
}

var dataLength: Int {

return name.utf8.count
}
}
Expand All @@ -52,7 +47,6 @@ public extension GAPCompleteLocalName {
extension GAPCompleteLocalName: CustomStringConvertible {

public var description: String {

return name
}
}
Expand All @@ -62,7 +56,6 @@ extension GAPCompleteLocalName: CustomStringConvertible {
extension GAPCompleteLocalName: ExpressibleByStringLiteral {

public init(stringLiteral value: String) {

self.init(name: value)
}
}
38 changes: 3 additions & 35 deletions Sources/BluetoothGAP/GAPData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// Copyright © 2018 PureSwift. All rights reserved.
//

import Foundation
@_exported import Bluetooth

// MARK: - Generic Access Profile Data
Expand All @@ -22,43 +21,12 @@ public protocol GAPData {
/// Generic Access Profile data type.
static var dataType: GAPDataType { get }

/// Initialize from LE advertisement data.
init?(data: Slice<LowEnergyAdvertisingData>)

/// Initialize from bytes.
init?(data: Data)

/// Append data representation into buffer.
func append(to data: inout Data)
/// Initialize from data.
init?<Data: DataContainer>(data: Data)

/// Append data representation into buffer.
func append(to data: inout LowEnergyAdvertisingData)
func append<Data: DataContainer>(to data: inout Data)

/// Length of value when encoded into data.
var dataLength: Int { get }
}

public extension GAPData {

init?(data slice: Slice<LowEnergyAdvertisingData>) {
let range = slice.startIndex ..< slice.endIndex
guard let value = slice.base.withUnsafeData({
Self.init(data: $0.subdataNoCopy(in: range))
}) else { return nil }
self = value
}

func append(to data: inout LowEnergyAdvertisingData) {
data += Data(self) // will be serialized on stack if small
}
}

public extension Data {

/// Initialize from GAP Data type.
init<T: GAPData>(_ value: T) {
self.init(capacity: value.dataLength)
value.append(to: &self)
assert(self.count == value.dataLength)
}
}
17 changes: 5 additions & 12 deletions Sources/BluetoothGAP/GAPFlags.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
// Copyright © 2018 PureSwift. All rights reserved.
//

import Foundation
import Bluetooth

/// GAP Flag
@frozen
public struct GAPFlags: GAPData, Equatable, Hashable {

public static var dataType: GAPDataType { return .flags }
public static var dataType: GAPDataType { .flags }

public var flags: BitMaskOptionSet<GAPFlag>

Expand All @@ -24,24 +23,20 @@ public struct GAPFlags: GAPData, Equatable, Hashable {

public extension GAPFlags {

init?(data: Data) {
init?<Data>(data: Data) where Data : Bluetooth.DataContainer {

guard data.count == 1
else { return nil }

self.flags = BitMaskOptionSet<GAPFlag>(rawValue: data[0])
}

func append(to data: inout Data) {
data += self
}

func append(to data: inout LowEnergyAdvertisingData) {
func append<Data>(to data: inout Data) where Data : Bluetooth.DataContainer {
data += self
}

var dataLength: Int {
return 1
1
}
}

Expand All @@ -59,7 +54,6 @@ extension GAPFlags: DataConvertible {
extension GAPFlags: CustomStringConvertible {

public var description: String {

return flags.description
}
}
Expand All @@ -69,7 +63,6 @@ extension GAPFlags: CustomStringConvertible {
extension GAPFlags: ExpressibleByIntegerLiteral {

public init(integerLiteral rawValue: GAPFlag.RawValue) {

self.init(flags: BitMaskOptionSet<GAPFlag>(rawValue: rawValue))
}
}
Expand Down
69 changes: 27 additions & 42 deletions Sources/BluetoothGAP/iBeacon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
// Created by Alsey Coleman Miller on 10/22/20.
//

#if canImport(Foundation)
import Foundation
#endif
import Bluetooth

public extension AppleBeacon {

init?(manufacturerData: GAPManufacturerSpecificData) {
init?<Data: DataContainer>(manufacturerData: GAPManufacturerSpecificData<Data>) {

let data = manufacturerData.additionalData

Expand All @@ -28,46 +30,46 @@ public extension AppleBeacon {
guard length == type(of: self).length
else { return nil }

let uuid = UUID(UInt128(bigEndian: UInt128(data: data.subdataNoCopy(in: 2 ..< 18))!))
let uuid = UUID(UInt128(bigEndian: UInt128(data: data.subdata(in: 2 ..< 18))!))
let major = UInt16(bigEndian: UInt16(bytes: (data[18], data[19])))
let minor = UInt16(bigEndian: UInt16(bytes: (data[20], data[21])))
let rssi = Int8(bitPattern: data[22])

self.init(uuid: uuid, major: major, minor: minor, rssi: rssi)
}
}

public extension GAPManufacturerSpecificData {

var manufacturerData: GAPManufacturerSpecificData {

var additionalData = Data(capacity: type(of: self).additionalDataLength)
appendAdditionalManufacturerData(to: &additionalData)
assert(additionalData.count == type(of: self).additionalDataLength)

let manufacturerData = GAPManufacturerSpecificData(
companyIdentifier: type(of: self).companyIdentifier,
init(beacon: AppleBeacon) {
var additionalData = AdditionalData()
additionalData.reserveCapacity(AppleBeacon.additionalDataLength)
beacon.appendAdditionalManufacturerData(to: &additionalData)
assert(additionalData.count == AppleBeacon.additionalDataLength)
self.init(
companyIdentifier: AppleBeacon.companyIdentifier,
additionalData: additionalData
)

return manufacturerData
}
}

internal extension AppleBeacon {

/// Apple iBeacon data type.
static var appleDataType: UInt8 { return 0x02 } // iBeacon
static var appleDataType: UInt8 { 0x02 } // iBeacon

/// The length of the TLV encoded data.
static var length: UInt8 { return 0x15 } // length: 21 = 16 byte UUID + 2 bytes major + 2 bytes minor + 1 byte RSSI
static var length: UInt8 { 0x15 } // length: 21 = 16 byte UUID + 2 bytes major + 2 bytes minor + 1 byte RSSI

static var additionalDataLength: Int { return Int(length) + 2 }

/*
static func from(advertisingData: LowEnergyAdvertisingData) -> (beacon: AppleBeacon, flags: GAPFlags)? {

guard let (flags, manufacturerData) = try? GAPDataDecoder.decode(GAPFlags.self, AppleBeacon.ManufacturerData.self, from: advertisingData)
else { return nil }

return (manufacturerData.beacon, flags)
}
}*/

func appendAdditionalManufacturerData <T: DataContainer> (to data: inout T) {

Expand All @@ -85,37 +87,27 @@ public extension LowEnergyAdvertisingData {
init(beacon: AppleBeacon,
flags: GAPFlags = [.lowEnergyGeneralDiscoverableMode, .notSupportedBREDR]) {

let encoder = GAPDataEncoder()
let encoder = GAPDataEncoder<LowEnergyAdvertisingData>()
let manufacturerData = AppleBeacon.ManufacturerData(beacon) // storage on stack
do { self = try encoder.encodeAdvertisingData(flags, manufacturerData) }
catch { fatalError("Unable to encode iBeacon advertisement: \(error)") }
self = encoder.encode(flags, manufacturerData)
}
}

internal extension AppleBeacon {

struct ManufacturerData: GAPData {

static var dataType: GAPDataType { return .manufacturerSpecificData }
static var dataType: GAPDataType { .manufacturerSpecificData }

internal let beacon: AppleBeacon

init(_ beacon: AppleBeacon) {
self.beacon = beacon
}

init?(data: Data) {

guard let manufacturerData = GAPManufacturerSpecificData(data: data),
let beacon = AppleBeacon(manufacturerData: manufacturerData)
else { return nil }

self.init(beacon)
}

init?(data slice: Slice<LowEnergyAdvertisingData>) {

guard let manufacturerData = GAPManufacturerSpecificData(data: slice),
init?<Data>(data: Data) where Data : DataContainer {

guard let manufacturerData = GAPManufacturerSpecificData<Data>(data: data),
let beacon = AppleBeacon(manufacturerData: manufacturerData)
else { return nil }

Expand All @@ -124,13 +116,7 @@ internal extension AppleBeacon {

var dataLength: Int { return 2 + AppleBeacon.additionalDataLength }

/// Append data representation into buffer.
func append(to data: inout Data) {
data += self
}

/// Append data representation into buffer.
func append(to data: inout LowEnergyAdvertisingData) {
func append<Data>(to data: inout Data) where Data : DataContainer {
data += self
}
}
Expand All @@ -139,9 +125,8 @@ internal extension AppleBeacon {
extension AppleBeacon.ManufacturerData: DataConvertible {

@usableFromInline
static func += <T>(data: inout T, value: AppleBeacon.ManufacturerData) where T : DataContainer {

data += GAPManufacturerSpecificData(companyIdentifier: AppleBeacon.companyIdentifier)
static func += <Data>(data: inout Data, value: AppleBeacon.ManufacturerData) where Data : DataContainer {
data += GAPManufacturerSpecificData<Data>(companyIdentifier: AppleBeacon.companyIdentifier)
value.beacon.appendAdditionalManufacturerData(to: &data)
}
}

0 comments on commit 80ba6bf

Please sign in to comment.