Upload
akihiro-uehara
View
173.544
Download
12
Embed Size (px)
DESCRIPTION
2013年3月22日に大垣市ドリームコアで開催したiOS開発者向けBluetooth Low Energyハンズオンの資料です。 BTLEデバイスと連携するアプリケーション開発、また企画立案に役立つ開発情報を盛り込みました。 実際に動くコードを使って、CoreBluetoothフレームワークおよびBTLEのプロトコルスタック(GATT,ATT)を詳しく、掘り下げています。
Citation preview
Bluetooth LE体験講座
ドリームコア 1F モバイル・コア3月22日
(合)わふう 上原 昭宏
13年3月25日月曜日
目次
• Bluetooth Low Energyって?
• キーホルダーをいじってみる
• iOSらしいBluetooth LEの使い方?
13年3月25日月曜日
Bluetooth Low Energyとは
13年3月25日月曜日
Bluetooth Low Energyとは
• 超低消費電力無線通信• コイン電池(CR2032、直径2cm、3.2mm厚)で1~2年の無線通信
13年3月25日月曜日
Bluetooth Low Energyとは
• 超低消費電力無線通信• コイン電池(CR2032、直径2cm、3.2mm厚)で1~2年の無線通信
• Bluetooth4で統合
• Bluetooth4 = Bluetooth3 + Low Energy (BTLE)
• 2.4GHz(2400~2480MHz)。クラシックBTと異なる変調方式、チャネル。
13年3月25日月曜日
Bluetooth Low Energyとは
• 超低消費電力無線通信• コイン電池(CR2032、直径2cm、3.2mm厚)で1~2年の無線通信
• Bluetooth4で統合
• Bluetooth4 = Bluetooth3 + Low Energy (BTLE)
• 2.4GHz(2400~2480MHz)。クラシックBTと異なる変調方式、チャネル。
• 少量データ、低頻度• 例:<20バイト、秒に1回。フィットネス、医療
13年3月25日月曜日
BTLEの使いどころ
13年3月25日月曜日
BTLEの使いどころ
13年3月25日月曜日
BTLEの使いどころ
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
• Appcessory
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット• ぶっちゃけ
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット• ぶっちゃけ• ハードメーカがスマフォで売れるぜは死亡フラグ
13年3月25日月曜日
BTLEの使いどころ• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット• ぶっちゃけ• ハードメーカがスマフォで売れるぜは死亡フラグ
• 異世界にようこそ
13年3月25日月曜日
iOSとBTLE• iOSデバイスのBluetooth4対応• iPhone4S (2011年10月発売) 以降のApple社製品 、iOS5 / iOS6
• BTLE対応アプリのストア承認• Made for iPhone(MFi) NDA締結不要 (ロゴ掲載には必要)
• ハードウェアの提出は求められるかも
• 開発環境• CoreBluetoothフレームワーク (一般開発者が使える)
• 従来BT
• MFi必須。
13年3月25日月曜日
実際に動かしてみる
13年3月25日月曜日
デバイスの確認
• iOS5/6の iPhone4S以降のiOSデバイス
• BTLE キーホルダ(BSHSBTPT01BK)
• Xcode 4.5.1以上
13年3月25日月曜日
サンプルコードを開く
• ソースコード• https://github.com/reinforce-lab/CoreBluetooth_samples
• プロジェクト first_sample/KeyFobSample.xcodeproj
13年3月25日月曜日
keyfobと接続• デバイス一覧• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
keyfobと接続• デバイス一覧• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
keyfobと接続• デバイス一覧• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
BTLEデバイスとの通信手順
• デバイスの発見
• 接続
• 読み書き
• 切断
13年3月25日月曜日
コードを読んでみる
13年3月25日月曜日
フレームワークの追加
13年3月25日月曜日
フレームワークの追加
13年3月25日月曜日
フレームワークの追加
13年3月25日月曜日
フレームワークの追加
#import "KeyFobController.h"#import <CoreBluetooth/CoreBluetooth.h>
@interface KeyFobController() <CBCentralManagerDelegate, CBPeripheralDelegate> { CBCentralManager *_centralManager;
13年3月25日月曜日
フレームワークの追加
• CoreBluetooth.frameworkを追加
• #import <CoreBluetooth/CoreBluetooth.h>
• CBCentralManagerDelegate, CBPeripheralDelegate を実装
#import "KeyFobController.h"#import <CoreBluetooth/CoreBluetooth.h>
@interface KeyFobController() <CBCentralManagerDelegate, CBPeripheralDelegate> { CBCentralManager *_centralManager;
13年3月25日月曜日
デバイスの発見
13年3月25日月曜日
ネットワーク・トポロジ• スター型• 接続数の上限がない• クラシックBTは7
• 役割が非対称• ペリフェラルがより低消費電力
セントラル(Central)
ペリフェラル(Peripheral)
13年3月25日月曜日
データモデル
セントラル(Central)
ペリフェラル(Peripheral)
CBCentralManager
CBPeripheral
13年3月25日月曜日
ペリフェラル・デバイスの発見
• アドバタイズメント
• パケットを送信
• 20ミリ秒~1.3秒周期
• デバイス名などの情報
Ad
Ad
Ad
Ad
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
-(void)startScanning { // BLEデバイスのスキャン時には、検索対象とするサービスを指定することが推奨です NSArray *scanServices = [NSArray arrayWithObjects:_linkLossServiceUUID, _immediateAlertServiceUUID, nil]; // スキャンにはオプションが指定できます。 // いまあるオプションは、ペリフェラルを見つけた時に重複して通知するか、の指定です。 // 近接検出など、コネクションレスでデバイスの状態を取得する用途などでは、これをYESに設定します。 // デフォルトでNOです。 NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey]; // デバイスのスキャン開始。iPhoneはアドバタイズメント・パケットの受信を開始します。 // このスキャンは、明示的に停止しない限り、スキャンし続けます。このスキャンは、アドバタイズメント・パケットの(2.4GHzの)受信処理で、RF回路は電力を消費します。 [_centralManager scanForPeripheralsWithServices:scanServices options:scanOptions];}
13年3月25日月曜日
-(void)startScanning { // BLEデバイスのスキャン時には、検索対象とするサービスを指定することが推奨です NSArray *scanServices = [NSArray arrayWithObjects:_linkLossServiceUUID, _immediateAlertServiceUUID, nil]; // スキャンにはオプションが指定できます。 // いまあるオプションは、ペリフェラルを見つけた時に重複して通知するか、の指定です。 // 近接検出など、コネクションレスでデバイスの状態を取得する用途などでは、これをYESに設定します。 // デフォルトでNOです。 NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey]; // デバイスのスキャン開始。iPhoneはアドバタイズメント・パケットの受信を開始します。 // このスキャンは、明示的に停止しない限り、スキャンし続けます。このスキャンは、アドバタイズメント・パケットの(2.4GHzの)受信処理で、RF回路は電力を消費します。 [_centralManager scanForPeripheralsWithServices:scanServices options:scanOptions];}
13年3月25日月曜日
-(void)startScanning { // BLEデバイスのスキャン時には、検索対象とするサービスを指定することが推奨です NSArray *scanServices = [NSArray arrayWithObjects:_linkLossServiceUUID, _immediateAlertServiceUUID, nil]; // スキャンにはオプションが指定できます。 // いまあるオプションは、ペリフェラルを見つけた時に重複して通知するか、の指定です。 // 近接検出など、コネクションレスでデバイスの状態を取得する用途などでは、これをYESに設定します。 // デフォルトでNOです。 NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey]; // デバイスのスキャン開始。iPhoneはアドバタイズメント・パケットの受信を開始します。 // このスキャンは、明示的に停止しない限り、スキャンし続けます。このスキャンは、アドバタイズメント・パケットの(2.4GHzの)受信処理で、RF回路は電力を消費します。 [_centralManager scanForPeripheralsWithServices:scanServices options:scanOptions];}
13年3月25日月曜日
-(void)startScanning { // BLEデバイスのスキャン時には、検索対象とするサービスを指定することが推奨です NSArray *scanServices = [NSArray arrayWithObjects:_linkLossServiceUUID, _immediateAlertServiceUUID, nil]; // スキャンにはオプションが指定できます。 // いまあるオプションは、ペリフェラルを見つけた時に重複して通知するか、の指定です。 // 近接検出など、コネクションレスでデバイスの状態を取得する用途などでは、これをYESに設定します。 // デフォルトでNOです。 NSDictionary *scanOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBCentralManagerScanOptionAllowDuplicatesKey]; // デバイスのスキャン開始。iPhoneはアドバタイズメント・パケットの受信を開始します。 // このスキャンは、明示的に停止しない限り、スキャンし続けます。このスキャンは、アドバタイズメント・パケットの(2.4GHzの)受信処理で、RF回路は電力を消費します。 [_centralManager scanForPeripheralsWithServices:scanServices options:scanOptions];}
13年3月25日月曜日
アドバタイズメントのフィルタ
• 重複を許すか• 通常はNO
• 近接ならYES
• ”受信したとき”に通知
• サービス(機能)でフィルタ
Ad
Ad
Ad
Ad
13年3月25日月曜日
// デバイスの発見時処理を行います。// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見するかもしれません。// アドバタイズメント・パケットに含まれる情報は、advertisementDataから得られます。デバイス名などで判別します。- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)p advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ // 同一機種が周囲に複数あるとき、自分がもっているものだけに接続するには、UUIDが同じかを判定します。 // !!注意!! iOS6では、一度も接続したことがない装置のUUIDはnilになります。一度でも接続すればUUIDが取れます。ここでは、一度は接続したことがある前提でUUIDを比較しています。 /* CBUUID *targetUUID = [CBUUID UUIDWithString:@"00000000-0000-0000-2F0C-F0289947EA35"]; if(peripheral.UUID == nil || ! [[CBUUID UUIDWithCFUUID:peripheral.UUID].data isEqualToData:targetUUID.data]) return; */ NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; if(localName != nil && [localName isEqualToString:kTargetDeviceName] ) { PeripheralContainer *c = [[PeripheralContainer alloc] init]; c.peripheral = p; c.RSSI = RSSI; [self findPeripheral:c]; }}
13年3月25日月曜日
// デバイスの発見時処理を行います。// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見するかもしれません。// アドバタイズメント・パケットに含まれる情報は、advertisementDataから得られます。デバイス名などで判別します。- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)p advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ // 同一機種が周囲に複数あるとき、自分がもっているものだけに接続するには、UUIDが同じかを判定します。 // !!注意!! iOS6では、一度も接続したことがない装置のUUIDはnilになります。一度でも接続すればUUIDが取れます。ここでは、一度は接続したことがある前提でUUIDを比較しています。 /* CBUUID *targetUUID = [CBUUID UUIDWithString:@"00000000-0000-0000-2F0C-F0289947EA35"]; if(peripheral.UUID == nil || ! [[CBUUID UUIDWithCFUUID:peripheral.UUID].data isEqualToData:targetUUID.data]) return; */ NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; if(localName != nil && [localName isEqualToString:kTargetDeviceName] ) { PeripheralContainer *c = [[PeripheralContainer alloc] init]; c.peripheral = p; c.RSSI = RSSI; [self findPeripheral:c]; }}
13年3月25日月曜日
// デバイスの発見時処理を行います。// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見するかもしれません。// アドバタイズメント・パケットに含まれる情報は、advertisementDataから得られます。デバイス名などで判別します。- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)p advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ // 同一機種が周囲に複数あるとき、自分がもっているものだけに接続するには、UUIDが同じかを判定します。 // !!注意!! iOS6では、一度も接続したことがない装置のUUIDはnilになります。一度でも接続すればUUIDが取れます。ここでは、一度は接続したことがある前提でUUIDを比較しています。 /* CBUUID *targetUUID = [CBUUID UUIDWithString:@"00000000-0000-0000-2F0C-F0289947EA35"]; if(peripheral.UUID == nil || ! [[CBUUID UUIDWithCFUUID:peripheral.UUID].data isEqualToData:targetUUID.data]) return; */ NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; if(localName != nil && [localName isEqualToString:kTargetDeviceName] ) { PeripheralContainer *c = [[PeripheralContainer alloc] init]; c.peripheral = p; c.RSSI = RSSI; [self findPeripheral:c]; }}
受信信号強度パケット・データ
13年3月25日月曜日
// デバイスの発見時処理を行います。// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見するかもしれません。// アドバタイズメント・パケットに含まれる情報は、advertisementDataから得られます。デバイス名などで判別します。- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)p advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{ // 同一機種が周囲に複数あるとき、自分がもっているものだけに接続するには、UUIDが同じかを判定します。 // !!注意!! iOS6では、一度も接続したことがない装置のUUIDはnilになります。一度でも接続すればUUIDが取れます。ここでは、一度は接続したことがある前提でUUIDを比較しています。 /* CBUUID *targetUUID = [CBUUID UUIDWithString:@"00000000-0000-0000-2F0C-F0289947EA35"]; if(peripheral.UUID == nil || ! [[CBUUID UUIDWithCFUUID:peripheral.UUID].data isEqualToData:targetUUID.data]) return; */ NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; if(localName != nil && [localName isEqualToString:kTargetDeviceName] ) { PeripheralContainer *c = [[PeripheralContainer alloc] init]; c.peripheral = p; c.RSSI = RSSI; [self findPeripheral:c]; }}
受信信号強度パケット・データ
13年3月25日月曜日
アドバタイズメントで取れる情報 (1/1)
• 名前、送信電力、その他• CBAdvertisementDataLocalNameKey
• CBAdvertisementDataTxPowerLevelKey
• CBAdvertisementDataManufacturerDataKey
• この3つの情報はキャッシュされない
• LocalName以外はペリフェラルの設計次第
• 周囲へ一斉通知(ブロードキャスト)
• 送信電力とRSSIから距離概算
13年3月25日月曜日
アドバタイズメントで取れる情報 (2/2)
• CBPeripheral インスタンス
• UUID : 128-bitの識別番号
• 一度でも接続したことがあれば≠nil
• RSSI : 受信信号強度
• 接続してreadRSSI:を呼び出せば≠nil
• 切断しても同じUUIDを見つけて再接続
• LocalNameに、識別番号や、状態を入れたり
13年3月25日月曜日
接続と切断
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
必ずretain
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
必ずretain
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
必ずretain
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
必ずretain
13年3月25日月曜日
-(void)connect:(PeripheralContainer *)c { //ターゲットを発見、接続します //この時点でperipheralはcentral managerに保持されていません。 //少なくとも接続が完了するまでの間、peripheralをアプリ側で保持します。 //接続処理はタイムアウトしません。接続に失敗すれば centralManager:didFailToConnectPeripheral:error: が呼ばれます。 //接続処理を中止するには、peripheralを開放するか、明示的に cancelPeripheralConnection を呼び出します。 self.peripheral = c.peripheral;
[_centralManager connectPeripheral:self.peripheral options:nil];}-(void)disconnect { // 切断処理をします。_peripheralをnilにするなどの、切断完了後処理は、 // centralManager:didDisconnectPeripheral:error: // で行います。 [_centralManager cancelPeripheralConnection:self.peripheral];}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p;
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
必ずretain
delegateで通知13年3月25日月曜日
サービスとキャラクタリスティクスそしてプロファイル
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
ペリフェラル=データベースハンドル,タイプ,値
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
サービス=クラスキャラクタリスティクス
=プロパティ13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
サービス=クラスキャラクタリスティクス
=プロパティ
13年3月25日月曜日
プロトコルスタックApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
サービス=クラスキャラクタリスティクス
=プロパティ
• キャラクタリスティクス• 制御/動作指定
• センサー値/外界の状態
• (装置の)動作状態/内部状態
13年3月25日月曜日
サービスとキャラクタリスティクスそしてプロファイル
13年3月25日月曜日
サービスと振る舞いの分離
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
Find MEProfile
ProximityProfile
デバイス発見
切断時の警告
13年3月25日月曜日
サービスと振る舞いの分離
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
ImmediateAlert Service
Tx Power Service
Link LossAlert Service
振動やブザーを出力
送信電力の値切断時の振る舞い指定
Find MEProfile
ProximityProfile
デバイス発見
切断時の警告
13年3月25日月曜日
サービスと振る舞いの分離
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
ImmediateAlert Service
Tx Power Service
Link LossAlert Service
振動やブザーを出力
送信電力の値切断時の振る舞い指定
Find MEProfile
ProximityProfile
デバイス発見
切断時の警告
13年3月25日月曜日
サービスと振る舞いの分離
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
ImmediateAlert Service
Tx Power Service
Link LossAlert Service
振動やブザーを出力
送信電力の値切断時の振る舞い指定
Find MEProfile
ProximityProfile
デバイス発見
切断時の警告
ユースケース ハード仕様
13年3月25日月曜日
プロファイルの実装ApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications • プロファイルがアプリ側
• 任意の振る舞い、OK
• すべてがアプリの管理下• 発見
• 接続/切断
• 読み書き
• iOSはいっさい関係してこない13年3月25日月曜日
プロファイルの実装ApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
• プロファイルがアプリ側
• 任意の振る舞い、OK
• すべてがアプリの管理下• 発見
• 接続/切断
• 読み書き
• iOSはいっさい関係してこない13年3月25日月曜日
プロファイルの実装ApplicationsCore Bluetooth
GATT
ATT
L2CAP
PHY
Link Layer
ApplicationsApplications
XPC
BTserver
• プロファイルがアプリ側
• 任意の振る舞い、OK
• すべてがアプリの管理下• 発見
• 接続/切断
• 読み書き
• iOSはいっさい関係してこない13年3月25日月曜日
サービスとキャラクタリスティクスを見てみる
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
• UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)13年3月25日月曜日
サービスとキャラクタリスティクスのリスティング
13年3月25日月曜日
// 接続- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p { // サービスを探します self.peripheral.delegate = self; [p discoverServices:[NSArray arrayWithObjects: _linkLossServiceUUID, _immediateAlertServiceUUID, _txPowerServiceUUID, _batteryLevelServiceUUID, nil]];}
#define kImmediateAlertServiceUUID @"1802"#define kLinkLossServiceUUID @"1803"#define kAlertLevelUUID @"2A06"... _linkLossServiceUUID = [CBUUID UUIDWithString:kLinkLossServiceUUID]; _immediateAlertServiceUUID = [CBUUID UUIDWithString:kImmediateAlertServiceUUID]; _alertLevelUUID = [CBUUID UUIDWithString:kAlertLevelUUID];
13年3月25日月曜日
// 接続- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p { // サービスを探します self.peripheral.delegate = self; [p discoverServices:[NSArray arrayWithObjects: _linkLossServiceUUID, _immediateAlertServiceUUID, _txPowerServiceUUID, _batteryLevelServiceUUID, nil]];}
#define kImmediateAlertServiceUUID @"1802"#define kLinkLossServiceUUID @"1803"#define kAlertLevelUUID @"2A06"... _linkLossServiceUUID = [CBUUID UUIDWithString:kLinkLossServiceUUID]; _immediateAlertServiceUUID = [CBUUID UUIDWithString:kImmediateAlertServiceUUID]; _alertLevelUUID = [CBUUID UUIDWithString:kAlertLevelUUID];
13年3月25日月曜日
//発見したサービスに対して、Characteristicsを探します- (void)peripheral:(CBPeripheral *)p didDiscoverServices:(NSError *)error { for (CBService *service in p.services) { if ([service.UUID.data isEqualToData:_linkLossServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } else if ([service.UUID.data isEqualToData:_immediateAlertServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } }}
- (void)peripheral:(CBPeripheral *)p didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ if ([service.UUID.data isEqualToData:_batteryLevelServiceUUID.data]) { _batteryLevelCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelUUID]; _batteryLevelSwitchCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelSwitchUUID]; [p setNotifyValue:YES forCharacteristic:_batteryLevelSwitchCharacteristics]; [p readValueForCharacteristic:_batteryLevelCharacteristics]; [p readValueForCharacteristic:_batteryLevelSwitchCharacteristics]; }}
13年3月25日月曜日
//発見したサービスに対して、Characteristicsを探します- (void)peripheral:(CBPeripheral *)p didDiscoverServices:(NSError *)error { for (CBService *service in p.services) { if ([service.UUID.data isEqualToData:_linkLossServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } else if ([service.UUID.data isEqualToData:_immediateAlertServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } }}
- (void)peripheral:(CBPeripheral *)p didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ if ([service.UUID.data isEqualToData:_batteryLevelServiceUUID.data]) { _batteryLevelCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelUUID]; _batteryLevelSwitchCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelSwitchUUID]; [p setNotifyValue:YES forCharacteristic:_batteryLevelSwitchCharacteristics]; [p readValueForCharacteristic:_batteryLevelCharacteristics]; [p readValueForCharacteristic:_batteryLevelSwitchCharacteristics]; }}
13年3月25日月曜日
//発見したサービスに対して、Characteristicsを探します- (void)peripheral:(CBPeripheral *)p didDiscoverServices:(NSError *)error { for (CBService *service in p.services) { if ([service.UUID.data isEqualToData:_linkLossServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } else if ([service.UUID.data isEqualToData:_immediateAlertServiceUUID.data]) { [p discoverCharacteristics:[NSArray arrayWithObjects: _alertLevelUUID, nil] forService:service]; } }}
- (void)peripheral:(CBPeripheral *)p didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ if ([service.UUID.data isEqualToData:_batteryLevelServiceUUID.data]) { _batteryLevelCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelUUID]; _batteryLevelSwitchCharacteristics = [self findCharacteristics:service.characteristics uuid:_batteryLevelSwitchUUID]; [p setNotifyValue:YES forCharacteristic:_batteryLevelSwitchCharacteristics]; [p readValueForCharacteristic:_batteryLevelCharacteristics]; [p readValueForCharacteristic:_batteryLevelSwitchCharacteristics]; }}
13年3月25日月曜日
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{ uint8_t b; if(characteristic == _txPowerCharacteristic) { [characteristic.value getBytes:&b length:1]; self.txPower = b;
LSB-first (Least Significant Byte First)
13年3月25日月曜日
まとめ• BTLE
• 超低消費電力、なんとなくつながる
• iOSとBTLE
• MFi不要、一般開発者権限
• 振るまいと機能の分離
• プロファイルはアプリ次第13年3月25日月曜日
開発体制
• ハード+プロファイル部分を担当すべし• 無線接続と振る舞い• デモアプリで動作確認、責任分界• ドキュメント、読める?• 納品後のトラブル (iOSの振舞い変化)
13年3月25日月曜日
参考
13年3月25日月曜日
情報源(1/3)
• https://developer.apple.com/videos/wwdc/2012/
• Session 703: Core Bluetooth 101
• Session 705 Advanced Core Bluetooth
• Apple Bluetooth Mailing list
• https://lists.apple.com/mailman/listinfo/bluetooth-dev
13年3月25日月曜日
情報源(2/3)• Texus Instruments社
• http://www.tij.co.jp/product/jp/cc2540
• http://processors.wiki.ti.com/index.php/Category:BluetoothLE?DCMP=blestack&HQS=ble-wiki
• Nordic Semiconductor社
• https://www.nordicsemi.com
• BlueGiga
• http://www.bluegiga.com
13年3月25日月曜日
情報源(3/3)
• AppleのBluetoothアクセサリ設計指針 (おすすめ)
• Bluetooth Low Energy Handbook (おすすめ)
• Bluetooth4 Core Specificaiton (辞書的に)
13年3月25日月曜日
ぶっちゃけ
13年3月25日月曜日
• CoreBluetoothを使う必要あるの?• API公開(Wahoo、NODE、konashi...)
• ハード販売、サービス展開• 自分で開発展開• ハードウェア開発?• 半導体/モジュール (組込開発)
• iOSでペリフェラル開発 (iOS6から)
13年3月25日月曜日
オリジナル開発
• 半導体買ってきて回路を作ると• BT認証 1万ドル、電波法 40万円(実費)。
• 1万台以上作るなら
• モジュール• 日本の認証OKなのが4月から続々。
• BlueGiga、おすすめ
• BASICみたいなスクリプト開発。
• 冗談みたいなお手軽さ。
13年3月25日月曜日
• ペリフェラルの設計• http://e2e.ti.com/support/low_power_rf/f/538/t/225290.aspx
• リファレンス設計/コード
• 必要な場面• 制御が入るとか、応答速度が必要とか• RFチップ+外付けマイコン
• RFチップ+RFチップ内蔵マイコン• 開発環境 TI社 8051互換 ~40万円、Nordic Semi.社 Cortex-M0 ~20万円 (32kBまで無償
版あり)
13年3月25日月曜日
こまったときの
• 何が何やら、わけがわかんないよ• 通信の把握が勝利の鍵• TI社のCC2540開発キットでパケットスニファ
• iOS6.0で、切断時にiOSが1分ほど接続保持ー>アドバタイズ出ない
13年3月25日月曜日
今時のBTLE
• BTLEデバイス、Over-the-airでファーム更新
• Kickstarterむっちゃでてる
• 10万台の呪い。日本、しんでる
• 覚えていますか♫
• 記憶にすら残らない、NECカシオのMEDIASとリモッピとG-SHOCK。まじ、ショック
13年3月25日月曜日
他のプラットホーム
• Android
• チップメーカ独自スタック、公式BTLE対応なし
• できることはiOSと同じ。GATTを叩ける。
• BT3/4混在、Android4。
• ねらってもできない統一性のなさ• 5月のGoogle IO、ドコモの健康なんとか?
• Windows Phone8
• 公式スタックなし、BT3が最新機種
• Windows8
• ハード認定要件にBT4、スタック公式サポート
• C+でドライバ13年3月25日月曜日
あどばんす
13年3月25日月曜日
• アプリ
• バックグラウンド
• CBPeripheralManager
• ハード開発
• 情報源
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
Central
Peripheral
Centralclient
Peripheralserver
13年3月25日月曜日
• サンプルファイル
• ペリフェラル(デバイス)
•
13年3月25日月曜日
CentralPeripheral
CBCentralManager
CBPeripheral
CBPeripheralManager
CBCentral
13年3月25日月曜日
CBCentralManager
CBPeripheral
CBPeripheralManager
CBCentral
iOS5 iOS6
CBService
CBCharacteristics
CBMutableService
CBMutableCharacteri
Data Objects
Main Objects
13年3月25日月曜日
CentralPeripheral
Ad
Ad
Ad
13年3月25日月曜日
discover and connect
CBCentralManager Periphearl device
scanForPeripheralsWithServices
didDiscoverPeripheral
stopScan
connectPeripheral
didConnectPeripheral
13年3月25日月曜日
Central Peripheral
Service
Characteristic
Characteristic
CBService
CBCharacteristic
13年3月25日月曜日
CBPeripheral CBPeripheralDelegate
discoverServicesdidDiscoverServices
discoverCharacteristics:forServicedidDiscoverCharacteristicsForSer
vice
13年3月25日月曜日
CBPeripheral CBPeripheralDelegate
readValueForCharacteristicdidUpdateValueForCharacteristics
setNotifyValue:forCharacteristic
didUpdateValueForCharacteristics
13年3月25日月曜日
• Scan and Connect
• Reconnecting using UUID
• Already connected?
•
13年3月25日月曜日
discover and connect
CBCentralManager Periphearl device
retrievePeripherals
didRetrievePeripherals
connectPeripheral
didConnectPeripheral
13年3月25日月曜日
iOS background
• Background app
• Scan and advertise
• Connect
• Interact
• “Start and stop”concept
• Info.plist
13年3月25日月曜日
• Foreground app
• High-intensity scanning
• Bacground app/screen off
• Low-intensity scanning
•
13年3月25日月曜日
• Ad
• Name
• Tx Power
• Service UUID
• Service Data
• Max: 31 bytes
13年3月25日月曜日
• 16-bit UUID
• assigned by Bluetooth SIG
• http://develper/bluetooth.org
• 128-bit UUID
• assigned by you!
• コマンドライン uuidgen
13年3月25日月曜日
• Centralがキャッシュするもの
• 発見したServiceとCharacteristics
• Valueはキャッシュされない
•
13年3月25日月曜日
ペアリング• ペアリング
• 接続する、認証されてないー>拒否
• Insufficient Authentication
• ペアリング、暗号化
• AES-128、公開鍵
13年3月25日月曜日
BTLE available?
• CBCentralManager
• delegate CBCentralManagerDelegate
• state CBCentralManagerState
• unknown -> 遷移
• 使う前にチェック
13年3月25日月曜日
13年3月25日月曜日
Bluetooth Smart ready と ready
• 2種類の周辺機器• デュアル・モード = クラシックBT + LE 両方搭載
• シングル・モード = LEのみ
• 接続問題• シングル・モード デバイスはクラシックBTとつながらない
• SMART READY (デュアル) / SMART (シングル) ロゴ
http://www.bluetooth.com/Pages/Smart-Logos.aspx13年3月25日月曜日
ちょっと規格の話
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日
13年3月25日月曜日