2018-07-01 00:25:15 -07:00
|
|
|
let bus = {}
|
2018-02-27 08:42:37 -08:00
|
|
|
import debounce from 'lodash.debounce'
|
|
|
|
import Base from '@uci/base'
|
|
|
|
|
2019-03-06 13:02:08 -08:00
|
|
|
import logger from '@uci-utils/logger'
|
2018-02-27 08:42:37 -08:00
|
|
|
let log = {}
|
2019-03-06 13:02:08 -08:00
|
|
|
// a pin makes a socket (server/listner) for each pin to which a consumer can be connected
|
2019-01-01 20:02:16 -08:00
|
|
|
class Interrupt extends Base {
|
|
|
|
constructor(pin, opts = {}) {
|
2019-03-07 07:35:08 -08:00
|
|
|
if (typeof pin !=='number') pin = parseInt(pin) // make sure pin is a number!
|
2019-03-06 13:02:08 -08:00
|
|
|
opts.conPacket = (opts.resetCmd && !opts.conPacket) ? opts.conPacket : { cmd: opts.resetCmd, pin: pin } // will use either option
|
|
|
|
// if opts .port/.path/.topic/.wport are base number/name to which pin number is added/appended (default being 9000,9100,'interrupt')
|
|
|
|
// for specific port number pass itrt.port,itrn.path,itrm.topic,itrw.port which override it if present
|
|
|
|
// conPacket is for uci socket. This will send this command on connect, needed to initially reset the interrupt
|
2019-01-01 20:02:16 -08:00
|
|
|
if (opts.path || opts.itrn) {
|
2018-02-27 08:42:37 -08:00
|
|
|
opts.itrn = opts.itrn || {}
|
2019-03-06 13:02:08 -08:00
|
|
|
if (opts.path && typeof opts.path !=='boolean') opts.path = opts.path + ':' + pin
|
|
|
|
if (typeof opts.path ==='boolean') opts.path = ''
|
|
|
|
opts.itrn.path = opts.itrn.path || opts.path || 'interrupt:' + pin
|
2018-07-31 17:28:02 -07:00
|
|
|
opts.itrn.conPacket = opts.conPacket
|
2019-01-01 20:02:16 -08:00
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'itrn#s>n'
|
2018-07-01 00:25:15 -07:00
|
|
|
}
|
2019-03-06 13:02:08 -08:00
|
|
|
if (opts.topic || opts.itrm) {
|
2018-07-01 00:25:15 -07:00
|
|
|
opts.itrm = opts.itrm || {}
|
2019-03-06 13:02:08 -08:00
|
|
|
opts.itrm.topics = opts.itrm.topic || opts.topic +'/'+ pin || 'interrupt/' + pin
|
2019-01-01 20:02:16 -08:00
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'itrm#s>m'
|
2018-07-01 00:25:15 -07:00
|
|
|
}
|
|
|
|
|
2019-03-06 13:02:08 -08:00
|
|
|
if (opts.itrw || opts.wport || opts.wport===0 ) {
|
|
|
|
opts.itrw = opts.itrw || {}
|
2019-03-07 07:35:08 -08:00
|
|
|
if (opts.wport) opts.wport = opts.wport + +pin
|
|
|
|
opts.itrw.port = opts.itrw.port || opts.wport || 9100 + +pin
|
2019-01-01 20:02:16 -08:00
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'itrw#s>w'
|
2018-02-27 08:42:37 -08:00
|
|
|
}
|
2018-07-01 00:25:15 -07:00
|
|
|
// default is a tcp socket server at 9000+pin
|
2019-03-06 13:02:08 -08:00
|
|
|
if (opts.itrt || opts.port || opts.port===0 || !opts.sockets ) {
|
2018-07-01 00:25:15 -07:00
|
|
|
opts.itrt = opts.itrt || {}
|
2019-03-07 07:35:08 -08:00
|
|
|
if (opts.port) opts.port = opts.port + +pin
|
|
|
|
opts.itrt.port = opts.itrt.port || opts.port || 9000 + +pin
|
2018-07-31 17:28:02 -07:00
|
|
|
opts.itrt.conPacket = opts.conPacket
|
2019-01-01 20:02:16 -08:00
|
|
|
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'itrt#s>t'
|
2018-07-01 00:25:15 -07:00
|
|
|
}
|
2018-02-27 08:42:37 -08:00
|
|
|
super(opts)
|
2019-01-01 20:02:16 -08:00
|
|
|
this.id = (opts.id || 'interrupt') + ':' + pin
|
|
|
|
log = logger({ name: 'interrupt', id: this.id })
|
|
|
|
log.info({ pins: pin, opts: opts }, 'created interrupt with these opts')
|
2019-03-07 07:35:08 -08:00
|
|
|
this.pin_num = +pin
|
2018-07-31 10:05:13 -07:00
|
|
|
this.mock = opts.mock || process.env.MOCK
|
2019-01-01 20:02:16 -08:00
|
|
|
this.wait = opts.wait || 0 // debounce is off by default
|
|
|
|
this.dbopts = {
|
|
|
|
maxWait: opts.maxwait || 500,
|
|
|
|
leading: opts.leading || true,
|
|
|
|
trailing: opts.trailing || false
|
|
|
|
}
|
2018-07-01 00:25:15 -07:00
|
|
|
this.edge = opts.edge
|
|
|
|
this.pull = opts.pull
|
2019-01-01 20:02:16 -08:00
|
|
|
this.pin = {} //set at init
|
2019-03-08 09:05:18 -08:00
|
|
|
this.hook = opts.hook
|
2018-02-27 08:42:37 -08:00
|
|
|
this.packet = opts.packet || {}
|
|
|
|
this.packet.pin = pin
|
2019-03-07 07:35:08 -08:00
|
|
|
this.packet.cmd = this.packet.cmd || opts.pushCmd || 'interrupt'
|
2018-02-27 08:42:37 -08:00
|
|
|
this.packet.count = 0
|
2019-01-01 20:02:16 -08:00
|
|
|
} // end constructor
|
2018-02-27 08:42:37 -08:00
|
|
|
|
2019-01-01 20:02:16 -08:00
|
|
|
async init() {
|
2018-02-27 08:42:37 -08:00
|
|
|
await super.init()
|
|
|
|
// for cntrl-c exit of interrupt
|
2018-07-01 00:25:15 -07:00
|
|
|
// create the pigio pin_num
|
2019-03-06 13:02:08 -08:00
|
|
|
// TODO check for rpi and pigpio, if not available use onoff
|
|
|
|
// wrap all needed commands so can call module for pigpio or onoff
|
2019-03-08 09:05:18 -08:00
|
|
|
if (process.env.UCI_MOCK==='true') bus = await import('pigpio-mock')
|
2018-07-01 15:37:59 -07:00
|
|
|
else bus = await import('pigpio')
|
2019-01-01 20:02:16 -08:00
|
|
|
this.pin = new bus.Gpio(this.pin_num, {
|
|
|
|
mode: bus.Gpio.INPUT,
|
|
|
|
pullUpDown: this.pull || bus.Gpio.PUD_DOWN
|
|
|
|
// do not! set edge here as it will start the emitter -- see pigio js
|
|
|
|
})
|
2018-07-01 00:25:15 -07:00
|
|
|
|
2018-02-27 08:42:37 -08:00
|
|
|
process.on('SIGINT', () => {
|
2019-01-01 20:02:16 -08:00
|
|
|
this.exit()
|
|
|
|
.then(resp => console.log('\n', resp)) // unexport on cntrl-c
|
2018-02-27 08:42:37 -08:00
|
|
|
.catch(err => console.log('error:', err))
|
|
|
|
})
|
|
|
|
let cb = () => {}
|
2019-01-01 20:02:16 -08:00
|
|
|
if (this.wait === 0) {
|
|
|
|
cb = this._interruptProcess.bind(this, this.packet)
|
2019-03-08 09:05:18 -08:00
|
|
|
log.info({ packet: this.packet },`starting interrupt on pin ${this.pin_num} without debounce`)
|
2019-01-01 20:02:16 -08:00
|
|
|
} else {
|
|
|
|
cb = debounce(
|
|
|
|
this._interruptProcess.bind(this, this.packet),
|
|
|
|
this.wait,
|
|
|
|
this.dbopts
|
|
|
|
)
|
2019-03-08 09:05:18 -08:00
|
|
|
log.info({ packet: this.packet, wait: this.wait, options: this.dbopts },`starting interrupt on pin ${this.pin_num} with debounce wait:${this.wait}`)
|
2018-03-02 08:32:37 -08:00
|
|
|
}
|
2019-01-01 20:02:16 -08:00
|
|
|
this.pin.on('interrupt', cb)
|
2018-02-27 08:42:37 -08:00
|
|
|
// rock n roll!!, start the pigpio interrupt
|
2019-01-01 20:02:16 -08:00
|
|
|
if (!this.mock) this.pin.enableInterrupt(this.edge || bus.Gpio.RISING_EDGE)
|
2019-03-08 09:05:18 -08:00
|
|
|
|
|
|
|
this.registerHook(defaultHook)
|
|
|
|
|
|
|
|
} // end init
|
2018-02-27 08:42:37 -08:00
|
|
|
|
|
|
|
// manual firing for testing
|
2018-07-01 15:37:59 -07:00
|
|
|
async fire() {
|
2018-02-27 08:42:37 -08:00
|
|
|
console.log('manually firing interrupt for pin', this.pin_num)
|
2019-01-01 20:02:16 -08:00
|
|
|
this.pin.emit('interrupt', 1)
|
|
|
|
return Promise.resolve({ status: 'fired' })
|
2018-02-27 08:42:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
exit() {
|
|
|
|
bus.terminate()
|
|
|
|
return Promise.reject('keyboard termination...terminating interrupts')
|
|
|
|
}
|
|
|
|
|
2019-03-08 09:05:18 -08:00
|
|
|
// use hook to do more processing
|
2019-01-01 20:02:16 -08:00
|
|
|
async _interruptProcess(packet) {
|
2018-02-27 08:42:37 -08:00
|
|
|
packet.count += 1
|
|
|
|
packet.time = new Date().getTime()
|
2019-03-08 09:05:18 -08:00
|
|
|
packet.id = this.id
|
|
|
|
if (this.hook) packet = await this._hookFunc.call(this,packet)
|
2019-01-01 20:02:16 -08:00
|
|
|
log.info({ packet: packet }, 'packet pushing to all clients')
|
2018-07-01 00:25:15 -07:00
|
|
|
this.push(packet)
|
2018-03-02 08:32:37 -08:00
|
|
|
}
|
|
|
|
|
2019-03-08 09:05:18 -08:00
|
|
|
|
|
|
|
registerHook(func) {
|
|
|
|
this._hookFunc = func
|
2018-02-27 08:42:37 -08:00
|
|
|
}
|
2019-03-08 09:05:18 -08:00
|
|
|
|
2018-02-27 08:42:37 -08:00
|
|
|
} // end Class
|
2019-01-01 20:02:16 -08:00
|
|
|
|
|
|
|
export default Interrupt
|
2019-03-08 09:05:18 -08:00
|
|
|
|
|
|
|
|
|
|
|
//default hook
|
|
|
|
async function defaultHook(packet) {
|
|
|
|
// return a promise or use await if anything async happens in hook
|
|
|
|
// new Promise((resolve) => {
|
|
|
|
console.log('==========default hook =============')
|
|
|
|
console.log(`pin ${packet.pin} on sbc gpio bus has thrown an interrupt`)
|
|
|
|
console.log(`pushing to all connected socket client with cmd:${packet.cmd}`)
|
|
|
|
console.dir('packet)
|
|
|
|
console.log('replace by a new function with .registerHook(function) to overwrite this')
|
|
|
|
console.log('Must be async/promise returning if anything async happens in your hook')
|
|
|
|
console.log('This hook allow you to modify/add to the packet being pushed to connected clients')
|
|
|
|
console.log('the function will be bound to the instance for complete access')
|
|
|
|
console.log('if you pass a hash for .hook you can use it here as this.hook')
|
|
|
|
console.log('the hook options contains', this.hook)
|
|
|
|
console.log('by default the instance id will be attached to the packet before this')
|
|
|
|
return packet
|
|
|
|
// resolve(packet)
|
|
|
|
// })
|
|
|
|
}
|