• ...yep, the abstraction and reduction to the minimum made it look like this... Actual code is this code below and hardware as attached pic... and it works pretty neat... it is a way to get out of callback hell and reduce it to sequence hell... I do not know what is better... global controller gCtl s the 'drug' to connect all kinds of (different types of) 'crystals' with meth(ods)... in correct sequence and with set forth configuration(s)... LOL

    // /ESP8266/xyz/abc.js
    
    // g(lobal)Log(ging) function:
    var gLog = function(v) { console.log(v); };
    
    // g(lobal) C(on)t(ro)l(ler) that handles:
    // - sequencing of initializers
    // - run workers after save() and power-cycle / power-on reset
    var gCtl = 
    { is:[], i:-1 // (registered) i(initializer)s, index for iterating initializers 
    , adi: function(i) { this.is.push(i); } // add/register initializer
    , ini: function(ok,str) { if (this.i >= 0) { // invoke registered initializers
        gLog("i[" + this.i + "]" + ((str)?str:"") + ": " + ((ok)?"ok":"failed")); } 
        if (ok) { if (++this.i < this.is.length) { var _t = this; 
          setTimeout(function(){_t.is[_t.i](functi­on(ok,txt){_t.ini(ok,txt);});},1);}  
        } else { /* is[i]() failed */
          /* code to handle failures... may be retries... not built/used yet */
      } }
    , run: function() { this.i = -1; this.ini(true); } // run() invoked in onInit()
    };
    
    /* 
     * CONFIGS AND MODULES
     */
    
    // g(lobal)D(isplay) and its DSP_C(onfiguration) objects
    var gD = null, DSP_C = 
    { md:require("ILI9341")
    , spi:SPI1
    , spiC: {sck:A5, miso:A6, mosi:A7, baud:1000000}
    , dc:B10, cs:B1, rst:B13
    };
    
    // g(lobal) T(e)rm(inal) and its T_C(onfiguration) objs using gD(isplay) and 
    var gTrm = null, T_C = {w:240, h:320, lh:12};  gTrm = 
    { c:T_C 
    , cl: 0 
    , p: function(l,nl) { var c = this.c;
        if (this.cl + c.lh > c.h) { this.cl = 0; }
        gD.setColor(0,0,0); gD.fillRect(0,c.cl,c.w-1,c.l + (c.lh*2) - 3);
        gD.setColor(1,1,1); gD.drawString(l,0,this.cl);
        if (nl) { this.cl += c.lh; }
      } 
    };
    
    // http and its HTTP_C(onfiguration) objs - mainly list of urls 
    var http = null, HTTP_C =
    { md:require("http") 
    , urls:
      [ "http://www.pur3.co.uk/hello.txt"
      , "http://weather.noaa.gov/pub/data/foreca­sts/marine/coastal/pz/pzz535.txt"
      ]
    };
    
    // g(lobal) W(ifi) and its WIFI_C(onfiguration) objects
    var gW = null, WIFI_C =
    { md:require("ESP8266WiFi_0v25")
    , ser:Serial2, bd:115200, serC:{tx:A2, rx:A3}
    , ssid:"myWLAN", lak:"myWLANpassword" 
    , ip:"", p:80 
    };
    
    /* 
     * INITIALIZERS
     */
    
    // display initializer with callback 'cb' to return control to gCtl sequencer
    // does display setup and connect spi to it as set forth in configuration and
    // clears display
    gCtl.adi(function(cb){ var c = DSP_C;
      c.spi.setup(c.spiC);
      gD = c.md.connect(c.spi, c.dc, c.cs, c.rst, function(){ 
        gD.clear();
        cb(true,"display");
      }); }
    );
    
    // wifi initializer 1 (create wifi) with callback 'cb' to return control to gCtl sequencer
    // does display setup and connect serial to it as set forth in configuration and
    // creates g(lobal)W(ifi) object
    gCtl.adi(function(cb){ var c = WIFI_C;
      c.ser.setup(c.bd, c.serC);                       
      gW = c.md.connect(c.ser, function(err){                     
        if (err) { cb(false,"wifi.reset: " + err); }
        else { cb(true,"wifi.reset"); }
      }); }
    );
    // wifi initializer 1 with callback 'cb' to return control to gCtl sequencer
    // does display setup and connect via spi to it as set forth in configuration
    gCtl.adi(function(cb){ var c = WIFI_C;
      gW.connect(c.ssid, c.lak, function(err){                         
        if (err) { cb(false,"wifi.connect: " + err); }
        else { cb(true,"wifi.connect"); }
      }); }
    );
    
    /*
     * WORKERS
     */
    
    function getb(udx) { var c = HTTP_C;
      gLog(c.urls[udx] + ":");
      c.md.get(c.urls[udx], function(res){
        res.on('data', function(dta){
          // gLog(dta);
          gTrm.p(dta,true);
        });
      });
    }
    
    function getm(udx) { var c = HTTP_C;
      gLog("---> " + c.urls[udx] + ":");
      var d = true, l = "", ol, nl;
      c.md.get(c.urls[udx], function(res){
        res.on('data', function(dta){
          l = l + dta;
          var ls = l.split("\n"), lm = ls.length - 1, lx = -1;
          while (++lx < lm) { ol = (l = ls[lx]).length;
            if ((d = d && (l != "$$"))) {
              while (ol > (nl = (l = l.replace(" OR LESS","|<")).length)) ol = nl; 
              while (ol > (nl = (l = l.replace(" TO ","~")).length)) ol = nl; 
              while (ol > (nl = (l = l.replace(" TO","~")).length)) ol = nl; 
              gTrm.p(l,true);
            } }
          l = ls[lm]; ls = null; 
        });
      });
    }
    
    function onInit() { gCtl.run(); }
    

    gCtl is global Control for initializers... and the discussed line is line # 15, which - in this case uses nested anonymous functions... (Above code does include application main flow/control yet... it is next: for example to store the info/forecast and go to a deep sleep until next user action to show stored info or info/forecast expires - zoom in on pic below to read what is displayed... gTerm - terminal - is not working correct yet: override / scroll...). setTimeout() is used to break the invocation chaining / avoid nested calling / to do stack 'reset' (to give Espruino a memory relieve...)

    The global controller for initializations is used to separate configuration from initialization - first - and - second - to have reliable constructs to call from onInit() afer saving the code and re-powering the device disconnected from Web IDE. An earlier approach was the Tasker - Task synchronizer - kind of a 'purposed' Promise. Another serialization approach has been discussed/suggested in conversation [How to carry out functions in a sequential manner]. (http://forum.espruino.com/conversations/­276388).

    Latter allowed to put calls like commands into a fifo and execution has to await an ack before moving on to the next command... almost the same as making a callback.

    Log output of above initializer produced in line 13 looks like:

    i[0] display: ok
    i[1] wifi.reset: ok
    i[2] wifi.connect: failed
    

    In case of failed, above - very lean - initializer control has no retries or error handling (vs the not so lean Tasker has).


    1 Attachment

    • PICO_ESP8266-01_ILI9341_NOAA_Msgs.jpg
About

Avatar for allObjects @allObjects started