lib/bmp180.js
/*
* BMP180 I2C Barometric Pressure + Temperature sensor driver
* http://cylonjs.com
*
* Copyright (c) 2013-2015 The Hybrid Group
* Licensed under the Apache 2.0 license.
*/
/* eslint camelcase: 0 */
"use strict";
var Cylon = require("cylon");
var I2CDriver = require("./i2c-driver");
/**
* A BMP180 Driver
*
* @constructor bmp180
*/
var Bmp180 = module.exports = function Bmp180() {
Bmp180.__super__.constructor.apply(this, arguments);
this.address = this.address || 0x77;
this.commands = {
get_pressure: this.getPressure,
get_temperature: this.getTemperature,
get_altitude: this.getAltitude
};
};
Cylon.Utils.subclass(Bmp180, I2CDriver);
Bmp180.REGISTER_CALIBRATION = 0xAA;
Bmp180.REGISTER_CONTROL = 0xF4;
Bmp180.REGISTER_TEMPDATA = 0xF6;
Bmp180.REGISTER_PRESSUREDATA = 0xF6;
Bmp180.REGISTER_READTEMPCMD = 0x2E;
Bmp180.REGISTER_READPRESSURECMD = 0x34;
Bmp180.MODE_LOWRES = 0;
Bmp180.MODE_MEDIUMRES = 1;
Bmp180.MODE_HIGHRES = 2;
Bmp180.MODE_UHIGHRES = 3;
function waitTime(mode) {
switch (mode) {
case Bmp180.MODE_LOWRES:
return 5;
case Bmp180.MODE_MEDIUMRES:
return 8;
case Bmp180.MODE_HIGHRES:
return 14;
case Bmp180.MODE_UHIGHRES:
return 26;
default:
return 8;
}
}
/**
* Starts the driver
*
* @param {Function} callback triggered when the driver is started
* @return {void}
*/
Bmp180.prototype.start = function(callback) {
var that = this;
this.readCoefficients(function() {
that.emit("start");
callback();
});
};
/**
* Gets the value of the pressure in Pascals.
*
* Since temperature is also calculated to determine pressure, it returns the
* temperature as well.
*
* @param {Number} mode mode to use
* @param {Function} callback function to be invoked with data
* @return {void}
* @publish
*/
Bmp180.prototype.getPressure = function(mode, callback) {
var self = this;
// need temperature for calibration
var p = 0,
temp = 0.0;
this.getRawTemp(function(err, rawTemp) {
if (err) {
callback(err, null);
} else {
var result = self.calculateTemperature(rawTemp);
temp = result.temp;
self.getRawPressure(mode, function(error, rawPress) {
if (error) {
callback(error, null);
} else {
var modeVal = parseInt(mode, 10);
p = self.calculatePressure(modeVal, rawPress, result.b5);
callback(null, { temp: temp, press: p });
}
});
}
});
};
/**
* Gets the value of the temperature in degrees Celsius.
*
* @param {Function} callback function to be invoked with data
* @return {void}
* @publish
*/
Bmp180.prototype.getTemperature = function(callback) {
var self = this;
var temp = 0.0;
this.getRawTemp(function(err, rawTemp) {
if (err) {
callback(err, null);
} else {
temp = self.calculateTemperature(rawTemp).temp;
callback(err, { temp: temp });
}
});
};
/**
* Calculates the altitude from the pressure and temperature.
*
* Since temperature and pressure are calculated to determine altitude, it
* returns all three.
*
* @param {Number} mode which mode to use
* @param {Number} seaLevelPressure the pressure at sea level
* @param {Function} callback function to be invoked with data
* @return {void}
* @publish
*/
Bmp180.prototype.getAltitude = function(mode, seaLevelPressure, callback) {
if (seaLevelPressure == null) { seaLevelPressure = 101325; }
this.getPressure(mode, function(err, v) {
if (err) {
callback(err, null);
} else {
var altitude = 44330.0 *
(1.0 - Math.pow(v.press / seaLevelPressure, 0.1903));
callback(null, { temp: v.temp, press: v.press, alt: altitude });
}
});
};
Bmp180.prototype.readCoefficients = function(callback) {
var self = this;
this.connection.i2cRead(
this.address,
Bmp180.REGISTER_CALIBRATION,
22,
function(err, d) {
if (err) {
callback(err, null);
} else {
var data = new Buffer(d);
self.ac1 = data.readInt16BE(0);
self.ac2 = data.readInt16BE(2);
self.ac3 = data.readInt16BE(4);
self.ac4 = data.readUInt16BE(6);
self.ac5 = data.readUInt16BE(8);
self.ac6 = data.readUInt16BE(10);
self.b1 = data.readInt16BE(12);
self.b2 = data.readInt16BE(14);
self.mb = data.readInt16BE(16);
self.mc = data.readInt16BE(18);
self.md = data.readInt16BE(20);
callback(err, data);
}
}
);
};
Bmp180.prototype.getRawTemp = function(callback) {
var self = this;
this.connection.i2cWrite(
self.address,
Bmp180.REGISTER_CONTROL,
[Bmp180.REGISTER_READTEMPCMD],
function(err) {
if (err) {
callback(err, null);
} else {
setTimeout(function() {
self.connection.i2cRead(
self.address,
Bmp180.REGISTER_TEMPDATA,
2,
function(error, d) {
if (error) {
callback(error, null);
} else {
var data = new Buffer(d);
var rawTemp = data.readUInt16BE(0);
callback(null, rawTemp);
}
}
);
}, 5);
}
}
);
};
Bmp180.prototype.getRawPressure = function(mode, callback) {
var self = this;
var modeVal = parseInt(mode, 10);
if (isNaN(modeVal) || modeVal < 0 || modeVal > 3) {
callback(new Error("Invalid pressure sensing mode."));
}
this.connection.i2cWrite(
self.address,
Bmp180.REGISTER_CONTROL,
[Bmp180.REGISTER_READPRESSURECMD],
function(err) {
if (err) {
callback(err, null);
} else {
setTimeout(function() {
self.connection.i2cRead(
self.address,
Bmp180.REGISTER_PRESSUREDATA,
3,
function(error, data) {
if (error) {
callback(error, null);
} else {
var msb = data[0];
var lsb = data[1];
var xlsb = data[2];
var press = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - modeVal);
callback(null, press);
}
}
);
}, waitTime(modeVal));
}
}
);
};
Bmp180.prototype.calculateTemperature = function(rawTemp) {
var x1 = 0,
x2 = 0,
b5 = 0,
temp = 0.0;
x1 = ((rawTemp - this.ac6) * this.ac5) >> 15;
x2 = Math.ceil((this.mc << 11) / (x1 + this.md));
b5 = x1 + x2;
temp = ((b5 + 8) >> 4) / 10.0;
return {temp: temp, b5: b5};
};
Bmp180.prototype.calculatePressure = function(mode, rawPress, b5) {
var x1 = 0,
x2 = 0,
x3 = 0,
b3 = 0,
b4 = 0,
b6 = 0,
b7 = 0,
p = 0;
b6 = b5 - 4000;
x1 = (this.b2 * (b6 * b6) >> 12) >> 11;
x2 = (this.ac2 * b6) >> 11;
x3 = x1 + x2;
b3 = Math.ceil((((this.ac1 * 4 + x3) << mode) + 2) / 4);
x1 = (this.ac3 * b6) >> 13;
x2 = (this.b1 * ((b6 * b6) >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (this.ac4 * (x3 + 32768)) >> 15;
b7 = (rawPress - b3) * (50000 >> mode);
if (b7 < 0x80000000) {
p = Math.ceil((b7 * 2) / b4);
} else {
p = Math.ceil((b7 / b4) * 2);
}
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
p = p + ((x1 + x2 + 3791) >> 4);
return p;
};