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
parent
02b291811d
commit
095a11064e
|
@ -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()
|
||||
|
||||
})()
|
|
@ -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
|
||||
}
|
|
@ -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')
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,20 +59,26 @@ 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)) {
|
||||
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') {
|
||||
|
@ -78,6 +87,16 @@ class MCP23008 extends Device {
|
|||
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))
|
||||
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
|
|
@ -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
|
||||
}
|
||||
// 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)) {
|
|
@ -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
|
||||
})
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue