total refactoring using pigpio library instead of epoll
parent
80c59b7ba8
commit
e85378168e
168
lib/interrupt.js
168
lib/interrupt.js
|
@ -1,150 +1,74 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const fs = require('mz/fs'),
|
const
|
||||||
exec = require('mz/child_process').exec,
|
pigpio = require('pigpio'),
|
||||||
EventEmitter = require('events'),
|
Gpio = pigpio.Gpio,
|
||||||
Epoll = require('epoll').Epoll,
|
EventEmitter = require('events')
|
||||||
_ = require('uci-utils')
|
//,_ = require('uci-utils')
|
||||||
|
//const debounce = require('debounce');
|
||||||
const pWaitFor = require('p-wait-for')
|
|
||||||
const pathExists = require('path-exists');
|
|
||||||
const debounce = require('debounce');
|
|
||||||
|
|
||||||
const GPIO_ROOT_PATH = '/sys/class/gpio/'
|
|
||||||
|
|
||||||
class Interrupt extends EventEmitter {
|
class Interrupt extends EventEmitter {
|
||||||
// bus is i2c-bus bus object
|
constructor(pin_number, handler, opts = {}) {
|
||||||
constructor(pin_number, opts = {}) {
|
|
||||||
super()
|
super()
|
||||||
this.num = pin_number;
|
this.pin_number = pin_number
|
||||||
this.hook = opts.hook // will be passed back with the emit
|
this.handler = handler
|
||||||
this.path = GPIO_ROOT_PATH + 'gpio' + this.num + '/'
|
this.mode = Gpio.INPUT
|
||||||
this.edge = opts.edge // default 'both'
|
this.pull = opts.pull ? opts.pull : Gpio.PUD_DOWN
|
||||||
this.delay = opts.delay // default = 50
|
this.edge = opts.edge ? opts.edge : Gpio.RISING_EDGE
|
||||||
this.pull = opts.pull // default = pu
|
this.sbc_interrupt = new Gpio(
|
||||||
this.puller = opts.puller ? opts.puller : (num, state) => { return `raspi-gpio set ${num} ${state}` } // default rpi using raspi-gpio
|
this.pin_number, {
|
||||||
// this.puller = (num, state) => { return `raspi-gpio set ${num} ${state}` }
|
mode: this.mode,
|
||||||
this.dbt = opts.debounce ? opts.debounce : 200
|
pullUpDown: this.pull,
|
||||||
this.poller = new Epoll(
|
// edge: this.edge // don't set edge here as it will start the emitter -- see pigio js
|
||||||
debounce((err, fd, events) => {
|
|
||||||
if (err) { this.emit('error', err) } else {
|
|
||||||
// this.clear().then(this.emit('fired', this.hook))
|
|
||||||
this.emit('fired', this.hook)
|
|
||||||
}
|
}
|
||||||
}, this.dbt, true) // true = leading
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
|
||||||
|
// console.log(`initialize interrupt ${this.pin_number}`)
|
||||||
|
return Promise.resolve()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
get pin() {
|
||||||
|
return this.pin_number
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
|
||||||
|
console.log(`starting interrupt on pin ${ this.pin_number}`)
|
||||||
|
|
||||||
|
// for cntrl-c exit of interrupt
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
this.exit().then((resp) => console.log("\n", resp)) // unexport on cntrl-c
|
this.exit().then((resp) => console.log("\n", resp)) // unexport on cntrl-c
|
||||||
.catch(err => console.log("error:", err))
|
.catch(err => console.log("error:", err))
|
||||||
})
|
})
|
||||||
|
// There are two interrupts here. One on the I2c mcp board and one on the sbc/rpi
|
||||||
|
// The mcp interrupt trips the sbc interrupt which emits an event to run handler attached to the mcp class interrupt
|
||||||
|
let interrupt = this // scope `this` for use in the listener for each interrupt
|
||||||
|
console.log(`interrupt listener set for rpi ${interrupt.pin_number}`)
|
||||||
|
this.sbc_interrupt.on('interrupt', function () {
|
||||||
|
console.log(`rpi interrupt tripped by rpi pin ${interrupt.pin_number}`)
|
||||||
|
interrupt.emit('fired')
|
||||||
|
})
|
||||||
|
|
||||||
return _.pSeries([
|
// rock n roll!!, turn on the pigpio interrupt
|
||||||
this.exit(),
|
this.sbc_interrupt.enableInterrupt(this.edge)
|
||||||
this._pull(this.num, this.pull),
|
|
||||||
this._export(this.num),
|
|
||||||
this._direction('in', this.delay),
|
|
||||||
() => this._edge(this.edge), // TODO determine why these need additional function
|
|
||||||
() => this._fd()
|
|
||||||
])
|
|
||||||
|
|
||||||
|
// return Promise.resolve("interrupt on pin listener")
|
||||||
}
|
}
|
||||||
|
|
||||||
// manual firing for testing
|
// manual firing for testing
|
||||||
fire(name = 'fired') {
|
fire(name = 'fired') {
|
||||||
this.emit(name, this.hook)
|
console.log('firing interrupt handler', this.handler)
|
||||||
}
|
this.emit(name, this.handler)
|
||||||
|
|
||||||
clear() {
|
|
||||||
let buffer = Buffer.from([0x00])
|
|
||||||
return fs.read(this.valuefd, buffer, 0, 1, 0).then(() => { return Promise.resolve('interrupt cleared') })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exit() {
|
exit() {
|
||||||
return new Promise((resolve, reject) => {
|
pigpio.terminate()
|
||||||
pathExists(this.path)
|
return Promise.reject(`keyboard termination...terminating interrupt on pin ${this.pin_number}`)
|
||||||
.then((exists) => {
|
|
||||||
if (exists) {
|
|
||||||
fs.writeFile(GPIO_ROOT_PATH + 'unexport', this.num)
|
|
||||||
.then(() => {
|
|
||||||
if (this.valuefd) {
|
|
||||||
this.stop()
|
|
||||||
fs.close(this.valuefd)
|
|
||||||
}
|
}
|
||||||
this._pull(this.num, 'pn')
|
|
||||||
})
|
|
||||||
.then(resolve('unexported and exited'))
|
|
||||||
} else {
|
|
||||||
resolve('already unexported')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => resolve(err))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
start() {
|
|
||||||
// this.inter(port).on('fired', () => {
|
|
||||||
// console.log(`interrupt port ${port} hook me \n ${relays}`)
|
|
||||||
// // hook.bind(this)(port)
|
|
||||||
//
|
|
||||||
// })
|
|
||||||
return this.clear().then(() => this.poller.add(this.valuefd, Epoll.EPOLLPRI | Epoll.EPOLLONESHOT));
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
return this.clear().then(() => this.poller.modify(this.valuefd, Epoll.EPOLLPRI | Epoll.EPOLLONESHOT));
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
this.poller.remove(this.valuefd).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******private methods*********/
|
|
||||||
|
|
||||||
_pull(num, state = 'pu') {
|
|
||||||
if (this.puller === 'external') { return Promise.resolve('pull must be set externally') } else {
|
|
||||||
return exec(this.puller(num, state))
|
|
||||||
.then(() => { return Promise.resolve(`pull set ${state}`) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_fd() {
|
|
||||||
return fs.open(this.path + 'value', 'r+')
|
|
||||||
.then(fd => {
|
|
||||||
this.valuefd = fd
|
|
||||||
return Promise.resolve(`value fd set ${fd}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_export(num) {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
fs.writeFile(GPIO_ROOT_PATH + 'export', num)
|
|
||||||
.then(() => { return resolve('exported') })
|
|
||||||
.catch((err) => { return reject(err) })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_direction(dir = 'in', delay = 50) {
|
|
||||||
return pWaitFor(() => pathExists(this.path + 'direction'))
|
|
||||||
.then(_.pDelay(delay))
|
|
||||||
.then(() => {
|
|
||||||
return fs.writeFile(dir + 'direction', dir)
|
|
||||||
.then(() => {
|
|
||||||
return Promise.resolve(`direction set ${dir}`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_edge(edge = 'both') {
|
|
||||||
return fs.writeFile(this.path + 'edge', edge)
|
|
||||||
.then(() => {
|
|
||||||
return Promise.resolve(`edge set ${edge}`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -30,13 +30,8 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/uCOMmandIt/uci-interrrupt#readme",
|
"homepage": "https://github.com/uCOMmandIt/uci-interrrupt#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debounce": "^1.0.0",
|
|
||||||
"epoll": "^0.1.20",
|
|
||||||
"mz": "^2.6.0",
|
|
||||||
"p-wait-for": "^1.0.0",
|
|
||||||
"path-exists": "^3.0.0",
|
|
||||||
"require-all": "git+https://github.com/dkebler/node-require-all.git#merge",
|
"require-all": "git+https://github.com/dkebler/node-require-all.git#merge",
|
||||||
"uci-utils": "0.0.1"
|
"pigpio": "^0.x"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
|
|
Loading…
Reference in New Issue