master
David Kebler 2017-01-12 20:05:20 -08:00
commit 4c08f12300
10 changed files with 376 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/node_modules/
/coverage/

13
.jshglobals Normal file
View File

@ -0,0 +1,13 @@
{
"globals": {
"Debug" : true,
/* MOCHA */
"describe" : false,
"it" : false,
"xit" : false,
"before" : false,
"beforeEach" : false,
"after" : false,
"afterEach" : false
}
}

70
.jshintrc Normal file
View File

@ -0,0 +1,70 @@
{
// https://gist.github.com/connor/1597131
// Globals - import repo spectific globals
"extends": "./.jshglobals",
// Settings
"passfail" : false, // Stop on first error.
"maxerr" : 100, // Maximum error before stopping.
// Predefined globals whom JSHint will ignore.
"browser" : true, // Standard browser globals e.g. `window`, `document`.
"node" : true,
"rhino" : false,
"couch" : false,
"wsh" : true, // Windows Scripting Host.
"jquery" : true,
"prototypejs" : false,
"mootools" : false,
"dojo" : false,
// Development.
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
"devel" : true, // Allow developments statements e.g. `console.log();`.
// ECMAScript
"esversion" : 6, //use this in new version of jshint
"strict" : false, // Require `use strict` pragma in every file.
"globalstrict" : false, // Allow global "use strict" (also enables 'strict').
// The Good Parts.
"asi" : true, // Tolerate Automatic Semicolon Insertion (no semicolons).
"laxbreak" : true, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
"bitwise" : true, // Allow bitwise operators (&, |, ^, etc.).
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
"curly" : true, // Require {} for every new block or scope.
"eqeqeq" : true, // Require triple equals i.e. `===`.
"eqnull" : false, // Tolerate use of `== null`.
"evil" : false, // Tolerate use of `eval`.
"expr" : false, // Tolerate `ExpressionStatement` as Programs.
"forin" : false, // Tolerate `for in` loops without `hasOwnPrototype`.
"immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
"latedef" : false, // Prohipit variable use before definition.
"loopfunc" : false, // Allow functions to be defined within loops.
"noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`.
"regexp" : true, // Prohibit `.` and `[^...]` in regular expressions.
"regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`.
"scripturl" : true, // Tolerate script-targeted URLs.
"shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`.
"supernew" : false, // Tolerate `new function () { ... };` and `new Object;`.
"undef" : true, // Require all non-global variables be declared before they are used.
// Personal styling preferences.
"newcap" : false, // Require capitalization of all constructor functions e.g. `new F()`.
"noempty" : true, // Prohibit use of empty blocks.
"nonew" : true, // Prohibit use of constructors for side-effects.
"nomen" : true, // Prohibit use of initial or trailing underbars in names.
"onevar" : false, // Allow only one `var` statement per function.
"plusplus" : false, // Prohibit use of `++` & `--`.
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
"trailing" : true, // Prohibit trailing whitespaces.
"white" : false, // Check against strict whitespace and indentation rules.
"indent" : 2 // Specify indentation spacing
}

4
.npmignore Normal file
View File

@ -0,0 +1,4 @@
tests/
test/
*.test.js
testing/

14
.travis.yml Normal file
View File

@ -0,0 +1,14 @@
language: node_js
node_js:
- '4.0'
- '5.0'
- '6.0'
- 'node'
sudo: false
script: npm test
after_success:
- bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"

8
index.js Normal file
View File

@ -0,0 +1,8 @@
let opts = {
dirname: __dirname + '/lib',
// http://stackoverflow.com/questions/2078915/a-regular-expression-to-exclude-a-word-string
filter: /^(?!index)([^\.].*)\.js?$/,
recursive: false,
merge: true // remove or comment to have each file in /lib be a prop/key in library...see node-require-all
}
module.exports = require('require-all')(opts);

146
lib/mcp23008-17.js Normal file
View File

