UNPKG

cylon-i2c

Version:

Cylon.js drivers for i2c devices

319 lines (274 loc) 7.37 kB
/* * 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; };