Gormsson

Harald "Bluetooth" Gormsson was a king of Denmark and Norway.

Requirements

  • iOS 9.1+
  • Xcode 10.2+

Installation

use CocoaPods with Podfile

pod 'Gormsson'

open your favorite terminal, go to your project root path:

pod install

use Carthage with Cartfile

github "MoveUpwards/Gormsson"

open your favorite terminal, go to your project root path and run:

carthage update

Usage

HeartRateDemo

Start the service

Gormsson init method let you define a specific queue to avoid being on Main thread. You can also give an optional Dictionary for the CoreBluetooth manager.

let manager = Gormsson(queue: DispatchQueue(label: "com.ble.manager", attributes: .concurrent))

Start scan for peripherals

Every peripheral scanned around are return in the didDiscover block along with the advertisement data. Check the documentation to see all GattAdvertisement properties available.

In the below example, we filter peripheral that provide the HeartRate service.

manager.scan([.heartRate], didDiscover: { [weak self] cbPeripheral, advertisementData in
    print(cbPeripheral)
    print(advertisementData.localName)
    print(advertisementData.txPowerLevel)
    print(advertisementData.isConnectable)
})

You can custom's advertisement datas variables. See Custom advertisement data.

Connect peripheral

When you connect a peripheral, the library automaticaly stop scan for near peripherals.

manager.connect(cbPeripheral)

Read characteristic

Let's say you want to read the Body Sensor Location provided by your favorite Heart Rate Monitor sensor, you simply ask the manager to read the .bodySensorLocation characteristic that will return a value type of BodySensorLocationEnum.

manager.read(.bodySensorLocation, success: { value in
    guard let location = value as? BodySensorLocationEnum else { return }

    print("\(location.description)")
}, error: { error in
    print(error ?? "Unknown error")
})

Subscribe characteristic updates

If you want to get the current Heart Rate and have all updated value, you use the Notify capability of the characteristic. To achieve this it's as simple as a simply read.

Now any time the value change, the block will be triggered.

manager.notify(.heartRateMeasurement, success: { value in
    guard let rate = (value as? HeartRateMeasurementType)?.heartRateValue else { return }

    print("\(rate)")
}, error: { error in
    print(error ?? "Unknown error")
})

Write characteristic

If you want to write value to a characteristic, it's pretty straight forward. You provide the characteristic to be used and the given value to write.

manager.write(.setState, value: UInt8(1), success: {
    print("set state success")
}, error: { error in
    print("set state failure:", error ?? "nil")
})

Custom service

In order to use custom service, you just need to create a custom GattService.

let gpsService = GattService.custom("C94E7734-F70C-4B96-BB48-F1E3CB95F79E")

So you can use this custom service to filter the scan peripheral.

manager.scan([gpsService], didDiscover: { [weak self] peripheral, advertisementData in

})

Custom characteristic

In order to use custom characteristic class that conforms to CharateristicProtocol.

public protocol CharacteristicProtocol {
    var service: GattService { get }
    var uuid: CBUUID { get }
    var format: DataInitializable.Type { get }
}

Here is an example of a custom characteristc that will provide the number of recorded GPS session.

public final class GPSSessionCount: CharacteristicProtocol {
    public var uuid: CBUUID {
        return CBUUID(string: "C94E0001-F70C-4B96-BB48-F1E3CB95F79E")
    }

    public var service: GattService {
        return gpsService
    }

    public var format: DataInitializable.Type {
        return UInt.self
    }
}

Then you can use it with read, notify or write BLE command.

manager.read(GPSSessionCount(), success: { value in
    print("GPSSessionCount read:", value as? UInt ?? "nil")
}, error: { error in
    print(error ?? "Unknown error")
})

Custom advertisement data

In case your BLE peripheral has custom manufacturer data, you can add extension to the GattAdvertisement class.

Let's say you have the peripheral MAC address provided in the manufacturer data.

extension GattAdvertisement {
    /// An object containing the manufacturer data of a peripheral.
    open var macAddress: String? {
        let gpsService = GattService.custom("C94E7734-F70C-4B96-BB48-F1E3CB95F79E")
        guard let data = serviceData?[gpsService.uuid] else { return nil }
        return [UInt8](data).map({ String(format: "%02hhx", $0).uppercased() })
            .reversed()
            .joined(separator: ":")
    }
}

GitHub