28

ゴール

Linux を実行する単純なデバイスを開発しています。BLE 対応で、現在 bluez 5.8 を使用しています。

iPhone を使用して、このデバイスでアクションをトリガーしたいと考えています。

すでに機能しているもの:

  • iPhoneにデバイスを「見せる」ことができます。
  • 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 は問題なく接続しているように見えますが、サービスは表示されません。

私が欠けているもの

  • シンプルな BLEサービスを宣伝する必要がありますが、bluez でこれを行う方法に関するドキュメントが見つかりません。
  • 私が宣伝するサービスの読み取り/書き込み特性を受け取るには、gatt-server のようなものが必要だと思います。bluez で plugins/gatt-example.c ファイルを見ましたが、使い方がまったくわかりません。ドキュメントがありません。

私はおそらく、次の質問を見たことに言及する必要があります:ガット サーバーの作成、しかし、答えはあまりにも多くの質問を提起します (たとえば、bluez の GATT API はどこにありますか? GATT データベースを設定する方法は? 読み取り/書き込みイベントに登録する方法は? )

編集: 私が使用するコマンドは、一部のデータをアドバタイズするために BLE デバイスをセットアップするだけですが、iOS は接続が受け入れられたと報告します。着信接続を受け入れる bluez の部分は?

4

2 に答える 2

19

最終的に、私は持っていたすべての質問に対する答えを発見しました。

最後の質問に答えることから始めます。

私が使用するコマンドは、一部のデータをアドバタイズするために BLE デバイスをセットアップするだけですが、iOS は接続が受け入れられたと報告します。着信接続を受け入れる bluez の部分は?

これは bluez mailing-listで回答がありました。

要約: BLE 接続はカーネルによって HCI レベルで受け入れられます。ユーザー空間からその接続を使用する場合は、ATT チャネル ID (4) を持つ l2cap ソケットを使用する必要があります。

Bleno は、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 ソケットを介してデータを読み取ることができれば、すべてがより理にかなっています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 での実装を参照してください

于 2014-11-26T20:34:54.270 に答える