• [1v64] - Hi,

    thanks for the friendly - (somewhat) embarrassing ;-) - 'hint' to look for setWatch(). I must have read '...that Espruino does not support hardware interrupts...' in a very early/old (or not very informed/educated) publication. That's why I came up with a software solution - shared below with - for now - only a few comments. I'm a bit embarrassed because my style of approaching a new language (extension) or library is to study the whole API/specs first before venturing into doing by mapping my programming patterns into particular target designs/implementations...

    But I just got the board from Adafruit and had to get my hands dirty to quench my curiosity. The setWatch() will not only simplify the code dramatically, but free up lots of cycles for other things than just watching and interpreting 'bug leg moves' and setting up and handling of timeouts. Interesting is the similarity of some of the parameters - last but not least the debouncer. The debouncer's implementation had to wait until my day job concluded. But with setWatch(), it may not even come to actual life. (So far, the hardware button is not worn out yet and therefore the software buttons works pretty predictable. More details following the code).

    Beside the button handling, the code has some interesting features. Implemented in a so called 'JS survival/micro framework' w/ single global muej are:

    1. Simple, variable controlled LED on/off switching led.(id,booleEvaluating) method.
    2. Software .tme w/out external components to get milliseconds since start-up.
    3. A .pub()(lish) / .sub()(scribe) mechanism for tight integration but loose coupling.
    4. An .itr(array,function) iterator method w/ function(element,index,array){...}
    5. Multiple software buttons using the only one onboard hardware BNT1 button.
    6. Running led light started/stopped and made faster/slower with one (1) single hardware but three (3) software buttons.

    And all this in almost pure, very easy to use, object-oriented fashion.

    var muej = // js survival framework - (f)markus@muet.com = FREE w/ reference
    { lds: [LED1,LED2,LED3]
    , led: function(i,v) { this.lds[i].write((v)?1:0); }
    , tme: 0
    , tms: function(y,m,d,H,M,S) { this.tme = new Date(y,m,d,H,M,S).getTime(); } // (?) 
    , tmr: function(p) { this.tme = this.tme + p; setTimeout("muej.tmr(10)",10); }
    , sbs: {}
    , sub: function(t,f) { var ss = this.sbs[t]; ss = (ss) ? ss : (this.sbs[t] = []); ss.push(f); }
    , pub: function(t,ps) { this.itr(this.sbs[t],function(s){ s.apply(null,ps); }); }
    , itr: function(a,f,s) { if (a) { var i = (s) ? s : 0; var m = a.length; while (i < m) {f(a[i],i,a); i++; } } }
    , log: function(vs) { console.log(vs.join(" ")); }
    };
    
    var RLL = // running led lights
    { P: 160       // on Period [ms]
    , i: 2         // current LED index
    , o: null      // on timeout
    , a: false     // running light state (active)
    , t: function() { this.r(this.a = !this.a); this.l(["i",(this.a) ? "on" : "off"]); } // toggle start/stop
    , f: function() { var p = this.P / 2; this.P = (p < 10) ? 10 : p; this.l(["i","faster",this.P]); } // faster
    , s: function() { this.P = this.P * 2; this.l(["i","slower",this.P]); } // slower
    , r: function(s) { // run(1) = start / run(0) = stop
        muej.led(this.i);
        if (s) {
          this.i = (this.i < 2) ? this.i + 1 : 0;
          muej.led(this.i,1);
          this.o = setTimeout("RLL.r(1)",this.P);
        } else {
          clearTimeout(this.o);
        }
      }
     ,l: function(vs) { muej.log(["RLL: "].concat(vs)); } 
    };
    
    var Btn1 = // SW buttons aka A. Morse by muet
    { B: 100       // min Short press / debounce [ms] - not used yet
    , S: 150       // max Short press [ms]
    , L: 250       // min Long press [ms]
    , P: 220       // min pause [ms]
    , b: 0         // last button bounce state ts [ms]
    , t: 0         // last butten state change ts [ms]
    , p: false     // last button state (pressed)
    , k: ""        // key
    , c: function() { // check BTN1 (detect 'up' and toggle start/stop
        var n = muej.tme; // now
        // muej.led(0,1); muej.led(0);  // dbg 1
        var p = digitalRead(BTN1) == 1;
        // muej.led(1,p); muej.led(1); // dbg 1 , 2
        if (p) { // pressed
            if (!this.p) { // was !pressed
              // muej.led(2,1); muej.led(2); // dbg 1, 2
              this.t = n;
              this.p = true;
          }
        } else { // not pressed
          if (this.p) { // was pressed
            // muej.led(2,1); muej.led(2); // dbg 1
            this.k = this.k + ((n - this.t < this.L) ? "S" :"L");
            this.t = n;
            this.p = false;
          } else { // was !pressed
            if (n - this.t > this.P && this.k.length > 0) {
              var _k = this.k; var _n = n; this.k = ""; this.t = n;
              // muej.led(0,1); muej.led(0); // dbg 2
              // console.log(_k); // dbg 3
              setTimeout(function(){ muej.pub(_k,[_n]); },1);
            }
          }
        }
        setTimeout("Btn1.c()",100);
      }
    };
    
    muej.tmr(0);
    muej.sub("S",function(){ RLL.t(); });
    muej.sub("SS",function(){ RLL.f(); });
    muej.sub("LL",function(){ RLL.s(); });
    Btn1.c();
    

    Originally, I had planned to make the code the subject of a multi part post/series with tutorial like comments... A perfect, fun tutorial that requires just the board and still have a UI and UI interaction. Now it is out there as a whole... and already outdated... :(]
    Time permitting, the series as tutorial may still happen... in a refactored form using setWatch(). For now, just some information about the implementation of the (quasi unlimited number of) software buttons:

    Most interesting is the button BTN1 handling and making it software-wise multiple buttons by loaning the ideas from http://en.wikipedia.org/wiki/Morse_code, developed 1836 by Samuel B. F. Morse... some 'things and thoughts' just never go out of style! - I was trained on it in the army in the signal corps.

    The Bnt1 object detects sequences of short and long presses. It decodes them into strings of "S"s and "L"s; for example, two short presses are decoded into "SS", and a short, long, and short press into "SLS". Once detected, the string is used as the topic to be published with some other parameters, such as the time. Any subscriber will be notified aka the subscribed function is invoked.

    In the running light RLL example, one short press ("S" topic) toggles the lights on and off. Two short presses ("SS" topic) make it run faster, and two long presses ("LL" topic) make it run slower. Try it yourself...

    PS: Gordon, did you notice the IDE's syntax coloring issue in line 8?

About

Avatar for allObjects @allObjects started