...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](function(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/forecasts/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).
Espruino is a JavaScript interpreter for low-power Microcontrollers. This site is both a support community for Espruino and a place to share what you are working on.
...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)... LOLgCtl 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:In case of failed, above - very lean - initializer control has no retries or error handling (vs the not so lean Tasker has).
1 Attachment