Skip to content

Commit

Permalink
Merge pull request #8 from jmarkstar/master
Browse files Browse the repository at this point in the history
#5 Read and Write local name HCI Commands
  • Loading branch information
colemancda authored Mar 24, 2018
2 parents 8628742 + 8408a59 commit e305dcb
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Sources/HostControllerBasebandCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,14 @@ public enum HostControllerBasebandCommand: UInt16, HCICommand {
If there is a contradiction between event filters, the latest set event filter will override older ones. An example is an incoming connection attempt where more than one Connection Setup filter matches the incoming connection attempt, but the Auto-Accept_Flag has different values in the different filters.
*/
case setEventFilter = 0x0005

/**
The Write_Local_Name command provides the ability to modify the user- friendly name for the BR/EDR Controller.
*/
case writeLocalName = 0x0013

/**
The Read_Local_Name command provides the ability to read the stored user- friendly name for the BR/EDR Controller.
*/
case readLocalName = 0x0014
}
62 changes: 62 additions & 0 deletions Sources/HostControllerBasebandCommandParameter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,66 @@ public extension HostControllerBasebandCommand {
case address
}
}

/**
The Write Local Name command provides the ability to modify the user-friendly name for the BR/EDR Controller.
*/
public struct WriteLocalNameParameter: HCICommandParameter {

public static let command = HostControllerBasebandCommand.writeLocalName

public static let length = 248

public let localName: String

public init?(localName: String) {

guard localName.utf8.count <= type(of: self).length
else { return nil }

self.localName = localName
}

public var byteValue: [UInt8] {

let maxLength = type(of: self).length

var bytes = [UInt8](localName.utf8)

assert(bytes.count <= maxLength)

if bytes.count < type(of: self).length {

bytes += [UInt8](repeating: 0x00, count: maxLength - bytes.count)
}

return bytes
}
}
}

// MARK: - Command Return Parameters

public extension HostControllerBasebandCommand {

/// LE Read Local name param
///
/// The command is used to read the total number of white list entries that can be stored in the Controller.
public struct ReadLocalNameReturnParameter: HCICommandReturnParameter {

public static let command = HostControllerBasebandCommand.readLocalName
public static let length = 248

public let localName: String

public init?(byteValue: [UInt8]) {

var data = unsafeBitCast(byteValue, to: [Int8].self)

guard let localName = String(validatingUTF8: &data)
else { return nil }

self.localName = localName
}
}
}
91 changes: 90 additions & 1 deletion Tests/BluetoothTests/HCITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,96 @@ final class HCITests: XCTestCase {
static let allTests = [
("testAdvertisingReport", testAdvertisingReport),
("testCommandStatusEvent", testCommandStatusEvent),
("testLEConnection", testLEConnection)
("testLEConnection", testLEConnection),
("testWriteLocalName", testWriteLocalName)
]

func testReadLocalName() {

typealias ReadLocalNameReturnParameter = HostControllerBasebandCommand.ReadLocalNameReturnParameter

do{
let data: [UInt8] = [/*0x0E, 0xFC, 0x01, 0x14, 0x0C, 0x00,*/ 0x41, 0x6C, 0x73, 0x65, 0x79, 0xE2, 0x80, 0x99, 0x73, 0x20, 0x4D, 0x61, 0x63, 0x42, 0x6F, 0x6F, 0x6B, 0x20, 0x50, 0x72, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

guard let readLocalNameParameter = ReadLocalNameReturnParameter(byteValue: data)
else { XCTFail("Bytes couldn't convert to String"); return }

let dataString = "Alsey’s MacBook Pro"

XCTAssert(readLocalNameParameter.localName == dataString, "Strings are not equal\n\(readLocalNameParameter.localName)\n\(dataString)")
}
}

func testWriteLocalName() {

typealias WriteLocalNameParameter = HostControllerBasebandCommand.WriteLocalNameParameter

XCTAssert((WriteLocalNameParameter(localName: "")?.byteValue ?? []) == [UInt8].init(repeating: 0x00, count: WriteLocalNameParameter.length))

// test local name lenght == 248
do {
let localNameParameter = String(repeating: "M", count: WriteLocalNameParameter.length) //248

guard let writeLocalNameParameter = WriteLocalNameParameter(localName: localNameParameter)
else { XCTFail(); return }

XCTAssert(writeLocalNameParameter.byteValue.isEmpty == false)
XCTAssert(writeLocalNameParameter.byteValue.count == WriteLocalNameParameter.length)
}

// test local name shorter than 248 octets
do{

let localName = String(repeating: "M", count: 10)

let data: [UInt8] = [UInt8](localName.utf8) + [UInt8](repeating: 0x00, count: WriteLocalNameParameter.length - 10)

guard let writeLocalNameParameter = WriteLocalNameParameter(localName: localName)
else { XCTFail(); return }

XCTAssert(writeLocalNameParameter.byteValue == data)
}

// test local name longer than 248
do {
let localNameParameter = String(repeating: "M", count: 260)

let writeLocalNameParameter = WriteLocalNameParameter(localName: localNameParameter)

XCTAssert(writeLocalNameParameter == nil, "WriteLocalNameParameter was created with local name longer than 248")
}

// compare byte localname
do {

let localName = String(repeating: "M", count: 248)

guard let writeLocalNameParameter = WriteLocalNameParameter(localName: localName)
else { XCTFail(); return }

XCTAssert(writeLocalNameParameter.localName == localName)
XCTAssert(writeLocalNameParameter.byteValue.isEmpty == false)

let data = [UInt8](repeating: 77, count: 248)

XCTAssert(writeLocalNameParameter.byteValue == data, "Local Name is not generating correct bytes")
}

do {
let localName = "Test"

guard let writeLocalNameParameter = WriteLocalNameParameter(localName: localName)
else { XCTFail(); return }

XCTAssert(writeLocalNameParameter.localName == localName)
XCTAssert(writeLocalNameParameter.byteValue.isEmpty == false)

let data: [UInt8] = [/* 0x13, 0x0C, 0xF8, */ 0x54, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

XCTAssert(writeLocalNameParameter.byteValue == data, "\(WriteLocalNameParameter.self) is not generating correct bytes")
}
}

func testAdvertisingReport() {

func parseAdvertisingReport(_ readBytes: Int, _ data: [UInt8]) -> [Address] {
Expand Down Expand Up @@ -129,6 +216,8 @@ final class HCITests: XCTestCase {
print("Connection handle: ", event.handle)
}
}


}

@inline(__always)
Expand Down

0 comments on commit e305dcb

Please sign in to comment.