BME280 module refactor

Posted on
  • The BME280 module is a bit unnecessarily large, so I'm refactoring it, primarily to remove unnecessary variable declarations and debugging code, reduce the length of non-minifiable public method names and generally tidy up a bit.

    Is there a protocol for this sort of thing, eg discussing here, or should I just change and create a pull request?

    FWIW here's the code, anything else?

    /* Copyright (c) 2015 Masafumi Okada. See the file LICENSE for copying permission. */
    /*
    Read Temperature, Pressure, and Humidity from Bosch Sensortec's BME280 sensor module.
    */
    
    var C = {ADDR: 0x76}
    
    function BME280(_i2c) {
      var t = this;
      t.i2c = _i2c;
    
      var osrs_t = 1;  //Temperature oversampling x 1
      var osrs_p = 1;  //Pressure oversampling x 1
      var osrs_h = 1;  //Humidity oversampling x 1
      var mode = 3;    //Normal mode
      var t_sb = 5;    //Tstandby 1000ms
      var filter = 0;  //Filter off
      var spi3w_en = 0;//3-wire SPI Disable
    
      var ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
      var config_reg = (t_sb << 5) | (filter << 2) | spi3w_en;
      var ctrl_hum_reg = osrs_h;
    
      t.wReg(0xF2, ctrl_hum_reg);
      t.wReg(0xF4, ctrl_meas_reg);
      t.wReg(0xF5, config_reg);
    
      t.rCoeffs();
    }
    
    /* Concatinate two Uint8Arrays */
    BME280.prototype.concatU8 = function(a, b) {
      var c = new Uint8Array(a.length + b.length);
      c.set(a);
      c.set(b, a.length);
      return (c);
    };
    
    /* Convert two UInt8 value into one "signed" number */
    BME280.prototype.convS16 = function(ub1, ub2) {
      var value = (ub1 << 8) + ub2;
      if (value & 0x8000) {
        value = -((value - 1) ^ 0xffff);
      }
      return (value);
    };
    
    /* Write single byte to register reg_address */
    BME280.prototype.wReg = function(reg_address, data) {
      this.i2c.writeTo(C.ADDR, [reg_address, data]);
    };
    
    /* Read single byte from register reg*/
    BME280.prototype.read8 = function(reg) {
      this.i2c.writeTo(C.ADDR, reg);
      return this.i2c.readFrom(C.ADDR, 1)[0];
    };
    
    /* Read and store all coefficients stored in the sensor */
    BME280.prototype.rCoeffs = function() {
      var t = this, i = t.i2c;
      i.writeTo(C.ADDR, 0x88);
      var data = i.readFrom(C.ADDR, 24);
      i.writeTo(C.ADDR, 0xA1);
      data = t.concatU8(data, i.readFrom(C.ADDR, 1));
      i.writeTo(C.ADDR, 0xE1);
      data = t.concatU8(data, i.readFrom(C.ADDR, 7));
    
      t.T1 = (data[1] << 8) | data[0];
      t.T2 = t.convS16(data[3], data[2]);
      t.T3 = t.convS16(data[5], data[4]);
    
      t.P1 = (data[7] << 8) | data[6];
      t.P2 = t.convS16(data[9], data[8]);
      t.P3 = t.convS16(data[11], data[10]);
      t.P4 = t.convS16(data[13], data[12]);
      t.P5 = t.convS16(data[15], data[14]);
      t.P6 = t.convS16(data[17], data[16]);
      t.P7 = t.convS16(data[19], data[18]);
      t.P8 = t.convS16(data[21], data[20]);
      t.P9 = t.convS16(data[23], data[22]);
      t.H1 = data[24];
      t.H2 = t.convS16(data[26], data[25]);
      t.H3 = data[27];
      t.H4 = (data[28] << 4) | (0x0F & data[29]);
      t.H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); 
      t.H6 = data[31]; 
    
    };
    
    /* Read Raw data from the sensor */
    BME280.prototype.rdRaw = function() {
      var t = this;
      t.i2c.writeTo(C.ADDR, 0xF7);
      var data = t.i2c.readFrom(C.ADDR, 8);
      t.pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
      t.temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
      t.hum_raw = (data[6] << 8) | data[7];
    };
    
    /* Calibration of Temperature, algorithm is taken from the datasheet */
    BME280.prototype.cal_T = function(adc_T) {
      var t = this, 
          v1 = ((adc_T) / 16384.0 - (t.T1) / 1024.0) * (t.T2),
          v2 = (((adc_T) / 131072.0 - (t.T1) / 8192.0) * ((adc_T) / 131072.0 - (t.T1) / 8192.0)) * (t.T3);
      t.t_fine = (v1 + v2);
      return 100 * t.t_fine / 5120.0;
    };
    
    /* Calibration of Pressure, algorithm is taken from the datasheet */
    BME280.prototype.cal_P = function(adc_P) {
      var v2, p, t = this, v1 = (t.t_fine / 2.0) - 64000.0;  
      v2 = v1 * v1 * (t.P6) / 32768.0;
      v2 = v2 + v1 * (t.P5) * 2.0;
      v2 = (v2 / 4.0) + ((t.P4) * 65536.0);
      v1 = ((t.P3) * v1 * v1 / 524288.0 + (t.P2) * v1) / 524288.0;
      v1 = (1.0 + v1 / 32768.0) * (t.P1);
      if (v1 === 0.0) {
        return 0; // avoid exception caused by division by zero
      }
      p = 1048576.0 - adc_P;
      p = (p - (v2 / 4096.0)) * 6250.0 / v1;
      v1 = (t.P9) * p * p / 2147483648.0;
      v2 = p * (t.P8) / 32768.0;
      p = p + (v1 + v2 + (t.P7)) / 16.0;
      return p;
    };
    
    /* Calibration of Humidity, algorithm is taken from the datasheet */
    BME280.prototype.cal_H = function(adc_H) {
      var t = this, v1 = (t.t_fine - (76800));
      v1 = (((((adc_H << 14) - ((t.H4) << 20) - ((t.H5) * v1)) +
        (16384)) >> 15) * (((((((v1 * (t.H6)) >> 10) *
          (((v1 * (t.H3)) >> 11) + (32768))) >> 10) + (2097152)) *
        (t.H2) + 8192) >> 14));
      v1 = (v1 - (((((v1 >> 15) * (v1 >> 15)) >> 7) * (t.H1)) >> 4));
      v1 = (v1 < 0 ? 0 : v1);
      v1 = (v1 > 419430400 ? 419430400 : v1);
      return (v1 >> 12);
    };
    
    exports.connect = function(_i2c) {
      return (new BME280(_i2c));
    };
    
  • That's great - thanks! As long as it's tested then yes, a PR would be really good.

  • [edited] PR completed. In the end rather than strip down all the variable names, I made the new version compatible with Closure advanced optimisation and contributed a .min.js made via that route.

  • made the new version compatible with Closure advanced optimisation and contributed a .min.js made via that route.

    ...will come to your knowledge-sharing brown-bag session/class about that. When and where will take place?

  • Thanks! It's interesting to see the changes needed to allow advanced optimisations. I might actually get rid of the .min.js file itself, because I imagine it could cause trouble in the long run (PRs from someone that changes one file but not the other), but I'll modify minify.js to search for some special token in the unminified file (like ADVANCED_MINIFY) and to then turn on advanced optimisations. That should allow us to turn it on for some other files too.

  • @allObjects it's pretty straightforward. The basic rule is refer to anything you don't want minified as an indirect property reference, so me.property should be written as me['property']. After minification is applied, this goes back to me.property, so although the unoptimised code looks more prolix, the minified is fine. The main problem seems to me that someone later will "improve" the unminified code so that it stops working with advanced optimisation. I looked at using the exports and externs options in advanced optimisation https://developers.google.com/closure/co­mpiler/docs/api-tutorial3?hl=en but they don't work well for the Espruino use case as is. Externs could work with some changes to WebIDE perhaps.

  • Just an aside on externs in Closure. In advanced compilation, it would be helpful to have an Espruino externs file which would prevent minification for example to methods of E or other Espruino bundled classes. I might have a go at this at some point. With more work, every module intended for Closure advanced optimisation could have an extern file to prevent references to it being minified when used with Closure. I am unlikely to find time for this.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

BME280 module refactor

Posted by Avatar for Moray @Moray

Actions