From 9652041671712822baab76c7427d286d3d99f82c Mon Sep 17 00:00:00 2001 From: David Kebler Date: Sun, 4 Mar 2018 15:13:55 -0800 Subject: [PATCH] added mcp interrupt extension class that adds functionality to handle the mcp port interrupt using and external socket --- examples/mcp-switch-relay.mjs | 65 ++++++++++++++++++++ package.json | 4 +- src/commands.mjs | 28 +-------- src/config.mjs | 8 +++ src/index.mjs | 3 +- src/interrupt.mjs | 50 --------------- src/mcp230xx.mjs | 4 +- src/mcp230xxi.mjs | 111 ++++++++++++++++++++++++++++++++++ 8 files changed, 192 insertions(+), 81 deletions(-) create mode 100644 examples/mcp-switch-relay.mjs delete mode 100644 src/interrupt.mjs create mode 100644 src/mcp230xxi.mjs diff --git a/examples/mcp-switch-relay.mjs b/examples/mcp-switch-relay.mjs new file mode 100644 index 0000000..3784560 --- /dev/null +++ b/examples/mcp-switch-relay.mjs @@ -0,0 +1,65 @@ +/* +* +* +*/ +import { MCP230XXi } from '../src' +import { MCP230XX } from '../src' + +const BUS_HOST = 'sbc' +const BUS_PORT = 1776 // 1776 is default port for i2c-bus module +const SW_ADDRESS = 0x25 // 1776 is default port for i2c-bus module +const RY_ADDRESS = 0x27 // 1776 is default port for i2c-bus module + +// let chip8 = new MCP230XX({id:'mcp8-27', address:0x27, nmcp: { path: '/opt/sockets/mcp2.sock' }}) +// let sw17 = new MCP230XXi([9,10],{id:'sw17', chip17:true, host:BUS_HOST, address:SW_ADDRESS, iport:9000, 10:{mport:'B'}}) + +let sw17 = new MCP230XXi([9,10],{id:'sw17', chip17:true, host:BUS_HOST, address:SW_ADDRESS+1, iport:true, 10:{mport:'B'}}) +let sw8 = new MCP230XXi([24],{id:'sw8', host:BUS_HOST, address:SW_ADDRESS, iport:true}) +let ry8 = new MCP230XX({id:'ry8', host:BUS_HOST, address:RY_ADDRESS}) +sw17.reply = () => {} +ry8.reply = () => {} +sw8.reply = () => {} + +function iprocess(details) { + console.log('--common interrupt processor--') + console.log(details) + action(details) +} + +async function action (details) { + if (details.id === 'sw17') { + await ry8.pin.state.toggle({pins:details.pin}) + } + if (details.id === 'sw8') { + if (details.pin===1) { + if (details.state==='off') await ry8.pin.state.off({pins:'all'}) + else ry8.pin.state.on({pins:'all'}) + } + if (details.pin===8) { + if (details.state==='off') await ry8.pin.state.off({pins:'1,3,5,7'}) + else await ry8.pin.state.on({pins:'1,3,5,7'}) + } + } +} + + +(async () => { + + await sw17.init() + let cfg = {port:'B',pins:'1', cfg:'toggle_switch_pulldown'} + console.log(await sw17.pin.cfg(cfg)) + sw17.interruptProcessor(iprocess) + + + + await sw8.init() + sw8.interruptProcessor(iprocess) + + + await ry8.init() + let packet = {pins:'all', cfg:'output'} + await ry8.pin.cfg(packet) + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/package.json b/package.json index 7331f16..87c4646 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "version": "0.1.2", "description": "Classes and Helper Functions for using the MCP chip on I2C Bus", "scripts": { - "relays": "SOCKETS_DIR=/opt/sockets node --require @std/esm examples/relays", + "relays": "node --require @std/esm examples/relays", + "swr": "node --require @std/esm examples/mcp-switch-relay", "test": "./node_modules/.bin/mocha --reporter list --timeout 30000", "testw": "./node_modules/.bin/mocha --reporter list -- watch --timeout 30000", "testibc": "istanbul cover ./node_modules/.bin/_mocha test/ --report lcovonly -- -R spec --recursive && codecov || true", @@ -30,6 +31,7 @@ "@uci/i2c-device": "^0.1.1", "@uci/interrupt": "^0.1.1", "@uci/logger": "0.0.1", + "@uci/mqtt": "0.0.1", "@uci/utils": "^0.1.1" }, "@std/esm": "cjs", diff --git a/src/commands.mjs b/src/commands.mjs index 77beef2..1ba7286 100644 --- a/src/commands.mjs +++ b/src/commands.mjs @@ -20,6 +20,7 @@ export const chip = { let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' }) if (byte < 128) byte += 128 // make sure BANK=1 remains on let reg = this.chip17 ? 0x0A : 0x05 + // console.log(this.chip17, reg, this.id, this.address) bus = await this.bus.write(reg,byte) if (bus.error) return bus bus = await this.bus.read(0x05) @@ -96,34 +97,7 @@ export const pin = { toggle: async function (packet) { return this.pin._state(packet,'toggle') } - }, - // will create packet to determine pin caused interrupt, packet will come from interrupt module - interrupt: { - reset: async function (port) { - // console.log('resetting interrupt for port',port || 'A') - return await this.bus.read(sreg(PIN.cmd.intcap,port)) - }, - find: async function (inter) { - // console.dir(inter) - // console.log(inter.count,'th interrupt: pin fired',inter.pin, inter.port) - let packet = {pins:'all',reg:'intf'} - packet.port = inter.port==='B' ? inter.port : 'A' - let res = await this.pin.status(packet) - this.pin.interrupt.reset(packet.port) - if (!res.status) return {error:'no pin associated with interrupt'} - let pin = _.byteFormat(res.status.port, { in: 'ARY', out: 'PLC' }) - // console.log('pin and port that caused the interrupt', pin, packet.port) - res.pin = pin[0] - res.port = packet.port - res.count = inter.count - res.inter = inter.pin - delete res.status - this.emit('interrupt',res) - return res - }, - report: ()=>{}, // come here after determining which pin to report to requester } - } // end pin. const parsePins = function(pins) { diff --git a/src/config.mjs b/src/config.mjs index b5e9be0..3160eb3 100644 --- a/src/config.mjs +++ b/src/config.mjs @@ -49,6 +49,14 @@ export const PIN = { usedef: 0, // if usedef = 0 defval not used defval: 0 }, + toggle_switch_pulldown: { + dir: 1, // 0 output,1 input + ivrt: 0, // for reading let 1 be zero and vice versa + pullup: 0, // use external pulldown + intr: 1, // if intr = 0 usedef,deval not used + usedef: 0, // if usedef = 0 defval not used + defval: 0 + }, momentary_switch: { dir: 1, // 0 output,1 input ivrt: 1, // for reading let 1 be zero and vice versa diff --git a/src/index.mjs b/src/index.mjs index 8c6513a..8fcc756 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1,11 +1,12 @@ import MCP230XX from './mcp230xx' -// import Interrupt from './interrupt' +import MCP230XXi from './mcp230xxi' // import Relays from './relays' // import RelayBanks from './relay-banks' // import Switches from './switches' // import SwitchBanks from './switch-banks' export { MCP230XX as MCP230XX } +export { MCP230XXi as MCP230XXi } // export { Interrupt as Interrupt } // export { Relays as Relays } // export { RelayBanks as RelayBanks } diff --git a/src/interrupt.mjs b/src/interrupt.mjs deleted file mode 100644 index 3c33f77..0000000 --- a/src/interrupt.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import UCIInterrupt from '@uci/interrupt' - -import logger from '@uci/logger' -let log = {} -const LOG_OPTS = (id) => { - return { - repo:'uci-mcp', - npm:'@uci/mcp', - file:'src/interrupt.mjs', - class:'Interrupt', - id:id, - instance_created:new Date().getTime() - }} - -export default class Interrupt extends UCIInterrupt { - constructor(opts) { - super(opts) - log = logger.child(LOG_OPTS(this.id)) - if (!opts.address) log.fatal({opts:opts},'no i2c bus address supplied' ) - this.address = opts.address - this.chip17 = opts.chip17 - this.pin = this.bindFuncs(pin) - this.chip = this.bindFuncs(chip) - this.interrupt = opts.interrupt - } - - async init(){ - await super.init() - } - -} // end of MCP230XX Class - - let times = 0 -async interruptProcess(pin) { - times += 1 - console.log(`Interrupt occured for ${times}th time on pin ${pin}`) - let packet = {cmd:'pin.interrupt.find', pin:pin, times:times} - interrupt.send(packet) // via any attached consumers - } - - interrupt.reply = function (packet) { - console.log(`REPLY: pin ${packet.pin}:${packet.port} on ${packet._header.responder.instanceID} caused the ${packet.times}th interrupt on gpio pin ${packet.inter}`) - } - - await interrupt.init() - process.send('_ready') - -})().catch(err => { - console.error('FATAL: UNABLE TO START SYSTEM!\n',err) -}) diff --git a/src/mcp230xx.mjs b/src/mcp230xx.mjs index 46039f8..29b69e1 100644 --- a/src/mcp230xx.mjs +++ b/src/mcp230xx.mjs @@ -19,8 +19,6 @@ export default class MCP230XX extends Device { constructor(opts) { super(opts) log = logger.child(LOG_OPTS(this.id)) - if (!opts.address) log.fatal({opts:opts},'no i2c bus address supplied' ) - this.address = opts.address this.chip17 = opts.chip17 this.pin = this.bindFuncs(pin) this.chip = this.bindFuncs(chip) @@ -28,7 +26,9 @@ export default class MCP230XX extends Device { async init(){ await super.init() + // console.log(this.address, this.chip17) let res = await this.chip.cfg({}) + // console.log(res) let cfg = this.chip17 ?'10100010':'00100010' if (res.response !==cfg ) throw `could not configure mcp chip at ${this.address}=0x${this.address.toString(16)}` } diff --git a/src/mcp230xxi.mjs b/src/mcp230xxi.mjs new file mode 100644 index 0000000..312528a --- /dev/null +++ b/src/mcp230xxi.mjs @@ -0,0 +1,111 @@ +import MCP230XX from './mcp230xx' +import logger from '@uci/logger' +import { byteFormat } from '@uci/utils/src/byte' + +let log = {} +const LOG_OPTS = (id) => { + return { + repo:'uci-mcp', + npm:'@uci/mcp', + file:'src/mcp230xxi.mjs', + class:'MCP230XXi', + id:id, + instance_created:new Date().getTime() + }} + +// sockets:'inter#s>t', inter:{port:INTERRUPT_PORT} + +export default class MCP230XXi extends MCP230XX { + constructor(pins,opts) { + if (typeof opts.iport ==='number' || opts.ipath) { + if (typeof opts.iport ==='number') { + opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#s>t' + opts.inter = {port:opts.iport} + } + if (opts.ipath) { + opts.inter = { path: opts.ipath || 'interrupt'} + opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#s>n' + } + } + else { + pins.forEach( pin => { + let ipin = 'i'+pin + opts[ipin] = opts[pin] || {} + if (opts[ipin].port || opts.iport !=='number') { + opts[ipin].port = opts[ipin].port || opts.iport + if (typeof opts[ipin].port !=='number') opts[ipin].port = 9000 + pin + opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + ipin +'#s>t' + } + // either on the same host as bus and interrupt or not - no need for both + else { + opts[pin].path = opts[pin].path || opts.ipath + if(!opts[pin].path) Object.assign(opts[pin],{path:'interrupt:'+pin}) + opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + pin+'#s>n' + } + }) + } + super(opts) + pins.forEach(pin => { + this[pin] = opts[pin] || {} + }) + this.pins = pins + log = logger.child(LOG_OPTS(this.id)) + Object.assign(this.pin, this.bindFuncs(pin)) + this._interruptProcess = null + + } + + async init(){ + await super.init() + this.pins.forEach(async pin => { + // console.log(this.id,pin,this[pin]) + // let cfg = {port:this[pin].mport||'A',pins:this[pin].pins||'all', cfg:this[pin].type ||'toggle_switch'} + // console.log(cfg) + await this.pin.cfg({port:this[pin].mport||'A',pins:this[pin].pins||'all', cfg:this[pin].type ||'toggle_switch'}) + this.pin.interrupt.reset(this[pin].mport) + }) + + this.on('interrupt', function (details) { + details.id = this.id + if (!this._interruptProcess) { + console.log('----default interrupt processor for mcp instance----') + console.log(this.id) + console.dir(details) + } else this._interruptProcess(details) + }) + + } + + interruptProcessor(func) {this._interruptProcess = func} + +} // end of MCP230XX Class + +const pin = { interrupt: { + reset: async function (port) { + console.log('resetting interrupt for port',port || 'A',this.id) + return await this.bus.read(port!=='B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register + }, + find: async function (inter) { + // console.dir(inter) + let packet = {pins:'all',reg:'intf'} + packet.port = inter.port || this[inter.pin].mport || 'A' + // console.log(`${inter.count}th interrupt fired, pin:${inter.pin}`) + // console.log('packet to read port\n',packet.port) + let res = await this.pin.status(packet) + this.pin.interrupt.reset(packet.port) + if (!res.status) return {error:'no pin associated with interrupt'} + let pin = byteFormat(res.status.port, { in: 'ARY', out: 'PLC' }) + // console.log('pin and port that caused the interrupt', pin, packet.port) + res.pin = pin[0] + packet.pins = pin[0] + packet.reg = null + res.state = (await this.pin.status(packet)).status.pins[0][1] + res.port = packet.port + res.count = inter.count + res.inter = inter.pin + delete res.status + this.emit('interrupt',res) + return res + } +} +}