Skip to content

Commit

Permalink
Added LECreateConnection command line tool
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Nov 30, 2017
1 parent 3c80478 commit 427661a
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 20 deletions.
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ let package = Package(
Target(
name: "LEScanTest",
dependencies: [.Target(name: "BluetoothLinux")]),
Target(
name: "LECreateConnection",
dependencies: [.Target(name: "BluetoothLinux")]),
Target(
name: "BluetoothLinux")
],
Expand Down
25 changes: 15 additions & 10 deletions Sources/BluetoothLinux/DeviceRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,29 @@ import Bluetooth
public extension Adapter {

/// Sends a command to the device and waits for a response.
/*
@inline(__always)
func deviceRequest<CP: HCICommandParameter, EP: HCIEventParameter>(commandParameter: CP, eventParameterType: EP.Type, timeout: Int = 1000) throws -> EP {

let command = CP.command

let opcodeGroupField = command.dynamicType.opcodeGroupField

let parameterData = commandParameter.bytes

let data = try HCISendRequest(internalSocket, opcode: (command.rawValue, opcodeGroupField.rawValue), commandParameterData: parameterData, eventParameterLength: EP.length, event: EP.event.rawValue, timeout: timeout)

guard let eventParameter = EP(bytes: data)
else { throw AdapterError.GarbageResponse(Data(bytes: data)) }
let opcodeGroupField = CP.HCICommandType.opcodeGroupField

let parameterData = commandParameter.byteValue

let data = try HCISendRequest(internalSocket,
opcode: (command.rawValue, opcodeGroupField.rawValue),
commandParameterData: parameterData,
event: EP.event.rawValue,
eventParameterLength: EP.length,
timeout: timeout)

guard let eventParameter = EP(byteValue: data)
else { throw AdapterError.garbageResponse(Data(bytes: data)) }

return eventParameter
}


/*
@inline(__always)
func deviceRequest<C: HCICommand, EP: HCIEventParameter>(command: C, eventParameterType: EP.Type, timeout: Int = 1000) throws -> EP {

Expand Down
15 changes: 11 additions & 4 deletions Sources/BluetoothLinux/L2CAP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ public final class L2CAPSocket {
let socketLength = socklen_t(MemoryLayout<sockaddr_l2>.size)

// bind socket to port and address
guard withUnsafePointer(to: &localAddress, { bind(internalSocket, unsafeBitCast($0, to: UnsafeMutablePointer<sockaddr>.self), socketLength) }) == 0
else { close(internalSocket); throw POSIXError.fromErrno! }
guard withUnsafeMutablePointer(to: &localAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1, {
bind(internalSocket, $0, socketLength) == 0
})
}) else { close(internalSocket); throw POSIXError.fromErrno! }

// set security level
var security = bt_security()
Expand Down Expand Up @@ -141,8 +144,12 @@ public final class L2CAPSocket {
var socketLength = socklen_t(MemoryLayout<sockaddr_l2>.size)

// accept new client
let client = withUnsafeMutablePointer(to: &remoteAddress, { accept(internalSocket, unsafeBitCast($0, to: UnsafeMutablePointer<sockaddr>.self), &socketLength) })

let client = withUnsafeMutablePointer(to: &remoteAddress, {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1, {
accept(internalSocket, $0, &socketLength)
})
})

// error accepting new connection
guard client >= 0 else { throw POSIXError.fromErrno! }

Expand Down
19 changes: 15 additions & 4 deletions Sources/BluetoothLinux/LowEnergyConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,31 @@ public extension Adapter {
public func lowEnergyCreateConnection(address peerAddress: Address,
type peerAddressType: LowEnergyAddressType = .public,
ownAddressType: LowEnergyAddressType = .public,
commandTimeout timeout: Int = 1000) throws {
commandTimeout timeout: Int = 1000) throws -> UInt16 {

let parameters = LowEnergyCommand.CreateConnectionParameter(peerAddressType: peerAddressType,
peerAddress: peerAddress,
ownAddressType: ownAddressType)

try lowEnergyCreateConnection(parameters: parameters, commandTimeout: timeout)
return try lowEnergyCreateConnection(parameters: parameters, commandTimeout: timeout)
}

public func lowEnergyCreateConnection(parameters: LowEnergyCommand.CreateConnectionParameter,
commandTimeout timeout: Int = 1000) throws {
commandTimeout timeout: Int = 1000) throws -> UInt16 {

// connect with specified parameters
try deviceRequest(parameters, timeout: timeout)
let event = try deviceRequest(commandParameter: parameters,
eventParameterType: LowEnergyEvent.ConnectionCompleteParameter.self,
timeout: timeout)

switch event.status {

case let .error(error):
throw error

case .success:
return event.handle
}
}

/// LE Create Connection Cancel Command
Expand Down
7 changes: 5 additions & 2 deletions Sources/L2CAPServerTest/L2CAPServerTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ func PeripheralTest(adapter: Adapter) {

let address = adapter.address!

let server = try L2CAPSocket(adapterAddress: address, channelIdentifier: ATT.CID, addressType: .LowEnergyPublic, securityLevel: .Low)

let server = try L2CAPSocket(adapterAddress: address,
channelIdentifier: ATT.CID,
addressType: .LowEnergyPublic,
securityLevel: .Low)

print("Created L2CAP server")

let newConnection = try server.waitForConnection()
Expand Down
46 changes: 46 additions & 0 deletions Sources/LECreateConnection/LECreateConnection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// LEScanTest.swift
// BluetoothLinux
//
// Created by Alsey Coleman Miller on 11/29/17.
// Copyright © 2017 PureSwift. All rights reserved.
//

#if os(Linux)
import BluetoothLinux
import Glibc
#elseif os(macOS) || os(iOS)
import Darwin.C
#endif

import Foundation
import Bluetooth

/// Tests the Scanning functionality
func LECreateConnection(adapter: Adapter, peerAddress: Address, duration: TimeInterval) {

typealias ConnectionInterval = LowEnergyCommand.CreateConnectionParameter.ConnectionInterval

let connectionParameters = LowEnergyCommand.CreateConnectionParameter
.init(scanInterval: .min, // 0x0004
scanWindow: .min, // 0x0004
initiatorFilterPolicy: .peerAddress,
peerAddressType: .public,
peerAddress: peerAddress,
ownAddressType: .public,
connectionInterval: ConnectionInterval(rawValue: (0x000F ... 0x000F))!,
connectionLatency: .zero,
supervisionTimeout: .max,
connectionLength: .init(rawValue: 0x0001 ... 0x0001))

do {

let handle = try adapter.lowEnergyCreateConnection(parameters: connectionParameters, commandTimeout: 25000)

print("Connection handle \(handle)")


}

catch { Error("Could not scan: \(error)") }
}
38 changes: 38 additions & 0 deletions Sources/LECreateConnection/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// main.swift
// BluetoothLinux
//
// Created by Alsey Coleman Miller on 12/6/15.
// Copyright © 2015 PureSwift. All rights reserved.
//

#if os(Linux)
import BluetoothLinux
import Glibc
#elseif os(OSX) || os(iOS)
import Darwin.C
#endif

import Foundation

func Error(_ text: String) -> Never {

print(text)
exit(1)
}

// get Bluetooth device

let adapter: Adapter

do { adapter = try Adapter() }

catch { Error("Error: \(error)") }

print("Found Bluetooth adapter with device ID: \(adapter.identifier)")

print("Address: \(adapter.address!)")

/// Perform Test
LECreateConnection(adapter: adapter, duration: 10)

15 changes: 15 additions & 0 deletions Xcode/BluetoothLinux.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
6E196CCB1C87B47E009FA9CF /* DeviceCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E196CCA1C87B47E009FA9CF /* DeviceCommand.swift */; };
6E1DC1EC1FCF9B7400C8DE52 /* LowEnergyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E1DC1EB1FCF9B7400C8DE52 /* LowEnergyConnection.swift */; };
6E1DC1EE1FCFA29700C8DE52 /* LowEnergyWhiteList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E1DC1ED1FCFA29700C8DE52 /* LowEnergyWhiteList.swift */; };
6E1DC1F21FCFC1A800C8DE52 /* LECreateConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E1DC1F01FCFC1A800C8DE52 /* LECreateConnection.swift */; };
6E3229181FCDDB320035605D /* LowEnergyScan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E3229171FCDDB320035605D /* LowEnergyScan.swift */; };
6E53E1731C84FD8200AC8FCA /* GATTServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1721C84FD8200AC8FCA /* GATTServer.swift */; };
6E53E1751C84FD8C00AC8FCA /* GATTClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E53E1741C84FD8C00AC8FCA /* GATTClient.swift */; };
Expand Down Expand Up @@ -78,6 +79,8 @@
6E196CCA1C87B47E009FA9CF /* DeviceCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceCommand.swift; sourceTree = "<group>"; };
6E1DC1EB1FCF9B7400C8DE52 /* LowEnergyConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyConnection.swift; sourceTree = "<group>"; };
6E1DC1ED1FCFA29700C8DE52 /* LowEnergyWhiteList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyWhiteList.swift; sourceTree = "<group>"; };
6E1DC1F01FCFC1A800C8DE52 /* LECreateConnection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LECreateConnection.swift; sourceTree = "<group>"; };
6E1DC1F11FCFC1A800C8DE52 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
6E3229171FCDDB320035605D /* LowEnergyScan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LowEnergyScan.swift; sourceTree = "<group>"; };
6E53E1721C84FD8200AC8FCA /* GATTServer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTServer.swift; sourceTree = "<group>"; };
6E53E1741C84FD8C00AC8FCA /* GATTClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GATTClient.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -137,6 +140,7 @@
6E0C5BBA1C83794700AF63E5 /* Tests Tools */ = {
isa = PBXGroup;
children = (
6E1DC1EF1FCFC1A800C8DE52 /* LECreateConnection */,
6E6AD9841FCE819A007F0250 /* LEScanTest */,
6EF3551D1C965E8F00730BAB /* GATTServerTest */,
6EA37EF01C84B4EA00A61969 /* L2CAPServerTest */,
Expand Down Expand Up @@ -166,6 +170,16 @@
path = ../Sources/iBeaconTest;
sourceTree = "<group>";
};
6E1DC1EF1FCFC1A800C8DE52 /* LECreateConnection */ = {
isa = PBXGroup;
children = (
6E1DC1F01FCFC1A800C8DE52 /* LECreateConnection.swift */,
6E1DC1F11FCFC1A800C8DE52 /* main.swift */,
);
name = LECreateConnection;
path = ../Sources/LECreateConnection;
sourceTree = "<group>";
};
6E6AD9841FCE819A007F0250 /* LEScanTest */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -405,6 +419,7 @@
6E894C001C83EA2000109F45 /* main.swift in Sources */,
6E196CC31C8659DA009FA9CF /* HCI.swift in Sources */,
6E196CC71C86A5EC009FA9CF /* BluetoothProtocol.swift in Sources */,
6E1DC1F21FCFC1A800C8DE52 /* LECreateConnection.swift in Sources */,
6E894BF41C83B51B00109F45 /* AddressType.swift in Sources */,
6E53E1791C8503CA00AC8FCA /* ATTConnection.swift in Sources */,
6EA37EF41C84B4EA00A61969 /* L2CAPServerTest.swift in Sources */,
Expand Down

0 comments on commit 427661a

Please sign in to comment.