adabru / BleWinrtDll

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

Reading/Polling Buffer #4

Closed Joelx closed 3 years ago

Joelx commented 3 years ago

Hey, it's me again :D I hope I'm not bugging you by now ;) But I'd really need your advice again :/

So here's the thing: I'm packaging uint8 (sbyte) packages on my ESP32 and sending them as 1 byte packets over my characteristic: uint8_t package[1]; package[0] = convertRawAngleToDegrees(ams5600.getRawAngle()); pCharacteristicCommand->setValue(package, 1); pCharacteristicCommand->notify(); It does nothing but continiously sending out a current HALL sensor angle value over BLE. Then in Unity I have a Thread thats reading the buffer like you showed in your example "ReadPackage()" function: Impl.BLEData packageReceived; bool result = Impl.PollData(out packageReceived, true); First I couldn't figure out how to access the data without HUGE latency (half a minute or so), until I made a really unpretty workaround: On my ESP32 I created a full package with 512 one byte packages before sending it out. With this "throwing s*** on the wall until it sticks approach" I could access my values from Unity ;) This was fine for debugging, but using the data for a game/simulation input is far too slow :/

On the UWP platform one could use the DataReader Interface I guess? Do I have a similar option with your DLL? I have also an Android app where I can receive the same data perfectly with a BLE characteristic "Notify". I have tried it in block and non block mode btw, but I'm not sure wether I used it correctly.

Long story short: How can I read the LATEST momentary value sent out from my BLE device at any given time?

Like I said, I'm sorry to have to bother you again, but I have tried for several hours ;(

adabru commented 3 years ago

Using the BLE characteristic "Notify" seems right to me.

I'm not sure what may be the cause in your description. One thing you could try out is changing your bluetooth dongle. For my project I tried 3 different ones until the last one had the performance I'd expect from BLE. But I doubt that is the reason here.

The timespan of half a minute reminds me of another thing. I am also using an ESP32. The BLE-connection (scan + Connect()) normally takes less than a second. Also the subscription to the characteristic notify event is normally very fast. The data is sent with latencies around <10-50ms, I didn't measure more exactly yet. After subscription the ESP32 starts sending its packages. Now, if I restart the program and it tries to reconnect, I have to wait somewhere between 30-60s before it connects again. I found out that the ESP is sending out packages around 60s after subscrption. Then it will stop sending them if it didn't receive any response from Windows. I guess it will think the connection was lost. If I send any BLE package from Windows to the ESP the 60s-timer is reset. I am not sure why Windows can't connect to the ESP while it is sending its package-stream. My guess was data-congestion on ESP-side. In my case I added code to the ESP that reduces the timer to 1s, so that reconnection is faster.

Another problem I had was when I sent data from the ESP too fast. I guess that was also due to data congestion, probably on ESP side but could also be on dongle or Windows side. Enforcing a maximum packages per second rate should avoid that. That could explain why it starts working when your ESP waits 512 sensor readings before it sends a package.

adabru commented 3 years ago

Or you can try out writing packages to your ESP in a regular interval (<30s, e.g. 2s).

Joelx commented 3 years ago

Thanks again for the help. You definitely brought be on the right track here again :) I looked a bit closer inside your BleWinrtDll.cpp and it seems that you are actually using the Notification for characteristics subscription:

fire_and_forget SubscribeCharacteristicAsync(wchar_t* deviceId, wchar_t* serviceId, wchar_t* characteristicId, bool* result) { .... .... auto status = co_await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify);

So accessing Impl.PollData(out packageReceived, true); packageReceived.buf[0] should be sufficient for reading a byte from the characteristic. I was a bit on the wrong track in thinking that the problem was on my processing on the Unity side.

Turns out, the keyword for my problem is, like you mentioned, "data congestion". After reading your reply I tried one simple thing. On my ESP32 program, after sending my packet, I added a simple delay(50): pCharacteristicCommand->setValue(package, 1); pCharacteristicCommand->notify(); delay(50);

.. and this ACTUALLY seems to have done the trick. It's not that I hadn't thought about it, but idk like I said - I was a bit on the wrong track :) I will have to fiddle around with and tweak it a bit, but overall I think that may have solved my problem!

sbExperiential commented 1 year ago

@adabru Do you remember the dongle that you used?

adabru commented 1 year ago

@adabru Do you remember the dongle that you used?

Sorry, I don't ☹. It was provided in the office.