2013-12-19 6 views
24

TorBluez: Werben Service/Gatt-Server Beispiel?

Ich bin ein einfaches Gerät developping Linux läuft. Es ist BLE-fähig, und ich verwende derzeit Bluez 5.8.

Ich möchte eine Aktion auf diesem Gerät mit einem iPhone auslösen.

Was bereits funktioniert:

  • kann ich das iPhone machen "sehen" das Gerät aus.
  • Das iPhone verbindet sich auch mit dem Gerät.

ich Setup die Bluetooth-Gerät wie dieses auf Linux (dank this question):

# 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 

Der iOS-Code ist einfach:

- (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); 
    } 
} 

Wenn auf dem iPhone diesen Code ausgeführt wird, ich Holen Sie sich dieses Protokoll:

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 

So ist es scheint, dass das iPhone gut verbindet, sieht aber keinen Dienst.

Was mir fehlt

  • Ich brauche einen einfachen BLE Service, zu werben, aber ich kann keine Dokumentation finden, wie dies in bluez zu tun.
  • Ich glaube, ich brauche so etwas wie einen Gatt-Server, um Lese-/Schreibeigenschaften für den Dienst zu erhalten, den ich annoncieren würde. Ich habe die Datei plugins/gatt-example.c in bluez gesehen, aber ich habe absolut keine Ahnung, wie man sie benutzt: Es gibt keine Dokumentation.

Ich soll wohl erwähnen, dass ich diese Frage sah:? Creating a gatt server, aber die Antworten erhöhen zu viele Fragen (zum Beispiel, wo der GATT api für bluez wie die GATT-Datenbank festlegen, wie für Lese registrieren/Ereignisse schreiben)

EDIT: die Befehle ich verwende nur die BLE Gerät set-up einige Daten zu werben, aber iOS berichtet, dass die Verbindung akzeptiert. Welcher Teil von Bluez akzeptiert eingehende Verbindungen?

+0

Sie haben Recht, Sie brauchen einen GATT-Server. Die Befehle, die Sie ausführen, richten nur die Hardware ein, um ein Werbepaket zu übertragen, aber nichts startet etwas, mit dem man sich verbinden kann. Leider muss ich noch herausfinden, wie ich einen GATT-Server selbst einrichten kann, damit ich Ihnen nicht helfen kann ... –

+0

@TimTisdall Ich weiß, dass diese Befehle keinen Server einrichten. Und das wirft die Frage auf: Wer akzeptiert die Bluetooth-Verbindung? Ich habe meinen Beitrag bearbeitet, um diese Frage klarzustellen. –

+0

Meine Vermutung ist, dass etwas im Kernel die Verbindung herstellt, aber es ist nur eine Vermutung. –

Antwort

16

Schließlich entdeckte ich die Antworten auf alle Fragen, die ich hatte.

Ich werde durch die Beantwortung der letzten Frage beginnen:

Die Befehle, die ich nur die BLE Gerät Set-up verwenden, um einige Daten zu werben, aber iOS berichtet, dass die Verbindung angenommen wird. Welcher Teil von Bluez akzeptiert eingehende Verbindungen?

Dieser war answered on the bluez mailing-list, als Antwort auf mich.

Zusammenfassung: die BLE-Verbindung wird auf der HCI-Ebene vom Kernel akzeptiert. Wenn Sie diese Verbindung aus dem Benutzerbereich verwenden möchten, müssen Sie einen l2cap-Socket mit der ATT-Kanal-ID (4) verwenden.

Bleno has a good example of using an L2CAP socket.

Wie ein L2CAP-Buchse funktioniert, ist im Grunde wie folgt:

/* 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); 
} 

Wie ein Service werben?

Ich erkannte, dass ich eine Antwort auf die vorherige Frage brauchte, um diese zu beantworten.

Nachdem Sie die Daten über L2CAP Socket lesen kann, macht alles mehr Sinn, zum Beispiel, wenn Ihr Android-Handy gatt.discoverServices() der Fall ist, dann wird das kleine Programm oben wird gelesen (dh erhalten):

10 0100 ffff 0028 

die im Grunde bedeutet:

10: READ_BY_GROUP 
0100: from handle 0001 
ffff: to handle ffff 
0028: with UUID 2800 

Diese Anforderung ist die Art, wie jedes BLE-Peripheriegerät die Liste der Dienste anfordern wird.

Dann können Sie diese Anfrage mit der Liste der Dienste beantworten, die Ihr Gerät gemäß dem GATT-Protokoll bereitstellt.

Wieder, see the implementation of this in Bleno.

+0

Haben Sie es jemals geschafft, dass Ihre GATT-Dienste mit Bluez funktionieren? Ich versuche das Gleiche zu erreichen. – Michael

4

Sie sind wirklich nah dran.

Um die Dienste auf einem Gerät mit dem iOS-Code zu sehen, versuchen

peripheral.delegate = self; 

zu Ihrem didConnectPeripheral vor dem discoverServices Gespräch hinzugefügt. Ich habe das von der Apple documentation und es repariert Dinge für mich (nur nicht vergessen, CBPeripheralDelegate zu der Schnittstellenkonvention in der Header-Datei hinzuzufügen). Ohne es wird didDiscoverServices nie aufgerufen werden.

Ich konnte das gatt-example Service-Plugin ausführen, indem Sie BlueZ aus der Quelle mit der ./configure --enable-maintainer-mode kompilieren. Dann, wenn Sie bluetoothd -nd starten Sie werden sehen, so etwas wie

src/plugin.c:add_plugin() Loading gatt_example plugin 

in der Nähe der Spitze des Ausgangs, und dann

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 

An diesem Punkt meines iOS-App konnte die BlueZ peripheral sehen, verbinden , und entdecken Sie seine Dienste (nach einem hciconfig hci0 leadv).

+0

danke für das Teilen. Es scheint, dass ich Bluez nicht kompiliert habe mit '--enable-maintainer-mode', _but_ die Verbindung wird akzeptiert. Nach (zu viel) Lesen des Bluez-Codes glaube ich, dass die Verbindung vom Service-Discovery-Teil von Bluez ... akzeptiert wird (siehe src/sdpd-server.c). –

+0

Ja, ich habe das gleiche Verhalten gesehen, bevor ich das Plugin 'gatt-example' aktiviert habe. Dies liegt daran, dass Verbindungen zuerst akzeptiert werden und anschließend eine Diensteerkennung stattfindet. Ohne das "gatt-example" -Plugin, das in "bluetoothd" enthalten ist, sieht Ihr iPhone immer noch Ihre Werbepakete und kann sich verbinden, findet aber keine Dienste. '--enable-maintainer-mode' ist eine Abkürzung um das' gatt-example' Plugin in den Build einzufügen ohne 'Makefile.plugins' zu verändern. – Gabriel

+0

Ich habe zwei schnelle, verwandte Fragen: a) Wo kann ich die Dienste und Attribute in Bluez konfigurieren? b) Wenn ein Attribut beschreibbar ist, "speichert" Bluez diese Information (oder ist eine Art Callback), um etwas mit diesem Wert zu tun, der von der ios App geschrieben wurde. –