目標
Linuxを実行する単純なデバイスを開発しています。 BLE対応で、現在bluez 5.8を使用しています。
iPhoneを使用してこのデバイスでアクションをトリガーしたい
すでに動作しているもの:
Linuxでこのようなbluetoothデバイスをセットアップします( この質問 に感謝します):
# activate bluetooth
hciconfig hci0 up
# set advertise data: "hello world"
hcitool -i hci0 cmd 0x08 0x0008 48 45 4c 4c 4f 57 4f 52 4c 44
# start advertising as connectable
hciconfig hci0 leadv 0
IOSコードは簡単です。
- (int) scanForPeripherals
{
if (self->centralManager.state != CBCentralManagerStatePoweredOn) {
return -1;
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
[self.centralManager scanForPeripheralsWithServices:nil options:options];
return 0;
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if (central.state == CBCentralManagerStatePoweredOn) {
NSLog(@"Starting scan");
[self scanForPeripherals];
}
}
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"didDiscoverPeripheral");
/*
* Retain the peripheral to avoid the error:
* CoreBluetooth[WARNING]: state = connecting> is being dealloc'ed while connecting
*/
self.activePeripheral = peripheral;
[centralManager connectPeripheral:peripheral options:nil];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Connected to peripheral");
/* discover all services */
[peripheral discoverServices:nil];
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
NSLog(@"Discovered services");
for (CBService *service in peripheral.services) {
NSLog(@"Discovered service %@", service);
}
}
IPhoneでこのコードを実行すると、次のログが表示されます。
2013-12-19 12:53:22.609 Test2[18518:60b] Starting scan
2013-12-19 12:53:29.945 Test2[18518:60b] didDiscoverPeripheral
2013-12-19 12:53:31.230 Test2[18518:60b] Connected to peripheral
IPhoneは正常に接続されているようですが、サービスは表示されません。
足りないもの
私はおそらくこの質問を見たことに言及する必要があります: gattサーバーの作成 、しかし、答えはあまりにも多くの質問を引き起こします(たとえば、bluezのGATT APIはどこにありますか?GATTデータベースの設定方法は?読み取り/書き込みイベントに登録しますか?)
編集:私が使用するコマンドは、BLEデバイスをセットアップして一部のデータをアドバタイズするだけですが、iOSは接続がacceptedであると報告します。 bluezのどの部分が着信接続を受け入れていますか?
最終的に、私は私が持っていたすべての質問に対する答えを発見しました。
最後の質問に答えることから始めます。
私が使用するコマンドは、BLEデバイスをセットアップしてデータをアドバタイズするだけですが、iOSは接続が受け入れられたと報告します。 bluezのどの部分が着信接続を受け入れていますか?
これは bluezメーリングリストで回答済み でした。
要約:BLE接続は、カーネルによってHCIレベルで受け入れられます。ユーザー空間からその接続を使用する場合は、ATTチャネルID(4)でl2capソケットを使用する必要があります。
L2CAPソケットの仕組みは基本的に次のとおりです。
_/* create L2CAP socket, and bind it to the local adapter */
l2cap_socket = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
hci_device_id = hci_get_route(NULL);
hci_socket = hci_open_dev(hci_device_id);
memset(&l2cap_address, sizeof(l2cap_address));
l2cap_address.l2_family = AF_BLUETOOTH;
l2cap_address.l2_bdaddr = hci_device_address;
l2cap_address.l2_cid = htobs(ATT_CID);
bind(l2cap_socket, (struct sockaddr*)&l2cap_address, sizeof(l2cap_address));
listen(l2cap_socket, 1);
while (1) {
/* now select and accept() client connections. */
select(l2cap_socket + 1, &afds, NULL, NULL, &tv);
client_socket = accept(l2cap_socket, (struct sockaddr *)&l2cap_address, &len);
/* you can now read() what the client sends you */
int ret = read(client_socket, buffer, sizeof(buffer));
printf("data len: %d\n", ret);
for (i = 0; i < ret; i++) {
printf("%02x", ((int)buffer[i]) & 0xff);
}
printf("\n");
close(client_socket);
}
_
サービスを宣伝する方法は?
その質問に答えるには、前の質問に答える必要があることに気付きました。
L2CAPソケットを介してデータを読み取れると、たとえば、Android電話がgatt.discoverServices()
の場合、上記の小さなプログラムは読み取り(つまり受信):
_10 0100 ffff 0028
_
これは基本的に次を意味します:
_10: READ_BY_GROUP
0100: from handle 0001
ffff: to handle ffff
0028: with UUID 2800
_
この要求は、BLE周辺機器がサービスのリストを要求する方法です。
次に、GATTプロトコルに従ってフォーマットされた、デバイスが提供するサービスのリストを使用して、この要求に答えることができます。
繰り返しますが、 Blenoでのこの実装を参照 です。
あなたは本当に近いです。
IOSコードを使用してデバイス上のサービスを表示するには、追加してみてください
peripheral.delegate = self;
didConnectPeripheral
呼び出しの前に、discoverServices
に。 Appleのドキュメント から得たもので、問題は解決しました(ヘッダーファイルのインターフェイス宣言にCBPeripheralDelegate
を追加することを忘れないでください)。それなしでは、didDiscoverServices
は呼び出されません。
ソースからBlueZをgatt-example
でコンパイルすることにより、./configure --enable-maintainer-mode
サービスプラグインを実行することができました。 bluetoothd -nd
を起動すると、次のようなものが表示されます
src/plugin.c:add_plugin() Loading gatt_example plugin
出力の上部付近、そして
attrib/gatt-service.c:gatt_service_add() New service: handle 0x0009, UUID a002, 4 attributes
src/attrib-server.c:attrib_db_add_new() handle=0x0009
attrib/gatt-service.c:gatt_service_add() New characteristic: handle 0x000a
src/attrib-server.c:attrib_db_add_new() handle=0x000a
その時点で、私のiOSアプリはBlueZ peripheral
を確認し、接続し、サービスを(hciconfig hci0 leadv
の後に)発見することができました。