• I'm using Waveform to rapidly read a sequence of data, very successfully. The code is like this:

    wfrm = new Waveform(5)
    wfrm.on('finish', callback)
    setInterval(() => {
      wfrm.startInput(A0, 50)
    }, 500)
    function callback(buf) {
      // do something with buf

    Every 500 ms a 'task' is started to do an A/D converesion, 5 times, at 50 Hz.
    When ready the callback evaluates the passed Uint8Array (argument 'buf') very quickly -> no problem at all.
    Sometimes, however, there are errors

    Uncaught Error: Waveform is already running
    Uncaught InternalError: Timeout on ADC

    Sometimes the callback has to do more, including an HTTP call. This might take longer than the repat interval of 500 ms an cause these errors.
    Does a long running callback (longer than 500 ms) really make the Waveform complain at the next startInput, as I'm thinking?
    Is there a way to effectively make the callback appear as completed although parts of the code still need to be executed - like process.nextTick?

  • Are you stuck on the 500ms interval of grabbing the data? If not, make it 'self invoking': in the place where you know that the callback has completed, place a setTimeout(<startNextGrab>,1). With other asynchronous things going on in a callback - callbacks of a callback and callbacks of their callbacks... you get the point - it is very difficult to find this point. Promises get you out of this.

    Since all javascript is single threaded executed, no two pieces can be run at the same time. Therefore, (pseudo) semaphoring is possible. You could use that to set a variable to true - like skipGrab = true;, and in function invoked by the 500ms interval you check and skip the data grabbing. The challenge though is the same as above: find the place where to clear this flag and set it to false...

    You published only part of the code, so it is not that easy to have a clear pic what to do.

  • .. published part of the code: well, it is pretty nested.
    The code is basically a presence sensor that needs to react snappy (turning on the kitchen light!!).
    I like your suggestion of using setTimeout instead of the more rigid setInterval. Although I think this way the root cause of the (very rare but annoying) delays is only obfuscated.
    I was trying something in the line of setTimeout within the callback but it didn't help so far. I obviously missed some point :(

  • After putting process.memory() at the end of the callback the errors seem to be gone, along with the inexplicable delays.

    @allObjects: On top of this, I've replaced setInterval with setTimeouts as you suggested. This ensures that the intervals never overlap, allowing to use much shorter intervals.

    Leaves the - somewhat academic - question open why explicitly calling the garbage collection via process.memory was necessary. GC takes about 15 ms, while the idle time between intervals is about 200 ms. I don't mind calling it, quite the contrary. Just thought that > 100 ms were enough for Espruino to decide to do it itself.

  • That's a really interesting problem... Espruino will do automatic GC only when there's not much free memory available - if you're battery powered generally you won't want it wasting time compacting when it's not needed. Usually the heuristics used work out but it seems like in this case they're not working for you.

    Just a quick one - you're not calling analogRead(...) elsewhere are you? That can interfere with the one that happens inside an interrupt and can end up causing you problems.

  • I don't call analogRead() but there is another Waveform active (looking for brightness every 10 s).
    Does it have the same sort of interferences? In this case I'll need to coordinate them.

  • That should be fine - the Waveforms are all handled in the same IRQ so they won't ever occur at the same times.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview

delayed Waveform.onfinish preventing a new startInput?

Posted by Avatar for Steffen @Steffen