accel-mma84
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -1,13 +0,23 @@ | ||
var accel = require('../').connect(myhardwareapi); | ||
/********************************************* | ||
This basic accelerometer example logs a stream | ||
of x, y, and z data from the accelerometer | ||
*********************************************/ | ||
// Any copyright is dedicated to the Public Domain. | ||
// http://creativecommons.org/publicdomain/zero/1.0/ | ||
var tessel = require('tessel'); | ||
var accel = require('../').use(tessel.port['A']); // Replace '../' with 'accel-mma84' in your own code | ||
// Initialize the accelerometer. | ||
accel.on('connected', function () { | ||
// Loop forever. | ||
setInterval(function () { | ||
accel.getAcceleration(function (err, xyz) { | ||
console.log("x:", xyz.x.toFixed(2), | ||
"y:", xyz.y.toFixed(2), | ||
"z:", xyz.z.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)); | ||
}); | ||
}); | ||
setInterval(function(){}, 20000); |
444
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; | ||
function Accelerometer (hardware, callback) { | ||
var self = this; | ||
// Command Queue | ||
self.queue = new queue(); | ||
// Port assignment | ||
self.hardware = hardware; | ||
// 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); | ||
/** | ||
* MMA | ||
*/ | ||
// 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); | ||
} | ||
// 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); | ||
function Accelerometer (hardware) | ||
{ | ||
var self = this; | ||
return; | ||
} | ||
}); | ||
} | ||
}); | ||
this.hardware = hardware; | ||
// Set up an interrupt handler for data ready | ||
self.dataInterrupt.watch('low', self._dataReady.bind(self)); | ||
self.i2c = new hardware.I2C(I2C_ADDRESS); | ||
self.i2c.initialize(); | ||
self.on('newListener', function(event) { | ||
// If we have a new sample listener | ||
if (event == 'data' || event == 'sample') { | ||
// Enable interrupts at whatever rate was previously set. | ||
self.enableDataInterrupts(true, queueNext); | ||
} | ||
}); | ||
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 | ||
} | ||
// 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 | ||
}); | ||
self.on('removeListener', function(event) { | ||
// If we have a new || event == 'sample' listener | ||
if (event == 'data' || event == 'sample') { | ||
// Disable interrupt. | ||
self.enableDataInterrupts(false, queueNext); | ||
} | ||
}); | ||
}) | ||
}); | ||
} | ||
util.inherits(Accelerometer, EventEmitter) | ||
util.inherits(Accelerometer, EventEmitter); | ||
Accelerometer.prototype._readRegisters = function (addressToRead, bytesToRead, next) | ||
{ | ||
this.i2c.transfer([addressToRead], bytesToRead, next); | ||
} | ||
Accelerometer.prototype._changeRegister = function(change, callback) { | ||
var self = this; | ||
Accelerometer.prototype._readRegister = function (addressToRead, next) | ||
{ | ||
this._readRegisters(addressToRead, 1, function (err, regs) { | ||
next(err, regs && regs[0]); | ||
// 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); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
}; | ||
// Write a single byte to the register. | ||
Accelerometer.prototype._writeRegister = function (addressToWrite, dataToWrite, next) | ||
{ | ||
this.i2c.send([addressToWrite, dataToWrite], 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); // old-style, deprecated | ||
self.emit('sample', xyz); | ||
} | ||
// Sets the MMA8452 to standby mode. It must be in standby to change most register settings | ||
Accelerometer.prototype.modeStandby = function (next) | ||
{ | ||
self.dataInterrupt.watch('low', self._dataReady.bind(self)); | ||
}); | ||
}; | ||
Accelerometer.prototype._failProcedure = function(err, callback) { | ||
var self = this; | ||
// Clear the active bit to go into standby | ||
self._readRegister(CTRL_REG1, function (err, c) { | ||
self._writeRegister(CTRL_REG1, c & ~(0x01), next); | ||
}) | ||
} | ||
// Emit the error | ||
setImmediate(function emitErr() { | ||
self.emit('error', err); | ||
}); | ||
// Call the callback | ||
if (callback) callback(err); | ||
return; | ||
}; | ||
// 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._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; | ||
} | ||
} | ||
// 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]); | ||
}; | ||
// 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) { | ||
var self = this; | ||
// Set the active bit to begin detection | ||
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) | ||
{ | ||
// Sets the MMA8452 to standby mode. It must be in standby to change most register settings | ||
Accelerometer.prototype._modeStandby = function (callback) { | ||
var self = this; | ||
self._readRegisters(OUT_X_MSB, 6, function (err, rawData) { | ||
// Loop to calculate 12-bit ADC and g value for each axis | ||
var out = [], axes = ['x', 'y', 'z']; | ||
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 | ||
// Clear the active bit to go into standby | ||
self._readRegister(CTRL_REG1, function (err, c) { | ||
if (err) { | ||
return self._failProcedure(err, callback); | ||
} | ||
else { | ||
return self._writeRegister(CTRL_REG1, c & ~(0x01), callback); | ||
} | ||
}); | ||
}; | ||
gCount = (gCount >> 4); //The registers are left align, here we right align the 12-bit integer | ||
Accelerometer.prototype._readRegister = function (addressToRead, callback) { | ||
this._readRegisters(addressToRead, 1, function (err, regs) { | ||
callback(err, regs && regs[0]); | ||
}); | ||
}; | ||
// 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 | ||
Accelerometer.prototype._readRegisters = function (addressToRead, bytesToRead, callback) { | ||
this.i2c.transfer(new Buffer([addressToRead]), bytesToRead, callback); | ||
}; | ||
// Write a single byte to the register. | ||
Accelerometer.prototype._writeRegister = function (addressToWrite, dataToWrite, callback) { | ||
this.i2c.send(new Buffer([addressToWrite, dataToWrite]), callback); | ||
}; | ||
// Logs the available interrupt rates in Hz | ||
Accelerometer.prototype.availableOutputRates = function() { | ||
return [800, 400, 200, 100, 50, 12.5, 6.25, 1.56]; | ||
}; | ||
// Logs the available accelerometer ranges (in units of Gs) | ||
Accelerometer.prototype.availableScaleRanges = function() { | ||
// The higher the range, the less accurate the readings are | ||
return [2, 4, 8]; | ||
}; | ||
// Enables or disables data interrupts. Set the first param truthy to enable, false to disable. | ||
Accelerometer.prototype.enableDataInterrupts = function(enable, callback) { | ||
var self = this; | ||
// Don't call unnecessarily. | ||
if (this._dataInterrupts == !!enable) { | ||
return callback && callback(); | ||
} | ||
this._dataInterrupts = !!enable; | ||
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); | ||
}); | ||
}); | ||
}; | ||
out[axes[i]] = gCount / ((1<<12)/(2*GSCALE)); | ||
} | ||
// Gets the acceleration from the device, outputs as array [x, y, z] | ||
Accelerometer.prototype.getAcceleration = function (callback) { | ||
var self = this; | ||
next(null, out); | ||
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 | ||
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)); | ||
} | ||
callback(null, out); | ||
setImmediate(self.queue.next); | ||
}); | ||
}); | ||
}; | ||
// Sets the output rate of the data (1.56-800 Hz) | ||
Accelerometer.prototype.setOutputRate = function (hz, callback) { | ||
var self = this; | ||
// 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); | ||
}); | ||
}); | ||
}; | ||
// Sets the accelerometer to read up to 2, 4, or 8 Gs of acceleration (smaller range = better precision) | ||
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); | ||
}); | ||
}); | ||
}; | ||
function use (hardware, callback) { | ||
return new Accelerometer(hardware, callback); | ||
} | ||
exports.Accelerometer = Accelerometer; | ||
exports.connect = function (hardware) { | ||
return new Accelerometer(hardware); | ||
}; | ||
exports.use = use; |
{ | ||
"name": "accel-mma84", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Library to run the MMA8452Q accelerometer.", | ||
"main": "index.js", | ||
"dependencies" : { | ||
"sync-queue" : "0.0.1" | ||
}, | ||
"hardware": { | ||
"./examples": false | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "./testsuite.js" | ||
}, | ||
"repository": "", | ||
"devDependencies": { | ||
"tape": "~2.3.2", | ||
"tap": "git+https://github.com/tcr/node-tap.git#3cb76e", | ||
"shelljs": "~0.3.0" | ||
}, | ||
"repository": "https://github.com/tessel/accel-mma84", | ||
"author": "Tim Cameron Ryan <tim@timryan.org>", | ||
"license": "MIT" | ||
} |
@@ -1,41 +0,68 @@ | ||
# MMA8452Q accelerometer driver | ||
#Accelerometer | ||
Driver for the accel-mma84 Tessel accelerometer module ([MMA8452Q](http://www.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf)). | ||
Install: | ||
##Installation | ||
```sh | ||
npm install accel-mma84 | ||
``` | ||
npm install accel-mmq84 | ||
``` | ||
Import: | ||
##Example | ||
```js | ||
/********************************************* | ||
This basic accelerometer example logs a stream | ||
of x, y, and z data from the accelerometer | ||
*********************************************/ | ||
var tessel = require('tessel'); | ||
var accel = require('accel-mma84').use(tessel.port['A']); | ||
// Initialize the accelerometer. | ||
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('error connecting', err); | ||
}); | ||
setInterval(function(){}, 20000); | ||
``` | ||
var accel = require('accel-mma84').connect(myhardwareapi); | ||
``` | ||
Functions: | ||
##Methods | ||
* **`accel`.initialize()** | ||
##### * `accel.availableOutputRates()` Logs the available interrupt rates in Hz. | ||
* **`accel`.getAcceleration(callback(err, xyz))** | ||
##### * `accel.availableScaleRanges()` Logs the available accelerometer ranges (in units of Gs). | ||
## Example | ||
##### * `accel.enableDataInterrupts(trueOrFalse, callback(err))` Enables or disables data interrupts. Set the first param truthy to enable, falsy to disable. | ||
` | ||
var accel = require('../').connect(myhardwareapi); | ||
##### * `accel.getAcceleration(callback(err, xyz))` Gets the acceleration from the device, outputs as array [x, y, z]. | ||
// Initialize the accelerometer. | ||
accel.on('connected', function () { | ||
// Loop forever. | ||
setInterval(function () { | ||
accel.getAcceleration(function (err, xyz) { | ||
console.log("x:", xyz.x.toFixed(2), | ||
"y:", xyz.y.toFixed(2), | ||
"z:", xyz.z.toFixed(2)); | ||
}); | ||
}, 100); | ||
}); | ||
` | ||
##### * `accel.setOutputRate(rateInHz, callback(err))` Sets the output rate of the data (1.56-800 Hz). | ||
##### * `accel.setScaleRange(scaleRange, callback(err))` Sets the accelerometer to read up to 2, 4, or 8 Gs of acceleration (smaller range = better precision). | ||
##Events | ||
##### * `accel.on('data', callback(xyz))` Emitted when data is available. `xyz` is an array in the form of [x, y, z]. | ||
##### * `accel.on('error', callback(err))` Emitted upon error. | ||
##### * `accel.on('ready', callback())` Emitted upon first successful communication between the Tessel and the module. | ||
##Further Examples | ||
See the examples folder for code. | ||
* show-axes: Manipulate LEDs based on acceleration in the three axes. | ||
* change-rates: Change the polling rate. | ||
## License | ||
MIT | ||
MIT | ||
APACHE |
Sorry, the diff of this file is not supported yet
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
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
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
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
31274
12
470
2
69
1
3
1
2
1
+ Addedsync-queue@0.0.1
+ Addedsync-queue@0.0.1(transitive)