@ -0,0 +1,146 @@
'use strict'
const Device = require('./device').Device,
Port = require('./gpio').Port,
_u = require('uci-utils')
const pSeries = require('p-series');
class MCP23008 extends Device {
constructor(busObj, i2cAddress, opts) {
super(busObj, i2cAddress, opts)
// opts could pass in array of custom pin config, or single for all, or anything
// this.registers = registers // load in register database
this.ports = {}
opts.portID = 'A'
this.ports.A = new Port(opts)
// if not specified there RPi is not managing the interrupt
// pin number on RPi that is connected to and services the interrupt. 4/17/27/22 = 7/11/13/15
this.ports.A.interPin = opts.interPin
} // end constructor
init() {
console.log('chip ', chip_config.cmd, chipSetByte())
return this.write(chip_config.cmd, chipSetByte()) // configure chip
.then(this.writePinsCfg())
}
pin(id) { return this.ports.A.pin(id) } // get a reference to a particular pin's object
// pin configurations should already be set before calling
writePinsCfg() {
let jobs = [];
for (let port in this.ports) {
for (let setting in registers.pin_config) {
let reg = registers.pin_config[setting]
if (port === 'B') { reg = reg + 16 }
let byte = 0;
let pins = this.ports[port].allPins
for (let i = 0; i < 8; i++) {
let pin = pins[i]
byte += pin.address.toFmt('DEC') * pin.cfg[setting]
}
// console.log(`port ${port} - setting ${setting} - reg ${reg} - byte ${byte}`)
jobs.push(
() => this.write(reg, byte) // .then((resp)=>console.log(`done writing config ${resp}`))
)
}
}
return pSeries(jobs)
} // end writePinsCfg
pinRead(id, opts) {
let mcpdev = this;
return new Promise(function (resolve, reject) {
let cmd = opts.cmd ? opts.cmd : 'gpio'
let reg = registers.pin_cmd[cmd]
let gpio = mcpdev.pin(id, opts.port)
if (!gpio) {
reject('no pin found for given id')
}
if (gpio.port === 'B') {
reg = reg + 16
}
// call device class read
console.log('port - reg', gpio.port, reg)
return mcpdev.read(reg).then(resp => {
resp = _u.byteFormat(resp, { in: 'DEC',
out: 'ARY'
})
let addr = gpio.pin.address.toFmt('ARY')
console.log(addr)
console.log(resp)
resolve(_u.sum(_u.and(addr, resp))) // resolve 1 or 0
})
})
.then(state => console.log(`pin state ${state}`))
.catch(err => console.log(err)) // end Promise
} // end pinRead
} // end 23008
module.exports.MCP23008 = MCP23008
class MCP23017 extends MCP23008 {
constructor(busObj, i2cAddress, opts) {
super(busObj, i2cAddress, opts)
// add a second port
opts.portID = 'B'
this.ports.B = new Port(opts)
this.ports.A.interPin = opts.interPin // if not specified the RPi is not managing the interrupt
}
pin(id, port) {
if (!port) {
return this.ports.A.pin(id) ? this.ports.A.pin(id) : this.ports.B.pin(id)
}
return this.ports[port].pin(id)
}
} // end MCP23017 Class
module.exports.MCP23017 = MCP23017
/* ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
* or see MCP23017.pdf and MCP 23008.pdf in /docs
* see table 1.5 and details in sections 1.6.x following
* !!! for 23017 MUST initialize with bit 7 "BANK" of IOCON = 1 for the addresses below
* then for all registers add 16 (0x10) to each reg address to talk to PortB pins
* this will make reg addresses be equilvant for 23008 and PortA of 23017
* reg addresses in the config objects are all in Hexidecminal
*/
// Chip cConfiguration to be used with Register
let chip_config = {
// byte: ['NULL','INTPOL','ODR','HAEN','DISSLW','SEQOP','MIRROR','BANK'] // see page 18 of 23017 datasheet for 8 setting details
cmd: 0x0A, // IOCON
default: {
val: '10000000', // int pins connected, port A + 0x10 = Port B -- ignored by 23008
fmt: 'STR'
},
twoints: {
val: '00000001', // int pins separate, port A + 0x10 = Port B -- ignored by 23008
fmt: 'STR'
}
}
function chipSetByte(setting = 'default') {
setting = chip_config[setting]
return _u.byteFormat(setting.val, { in: setting.fmt,
out: 'DEC'
})
}
let registers = {
pin_config: {
dir: 0,
ivrt: 1,
pullup: 6,
intr: 2,
usedef: 4,
defval: 3,
},
pin_cmd: {
intf: 7, // readonly
intcap: 8, // readonly
gpio: 9, // read/write
olat: 10 // read only
}
}

34
package.json Normal file
View File

