• @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.

    // 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
    
About

Avatar for allObjects @allObjects started