improved sample demo, added interrrupt demo, and added mocha hooks to test suite, added function to determine which pin of port fired the interrupt, added pin id to port pins

master
David Kebler 2017-05-28 21:44:35 -07:00
parent 02b291811d
commit 095a11064e
7 changed files with 114 additions and 120 deletions

43
demo/interrupt.js Normal file
View File

@ -0,0 +1,43 @@
// to try this demo
// npm install @uci/interrupt
// Connect 5V MCP interrupt pin via 3.3 V logic level!!!!! converter to a gpio pin
// Set your SETTINGS below
// npm run inter
const Bus = require('@uci/i2c').Bus,
MCP = require('../src/mcp23008-17'),
// use this require when using your own code
// MCP = require('@uci/mcp')
Interrupt = require('@uci/interrupt')
let bus = new Bus()
// SETTINGS
let ADDR = 0x20
let CHIP = 'MCP23017'
let MS = 300 // so humans can watch the light otherwise set to zero
let pinA = 12
let pinB = 16
let id = `${CHIP} at I2C bus address of 0x${ADDR.toString(16)}`
async function ihandler(port) {
let pin = await this.interruptPin(port, 'PLC')
console.log(`handler fired for ${this.id} on port ${port} pin ${pin}`)
await this.interruptReset(port)
}
let mcp = new MCP[CHIP](bus, ADDR, {
pin_cfg_default: 'toggle_switch',
id: id,
interruptA: new Interrupt(pinA, ihandler),
interruptB: new Interrupt(pinB, ihandler)
});
(async function () {
await mcp.init()
// start will start the
await mcp.start()
})()

View File

@ -1,68 +0,0 @@
//to run this test you MUST install @uci/i2c which is not a dependency of @uci/mcp
// npm install @uci/i2c
const Bus = require('@uci/i2c').Bus,
MCP = require('../lib/mcp23008-17'),
expect = require('chai').expect,
pause = require('@uci/utils').pPause
let bus = new Bus()
let ADDR = 0x24
let CHIP = 'MCP23017'
let MS = 500 // so humans can watch the light otherwise set to zero
let PORT = 'B'
let mcp = new MCP[CHIP](bus, ADDR, {
pin_cfg_default: 'output',
});
(async function () {
await mcp.init()
await mcp.allOff(PORT) // start clean
await eachpin()
await somepins()
})()
//****************** TEST SUITES **********************
async function eachpin() {
let result
for (let pin of mcp.ports[PORT].pins) {
await mcp.on(pin.address, PORT)
result = await mcp.readPort(PORT)
console.log(pin.address, result)
await mcp.off(pin.address, PORT)
await pause(MS)
}
}
async function somepins() {
let pins = [1, 7, 8]
await mcp.on(pins, PORT, 'PLC')
let shouldbe = [1, 7, 8]
let result = await mcp.readPort(PORT, { format: 'PLC' })
console.log(pins, shouldbe, result)
await pause(MS)
pins = [2, 1, 7]
await mcp.on(pins, PORT, 'PLC')
shouldbe = [2, 1, 7, 8]
result = await mcp.readPort(PORT, { format: 'PLC' })
console.log(pins, shouldbe, result)
await pause(MS)
pins = [2, 1, 6]
await mcp.toggle(pins, PORT, 'PLC')
shouldbe = [6, 7, 8]
result = await mcp.readPort(PORT, { format: 'PLC' })
console.log(pins, shouldbe, result)
await pause(MS)
pins = [2, 1, 7]
await mcp.off(pins, PORT, 'PLC')
shouldbe = [6, 8]
result = await mcp.readPort(PORT, { format: 'PLC' })
console.log(pins, shouldbe, result)
await pause(MS)
await mcp.allOff(PORT) // clear port after each test
}

View File

