Bluez:做广告服务/ gatt服务器的例子?

目标

我正在开发一个运行Linux的简单设备。 这是BLE能力,我目前使用蓝色5.8。

我想用iPhone触发此设备上的操作。

什么已经工作:

  • 我可以让iPhone“看”设备。
  • iPhone也连接到设备。

我在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-server这样的服务器来接收读/写特性,我将做广告的服务。 我看到了bluez中的plugins / gatt-example.c文件,但我完全不知道如何使用它:没有文档。

我应该提到,我看到了这个问题: 创build一个gatt服务器 ,但是答案提出了太多问题(例如,bluez的GATT api在哪里?如何设置GATT数据库?如何注册读/写事件? )

编辑:我使用的命令只设置BLE设备来宣传一些数据,但iOS报告连接被接受 。 bluez的哪个部分接受传入连接?

Solutions Collecting From Web of "Bluez:做广告服务/ gatt服务器的例子?"

最终,我发现了所有问题的答案。

我将首先回答最后一个问题:

我使用的命令只设置BLE设备来公布一些数据,但是iOS报告连接被接受。 bluez的哪个部分接受传入连接?

这个是在bluez邮件列表上回答的,对我的回应。

总结: 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套接字读取数据,一切都变得更有意义,例如,如果你的Android手机使用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中的这个实现 。

你真的很亲密

要使用iOS代码查看设备上的服务,请尝试添加

 peripheral.delegate = self; 

发送到您的didConnectPeripheral ,在discoverServices调用之前。 我从苹果文档中得到了它,它为我解决了一些问题(只是不要忘记把CBPeripheralDelegate添加CBPeripheralDelegate中的接口声明中)。 没有它, didDiscoverServices将永远不会被调用。

我可以通过使用./configure --enable-maintainer-mode从源代码编译BlueZ来运行gatt-example服务插件。 然后,如果你启动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 )。