[CoreBluetooth] iOSでBLEを扱うための基礎

# はじめに
BLEに触れることがあったので、備忘録としてまとめておきます。
※私が理解できた範囲でまとめています。

ご覧になった方で、これ違うよ？っていうところがあればご指摘よろしくお願いいたします。

## 環境
iOS 13.3
xcode 11.5
swift 5.2.4

## そもそもBLEって？
正式名称を **Bluetooth Low Energy** と言い、低電力消費・低コスト化に特化した規格です。
それまでの規格(Bluetoothクラシック)とは変更点も多く、互換性がありません。
(しかし、BLEとBluetoothクラシックのデュアルモード技術もあるみたい？)

BLEには以下のような特徴があります。

#### 特徴
- 消費電力の低さ
- 低コスト
- 障害物に強い
- 通信速度が遅い(早くすることも可能だが消費電力の面を考えると速度を遅くするのが妥当)

## BLEに関する用語集
###セントラル
通信の制御を担う役割を果たす
例）iPhone、PCなど

###ペリフェラル
セントラルからの要求に応える形で通信を行うため通信制御機能は持たない<br>
例）Beacon

- サービス・・・ペリフェラル内に必ず存在し、機能単位を表す
- キャラクタリスティック・・・実際にやりとりするデータが含まれる
 
###アドバタイズ
ペリフェラルがセントラルに自身を認識させるために単方向通信（ブロードキャスト型通信）によって自分自身に関する情報を定期的に発信し続けること<br>

###RSSI(Received signal strength indication)
受信機入力に入る受信信号の強度を示す数値(相対値)

# BLEに接続する手順
おおよそ3つの手順で接続されます。

**1. ペリフェラルがアドバタイズを送信する**
**2. セントラルがアドバタイズを受け取り、接続要求を送信する**
**3. 接続完了**

手順としては、簡単に接続することができます。

# BLE機器に接続するための実装手順
### 1. フレームワークの導入
フレームワーク「CoreBluetooth」をインポートします。

```swift
import CoreBluetooth
```

### 2.必要変数の定義
そして、今回必要なインスタンス(メンバ)変数を定義します。

```swift
var centralManager: CBCentralManager!
var peripheral: CBPeripheral!
```

### 3. CBCentralManagerのインスタンス生成
今回メインで利用していくインスタンスを作成します。

```swift
self.centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
```

### 4. ペリフェラルスキャン開始
先ほど作成したインスタンスを利用し、ペリフェラルのスキャンを開始します。

```swift
self.centralManager.scanForPeripherals(withServices: nil, options: nil)
```

また、UUIDを指定すれば特定のペリフェラルのみに絞ってスキャンをすることもできます。

```swift
let services = [CBUUID(string: "○○○")]
self.centralManager.scanForPeripherals(withServices: services, options: nil)
```

### 5. ペリフェラル接続
4のペリフェラルのスキャンによりペリフェラルが発見されれば、以下のようなデリゲートメソッドも呼ばれます。
この関数内1行目で、発見されたペリフェラルに接続を行います。
また、そのペリフェラルに対してデリゲートを指定したいので、先ほど定義したインスタンス変数に代入しておきます。

```swift
func centralManager(_ central: CBCentralManager,
                    didDiscover peripheral: CBPeripheral,
                    advertisementData: [String: Any], rssi RSSI: NSNumber) {
    self.centralManager.connect(peripheral, options: nil)
    self.peripheral = peripheral
}
```

### 6. サービスの取得
5でペリフェラルと接続されれば、以下のようなデリゲートメソッドが呼ばれます。
この関数内1行目でデリゲートを指定します。
そして、関数内2行目でサービスの取得を行います。

```swift
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    self.peripheral.delegate = self
    self.peripheral.discoverServices(nil)
}
```

### 7.キャラクタリスティックの取得
6でサービスの取得が行われた場合、以下のようなデリゲートメソッドが呼ばれます。
関数内1行目でキャラクタリスティックの取得を行います。

```swift
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    self.peripheral.discoverCharacteristics(nil, for: (peripheral.services?.first)!)
}
```

# まとめ
今回は、「SwiftでBLEを扱う方法」について備忘録としてまとめました。
まだまだ、足りない部分や間違った部分、理解度不十分な部分があると思うので適宜修正を加えていきたいと思います。


# ソースコード全体

```swift
import UIKit
import CoreBluetooth

class ViewController: UIViewController{
    
    var centralManager: CBCentralManager!
    var peripheral: CBPeripheral!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
    }
    
    // ボタン押下でスキャン開始
    @IBAction func scanButton(_ sender: Any) {
        self.centralManager.scanForPeripherals(withServices: nil, options: nil)
    }
}

extension ViewController: CBCentralManagerDelegate {
    // BLEの状態を返す
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case CBManagerState.poweredOn:
            print("電源がONになっています。")
        case CBManagerState.poweredOff {
            print("電源がOFFになっています。")
        default:
            break
        }
    }
    
    // スキャン後に呼ばれる
    func centralManager(_ central: CBCentralManager,
                        didDiscover peripheral: CBPeripheral,
                        advertisementData: [String: Any], rssi RSSI: NSNumber) {
        self.centralManager.connect(peripheral, options: nil)
        self.peripheral = peripheral
        self.centralManager.stopScan()    //スキャン停止
    }
    
    // 接続時に呼ばれる
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        self.peripheral.delegate = self
        self.peripheral.discoverServices(nil)
    }
}

extension ViewController: CBPeripheralDelegate {
    // サービスの取得時に呼ばれる
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        self.peripheral.discoverCharacteristics(nil, for: (peripheral.services?.first)!)
    }
    
    // キャラクタリスティック取得時に呼ばれる
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    }
}
```

# 参考
・[はじめてのBLE/丸文株式会社](https://www.marubun.co.jp/service/technicalsquare/a7ijkd000000brgj.html)
・[iOS SwiftでBLEのサンプルを動かしてみる](https://qiita.com/eKushida/items/def628e0eff6c106d467)