Bluez: рекламировать сервис / пример сервера gatt?

цель

Я разрабатываю простое устройство под управлением Linux. Это BLE способен, и в настоящее время я использую bluez 5.8.

Я хочу запустить действие на этом устройстве с помощью iPhone.

что уже работает:

  • я могу сделать iPhone "видеть" устройство.
  • iPhone также подключается к устройства.

я настраиваю устройство bluetooth, как это на linux (благодаря этот вопрос):

# 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-сервера для получения характеристик чтения/записи для службы, которую я бы рекламировал. Я видел пример плагинов / gatt.C файл в bluez, но я абсолютно не знаю, как его использовать: нет документации.

Я, вероятно, должен упомянуть, что я видел этот вопрос:создание сервера gatt, но ответы вызывают слишком много вопросов (например, где api GATT для bluez? как установить базу данных GATT? Как зарегистрироваться для чтения/записи событий?)

изменить: Команды, которые я использую, только настраивают устройство BLE для рекламы некоторых данных, но iOS сообщает, что соединение принят. Какая часть bluez принимает входящие соединения?

2 ответов


в конце концов, я нашел ответы на все вопросы, которые я имел.

Я начну с ответа на последний вопрос:

команды, которые я использую, только настраивают устройство BLE для рекламы некоторых данных, но iOS сообщает, что соединение принято. Какая часть bluez принимает входящие соединения?

этот ответил на рассылку bluez, в ответ на меня.

резюме: BLE соединение принимается ядром на уровне HCI. Если вы хотите использовать это соединение из пользовательского пространства, вам нужно использовать сокет l2cap с идентификатором канала ATT (который равен 4).

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 запросит список услуг.

затем вы можете ответить на этот запрос списком услуг, предоставляемых вашим устройством, отформатированным в соответствии с ГАТТ протокол.

опять см. реализацию этого в Bleno.


вы действительно близки.

чтобы просмотреть службы на устройстве с помощью кода iOS, попробуйте добавить

peripheral.delegate = self;

на didConnectPeripheral до discoverServices звонок. Я получил это от документация Apple и это исправило вещи для меня (просто не забудьте добавить CBPeripheralDelegate к объявлению интерфейса в заголовочном файле). Без него,didDiscoverServices никогда не будет вызван.

я смог получить gatt-example плагин службы для запуска путем компиляции BlueZ из источника с ./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).