An implementation w/ retries w/ timeouts and callback
...not the most elegant solution, but it works... (logically... have no way to test since I do not have device at hand).
Using Promises may yield more elegant, concise code.
Number of tries and timeoutTimes are just sample values... Consult datasheet for reasonable values. Currently, they are inline hard coded, but they can be put into the C-onstants as well. I assuem that the correct status check registers and respective check value are used to determine readiness and completenes and retry condition.
// Read range function - expects callback with two (2) args:
// - err: error code of module: 32 not ready for | 64 not completed measurement
// - val: range in mm if module err == 0 else device error code (see Table 12)
VL6180X.prototype.readRange = function(cb) {
var rc = this._readRangeRC.bind(this); // ready check as funct w/ obj context
rc(5,10,rc,cb); // 5 tries, each retry 10ms (rcTimeoutTime) deferred
};
VL6180X.prototype._readRangeRC(triesLeft,rcTimeoutTime,rc,cb) {
// ready check for measurement - and start measurement
var s = this.read8(C.VL6180X_REG_RESULT_RANGE_STATUS);
if (s & 0x01) { // ready for measurement
this.write8(C.VL6180X_REG_SYSRANGE_START, 0x01); // start measurement
var cc = this._readRangeCC.bind(this); // check completion as f w/ obj ctx
cc(6,12,cc,cb); // 6 tries, each retry 12ms (ccTimeoutTime) deferred
} else { // not ready yet for measurement
if (--triesLeft>0) { // retry ready check delayed/deferred
setTimeout(rc,rcTimeoutTime,triesLeft,rcTimeoutTime,rc,cb); // retry
} else {
cb(32,s); // err in module = 32 / 0x20: not ready within...
} // ...tries-1 x rcTimeoutTime, device err code in val;
} // alternative: cb(32|s); // combined err and undefined for val
};
VL6180X.prototype._readRangeCC(triesLeft,ccTimeoutTime,cc,cb) {
// completion check for measurement - and read measurement and clear interrupt
var s = this.read8(C.VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO);
if (s & 0x04) { // completed measurement
var range = this.read8(C.VL6180X_REG_RESULT_RANGE_VAL); // read range in mm
this.write8(C.VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07); // clear interrupt
cb(0,range); // module and device err = 0, measured range in val
} else { // not completed measurement yet
if (--triesLeft>0) { // retry completion check delayed/deferred
setTimeout(cc,ccTimeoutTime,triesLeft,ccTimeoutTime,cc,cb); // retry
} else {
cb(64,s); // err in module = 64 / 0x40: not completed within...
} // ...tries-1 x ccTimeoutTime, device err code in val;
} // alternative: cb(64|s); // combined err and undefined for val
};
and usage in doStart():
var sensor1IID; // clearInterval(sensor1IID) stops sensor1 measuring
function doStart(){
initHW();
initSensor();
setTimeout(function(){ // initial delay/defer
sensor1IID = setInterval(function(){ // every 500ms get range w/...
sensor1.readRange(function(err,val){ // ...callback, logging...
if (err) { // ...error - if there is -...
console.log("ModuleError:", err, " - DeviceError:", val);
} else { // ...and range else
console.log("Sensor 1:",val,"mm");
}
})
},500);
},1);
}
The individual anonymous functions in setTimeout() and setInterval() can be put into named functions and just referred by by name.
You can drop onTimer(){...} or implement it differently.
Btw, your initial setTimeout(function() {}, 1); in doStart(){...} did nothing. It does not work as a delay of 1ms as you thought it would. It puts just an empty function in the list of timed things to do / to do after 1 ms. But the code flow keeps going... so no real controlled delay. You have to put the code that should be executed a ms later INTO the timeout function body to have that effect; but then it becomes async and you have to use callback / passed function).
Setting up ready check and completion check as functions bound to object makes them easy to use in the timeout. Alternative solution is to pass this - the object context as _ parameter. With other 'trickery' applied, the code looks then like:
// Read range function - expects callback w/ 2 mandatory and 1 optional args:
// - err: error code of module: 32 not ready for | 64 not completed measurement
// - val: range in mm if module err == 0 else device error code (see Table 12)
// - _: (optional) this / context, useful to get evtl more details from sensor
VL6180X.prototype.readRange = function(cb) {
this._readRangeRCS(this,5,10,cb); }; // 5 tries, defer retries 10ms
VL6180X.prototype._readRangeRCS(_,triesLeft,rcTimeoutTime,cb,s) { // rdyC+strt
if ((s=_.read8(C.VL6180X_REG_RESULT_RANGE_STATUS))&1) { // ready f/ measure
_.write8(C.VL6180X_REG_SYSRANGE_START,1); // start measurement
_._readRangeCCR(_._readRangeCCR,6,12,cb); // 6 tries, defer retries 12ms
} else if (--triesLeft>0) { // not ready yet: retry ready check deferred
setTimeout(_._readRangeRCS,rcTimeoutTime,_,triesLeft,rcTimeoutTime,cb);
} else { cb(32,s,_); } }; // err in module = 32 / 0x20: not ready f/ m/t
VL6180X.prototype._readRangeCCR(_,triesLeft,ccTimeoutTime,cb,s) { // complC+rd
if ((s=_.read8(C.VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO))&4) { // complete
var range = _.read8(C.VL6180X_REG_RESULT_RANGE_VAL); // read range in mm
_.write8(C.VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07); // clear interrupt
cb(0,range,_); // module & device err=0, measured range in val
} else if (--triesLeft>0) { // not completed yet: retry compl/n chk deferred
setTimeout(_._readRangeCCR,ccTimeoutTime,_,triesLeft,ccTimeoutTime,cb);
} else { cb(64,s,_); } }; // err in module = 64 / 0x40: not completed m/t
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.
@user109290
An implementation w/ retries w/ timeouts and callback
...not the most elegant solution, but it works... (logically... have no way to test since I do not have device at hand).
Using Promises may yield more elegant, concise code.
Number of tries and timeoutTimes are just sample values... Consult datasheet for reasonable values. Currently, they are inline hard coded, but they can be put into the C-onstants as well. I assuem that the correct status check registers and respective check value are used to determine readiness and completenes and retry condition.
and usage in doStart():
The individual anonymous functions in
setTimeout()
andsetInterval()
can be put into named functions and just referred by by name.You can drop onTimer(){...} or implement it differently.
Btw, your initial
setTimeout(function() {}, 1);
indoStart(){...}
did nothing. It does not work as a delay of 1ms as you thought it would. It puts just an empty function in the list of timed things to do / to do after 1 ms. But the code flow keeps going... so no real controlled delay. You have to put the code that should be executed a ms later INTO the timeout function body to have that effect; but then it becomes async and you have to use callback / passed function).Setting up ready check and completion check as functions bound to object makes them easy to use in the timeout. Alternative solution is to pass this - the object context as
_
parameter. With other 'trickery' applied, the code looks then like: