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
).