@ -0,0 +1,34 @@
{
"name": "uci-mcp",
"version": "0.0.1",
"description": "classes and functions for use the MCP chips",
"main": "index.js",
"scripts": {
"testw": "./node_modules/.bin/mocha --reporter list --recursive --watch",
"test": "istanbul cover ./node_modules/.bin/_mocha test/ --report lcovonly -- -R spec --recursive && codecov || true"
},
"author": "David Kebler",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/uCOMmandIt/uci-mcp.git"
},
"keywords": [
"node.js",
"microchip",
"i2c"
],
"bugs": {
"url": "https://github.com/uCOMmandIt/uci-mcp/issues"
},
"homepage": "https://github.com/uCOMmandIt/uci-mcp#readme",
"dependencies": {
"require-all": "git+https://github.com/dkebler/node-require-all.git#merge"
},
"devDependencies": {
"chai": "^3.5.0",
"codecov": "^1.0.1",
"istanbul": "^0.4.5",
"mocha": "^3.2.0"
}
}

12
readme.md Normal file
View File

@ -0,0 +1,12 @@
# uCOMmandIt MCP - Micro Chip Library
[![Build Status](https://img.shields.io/travis/uCOMmandIt/uci-mcp.svg?branch=master)](https://travis-ci.org/uCOMmandIt/uci-mcp)
[![Inline docs](http://inch-ci.org/github/uCOMmandIt/uci-mcp.svg?branch=master)](http://inch-ci.org/github/uCOMmandIt/uci-mcp)
[![Dependencies](https://img.shields.io/david/uCOMmandIt/uci-mcp.svg)](https://david-dm.org/uCOMmandIt/uci-mcp)
[![devDependencies](https://img.shields.io/david/dev/uCOMmandIt/uci-mcp.svg)](https://david-dm.org/uCOMmandIt/uci-mcp?type=dev)
[![codecov](https://img.shields.io/codecov/c/github/uCOMmandIt/uci-mcp/master.svg)](https://codecov.io/gh/uCOMmandIt/uci-mcp)
**Classes and Library to Support Microchip corporation chips**
http://www.microchip.com/wwwproducts/en/mcp23017
http://www.microchip.com/wwwproducts/en/mcp23008

73
test/mcp.test.js Normal file
View File

@ -0,0 +1,73 @@
'use strict'
const expect = require('chai').expect,
i2c = require('../class'),
_u = require('uci-utils')
let bus1 = new i2c.Bus(1)
// console.log(bus1)
// bus1.scan((devs)=>{console.log('devices: ', devs)})
//bus1.scan().then(results=>console.log(results))
describe('I2C Device Classes - ', function () {
let mcp17 = new i2c.MCP.MCP23017(bus1, 0x20, {
name: 'switches 1-16'
})
describe('MCP23017 Class - ', function () {
it('can set and get a single pin config', function () {
expect(mcp17.pin(8).cfg.dir, "pin address getter failed").to.equal(0)
mcp17.portA.pin(8).cfg.dir = 1
console.log(mcp17.pin(8).cfg.dir)
// expect(mcp17.pin(8).config.dir, "pin address setter failed").to.equal(1)
});
it('a pin can access device methods when attached to a device', function () {
expect(mcp17.portA.pin(8).device.address.val).to.equal(mcp17.address.val)
})
});
let mcp8 = new i2c.MCP.MCP23008(bus1, 0x21, {
cfgDefault: 'output',
name: 'relay 1-8'
})
describe('MCP23008 Class - ', function () {
mcp8.pin(8).dir = 1
it('can set and get a single pin config', function () {
expect(mcp8.port.pin(8).dir, "pin address getter failed").to.equal(1)
mcp8.port.pin(8).dir = 0
expect(mcp8.port.pin(8).dir, "pin address getter failed").to.equal(0)
expect(mcp8.port.pin(8).itr, "pin address getter failed").to.equal(Boolean(0))
});
it('a pin can access device methods when attached to a device', function () {
expect(mcp17.portA.pin(8).device.address.val).to.equal(mcp17.address.val)
})
// console.log(bus1.bus.writeI2cBlock_p)
// mcp8.func()
const ADDR = 0x21,
DIR = 0x00,
RW = 0x09,
ALLPINS = 0x40,
NOPINS = 0x00
mcp8.write(DIR, 0x00).then(() =>
mcp8.write(RW, ALLPINS).then(() =>
mcp8.read(RW, ALLPINS).then((resp) => {
console.log('relays on', resp)
})
)
)
});
});