Weitere ähnliche Inhalte Mehr von akihiro uehara (20) Kürzlich hochgeladen (11) iOSアプリ開発者のための Bluetooth Low Energy体験講座1. Bluetooth LE
体験講座
ドリームコア 1F モバイル・コア
3月22日
(合)わふう 上原 昭宏
13年3月25日月曜日
2. 目次
• Bluetooth Low Energyって?
• キーホルダーをいじってみる
• iOSらしいBluetooth LEの使い方?
13年3月25日月曜日
5. Bluetooth Low Energyとは
• 超低消費電力無線通信
• コイン電池(CR2032、直径2cm、3.2mm厚)で1~2年の無線通信
• Bluetooth4で統合
• Bluetooth4 = Bluetooth3 + Low Energy (BTLE)
• 2.4GHz(2400~2480MHz)。クラシックBTと異なる変調方式、チャネル。
13年3月25日月曜日
6. 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日月曜日
11. BTLEの使いどころ
• 運動、健康、近接...
• Appcessory
13年3月25日月曜日
12. BTLEの使いどころ
• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット
13年3月25日月曜日
13. BTLEの使いどころ
• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット
• ぶっちゃけ
13年3月25日月曜日
14. BTLEの使いどころ
• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット
• ぶっちゃけ
• ハードメーカがスマフォで
売れるぜは死亡フラグ
13年3月25日月曜日
15. BTLEの使いどころ
• 運動、健康、近接...
• Appcessory
• ハード、スマフォ、ネット
• ぶっちゃけ
• ハードメーカがスマフォで
売れるぜは死亡フラグ
• 異世界にようこそ
13年3月25日月曜日
16. iOSとBTLE
• iOSデバイスのBluetooth4対応
• iPhone4S (2011年10月発売) 以降のApple社製品 、iOS5 / iOS6
• BTLE対応アプリのストア承認
• Made for iPhone(MFi) NDA締結不要 (ロゴ掲載には必要)
• ハードウェアの提出は求められるかも
• 開発環境
• CoreBluetoothフレームワーク (一般開発者が使える)
• 従来BT
• MFi必須。
13年3月25日月曜日
18. デバイスの確認
• iOS5/6の iPhone4S以降のiOSデバイス
• BTLE キーホルダ(BSHSBTPT01BK)
• Xcode 4.5.1以上
13年3月25日月曜日
19. サンプルコードを開く
• ソースコード
• https://github.com/reinforce-lab/CoreBluetooth_samples
• プロジェクト first_sample/KeyFobSample.xcodeproj
13年3月25日月曜日
20. keyfobと接続
• デバイス一覧
• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
21. keyfobと接続
• デバイス一覧
• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
22. keyfobと接続
• デバイス一覧
• RSSIが一番大きい(マイナスの数字が小さい)
行を選択
• Immediate alert
• Buzzerを押す
13年3月25日月曜日
28. フレームワークの追加
#import "KeyFobController.h"
#import <CoreBluetooth/CoreBluetooth.h>
@interface KeyFobController()
<CBCentralManagerDelegate, CBPeripheralDelegate> {
CBCentralManager *_centralManager;
13年3月25日月曜日
29. フレームワークの追加
#import "KeyFobController.h"
#import <CoreBluetooth/CoreBluetooth.h>
@interface KeyFobController()
<CBCentralManagerDelegate, CBPeripheralDelegate> {
CBCentralManager *_centralManager;
• CoreBluetooth.frameworkを追加
• #import <CoreBluetooth/CoreBluetooth.h>
• CBCentralManagerDelegate,
CBPeripheralDelegate を実装
13年3月25日月曜日
31. ネットワーク・トポロジ
• スター型
• 接続数の上限がない
• クラシックBTは7
• 役割が非対称
セントラル • ペリフェラルがより低消
(Central) 費電力
ペリフェラル
(Peripheral)
13年3月25日月曜日
32. データモデル
セントラル ペリフェラル
(Central) (Peripheral)
CBCentralManager
CBPeripheral
13年3月25日月曜日
33. ペリフェラル・デバイスの発見
• アドバタイズメント
Ad • パケットを送信
Ad • 20ミリ秒~1.3秒周期
Ad
• デバイス名などの情報
Ad
13年3月25日月曜日
37. -(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日月曜日
38. -(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日月曜日
39. -(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日月曜日
40. -(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日月曜日
41. アドバタイズメントのフィルタ
• 重複を許すか
Ad • 通常はNO
Ad
• 近接ならYES
Ad • ”受信したとき”に通知
• サービス(機能)でフィルタ
Ad
13年3月25日月曜日
42. // デバイスの発見時処理を行います。
// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見す
るかもしれません。
// アドバタイズメント・パケットに含まれる情報は、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日月曜日
43. // デバイスの発見時処理を行います。
// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見す
るかもしれません。
// アドバタイズメント・パケットに含まれる情報は、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日月曜日
44. // デバイスの発見時処理を行います。
// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見す
るかもしれません。
// アドバタイズメント・パケットに含まれる情報は、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日月曜日
45. // デバイスの発見時処理を行います。
// スキャンで指定したサービスがあるデバイスのみが通知されますが、同じような機能を持った対象外の装置を発見す
るかもしれません。
// アドバタイズメント・パケットに含まれる情報は、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日月曜日
46. アドバタイズメントで取れる情報 (1/1)
• 名前、送信電力、その他
• CBAdvertisementDataLocalNameKey
• CBAdvertisementDataTxPowerLevelKey
• CBAdvertisementDataManufacturerDataKey
• この3つの情報はキャッシュされない
• LocalName以外はペリフェラルの設計次第
• 周囲へ一斉通知(ブロードキャスト)
• 送信電力とRSSIから距離概算
13年3月25日月曜日
47. アドバタイズメントで取れる情報 (2/2)
• CBPeripheral インスタンス
• UUID : 128-bitの識別番号
• 一度でも接続したことがあれば≠nil
• RSSI : 受信信号強度
• 接続してreadRSSI:を呼び出せば≠nil
• 切断しても同じUUIDを見つけて再接続
• LocalNameに、識別番号や、状態を入れたり
13年3月25日月曜日
49. -(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日月曜日
50. -(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日月曜日
51. -(void)connect:(PeripheralContainer *)c {
//ターゲットを発見、接続します
//この時点でperipheralはcentral managerに保持されていません。
必ずretain
//少なくとも接続が完了するまでの間、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日月曜日
52. -(void)connect:(PeripheralContainer *)c {
//ターゲットを発見、接続します
//この時点でperipheralはcentral managerに保持されていません。
必ずretain
//少なくとも接続が完了するまでの間、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日月曜日
53. -(void)connect:(PeripheralContainer *)c {
//ターゲットを発見、接続します
//この時点でperipheralはcentral managerに保持されていません。
必ずretain
//少なくとも接続が完了するまでの間、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日月曜日
54. -(void)connect:(PeripheralContainer *)c {
//ターゲットを発見、接続します
//この時点でperipheralはcentral managerに保持されていません。
必ずretain
//少なくとも接続が完了するまでの間、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;
13年3月25日月曜日
55. -(void)connect:(PeripheralContainer *)c {
//ターゲットを発見、接続します
//この時点でperipheralはcentral managerに保持されていません。
必ずretain
//少なくとも接続が完了するまでの間、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;
delegateで通知
13年3月25日月曜日
57. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
58. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
59. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
60. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
61. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer
ペリフェラル=データベース
PHY
ハンドル,タイプ,値
13年3月25日月曜日
62. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
63. プロトコルスタック
Applications
Applications
Applications
Core Bluetooth
XPC
BTserver
GATT
ATT
L2CAP
Link Layer サービス=クラス
キャラクタリスティクス
PHY
=プロパティ
13年3月25日月曜日
64. プロトコルスタック
Applications
Applications サービス=クラス
Applications
キャラクタリスティクス
Core Bluetooth
XPC =プロパティ
BTserver
GATT
ATT
L2CAP
Link Layer
PHY
13年3月25日月曜日
65. プロトコルスタック
Applications
Applications サービス=クラス
Applications
キャラクタリスティクス
Core Bluetooth
XPC =プロパティ
BTserver
GATT • キャラクタリスティクス
ATT
• 制御/動作指定
L2CAP
• センサー値/外界の状態
Link Layer
PHY
• (装置の)動作状態/内部状態
13年3月25日月曜日
67. サービスと振る舞いの分離
デバイス発見
Find ME
Profile
Proximity
Profile
切断時の警告
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
13年3月25日月曜日
68. サービスと振る舞いの分離
デバイス発見
Find ME Immediate 振動やブザー
Profile Alert Service
を出力
Tx Power 送信電力
Proximity
Service
Profile の値
切断時の警告 Link Loss 切断時の
Alert Service
振る舞い指定
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
13年3月25日月曜日
69. サービスと振る舞いの分離
デバイス発見
Find ME Immediate 振動やブザー
Profile Alert Service
を出力
Tx Power 送信電力
Proximity
Service
Profile の値
切断時の警告 Link Loss 切断時の
Alert Service
振る舞い指定
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
13年3月25日月曜日
70. サービスと振る舞いの分離
ユースケース ハード仕様
デバイス発見
Find ME Immediate 振動やブザー
Profile Alert Service
を出力
Tx Power 送信電力
Proximity
Service
Profile の値
切断時の警告 Link Loss 切断時の
Alert Service
振る舞い指定
http://developer.bluetooth.org/gatt/profiles/Pages/ProfileViewer.aspx?u=org.bluetooth.profile.find_me.xml
13年3月25日月曜日
71. プロファイルの実装
Applications
Applications
Applications • プロファイルがアプリ側
Core Bluetooth
• 任意の振る舞い、OK
• すべてがアプリの管理下
GATT
• 発見
ATT
L2CAP • 接続/切断
Link Layer • 読み書き
PHY
• iOSはいっさい関係してこない
13年3月25日月曜日
72. プロファイルの実装
Applications
Applications
Applications • プロファイルがアプリ側
XPC
Core Bluetooth
• 任意の振る舞い、OK
BTserver
• すべてがアプリの管理下
GATT
• 発見
ATT
L2CAP • 接続/切断
Link Layer • 読み書き
PHY
• iOSはいっさい関係してこない
13年3月25日月曜日
73. プロファイルの実装
Applications
Applications
Applications • プロファイルがアプリ側
XPC
Core Bluetooth
• 任意の振る舞い、OK
BTserver
• すべてがアプリの管理下
GATT
• 発見
ATT
L2CAP • 接続/切断
Link Layer • 読み書き
PHY
• iOSはいっさい関係してこない
13年3月25日月曜日
77. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
78. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
79. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
80. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
81. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
82. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
83. • UUIDで識別
• 16-bit / 128-bit
• 読み(read)/書き(write)/通知(notify)
13年3月25日月曜日
85. #define kImmediateAlertServiceUUID @"1802"
#define kLinkLossServiceUUID @"1803"
#define kAlertLevelUUID @"2A06"
...
_linkLossServiceUUID = [CBUUID UUIDWithString:kLinkLossServiceUUID];
_immediateAlertServiceUUID = [CBUUID UUIDWithString:kImmediateAlertServiceUUID];
_alertLevelUUID = [CBUUID UUIDWithString:kAlertLevelUUID];
// 接続
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p {
// サービスを探します
self.peripheral.delegate = self;
[p discoverServices:[NSArray arrayWithObjects:
_linkLossServiceUUID,
_immediateAlertServiceUUID,
_txPowerServiceUUID,
_batteryLevelServiceUUID,
nil]];
}
13年3月25日月曜日
86. #define kImmediateAlertServiceUUID @"1802"
#define kLinkLossServiceUUID @"1803"
#define kAlertLevelUUID @"2A06"
...
_linkLossServiceUUID = [CBUUID UUIDWithString:kLinkLossServiceUUID];
_immediateAlertServiceUUID = [CBUUID UUIDWithString:kImmediateAlertServiceUUID];
_alertLevelUUID = [CBUUID UUIDWithString:kAlertLevelUUID];
// 接続
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)p {
// サービスを探します
self.peripheral.delegate = self;
[p discoverServices:[NSArray arrayWithObjects:
_linkLossServiceUUID,
_immediateAlertServiceUUID,
_txPowerServiceUUID,
_batteryLevelServiceUUID,
nil]];
}
13年3月25日月曜日
87. //発見したサービスに対して、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日月曜日
88. //発見したサービスに対して、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日月曜日
89. //発見したサービスに対して、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日月曜日
90. - (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日月曜日
91. まとめ
• BTLE
• 超低消費電力、なんとなくつながる
• iOSとBTLE
• MFi不要、一般開発者権限
• 振るまいと機能の分離
• プロファイルはアプリ次第
13年3月25日月曜日
92. 開発体制
• ハード+プロファイル部分を担当すべし
• 無線接続と振る舞い
• デモアプリで動作確認、責任分界
• ドキュメント、読める?
• 納品後のトラブル (iOSの振舞い変化)
13年3月25日月曜日
94. 情報源(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日月曜日
95. 情報源(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日月曜日
96. 情報源(3/3)
• AppleのBluetoothアクセサリ設計指針 (おすすめ)
• Bluetooth Low Energy Handbook (おすすめ)
• Bluetooth4 Core Specificaiton (辞書的に)
13年3月25日月曜日
98. • CoreBluetoothを使う必要あるの?
• API公開(Wahoo、NODE、konashi...)
• ハード販売、サービス展開
• 自分で開発展開
• ハードウェア開発?
• 半導体/モジュール (組込開発)
• iOSでペリフェラル開発 (iOS6から)
13年3月25日月曜日
99. オリジナル開発
• 半導体買ってきて回路を作ると
• BT認証 1万ドル、電波法 40万円(実費)。
• 1万台以上作るなら
• モジュール
• 日本の認証OKなのが4月から続々。
• BlueGiga、おすすめ
• BASICみたいなスクリプト開発。
• 冗談みたいなお手軽さ。
13年3月25日月曜日
100. • ペリフェラルの設計
• 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日月曜日
101. こまったときの
• 何が何やら、わけがわかんないよ
• 通信の把握が勝利の
• TI社のCC2540開発キットでパケットスニファ
• iOS6.0で、切断時にiOSが1分ほど接続保持ー>アドバタ
イズ出ない
13年3月25日月曜日
102. 今時のBTLE
• BTLEデバイス、Over-the-airでファーム更新
• Kickstarterむっちゃでてる
• 10万台の呪い。日本、しんでる
• 覚えていますか
• 記憶にすら残らない、NECカシオの
MEDIASとリモッピとG-SHOCK。まじ、
ショック
13年3月25日月曜日
103. 他のプラットホーム
• Android
• チップメーカ独自スタック、公式BTLE対応なし
• できることはiOSと同じ。GATTを叩ける。
• BT3/4混在、Android4。
• ねらってもできない統一性のなさ
• 5月のGoogle IO、ドコモの健康なんとか?
• Windows Phone8
•公式スタックなし、BT3が最新機種
• Windows8
•ハード認定要件にBT4、スタック公式サポート
13年3月25日月曜日
• C+でドライバ
105. • アプリ
• バックグラウンド
• CBPeripheralManager
• ハード開発
• 情報源
13年3月25日月曜日
110. Central
Central client
Peripheral
Peripheral server
13年3月25日月曜日
112. Central
Peripheral
CBCentralManager
CBPeripheralManager
CBPeripheral
CBCentral
13年3月25日月曜日
113. iOS5 iOS6
Main
Objects
CBCentralManager CBPeripheralManager
Data CBPeripheral CBCentral
Objects
CBService
CBMutableService
CBCharacteristics
CBMutableCharacteri
13年3月25日月曜日
114. Central
Peripheral
Ad
Ad
Ad
13年3月25日月曜日
115. discover and connect
CBCentralManager Periphearl device
scanForPeripheralsWithServices
didDiscoverPeripheral
stopScan
connectPeripheral
didConnectPeripheral
13年3月25日月曜日
116. Central Peripheral
CBService
Service
CBCharacteristic
Characteristic
Characteristic
13年3月25日月曜日
117. CBPeripheral CBPeripheralDelegate
discoverServices
didDiscoverServices
discoverCharacteristics:forService
didDiscoverCharacteristicsForSer
vice
13年3月25日月曜日
118. CBPeripheral CBPeripheralDelegate
readValueForCharacteristic
didUpdateValueForCharacteristics
setNotifyValue:forCharacteristic
didUpdateValueForCharacteristics
13年3月25日月曜日
119. • Scan and Connect
• Reconnecting using UUID
• Already connected?
•
13年3月25日月曜日
120. discover and connect
CBCentralManager Periphearl device
retrievePeripherals
didRetrievePeripherals
connectPeripheral
didConnectPeripheral
13年3月25日月曜日
121. iOS background
• Background app
• Scan and advertise
• Connect
• Interact
• “Start and stop”concept
• Info.plist
13年3月25日月曜日
122. • Foreground app
• High-intensity scanning
• Bacground app/screen off
• Low-intensity scanning
•
13年3月25日月曜日
123. • Ad
• Name
• Tx Power
• Service UUID
• Service Data
• Max: 31 bytes
13年3月25日月曜日
124. • 16-bit UUID
• assigned by Bluetooth SIG
• http://develper/bluetooth.org
• 128-bit UUID
• assigned by you!
• コマンドライン uuidgen
13年3月25日月曜日
126. ペアリング
• ペアリング
• 接続する、認証されてないー>拒否
• Insufficient Authentication
• ペアリング、暗号化
• AES-128、公開
13年3月25日月曜日
127. BTLE available?
• CBCentralManager
• delegate CBCentralManagerDelegate
• state CBCentralManagerState
• unknown -> 遷移
• 使う前にチェック
13年3月25日月曜日
129. Bluetooth Smart ready と ready
• 2種類の周辺機器
• デュアル・モード = クラシックBT + LE 両方搭載
• シングル・モード = LEのみ
• 接続問題
• シングル・モード デバイスはクラシックBTとつながらない
• SMART READY (デュアル) / SMART (シングル) ロゴ
http://www.bluetooth.com/Pages/Smart-Logos.aspx
13年3月25日月曜日