accel-mma84
Advanced tools
Comparing version 0.0.5 to 0.0.6
@@ -9,29 +9,31 @@ /********************************************* | ||
var tessel = require('tessel'); | ||
var accel = require('../').connect(tessel.port("A")); | ||
var accel = require('../').use(tessel.port("A")); | ||
// Initialize the accelerometer. | ||
accel.on('connected', function () { | ||
// Stream accelerometer data | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
accel.on('ready', function () { | ||
// Stream accelerometer data | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
"y:", xyz[1].toFixed(2), | ||
"z:", xyz[2].toFixed(2)); | ||
}); | ||
//After two seconds, stop streaming | ||
setTimeout(function () { | ||
console.log('Stopping stream') | ||
accel.removeAllListeners('data', function () { | ||
console.log('listener removed') | ||
//After two more seconds, change stream rate, then stream again | ||
setTimeout(function () { | ||
console.log('Changing poll frequency') | ||
accel.setPollFrequency(1000); // every 1 second (default is 10x/second) | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
"y:", xyz[1].toFixed(2), | ||
"z:", xyz[2].toFixed(2)); | ||
}); | ||
}, 2000); | ||
}); | ||
}, 2000); | ||
}); | ||
}); | ||
//After two seconds, change stream rate, then stream again | ||
setTimeout(function () { | ||
console.log('Changing the output rate...'); | ||
accel.removeAllListeners('data'); | ||
// Setting the output data rate in Hz | ||
accel.setOutputRate(1.56, function rateSet() { | ||
accel.on('data', function (xyz) { | ||
console.log("slower rate x:", xyz[0].toFixed(2), | ||
"slower rate y:", xyz[1].toFixed(2), | ||
"slower rate z:", xyz[2].toFixed(2)); | ||
}); | ||
}); | ||
}, 2000); | ||
}); | ||
accel.on('error', function(err) { | ||
console.log('there was an error', err); | ||
}); | ||
setInterval(function() {}, 20000); |
@@ -7,12 +7,19 @@ /********************************************* | ||
var tessel = require('tessel'); | ||
var accel = require('../').connect(tessel.port("A")); | ||
var accel = require('../').use(tessel.port("A")); | ||
// Initialize the accelerometer. | ||
accel.on('connected', function () { | ||
accel.on('ready', function () { | ||
// Stream accelerometer data | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
"y:", xyz[1].toFixed(2), | ||
"z:", xyz[2].toFixed(2)); | ||
}); | ||
}); | ||
}); | ||
}); | ||
accel.on('error', function(err) { | ||
console.log('error connecting', err); | ||
}); | ||
setInterval(function(){}, 20000); |
459
index.js
var util = require('util'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var queue = require('sync-queue'); | ||
// Copyright 2014 Technical Machine, Inc. See the COPYRIGHT | ||
// file at the top-level directory of this distribution. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
/** | ||
* Configuration | ||
*/ | ||
// The SparkFun breakout board defaults to 1, set to 0 if SA0 jumper on the bottom of the board is set | ||
var I2C_ADDRESS = 0x1D // 0x1D if SA0 is high, 0x1C if low | ||
var I2C_ADDRESS = 0x1D; // 0x1D if SA0 is high, 0x1C if low | ||
// Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values. | ||
var GSCALE = 2 | ||
// See the many application notes for more info on setting all of these registers: | ||
// http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MMA8452Q | ||
// MMA8452 registers | ||
var OUT_X_MSB = 0x01 | ||
var XYZ_DATA_CFG = 0x0E | ||
var WHO_AM_I = 0x0D | ||
var CTRL_REG1 = 0x2A | ||
var OUT_X_MSB = 0x01; | ||
var XYZ_DATA_CFG = 0x0E; | ||
var WHO_AM_I = 0x0D; | ||
var CTRL_REG1 = 0x2A; | ||
var CTRL_REG4 = 0x2D; | ||
/** | ||
* MMA | ||
*/ | ||
function Accelerometer (hardware) | ||
function Accelerometer (hardware, callback) | ||
{ | ||
var self = this; | ||
// Command Queue | ||
self.queue = new queue(); | ||
// Port assignment | ||
self.hardware = hardware; | ||
self.numListeners = 0; | ||
self.listening = false; | ||
self.pollFrequency = 100; | ||
// Rate at which data is collected and is ready to be read | ||
self.outputRate = 12.5; | ||
// Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values. | ||
self.scaleRange = 2; | ||
// Interrupt pin for the data ready event | ||
self.dataInterrupt = self.hardware.gpio(2); | ||
// Address for i2C | ||
// TODO: Account for manual address changes? | ||
self.i2c = hardware.I2C(I2C_ADDRESS); | ||
self.i2c = new hardware.I2C(I2C_ADDRESS); | ||
self._readRegister(WHO_AM_I, function (err, c) { | ||
if (c == 0x2A) { // WHO_AM_I should always return 0x2A | ||
console.log("MMA8452Q is online..."); | ||
} else { | ||
console.log("Could not connect to MMA8452Q, received", c); | ||
while (1) { continue; } // Loop forever if communication doesn't happen | ||
// Check that we can read the correct chip id | ||
self.getChipID(function IDRead(err, c) { | ||
if (err) { | ||
// Fail the init | ||
return self.failProcedure(err); | ||
} | ||
// should always return 0x2A | ||
if (c !== 0x2A) { | ||
// This is the wrong chip | ||
err = new Error("Could not connect to MMA8452Q, received " + c.toString() + ". Expected 0x2A."); | ||
// Fail the init | ||
return self.failProcedure(err); | ||
} | ||
// Must be in standby to change registers | ||
self.modeStandby(function () { | ||
// Set up the full scale range to 2, 4, or 8g. | ||
var fsr = GSCALE; | ||
if (fsr > 8) fsr = 8; //Easy error check | ||
fsr >>= 2; // Neat trick, see page 22. 00 = 2G, 01 = 4A, 10 = 8G | ||
self._writeRegister(XYZ_DATA_CFG, fsr, function () { | ||
// The default data rate is 800Hz and we don't modify it in this example code | ||
self.modeActive(function () { | ||
self.emit('connected'); | ||
}); // Set to active to start reading | ||
}); | ||
// Set the scale range to standard | ||
self.setScaleRange(self.scaleRange, function(err) { | ||
if (err) { | ||
return self.failProcedure(err, callback); | ||
} | ||
else { | ||
// Set the output rate to standard | ||
self.setOutputRate(self.outputRate, function(err) { | ||
if (err) { | ||
return self.failProcedure(err, callback); | ||
} | ||
else { | ||
// Emit the ready event | ||
setImmediate(function emitReady() { | ||
self.emit('ready'); | ||
}); | ||
// Call the callback with object | ||
if (callback) callback(null, self); | ||
return; | ||
} | ||
}); | ||
} | ||
}); | ||
// If we get a new listener | ||
// Set up an interrupt handler for data ready | ||
self.dataInterrupt.watch('low', self.dataReady.bind(self)); | ||
self.on('newListener', function(event) { | ||
if (event == "data") { | ||
// Add to the number of things listening | ||
self.numListeners += 1; | ||
// If we're not already listening | ||
if (!self.listening) { | ||
// Start listening | ||
self.setListening(); | ||
// If we have a new data listener | ||
if (event === 'data') { | ||
// And the count was previously zero | ||
if (self.listeners('event').length === 0) { | ||
// Enable interrupts at whatever rate was previously set | ||
self.enableDataInterrupts(true, queueNext); | ||
} | ||
@@ -74,62 +96,50 @@ } | ||
// If we remove a listener | ||
self.on('removeListener', function(event) { | ||
if (event == "data") { | ||
// Remove from the number of things listening | ||
console.log('prev listeners', self.numListeners); | ||
self.numListeners -= 1; | ||
console.log('now', self.numListeners); | ||
// Because we listen in a while loop, if this.listening goes to 0, we'll stop listening automatically | ||
if (self.numListeners < 1) { | ||
self.listening = 0; | ||
// If we have a new data listener | ||
if (event === 'data') { | ||
// And the count was previously zero | ||
if (self.listeners(event).length === 0) { | ||
// Set the default rate of output | ||
self.enableDataInterrupts(false, queueNext); | ||
} | ||
} | ||
}); | ||
// If all listeners removed | ||
self.on('removeAllListeners', function(event) { | ||
self.numListeners = 0; | ||
self.listening = 0; | ||
}); | ||
}); | ||
} | ||
util.inherits(Accelerometer, EventEmitter) | ||
util.inherits(Accelerometer, EventEmitter); | ||
Accelerometer.prototype._readRegisters = function (addressToRead, bytesToRead, next) | ||
Accelerometer.prototype.failProcedure = function(err, callback) { | ||
var self = this; | ||
// Emit the error | ||
setImmediate(function emitErr() { | ||
self.emit('error', err); | ||
}); | ||
// Call the callback | ||
if (callback) callback(err); | ||
return; | ||
}; | ||
Accelerometer.prototype._readRegisters = function (addressToRead, bytesToRead, callback) | ||
{ | ||
this.i2c.transfer(new Buffer([addressToRead]), bytesToRead, next); | ||
} | ||
this.i2c.transfer(new Buffer([addressToRead]), bytesToRead, callback); | ||
}; | ||
Accelerometer.prototype._readRegister = function (addressToRead, next) | ||
Accelerometer.prototype._readRegister = function (addressToRead, callback) | ||
{ | ||
this._readRegisters(addressToRead, 1, function (err, regs) { | ||
next(err, regs && regs[0]); | ||
callback(err, regs && regs[0]); | ||
}); | ||
} | ||
}; | ||
// Write a single byte to the register. | ||
Accelerometer.prototype._writeRegister = function (addressToWrite, dataToWrite, next) | ||
Accelerometer.prototype._writeRegister = function (addressToWrite, dataToWrite, callback) | ||
{ | ||
this.i2c.send(new Buffer([addressToWrite, dataToWrite]), next); | ||
} | ||
this.i2c.send(new Buffer([addressToWrite, dataToWrite]), callback); | ||
}; | ||
Accelerometer.prototype.setListening = function () { | ||
var self = this; | ||
self.listening = true; | ||
// Loop until nothing is listening | ||
self.listeningLoop = setInterval (function () { | ||
if (self.numListeners) { | ||
self.getAcceleration(function (err, xyz) { | ||
if (err) throw err; | ||
self.emit('data', xyz); | ||
}); | ||
} else { | ||
clearInterval(listeningLoop); | ||
} | ||
}, self.pollFrequency); | ||
} | ||
// Sets the MMA8452 to standby mode. It must be in standby to change most register settings | ||
Accelerometer.prototype.modeStandby = function (next) | ||
Accelerometer.prototype.modeStandby = function (callback) | ||
{ | ||
@@ -139,8 +149,13 @@ var self = this; | ||
self._readRegister(CTRL_REG1, function (err, c) { | ||
self._writeRegister(CTRL_REG1, c & ~(0x01), next); | ||
}) | ||
} | ||
if (err) { | ||
return self.failProcedure(err, callback); | ||
} | ||
else { | ||
return self._writeRegister(CTRL_REG1, c & ~(0x01), callback); | ||
} | ||
}); | ||
}; | ||
// Sets the MMA8452 to active mode. Needs to be in this mode to output data | ||
Accelerometer.prototype.modeActive = function (next) | ||
Accelerometer.prototype.modeActive = function (callback) | ||
{ | ||
@@ -150,43 +165,241 @@ var self = this; | ||
self._readRegister(CTRL_REG1, function (err, c) { | ||
self._writeRegister(CTRL_REG1, c | (0x01), next); | ||
if (err) { | ||
return failProcedure(err); | ||
} | ||
else { | ||
return self._writeRegister(CTRL_REG1, c | (0x01), callback); | ||
} | ||
}); | ||
} | ||
}; | ||
Accelerometer.prototype.getAcceleration = function (next) | ||
Accelerometer.prototype.getAcceleration = function (callback) | ||
{ | ||
var self = this; | ||
self._readRegisters(OUT_X_MSB, 6, function (err, rawData) { | ||
if (err) throw err; | ||
// Loop to calculate 12-bit ADC and g value for each axis | ||
var out = []; | ||
for (var i = 0; i < 3 ; i++) { | ||
var gCount = (rawData[i*2] << 8) | rawData[(i*2)+1]; //Combine the two 8 bit registers into one 12-bit number | ||
gCount = (gCount >> 4); //The registers are left align, here we right align the 12-bit integer | ||
self.queue.place( function readAccel() { | ||
self._readRegisters(OUT_X_MSB, 6, function (err, rawData) { | ||
if (err) throw err; | ||
// Loop to calculate 12-bit ADC and g value for each axis | ||
var out = []; | ||
for (var i = 0; i < 3 ; i++) { | ||
var gCount = (rawData[i*2] << 8) | rawData[(i*2)+1]; //Combine the two 8 bit registers into one 12-bit number | ||
// If the number is negative, we have to make it so manually (no 12-bit data type) | ||
if (rawData[i*2] > 0x7F) { | ||
gCount = -(1 + 0xFFF - gCount); // Transform into negative 2's complement | ||
gCount = (gCount >> 4); //The registers are left align, here we right align the 12-bit integer | ||
// If the number is negative, we have to make it so manually (no 12-bit data type) | ||
if (rawData[i*2] > 0x7F) { | ||
gCount = -(1 + 0xFFF - gCount); // Transform into negative 2's complement | ||
} | ||
out[i] = gCount / ((1<<12)/(2*self.scaleRange)); | ||
} | ||
out[i] = gCount / ((1<<12)/(2*GSCALE)); | ||
callback(null, out); | ||
setImmediate(self.queue.next); | ||
}); | ||
}); | ||
}; | ||
// Get the id of the chip | ||
Accelerometer.prototype.getChipID = function(callback) { | ||
this._readRegister(WHO_AM_I, function (err, c) { | ||
if (callback) callback(err, c); | ||
}); | ||
}; | ||
Accelerometer.prototype.availableOutputRates = function() { | ||
// Available interrupt rates in Hz | ||
return [800, 400, 200, 100, 50, 12.5, 6.25, 1.56]; | ||
}; | ||
Accelerometer.prototype.availableScaleRanges = function() { | ||
// Available accelerometer ranges (in units of Gs) | ||
// The higher the range, the less accurate the readings are | ||
return [2, 4, 8]; | ||
}; | ||
Accelerometer.prototype._getClosestOutputRate = function(requestedRate, callback) { | ||
// If a negative number is requested, stop output (0 hz) | ||
if (requestedRate < 0) requestedRate = 0; | ||
// If 0 hz is requested, return just that so that output will be stopped | ||
if (requestedRate === 0) { | ||
if (callback) callback(null, 0); | ||
return; | ||
} | ||
// Get the available rates | ||
var available = this.availableOutputRates(); | ||
// Iterate through each | ||
for (var i = 0; i < available.length; i++) { | ||
// The first available rate less than or equal to requested is a match | ||
if (available[i] <= requestedRate) { | ||
// Send the match back | ||
if (callback) callback(null, available[i]); | ||
return; | ||
} | ||
} | ||
next(null, out); | ||
// If there were no match, this number must be between 0 and 1.56. Use 1.56 | ||
if (callback) callback(null, available[available.length-1]); | ||
}; | ||
Accelerometer.prototype._changeRegister = function(change, callback) { | ||
var self = this; | ||
// Put the accelerometer into standby | ||
self.modeStandby(function inStandby(err) { | ||
if (err) { | ||
return self.failProcedure(err, callback); | ||
} | ||
else { | ||
// Make whatever change was requested | ||
change( function setActive(err) { | ||
if (err) { | ||
return self.failProcedure(err, callback); | ||
} | ||
else { | ||
// Put the accelerometer back into active mode | ||
self.modeActive(callback); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
}; | ||
// Sets the polling frequency for streamed data (default 100ms) | ||
Accelerometer.prototype.setPollFrequency = function (milliseconds) { | ||
// Sets the output rate of the data (1.56-800 Hz) | ||
Accelerometer.prototype.setOutputRate = function (hz, callback) { | ||
var self = this; | ||
self.pollFrequency = milliseconds; | ||
if (self.listening) { | ||
clearInterval(self.listeningLoop); | ||
self.setListening(); | ||
} | ||
} | ||
// Put accel into standby | ||
self.queue.place(function addedQueue() { | ||
self._changeRegister( function setRegisters(finishChange) { | ||
// Find the closest available rate (rounded down) | ||
self._getClosestOutputRate(hz, function gotRequested(err, closest) { | ||
if (err) { | ||
return finishChange(new Error("Rate must be >= 1.56Hz")); | ||
} | ||
else { | ||
// Set our property | ||
self.outputRate = closest; | ||
// Get the binary representation of the rate (for the register) | ||
var bin = self.availableOutputRates().indexOf(closest); | ||
// If the binary rep could be found | ||
if (bin !== -1) { | ||
// Read the current register value | ||
self._readRegister(CTRL_REG1, function readComplete(err, regVal) { | ||
if (err) { | ||
return finishChange(err); | ||
} | ||
else { | ||
// Clear the three bits of output rate control (0b11000111 = 199) | ||
regVal &= 199; | ||
// Move the binary rep into place (bits 3:5) | ||
if (bin !== 0) regVal |= (bin << 3); | ||
// Write that value into the control register | ||
self._writeRegister(CTRL_REG1, regVal, finishChange); | ||
} | ||
}); | ||
} | ||
else { | ||
return finishChange(new Error("Invalid output rate.")); | ||
} | ||
} | ||
}); | ||
}, | ||
function rateSet(err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
setImmediate(self.queue.next); | ||
}); | ||
}); | ||
}; | ||
Accelerometer.prototype.enableDataInterrupts = function(enable, callback) { | ||
var self = this; | ||
self.queue.place(function queueEnable() { | ||
// We're going to change register 4 | ||
self._changeRegister(function change(complete) { | ||
// Read the register first | ||
self._readRegister(CTRL_REG4, function(err, reg4) { | ||
if (err) { | ||
return complete(err); | ||
} | ||
else { | ||
// If we are enabling, set first bit to 1, else 0 | ||
var regVal = (enable ? (reg4 |= 1) : (reg4 &= ~1)); | ||
// Write to the register | ||
self._writeRegister(CTRL_REG4, regVal, function(err) { | ||
return complete(err); | ||
}); | ||
} | ||
}); | ||
}, function intSet(err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
setImmediate(self.queue.next); | ||
}); | ||
}); | ||
}; | ||
Accelerometer.prototype.setScaleRange = function(scaleRange, callback) { | ||
var self = this; | ||
var fsr = scaleRange; | ||
if (fsr > 8) fsr = 8; //Easy error check | ||
fsr >>= 2; // Neat trick, see page 22. 00 = 2G, 01 = 4G, 10 = 8G | ||
// Go into standby to edit registers | ||
self.queue.place( function queueScale() { | ||
self._changeRegister(function change(complete) { | ||
if (err) { | ||
return complete(err); | ||
} | ||
else { | ||
// Write the new scale into the register | ||
self._writeRegister(XYZ_DATA_CFG, fsr, function wroteReg(err) { | ||
self.scaleRange = scaleRange; | ||
return complete(err); | ||
}); | ||
} | ||
}, function scaleSet(err) { | ||
if (callback) { | ||
callback(err); | ||
} | ||
setImmediate(self.queue.next); | ||
}); | ||
}); | ||
}; | ||
Accelerometer.prototype.dataReady = function() { | ||
var self = this; | ||
// Data is ready so grab the data | ||
self.getAcceleration(function(err, xyz) { | ||
// If we had an error, emit it | ||
if (err) { | ||
// Emitting error | ||
self.emit('error', err); | ||
} | ||
// If there was no error | ||
else { | ||
// Emit the data | ||
self.emit('data', xyz); | ||
} | ||
self.dataInterrupt.watch('low', self.dataReady.bind(self)); | ||
}); | ||
}; | ||
exports.Accelerometer = Accelerometer; | ||
exports.connect = function (hardware) { | ||
return new Accelerometer(hardware); | ||
exports.use = function (hardware, callback) { | ||
return new Accelerometer(hardware, callback); | ||
}; |
{ | ||
"name": "accel-mma84", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "Library to run the MMA8452Q accelerometer.", | ||
@@ -9,2 +9,5 @@ "main": "index.js", | ||
}, | ||
"dependencies" : { | ||
"sync-queue" : "0.0.1" | ||
}, | ||
"hardware": { | ||
@@ -11,0 +14,0 @@ "./examples": false |
@@ -14,15 +14,17 @@ #Accelerometer | ||
console.log("Connecting to accelerometer on port bank A"); | ||
var accel = require('accel-mma84').connect(tessel.port("A")); | ||
var accel = require('accel-mma84').use(tessel.port("A")); | ||
// Initialize the accelerometer. | ||
accel.on('connected', function () { | ||
// Loop forever. | ||
setInterval(function () { | ||
accel.getAcceleration(function (err, xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
"y:", xyz[1].toFixed(2), | ||
"z:", xyz[2].toFixed(2)); | ||
}); | ||
}, 100); | ||
accel.on('ready', function () { | ||
// Stream accelerometer data | ||
accel.on('data', function (xyz) { | ||
console.log("x:", xyz[0].toFixed(2), | ||
"y:", xyz[1].toFixed(2), | ||
"z:", xyz[2].toFixed(2)); | ||
}); | ||
}); | ||
accel.on('error', function(err) { | ||
console.log("Unable to connect to module: ", err); | ||
}) | ||
``` | ||
@@ -32,10 +34,18 @@ | ||
* **`accel`.initialize()** | ||
* **`accel`.getAcceleration(callback(err, xyz))** | ||
* **`accel`.setOutputRate(rateInHz, callback(err, xyz))** | ||
* **`accel`.availableOutputRates()** | ||
* **`accel`.setScaleRange(scaleRange, callback(err, xyz))** | ||
* **`accel`.availableScaleRanges()** | ||
##Events | ||
* *connected* | ||
* *ready* | ||
* *error* | ||
* *data* | ||
@@ -42,0 +52,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28690
9
447
58
1
1
1
+ Addedsync-queue@0.0.1
+ Addedsync-queue@0.0.1(transitive)