UNPKG

cdif-sensortag

Version:

CDIF BLE module for the TI SensorTag

354 lines (270 loc) 11.9 kB
// http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide // var NobleDevice = require('noble-device'); var events = require('events'); var util = require('util'); var Common = require('./common'); var MPU9250_UUID = 'f000aa8004514000b000000000000000'; var BAROMETRIC_PRESSURE_UUID = 'f000aa4004514000b000000000000000'; var IO_UUID = 'f000aa6404514000b000000000000000'; var LUXOMETER_UUID = 'f000aa7004514000b000000000000000'; var BAROMETRIC_PRESSURE_CONFIG_UUID = 'f000aa4204514000b000000000000000'; var MPU9250_CONFIG_UUID = 'f000aa8204514000b000000000000000'; var MPU9250_DATA_UUID = 'f000aa8104514000b000000000000000'; var MPU9250_PERIOD_UUID = 'f000aa8304514000b000000000000000'; var MPU9250_GYROSCOPE_MASK = 0x0007; var MPU9250_ACCELEROMETER_MASK = 0x0038; var MPU9250_MAGNETOMETER_MASK = 0x0040; var IO_DATA_UUID = 'f000aa6504514000b000000000000000'; var IO_CONFIG_UUID = 'f000aa6604514000b000000000000000'; var LUXOMETER_CONFIG_UUID = 'f000aa7204514000b000000000000000'; var LUXOMETER_DATA_UUID = 'f000aa7104514000b000000000000000'; var LUXOMETER_PERIOD_UUID = 'f000aa7304514000b000000000000000'; var CC2650SensorTag = function(peripheral) { // NobleDevice.call(this, peripheral); Common.call(this); this.type = 'cc2650'; this.mpu9250mask = 0; this.mpu9250notifyCount = 0; this.onMPU9250ChangeBinded = this.onMPU9250Change.bind(this); this.onLuxometerChangeBinded = this.onLuxometerChange.bind(this); }; CC2650SensorTag.is = function(peripheral) { var localName = peripheral.advertisement.localName; return (localName === 'CC2650 SensorTag') || (localName === 'SensorTag 2.0'); }; // NobleDevice.Util.inherits(CC2650SensorTag, NobleDevice); // NobleDevice.Util.mixin(CC2650SensorTag, NobleDevice.DeviceInformationService); // NobleDevice.Util.mixin(CC2650SensorTag, Common); util.inherits(CC2650SensorTag, events.EventEmitter); for (var i in Common.prototype) { CC2650SensorTag.prototype[i] = Common.prototype[i]; } CC2650SensorTag.prototype.convertIrTemperatureData = function(data, callback) { var ambientTemperature = data.readInt16LE(2) / 128.0; var objectTemperature = data.readInt16LE(0) / 128.0; callback(objectTemperature, ambientTemperature); }; CC2650SensorTag.prototype.convertHumidityData = function(data, callback) { var temperature = -40 + ((165 * data.readUInt16LE(0)) / 65536.0); var humidity = data.readUInt16LE(2) * 100 / 65536.0; callback(temperature, humidity); }; CC2650SensorTag.prototype.enableBarometricPressure = function(callback) { this.enableConfigCharacteristic(BAROMETRIC_PRESSURE_UUID, BAROMETRIC_PRESSURE_CONFIG_UUID, callback); }; CC2650SensorTag.prototype.convertBarometricPressureData = function(data, callback) { // data is returned as // Firmare 0.89 16 bit single precision float // Firmare 1.01 24 bit single precision float var flTempBMP; var flPressure; if (data.length > 4) { // Firmware 1.01 flTempBMP = (data.readUInt32LE(0) & 0x00ffffff)/ 100.0; flPressure = ((data.readUInt32LE(2) >> 8) & 0x00ffffff) / 100.0; } else { // Firmware 0.89 var tempBMP = data.readUInt16LE(0); var tempExponent = (tempBMP & 0xF000) >> 12; var tempMantissa = (tempBMP & 0x0FFF); flTempBMP = tempMantissa * Math.pow(2, tempExponent) / 100.0; var tempPressure = data.readUInt16LE(2); var pressureExponent = (tempPressure & 0xF000) >> 12; var pressureMantissa = (tempPressure & 0x0FFF); flPressure = pressureMantissa * Math.pow(2, pressureExponent) / 100.0; } callback(flPressure); }; CC2650SensorTag.prototype.setMPU9250Period = function(period, callback) { this.writePeriodCharacteristic(MPU9250_UUID, MPU9250_PERIOD_UUID, period, callback); }; CC2650SensorTag.prototype.enableMPU9250 = function(mask, callback) { this.mpu9250mask |= mask; // for now, always write 0x007f, magnetometer does not seem to notify is specific mask is used this.device.writeUInt16LECharacteristic(MPU9250_UUID, MPU9250_CONFIG_UUID, 0x007f, callback); }; CC2650SensorTag.prototype.disableMPU9250 = function(mask, callback) { this.mpu9250mask &= ~mask; if (this.mpu9250mask === 0) { this.device.writeUInt16LECharacteristic(MPU9250_UUID, MPU9250_CONFIG_UUID, 0x0000, callback); } else if (typeof(callback) === 'function') { callback(); } }; CC2650SensorTag.prototype.notifyMPU9250 = function(callback) { this.mpu9250notifyCount++; if (this.mpu9250notifyCount === 1) { this.device.notifyCharacteristic(MPU9250_UUID, MPU9250_DATA_UUID, true, this.onMPU9250ChangeBinded, callback); } else if (typeof(callback) === 'function') { callback(); } }; CC2650SensorTag.prototype.unnotifyMPU9250 = function(callback) { this.mpu9250notifyCount--; if (this.mpu9250notifyCount === 0) { this.device.notifyCharacteristic(MPU9250_UUID, MPU9250_DATA_UUID, false, this.onMPU9250ChangeBinded, callback); } else if (typeof(callback) === 'function') { callback(); } }; CC2650SensorTag.prototype.enableAccelerometer = function(callback) { this.enableMPU9250(MPU9250_ACCELEROMETER_MASK, callback); }; CC2650SensorTag.prototype.disableAccelerometer = function(callback) { this.disableMPU9250(MPU9250_ACCELEROMETER_MASK, callback); }; CC2650SensorTag.prototype.readAccelerometer = function(callback) { this.device.readDataCharacteristic(MPU9250_UUID, MPU9250_DATA_UUID, function(error, data) { if (error) { return callback(error); } this.convertMPU9250Data(data, function(x, y, z) { callback(null, x, y, z); }.bind(this)); }.bind(this)); }; CC2650SensorTag.prototype.onMPU9250Change = function(data) { this.convertMPU9250Data(data, function(x, y, z, xG, yG, zG, xM, yM, zM) { if (this.mpu9250mask & MPU9250_ACCELEROMETER_MASK) { this.emit('accelerometerChange', x, y, z); } if (this.mpu9250mask & MPU9250_GYROSCOPE_MASK) { this.emit('gyroscopeChange', xG, yG, zG); } if (this.mpu9250mask & MPU9250_MAGNETOMETER_MASK) { this.emit('magnetometerChange', xM, yM, zM); } }.bind(this)); }; CC2650SensorTag.prototype.convertMPU9250Data = function(data, callback) { // 250 deg/s range var xG = data.readInt16LE(0) * (500.0 / 65536.0); var yG = data.readInt16LE(2) * (500.0 / 65536.0); var zG = data.readInt16LE(4) * (500.0 / 65536.0); // we specify 2G range in setup var x = data.readInt16LE(6) * 2.0 / 32768.0; var y = data.readInt16LE(8) * 2.0 / 32768.0; var z = data.readInt16LE(10) * 2.0 / 32768.0; // magnetometer (page 50 of http://www.invensense.com/mems/gyro/documents/RM-MPU-9250A-00.pdf) var xM = data.readInt16LE(12) * 4912.0 / 32760.0; var yM = data.readInt16LE(14) * 4912.0 / 32760.0; var zM = data.readInt16LE(16) * 4912.0 / 32760.0; callback(x, y, z, xG, yG, zG, xM, yM, zM); }; CC2650SensorTag.prototype.notifyAccelerometer = function(callback) { this.notifyMPU9250(callback); }; CC2650SensorTag.prototype.unnotifyAccelerometer = function(callback) { this.unnotifyMPU9250(callback); }; CC2650SensorTag.prototype.setAccelerometerPeriod = function(period, callback) { this.setMPU9250Period(period, callback); }; CC2650SensorTag.prototype.enableMagnetometer = function(callback) { this.enableMPU9250(MPU9250_MAGNETOMETER_MASK, callback); }; CC2650SensorTag.prototype.disableMagnetometer = function(callback) { this.disableMPU9250(MPU9250_MAGNETOMETER_MASK, callback); }; CC2650SensorTag.prototype.readMagnetometer = function(callback) { this.device.readDataCharacteristic(MPU9250_UUID, MPU9250_DATA_UUID, function(error, data) { if (error) { return callback(error); } this.convertMPU9250Data(data, function(x, y, z, xG, yG, zG, xM, yM, zM) { callback(null, xM, yM, zM); }.bind(this)); }.bind(this)); }; CC2650SensorTag.prototype.notifyMagnetometer = function(callback) { this.notifyMPU9250(callback); }; CC2650SensorTag.prototype.unnotifyMagnetometer = function(callback) { this.unnotifyMPU9250(callback); }; CC2650SensorTag.prototype.setMagnetometerPeriod = function(period, callback) { this.setMPU9250Period(period, callback); }; CC2650SensorTag.prototype.setGyroscopePeriod = function(period, callback) { this.setMPU9250Period(period, callback); }; CC2650SensorTag.prototype.enableGyroscope = function(callback) { this.enableMPU9250(MPU9250_GYROSCOPE_MASK, callback); }; CC2650SensorTag.prototype.disableGyroscope = function(callback) { this.disableMPU9250(MPU9250_GYROSCOPE_MASK, callback); }; CC2650SensorTag.prototype.readGyroscope = function(callback) { this.device.readDataCharacteristic(MPU9250_UUID, MPU9250_DATA_UUID, function(error, data) { if (error) { return callback(error); } this.convertMPU9250Data(data, function(x, y, z, xG, yG, zG) { callback(null, xG, yG, zG); }.bind(this)); }.bind(this)); }; CC2650SensorTag.prototype.notifyGyroscope = function(callback) { this.notifyMPU9250(callback); }; CC2650SensorTag.prototype.unnotifyGyroscope = function(callback) { this.unnotifyMPU9250(callback); }; CC2650SensorTag.prototype.readIoData = function(callback) { this.readUInt8Characteristic(IO_UUID, IO_DATA_UUID, callback); }; CC2650SensorTag.prototype.writeIoData = function(value, callback) { this.writeUInt8Characteristic(IO_UUID, IO_DATA_UUID, value, callback); }; CC2650SensorTag.prototype.readIoConfig = function(callback) { this.readUInt8Characteristic(IO_UUID, IO_CONFIG_UUID, callback); }; CC2650SensorTag.prototype.writeIoConfig = function(value, callback) { this.writeUInt8Characteristic(IO_UUID, IO_CONFIG_UUID, value, callback); }; CC2650SensorTag.prototype.enableLuxometer = function(callback) { this.enableConfigCharacteristic(LUXOMETER_UUID, LUXOMETER_CONFIG_UUID, callback); }; CC2650SensorTag.prototype.disableLuxometer = function(callback) { this.disableConfigCharacteristic(LUXOMETER_UUID, LUXOMETER_CONFIG_UUID, callback); }; CC2650SensorTag.prototype.readLuxometer = function(callback) { this.device.readDataCharacteristic(LUXOMETER_UUID, LUXOMETER_DATA_UUID, function(error, data) { if (error) { return callback(error); } this.convertLuxometerData(data, function(lux) { callback(null, lux); }.bind(this)); }.bind(this)); }; CC2650SensorTag.prototype.onLuxometerChange = function(data) { this.convertLuxometerData(data, function(lux) { this.emit('luxometerChange', lux); }.bind(this)); }; CC2650SensorTag.prototype.convertLuxometerData = function(data, callback) { var rawLux = data.readUInt16LE(0); var exponent = (rawLux & 0xF000) >> 12; var mantissa = (rawLux & 0x0FFF); var flLux = mantissa * Math.pow(2, exponent) / 100.0; callback(flLux); }; CC2650SensorTag.prototype.notifyLuxometer = function(callback) { this.device.notifyCharacteristic(LUXOMETER_UUID, LUXOMETER_DATA_UUID, true, this.onLuxometerChangeBinded, callback); }; CC2650SensorTag.prototype.unnotifyLuxometer = function(callback) { this.device.notifyCharacteristic(LUXOMETER_UUID, LUXOMETER_DATA_UUID, false, this.onLuxometerChangeBinded, callback); }; CC2650SensorTag.prototype.setLuxometerPeriod = function(period, callback) { this.writePeriodCharacteristic(LUXOMETER_UUID, LUXOMETER_PERIOD_UUID, period, callback); }; CC2650SensorTag.prototype.convertSimpleKeyData = function(data, callback) { var b = data.readUInt8(0); var left = (b & 0x2) ? true : false; var right = (b & 0x1) ? true : false; var reedRelay = (b & 0x4) ? true : false; callback(left, right, reedRelay); }; module.exports = CC2650SensorTag;