@ -1,15 +1,15 @@
const Bus = require('@uci/i2c').Bus,
MCP = require('../lib/mcp23008-17'),
MCP = require('../src/mcp23008-17'),
// use this require when using your own code
// MCP = require('@uci/mcp')
pause = require('@uci/utils').pPause
let bus = new Bus()
let ADDR = 0x24
let ADDR = 0x27
let CHIP = 'MCP23017'
let MS = 300 // so humans can watch the light otherwise set to zero
let PORT = 'A'
let PORT = 'B'
let mcp = new MCP[CHIP](bus, ADDR);
@ -39,12 +39,11 @@ let mcp = new MCP[CHIP](bus, ADDR);
await pause(MS)
let pin = 7
result = await mcp.readPin(pin) ? 'on' : 'off'
result = await mcp.readPin(pin, PORT) ? 'on' : 'off'
console.log(`Pin ${pin} is ${result}`)
pin = 6
// result = await mcp.readPin(pin)
result = await mcp.readPin(pin) ? 'on' : 'off'
result = await mcp.readPin(pin, PORT) ? 'on' : 'off'
console.log(`Pin ${pin} is ${result}`)
console.log('all pins off')

View File

@ -1,6 +1,6 @@
{
"name": "@uci/mcp",
"main": "index.js",
"main": "src/mcp23008-17.js",
"version": "0.1.0",
"description": "Classes and Helper Functions for using the MCP chip on I2C Bus",
"scripts": {
@ -10,7 +10,8 @@
"testd2": "DEBUG='1:*,2:*' ./node_modules/.bin/mocha --reporter list --watch --timeout 30000",
"testd3": "DEBUG='1:*,2:*,3:*' ./node_modules/.bin/mocha --reporter list --watch --timeout 30000",
"testibc": "istanbul cover ./node_modules/.bin/_mocha test/ --report lcovonly -- -R spec --recursive && codecov || true",
"sample": "node demo/sample.js"
"sample": "node demo/sample.js",
"inter": "sudo node demo/interrupt.js"
},
"author": "David Kebler",
"license": "MIT",

View File

@ -28,6 +28,8 @@ class MCP23008 extends Device {
pid(address) { return this.ports.A.pid(address) } // return pin id for a given address on a port
pid(num) { return this.ports.A.pins[num - 1].id }
portByPin(id) {
if (this.ports.A.pin(id)) { return 'A' }
return false
@ -48,6 +50,7 @@ class MCP23008 extends Device {
debug.L1(`\n=======\nInitializing ${this.id}`)
await this.writeChipCfg(this.chip_config) // chip settings
await this.writePinsCfg()
// write out any loaded state
for (let port in this.ports) {
await this.writePort(this.state(port), 'force', port)
}
@ -56,28 +59,44 @@ class MCP23008 extends Device {
// must call after init if using interrupts
async start() {
debug.L1(`starting ${ this.id }`)
for (let port of this.ports) {
for (let port in this.ports) {
// if there are interrupts being used then start them and listeners
if (this.inter(port)) {
await this.interruptReset(port)
await this.inter(port).start()
// bind handler to the chip so handler can read/write to chip/bank when interrupt is emitted
let ihandler = this.inter(port).handler.bind(this)
// inside the listener `this` is the interrupt not the chip/bank
this.inter(port).on('fired', function () {
debug.L1(`interrupt from ${this.pin_number}`)
ihandler(port)
})
this.startInterrupt(port)
}
}
}
async startInterrupt(port) {
await this.interruptReset(port)
await this.inter(port).start()
// bind handler to the chip so handler can read/write to chip/bank when interrupt is emitted
debug.L2('handler', this.inter(port).handler)
let ihandler = this.inter(port).handler.bind(this)
// inside the listener `this` is the interrupt not the chip/bank
this.inter(port).on('fired', function () {
debug.L1(`interrupt from ${this.pin_number}`)
ihandler(port)
})
}
async interruptReset(port = 'A') {
await this.read(portReg(0x08, port))
await pause(100) // give enough time for mcp to reset its interupt
debug.L1(`interrupt reset on ${this.id} port ${port}`)
}
async interruptPin(port, format) {
if ('AB'.indexOf(port) === -1) {
format = port ? port : null
port = 'A'
}
let result = await this.read(portReg(0x07, port))
return format ? _.byteFormat(result, { in: 'DEC', out: format }) : result
}
async writeChipCfg(cfg = 'default') {
let setting = chip_config[cfg]
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
@ -109,7 +128,13 @@ class MCP23008 extends Device {
}
let cmd = opts.cmd ? opts.cmd : 'gpio'
let result = await this.read(portReg(registers.pin_cmd[cmd], port))
this.ports[port].state.value = result
debug.L2('read prev ', this.ports[port].state.toFmtPrev('ARY'))
debug.L2('read result', _.byteFormat(result, { in: 'DEC', out: 'ARY' }))
debug.L2('read state ', this.ports[port].state.toFmt('ARY'))
// if port pins changed without a write then update state
if (_.bitChanges(_.byteFormat(result, { in: 'DEC', out: 'ARY' }), this.ports[port].state.toFmt('ARY'))) {
this.ports[port].state.value = result
}
return opts.format ? this.ports[port].state.toFmt(opts.format) : result
}
@ -206,6 +231,8 @@ class MCP23017 extends MCP23008 {
return this.ports[port].pin(id)
}
pid(num, port) { return this.ports[port].pins[num - 1].id }
} // end MCP23017 Class
// EXPORTS

View File

@ -10,6 +10,7 @@ class Pin {
// a pin id MUST be supplied in opts 1 to 8
this.id = id
// a custom pin configuration can be passed or choosen from one of the sets, if neither than the default output config is chosen
// TODO allow custom pin configurations based on passed opts so individual pins can be configured differently
if (opts.pin_cfg_default) {
if (_.keyExists(config_sets, opts.pin_cfg_default)) {
this.config = _.clone(config_sets[opts.pin_cfg_default])
@ -57,21 +58,16 @@ class Pin {
// A port of 8 GPIO pins
class Port {
constructor(opts) {
constructor(opts = {}) {
if (opts) {
this.reverse = opts.reverse ? opts.reverse : false
this.id = opts.portID ? opts.portID : ''
this.desc = opts.portDesc ? opts.portDesc : ''
} else {
opts = {}
this.reverse = false
}
this.id = opts.portID ? opts.portID : ''
this.desc = opts.portDesc ? opts.portDesc : ''
// Create group of 8 pins for port
this.pins = new Array(8)
let pid = ''
for (let i = 0; i < 8; i++) {
this.pins[i] = new Pin(i, Math.pow(2, i), opts)
pid = opts.pids ? opts.pids[i] : i + 1
this.pins[i] = new Pin(pid, Math.pow(2, i), opts)
}
}
@ -93,14 +89,6 @@ class Port {
//====================
// needs to take current pin and pick out details and make a call the contstructor.
// clone(adr, alias) {
// let newPin = _.clone(this)
// newPin.address = adr
// newPin.alias = alias
// return newPin
// }
// return list of all pin configs, handle to particular config or adding of custom pin configuration at runtime
function configs(cfg) {
if (_.isString(cfg)) {

View File

@ -7,10 +7,10 @@ const Bus = require('@uci/i2c').Bus,
let bus = new Bus()
let ADDR = 0x24
let ADDR = 0x27
let CHIP = 'MCP23017'
let MS = 300 // so humans can watch the lights on boards with leds otherwise set to zero
let PORT = 'A'
let PORT = 'B'
let id = `${CHIP} at I2C bus address of 0x${ADDR.toString(16)}`
@ -19,22 +19,10 @@ let mcp = new MCP[CHIP](bus, ADDR, {
id: id
});
describe('set up MCP Chip', () => {
before(async() => {
await mcp.init()
})
beforeEach(async() => {
await mcp.allOff(PORT) // start clean
})
})
describe(
`Testing Chip ${id}, port: ${PORT}`,
function () {
hooks()
eachpin()
somepins()
})
@ -86,3 +74,19 @@ function somepins() {
})
}
function hooks() {
before(async() => {
await mcp.init()
})
beforeEach(async() => {
await mcp.allOff(PORT) // start clean
})
after(async() => {
await mcp.allOff(PORT) // start clean
})
}