electron开发的客户端中想操作蓝牙设备,找到第三方类库nodejs的类库webbluetooth 。在mac系统上ok,在window系统上出现蓝牙设备的服务枚举不全,通过增加输出日志的方式定位到代码。并记录解决方法。
SimpleBLE\simpleble\src\frontends\base\Peripheral.cpp
- 获取服务,当设备连接连接成功后is_connected()为true,调用services获取到服务列表。
- 但是
std::vector<Service> Peripheral::services() {
if (!initialized()) throw Exception::NotInitialized();
if (is_connected()) {
return internal_->services();
} else {
return internal_->advertised_services();
}
return internal_->services();
}
SimpleBLE\simpleble\src\backends\windows\PeripheralBase.cpp
- 服务枚举中用到了gatt_map_缓存数据,那这个数据是在什么时候填充进去的呢?
- 通过查找gatt_map_发现是在设备连接的方法中填充进去的。
std::vector<Service> PeripheralBase::services() {
std::vector<Service> service_list;
for (auto& [service_uuid, service] : gatt_map_) {
// Build the list of characteristics for the service.
std::vector<Characteristic> characteristic_list;
for (auto& [characteristic_uuid, characteristic] : service.characteristics) {
// Build the list of descriptors for the characteristic.
std::vector<Descriptor> descriptor_list;
for (auto& [descriptor_uuid, descriptor] : characteristic.descriptors) {
descriptor_list.push_back(DescriptorBuilder(descriptor_uuid));
}
uint32_t properties = (uint32_t)characteristic.obj.CharacteristicProperties();
bool can_read = (properties & (uint32_t)GattCharacteristicProperties::Read) != 0;
bool can_write_request = (properties & (uint32_t)GattCharacteristicProperties::Write) != 0;
bool can_write_command = (properties & (uint32_t)GattCharacteristicProperties::WriteWithoutResponse) != 0;
bool can_notify = (properties & (uint32_t)GattCharacteristicProperties::Notify) != 0;
bool can_indicate = (properties & (uint32_t)GattCharacteristicProperties::Indicate) != 0;
characteristic_list.push_back(CharacteristicBuilder(characteristic_uuid, descriptor_list, can_read,
can_write_request, can_write_command, can_notify,
can_indicate));
}
service_list.push_back(ServiceBuilder(service_uuid, characteristic_list));
}
return service_list;
}
SimpleBLE\simpleble\src\backends\windows\PeripheralBase.cpp
- 设备连接方法connect中调用了_attempt_connect,就是用来枚举服务、特征值、描述符的。
- _attempt_connect中第一层for循环,若特征值枚举失败,就直接返回falsele .若该服务下确实没有特征值,则会出现服务枚举不全的情况。比如本来8个服务只枚举出来6个。
- 改造for,使用continue代替false.问题解决。以下是调测的代码, 供参考、备忘。
void PeripheralBase::connect() {
device_ = async_get(BluetoothLEDevice::FromBluetoothAddressAsync(_str_to_mac_address(address_)));
// Attempt to connect to the device.
for (size_t i = 0; i < 3; i++) {
if (_attempt_connect()) {
break;
}
}
if (is_connected()) {
connection_status_changed_token_ = device_.ConnectionStatusChanged(
[this](const BluetoothLEDevice device, const auto args) {
if (device.ConnectionStatus() == BluetoothConnectionStatus::Disconnected) {
this->disconnection_cv_.notify_all();
SAFE_CALLBACK_CALL(this->callback_on_disconnected_);
}
});
SAFE_CALLBACK_CALL(this->callback_on_connected_);
}
}
bool PeripheralBase::_attempt_connect() {
gatt_map_.clear();
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect 执行了 : " << std::endl;
// We need to cache all services, characteristics and descriptors in the class, else
// the underlying objects will be garbage collected.
auto services_result = async_get(device_.GetGattServicesAsync(BluetoothCacheMode::Uncached));
if (services_result.Status() != GattCommunicationStatus::Success) {
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect 准备退出false : " << std::endl;
return false;
}
int testIndex = 0;// for test
auto gatt_services = services_result.Services();
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect services_result.Services()执行了 " << std::endl;
for (GattDeviceService&& service : gatt_services) {
testIndex++;
// For each service...
gatt_service_t gatt_service;
gatt_service.obj = service;
// Save the MTU size
mtu_ = service.Session().MaxPduSize();
// Fetch the service UUID
std::string service_uuid = guid_to_uuid(service.Uuid());
// Fetch the service characteristics
auto characteristics_result = async_get(service.GetCharacteristicsAsync(BluetoothCacheMode::Uncached));
if (characteristics_result.Status() != GattCommunicationStatus::Success) {
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect 准备退出false : 特征值出错 service_uuid= " << service_uuid << std::endl;
gatt_map_.emplace(service_uuid, std::move(gatt_service));
continue;
// return false;
}
// Load the characteristics into the service
auto gatt_characteristics = characteristics_result.Characteristics();
for (GattCharacteristic&& characteristic : gatt_characteristics) {
// For each characteristic...
gatt_characteristic_t gatt_characteristic;
gatt_characteristic.obj = characteristic;
// Fetch the characteristic UUID
std::string characteristic_uuid = guid_to_uuid(characteristic.Uuid());
// Fetch the characteristic descriptors
auto descriptors_result = async_get(characteristic.GetDescriptorsAsync(BluetoothCacheMode::Uncached));
if (descriptors_result.Status() != GattCommunicationStatus::Success) {
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect 准备退出false : 描述符出错 " << std::endl;
gatt_map_.emplace(service_uuid, std::move(gatt_service));
continue;
// return false;
}
// Load the descriptors into the characteristic
auto gatt_descriptors = descriptors_result.Descriptors();
for (GattDescriptor&& descriptor : gatt_descriptors) {
// For each descriptor...
gatt_descriptor_t gatt_descriptor;
gatt_descriptor.obj = descriptor;
// Fetch the descriptor UUID.
std::string descriptor_uuid = guid_to_uuid(descriptor.Uuid());
// Append the descriptor to the characteristic.
gatt_characteristic.descriptors.emplace(descriptor_uuid, std::move(gatt_descriptor));
}
// Append the characteristic to the service.
gatt_service.characteristics.emplace(characteristic_uuid, std::move(gatt_characteristic));
}
// Append the service to the map.
gatt_map_.emplace(service_uuid, std::move(gatt_service));
}
std::cout << "ssss gatt_map_.emplace testIndex : " << testIndex << std::endl;
std::cout << "ssss gatt_map_ PeripheralBase::_attempt_connect 准备退出 true " << std::endl;
return true;
}