Bluetooth низкий уровень энергопотребления в Windows?

У меня есть устройство с пользовательским сервисом, который отправляет данные датчика с очень высокой скоростью, используя функцию уведомления BLE.

Я использую следующий API на компьютере с Windows 10: https://msdn.microsoft.com/en-us/library/windows/hardware/jj159880(v=vs.85).aspx

Я ищу устройство по пользовательскому идентификатору службы с помощью API SetupDi, а затем «подключаюсь» к нему с помощью CreateFile.

Когда я впервые подключаю устройство к Windows, в окне настроек Bluetooth сразу отображается «Подключено», а затем, когда я запускаю свое приложение, оно прекрасно работает (я получаю данные с высокой скоростью). Если я закрываю свое приложение, оно меняет статус в окне «Настройки» на «Сопряженный», а не подключенный (что, я полагаю, подходит). Когда я снова открываю свое приложение, оно подключается и снова меняет статус в настройках на «Подключено», но теперь я почему-то получаю данные с гораздо меньшей скоростью. (сами данные верны). Если я отключаю его через окна настроек Bluetooth, нажимая «Удалить устройство», а затем снова подключаю его, как я делал, прежде чем он снова заработает с высокой скоростью в первый раз.

Я знаю, что это не проблема с самим устройством, потому что оно отлично работает с Android и другими BLE-поддерживаемыми платформами.

Есть идеи, что может вызвать эту проблему?

Вот код, который я использую:

GUID serviceGuid = StringToGUID(GEM_SERVICE_GUID);

HDEVINFO info = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_DEVICEINTERFACE);
SP_DEVICE_INTERFACE_DATA data;
data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

int i = 0;

while (SetupDiEnumDeviceInterfaces(info, NULL, &guid, i, &data))
{
i++;
}

if (GetLastError() != ERROR_NO_MORE_ITEMS)
{
// TODO throw
}

DWORD requiredSize;

if (!SetupDiGetDeviceInterfaceDetail(info, &data, NULL, 0, &requiredSize, NULL))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
// TODO throw
}
}

PSP_DEVICE_INTERFACE_DETAIL_DATA details = (PSP_DEVICE_INTERFACE_DETAIL_DATA)std::malloc(requiredSize);
details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

if (!SetupDiGetDeviceInterfaceDetail(info, &data, details, requiredSize, NULL, NULL))
{
// TODO throw
}

m_service = CreateFile(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (m_service == INVALID_HANDLE_VALUE)
{
// TODO throw
return;
}

BTH_LE_GATT_CHARACTERISTIC combinedDataChar = FindCharacteristicByUUID(m_service, COMBINED_DATA_CHAR_HANDLE);
BTH_LE_GATT_DESCRIPTOR desc = FindDescriptorByType(m_service, &combinedDataChar, ClientCharacteristicConfiguration);

BTH_LE_GATT_DESCRIPTOR_VALUE val;
RtlZeroMemory(&val, sizeof(val));
val.DescriptorType = ClientCharacteristicConfiguration;
val.ClientCharacteristicConfiguration.IsSubscribeToNotification = TRUE;

HRESULT res = BluetoothGATTSetDescriptorValue(m_service, &desc, &val, BLUETOOTH_GATT_FLAG_NONE);

if (res != S_OK)
{
// TODO throw
}

BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION chars;
chars.NumCharacteristics = 1;
chars.Characteristics[0] = combinedDataChar;

res = BluetoothGATTRegisterEvent(m_service, CharacteristicValueChangedEvent, &chars, OnValueChanged, NULL, &m_registrationHandle, BLUETOOTH_GATT_FLAG_NONE);

if (res != S_OK)
{
// TODO throw
}

РЕДАКТИРОВАТЬ:

Код для OnValueChanged Перезвоните:

void OnValueChanged(BTH_LE_GATT_EVENT_TYPE eventType, PVOID eventOutParameter, PVOID context)
{
BLUETOOTH_GATT_VALUE_CHANGED_EVENT* e = (BLUETOOTH_GATT_VALUE_CHANGED_EVENT*)eventOutParameter;

std::cout << e->CharacteristicValue->DataSize << std::endl;
}

1

Решение

Я полагаю, что вы получаете данные через OnValueChanged Перезвоните? Это не предусмотрено в вашем коде, и проблема может быть где-то внутри. Если вы не решаетесь предоставить его код, я предлагаю вам выполнить следующие эксперименты во время «плохой» сессии:

  1. Удалите весь код из него, за исключением увеличения некоторого счетчика, чтобы узнать скорость передачи данных.
  2. Измерьте нагрузку на процессор. Если он приближается к полной загрузке ядра, то вы привязаны к процессору.
  3. Используйте профилировщик по вашему выбору, чтобы проверить, где ваш код тратит время.

Теперь, когда код для OnValueChanged доступен:

  1. Вывод на консоль с высокой скоростью может стать узким местом. Я предлагаю, чтобы вы подсчитывали только события и подсчитывали результат раз в несколько секунд, вот так:

    static DWORD lastTicks = GetTickCount();
    static DWORD count = 0;
    count++;
    
    DWORD ticksElapsed = GetTickCount() - lastTicks;
    if (ticksElapsed > 5000)
    {
    std::cout << "Rate: " << (double(count) / ticksElapsed) << " / sec" << std::endl;
    lastTicks = GetTickCount();
    count = 0;
    }
    
  2. Сделайте больше тестов (например, 5 пар, 5 соединений после каждой пары) и укажите частоту событий. Может случиться так, что падение ставки на самом деле связано с чем-то другим, а не с повторным соединением.

0

Другие решения