adabru / BleWinrtDll

BLE for Unity 3d in Windows without UWP.
Do What The F*ck You Want To Public License
168 stars 52 forks source link

SubscribeCharacteristicAsync error #30

Closed tufeixp closed 2 years ago

tufeixp commented 2 years ago

it's working when query fe55 / 0001 bytes from a google daydream controller, but, report failure in SubscribeCharacteristicAsync() / characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(), when I'm trying to get data from 180a / 2a25 (or 180f/2a29 which is the 1 byte battery data), which was supposed to be a string of some 34 bytes serial numbers. Would you help me to figure out why?

adabru commented 2 years ago

Maybe related: https://github.com/adabru/BleWinrtDll/issues/7, https://github.com/adabru/BleWinrtDll/issues/19, https://github.com/adabru/BleWinrtDll/issues/21, https://github.com/adabru/BleWinrtDll/issues/20

Hi @tufeixp, the error message could help you.

tufeixp commented 2 years ago

Hi @adabru , I have ran the Microsoft sample project and it does not have this problem, would you please help me to debug this issue 'cause I'm really not good at C++ coding :-|

adabru commented 2 years ago

I have ran the Microsoft sample project and it does not have this problem

This seems like a good start.

Do you receive any error message? Also make sure that you use the version after February with the ui fix (https://github.com/adabru/BleWinrtDll/pull/25).

tufeixp commented 2 years ago

Sure, I have the ui fix. The error message is as simple as "Subscribe Characteristic catch: The attribute cannot be written"

adabru commented 2 years ago

I did a short google, maybe this can help: https://stackoverflow.com/questions/50596561/writeclientcharacteristicconfigurationdescriptorasync-not-working-in-uwp#50604121

You can also compare the subscribing code (https://github.com/adabru/BleWinrtDll/blob/main/BleWinrtDll/BleWinrtDll.cpp#L482) to the winrt code of the Microsoft sample.

For faster debugging you may consider using the DebugBle program. You can also print to the console from the dll like in https://github.com/adabru/BleWinrtDll/blob/main/BleWinrtDll/BleWinrtDll.cpp#L108.

tufeixp commented 2 years ago

Thanks @adabru I looked into the code, and find it's my miss-understanding lead me to the question, that read-only params eg. the serial infor can Not be "notified" other than query. I understand the current code does not implement a query method, and I tried to code in Cpp and able to read the correct info I need, however, due to my lacking of coding experience, the code will freeze and fail to pass over the data to C#, here's my simple code:

fire_and_forget ReadDataAsync(BLEData data) { { lock_guard lock(characteristicQueueLock); } auto characteristic = co_await retrieveCharacteristic(data.deviceId, data.serviceUuid, data.characteristicUuid); GattReadResult result = co_await characteristic.ReadValueAsync(); if (result.Status() == GattCommunicationStatus::Success) { auto dataReader = DataReader::FromBuffer(result.Value()); auto output = dataReader.ReadString(dataReader.UnconsumedBufferLength());

    Characteristic charStruct;
    wcscpy_s(charStruct.uuid, sizeof(charStruct.uuid) / sizeof(wchar_t), to_hstring(characteristic.Uuid()).c_str());
    wcscpy_s(charStruct.userDescription, sizeof(charStruct.userDescription) / sizeof(wchar_t), output.c_str());
    {
        lock_guard queueGuard(characteristicQueueLock);
        characteristicQueue.push(charStruct);
        characteristicQueueSignal.notify_one();
    }
    saveError(L"%s:%d read done: %s", __WFILE__, __LINE__, charStruct.userDescription);
}

}

void ReadData(BLEData data) { ReadDataAsync(data); }

adabru commented 2 years ago

Glad you found the problem! Do you want a blocking, a non-blocking, or an optionally blocking read function?

tufeixp commented 2 years ago

A none blocking read function is needed~

adabru commented 2 years ago

Ok. The code actually already looks quite nice.

The first lock_guard looks redundant?

I guess you can use dataQueue instead of characteristicQueue. You could also reuse the function PollData without modification. Furthermore you would have more space for your data. The size limit could be a reason for the crash.

And maybe a try catch would be helpful to prevent a freeze.

tufeixp commented 2 years ago

Here's the code finally works:

fire_and_forget ReadDataAsync(BLEData data) {
    {
        lock_guard lock(dataQueueLock);
    }
    auto characteristic = co_await retrieveCharacteristic(data.deviceId, data.serviceUuid, data.characteristicUuid);
    GattReadResult result = co_await characteristic.ReadValueAsync();
    if (result.Status() == GattCommunicationStatus::Success) {
        auto dataReader = DataReader::FromBuffer(result.Value());
        auto output = dataReader.ReadString(dataReader.UnconsumedBufferLength());

        BLEData data;
        wcscpy_s(data.characteristicUuid, sizeof(data.characteristicUuid) / sizeof(wchar_t), to_hstring(characteristic.Uuid()).c_str());
        wcscpy_s(data.serviceUuid, sizeof(data.serviceUuid) / sizeof(wchar_t), to_hstring(characteristic.Service().Uuid()).c_str());
        wcscpy_s(data.deviceId, sizeof(data.deviceId) / sizeof(wchar_t), characteristic.Service().Device().DeviceId().c_str());

        data.size = output.size();
        memcpy(data.buf, output.data(), data.size);
        {
            lock_guard queueGuard(dataQueueLock);
            dataQueue.push(data);
            dataQueueSignal.notify_one();
        }
        //saveError(L"%s:%d read done: %s", __WFILE__, __LINE__, output.c_str());
    }
}