Add JavaScript mraaStub project
Signed-off-by: David Antler <david.a.antler@intel.com> Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
committed by
Brendan Le Foll
parent
a321d6707f
commit
1cfdfcddc6
17
jsstub/Gruntfile.js
Normal file
17
jsstub/Gruntfile.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module.exports = function(grunt) {
|
||||||
|
grunt.loadNpmTasks('grunt-mocha-test');
|
||||||
|
// Project configuration.
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
mochaTest: {
|
||||||
|
test: {
|
||||||
|
options: {
|
||||||
|
reporter: 'spec'
|
||||||
|
},
|
||||||
|
src: ['test/*.js']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
grunt.registerTask('test', ['mochaTest:test']);
|
||||||
|
};
|
||||||
52
jsstub/README.md
Normal file
52
jsstub/README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
mraaStub - JavaScript simulation and stubs for mraa
|
||||||
|
====================
|
||||||
|
|
||||||
|
This project enables simulation of a device which might be accessed via mraa.
|
||||||
|
Currently this library supports I2c, SPI, and GPIO. This project provides
|
||||||
|
several benefits:
|
||||||
|
|
||||||
|
1. Prevent crashes in nodejs applications using mraa on unsuported or
|
||||||
|
misconfigured hardware.
|
||||||
|
2. Enable basic simulation of mraa-accessible devices for unit testing.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
The following example is based on an imaginary 'light bulb' device abstraction,
|
||||||
|
which exposes a value of brightness over a mraa-provided interface. Please see
|
||||||
|
the `test/index.js` file for an example.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
mraaStub is not yet in npm so has to be installed from git. In the future
|
||||||
|
you'll be able to install `mraaStub` from npm like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install mraaStub
|
||||||
|
```
|
||||||
|
|
||||||
|
Since we often switch between a mraaStub and the real mraa library, we
|
||||||
|
suggest creating an `index.js` file inside a `lib/mraaSwitcher` folder.
|
||||||
|
|
||||||
|
```js
|
||||||
|
/* index.js - file for switching between mraa and mraaStub
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Define the conditions under which the mraaStub should be loaded
|
||||||
|
var platform = require('os').platform();
|
||||||
|
var m;
|
||||||
|
|
||||||
|
if (platform === 'win32') {
|
||||||
|
m = require('mraaStub');
|
||||||
|
} else {
|
||||||
|
m = require('mraa');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = m;
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add this to your project in its own `lib/mraaSwitcher/index.js` file
|
||||||
|
and use `require('../mraaSwitcher')` everywhere!
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
See [COPYING file](../COPYING) in the root of this repository.
|
||||||
223
jsstub/index.js
Normal file
223
jsstub/index.js
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview This file implements a fake mraa stub which enables testing
|
||||||
|
* as well as the ability to run on Windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var m;
|
||||||
|
var winston = require('winston');
|
||||||
|
var logger = new winston.Logger({
|
||||||
|
transports: [
|
||||||
|
new winston.transports.Console({
|
||||||
|
level: 'error',
|
||||||
|
handleExceptions: false,
|
||||||
|
json: false,
|
||||||
|
colorize: true})
|
||||||
|
],
|
||||||
|
exitOnError: false
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class mraaStub
|
||||||
|
* @classdesc This class is designed to stub out libmraa so we can run
|
||||||
|
* test code on unsupported platforms (specifically Windows).
|
||||||
|
*/
|
||||||
|
var mraaStub = function() {
|
||||||
|
var verison = '0.0.1';
|
||||||
|
var self = this;
|
||||||
|
self.EDGE_BOTH = 1;
|
||||||
|
self.EDGE_NONE = 2;
|
||||||
|
self.EDGE_RISING = 3;
|
||||||
|
self.EDGE_FALLING = 4;
|
||||||
|
self.DIR_IN = 1;
|
||||||
|
self.DIR_OUT = 2;
|
||||||
|
|
||||||
|
self.getVersion = function() {
|
||||||
|
return "mraaStub " + version;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stub out GPIO
|
||||||
|
function Gpio(num) {
|
||||||
|
this.num = num;
|
||||||
|
this._callback = null;
|
||||||
|
this._dir = null;
|
||||||
|
this._isr_mode = self.EDGE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
var logGpio = false;
|
||||||
|
Gpio.prototype._callIsr = function() {
|
||||||
|
if(this.isr_mode === self.EDGE_NONE) {
|
||||||
|
logger.log('info',"Could not call ISR. Not set up for triggering");
|
||||||
|
}
|
||||||
|
this._callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
Gpio.prototype.isr = function(mode, handler){
|
||||||
|
if(logGpio) {
|
||||||
|
logger.log('info',"GPIO " + this.num + " isr stub invoked.");
|
||||||
|
}
|
||||||
|
this._isr_mode = self.EDGE_NONE;
|
||||||
|
this._callback = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
Gpio.prototype.dir = function(d) {
|
||||||
|
if(logGpio) {
|
||||||
|
logger.log('info',"GPIO " + this.num + " dir stub invoked.");
|
||||||
|
}
|
||||||
|
this._dir = d;
|
||||||
|
};
|
||||||
|
Gpio.prototype.write = function(z) {
|
||||||
|
if(logGpio) {
|
||||||
|
logger.log('logger',"GPIO " + this.num + " write stub invoked.");
|
||||||
|
}
|
||||||
|
if(this._dir !== self.DIR_OUT) {
|
||||||
|
logger.log('info',"GPIO " + this.num + " write called without DIR_OUT set.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Gpio.prototype.read = function() {
|
||||||
|
if(logGpio) {
|
||||||
|
logger.log('info',"GPIO " + this.num + " read stub invoked.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stub out SPI
|
||||||
|
function Spi(num) {
|
||||||
|
var self = this;
|
||||||
|
this.num = num;
|
||||||
|
this._buffer = new Buffer(29);
|
||||||
|
this._buffer.fill(0);
|
||||||
|
this._loopback = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Spi.prototype._setOutput = function(buf) {
|
||||||
|
this._buffer = buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
Spi.prototype._enableLoopback = function(x) {
|
||||||
|
if(x === true) {
|
||||||
|
this._loopback = true;
|
||||||
|
} else {
|
||||||
|
this._loopback = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Spi.prototype.write = function(b) {
|
||||||
|
logger.log('info',"SPI write stub invoked.");
|
||||||
|
if(this._loopback === true) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return new Buffer(this._buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
Spi.prototype.frequency = function(f) {
|
||||||
|
logger.log('info',"SPI frequency stub invoked.");
|
||||||
|
return f;
|
||||||
|
};
|
||||||
|
|
||||||
|
Spi.prototype.lsbmode = function(t) {
|
||||||
|
logger.log('info',"SPI lsbmode stub invoked.");
|
||||||
|
};
|
||||||
|
|
||||||
|
Spi.prototype.mode = function(x) {
|
||||||
|
logger.log('info',"SPI mode stub invoked.");
|
||||||
|
};
|
||||||
|
|
||||||
|
function I2c(num) {
|
||||||
|
this._num = num;
|
||||||
|
this._regMapInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function sets an internal register map for the I2c device.
|
||||||
|
*/
|
||||||
|
I2c.prototype._setRegisterMapInternal = function(buffer) {
|
||||||
|
this._regMapInitialized = true;
|
||||||
|
this._buffer = buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.frequency = function(freq) {
|
||||||
|
// Do nothing. We don't care.
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.address = function(address) {
|
||||||
|
var self = this;
|
||||||
|
self.address = address;
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.readReg = function(regAddr) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._buffer.readUInt8(regAddr);
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.readWordReg = function(regAddr) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._buffer.readUInt16LE(regAddr);
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.readBytesReg = function(regAddr, len) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._buffer.slice(regAddr,regAddr+len);
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.write = function(buf) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
var regAddr = buf[0];
|
||||||
|
var newBuf = buf.slice(1);
|
||||||
|
newBuf.copy(this._buffer, regAddr);
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.writeReg = function(regAddr, data) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._buffer.writeUInt8(regAddr,data);
|
||||||
|
};
|
||||||
|
|
||||||
|
I2c.prototype.writeWordReg = function(regAddr, dataWord) {
|
||||||
|
if(!this._regMapInitialized) {
|
||||||
|
logger.log('error', "Need to set reg map");
|
||||||
|
}
|
||||||
|
if(!this.address) {
|
||||||
|
logger.log('error', "Need to set address");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._buffer.writeUInt16LE(regAddr,data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export our stubs
|
||||||
|
self.Gpio = Gpio;
|
||||||
|
self.Spi = Spi;
|
||||||
|
self.I2c = I2c;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
m = new mraaStub();
|
||||||
|
|
||||||
|
module.exports = m;
|
||||||
34
jsstub/package.json
Normal file
34
jsstub/package.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "mraaStub",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Enables simulation of mraa interfaces for testing purposes",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "grunt test"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/intel-iot-devkit/mraa.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"mraa",
|
||||||
|
"iot",
|
||||||
|
"intel",
|
||||||
|
"libmraa",
|
||||||
|
"test",
|
||||||
|
"galileo",
|
||||||
|
"edison"
|
||||||
|
],
|
||||||
|
"author": "David A Antler <david.a.antler@intel.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/intel-iot-devkit/mraa/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/intel-iot-devkit/mraa#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"expect.js": "^0.3.1",
|
||||||
|
"grunt": "^1.0.1",
|
||||||
|
"grunt-mocha-test": "^0.12.7",
|
||||||
|
"mocha": "^2.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
jsstub/test/index.js
Normal file
32
jsstub/test/index.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
var expect = require('expect.js');
|
||||||
|
var m = require('../index');
|
||||||
|
var LightBulb = require('./lightbulb');
|
||||||
|
|
||||||
|
describe('LightBulb', function() {
|
||||||
|
|
||||||
|
/** Model the internal data of LightBulb as a buffer */
|
||||||
|
var bufferFullBrightness = new Buffer(
|
||||||
|
[ 'N', // Four bytes allocated for name
|
||||||
|
'a',
|
||||||
|
'm',
|
||||||
|
'e',
|
||||||
|
95 // One byte allocated for brightness. Stuff in '95' value!
|
||||||
|
]);
|
||||||
|
|
||||||
|
it('getBrightness() function should return 95', function() {
|
||||||
|
|
||||||
|
// Create a fake I2c bus based on the 'full brightness' data model
|
||||||
|
var testI2cBus = new m.I2c(0);
|
||||||
|
testI2cBus._setRegisterMapInternal(bufferFullBrightness);
|
||||||
|
|
||||||
|
// Create a new LightBulb that opens the testI2cBus, instead of a real
|
||||||
|
// mraa I2c bus.
|
||||||
|
var lightBulbI2c = new LightBulb(testI2cBus);
|
||||||
|
|
||||||
|
// presumably getBrightness will gather data from I2C and get '95'
|
||||||
|
var brightness = lightBulbI2c.getBrightness();
|
||||||
|
|
||||||
|
expect(brightness).to.be(95);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
32
jsstub/test/lightbulb.js
Normal file
32
jsstub/test/lightbulb.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Implementation of a LightBulb class abstraction
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (function() {
|
||||||
|
"use strict";
|
||||||
|
var m = require('../index');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for a new LightBulb
|
||||||
|
* @class LightBulb
|
||||||
|
*
|
||||||
|
* @classdesc This class abstracts access to the control and data registers
|
||||||
|
* on an imaginary lightbulb.
|
||||||
|
* @param {Object} A libmraa I2c object, initialized
|
||||||
|
*/
|
||||||
|
function LightBulb (i2cInterface) {
|
||||||
|
var self = this;
|
||||||
|
self._i2cInterface = i2cInterface;
|
||||||
|
|
||||||
|
self.getBrightness = function() {
|
||||||
|
// Presume our brightness data is one byte at offset 4
|
||||||
|
return self._i2cInterface.readReg(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LightBulb;
|
||||||
|
})();
|
||||||
|
|
||||||
Reference in New Issue
Block a user