import MCP230XX from './mcp230xx' import { byteFormat } from '@uci-utils/byte' import logger from '@uci-utils/logger' let log = {} // if opts.iport not set then will be generated based on pin number class MCP230XXi extends MCP230XX { constructor(pins, options={}) { if (!Array.isArray(pins)) { options = pins; pins = options.interrupt.pins} // if pins sent via .interrupt.pins let opts = Object.assign({},options) // don't allow options to mutate if (opts.interrupt) delete opts.interrupt.pins // if .interrupt is passed then .pins must be removed delete opts.sockets // .sockets is used by uci base so clear it was sent by mistake // console.log('options as ready for mcp',pins, opts) // if iport or ipath is set then all interrupts have a single consolidating socket if (typeof opts.iport === 'number' || opts.ipath) { if (typeof opts.iport === 'number') { opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'inter#c>t' opts.inter = { port: opts.iport } opts.inter.host = opts.ihost || opts.host } if (opts.ipath) { opts.inter = { path: opts.ipath || 'interrupt' } opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'inter#c>n' } } else { // otherwise each pin will have its own socket so make a client for each pins.forEach((pin, index) => { let ipin = 'i' + pin opts[ipin] = opts[pin] || opts.interrupt || {} if (index === 1) opts[ipin].mport = opts[ipin].mport || 'B' delete opts[pin] if (opts[ipin].host) { opts[ipin].port = opts[ipin].port ? opts[ipin].port + +pin : 9000 + +pin opts[ipin].host = opts[ipin].host opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + ipin + '#c>t' } // no host will make a pipe by default else { opts[ipin].path = (opts[ipin].path || 'interrupt') + ':'+ pin opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + ipin + '#c>n' } }) } super(opts) log = logger({ file: 'src/mcp230xxi.js', class: 'MCP230XXi', name: 'mcp', id: this.id }) log.info( { opts: opts }, 'mcp interrupt options after calling super() on base' ) pins.forEach(pin => { this[pin] = opts['i' + pin] || {} }) this.pins = pins Object.assign(this.commands.pin, this.bindFuncs(ipincommands)) // add interrupt pin commands to base set in "command.js" this.addNamespace('commands', 'c') this._interruptProcess = null this.ready = false log.info({ opts: opts, pins: pins }, 'options for mcp interrupt processor') } async init() { await super.init() this.pins.forEach(async pin => { let cfg = { port: this[pin].mport || 'A', pins: this[pin].pins || 'all', cfg: this[pin].type || 'toggle_switch' } // this will set default type to internal pullup, only need to to change indivial pins to external if desired await this.pin.cfg(cfg) // shouldn't need this as reset is pushed upon connection to interrupt socket // log.info('initial resetting of mcp interrupt port for corresponding sbc gpio pin') // await this._reset(this[pin].mport) this.ready = true }) 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) }) } async _reset(port) { // local non-packet hidden command console.log(`resetting interrupt for port ${port || 'A'},${this.id} arg ${port !== 'B' ? 0x08 : 0x1}`) return await this.bus.read(port !== 'B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register } interruptProcessor(func) { this._interruptProcess = func } } // end of MCP230XXi Class export default MCP230XXi // commands to be added to pin packet command functions const ipincommands = { interrupt: { reset: async function(packet) { log.info( { packet: packet }, `'socket has push requested a reset of mcp interrupt port for gpio pin ${ packet.pin }` ) let port = this[packet.pin].mport || 'A' await this._reset(port) }, // given a gpio interrupt then push a packet with cmd: 'pin.interrupt.find' and pin: the gpio pin number find: async function(inter) { // inter is a UCI packet console.log('packet from interrupt to interpret',inter) if (this.ready) { // protects tripped interrupt before it's fully initialized, or interrupt requests arriving before porcessing is complete this.ready = false log.info({ packet: inter }, 'finding mcp pin which caused interrupt') let packet = { pins: 'all', reg: 'intf' } packet.port = inter.port || this[inter.pin].mport || 'A' let res = await this.pin.status(packet) log.info('found pin now resetting mcp port interrupt') if (!res.status) return { error: 'no pin associated with interrupt' } let pin = byteFormat(res.status.port, { in: 'ARY', out: 'PLC' }) res.pin = pin[0] packet.pins = pin[0] packet.reg = null if (packet.pins) { // avoid bad interrupt (i.e. no pin caused interrupt) 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) } await this._reset(packet.port) this.ready = true return res } } } }