• I have this so far, for writing as fast as possible to a gatt characteristic. The timing seems to vary though, and certainly the writing isn't 'continuous'. Is there a way to do better? I want to write 10 times per second, as stable as possible.

    interval = 100;
    function writeValue() {
        return new Promise(function(resolve, reject) {
            if (!isConnected()) {
                console.log("not connected");
                setTimeout(function() {writeValue().catch(function() {});}, 1000);
                reject();
                return;
            }
    
            char.writeValue(calculateValue()).then(f­unction() {
                setTimeout(function() {writeValue().catch(function() {});}, interval);
                resolve();
            }).catch(function(e) {
                console.log(e);
                setTimeout(function() {writeValue().catch(function() {});}, interval);
                reject();
            });
        });
    }
    

    I'm most familiar with writing in C or Python, so unfamiliar with Promises. I think I need to use them here, since if I simply call char.writeValue(calculateValue()) in a loop then often there's an error that BLE is busy (from https://github.com/espruino/Espruino/blo­b/31c67baa20302b80aafc5b355aade9028a37c4­71/libs/bluetooth/jswrap_bluetooth.c#L78­ )

  • Hi,

    It's not out of the question but I think it's probably a bit early to assume it's an error in the interpreter source code.

    You may be hitting issues with the connection interval. Espruino negotiates how fast it'll talk with another device, and it may end up (especially for the first few seconds) having only a few intervals a second (so not enough for 10Hz).

    When you connect to a device, you can set the connection interval you want as an option - see http://www.espruino.com/Reference#l_Blue­toothRemoteGATTServer_connect - and setting that to something far below 100ms should really help.

    The code you have won't manage 10Hz because it's running the next step 100ms after the write completes, and the write definitely won't be instantaneous.

    Once you've got a high enough connection interval, something like this should be possible:

    setInterval(function() {
      char.writeValue(calculateValue());
    }, 100);
    

    But you're right, writeValue may cause an exception if the data hasn't been sent yet (eg it fails first and has to retry).

    In that case it should be possible to do something like this:

    var promise = Promise.resolve();
    setInterval(function() {
       if (!isConnected()) { // if not connected, remove previous promises
        promise = Promise.resolve();
        return;
      }
      promise = promise.then(() => char.writeValue(calculateValue()));
    }, 100);
    

    So now the next send is always queued up behind the last, even if the last hasn't completed. Obviously you might want some checking here because if you end up with a low connection interval, the chain of promises will just keep getting longer until you run out of memory!

    If you want to push output as fast as possible you could also see what I do for the UART code: http://www.espruino.com/modules/ble_simp­le_uart.js

  • Thanks @Gordon . The connection interval helps immensely! Thank you for directing me to that.

    I've just numbered the below so that it's clear they are unrelated to each other!

    (1)

    I will work through how to add a some good error handling. Currently I think one of the "tasks" got "lost", so any writeValue() now fails with:

    Uncaught Error: Unhandled promise rejection: Error: BLE task 6 is already in progress
    

    (2)

    I've held BTN3, launched my app again, but my target BLE device has maintained the connection state, yet my app doesn't know about that. For robustness, maybe I need to store gatt in some kind of global that persists outside my app?

    (3)

    In http://www.espruino.com/modules/ble_simp­le_uart.js -

        function sender(resolve, reject) {
          if (text.length) {
            c.writeValue(text.substr(0,20)).then(fun­ction() {
              sender(resolve, reject);
            }).catch(reject);
            text = text.substr(20);
          } else  {
            resolve();
          }
        }
    

    Why is it catch(reject), not catch(reject()) ?

  • Currently I think one of the "tasks" got "lost", so any writeValue() now fails with: BLE task 6

    Ok, task 6 is BLETASK_CHARACTERISTIC_WRITE, so it sounds like a write got lost somehow as you say. It's an odd one as we've had this bluetooth functionality for a while and this is the first time I've had a complaint about the issue. I'll have to see if I can reproduce it.

    From your previous link though:

    Is there a case where "BLE_GATTC_EVT_WRITE_RSP" does not occur?
    No, but it can be either success or an error.

    So unless I'm mis-reading, we seem to be doing the right thing...

    target BLE device has maintained the connection state

    It really shouldn't have... long-press BTN3 tears down everything (including connection state) and restarts it from scratch, so I'm not really sure what's going on there.

    Why is it catch(reject), not catch(reject()) ?

    You're passing a function into catch which should be called when an error occurs. If you do catch(reject()) then reject() is executed immediately (probably even before the first bit of the promise has executed), and the result of that function call is passed into catch - probably not what you intend :)

  • Why is it catch(reject), not catch(reject()) ?

    You're passing a function into catch which should be called when an error occurs. If you do catch(reject()) then reject() is executed immediately (probably even before the first bit of the promise has executed), and the result of that function call is passed into catch - probably not what you intend :)

    Oh yes, of course, my lack of JS familiarity forgot that I had this in my mind:

    .catch(function() {reject();})
    

    which, I suppose is actually the same thing as

    .catch(reject);
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How to write to gatt characteristic as fast as possible?

Posted by Avatar for John @John

Actions