added mcp interrupt extension class that adds functionality to handle the mcp port interrupt using and external socket
parent
0de3dfd825
commit
9652041671
|
@ -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)
|
||||||
|
})
|
|
@ -4,7 +4,8 @@
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"description": "Classes and Helper Functions for using the MCP chip on I2C Bus",
|
"description": "Classes and Helper Functions for using the MCP chip on I2C Bus",
|
||||||
"scripts": {
|
"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",
|
"test": "./node_modules/.bin/mocha --reporter list --timeout 30000",
|
||||||
"testw": "./node_modules/.bin/mocha --reporter list -- watch --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",
|
"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/i2c-device": "^0.1.1",
|
||||||
"@uci/interrupt": "^0.1.1",
|
"@uci/interrupt": "^0.1.1",
|
||||||
"@uci/logger": "0.0.1",
|
"@uci/logger": "0.0.1",
|
||||||
|
"@uci/mqtt": "0.0.1",
|
||||||
"@uci/utils": "^0.1.1"
|
"@uci/utils": "^0.1.1"
|
||||||
},
|
},
|
||||||
"@std/esm": "cjs",
|
"@std/esm": "cjs",
|
||||||
|
|
|
@ -20,6 +20,7 @@ export const chip = {
|
||||||
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
|
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
|
||||||
if (byte < 128) byte += 128 // make sure BANK=1 remains on
|
if (byte < 128) byte += 128 // make sure BANK=1 remains on
|
||||||
let reg = this.chip17 ? 0x0A : 0x05
|
let reg = this.chip17 ? 0x0A : 0x05
|
||||||
|
// console.log(this.chip17, reg, this.id, this.address)
|
||||||
bus = await this.bus.write(reg,byte)
|
bus = await this.bus.write(reg,byte)
|
||||||
if (bus.error) return bus
|
if (bus.error) return bus
|
||||||
bus = await this.bus.read(0x05)
|
bus = await this.bus.read(0x05)
|
||||||
|
@ -96,34 +97,7 @@ export const pin = {
|
||||||
toggle: async function (packet) {
|
toggle: async function (packet) {
|
||||||
return this.pin._state(packet,'toggle')
|
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.
|
} // end pin.
|
||||||
|
|
||||||
const parsePins = function(pins) {
|
const parsePins = function(pins) {
|
||||||
|
|
|
@ -49,6 +49,14 @@ export const PIN = {
|
||||||
usedef: 0, // if usedef = 0 defval not used
|
usedef: 0, // if usedef = 0 defval not used
|
||||||
defval: 0
|
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: {
|
momentary_switch: {
|
||||||
dir: 1, // 0 output,1 input
|
dir: 1, // 0 output,1 input
|
||||||
ivrt: 1, // for reading let 1 be zero and vice versa
|
ivrt: 1, // for reading let 1 be zero and vice versa
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import MCP230XX from './mcp230xx'
|
import MCP230XX from './mcp230xx'
|
||||||
// import Interrupt from './interrupt'
|
import MCP230XXi from './mcp230xxi'
|
||||||
// import Relays from './relays'
|
// import Relays from './relays'
|
||||||
// import RelayBanks from './relay-banks'
|
// import RelayBanks from './relay-banks'
|
||||||
// import Switches from './switches'
|
// import Switches from './switches'
|
||||||
// import SwitchBanks from './switch-banks'
|
// import SwitchBanks from './switch-banks'
|
||||||
|
|
||||||
export { MCP230XX as MCP230XX }
|
export { MCP230XX as MCP230XX }
|
||||||
|
export { MCP230XXi as MCP230XXi }
|
||||||
// export { Interrupt as Interrupt }
|
// export { Interrupt as Interrupt }
|
||||||
// export { Relays as Relays }
|
// export { Relays as Relays }
|
||||||
// export { RelayBanks as RelayBanks }
|
// export { RelayBanks as RelayBanks }
|
||||||
|
|
|
@ -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)
|
|
||||||
})
|
|
|
@ -19,8 +19,6 @@ export default class MCP230XX extends Device {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
super(opts)
|
super(opts)
|
||||||
log = logger.child(LOG_OPTS(this.id))
|
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.chip17 = opts.chip17
|
||||||
this.pin = this.bindFuncs(pin)
|
this.pin = this.bindFuncs(pin)
|
||||||
this.chip = this.bindFuncs(chip)
|
this.chip = this.bindFuncs(chip)
|
||||||
|
@ -28,7 +26,9 @@ export default class MCP230XX extends Device {
|
||||||
|
|
||||||
async init(){
|
async init(){
|
||||||
await super.init()
|
await super.init()
|
||||||
|
// console.log(this.address, this.chip17)
|
||||||
let res = await this.chip.cfg({})
|
let res = await this.chip.cfg({})
|
||||||
|
// console.log(res)
|
||||||
let cfg = this.chip17 ?'10100010':'00100010'
|
let cfg = this.chip17 ?'10100010':'00100010'
|
||||||
if (res.response !==cfg ) throw `could not configure mcp chip at ${this.address}=0x${this.address.toString(16)}`
|
if (res.response !==cfg ) throw `could not configure mcp chip at ${this.address}=0x${this.address.toString(16)}`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue