Bluez: reklamuj usługę / przykład serwera gatt?

Gol

Rozwijam proste urządzenie z systemem Linux. Jest zdolny do BLE, a obecnie używam bluez 5.8.

chcę wywołać akcję na tym urządzeniu za pomocą iPhone ' a.

Co już działa:

    Mogę sprawić, że iPhone "zobaczy" urządzenie. [[18]}iPhone również łączy się z urządzeniem.

Skonfigurowałem urządzenie bluetooth tak na Linuksie (dzięki to pytanie):

# 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

Kod iOS jest prosty:

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

Podczas uruchamiania tego kodu na iPhonie, dostaję ten log:

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

Wygląda na to, że iPhone łączy się dobrze, ale nie widzi żadnej usługi.

Czego mi brakuje

  • muszę zareklamować prosty serwis BLE , ale nie mogę znaleźć żadnej dokumentacji, jak to zrobić w bluez .
  • myślę, że potrzebuję czegoś takiego jak serwer gatt, aby odbierać Odczyt/Zapis charakterystyka usługi, którą reklamuję. Widziałem wtyczki / gatt-przykład.plik c w bluez, ale nie mam zielonego pojęcia jak z niego korzystać: nie ma dokumentacji.

Powinienem chyba wspomnieć, że widziałem to pytanie: Tworzenie serwera gatt , ale odpowiedzi budzą zbyt wiele pytań (na przykład, gdzie jest API GATT dla bluez? jak ustawić bazę danych GATT? Jak zarejestrować się do odczytu/zapisu zdarzeń?)

Edytuj: Polecenia, których używam, ustawiają tylko urządzenie BLE aby zareklamować niektóre dane, ALE iOS informuje, że połączenie jest zaakceptowane. Która część bluez akceptuje połączenia przychodzące?

Author: Community, 2013-12-19

2 answers

W końcu odkryłem odpowiedzi na wszystkie pytania, które miałem.

Zacznę od odpowiedzi na ostatnie pytanie:

Polecenia używam tylko skonfigurować urządzenie BLE do reklamowania niektórych danych, ALE iOS zgłasza, że połączenie jest akceptowane. Która część bluez akceptuje połączenia przychodzące?

Ta odpowiedź została wysłana na listę mailingową bluez, w odpowiedzi dla mnie.

podsumowanie: połączenie BLE jest akceptowane na poziomie HCI przez jądro. Jeśli chcesz używać tego połączenia z przestrzeni użytkownika, musisz użyć gniazda l2cap z ID kanału ATT (czyli 4).

Bleno ma dobry przykład użycia gniazda L2CAP .

Jak działa Gniazdo L2CAP jest w zasadzie tak:

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

Jak reklamować serwis?

Zdałem sobie sprawę, że potrzebuję odpowiedzi na poprzednie pytanie, aby odpowiedzieć na to pytanie.

Gdy będziesz mógł odczytać dane przez gniazdo L2CAP, wszystko nabiera sensu, na przykład, jeśli twój telefon z Androidem robi gatt.discoverServices(), to mały program powyżej będzie odczytywał (tj. odbierał):

10 0100 ffff 0028

Co w zasadzie oznacza:

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

To żądanie jest sposobem, w jaki każdy BLE będzie żądał listy usług.

Następnie możesz odpowiedzieć na to żądanie listą usług, które zapewnia Twoje urządzenie, sformatowaną zgodnie z protokołem GATT.

Ponownie, zobacz implementację tego w Bleno .

 16
Author: Gilles Gregoire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-26 20:34:54

Jesteś naprawdę blisko.

Aby zobaczyć usługi na urządzeniu z kodem iOS, spróbuj dodać
peripheral.delegate = self;

Do twojego didConnectPeripheral, przed discoverServices telefonem. Otrzymałem to z dokumentacji Apple i to poprawiło mi pewne rzeczy (tylko nie zapomnij dodać CBPeripheralDelegate do deklaracji interfejsu w pliku nagłówkowym). Bez niego, didDiscoverServices nigdy nie zostanie wywołany.

Udało mi się uruchomić wtyczkę usługi gatt-example kompilując BlueZ ze źródła za pomocą ./configure --enable-maintainer-mode. Następnie, jeśli uruchomisz bluetoothd -nd zobaczysz coś takiego

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

Blisko góry wyjścia, a następnie

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
W tym momencie Moja aplikacja na iOS była w stanie zobaczyć BlueZ peripheral, połączyć się i odkryć jego usługi (po hciconfig hci0 leadv).
 4
Author: Gabriel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-21 04:51:24