bleno-mac
bleno-mac copied to clipboard
Writing multiple values quickly on a characteristic fails
I use bleno to emulate a BLE device, which writes values on a characteristic as data packets.
When I switched to Mojave, I started using bleno-mac, and my emulator stopped working.
The only output I got is peripheralManagerIsReadyToUpdateSubscribers
.
Seems it is due to too much data being written.
I was able to verify this by:
- setting up breakpoints before writing data, thus slowing the rate
- setting up a delay in between the writes
Interesting! I won't have a chance to look at it this week I don't think, and nothing comes immediately to mind.
I'll try setting up a purely native harness and see if it's a macOS issue, or an issue with the dispatching across to JS.
How much data are you writing? Do you have a small repro you can provide?
I'll try to provide an example, though basically I call updateValueCallback
twice in a row.
From my understanding, there is some backpressure management in the Apple framework. So, there should probably be some queueing in place in order to avoid this.
As a reference : https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393248-peripheralmanagerisreadytoupdate
Ahh right, of course, that would make sense! That should be (hopefully) be simple enough. I remember thinking about that, and if(& how) that would be exposed back to the JS side without complicating the non-Apple implementations. I think a "fire and forget" from the JS side is probably fine since it's all async anyway, but I'm not sure if there are cases where you'd want to know when a value is queued (and eventually fired). Thoughts?
My views are the following: keep it simple (fire and forget) and hide it in the Apple implementation, seems to make quite a lot of sense.
Source: I do it this way on Android ;)
The alternative would be to return a Promise, letting us know when and if the write completes
I agree! 👍 I'll see what I can manage, I'll let you know when I get a chance to look at it.
Awesome, if I get some time I'll try to dig in the native code and documentation too.
Hey @saiimons and @notjosh did you guys ever figure out how to get this to work? I'm hitting it now too.
Well I experimented and found this works, not sure I'm happy about it but if it helps... I tried promises but not very hard, it seems like it's a timing issue because timeout doesn't work.
function chunkData(str, size) {
const chunks = new Array(Math.round(str.length / size));
let newo = 0;
for (let i = 0, o = 0; i < chunks.length; i += 1, o = newo) {
newo += size;
chunks[i] = str.substr(o, size);
}
return chunks;
}
function wait(ms) {
const waitTill = new Date(new Date().getTime() + ms);
while (waitTill > new Date()) { /* Don nothing */ }
}
const chunks = chunkData('Bob is your uncle and stuff like that', maxMessageResponseValueSize);
chunks.forEach((chunk) => {
const data = Buffer.from(chunk, 'utf-8');
console.log(chunk);
messageUpdateValueCallback(data);
wait(10);
});
Do either of you happen to have a simple repro project? I'm sure it's easy enough, but I don't know how many "multiple" is, or how quickly we're talking.
I think I know the issue, but not certain.
@notjosh here is a gist, it's a dumbed down version of what I am working on and has not actually been run as is but should work https://gist.github.com/cwhittl/2bc19de82df28f2b415b8cd77180d2f4
If you remove the wait you only see the first callback on my android app, if you leave the wait it does all of them