You are reading a single comment by @allObjects and its replies. Click here to read the full conversation.
  • Working with timeouts in an asynchronous, event driven context is the recipe for failure.

    No matter what, it is only the question of 'when' will it fail: there will always be - randomly - a case where the timeout is not long enough. Furthermore, this pattern robs you of the option to take care of other things you need to do... How would you get something done expedited and being able to set a real timeout that concludes with almost certainty that something went wrong and a redo / start over is required?

    You can go nested, which is also called 'callback hell', our can go with a (command or just data / character) FIFO - first-in-first-out - queue that is easy to write to and with a (dispatcher) worker that reads from the queue and does the command / send.

    I do not know your overall application, but I expect that after sending quite some information over HID to your other device, you wait for some events with event data to happen before you move on in Espruino, and you moving on depends on that event data.

    In multiple places of my forum published code you may find these patterns. A simple one, which just writes is a number id-ed message logger to track what the code does that, when no console is detected, writes blinking sequences in morse code for the message id. It even changes color - choses green or red led to blink for information/success messages vs. error messages. You find the code in lines 237..259 and a two typical usages in lines 29..295. After walking through the mentioned lines of code you will quite well understand what is going on an what I'm talking about when referring to a queue... especially since there are like two queues: one holds the the error or success indicator and the message code, and the other one then short and long di-and-dah-s for the morse code... The first elements select the LED to blink, almost like a command, and the second one sets up the second queue with the string with Ss and Ls with the short and long blinks.

    Let's get you started on the simple part: getting a string out over BLE HID.

    // setup of you convenience hidKeyBoardObject... (here or later)
    var hidKBD = ( // the singleton object that does all things
                   // what you want to do in encapsulated manner
    { string: ""   // the FIFO queue or buffer you feed with what
                   // you want to write as HID over BLE keyboard
                   // and feeds the tapping char by char from begin
    , type: function(s) { // feeding the FIFO w/ string to write
        this.string += s; // add string to FIFO w/ simple concat
        if (this.string.length = s.length) { // length are the same
                          // which means that all was tapped and
                          // a new tapping streak has to be started
          this._send(this.string.charAt(0)); // get first char out
      } }
    , _send: function(c) { // tapping the keyboard w/ a char
        kb.tap(kb.KEY[c],0,this._sent.bind(this)­); // invoke tap and
                           // tell tap to invoke ._sent() when done.
                           // .bind(..) is some JS idiom you google.
      }
    , _sent: function() {  // is invoked by tapping as callback when
                           // tapping has completed...
        this.string = this.string.substring(1); // remove tapped char
        if (this.string.length > 0) { // not done yet with all chars
          this._send(this.string.charAt(0)); // tap next char... ;)
      } }
    } );
    
    // setup and other code functions of yours (here or before hidKBD)
    
    function onInit() {
       // invoke your set up code as needed (init and getting connections)
       hidKBD.type("ABC");
       hidKBD.type("XYZ");
    }
    

    Lines 1..25 do what inline commented/documented.

    Lines 31 and 32 show a usage (EDITED to this as pointed out by post #22). Even though are executed more or less right one ofter the other, all is perfect. The second one may have been executed while the send of the first character of the first one has not even completed yet... ;-)

    Note that I used kb.KEY[] freely without looking at the constraints... (which there are in order to send on character keys... So you have to come up with some notation / patterns like shift-in/out of command keys -like: "ABC~RETURN~XYZ~RETURN~" (1st ~ is shift-in and 2nd is -out) and respective code to handle such sorts of 'strings' to type / tap... Looks like a fun project to me.)

    Next step would be to wrap your action code and hidKBD into a state machine that works of a command queue to do what is needed:

    • some input / sensors / timeouts / intervals feed the command queue with:
      • commands that invoke hidKBD.type(..)
      • commands the invoke some action functions other hidKBD.type(..)
      • commands that read sensors / wait for any kind of input
    • and each execution of these commands can add command to your command queue.

    As the name hints, the command queue holds on to a string of commands - array of commands / command objects - rather than just a string of characters . But the implementation pattern is the very same:

    • feed FIFO queue: .type(..), .exec(..)
    • do 1st item in queue: ._send(..), ._exec(..)
    • when item done, do: ._sent(..), ._excd(..)

    When you get there, we can feast on it with details how a command object can look like, such as real object or array / array of scalars and arrays etc, to get things code-wise done as expedient
    as possible.

    Related topics to your 'coding challenges' are:

    NB: having (function) names with with leading underscore (_) indicate that these are things private to the object and should NOT be referenced or used from the outside.

About

Avatar for allObjects @allObjects started