diff --git a/demo/interrupt.js b/demo/interrupt.js new file mode 100644 index 0000000..e5db5bc --- /dev/null +++ b/demo/interrupt.js @@ -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() + +})() diff --git a/demo/read-write.js b/demo/read-write.js deleted file mode 100644 index 5c765fb..0000000 --- a/demo/read-write.js +++ /dev/null @@ -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 -} diff --git a/demo/sample.js b/demo/sample.js index adcd7ce..97d0c50 100644 --- a/demo/sample.js +++ b/demo/sample.js @@ -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') diff --git a/package.json b/package.json index 577b216..c75962a 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/lib/mcp23008-17.js b/src/mcp23008-17.js similarity index 84% rename from lib/mcp23008-17.js rename to src/mcp23008-17.js index 085d94f..db8f7c0 100644 --- a/lib/mcp23008-17.js +++ b/src/mcp23008-17.js @@ -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 diff --git a/lib/port-pin.js b/src/port-pin.js similarity index 86% rename from lib/port-pin.js rename to src/port-pin.js index 06a5af2..08e0a84 100644 --- a/lib/port-pin.js +++ b/src/port-pin.js @@ -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)) { diff --git a/test/mcp.test.js b/test/mcp.test.js index 8f0c038..91a7f35 100644 --- a/test/mcp.test.js +++ b/test/mcp.test.js @@ -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 + }) + +}