diff --git a/Cartfile b/Cartfile index e992342..492e117 100644 --- a/Cartfile +++ b/Cartfile @@ -1 +1 @@ -github "PureSwift/SwiftFoundation" "develop" \ No newline at end of file +github "PureSwift/Bluetooth" "master" \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 01ff0b7..d301bc4 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,2 +1,3 @@ github "PureSwift/JSON-C" "e8e38025563d43e425536200002ad13c3f35a98b" -github "PureSwift/SwiftFoundation" "3d91b1d934779145fb72483d7f2530d9a7232d84" +github "PureSwift/SwiftFoundation" "5d636525d44dc06a906fe103ecbb7a5145a4c420" +github "PureSwift/Bluetooth" "23c9bc540cad1f336330d44f962ad552b7e67aa4" diff --git a/Package.swift b/Package.swift index 0a7137e..572c218 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription let package = Package( name: "BluetoothLinux", dependencies: [ - .Package(url: "https://github.com/PureSwift/CSwiftBluetoothLinux", majorVersion: 1), - .Package(url: "https://github.com/PureSwift/SwiftFoundation.git", majorVersion: 1), + .Package(url: "https://github.com/PureSwift/Bluetooth.git", majorVersion: 1), + .Package(url: "https://github.com/PureSwift/CSwiftBluetoothLinux", majorVersion: 1) ], targets: [ Target( diff --git a/Sources/BluetoothLinux/ATT.swift b/Sources/BluetoothLinux/ATT.swift deleted file mode 100644 index d0cfecb..0000000 --- a/Sources/BluetoothLinux/ATT.swift +++ /dev/null @@ -1,257 +0,0 @@ -// -// ATT.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 2/29/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -// MARK: - Protocol Definitions - -/// Bluetooth ATT protocol -public struct ATT { - - public static let PSM: ProtocolServiceMultiplexer = .ATT - - public static let CID: UInt16 = 4 - - public static let MinimumPDULength = 1 /* At least 1 byte for the opcode. */ - - /// ATT Timeout, in miliseconds - public static let Timeout: Int = 30000 /* 30000 ms */ - - /// Length of signature in write signed packet. - public static let SignatureLength = 12 - - public static let MaximumValueLength = 512 - - /// ATT MTU constants - public struct MTU { - - public struct LowEnergy { - - public static let Default = 23 - - public static let Maximum = 517 - } - } - - // Namespace Typealiases - - public typealias Security = ATTSecurity - - public typealias Error = ATTError - - public typealias Opcode = ATTOpcode - - public typealias OpcodeType = ATTOpcodeType - - public typealias AttributePermission = ATTAttributePermission -} - -/// ATT protocol security -public enum ATTSecurity: CInt { - - case Auto = 0 - case Low = 1 - case Medium = 2 - case High = 3 -} - -/// Error codes for Error response PDU. -public enum ATTError: UInt8, ErrorType { - - /// The attribute handle given was not valid on this server. - case InvalidHandle = 0x01 - - /// The attribute cannot be read. - case ReadNotPermitted = 0x02 - - /// The attribute cannot be written. - case WriteNotPermitted = 0x03 - - /// The attribute PDU was invalid. - case InvalidPDU = 0x04 - - /// The attribute requires authentication before it can be read or written. - case Authentication = 0x05 - - /// Attribute server does not support the request received from the client. - case RequestNotSupported = 0x06 - - /// Offset specified was past the end of the attribute. - case InvalidOffset = 0x07 - - /// The attribute requires authorization before it can be read or written. - case InsufficientAuthorization = 0x08 - - /// Too many prepare writes have been queued. - case PrepareQueueFull = 0x09 - - /// No attribute found within the given attribute handle range. - case AttributeNotFound = 0x0A - - /// The attribute cannot be read or written using the *Read Blob Request*. - case AttributeNotLong = 0x0B - - /// The *Encryption Key Size* used for encrypting this link is insufficient. - case InsufficientEncryptionKeySize = 0x0C - - /// The attribute value length is invalid for the operation. - case InvalidAttributeValueLength = 0x0D - - /// The attribute request that was requested has encountered an error that was unlikely, - /// and therefore could not be completed as requested. - case UnlikelyError = 0x0E - - /// The attribute requires encryption before it can be read or written. - case InsufficientEncryption = 0x0F - - /// The attribute type is not a supported grouping attribute as defined by a higher layer specification. - case UnsupportedGroupType = 0x10 - - /// Insufficient Resources to complete the request. - case InsufficientResources = 0x11 - - /* - public init(POSIXError: SwiftFoundation.POSIXError) { - - - }*/ -} - -/// ATT protocol opcodes. -public enum ATTOpcode: UInt8 { - - // Masks - public static let CommandMask = 0x40 - public static let SignedMask = 0x80 - - /// Error response - case ErrorResponse = 0x01 - - // Exchange MTU - case MaximumTransmissionUnitRequest = 0x02 - case MaximumTransmissionUnitResponse = 0x03 - - // Find Information - case FindInformationRequest = 0x04 - case FindInformationResponse = 0x05 - - // Find By Type Value - case FindByTypeRequest = 0x06 - case FindByTypeResponse = 0x07 - - // Read By Type - case ReadByTypeRequest = 0x08 - case ReadByTypeResponse = 0x09 - - // Read - case ReadRequest = 0x0a - case ReadResponse = 0x0b - - // Read Blob - case ReadBlobRequest = 0x0c - case ReadBlobResponse = 0x0d - - // Read Multiple - case ReadMultipleRequest = 0x0e - case ReadMultipleResponse = 0x0f - - // Read By Group Type - case ReadByGroupTypeRequest = 0x10 - case ReadByGroupTypeResponse = 0x11 - - // Write - case WriteRequest = 0x12 - case WriteResponse = 0x13 - case WriteCommand = 0x52 - case SignedWriteCommand = 0xD2 - - // Prepare Write - case PreparedWriteRequest = 0x16 - case PreparedWriteResponse = 0x17 - - // Execute Write - case ExecuteWriteRequest = 0x18 - case ExecuteWriteResponse = 0x19 - - // Handle Value - case HandleValueNotification = 0x1B - case HandleValueIndication = 0x1D - case HandleValueConfirmation = 0x1E - - /// Specifies the opcode category. - public var type: ATT.OpcodeType { - - switch self { - - case .ErrorResponse: return .Response - case .MaximumTransmissionUnitRequest: return .Request - case .MaximumTransmissionUnitResponse: return .Response - case .FindInformationRequest: return .Request - case .FindInformationResponse: return .Response - case .FindByTypeRequest: return .Request - case .FindByTypeResponse: return .Response - case .ReadByTypeRequest: return .Request - case .ReadByTypeResponse: return .Response - case .ReadRequest: return .Request - case .ReadResponse: return .Response - case .ReadBlobRequest: return .Request - case .ReadBlobResponse: return .Response - case .ReadMultipleRequest: return .Request - case .ReadMultipleResponse: return .Response - case .ReadByGroupTypeRequest: return .Request - case .ReadByGroupTypeResponse: return .Response - case .WriteRequest: return .Request - case .WriteResponse: return .Response - case .WriteCommand: return .Command - case .SignedWriteCommand: return .Command - case .PreparedWriteRequest: return .Request - case .PreparedWriteResponse: return .Response - case .ExecuteWriteRequest: return .Request - case .ExecuteWriteResponse: return .Response - case .HandleValueNotification: return .Notification - case .HandleValueIndication: return .Indication - case .HandleValueConfirmation: return .Confirmation - - } - } -} - -/// ATT protocol opcode categories. -public enum ATTOpcodeType { - - case Request - case Response - case Command - case Indication - case Notification - case Confirmation -} - -/// ATT attribute permission bitfield values. Permissions are grouped as -/// "Access", "Encryption", "Authentication", and "Authorization". A bitmask of -/// permissions is a byte that encodes a combination of these. -public enum ATTAttributePermission: UInt8 { - - // Access - case Read = 0x01 - case Write = 0x02 - - // Encryption - public static let Encrypt = [ReadEncrypt, WriteEncrypt] - case ReadEncrypt = 0x04 - case WriteEncrypt = 0x08 - - // Authentication - public static let Authentication = [ReadAuthentication, WriteAuthentication] - case ReadAuthentication = 0x10 - case WriteAuthentication = 0x20 - - // Authorization - case Authorized = 0x40 - case None = 0x80 -} - - diff --git a/Sources/BluetoothLinux/ATTConnection.swift b/Sources/BluetoothLinux/ATTConnection.swift index 72517bc..bd7b4a4 100644 --- a/Sources/BluetoothLinux/ATTConnection.swift +++ b/Sources/BluetoothLinux/ATTConnection.swift @@ -12,7 +12,8 @@ import Darwin.C #endif -import SwiftFoundation +import struct SwiftFoundation.Data +import Bluetooth /// Manages a Bluetooth connection using the ATT protocol. public final class ATTConnection { diff --git a/Sources/BluetoothLinux/ATTProtocolDataUnit.swift b/Sources/BluetoothLinux/ATTProtocolDataUnit.swift deleted file mode 100644 index d907cfb..0000000 --- a/Sources/BluetoothLinux/ATTProtocolDataUnit.swift +++ /dev/null @@ -1,1893 +0,0 @@ -// -// ATTProtocolDataUnit.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/1/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -import struct SwiftFoundation.UUID - -// MARK: - Protocol Definition - -/// Data packet for the ATT protocol. -public protocol ATTProtocolDataUnit { - - /// The PDU's attribute opcode. - static var attributeOpcode: ATT.Opcode { get } - - /// Converts PDU to raw bytes. - var byteValue: [UInt8] { get } - - /// Initializes PDU from raw bytes. - init?(byteValue: [UInt8]) -} - -// MARK: - Error Handling - -/// The Error Response is used to state that a given request cannot be performed, -/// and to provide the reason. -/// -/// - Note: The Write Command does not generate an Error Response. -public struct ATTErrorResponse: ATTProtocolDataUnit, ErrorType { - - /// The request that generated this error response - public var requestOpcode: ATT.Opcode - - /// The attribute handle that generated this error response. - public var attributeHandle: UInt16 - - /// The reason why the request has generated an error response. - public var errorCode: UInt8 - - public init(requestOpcode: ATT.Opcode, attributeHandle: UInt16, error: ATT.Error) { - - self.requestOpcode = requestOpcode - self.attributeHandle = attributeHandle - self.errorCode = error.rawValue - } - - public init(requestOpcode: ATT.Opcode, attributeHandle: UInt16, errorCode: UInt8) { - - self.requestOpcode = requestOpcode - self.attributeHandle = attributeHandle - self.errorCode = errorCode - } - - // ATTProtocolDataUnit - - public static let attributeOpcode = ATT.Opcode.ErrorResponse - - public static let length = 5 - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == ATTErrorResponse.length else { return nil } - - let attributeOpcodeByte = byteValue[0] - let requestOpcodeByte = byteValue[1] - let attributeHandleByte1 = byteValue[2] - let attributeHandleByte2 = byteValue[3] - let errorByte = byteValue[4] - - guard attributeOpcodeByte == ATTErrorResponse.attributeOpcode.rawValue, - let requestOpcode = ATTOpcode(rawValue: requestOpcodeByte) - else { return nil } - - self.requestOpcode = requestOpcode - self.errorCode = errorByte - self.attributeHandle = UInt16(littleEndian: (attributeHandleByte1, attributeHandleByte2)) - } - - public var byteValue: [UInt8] { - - var bytes = [UInt8](count: ATTErrorResponse.length, repeatedValue: 0) - - bytes[0] = ATTErrorResponse.attributeOpcode.rawValue - bytes[1] = requestOpcode.rawValue - bytes[2] = attributeHandle.littleEndianBytes.0 - bytes[3] = attributeHandle.littleEndianBytes.1 - bytes[4] = errorCode - - return bytes - } -} - -// MARK: - MTU Exchange - -/// Exchange MTU Request -/// -/// The *Exchange MTU Request* is used by the client to inform the server of the client’s maximum receive MTU -/// size and request the server to respond with its maximum receive MTU size. -/// -/// - Note: This request shall only be sent once during a connection by the client. -/// The *Client Rx MTU* parameter shall be set to the maximum size of the attribute protocol PDU that the client can receive. -public struct ATTMaximumTransmissionUnitRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.MaximumTransmissionUnitRequest - public static let length = 3 - - /// Client Rx MTU - var clientMTU: UInt16 - - public init(clientMTU: UInt16 = 0) { - - self.clientMTU = clientMTU - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == self.dynamicType.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - self.clientMTU = UInt16(littleEndian: (byteValue[1], byteValue[2])) - } - - public var byteValue: [UInt8] { - - var bytes = [UInt8](count: ATTErrorResponse.length, repeatedValue: 0) - - bytes[0] = self.dynamicType.attributeOpcode.rawValue - - let mtuBytes = self.clientMTU.littleEndianBytes - - bytes[1] = mtuBytes.0 - bytes[2] = mtuBytes.1 - - return bytes - } -} - -/// Exchange MTU Response -/// -/// The *Exchange MTU Response* is sent in reply to a received *Exchange MTU Request*. -public struct ATTMaximumTranssmissionUnitResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.MaximumTransmissionUnitResponse - public static let length = 3 - - /// Server Rx MTU - public var serverMTU: UInt16 - - public init(serverMTU: UInt16 = 0) { - - self.serverMTU = serverMTU - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == self.dynamicType.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - self.serverMTU = UInt16(littleEndian: (byteValue[1], byteValue[2])) - } - - public var byteValue: [UInt8] { - - var bytes = [UInt8](count: self.dynamicType.length, repeatedValue: 0) - - bytes[0] = self.dynamicType.attributeOpcode.rawValue - - let mtuBytes = self.serverMTU.littleEndianBytes - - bytes[1] = mtuBytes.0 - bytes[2] = mtuBytes.1 - - return bytes - } -} - -// MARK: - Find Information - -/// Find Information Request -/// -/// The *Find Information Request* is used to obtain the mapping of attribute handles with their associated types. -/// This allows a client to discover the list of attributes and their types on a server. -public struct ATTFindInformationRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.FindInformationRequest - public static let length = 5 - - public var startHandle: UInt16 - - public var endHandle: UInt16 - - public init(startHandle: UInt16 = 0, endHandle: UInt16 = 0) { - - self.startHandle = startHandle - self.endHandle = endHandle - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == self.dynamicType.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - self.startHandle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - self.endHandle = UInt16(littleEndian: (byteValue[3], byteValue[4])) - } - - public var byteValue: [UInt8] { - - var bytes = [UInt8](count: self.dynamicType.length, repeatedValue: 0) - - bytes[0] = self.dynamicType.attributeOpcode.rawValue - - let startHandleBytes = self.startHandle.littleEndianBytes - let endHandleBytes = self.endHandle.littleEndianBytes - - bytes[1] = startHandleBytes.0 - bytes[2] = startHandleBytes.1 - - bytes[3] = endHandleBytes.0 - bytes[4] = endHandleBytes.1 - - return bytes - } -} - -/// Find Information Response -/// -/// The *Find Information Response* is sent in reply to a received *Find Information Request* -/// and contains information about this server. -public struct ATTFindInformationResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.FindInformationRequest - - /// Length ranges from 6, to the maximum MTU size. - public static let length = 8 - - /// The information data whose format is determined by the Format field. - public var data: Data - - public init(data: Data) { - - self.data = data - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTFindInformationResponse.length else { return nil } - - let attributeOpcodeByte = byteValue[0] - let formatByte = byteValue[1] - let remainderData = Array(byteValue.suffixFrom(2)) - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue, - let format = Format(rawValue: formatByte), - let data = Data(byteValue: remainderData, format: format) - else { return nil } - - self.data = data - } - - public var byteValue: [UInt8] { - - // first 2 bytes are opcode and format - return [self.dynamicType.attributeOpcode.rawValue, data.format.rawValue] + data.byteValue - } - - public enum Format: UInt8 { - - /// A list of 1 or more handles with their 16-bit Bluetooth UUIDs. - case Bit16 = 0x01 - - /// A list of 1 or more handles with their 128-bit UUIDs. - case Bit128 = 0x02 - - public init(UUID: BluetoothUUID) { - - switch UUID { - case .Bit16(_): self = .Bit16 - case .Bit128(_): self = .Bit128 - } - } - - public var length: Int { - - switch self { - case .Bit16: return 2 + 2 - case .Bit128: return 2 + 16 - } - } - } - - public enum Data { - - /// Handle and 16-bit Bluetooth UUID - case Bit16([(UInt16, UInt16)]) - - /// Handle and 128-bit UUIDs - case Bit128([(UInt16, SwiftFoundation.UUID)]) - - /// The data's format. - public var format: Format { - - switch self { - - case .Bit16(_): return .Bit16 - case .Bit128(_): return .Bit128 - - } - } - - public init?(byteValue: [UInt8], format: Format) { - - let pairLength = format.length - - guard byteValue.count % pairLength == 0 else { return nil } - - let pairCount = byteValue.count / pairLength - - var bit16Pairs: [(UInt16, UInt16)] = [] - - var bit128Pairs: [(UInt16, SwiftFoundation.UUID)] = [] - - for pairIndex in 0 ..< pairCount { - - let byteIndex = pairIndex * pairLength - - let pairBytes = Array(byteValue[byteIndex ..< byteIndex + pairLength]) - - let handle = UInt16(littleEndian: (pairBytes[0], pairBytes[1])) - - switch format { - - case .Bit16: - - let uuid = UInt16(littleEndian: (pairBytes[2], pairBytes[3])) - - bit16Pairs.append((handle, uuid)) - - case .Bit128: - - let uuid = UUID(byteValue: (pairBytes[2], pairBytes[3], pairBytes[4], pairBytes[5], pairBytes[6], pairBytes[7], pairBytes[8], pairBytes[9], pairBytes[10], pairBytes[11], pairBytes[12], pairBytes[13], pairBytes[14], pairBytes[15], pairBytes[16], pairBytes[17])) - - bit128Pairs.append((handle, uuid)) - } - } - - switch format { - - case .Bit16: self = .Bit16(bit16Pairs) - - case .Bit128: self = .Bit128(bit128Pairs) - } - } - - public var byteValue: [UInt8] { - - var bytes = [UInt8]() - - switch self { - - case let .Bit16(value): - - for pair in value { - - let handleBytes = pair.0.littleEndianBytes - - let uuidBytes = pair.1.littleEndianBytes - - bytes += [handleBytes.0, handleBytes.1, uuidBytes.0, uuidBytes.1] - } - - case let .Bit128(value): - - for pair in value { - - let handleBytes = pair.0.littleEndianBytes - - let uuidBytes = pair.1.byteValue - - bytes += [handleBytes.0, handleBytes.1, uuidBytes.0, uuidBytes.1, uuidBytes.2, uuidBytes.3, uuidBytes.4, uuidBytes.5, uuidBytes.6, uuidBytes.7, uuidBytes.8, uuidBytes.9, uuidBytes.10, uuidBytes.11, uuidBytes.12, uuidBytes.13, uuidBytes.14, uuidBytes.15] - } - } - - return bytes - } - } -} - -/// Find By Type Value Request -/// -/// The *Find By Type Value Request* is used to obtain the handles of attributes that have a 16-bit UUID attribute type -/// and attribute value. This allows the range of handles associated with a given attribute to be discovered when -/// the attribute type determines the grouping of a set of attributes. -/// -/// - Note: Generic Attribute Profile defines grouping of attributes by attribute type. -public struct ATTFindByTypeRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.FindByTypeRequest - - /// Minimum length. - public static let length = 1 + 2 + 2 + 2 + 0 - - /// First requested handle number - public var startHandle: UInt16 - - /// Last requested handle number - public var endHandle: UInt16 - - /// 2 octet UUID to find. - public var attributeType: UInt16 - - /// Attribute value to find. - public var attributeValue: [UInt8] - - public init(startHandle: UInt16 = 0, endHandle: UInt16 = 0, attributeType: UInt16 = 0, attributeValue: [UInt8] = []) { - - self.startHandle = startHandle - self.endHandle = endHandle - self.attributeType = attributeType - self.attributeValue = attributeValue - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTFindByTypeRequest.length else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - self.startHandle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - self.endHandle = UInt16(littleEndian: (byteValue[3], byteValue[4])) - - self.attributeType = UInt16(littleEndian: (byteValue[5], byteValue[6])) - - /// if attributeValue is included - if byteValue.count >= 7 { - - // rest of data is attribute - self.attributeValue = Array(byteValue.suffixFrom(7)) - - } else { - - self.attributeValue = [] - } - } - - public var byteValue: [UInt8] { - - let startHandleBytes = self.startHandle.littleEndianBytes - - let endHandleBytes = self.endHandle.littleEndianBytes - - let attributeTypeBytes = self.attributeType.littleEndianBytes - - return [self.dynamicType.attributeOpcode.rawValue, startHandleBytes.0, startHandleBytes.1, endHandleBytes.0, endHandleBytes.1, attributeTypeBytes.0, attributeTypeBytes.1] + attributeValue - } -} - -/// Find By Type Value Response -/// -/// The *Find By Type Value Response* is sent in reply to a received *Find By Type Value Request* -/// and contains information about this server. -public struct ATTFindByTypeResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.FindByTypeResponse - - /// Minimum length. - public static let length = 1 + HandlesInformation.length - - /// A list of 1 or more Handle Informations. - public var handlesInformationList: [HandlesInformation] - - public init(handlesInformationList: [HandlesInformation]) { - - assert(handlesInformationList.count >= 1, "Must have at least one HandlesInformation") - - self.handlesInformationList = handlesInformationList - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTFindByTypeResponse.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - let handleLength = HandlesInformation.length - - let handleBytesCount = byteValue.count - 1 - - guard handleBytesCount % handleLength == 0 else { return nil } - - let handleCount = handleBytesCount / handleLength - - // preallocate handles for better performance - var handles = [HandlesInformation](count: handleCount, repeatedValue: HandlesInformation()) - - for index in 0 ..< handleCount { - - let byteIndex = (index * handleLength) + 1 - - let handleBytes = Array(byteValue[byteIndex ..< byteIndex + handleLength]) - - guard let handle = HandlesInformation(byteValue: handleBytes) - else { return nil } - - handles[index] = handle - } - - self.handlesInformationList = handles - } - - public var byteValue: [UInt8] { - - // complex algorithm for better performance - let handlesDataByteCount = handlesInformationList.count * HandlesInformation.length - - // preallocate memory to avoid performance penalty by increasing buffer - var handlesData = [UInt8](count: handlesDataByteCount, repeatedValue: 0) - - for (handleIndex, handle) in handlesInformationList.enumerate() { - - let startByteIndex = handleIndex * HandlesInformation.length - - let byteRange = startByteIndex ..< startByteIndex + HandlesInformation.length - - handlesData.replaceRange(byteRange, with: handle.byteValue) - } - - return [self.dynamicType.attributeOpcode.rawValue] + handlesData - } - - /// Handles Information - /// - /// For each handle that matches the attribute type and attribute value in the *Find By Type Value Request* - /// a *Handles Information* shall be returned. - /// The *Found Attribute Handle* shall be set to the handle of the attribute that has the exact attribute type - /// and attribute value from the *Find By Type Value Request*. - public struct HandlesInformation { - - public static let length = 2 + 2 - - /// Found Attribute Handle - var foundAttribute: UInt16 - - /// Group End Handle - var groupEnd: UInt16 - - public init(foundAttribute: UInt16 = 0, groupEnd: UInt16 = 0) { - - self.foundAttribute = foundAttribute - self.groupEnd = groupEnd - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == HandlesInformation.length - else { return nil } - - self.foundAttribute = UInt16(littleEndian: (byteValue[0], byteValue[1])) - self.groupEnd = UInt16(littleEndian: (byteValue[3], byteValue[4])) - } - - public var byteValue: [UInt8] { - - let foundAttributeBytes = foundAttribute.littleEndianBytes - let groupEndBytes = groupEnd.littleEndianBytes - - return [foundAttributeBytes.0, foundAttributeBytes.1, groupEndBytes.0, groupEndBytes.1] - } - } -} - -// MARK: - Reading Attributes - -/// Read By Type Request -/// -/// The *Read By Type Request* is used to obtain the values of attributes where the -/// attribute type is known but the handle is not known. -public struct ATTReadByTypeRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadByTypeRequest - - /// First requested handle number - public var startHandle: UInt16 - - /// Last requested handle number - public var endHandle: UInt16 - - /// 2 or 16 octet UUID - public var attributeType: BluetoothUUID - - public init(startHandle: UInt16, endHandle: UInt16, attributeType: BluetoothUUID) { - - self.startHandle = startHandle - self.endHandle = endHandle - self.attributeType = attributeType - } - - public init?(byteValue: [UInt8]) { - - guard let length = Length(rawValue: byteValue.count) - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - self.startHandle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - self.endHandle = UInt16(littleEndian: (byteValue[3], byteValue[4])) - - switch length { - - case .UUID16: - - let value = UInt16(littleEndian: (byteValue[5], byteValue[6])) - - self.attributeType = .Bit16(value) - - case .UUID128: - - let value = UUID(byteValue: (byteValue[5], byteValue[6], byteValue[7], byteValue[8], byteValue[9], byteValue[10], byteValue[11], byteValue[12], byteValue[13], byteValue[14], byteValue[15], byteValue[16], byteValue[17], byteValue[18], byteValue[19], byteValue[20])) - - self.attributeType = .Bit128(value) - } - } - - public var byteValue: [UInt8] { - - let startHandleBytes = startHandle.littleEndianBytes - - let endHandleBytes = endHandle.littleEndianBytes - - return [self.dynamicType.attributeOpcode.rawValue, startHandleBytes.0, startHandleBytes.1, endHandleBytes.0, endHandleBytes.1] + attributeType.byteValue - } - - private enum Length: Int { - - case UUID16 = 7 - case UUID128 = 21 - - init(UUID: BluetoothUUID) { - - switch UUID { - - case .Bit16(_): self = .UUID16 - case .Bit128(_): self = .UUID128 - } - } - } -} - -/// Read By Type Response -/// -/// The *Read By Type Response* is sent in reply to a received *Read By Type Request* -/// and contains the handles and values of the attributes that have been read. -public struct ATTReadByTypeResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadByTypeResponse - - /// Minimum length - public static let length = 1 + 1 + AttributeData.length - - /// A list of Attribute Data. - public let data: [AttributeData] - - public init?(data: [AttributeData]) { - - // must have at least one attribute data - guard data.count > 0 else { return nil } - - let length = data[0].value.count - - // length must be at least 3 bytes - guard length >= AttributeData.length else { return nil } - - // validate the length of each pair - for pair in data { - - guard pair.value.count == length - else { return nil } - } - - self.data = data - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTReadByTypeResponse.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == self.dynamicType.attributeOpcode.rawValue - else { return nil } - - let attributeDataLength = Int(byteValue[1]) - - let attributeDataByteCount = byteValue.count - 2 - - guard attributeDataByteCount % attributeDataLength == 0 else { return nil } - - let attributeDataCount = attributeDataByteCount / attributeDataLength - - var attributeData = [AttributeData](count: attributeDataCount, repeatedValue: AttributeData()) - - for index in 0 ..< attributeDataCount { - - let byteIndex = 2 + (index * attributeDataLength) - - let dataBytes = Array(byteValue[byteIndex ..< byteIndex + attributeDataLength]) - - guard let data = AttributeData(byteValue: dataBytes) - else { return nil } - - attributeData[index] = data - } - - self.data = attributeData - } - - public var byteValue: [UInt8] { - - let valueLength = UInt8(2 + data[0].value.count) - - var bytes = [self.dynamicType.attributeOpcode.rawValue, valueLength] - - for attributeData in data { - - bytes += attributeData.byteValue - } - - return bytes - } - - /// Attribute handle and value pair. - public struct AttributeData { - - /// Minimum length. - public static let length = 2 - - /// Attribute Handle - public var handle: UInt16 - - /// Attribute Value - public var value: [UInt8] - - public init(handle: UInt16 = 0, value: [UInt8] = []) { - - self.handle = handle - self.value = value - } - - public init?(byteValue: [UInt8] = []) { - - guard byteValue.count >= AttributeData.length - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[0], byteValue[1])) - - if byteValue.count > AttributeData.length { - - let startingIndex = AttributeData.length - - self.value = Array(byteValue.suffixFrom(startingIndex)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let handleBytes = handle.littleEndianBytes - - return [handleBytes.0, handleBytes.1] + value - } - } -} - -/// Read Request -/// -/// The *Read Request* is used to request the server to read the value of an attribute -/// and return its value in a *Read Response*. -public struct ATTReadRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadRequest - public static let length = 1 + 2 - - public var handle: UInt16 - - public init(handle: UInt16 = 0) { - - self.handle = handle - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == ATTReadRequest.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == ATTReadRequest.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - } - - public var byteValue: [UInt8] { - - let handleBytes = handle.littleEndianBytes - - return [ATTReadRequest.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] - } -} - -/// Read Response -/// -/// The *Read Response* is sent in reply to a received *Read Request* and contains -/// the value of the attribute that has been read. -/// -/// - Note: The *Read Blob Request* would be used to read the remaining octets of a long attribute value. -public struct ATTReadResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadResponse - - /// Minimum length - public static let length = 1 + 0 - - /// The value of the attribute with the handle given. - public var attributeValue: [UInt8] - - public init(attributeValue: [UInt8] = []) { - - self.attributeValue = attributeValue - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTReadRequest.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == ATTReadResponse.attributeOpcode.rawValue - else { return nil } - - if byteValue.count > ATTReadRequest.length { - - self.attributeValue = Array(byteValue.suffixFrom(1)) - - } else { - - self.attributeValue = [] - } - } - - public var byteValue: [UInt8] { - - return [ATTReadResponse.attributeOpcode.rawValue] + attributeValue - } -} - -/// Read Blob Request -/// -/// The *Read Blob Request* is used to request the server to read part of the value of an attribute -/// at a given offset and return a specific part of the value in a *Read Blob Response*. -public struct ATTReadBlobRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadBlobRequest - public static let length = 1 + 2 + 2 - - /// The handle of the attribute to be read. - public var handle: UInt16 - - /// The offset of the first octet to be read. - public var offset: UInt16 - - public init(handle: UInt16 = 0, offset: UInt16 = 0) { - - self.handle = handle - self.offset = offset - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == ATTReadBlobRequest.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == ATTReadBlobRequest.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[0], byteValue[1])) - - self.offset = UInt16(littleEndian: (byteValue[2], byteValue[3])) - } - - public var byteValue: [UInt8] { - - let handleBytes = handle.littleEndianBytes - - let offsetBytes = offset.littleEndianBytes - - return [ATTReadBlobRequest.attributeOpcode.rawValue, handleBytes.0, handleBytes.1, offsetBytes.0, offsetBytes.1] - } -} - -/// Read Blob Response -/// -/// The *Read Blob Response* is sent in reply to a received *Read Blob Request* -/// and contains part of the value of the attribute that has been read. -public struct ATTReadBlobResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadBlobResponse - - /// Minimum length - public static let length = 1 + 0 - - /// Part of the value of the attribute with the handle given. - /// - /// - /// The part attribute value shall be set to part of the value of the attribute identified - /// by the attribute handle and the value offset in the request. - public var partAttributeValue: [UInt8] - - public init(partAttributeValue: [UInt8] = []) { - - self.partAttributeValue = partAttributeValue - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= ATTReadBlobResponse.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == ATTReadBlobResponse.attributeOpcode.rawValue - else { return nil } - - if byteValue.count > ATTReadBlobResponse.length { - - self.partAttributeValue = Array(byteValue.suffixFrom(1)) - - } else { - - self.partAttributeValue = [] - } - } - - public var byteValue: [UInt8] { - - return [ATTReadBlobResponse.attributeOpcode.rawValue] + partAttributeValue - } -} - -/// Read Multiple Request -/// -/// The *Read Multiple Request* is used to request the server to read two or more values -/// of a set of attributes and return their values in a *Read Multiple Response*. -/// -/// Only values that have a known fixed size can be read, with the exception of the last value that can have a variable length. -/// The knowledge of whether attributes have a known fixed size is defined in a higher layer specification. -public struct ATTReadMultipleRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadMultipleRequest - - /// Minimum length - public static let length = 1 + 4 - - public var handles: [UInt16] - - public init?(handles: [UInt16]) { - - guard handles.count >= 2 - else { return nil } - - self.handles = handles - } - - public init?(byteValue: [UInt8]) { - - let type = ATTReadBlobResponse.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - let handleCount = (byteValue.count - 1) / 2 - - guard (byteValue.count - 1) % 2 == 0 - else { return nil } - - // preallocate handle buffer - var handles = [UInt16](count: handleCount, repeatedValue: 0) - - for index in 0 ..< handleCount { - - let handleIndex = 1 + (index * 2) - - let handle = UInt16(littleEndian: (byteValue[handleIndex], byteValue[handleIndex + 1])) - - handles[index] = handle - } - - self.handles = handles - } - - public var byteValue: [UInt8] { - - let type = ATTReadBlobResponse.self - - var handlesBytes = [UInt8](count: handles.count * 2, repeatedValue: 0) - - for handle in handles { - - let handleBytes = handle.littleEndianBytes - - let handleByteIndex = handles.count * 2 - - handlesBytes[handleByteIndex] = handleBytes.0 - - handlesBytes[handleByteIndex + 1] = handleBytes.1 - } - - return [type.attributeOpcode.rawValue] + handlesBytes - } -} - -/// Read Multiple Response -/// -/// The read response is sent in reply to a received *Read Multiple Request* and -/// contains the values of the attributes that have been read. -public struct ATTReadMultipleResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadMultipleResponse - - /// Minimum length - public static let length = 1 + 0 - - public var values: [UInt8] - - public init(values: [UInt8] = []) { - - self.values = values - } - - public init?(byteValue: [UInt8]) { - - let type = ATTReadMultipleResponse.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - if byteValue.count > 1 { - - self.values = Array(byteValue.suffixFrom(1)) - - } else { - - self.values = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTReadBlobResponse.self - - return [type.attributeOpcode.rawValue] + values - } -} - - -/// Read by Group Type Request -/// -/// The *Read By Group Type Request* is used to obtain the values of attributes where the attribute type is known, -/// the type of a grouping attribute as defined by a higher layer specification, but the handle is not known. -public struct ATTReadByGroupTypeRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadByGroupTypeRequest - - /// First requested handle number. - public var startHandle: UInt16 - - /// Last requested handle number. - public var endHandle: UInt16 - - /// Attribute Group Type - /// - /// 2 or 16 octet UUID - public var type: BluetoothUUID - - public init(startHandle: UInt16, endHandle: UInt16, type: BluetoothUUID) { - - self.startHandle = startHandle - self.endHandle = endHandle - self.type = type - } - - public init?(byteValue: [UInt8]) { - - guard let length = Length(rawValue: byteValue.count) - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == ATTReadByGroupTypeRequest.attributeOpcode.rawValue - else { return nil } - - self.startHandle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - self.endHandle = UInt16(littleEndian: (byteValue[3], byteValue[4])) - - switch length { - - case .UUID16: - - let value = UInt16(littleEndian: (byteValue[5], byteValue[6])) - - self.type = .Bit16(value) - - case .UUID128: - - let value = UUID(byteValue: (byteValue[5], byteValue[6], byteValue[7], byteValue[8], byteValue[9], byteValue[10], byteValue[11], byteValue[12], byteValue[13], byteValue[14], byteValue[15], byteValue[16], byteValue[17], byteValue[18], byteValue[19], byteValue[20])) - - self.type = .Bit128(value) - } - } - - public var byteValue: [UInt8] { - - let startHandleBytes = startHandle.littleEndianBytes - - let endHandleBytes = endHandle.littleEndianBytes - - return [ATTReadByGroupTypeRequest.attributeOpcode.rawValue, startHandleBytes.0, startHandleBytes.1, endHandleBytes.0, endHandleBytes.1] + type.byteValue - } - - private enum Length: Int { - - case UUID16 = 7 - case UUID128 = 21 - - init(UUID: BluetoothUUID) { - - switch UUID { - - case .Bit16(_): self = .UUID16 - case .Bit128(_): self = .UUID128 - } - } - } -} - -/// Read By Group Type Response -/// -/// The *Read By Group Type Response* is sent in reply to a received *Read By Group Type Request* -/// and contains the handles and values of the attributes that have been read. -/// -/// - Note: The *Read Blob Request* would be used to read the remaining octets of a long attribute value. -public struct ATTReadByGroupTypeResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ReadByGroupTypeResponse - - /// Minimum length - public static let length = 1 + 1 + 4 - - /// A list of Attribute Data - public let data: [AttributeData] - - public init?(data: [AttributeData]) { - - // must have at least one item - guard let valueLength = data.first?.value.count - else { return nil } - - for attributeData in data { - - // all items must have same length - guard attributeData.value.count == valueLength - else { return nil } - } - - self.data = data - } - - public init?(byteValue: [UInt8]) { - - let type = ATTReadByGroupTypeResponse.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - let length = Int(byteValue[1]) - - let attributeDataBytesCount = byteValue.count - 2 - - let attributeCount = attributeDataBytesCount / length - - guard attributeDataBytesCount % length == 0 - else { return nil } - - var attributeDataList = [AttributeData](count: attributeCount, repeatedValue: AttributeData()) - - for index in 0 ..< attributeCount { - - let byteIndex = 2 + (index * length) - - let data = Array(byteValue[byteIndex ..< byteIndex + length]) - - guard let attributeData = AttributeData(byteValue: data) - else { return nil } - - attributeDataList[index] = attributeData - } - - self.data = attributeDataList - } - - public var byteValue: [UInt8] { - - let type = ATTReadByGroupTypeResponse.self - - let length = UInt8(data[0].value.count + 4) - - var attributeDataBytes = [UInt8]() - - for attributeData in data { - - attributeDataBytes += attributeData.byteValue - } - - return [type.attributeOpcode.rawValue, length] + attributeDataBytes - } - - public struct AttributeData { - - /// Minimum length - public static let length = 4 - - /// Attribute Handle - public var attributeHandle: UInt16 - - /// End Group Handle - public var endGroupHandle: UInt16 - - /// Attribute Value - public var value: [UInt8] - - public init(attributeHandle: UInt16 = 0, endGroupHandle: UInt16 = 0, value: [UInt8] = []) { - - self.attributeHandle = attributeHandle - self.endGroupHandle = endGroupHandle - self.value = value - } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= AttributeData.length - else { return nil } - - self.attributeHandle = UInt16(littleEndian: (byteValue[0], byteValue[1])) - self.endGroupHandle = UInt16(littleEndian: (byteValue[2], byteValue[3])) - - if byteValue.count > 4 { - - self.value = Array(byteValue.suffixFrom(4)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let attributeHandleBytes = attributeHandle.littleEndianBytes - - let endGroupHandleBytes = endGroupHandle.littleEndianBytes - - return [attributeHandleBytes.0, attributeHandleBytes.1, endGroupHandleBytes.0, endGroupHandleBytes.1] + value - } - } - - public mutating func adjust(maximumTransmissionUnit: UInt16) { - - - } -} - -// MARK: - Writing Attributes - -/// Write Request -/// -/// The *Write Request* is used to request the server to write the value of an attribute -/// and acknowledge that this has been achieved in a *Write Response*. -public struct ATTWriteRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.WriteRequest - - /// Minimum length - public static let length = 3 - - /// The handle of the attribute to be written. - public var handle: UInt16 - - /// The value to be written to the attribute. - public var value: [UInt8] - - public init(handle: UInt16 = 0, value: [UInt8] = []) { - - self.handle = handle - self.value = value - } - - public init?(byteValue: [UInt8]) { - - let type = ATTWriteRequest.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - if byteValue.count > ATTWriteRequest.length { - - self.value = Array(byteValue.suffixFrom(3)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTWriteRequest.self - - let handleBytes = handle.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] + value - } -} - -/// Write Response -/// -/// The *Write Response* is sent in reply to a valid *Write Request* -/// and acknowledges that the attribute has been successfully written. -public struct ATTWriteResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.WriteResponse - public static let length = 1 - - public init() { } - - public init?(byteValue: [UInt8]) { - - let type = ATTWriteResponse.self - - guard byteValue.count == type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - } - - public var byteValue: [UInt8] { - - let type = ATTWriteResponse.self - - return [type.attributeOpcode.rawValue] - } -} - -/// Write Command -/// -/// The *Write Command* is used to request the server to write the value of an attribute, typically into a control-point attribute. -public struct ATTWriteCommand: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.WriteCommand - - /// Minimum length - public static let length = 3 - - /// The handle of the attribute to be set. - public var handle: UInt16 - - /// The value of be written to the attribute. - public var value: [UInt8] - - public init(handle: UInt16 = 0, value: [UInt8] = []) { - - self.handle = handle - self.value = value - } - - public init?(byteValue: [UInt8]) { - - let type = ATTWriteCommand.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - if byteValue.count > type.length { - - self.value = Array(byteValue.suffixFrom(3)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTWriteCommand.self - - let handleBytes = handle.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] + value - } -} - -/// Signed Write Command -/// -/// The Signed Write Command is used to request the server to write the value of an attribute with an authentication signature, -/// typically into a control-point attribute. -public struct ATTSignedWriteCommand: ATTProtocolDataUnit { - - public typealias Signature = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - - public static let attributeOpcode = ATT.Opcode.SignedWriteCommand - - /// Minimum length - public static let length = 1 + 2 + 0 + 12 - - /// The handle of the attribute to be set. - public var handle: UInt16 - - /// The value to be written to the attribute - public var value: [UInt8] - - /// Authentication signature for the Attribute Upload, Attribute Handle and Attribute Value Parameters. - public var signature: Signature - - public init(handle: UInt16, value: [UInt8], signature: Signature) { - - self.handle = handle - self.value = value - self.signature = signature - } - - public init?(byteValue: [UInt8]) { - - let type = ATTSignedWriteCommand.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - if byteValue.count > type.length { - - self.value = Array(byteValue[3 ..< byteValue.count - 12]) - - } else { - - self.value = [] - } - - self.signature = (byteValue[byteValue.count - 12], byteValue[byteValue.count - 11], byteValue[byteValue.count - 10], byteValue[byteValue.count - 9], byteValue[byteValue.count - 8], byteValue[byteValue.count - 7], byteValue[byteValue.count - 6], byteValue[byteValue.count - 5], byteValue[byteValue.count - 4], byteValue[byteValue.count - 3], byteValue[byteValue.count - 2], byteValue[byteValue.count - 1]) - } - - public var byteValue: [UInt8] { - - let type = ATTSignedWriteCommand.self - - let handleBytes = handle.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] + value + [signature.0, signature.1, signature.2, signature.3, signature.4, signature.5, signature.6, signature.7, signature.8, signature.9, signature.10, signature.11] - } -} - -// MARK: - Queued Writes - -/// Prepare Write Request -/// -/// The *Prepare Write Request* is used to request the server to prepare to write the value of an attribute. -/// The server will respond to this request with a *Prepare Write Response*, -/// so that the client can verify that the value was received correctly. -public struct ATTPrepareWriteRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.PreparedWriteRequest - - /// Minimum length - public static let length = 1 + 2 + 2 + 0 - - /// The handle of the attribute to be written. - public var handle: UInt16 - - /// The offset of the first octet to be written. - public var offset: UInt16 - - /// The value of the attribute to be written. - public var partValue: [UInt8] - - public init(handle: UInt16 = 0, offset: UInt16 = 0, partValue: [UInt8] = []) { - - self.handle = handle - self.offset = offset - self.partValue = partValue - } - - public init?(byteValue: [UInt8]) { - - let type = ATTPrepareWriteRequest.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - self.offset = UInt16(littleEndian: (byteValue[3], byteValue[4])) - - if byteValue.count > type.length { - - self.partValue = Array(byteValue.suffixFrom(5)) - - } else { - - self.partValue = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTPrepareWriteRequest.self - - let handleBytes = handle.littleEndianBytes - - let offsetBytes = offset.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1, offsetBytes.0, offsetBytes.1] + partValue - } -} - -/// Prepare Write Response -/// The *Prepare Write Response* is sent in response to a received *Prepare Write Request* -/// and acknowledges that the value has been successfully received and placed in the prepare write queue. -public struct ATTPrepareWriteResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.PreparedWriteResponse - - /// Minimum length - public static let length = 1 + 2 + 2 + 0 - - /// The handle of the attribute to be written. - public var handle: UInt16 - - /// The offset of the first octet to be written. - public var offset: UInt16 - - /// The value of the attribute to be written. - public var partValue: [UInt8] - - public init(handle: UInt16 = 0, offset: UInt16 = 0, partValue: [UInt8] = []) { - - self.handle = handle - self.offset = offset - self.partValue = partValue - } - - public init?(byteValue: [UInt8]) { - - let type = ATTPrepareWriteResponse.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - self.offset = UInt16(littleEndian: (byteValue[3], byteValue[4])) - - if byteValue.count > type.length { - - self.partValue = Array(byteValue.suffixFrom(5)) - - } else { - - self.partValue = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTPrepareWriteResponse.self - - let handleBytes = handle.littleEndianBytes - - let offsetBytes = offset.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1, offsetBytes.0, offsetBytes.1] + partValue - } -} - -/// Execute Write Request -/// -/// The *Execute Write Request* is used to request the server to write or cancel the write -/// of all the prepared values currently held in the prepare queue from this client. -/// This request shall be handled by the server as an atomic operation. -public struct ATTExecuteWriteRequest: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ExecuteWriteRequest - public static let length = 1 + 1 - - public var flag: Flag - - public init(flag: Flag = Flag()) { - - self.flag = flag - } - - public init?(byteValue: [UInt8]) { - - let type = ATTExecuteWriteRequest.self - - guard byteValue.count == type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - let flagByte = byteValue[1] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue, - let flag = Flag(rawValue: flagByte) - else { return nil } - - self.flag = flag - } - - public var byteValue: [UInt8] { - - let type = ATTPrepareWriteResponse.self - - return [type.attributeOpcode.rawValue, flag.rawValue] - } - - public enum Flag: UInt8 { - - /// Cancel all prepared writes. - case Cancel = 0x00 - - /// Immediately write all pending prepared values. - case Write = 0x01 - - public init() { self = .Cancel } - } -} - -/// The *Execute Write Response* is sent in response to a received *Execute Write Request*. -public struct ATTExecuteWriteResponse: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.ExecuteWriteResponse - public static let length = 1 - - public init() { } - - public init?(byteValue: [UInt8]) { - - let type = ATTExecuteWriteResponse.self - - guard byteValue.count == type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - } - - public var byteValue: [UInt8] { - - return [ATT.Opcode.ExecuteWriteResponse.rawValue] - } -} - -// MARK: - Server Initiated - -/// Handle Value Notification -/// -/// A server can send a notification of an attribute’s value at any time. -public struct ATTHandleValueNotification: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.HandleValueNotification - - /// minimum length - public static let length = 1 + 2 + 0 - - /// The handle of the attribute. - public var handle: UInt16 - - /// The handle of the attribute. - public var value: [UInt8] - - public init?(byteValue: [UInt8]) { - - let type = ATTHandleValueNotification.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - if byteValue.count > type.length { - - self.value = Array(byteValue.suffixFrom(3)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTHandleValueNotification.self - - let handleBytes = handle.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] + value - } -} - -/// Handle Value Indication -/// -/// A server can send an indication of an attribute’s value. -public struct ATTHandleValueIndication: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.HandleValueIndication - - /// Minimum length - public static let length = 1 + 2 + 0 - - /// The handle of the attribute. - public var handle: UInt16 - - /// The handle of the attribute. - public var value: [UInt8] - - public init?(byteValue: [UInt8]) { - - let type = ATTHandleValueIndication.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - - self.handle = UInt16(littleEndian: (byteValue[1], byteValue[2])) - - if byteValue.count > type.length { - - self.value = Array(byteValue.suffixFrom(3)) - - } else { - - self.value = [] - } - } - - public var byteValue: [UInt8] { - - let type = ATTHandleValueIndication.self - - let handleBytes = handle.littleEndianBytes - - return [type.attributeOpcode.rawValue, handleBytes.0, handleBytes.1] + value - } -} - -/// Handle Value Confirmation -/// -/// The *Handle Value Confirmation* is sent in response to a received *Handle Value Indication* -/// and confirms that the client has received an indication of the given attribute. -public struct ATTHandleValueConfirmation: ATTProtocolDataUnit { - - public static let attributeOpcode = ATT.Opcode.HandleValueConfirmation - public static let length = 1 - - public init() { } - - public init?(byteValue: [UInt8]) { - - let type = ATTHandleValueConfirmation.self - - guard byteValue.count >= type.length - else { return nil } - - let attributeOpcodeByte = byteValue[0] - - guard attributeOpcodeByte == type.attributeOpcode.rawValue - else { return nil } - } - - public var byteValue: [UInt8] { - - let type = ATTHandleValueConfirmation.self - - return [type.attributeOpcode.rawValue] - } -} - - diff --git a/Sources/BluetoothLinux/Adapter.swift b/Sources/BluetoothLinux/Adapter.swift index 55c80f1..a7e111c 100644 --- a/Sources/BluetoothLinux/Adapter.swift +++ b/Sources/BluetoothLinux/Adapter.swift @@ -13,6 +13,7 @@ import Darwin.C #endif +import Bluetooth import SwiftFoundation /// Manages connection / communication to the underlying Bluetooth hardware. @@ -54,6 +55,28 @@ public final class Adapter { } } +// MARK: - Address Extensions + +public extension Address { + + /// Extracts the Bluetooth address from the device ID. + public init(deviceIdentifier: CInt) throws { + + self = try HCIDeviceAddress(deviceIdentifier) + } +} + +public extension Adapter { + + /// Attempts to get the address from the underlying Bluetooth hardware. + /// + /// Fails if the Bluetooth adapter was disconnected or hardware failure. + public var address: Address? { + + return try? Address(deviceIdentifier: identifier) + } +} + // MARK: - Errors public extension Adapter { diff --git a/Sources/BluetoothLinux/Address.swift b/Sources/BluetoothLinux/Address.swift deleted file mode 100644 index ca5e1a1..0000000 --- a/Sources/BluetoothLinux/Address.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// Address.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 12/6/15. -// Copyright © 2015 PureSwift. All rights reserved. -// - -#if os(Linux) - import Glibc -#elseif os(OSX) || os(iOS) - import Darwin.C -#endif - -import SwiftFoundation - - -/// Bluetooth Address type. -public struct Address: ByteValueType { - - // MARK: - ByteValueType - - /// Raw Bluetooth Address 6 byte (48 bit) value. - public typealias ByteValue = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - - // MARK: - Properties - - public var byteValue: ByteValue - - // MARK: - Initialization - - public init(byteValue: ByteValue = (0,0,0,0,0,0)) { - - self.byteValue = byteValue - } -} - -// MARK: - RawRepresentable - -extension Address: RawRepresentable { - - public init?(rawValue: String) { - - self.byteValue = (0,0,0,0,0,0) - - fatalError("Bluetooth address parsing not implemented") - } - - public var rawValue: String { - - let bytes = [byteValue.5, byteValue.4, byteValue.3, byteValue.2, byteValue.1, byteValue.0] - - var string = "" - - for (index, byte) in bytes.enumerate() { - - string += byte.toHexadecimal() - - if index != bytes.count - 1 { - - string += ":" - } - } - - assert(string.utf8.count == 17) - - return string - } -} - -// MARK: - Equatable - -extension Address: Equatable { } - -public func == (lhs: Address, rhs: Address) -> Bool { - - return lhs.byteValue.0 == rhs.byteValue.0 - && lhs.byteValue.1 == rhs.byteValue.1 - && lhs.byteValue.2 == rhs.byteValue.2 - && lhs.byteValue.3 == rhs.byteValue.3 - && lhs.byteValue.4 == rhs.byteValue.4 - && lhs.byteValue.5 == rhs.byteValue.5 -} - -// MARK: - CustomStringConvertible - -extension Address: CustomStringConvertible { - - public var description: String { return rawValue } -} - -// MARK: - Adapter Extensions - -public extension Address { - - /// Extracts the Bluetooth address from the device ID. - public init(deviceIdentifier: CInt) throws { - - self = try HCIDeviceAddress(deviceIdentifier) - } -} - -public extension Adapter { - - /// Attempts to get the address from the underlying Bluetooth hardware. - /// - /// Fails if the Bluetooth adapter was disconnected or hardware failure. - public var address: Address? { - - return try? Address(deviceIdentifier: identifier) - } -} - diff --git a/Sources/BluetoothLinux/AddressType.swift b/Sources/BluetoothLinux/AddressType.swift index 8b76f08..c78c0c8 100644 --- a/Sources/BluetoothLinux/AddressType.swift +++ b/Sources/BluetoothLinux/AddressType.swift @@ -30,13 +30,4 @@ public enum AddressType: UInt8 { return false } } -} - -/// Bluetooth Low Energy Address type -public enum LowEnergyAddressType: UInt8 { - - case Public = 0x00 - case Random = 0x01 - - public init() { self = .Public } } \ No newline at end of file diff --git a/Sources/BluetoothLinux/DeviceCommand.swift b/Sources/BluetoothLinux/DeviceCommand.swift index c9a399f..4d368b7 100644 --- a/Sources/BluetoothLinux/DeviceCommand.swift +++ b/Sources/BluetoothLinux/DeviceCommand.swift @@ -13,6 +13,7 @@ #endif import SwiftFoundation +import Bluetooth public extension Adapter { diff --git a/Sources/BluetoothLinux/DeviceRequest.swift b/Sources/BluetoothLinux/DeviceRequest.swift index 310641d..489b8ef 100644 --- a/Sources/BluetoothLinux/DeviceRequest.swift +++ b/Sources/BluetoothLinux/DeviceRequest.swift @@ -13,6 +13,7 @@ #endif import SwiftFoundation +import Bluetooth public extension Adapter { diff --git a/Sources/BluetoothLinux/Endianness.swift b/Sources/BluetoothLinux/Endianness.swift deleted file mode 100644 index bc30cad..0000000 --- a/Sources/BluetoothLinux/Endianness.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// Endianness.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 2/29/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// Number can be converted to little / big endian. -public protocol EndianConvertible: Equatable { - - var littleEndian: Self { get } - - var bigEndian: Self { get } -} - -extension Int: EndianConvertible { } -extension UInt16: EndianConvertible { } -extension Int16: EndianConvertible { } -extension UInt32: EndianConvertible { } -extension Int32: EndianConvertible { } -extension UInt64: EndianConvertible { } -extension Int64: EndianConvertible { } - -public extension EndianConvertible { - - /// Converts the number to the current endianness. - var currentEndian: Self { - - if isBigEndian { - - return bigEndian - - } else { - - return littleEndian - } - } -} - -public let isBigEndian = 10.bigEndian == 10 - -public extension UInt16 { - - /// Initializes value from two little endian ordered bytes. - public init(littleEndian value: (UInt8, UInt8)) { - - self = (UInt16(value.0).littleEndian + UInt16(value.1).bigEndian).currentEndian - } - - public var littleEndianBytes: (UInt8, UInt8) { - - let value = self.littleEndian - - let lowerByte = value & 0xff - let higherByte = value >> 8 - - return (UInt8(truncatingBitPattern: lowerByte), UInt8(truncatingBitPattern: higherByte)) - } -} diff --git a/Sources/BluetoothLinux/GATT.swift b/Sources/BluetoothLinux/GATT.swift deleted file mode 100644 index 3c130fe..0000000 --- a/Sources/BluetoothLinux/GATT.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// GATT.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 2/29/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -import protocol SwiftFoundation.BitMaskOption - -/// Bluetooth GATT protocol -public struct GATT { - - /// GATT UUIDs - public enum UUID: UInt16 { - - case PrimaryService = 0x2800 - case SecondaryService = 0x2801 - case Include = 0x2802 - case Characteristic = 0x2803 - - /// Initializes a GATT UUID for service type. - public init(primaryService: Bool) { - - self = primaryService ? .PrimaryService : .SecondaryService - } - - /// Initializes from a Bluetooth UUID - public init?(UUID: BluetoothUUID) { - - switch UUID { - - case let .Bit16(value): - - guard let gatt = GATT.UUID(rawValue: value) - else { return nil } - - self = gatt - - default: return nil - } - } - - /// Returns a Bluetooth UUID initialized with the `rawValue` of this GATT UUID. - public func toUUID() -> BluetoothUUID { - - return .Bit16(rawValue) - } - } - - /// GATT Characteristic Descriptors - public enum CharacteristicDescriptor: UInt16 { - - case ExtendedProperty = 0x2900 - - // TODO: All Characteristic Descriptors - } - - /// GATT Characteristic Properties Bitfield valuess - public enum CharacteristicProperty: UInt8, BitMaskOption { - - case Broadcast = 0x01 - case Read = 0x02 - case WriteWithoutResponse = 0x04 - case Write = 0x08 - case Notify = 0x10 - case Indicate = 0x20 - - /// Characteristic supports write with signature - case SignedWrite = 0x40 // BT_GATT_CHRC_PROP_AUTH - - case ExtendedProperties = 0x80 - } - - /// GATT Characteristic Extended Properties Bitfield values. - public enum CharacteristicExtendedProperty: UInt8 { - - case ReliableWrite = 0x01 - - // TODO: All CharacteristicExtendedProperty - } -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/GATTDatabase.swift b/Sources/BluetoothLinux/GATTDatabase.swift index 7f5b4e6..8dc6c34 100644 --- a/Sources/BluetoothLinux/GATTDatabase.swift +++ b/Sources/BluetoothLinux/GATTDatabase.swift @@ -6,6 +6,9 @@ // Copyright © 2016 PureSwift. All rights reserved. // +import SwiftFoundation +import Bluetooth + /// GATT Database public struct GATTDatabase { @@ -42,9 +45,9 @@ public struct GATTDatabase { } /// Write the value to attribute specified by the handle. - public mutating func write(value: [UInt8], _ characteristicHandle: UInt16) { - + public mutating func write(value: [UInt8], _ handle: UInt16) { + fatalError("Write to GATTDatabase not implemented") } /// The handles of the service at the specified index. @@ -145,23 +148,6 @@ public struct GATTDatabase { public extension GATTDatabase { - /// GATT Service - public struct Service { - - public var UUID: BluetoothUUID - - public var characteristics: [Characteristic] - - public var primary: Bool - - public init(characteristics: [Characteristic], UUID: BluetoothUUID, primary: Bool = true) { - - self.characteristics = characteristics - self.primary = primary - self.UUID = UUID - } - } - /// GATT Include Declaration public struct Include { @@ -172,9 +158,9 @@ public extension GATTDatabase { public var endGroupHandle: UInt16 /// Included Service UUID - public var serviceUUID: BluetoothUUID + public var serviceUUID: Bluetooth.UUID - public init(serviceHandle: UInt16, endGroupHandle: UInt16, serviceUUID: BluetoothUUID) { + public init(serviceHandle: UInt16, endGroupHandle: UInt16, serviceUUID: Bluetooth.UUID) { self.serviceHandle = serviceHandle self.endGroupHandle = endGroupHandle @@ -188,75 +174,23 @@ public extension GATTDatabase { let endGroupBytes = endGroupHandle.littleEndianBytes - return [handleBytes.0, handleBytes.1, endGroupBytes.0, endGroupBytes.1] + serviceUUID.byteValue - } - } - - /// GATT Characteristic - public struct Characteristic { - - public typealias Descriptor = GATTDatabase.Descriptor - public typealias Permission = ATT.AttributePermission - public typealias Property = GATT.CharacteristicProperty - - public var UUID: BluetoothUUID - - public var value: [UInt8] - - public var descriptors: [Descriptor] - - public var permissions: [Permission] - - public var properties: [Property] - - public init(UUID: BluetoothUUID, - value: [UInt8] = [], - permissions: [Permission] = [], - properties: [Property] = [], - descriptors: [Descriptor] = []) { - - self.UUID = UUID - self.value = value - self.permissions = permissions - self.descriptors = descriptors - self.properties = properties - } - } - - /// GATT Characteristic Descriptor - public struct Descriptor { - - public typealias Permission = ATT.AttributePermission - - public var UUID: BluetoothUUID - - public var permissions: [Permission] - - public var value: [UInt8] - - public init(UUID: BluetoothUUID, value: [UInt8] = [], permissions: [Permission] = []) { - - self.UUID = UUID - self.value = value - self.permissions = permissions + return [handleBytes.0, handleBytes.1, endGroupBytes.0, endGroupBytes.1] + serviceUUID.toData().byteValue } } /// ATT Attribute public struct Attribute { - public typealias Permission = ATT.AttributePermission - public let handle: UInt16 - public let UUID: BluetoothUUID + public let UUID: Bluetooth.UUID public let value: [UInt8] public let permissions: [Permission] /// Defualt initializer - private init(handle: UInt16, UUID: BluetoothUUID, value: [UInt8] = [], permissions: [Permission] = []) { + private init(handle: UInt16, UUID: Bluetooth.UUID, value: [UInt8] = [], permissions: [Permission] = []) { self.handle = handle self.UUID = UUID @@ -265,11 +199,11 @@ public extension GATTDatabase { } /// Initialize attribute with a `Service`. - private init(service: Service, handle: UInt16) { + private init(service: GATT.Service, handle: UInt16) { self.handle = handle self.UUID = GATT.UUID(primaryService: service.primary).toUUID() - self.value = service.UUID.byteValue + self.value = service.UUID.toData().byteValue self.permissions = [.Read] // Read only } @@ -291,14 +225,14 @@ public extension GATTDatabase { let propertiesMask = characteristic.properties.optionsBitmask() let valueHandleBytes = (handle + 1).littleEndianBytes - let value = [propertiesMask, valueHandleBytes.0, valueHandleBytes.1] + characteristic.UUID.byteValue + let value = [propertiesMask, valueHandleBytes.0, valueHandleBytes.1] + characteristic.UUID.toData().byteValue return Attribute(handle: currentHandle, UUID: GATT.UUID.Characteristic.toUUID(), value: value, permissions: [.Read]) }() currentHandle += 1 - let valueAttribute = Attribute(handle: currentHandle, UUID: characteristic.UUID, value: characteristic.value, permissions: characteristic.permissions) + let valueAttribute = Attribute(handle: currentHandle, UUID: characteristic.UUID, value: characteristic.value.byteValue, permissions: characteristic.permissions) var attributes = [declarationAttribute, valueAttribute] @@ -333,4 +267,17 @@ public extension GATTDatabase { } } +// MARK: - Typealiases +public extension GATT { + + public typealias Database = GATTDatabase +} + +public extension GATTDatabase { + + public typealias Service = GATT.Service + public typealias Characteristic = GATT.Characteristic + public typealias Descriptor = GATT.Descriptor + public typealias Permission = GATT.Permission +} diff --git a/Sources/BluetoothLinux/GATTServer.swift b/Sources/BluetoothLinux/GATTServer.swift index 3c4e37f..43ec296 100644 --- a/Sources/BluetoothLinux/GATTServer.swift +++ b/Sources/BluetoothLinux/GATTServer.swift @@ -7,6 +7,7 @@ // import struct SwiftFoundation.UUID +import Bluetooth public final class GATTServer { @@ -275,7 +276,7 @@ public final class GATTServer { guard data.isEmpty == false else { errorResponse(opcode, .AttributeNotFound, pdu.startHandle); return } - let attributeData = data.map { AttributeData(attributeHandle: $0.start, endGroupHandle: $0.end, value: $0.UUID.byteValue) } + let attributeData = data.map { AttributeData(attributeHandle: $0.start, endGroupHandle: $0.end, value: $0.UUID.toData().byteValue) } var limitedAttributes = [attributeData[0]] @@ -543,9 +544,9 @@ public final class GATTServer { internal extension GATTDatabase { /// Used for Service discovery. Should return tuples with the Service start handle, end handle and UUID. - func readByGroupType(handle: Range, primary: Bool) -> [(start: UInt16, end: UInt16, UUID: BluetoothUUID)] { + func readByGroupType(handle: Range, primary: Bool) -> [(start: UInt16, end: UInt16, UUID: Bluetooth.UUID)] { - var data = [(start: UInt16, end: UInt16, UUID: BluetoothUUID)]() + var data: [(start: UInt16, end: UInt16, UUID: Bluetooth.UUID)] = [] for (index, service) in self.services.enumerate() { @@ -565,7 +566,7 @@ internal extension GATTDatabase { return data } - func readByType(handle: Range, type: BluetoothUUID) -> [Attribute] { + func readByType(handle: Range, type: Bluetooth.UUID) -> [Attribute] { return attributes.filter { handle.contains($0.handle) && $0.UUID == type } } diff --git a/Sources/BluetoothLinux/HCI.swift b/Sources/BluetoothLinux/HCI.swift index 375b475..bc9c4b5 100644 --- a/Sources/BluetoothLinux/HCI.swift +++ b/Sources/BluetoothLinux/HCI.swift @@ -13,31 +13,12 @@ import Darwin.C #endif -import SwiftFoundation +import Bluetooth -/// Bluetooth HCI -public struct HCI { - - // MARK: - Constants - - public static let MaximumDeviceCount = 16 - - public static let MaximumACLSize = (1492 + 4) - - public static let MaximumSCOSize = 255 - - public static let MaximumEventSize = 260 - - public static let MaximumFrameSize = MaximumACLSize + 4 - - public static let MaximumNameLength = 248 - - public static let TypeLength = 1 +public extension HCI { // MARK: - Typealiases - public typealias Error = HCIError - public typealias DeviceFlag = HCIDeviceFlag public typealias DeviceEvent = HCIDeviceEvent @@ -49,44 +30,6 @@ public struct HCI { public typealias IOCTL = HCIIOCTL } -/// Bluetooth HCI Errors -public enum HCIError: UInt8, ErrorType { - - case UnknownCommand = 0x01 - case NoConnection - case HardwareFailure - case PageTimeout - case AuthenticationFailure - case KeyMissing - case MemoryFull - case ConnectionTimeout - case MaxConnections - case MaxSCOConnections - case ACLConnectionExists - case CommandDisallowed - case RejectedLimitedResources - case RejectedSecurity - case RejectedPersonal - case HostTimeout - case UnsupportedFeature - case InvalidParameters - case OEUserEndedConnection - case OELowResources - case OEPowerOff - case ConnectionTerminated - case RepeatedAttempts - case PairingNotAllowed - - // ... Add More - - case TransactionCollision = 0x2a - case QOSUnacceptableParameter = 0x2c - - // TODO: Add all errors - - case HostBusyPairing = 0x38 -} - /// HCI device flags public enum HCIDeviceFlag: CInt { diff --git a/Sources/BluetoothLinux/HCICommand.swift b/Sources/BluetoothLinux/HCICommand.swift deleted file mode 100644 index b07cd42..0000000 --- a/Sources/BluetoothLinux/HCICommand.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// HCICommand.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/13/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// HCI Command. -public protocol HCICommand: RawRepresentable { - - static var opcodeGroupField: HCIOpcodeGroupField { get } - - init?(rawValue: HCIOpcodeCommandField) - - var rawValue: HCIOpcodeCommandField { get } -} - -public typealias HCIOpcodeCommandField = UInt16 - -/// HCI Command Parameter. -public protocol HCICommandParameter { - - associatedtype HCICommandType: HCICommand - - static var command: HCICommandType { get } - - /// Length of the command when encoded to data. - static var length: Int { get } - - /// Converts command parameter to raw bytes. - var byteValue: [UInt8] { get } -} - - diff --git a/Sources/BluetoothLinux/HCIEvent.swift b/Sources/BluetoothLinux/HCIEvent.swift deleted file mode 100644 index 2b55bd2..0000000 --- a/Sources/BluetoothLinux/HCIEvent.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// HCIEvent.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/3/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -#if os(Linux) - import Glibc -#elseif os(OSX) || os(iOS) - import Darwin.C -#endif - -/// HCI Event Opcode -public protocol HCIEvent: RawRepresentable { - - init?(rawValue: UInt8) - - var rawValue: UInt8 { get } -} - -public protocol HCIEventParameter { - - associatedtype HCIEventType: HCIEvent - - /// Event Opcode - static var event: HCIEventType { get } - - /// Length of the event parameter when encoded to data. - static var length: Int { get } - - /// Attempt to initialize event parameter from data. - init?(byteValue: [UInt8]) -} - diff --git a/Sources/BluetoothLinux/HCIGeneralEvent.swift b/Sources/BluetoothLinux/HCIGeneralEvent.swift deleted file mode 100644 index e1aeecc..0000000 --- a/Sources/BluetoothLinux/HCIGeneralEvent.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// HCIGeneralEvent.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/3/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// Bluetooth HCI Events (not categorized) -public enum HCIGeneralEvent: UInt8, HCIEvent { - - case InquiryComplete = 0x01 - case InquiryResult = 0x02 - case ConnectionComplete = 0x03 - - // TODO: Complete all HCI events - - case RemoteNameRequestComplete = 0x07 - case CommandComplete = 0x0E - case CommandStatus = 0x0F - - case LowEnergyMeta = 0x3E -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/HCIGeneralEventParameter.swift b/Sources/BluetoothLinux/HCIGeneralEventParameter.swift deleted file mode 100644 index c040e6d..0000000 --- a/Sources/BluetoothLinux/HCIGeneralEventParameter.swift +++ /dev/null @@ -1,113 +0,0 @@ -// -// HCIGeneralEventParameter.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/3/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -import SwiftFoundation - -public extension HCIGeneralEvent { - - // TODO: Complete all command parameters - - public struct CommandCompleteParameter: HCIEventParameter { - - public static let event = HCIGeneralEvent.CommandComplete - public static let length = 3 - - /// The Number of HCI command packets which are allowed to be sent to the Controller from the Host. - public var numberOfCommandPackets: UInt8 = 0 - public var opcode: UInt16 = 0 - - public init() { } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == CommandCompleteParameter.length - else { return nil } - - self.numberOfCommandPackets = byteValue[0] - self.opcode = UInt16(littleEndian: (byteValue[1], byteValue[2])) - } - } - - public struct CommandStatusParameter: HCIEventParameter { - - public static let event = HCIGeneralEvent.CommandStatus - public static let length = 4 - - public var status: UInt8 = 0 - public var ncmd: UInt8 = 0 - public var opcode: UInt16 = 0 - - public init() { } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == CommandStatusParameter.length - else { return nil } - - self.status = byteValue[0] - self.ncmd = byteValue[1] - self.opcode = UInt16(littleEndian: (byteValue[2], byteValue[3])) - } - } - - public struct RemoteNameRequestCompleteParameter: HCIEventParameter { - - public static let event = HCIGeneralEvent.RemoteNameRequestComplete - public static let length = 255 - - public var status: UInt8 = 0 - public var address: Address = Address() - public var name: String = "" - - public init() { } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == RemoteNameRequestCompleteParameter.length - else { return nil } - - self.status = byteValue[0] - self.address = Address(byteValue: (byteValue[1], byteValue[2], byteValue[3], byteValue[4], byteValue[5], byteValue[6])) - - let nameBytes = Array(byteValue[7 ..< HCI.MaximumNameLength]) - - guard let name = String(UTF8Data: Data(byteValue: nameBytes)) - else { return nil } - - self.name = name - } - } - - public struct LowEnergyMetaParameter: HCIEventParameter { - - public static let event = HCIGeneralEvent.LowEnergyMeta - public static let length = 1 // Why? - - public var subevent: UInt8 = 0 - public var data = [UInt8]() - - public init() { } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count >= LowEnergyMetaParameter.length - else { return nil } - - self.subevent = byteValue[0] - - if byteValue.count > 1 { - - self.data = Array(byteValue.suffixFrom(1)) - - } else { - - self.data = [] - } - } - } -} diff --git a/Sources/BluetoothLinux/HCIOpcodeGroupField.swift b/Sources/BluetoothLinux/HCIOpcodeGroupField.swift deleted file mode 100644 index 8dd7a29..0000000 --- a/Sources/BluetoothLinux/HCIOpcodeGroupField.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// OpcodeGroupField.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/3/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// HCI Opcode Group Field values. -public enum HCIOpcodeGroupField: UInt16 { - - /// Link Control - case LinkControl = 0x01 - - /// Link Policy - case LinkPolicy = 0x02 - - /// Host Controller and Baseband - case HostController = 0x03 - - /// Informational Parameters - case InformationalParameters = 0x04 - - /// Status Parameters - case StatusParameters = 0x05 - - /// Low Energy - case LowEnergy = 0x08 - - /// Testing Commands - case Testing = 0x3e - - /// Vendor specific commands - case Vendor = 0x3f -} - diff --git a/Sources/BluetoothLinux/Hexadecimal.swift b/Sources/BluetoothLinux/Hexadecimal.swift deleted file mode 100644 index e398292..0000000 --- a/Sources/BluetoothLinux/Hexadecimal.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Hexadecimal.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/2/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -public extension UInt8 { - - func toHexadecimal() -> String { - - var string = String(self, radix: 16) - - if string.utf8.count == 1 { - - string = "0" + string - } - - return string.uppercaseString - } -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/IOCTL.swift b/Sources/BluetoothLinux/IOCTL.swift index b56f28b..473ab2e 100644 --- a/Sources/BluetoothLinux/IOCTL.swift +++ b/Sources/BluetoothLinux/IOCTL.swift @@ -12,8 +12,6 @@ import Darwin.C #endif -import SwiftFoundation - internal struct IOC { static let NRBITS = CInt(8) diff --git a/Sources/BluetoothLinux/L2CAP.swift b/Sources/BluetoothLinux/L2CAP.swift index b91b365..9c55c80 100644 --- a/Sources/BluetoothLinux/L2CAP.swift +++ b/Sources/BluetoothLinux/L2CAP.swift @@ -13,6 +13,7 @@ #endif import SwiftFoundation +import Bluetooth /// L2CAP Bluetooth socket public final class L2CAPSocket { @@ -35,7 +36,7 @@ public final class L2CAPSocket { return internalAddress.l2_psm.currentEndian } - + /// Channel Identifier (CID) /// /// L2CAP channel endpoints are identified to their clients by a Channel Identifier (CID). diff --git a/Sources/BluetoothLinux/LinkControlCommand.swift b/Sources/BluetoothLinux/LinkControlCommand.swift deleted file mode 100644 index 2b3582c..0000000 --- a/Sources/BluetoothLinux/LinkControlCommand.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// LinkControlCommand.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/13/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -public enum LinkControlCommand: UInt16, HCICommand { - - public static let opcodeGroupField = HCIOpcodeGroupField.LinkControl - - /// Command used to enter Inquiry mode where it discovers other Bluetooth devices. - case Inquiry = 0x0001 - - /// Command to cancel the Inquiry mode in which the Bluetooth device is in. - case InquiryCancel = 0x0002 - - /// Command to set the device to enter Inquiry modes periodically according to the time interval set. - case PeriodicInquiry = 0x0003 - - /// Command to exit the periodic Inquiry mode. - case ExitPeriodicInquiry = 0x0004 - - /// Command to create an ACL connection to the device specified by the BD_ADDR in the parameters. - case CreateConnection = 0x0005 - - /// Command to terminate the existing connection to a device. - case Disconnect = 0x0006 - - /// Create an SCO connection defined by the connection handle parameters. - case AddSCOConnection = 0x0007 - - /// Cancel Create Connection - case CreateConnectionCancel = 0x0008 - - /// Command to accept a new connection request. - case AcceptConnection = 0x0009 - - /// Command to reject a new connection request. - case RejectConnection = 0x000A - - /// Reply command to a link key request event sent from controller to the host. - case LinkKeyReply = 0x000B - - /// Reply command to a link key request event from the controller to the host if there is no link key associated with the connection. - case LinkKeyNegativeReply = 0x000C - - /// Reply command to a PIN code request event sent from a controller to the host. - case PinCodeReply = 0x000D - - /// Reply command to a PIN code request event sent from the controller to the host if there is no PIN associated with the connection. - case PinCodeNegativeReply = 0x000E - - /// Command to change the type of packets to be sent for an existing connection. - case SetConnectionPacketType = 0x000F - - /// Command to establish authentication between two devices specified by the connection handle. - case AuthenticationRequested = 0x0011 - - /// Command to enable or disable the link level encryption. - case SetConnectionEncryption = 0x0013 - - /// Command to force the change of a link key to a new one between two connected devices. - case ChangeConnectionLinkKey = 0x0015 - - /// Command to force two devices to use the master's link key temporarily. - case MasterLinkKey = 0x0017 - - /// Command to determine the user friendly name of the connected device. - case RemoteNameRequest = 0x0019 - - /// Cancels the remote name request. - case RemoteNameRequestCancel = 0x001A - - /// Command to determine the features supported by the connected device. - case ReadRemoteFeatures = 0x001B - - /// Command to determine the extended features supported by the connected device. - case ReadRemoteExtendedFeatures = 0x001C - - /// Command to determine the version information of the connected device. - case ReadRemoteVersion = 0x001D - - /// Command to read the clock offset of the remote device. - case ReadClockOffset = 0x001F - - /// Read LMP Handle - case ReadLMPHandle = 0x0020 -} - diff --git a/Sources/BluetoothLinux/LinkControlCommandParameter.swift b/Sources/BluetoothLinux/LinkControlCommandParameter.swift deleted file mode 100644 index 8aba776..0000000 --- a/Sources/BluetoothLinux/LinkControlCommandParameter.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// LinkControlCommandParameter.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/14/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -#if os(Linux) - import Glibc -#elseif os(OSX) || os(iOS) - import Darwin.C -#endif - -public extension LinkControlCommand { - - public struct InquiryParameter: HCICommandParameter { - - public static let command = LinkControlCommand.Inquiry - - public static let length = 5 - - public var lap: (UInt8, UInt8, UInt8) = (0, 0, 0) - - public var length: UInt8 = 0 /* 1.28s units */ - - public var count: UInt8 = 0 - - public init() { } - - public var byteValue: [UInt8] { - - return [lap.0, lap.1, lap.2, length, count] - } - } - - public struct RemoteNameRequestParameter: HCICommandParameter { - - public static let command = LinkControlCommand.RemoteNameRequest - - public static let length = 10 - - public var address = Address() - - public var pscanRepMode: UInt8 = 0 - - public var pscanMode: UInt8 = 0 - - public var clockOffset: UInt16 = 0 - - public init() { } - - public init?(byteValue: [UInt8]) { - - guard byteValue.count == RemoteNameRequestParameter.length - else { return nil } - - self.address = Address(byteValue: (byteValue[0], byteValue[1], byteValue[2], byteValue[3], byteValue[4], byteValue[5])) - - self.pscanRepMode = byteValue[6] - self.pscanMode = byteValue[7] - self.clockOffset = UInt16(littleEndian: (byteValue[8], byteValue[9])) - } - - public var byteValue: [UInt8] { - - let address = self.address.byteValue - - let clockOffsetBytes = clockOffset.littleEndianBytes - - return [address.0, address.1, address.2, address.3, address.4, address.5, pscanRepMode, pscanMode, clockOffsetBytes.0, clockOffsetBytes.1] - } - } -} diff --git a/Sources/BluetoothLinux/LowEnergyAddressType.swift b/Sources/BluetoothLinux/LowEnergyAddressType.swift deleted file mode 100644 index e2b7c71..0000000 --- a/Sources/BluetoothLinux/LowEnergyAddressType.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// LowEnergyAddressType.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/3/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - diff --git a/Sources/BluetoothLinux/LowEnergyCommand.swift b/Sources/BluetoothLinux/LowEnergyCommand.swift deleted file mode 100644 index d362d16..0000000 --- a/Sources/BluetoothLinux/LowEnergyCommand.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// LowEnergyCommand.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/14/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// Bluetooth Low Energy Command opcode -public enum LowEnergyCommand: UInt16, HCICommand { - - public static let opcodeGroupField = HCIOpcodeGroupField.LowEnergy - - case SetEventMask = 0x0001 - case ReadBufferSize = 0x0002 - case ReadLocalSupportedFeatures = 0x0003 - case SetRandomAddress = 0x0005 - case SetAdvertisingParameters = 0x0006 - case ReadAdvertisingChannelTXPower = 0x0007 - case SetAdvertisingData = 0x0008 - case SetScanResponseData = 0x0009 - case SetAdvertiseEnable = 0x000A - case SetScanParameters = 0x000B - case SetScanEnable = 0x000C - case CreateConnection = 0x000D - case CreateConnectionCancel = 0x000E - case ReadWhiteListSize = 0x000F - case ClearWhiteList = 0x0010 - case AddDeviceToWhiteList = 0x0011 - case RemoveDeviceFromWhiteList = 0x0012 - case ConnectionUpdate = 0x0013 - case SetHostChannelClassification = 0x0014 - case ReadChannelMap = 0x0015 - case ReadRemoteUsedFeatures = 0x0016 - case Encrypt = 0x0017 - case Random = 0x0018 - case StartEncryption = 0x0019 - case LTKReply = 0x001A - case LTKNegativeReply = 0x001B - case ReadSupportedStates = 0x001C - case ReceiverTest = 0x001D - case TransmitterTest = 0x001E - case TestEnd = 0x001F - case AddDeviceToResolvedList = 0x0027 - case RemoveDeviceFromResolvedList = 0x0028 - case ClearResolvedList = 0x0029 - case ReadResolvedListSize = 0x002A - case SetAddressResolutionEnable = 0x002D -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/LowEnergyCommandParameter.swift b/Sources/BluetoothLinux/LowEnergyCommandParameter.swift deleted file mode 100644 index 9755a4a..0000000 --- a/Sources/BluetoothLinux/LowEnergyCommandParameter.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// LowEnergyCommandParameter.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 1/14/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -public extension LowEnergyCommand { - - /// LE Set Advertising Data Command - /// - /// Used to set the data used in advertising packets that have a data field. - /// - /// - Note: Only the significant part of the Advertising Data is transmitted in the advertising packets. - public struct SetAdvertisingDataParameter: HCICommandParameter { - - public static let command = LowEnergyCommand.SetAdvertisingData - public static let length = 32 - - /// The number of significant bytes. - public var length: UInt8 - - /// 31 octets of advertising data. - public var data: LowEnergyAdvertisingData - - public init(data: LowEnergyAdvertisingData, length: UInt8) { - - self.length = length - self.data = data - } - - public init() { - - self.length = 0 - self.data = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - } - - public var byteValue: [UInt8] { - - return [length, data.0, data.1, data.2, data.3, data.4, data.5, data.6, data.7, data.8, data.9, data.10, data.11, data.12, data.13, data.14, data.15, data.16, data.17, data.18, data.19, data.20, data.21, data.22, data.23, data.24, data.25, data.26, data.27, data.28, data.29, data.30] - } - } - - /// LE Set Advertising Parameters Command - /// - /// Used by the Host to set the advertising parameters. - public struct SetAdvertisingParametersParameter: HCICommandParameter { - - public static let command = LowEnergyCommand.SetAdvertisingParameters - public static let length = 2 + 2 + 1 + 1 + 1 + 6 + 1 + 1 - - /// Interval for non-directed advertising. - public var interval: (minimum: UInt16, maximum: UInt16) - - public var advertisingType: AdvertisingChannelHeader - - public var addressType: (own: LowEnergyAddressType, direct: LowEnergyAddressType) - - /// Public Device Address or Random Device Address of the device to be connected. - public var directAddress: Address - - public var channelMap: ChannelMap - - public var filterPolicy: FilterPolicy - - public init(interval: (minimum: UInt16, maximum: UInt16) = (0x0800, 0x0800), - advertisingType: AdvertisingChannelHeader = AdvertisingChannelHeader(), - addressType: (own: LowEnergyAddressType, direct: LowEnergyAddressType) = (.Public, .Public), - directAddress: Address = Address(byteValue: (0,0,0,0,0,0)), - channelMap: ChannelMap = ChannelMap(), - filterPolicy: FilterPolicy = FilterPolicy()) { - - self.interval = interval - self.advertisingType = advertisingType - self.addressType = addressType - self.directAddress = directAddress - self.channelMap = channelMap - self.filterPolicy = filterPolicy - } - - public var byteValue: [UInt8] { - - let minimumIntervalBytes = interval.minimum.littleEndianBytes - let maximumIntervalBytes = interval.maximum.littleEndianBytes - - return [minimumIntervalBytes.0, minimumIntervalBytes.1, - maximumIntervalBytes.0, maximumIntervalBytes.1, - advertisingType.rawValue, - addressType.own.rawValue, - addressType.direct.rawValue, - directAddress.byteValue.0, directAddress.byteValue.1, directAddress.byteValue.2, directAddress.byteValue.3, directAddress.byteValue.4, directAddress.byteValue.5, channelMap.rawValue, filterPolicy.rawValue] - } - - public enum ChannelMap: UInt8 { - - /// Default (all channels enabled) - case All = 0b00000111 - case Channel37 = 0b00000001 - case Channel38 = 0b00000010 - case Channel39 = 0b00000100 - - public init() { self = ChannelMap.All } - } - - public enum FilterPolicy: UInt8 { - - /// Allow Scan Request from Any, Allow Connect Request from Any (default). - case AnyScanConnect = 0x00 - - /// Allow Scan Request from White List Only, Allow Connect Request from Any. - case WhiteListScan = 0x01 - - /// Allow Scan Request from Any, Allow Connect Request from White List Only. - case WhiteListConnect = 0x02 - - /// Allow Scan Request from White List Only, Allow Connect Request from White List Only. - case WhiteListScanConnect = 0x03 - - public init() { self = FilterPolicy.AnyScanConnect } - } - } - - /// LE Set Advertise Enable Command - public struct SetAdvertiseEnableParameter: HCICommandParameter { - - public static let command = LowEnergyCommand.SetAdvertiseEnable - public static let length = 1 - - public var enabled: Bool - - public init(enabled: Bool = false) { - - self.enabled = enabled - } - - public var byteValue: [UInt8] { - - let enabledByte: UInt8 = enabled ? 0x01 : 0x00 - - return [enabledByte] - } - } -} - - diff --git a/Sources/BluetoothLinux/LowEnergyEvent.swift b/Sources/BluetoothLinux/LowEnergyEvent.swift deleted file mode 100644 index 60c6200..0000000 --- a/Sources/BluetoothLinux/LowEnergyEvent.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// LowEnergyEvent.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/2/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// Bluetooth Low Energy HCI Events -public enum LowEnergyEvent: UInt8, HCIEvent { - - case ConnectionComplete = 0x01 - - // TODO: All LE Events -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/LowEnergyEventParameter.swift b/Sources/BluetoothLinux/LowEnergyEventParameter.swift deleted file mode 100644 index 2f8e538..0000000 --- a/Sources/BluetoothLinux/LowEnergyEventParameter.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// LowEnergyEventParameter.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/2/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -public extension LowEnergyEvent { - - public struct ConnectionCompleteParameter: HCIEventParameter { - - public static let event = LowEnergyEvent.ConnectionComplete - public static let length = 18 - - public var status: UInt8 = 0 - public var handle: UInt16 = 0 - public var role: UInt8 = 0 - public var peerAddressType: LowEnergyAddressType = LowEnergyAddressType() - public var peerAddress: Address = Address() - public var interval: UInt16 = 0 - public var latency: UInt16 = 0 - public var supervisionTimeout: UInt16 = 0 - public var masterClockAccuracy: UInt8 = 0 - - public init() { } - - public init?(byteValue: [UInt8]) { - - fatalError("Not implemented") - } - } -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/PSM.swift b/Sources/BluetoothLinux/PSM.swift deleted file mode 100644 index a03c76e..0000000 --- a/Sources/BluetoothLinux/PSM.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// PSM.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/1/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -/// Protocol/Service Multiplexer (PSM). -public enum ProtocolServiceMultiplexer: UInt8 { - - case SDP = 0x0001 - case RFCOMM = 0x0003 - case TCS = 0x0005 - case CTP = 0x0007 - case BNEP = 0x000F - case HIDC = 0x0011 - case HIDI = 0x0013 - case UPNP = 0x0015 - case AVCTP = 0x0017 - case AVDTP = 0x0019 - - /// Advanced Control - Browsing - case AVCTP13 = 0x001B - - /// Unrestricted Digital Information Profile C-Plane - case UDICP = 0x001D - - /// Attribute Protocol - case ATT = 0x001F -} \ No newline at end of file diff --git a/Sources/BluetoothLinux/Scan.swift b/Sources/BluetoothLinux/Scan.swift index 6c37171..81ba95d 100644 --- a/Sources/BluetoothLinux/Scan.swift +++ b/Sources/BluetoothLinux/Scan.swift @@ -14,6 +14,7 @@ #endif import SwiftFoundation +import Bluetooth // MARK: - Methods diff --git a/Sources/BluetoothLinux/UUID.swift b/Sources/BluetoothLinux/UUID.swift deleted file mode 100644 index b0d13d6..0000000 --- a/Sources/BluetoothLinux/UUID.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// UUID.swift -// BluetoothLinux -// -// Created by Alsey Coleman Miller on 3/4/16. -// Copyright © 2016 PureSwift. All rights reserved. -// - -import struct SwiftFoundation.UUID - -/// Bluetooth UUID -public enum BluetoothUUID: Equatable { - - /// Bluetooth Base UUID - public static let BaseUUID = UUID(byteValue: (0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB)) - - case Bit16(UInt16) - case Bit128(SwiftFoundation.UUID) - - public var byteValue: [UInt8] { - - switch self { - - case let .Bit16(value): - - let bytes = value.littleEndianBytes - - return [bytes.0, bytes.1] - - case let .Bit128(value): - - let bytes = value.byteValue - - return [bytes.0, bytes.1, bytes.2, bytes.3, bytes.4, bytes.5, bytes.6, bytes.7, bytes.8, bytes.9, bytes.10, bytes.11, bytes.12, bytes.13, bytes.14, bytes.15] - } - } - - /// Converts the Bluetooth UUID to a universal UUID. - public func toUUID() -> SwiftFoundation.UUID { - - switch self { - - case let .Bit128(value): return value - - case let .Bit16(value): - - let bytes = value.littleEndianBytes - - var byteValue = BluetoothUUID.BaseUUID.byteValue - - // replace empty bytes with UInt16 bytes - byteValue.0 = bytes.0 - byteValue.1 = bytes.1 - - return SwiftFoundation.UUID(byteValue: byteValue) - } - } -} - -// MARK: - Equatable - -public func == (lhs: BluetoothUUID, rhs: BluetoothUUID) -> Bool { - - switch (lhs, rhs) { - - case let (.Bit16(lhsValue), .Bit16(rhsValue)): return lhsValue == rhsValue - - case let (.Bit128(lhsValue), .Bit128(rhsValue)): return lhsValue == rhsValue - - default: return false - } -} - diff --git a/Sources/BluetoothLinux/iBeacon.swift b/Sources/BluetoothLinux/iBeacon.swift index 1b3343d..a5a0f1f 100644 --- a/Sources/BluetoothLinux/iBeacon.swift +++ b/Sources/BluetoothLinux/iBeacon.swift @@ -13,26 +13,7 @@ #endif import SwiftFoundation - -/// 31 Byte LE Advertising Data -public typealias LowEnergyAdvertisingData = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - -public enum AdvertisingChannelHeader: UInt8 { - - /// Connectable undirected advertising event - case Undirected = 0x00 - - /// Connectable directed advertising event - case Directed = 0x01 - - /// Scannable undirected advertising event - case Scannable = 0x02 - - /// Non-connectable undirected advertising event - case NonConnectable = 0x03 - - public init() { self = .Undirected } -} +import Bluetooth public extension Adapter { diff --git a/Sources/GATTServerTest/GATTServerTest.swift b/Sources/GATTServerTest/GATTServerTest.swift index f23a938..8147740 100644 --- a/Sources/GATTServerTest/GATTServerTest.swift +++ b/Sources/GATTServerTest/GATTServerTest.swift @@ -14,6 +14,7 @@ #endif import SwiftFoundation +import Bluetooth func GATTServerTest(adapter: Adapter) { @@ -75,39 +76,39 @@ func GATTServerTest(adapter: Adapter) { private func generateDB() -> GATTDatabase { - let uuid = { BluetoothUUID.Bit128(UUID()) } + let uuid = { Bluetooth.UUID.Bit128(SwiftFoundation.UUID()) } var services: [GATTDatabase.Service] = [] do { - let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Hey".toUTF8Data().byteValue, permissions: [.Read, .Write], properties: [.Read, .Write]) + let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Hey".toUTF8Data(), permissions: [.Read, .Write], properties: [.Read, .Write]) - let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Hola".toUTF8Data().byteValue, permissions: [.Read, .Write], properties: [.Read, .Write]) + let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Hola".toUTF8Data(), permissions: [.Read, .Write], properties: [.Read, .Write]) - let service = GATTDatabase.Service(characteristics: [characteristic, characteristic2], UUID: uuid()) + let service = GATTDatabase.Service(UUID: uuid(), characteristics: [characteristic, characteristic2]) services.append(service) } do { - let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Bye".toUTF8Data().byteValue, permissions: [.Read, .Write], properties: [.Read, .Write]) + let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Bye".toUTF8Data(), permissions: [.Read, .Write], properties: [.Read, .Write]) - let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Chau".toUTF8Data().byteValue, permissions: [.Read, .Write], properties: [.Read, .Write]) + let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Chau".toUTF8Data(), permissions: [.Read, .Write], properties: [.Read, .Write]) - let service = GATTDatabase.Service(characteristics: [characteristic, characteristic2], UUID: uuid()) + let service = GATTDatabase.Service(UUID: uuid(), characteristics: [characteristic, characteristic2]) services.append(service) } do { - let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Read Only".toUTF8Data().byteValue, permissions: [.Read], properties: [.Read]) + let characteristic = GATTDatabase.Characteristic(UUID: uuid(), value: "Read Only".toUTF8Data(), permissions: [.Read], properties: [.Read]) - let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Write Only".toUTF8Data().byteValue, permissions: [.Write], properties: [.Write]) + let characteristic2 = GATTDatabase.Characteristic(UUID: uuid(), value: "Write Only".toUTF8Data(), permissions: [.Write], properties: [.Write]) - let service = GATTDatabase.Service(characteristics: [characteristic, characteristic2], UUID: uuid()) + let service = GATTDatabase.Service(UUID: uuid(), characteristics: [characteristic, characteristic2]) services.append(service) } diff --git a/Sources/L2CAPServerTest/L2CAPServerTest.swift b/Sources/L2CAPServerTest/L2CAPServerTest.swift index 5e95c1c..f50fc1b 100644 --- a/Sources/L2CAPServerTest/L2CAPServerTest.swift +++ b/Sources/L2CAPServerTest/L2CAPServerTest.swift @@ -14,6 +14,7 @@ #endif import SwiftFoundation +import Bluetooth func PeripheralTest(adapter: Adapter) { diff --git a/Xcode/BluetoothLinux.xcodeproj/project.pbxproj b/Xcode/BluetoothLinux.xcodeproj/project.pbxproj index 9ba8927..d41e72e 100644 --- a/Xcode/BluetoothLinux.xcodeproj/project.pbxproj +++ b/Xcode/BluetoothLinux.xcodeproj/project.pbxproj @@ -11,46 +11,26 @@ 6E0C5BC21C837AA700AF63E5 /* ScanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0C5BBE1C8379D100AF63E5 /* ScanTest.swift */; }; 6E0C5BC31C837AAA00AF63E5 /* iBeaconTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0C5BC01C837A9F00AF63E5 /* iBeaconTest.swift */; }; 6E0C5BD81C83A45100AF63E5 /* SecurityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0C5BD71C83A45100AF63E5 /* SecurityType.swift */; }; - 6E1552461C39A045002CC322 /* HCIEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E1552451C39A045002CC322 /* HCIEvent.swift */; }; - 6E15524A1C39A284002CC322 /* LowEnergyAddressType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E1552491C39A284002CC322 /* LowEnergyAddressType.swift */; }; 6E196CC31C8659DA009FA9CF /* HCI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CC21C8659DA009FA9CF /* HCI.swift */; }; 6E196CC51C869A2E009FA9CF /* IOCTL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CC41C869A2E009FA9CF /* IOCTL.swift */; }; 6E196CC71C86A5EC009FA9CF /* BluetoothProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CC61C86A5EC009FA9CF /* BluetoothProtocol.swift */; }; - 6E196CC91C86E797009FA9CF /* Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CC81C86E797009FA9CF /* Hexadecimal.swift */; }; 6E196CCB1C87B47E009FA9CF /* DeviceCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CCA1C87B47E009FA9CF /* DeviceCommand.swift */; }; - 6E196CCC1C87BA9F009FA9CF /* LinkControlCommandParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E795E911C48A186002377FE /* LinkControlCommandParameter.swift */; }; - 6E196CCE1C87BBE1009FA9CF /* LowEnergyEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CCD1C87BBE1009FA9CF /* LowEnergyEvent.swift */; }; - 6E196CD01C87BE63009FA9CF /* LowEnergyEventParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CCF1C87BE63009FA9CF /* LowEnergyEventParameter.swift */; }; - 6E196CD11C87C0B9009FA9CF /* LowEnergyCommandParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E795E8F1C489FE7002377FE /* LowEnergyCommandParameter.swift */; }; - 6E434C2D1C89984A0069045A /* UUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E434C2C1C89984A0069045A /* UUID.swift */; }; 6E53E1731C84FD8200AC8FCA /* GATTServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1721C84FD8200AC8FCA /* GATTServer.swift */; }; 6E53E1751C84FD8C00AC8FCA /* GATTClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1741C84FD8C00AC8FCA /* GATTClient.swift */; }; 6E53E1771C8503AC00AC8FCA /* GATTDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1761C8503AC00AC8FCA /* GATTDatabase.swift */; }; 6E53E1791C8503CA00AC8FCA /* ATTConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1781C8503CA00AC8FCA /* ATTConnection.swift */; }; - 6E53E17B1C85645400AC8FCA /* PSM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E17A1C85645400AC8FCA /* PSM.swift */; }; 6E53E17F1C85945E00AC8FCA /* Deque.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E17E1C85945E00AC8FCA /* Deque.swift */; }; - 6E53E1831C859E8300AC8FCA /* ATTProtocolDataUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1821C859E8300AC8FCA /* ATTProtocolDataUnit.swift */; }; - 6E739C8A1C884F1200D4775B /* HCIGeneralEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E739C891C884F1200D4775B /* HCIGeneralEvent.swift */; }; - 6E739C8C1C884F3A00D4775B /* HCIGeneralEventParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E739C8B1C884F3A00D4775B /* HCIGeneralEventParameter.swift */; }; - 6E795E891C47EC90002377FE /* LowEnergyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E795E881C47EC8F002377FE /* LowEnergyCommand.swift */; }; 6E795E9B1C49821B002377FE /* LinkMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E795E9A1C49821B002377FE /* LinkMode.swift */; }; 6E881D821C389F4B00E509A9 /* iBeacon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E881D811C389F4B00E509A9 /* iBeacon.swift */; }; 6E881DA21C39812F00E509A9 /* DeviceRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E881D831C39783F00E509A9 /* DeviceRequest.swift */; }; - 6E881DAC1C3996A200E509A9 /* HCIOpcodeGroupField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E881DAB1C3996A200E509A9 /* HCIOpcodeGroupField.swift */; }; 6E894BF41C83B51B00109F45 /* AddressType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E894BF31C83B51B00109F45 /* AddressType.swift */; }; 6E894C001C83EA2000109F45 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0C5BBD1C8379D100AF63E5 /* main.swift */; }; 6E894C021C83F1C500109F45 /* L2CAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E894C011C83F1C500109F45 /* L2CAP.swift */; }; - 6E894C041C84092100109F45 /* Endianness.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E894C031C84092100109F45 /* Endianness.swift */; }; 6E927EC91C977D7D009AB500 /* IOVector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E927EC81C977D7D009AB500 /* IOVector.swift */; }; 6E92A4281C15309B007BC4E9 /* BluetoothLinux.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E92A4271C15309B007BC4E9 /* BluetoothLinux.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6E92A4371C1530EF007BC4E9 /* Adapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E92A4321C1530EF007BC4E9 /* Adapter.swift */; }; - 6E92A4381C1530EF007BC4E9 /* Address.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E92A4331C1530EF007BC4E9 /* Address.swift */; }; 6E92A43B1C1530EF007BC4E9 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E92A4361C1530EF007BC4E9 /* Scan.swift */; }; 6EA37EF41C84B4EA00A61969 /* L2CAPServerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA37EF21C84B4EA00A61969 /* L2CAPServerTest.swift */; }; - 6EA37EF61C84D6C800A61969 /* ATT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA37EF51C84D6C800A61969 /* ATT.swift */; }; - 6EA37EF81C84D6CE00A61969 /* GATT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EA37EF71C84D6CE00A61969 /* GATT.swift */; }; - 6ECB305D1C47613F004CCA68 /* LinkControlCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ECB305C1C47613F004CCA68 /* LinkControlCommand.swift */; }; - 6ECB30601C47618E004CCA68 /* HCICommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ECB305F1C47618E004CCA68 /* HCICommand.swift */; }; 6EF355211C965EB400730BAB /* GATTServerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EF355201C965EB400730BAB /* GATTServerTest.swift */; }; 6EF928FB1C8830D200D9A103 /* BluetoothLinux.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E92A4241C15309B007BC4E9 /* BluetoothLinux.framework */; }; 6EF929031C88316D00D9A103 /* MathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6EF929021C88316D00D9A103 /* MathTests.swift */; }; @@ -89,50 +69,31 @@ 6E0C5BC01C837A9F00AF63E5 /* iBeaconTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iBeaconTest.swift; sourceTree = ""; }; 6E0C5BC11C837A9F00AF63E5 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 6E0C5BD71C83A45100AF63E5 /* SecurityType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecurityType.swift; sourceTree = ""; }; - 6E1552451C39A045002CC322 /* HCIEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCIEvent.swift; sourceTree = ""; }; - 6E1552491C39A284002CC322 /* LowEnergyAddressType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyAddressType.swift; sourceTree = ""; }; 6E196CC21C8659DA009FA9CF /* HCI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCI.swift; sourceTree = ""; }; 6E196CC41C869A2E009FA9CF /* IOCTL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOCTL.swift; sourceTree = ""; }; 6E196CC61C86A5EC009FA9CF /* BluetoothProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothProtocol.swift; sourceTree = ""; }; - 6E196CC81C86E797009FA9CF /* Hexadecimal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hexadecimal.swift; sourceTree = ""; }; 6E196CCA1C87B47E009FA9CF /* DeviceCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceCommand.swift; sourceTree = ""; }; - 6E196CCD1C87BBE1009FA9CF /* LowEnergyEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyEvent.swift; sourceTree = ""; }; - 6E196CCF1C87BE63009FA9CF /* LowEnergyEventParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyEventParameter.swift; sourceTree = ""; }; - 6E434C2C1C89984A0069045A /* UUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UUID.swift; sourceTree = ""; }; 6E53E1721C84FD8200AC8FCA /* GATTServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTServer.swift; sourceTree = ""; }; 6E53E1741C84FD8C00AC8FCA /* GATTClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTClient.swift; sourceTree = ""; }; 6E53E1761C8503AC00AC8FCA /* GATTDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTDatabase.swift; sourceTree = ""; }; 6E53E1781C8503CA00AC8FCA /* ATTConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATTConnection.swift; sourceTree = ""; }; - 6E53E17A1C85645400AC8FCA /* PSM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PSM.swift; sourceTree = ""; }; 6E53E17E1C85945E00AC8FCA /* Deque.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deque.swift; sourceTree = ""; }; - 6E53E1821C859E8300AC8FCA /* ATTProtocolDataUnit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATTProtocolDataUnit.swift; sourceTree = ""; }; - 6E739C891C884F1200D4775B /* HCIGeneralEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCIGeneralEvent.swift; sourceTree = ""; }; - 6E739C8B1C884F3A00D4775B /* HCIGeneralEventParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCIGeneralEventParameter.swift; sourceTree = ""; }; 6E739C8D1C88EE4C00D4775B /* ioctl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioctl.h; sourceTree = ""; }; - 6E795E881C47EC8F002377FE /* LowEnergyCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyCommand.swift; sourceTree = ""; }; - 6E795E8F1C489FE7002377FE /* LowEnergyCommandParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyCommandParameter.swift; sourceTree = ""; }; - 6E795E911C48A186002377FE /* LinkControlCommandParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkControlCommandParameter.swift; sourceTree = ""; }; 6E795E9A1C49821B002377FE /* LinkMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkMode.swift; sourceTree = ""; }; 6E881D811C389F4B00E509A9 /* iBeacon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = iBeacon.swift; sourceTree = ""; }; 6E881D831C39783F00E509A9 /* DeviceRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceRequest.swift; sourceTree = ""; }; - 6E881DAB1C3996A200E509A9 /* HCIOpcodeGroupField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCIOpcodeGroupField.swift; sourceTree = ""; }; 6E894BF31C83B51B00109F45 /* AddressType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddressType.swift; sourceTree = ""; }; 6E894C011C83F1C500109F45 /* L2CAP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = L2CAP.swift; sourceTree = ""; }; - 6E894C031C84092100109F45 /* Endianness.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endianness.swift; sourceTree = ""; }; 6E927EC81C977D7D009AB500 /* IOVector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IOVector.swift; sourceTree = ""; }; 6E92A4241C15309B007BC4E9 /* BluetoothLinux.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BluetoothLinux.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6E92A4271C15309B007BC4E9 /* BluetoothLinux.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BluetoothLinux.h; sourceTree = ""; }; 6E92A4291C15309B007BC4E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 6E92A42F1C1530DC007BC4E9 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Package.swift; path = ../Package.swift; sourceTree = ""; }; 6E92A4321C1530EF007BC4E9 /* Adapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Adapter.swift; sourceTree = ""; }; - 6E92A4331C1530EF007BC4E9 /* Address.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Address.swift; sourceTree = ""; }; 6E92A4361C1530EF007BC4E9 /* Scan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scan.swift; sourceTree = ""; }; 6EA37EF11C84B4EA00A61969 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 6EA37EF21C84B4EA00A61969 /* L2CAPServerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = L2CAPServerTest.swift; sourceTree = ""; }; - 6EA37EF51C84D6C800A61969 /* ATT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATT.swift; sourceTree = ""; }; - 6EA37EF71C84D6CE00A61969 /* GATT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATT.swift; sourceTree = ""; }; - 6ECB305C1C47613F004CCA68 /* LinkControlCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkControlCommand.swift; sourceTree = ""; }; - 6ECB305F1C47618E004CCA68 /* HCICommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HCICommand.swift; sourceTree = ""; }; + 6EE84E071CAF8E7B00A40C4D /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; name = Cartfile; path = ../Cartfile; sourceTree = ""; }; 6EF3551E1C965E8F00730BAB /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 6EF355201C965EB400730BAB /* GATTServerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTServerTest.swift; sourceTree = ""; }; 6EF928F61C8830D100D9A103 /* BluetoothLinuxTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BluetoothLinuxTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -195,23 +156,12 @@ path = ../Sources/iBeaconTest; sourceTree = ""; }; - 6E795E951C48B815002377FE /* HCI Event */ = { - isa = PBXGroup; - children = ( - 6E1552451C39A045002CC322 /* HCIEvent.swift */, - 6E739C891C884F1200D4775B /* HCIGeneralEvent.swift */, - 6E739C8B1C884F3A00D4775B /* HCIGeneralEventParameter.swift */, - 6E196CCD1C87BBE1009FA9CF /* LowEnergyEvent.swift */, - 6E196CCF1C87BE63009FA9CF /* LowEnergyEventParameter.swift */, - ); - name = "HCI Event"; - sourceTree = ""; - }; 6E92A41A1C15309B007BC4E9 = { isa = PBXGroup; children = ( - 6EF9290C1C88377100D9A103 /* Dependencies */, + 6EE84E071CAF8E7B00A40C4D /* Cartfile */, 6E92A42F1C1530DC007BC4E9 /* Package.swift */, + 6EF9290C1C88377100D9A103 /* Dependencies */, 6EF929011C88312A00D9A103 /* Unit Tests */, 6E0C5BBA1C83794700AF63E5 /* Tests Tools */, 6E92A4311C1530EF007BC4E9 /* Source */, @@ -243,13 +193,8 @@ isa = PBXGroup; children = ( 6E0C5BB81C8373DB00AF63E5 /* Darwin.swift */, - 6E894C031C84092100109F45 /* Endianness.swift */, - 6E196CC81C86E797009FA9CF /* Hexadecimal.swift */, 6E92A4321C1530EF007BC4E9 /* Adapter.swift */, - 6E92A4331C1530EF007BC4E9 /* Address.swift */, - 6E434C2C1C89984A0069045A /* UUID.swift */, 6E894BF31C83B51B00109F45 /* AddressType.swift */, - 6E1552491C39A284002CC322 /* LowEnergyAddressType.swift */, 6E0C5BD71C83A45100AF63E5 /* SecurityType.swift */, 6E196CCA1C87B47E009FA9CF /* DeviceCommand.swift */, 6E881D831C39783F00E509A9 /* DeviceRequest.swift */, @@ -258,21 +203,14 @@ 6E92A4361C1530EF007BC4E9 /* Scan.swift */, 6E881D811C389F4B00E509A9 /* iBeacon.swift */, 6E927EC81C977D7D009AB500 /* IOVector.swift */, - 6E53E17A1C85645400AC8FCA /* PSM.swift */, 6E894C011C83F1C500109F45 /* L2CAP.swift */, - 6EA37EF51C84D6C800A61969 /* ATT.swift */, - 6E53E1821C859E8300AC8FCA /* ATTProtocolDataUnit.swift */, 6E53E1781C8503CA00AC8FCA /* ATTConnection.swift */, - 6EA37EF71C84D6CE00A61969 /* GATT.swift */, 6E53E1721C84FD8200AC8FCA /* GATTServer.swift */, 6E53E1741C84FD8C00AC8FCA /* GATTClient.swift */, 6E53E1761C8503AC00AC8FCA /* GATTDatabase.swift */, 6E53E17E1C85945E00AC8FCA /* Deque.swift */, 6E196CC41C869A2E009FA9CF /* IOCTL.swift */, 6E196CC21C8659DA009FA9CF /* HCI.swift */, - 6E881DAB1C3996A200E509A9 /* HCIOpcodeGroupField.swift */, - 6E795E951C48B815002377FE /* HCI Event */, - 6ECB305E1C476145004CCA68 /* HCI Commands */, ); name = Source; path = ../Sources/BluetoothLinux; @@ -288,18 +226,6 @@ path = ../Sources/L2CAPServerTest; sourceTree = ""; }; - 6ECB305E1C476145004CCA68 /* HCI Commands */ = { - isa = PBXGroup; - children = ( - 6ECB305F1C47618E004CCA68 /* HCICommand.swift */, - 6ECB305C1C47613F004CCA68 /* LinkControlCommand.swift */, - 6E795E911C48A186002377FE /* LinkControlCommandParameter.swift */, - 6E795E881C47EC8F002377FE /* LowEnergyCommand.swift */, - 6E795E8F1C489FE7002377FE /* LowEnergyCommandParameter.swift */, - ); - name = "HCI Commands"; - sourceTree = ""; - }; 6EF3551D1C965E8F00730BAB /* GATTServerTest */ = { isa = PBXGroup; children = ( @@ -458,50 +384,30 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 6E795E891C47EC90002377FE /* LowEnergyCommand.swift in Sources */, - 6E894C041C84092100109F45 /* Endianness.swift in Sources */, - 6E53E17B1C85645400AC8FCA /* PSM.swift in Sources */, - 6E196CCC1C87BA9F009FA9CF /* LinkControlCommandParameter.swift in Sources */, + 6E0C5BB91C8373DB00AF63E5 /* Darwin.swift in Sources */, + 6E92A4371C1530EF007BC4E9 /* Adapter.swift in Sources */, + 6E894C021C83F1C500109F45 /* L2CAP.swift in Sources */, 6E53E1771C8503AC00AC8FCA /* GATTDatabase.swift in Sources */, - 6E881DAC1C3996A200E509A9 /* HCIOpcodeGroupField.swift in Sources */, - 6E434C2D1C89984A0069045A /* UUID.swift in Sources */, - 6E15524A1C39A284002CC322 /* LowEnergyAddressType.swift in Sources */, + 6E53E1731C84FD8200AC8FCA /* GATTServer.swift in Sources */, 6E0C5BC31C837AAA00AF63E5 /* iBeaconTest.swift in Sources */, 6E53E1751C84FD8C00AC8FCA /* GATTClient.swift in Sources */, 6E0C5BD81C83A45100AF63E5 /* SecurityType.swift in Sources */, 6E92A43B1C1530EF007BC4E9 /* Scan.swift in Sources */, 6E881D821C389F4B00E509A9 /* iBeacon.swift in Sources */, - 6E196CD01C87BE63009FA9CF /* LowEnergyEventParameter.swift in Sources */, - 6E92A4381C1530EF007BC4E9 /* Address.swift in Sources */, 6EF355211C965EB400730BAB /* GATTServerTest.swift in Sources */, - 6E196CCE1C87BBE1009FA9CF /* LowEnergyEvent.swift in Sources */, 6E196CCB1C87B47E009FA9CF /* DeviceCommand.swift in Sources */, - 6E53E1731C84FD8200AC8FCA /* GATTServer.swift in Sources */, - 6E53E1831C859E8300AC8FCA /* ATTProtocolDataUnit.swift in Sources */, 6E927EC91C977D7D009AB500 /* IOVector.swift in Sources */, - 6E739C8C1C884F3A00D4775B /* HCIGeneralEventParameter.swift in Sources */, 6E196CC51C869A2E009FA9CF /* IOCTL.swift in Sources */, 6E881DA21C39812F00E509A9 /* DeviceRequest.swift in Sources */, 6E795E9B1C49821B002377FE /* LinkMode.swift in Sources */, 6E53E17F1C85945E00AC8FCA /* Deque.swift in Sources */, - 6EA37EF61C84D6C800A61969 /* ATT.swift in Sources */, 6E0C5BC21C837AA700AF63E5 /* ScanTest.swift in Sources */, - 6E739C8A1C884F1200D4775B /* HCIGeneralEvent.swift in Sources */, - 6ECB305D1C47613F004CCA68 /* LinkControlCommand.swift in Sources */, - 6E196CC91C86E797009FA9CF /* Hexadecimal.swift in Sources */, - 6EA37EF81C84D6CE00A61969 /* GATT.swift in Sources */, - 6ECB30601C47618E004CCA68 /* HCICommand.swift in Sources */, - 6E1552461C39A045002CC322 /* HCIEvent.swift in Sources */, - 6E196CD11C87C0B9009FA9CF /* LowEnergyCommandParameter.swift in Sources */, 6E894C001C83EA2000109F45 /* main.swift in Sources */, 6E196CC31C8659DA009FA9CF /* HCI.swift in Sources */, 6E196CC71C86A5EC009FA9CF /* BluetoothProtocol.swift in Sources */, 6E894BF41C83B51B00109F45 /* AddressType.swift in Sources */, - 6EA37EF41C84B4EA00A61969 /* L2CAPServerTest.swift in Sources */, - 6E894C021C83F1C500109F45 /* L2CAP.swift in Sources */, - 6E92A4371C1530EF007BC4E9 /* Adapter.swift in Sources */, - 6E0C5BB91C8373DB00AF63E5 /* Darwin.swift in Sources */, 6E53E1791C8503CA00AC8FCA /* ATTConnection.swift in Sources */, + 6EA37EF41C84B4EA00A61969 /* L2CAPServerTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };