nomunomu0504.blog

技術メモ / 車 / 音楽 / 雑記 / etc...

Swift4.2でBluetooth通信の簡単な実装

みなさまご無沙汰です。かれこれ前回のブログから2ヶ月近く経ってました...。

その間に、シリコンバレーに起業するための研修などいってたのですが、その記事はいつか書きます...。

今回はあるプロジェクトでiOSBluetooth周りを担当することになったので、その知見をまとめておきます。

通信関係は、バージョンが上がるたびに変わったりするので、過去の遺産になるのも早そうだけど....😇

環境情報

  • Xcode 10.1 (10B61)
  • Swift4.2

実装

とりあえず Bluetooth を使うには CoreBluetooth が必要になるので、importします

import CoreBluetooth

そのほかに継承するべきクラスとして、CBCentralManagerDelegate, CBPeripheralDelegate があるので、継承します。

ここで、すべてのファイルに全ての implementメソッドを書いてもいいのですが、チームでソース管理をしたりすると、何かと面倒なので、extension として分割することにしました。

ディレクトリ構成としては、以下の通りにしておきました。

ProjectDir/
┠ ViewController.swift
┠ BluetoothController.swift
┗ BluetoothExt/
 ┠ CBCentralManagerDelegate.swift
 ┗ CBPeripheralDelegate.swift

また、Bluetooth 関連のクラスは複数のクラスから呼び出されることが想定されます。その時に毎回インスタンスが生成されると、ちょっとややこしいのでBluetooth関連のクラスはシングルトンにして、生成は一回のみ、あとは初回生成されたインスタンスを使うことにします。

・ViewController.swift

import UIKit

class ViewController: UIViewController
{
    /**
     * Bluetooth制御クラスインスタンス
     **/
    var bluetoothController = BluetoothController.shared()
}

・BluetoothController.swift

import UIKit
import CoreBluetooth

class BluetoothController: UIViewController
{
    // シングルトンクラスを生成
    private static let sharedInstance : BluetoothController =
    {
        return BluetoothController()
    }()
    
    // Sharedインスタンスを返す
    class func shared() -> BluetoothController
    {
        return self.sharedInstance
    }
    
    /**
     * Bluetooth
     **/
    var centralManager       : CBCentralManager!  // Bluetooth_CentralManager
    var targetPeripheral     : CBPeripheral!      // 接続先のBluetooth情報を保持
    var targetService        : CBService!         // 対象BLE端末の接続サービスを保持
    var targetCharacteristic : CBCharacteristic!  // 対象のBLE端末のCharacteristicを保持
}

・ CBCentralManagerDelegate.swift

import UIKit
import CoreBluetooth

/**
 * Bluetooth制御に関するデリゲートをViewControllerに拡張
 */
extension BluetoothController : CBCentralManagerDelegate
{
    /**
     * CentralManagerのステートが更新された時に呼び出されるコールバック関数
     **/
    public func centralManagerDidUpdateState(_ central: CBCentralManager)
    {
        // セントラルの状態を取得
        switch central.state
        {
            case .poweredOff:   // Bluetooth is OFF.
                break
            case .poweredOn:    // Bluetooth is ON.
                // Peripheralが使用できるサービスを指定
                // Peripheral端末の検索を開始
                break
            case .resetting:    // Bluetooth is Resetting. Connection was momentarily lost.
                break
            case .unauthorized: // Not Authorized.
                break
            case .unsupported:  // Bluetooth is not Support.
                break
            case .unknown:      // Somethings Error.
                break
            default:
                break
        }
    }
    
    /**
     * PheripheralのScanが成功した時
     **/
    public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
    {
        // BLE端末の検索を止める
        self.centralManager.stopScan()
        
        // 接続先のBLE端末としてデータ保持
        self.targetPeripheral = peripheral
        
        // 接続開始
        self.centralManager.connect(self.targetPeripheral, options: nil)
    }
    
    /**
     * Pheripheralに接続した時
     **/
    public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
    {
        // 検索に関するメソッドデリゲートを自分自身にバインド
        self.targetPeripheral.delegate = self
        // 対象のBLE端末の提供しているサービスを検索
        self.targetPeripheral.discoverServices(nil)
    }
    
    /**
     * Pheripheralと接続が切れた時
     **/
    public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
    }
    
    /**
     * Pheripheralへの接続が失敗した時
     **/
    public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
    }
}

・ CBPeripheralDelegate.swift

import UIKit
import CoreBluetooth

/**
 * 接続先のBLE端末間通信制御デリゲートをViewControllerに拡張
 **/
extension BluetoothController : CBPeripheralDelegate
{
    /**
     * BLE端末が提供してるサービスの検索が終わった
     **/
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
        
        // 取得したサービスを一覧で表示
        for service in peripheral.services!
        {
            self.targetService = service
            
            // BLE端末検索に関するメソッドを自分自身にバインド
            self.targetPeripheral.delegate = self
            // 対象BLE端末のCharacteristicの検索
            self.targetPeripheral.discoverCharacteristics(nil, for: self.targetService)
        }
    }
    
    /**
     * 対象BLE端末のCharacteristicの検索
     **/
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
        
        for characteristic in service.characteristics!
        {
            // poproのCharacteristicCBUUIDと対象のCBUUIDが同じか
        }
        
        /***
          peripheralの情報(GATT情報)はiOS端末がキャッシュする
          新規情報を得るためにはSwiftから操作することはできない
          iOS端末のBluetoothスイッチをOn/Offするしか今の所方法はない
         ***/
    }
    
    
    /**
     * Characteristic読み込み時のコールバック関数
     **/
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
    }
    
    /**
     * BLE端末へのCharacteristic書き込みが完了した時に呼び出されるコールバック関数
     **/
    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?)
    {
        print(#function)
        if let _ = error
        {
            return
        }
    }
}

基本的にはこれだけでBluetooth通信を使えるようになりますが、自分で接続しようとしているBLE端末のUUIDなどを指定して検索しないと、特定の端末に接続することはできないので要注意です。

高専カンファレンス新春 in 大阪でもトップバッターだった話

またもや高専イベント

先週はブログにも書いた『高専キャリア』というイベントに行ってきましたが、今回は『高専カンファレンス』というイベントに参加して、登壇してきました!ってお話です。高専キャリアでもトップバッターを勤めたのにも関わらず、今回の高専カンファでもトップバッターでした。つまり『二度あることは三度ある』ってことですよね?()

高専カンファレンス

kosenconf.jp

高専カンファレンンスは各地方で行われていて、主催は『カンファレンスしたい!』っていう人たちで構成されています。高専カンファだから何か難しいことしないといけないってわけではなくて、サイト見てもらうとわかるように、軽いものから、マニアックなものまでいろいろあります。発表しなくても見にこれたりするので、ぜひ来てもらいたいです!!

カンファレンス参加者の感想ブログ

ymgn.hatenablog.com

rikitosama.hatenadiary.jp

登壇内容

量子コンピュータ』について『簡単にわかりやすく』解説しました(は?)
『簡単にわかりやすく』って思ったんですが、時間15分(延長込み)で60枚弱のスライドを解説するのは難しいようでした笑

発表資料

speakerdeck.com

簡単にプレゼンをまとめるとこんな感じ

発表中のTL

プレゼン開始頃

プレゼンの1/4通過頃

プレゼンの2/4通過頃

プレゼン3/4通過頃

プレゼン終わり頃

スライド解説(随時追加中)

しばしお待ちを...。

57 is なに?

『57』という数字は『グロタンディーク素数』と呼ばれ合成数であり、非素数です。実は57以外にも『51 87 91』があります。100以下の数値ではこの4つしか存在しません。

つまり、ぱっと見素数かもしれませんが、素数ではないのです...。

参考にした文献等

== 書籍 ==

量子アルゴリズム[本/雑誌] / 中山茂/著

価格:5,832円
(2019/1/13 00:27時点)

量子計算理論 量子コンピュータの原理 [ 森前 智行 ]

価格:3,888円
(2019/1/13 00:28時点)

== 論文等 ==

すべて英論です...。

https://homepages.cwi.nl/~rdewolf/qcnotes.pdf

https://homes.cs.washington.edu/~oskin/quantum-notes.pdf ← わかりやすくておすすめ

第2回高専キャリア全国大会でトップバッターしてきた話

はじめに

1月5日(土)に東京・六本木にある「六本木ヒルズ クロスポイント」で「高専キャリア全国大会」に参加してきました! and 登壇してきたよ(トップバッターで)って話をします。

高専キャリア全国大会

kosen-zenkokutaikai.strikingly.com

今回で2回目になるイベントですがサブタイが『〜ご注文は進捗ですか?〜』となっていて、なんとも上澄み(湯葉)が集まりそうなイベントです(湯葉理論だ!!)

主催・運営の『高専キャリア』については本家サイトをぜひご覧ください!

kosen-career.tech

ようは、『高専卒業生の高専卒業生による現・高専生のための団体』ってことです。最高です。

イベント当日

会場は『六本木ヒルズ クロスポイント』のワンフロア。さすが東京。

f:id:nomunomu0504:20190106172617j:plain

プレゼン前にいくつかイベントがありましたが、詳しい内容と『ある事件』については、本イベント主催者の『開催レポート』のブログを貼って省略しますw

ryu-kan.hatenablog.com

高専生の代名詞といえば....。そう『魔剤』。ということで...。

f:id:nomunomu0504:20190106172530j:plain

必ずと言っていいほど用意されている『魔剤』。これも最高。

発表中のTwitterエゴサ

今回のイベントのTweetハッシュタグ『#高専キャリア』で検索してみてください。ものすごい量ですが....。

twitter.com

f:id:nomunomu0504:20190106205244p:plain

同じハッシュタグをいいね、RTしまくって、イベント中に垢ロックくらいました。(通称:ヤマゲン効果)

その『ヤマゲン』が書いたブログはこちら(← 半角カタカナなの重要!!) ymgn.hatenablog.com

発表した内容

今回発表した内容はこちらです

speakerdeck.com

その補助資料はこちら

speakerdeck.com

・学生団体withについて with-sabae.com

鯖江地域活性化プランコンテスト sabae-plancontest.jp

懇親会

高専生、高専OB/OG、高専中退して企業した人などいろいろな人と話す機会がありました。その中でも『高専に全く関係ない』しおみさんがスゴイ笑

高専卒でもなく、普通高校卒なのにも関わらず高専(変人たち)の集いに参加してくるのがすごい笑笑

FSC(ファイヤーサイドチャット)はとても盛り上がってました。事件もありましたが笑

f:id:nomunomu0504:20190106204415j:plain

Microsoft Imagine Cup の日本代表 & 世界2位という、つよつよのおーちょさんも最高でした!!ドタバタしてたようですね笑

さいごに

このイベントを開いてくれた関係者のみなさん!おつかれさまでした!そしてありがとうございます!!

りゅーかんさん曰く、『今年はあと3回ぐらいは開きます!!』って断言していたので、もれなく参加させてもらいます!!

また会える日まで!(いや、参加者の6~7割は来週の 新春高専カンファ in 大阪 で再開するんだけどね笑)

f:id:nomunomu0504:20190106172726j:plain

※ 集合写真でセンターにいるけど、特になにもしてません笑笑