2018-03-04 15:13:55 -08:00
|
|
|
import MCP230XX from './mcp230xx'
|
2019-02-14 14:01:30 -08:00
|
|
|
import { byteFormat } from '@uci-utils/byte'
|
2018-03-04 15:13:55 -08:00
|
|
|
|
2019-02-14 14:01:30 -08:00
|
|
|
import logger from '@uci-utils/logger'
|
2018-03-04 15:13:55 -08:00
|
|
|
let log = {}
|
|
|
|
|
2018-07-31 10:29:11 -07:00
|
|
|
// if opts.iport not set then will be generated based on pin number
|
2018-03-04 15:13:55 -08:00
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
class MCP230XXi extends MCP230XX {
|
2019-03-07 07:48:16 -08:00
|
|
|
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)
|
2019-03-06 16:45:53 -08:00
|
|
|
// if iport or ipath is set then all interrupts have a single consolidating socket
|
2019-01-01 19:45:25 -08:00
|
|
|
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 }
|
2018-07-31 10:29:11 -07:00
|
|
|
opts.inter.host = opts.ihost || opts.host
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
|
|
|
if (opts.ipath) {
|
2019-01-01 19:45:25 -08:00
|
|
|
opts.inter = { path: opts.ipath || 'interrupt' }
|
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'inter#c>n'
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
2019-01-01 19:45:25 -08:00
|
|
|
} else {
|
2019-03-06 16:45:53 -08:00
|
|
|
// otherwise each pin will have its own socket so make a client for each
|
2019-01-01 19:45:25 -08:00
|
|
|
pins.forEach((pin, index) => {
|
|
|
|
let ipin = 'i' + pin
|
2019-03-06 16:45:53 -08:00
|
|
|
opts[ipin] = opts[pin] || opts.interrupt || {}
|
|
|
|
if (index === 1) opts[ipin].mport = opts[ipin].mport || 'B'
|
2019-01-01 19:45:25 -08:00
|
|
|
delete opts[pin]
|
2019-03-06 16:45:53 -08:00
|
|
|
if (opts[ipin].host) {
|
2019-03-07 07:48:16 -08:00
|
|
|
opts[ipin].port = opts[ipin].port ? opts[ipin].port + +pin : 9000 + +pin
|
2019-03-06 16:45:53 -08:00
|
|
|
opts[ipin].host = opts[ipin].host
|
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + ipin + '#c>t'
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
2019-03-06 16:45:53 -08:00
|
|
|
// no host will make a pipe by default
|
2018-03-04 15:13:55 -08:00
|
|
|
else {
|
2019-03-06 16:45:53 -08:00
|
|
|
opts[ipin].path = (opts[ipin].path || 'interrupt') + ':'+ pin
|
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + ipin + '#c>n'
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
super(opts)
|
2019-01-01 19:45:25 -08:00
|
|
|
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'
|
|
|
|
)
|
2018-03-04 15:13:55 -08:00
|
|
|
pins.forEach(pin => {
|
2019-01-01 19:45:25 -08:00
|
|
|
this[pin] = opts['i' + pin] || {}
|
2018-03-04 15:13:55 -08:00
|
|
|
})
|
|
|
|
this.pins = pins
|
2018-07-31 10:29:11 -07:00
|
|
|
Object.assign(this.commands.pin, this.bindFuncs(ipincommands)) // add interrupt pin commands to base set in "command.js"
|
2019-01-01 19:45:25 -08:00
|
|
|
this.addNamespace('commands', 'c')
|
2018-03-04 15:13:55 -08:00
|
|
|
this._interruptProcess = null
|
2018-07-31 10:29:11 -07:00
|
|
|
this.ready = false
|
2019-01-01 19:45:25 -08:00
|
|
|
log.info({ opts: opts, pins: pins }, 'options for mcp interrupt processor')
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
async init() {
|
2018-03-04 15:13:55 -08:00
|
|
|
await super.init()
|
|
|
|
this.pins.forEach(async pin => {
|
2019-01-01 19:45:25 -08:00
|
|
|
let cfg = {
|
|
|
|
port: this[pin].mport || 'A',
|
|
|
|
pins: this[pin].pins || 'all',
|
|
|
|
cfg: this[pin].type || 'toggle_switch'
|
|
|
|
}
|
2019-03-06 16:45:53 -08:00
|
|
|
// this will set default type to internal pullup, only need to to change indivial pins to external if desired
|
2018-07-31 10:29:11 -07:00
|
|
|
await this.pin.cfg(cfg)
|
2018-07-31 17:11:43 -07:00
|
|
|
// 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)
|
2019-01-01 19:45:25 -08:00
|
|
|
this.ready = true
|
2018-03-04 15:13:55 -08:00
|
|
|
})
|
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
this.on('interrupt', function(details) {
|
2018-03-04 15:13:55 -08:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
async _reset(port) {
|
|
|
|
// local non-packet hidden command
|
2019-03-07 07:48:16 -08:00
|
|
|
console.log(`resetting interrupt for port ${port || 'A'},${this.id} arg ${port !== 'B' ? 0x08 : 0x1}`)
|
2019-01-01 19:45:25 -08:00
|
|
|
return await this.bus.read(port !== 'B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register
|
2018-07-31 17:11:43 -07:00
|
|
|
}
|
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
interruptProcessor(func) {
|
|
|
|
this._interruptProcess = func
|
|
|
|
}
|
|
|
|
} // end of MCP230XXi Class
|
2018-03-04 15:13:55 -08:00
|
|
|
|
2019-01-01 19:45:25 -08:00
|
|
|
export default MCP230XXi
|
2018-03-04 15:13:55 -08:00
|
|
|
|
2018-07-31 17:11:43 -07:00
|
|
|
// commands to be added to pin packet command functions
|
2019-01-01 19:45:25 -08:00
|
|
|
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
|
2019-03-07 07:48:16 -08:00
|
|
|
console.log('packet from interrupt to interpret',inter)
|
2019-01-01 19:45:25 -08:00
|
|
|
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
|
2018-07-31 17:11:43 -07:00
|
|
|
}
|
2018-07-31 10:29:11 -07:00
|
|
|
}
|
2018-03-04 15:13:55 -08:00
|
|
|
}
|
|
|
|
}
|