commands.js
added pin.cfgs for multiple pin configurations
refactored pin.status, pin._state to better handle multiple pins and 08 vs 17
mpc230xx.js
  changed to not having default sockets but socket can be added by passing lport or lpath
  now supports new new uci-utils/ready module and adds an observer for when chip and pins are configured
mcp230xxi.js
   now supports new new uci-utils/ready module by adds an observer for when the interrupt process connects and also resets
   refactored the interrupt methods and commands to compliment changes in the interrupt module
master
David Kebler 2020-01-09 20:17:32 -08:00
parent 9650698683
commit 9a7fdd9539
9 changed files with 238 additions and 279 deletions

View File

@ -1,59 +0,0 @@
/*
* i2c bus unix socket and client in one for demo
*
*/
import Base from '../../uci-base/src/base'
import { spawn } from 'child_process'
const PATH = '/opt/sockets/mcp.sock'
const delay = time => new Promise(res=>setTimeout(()=>res(),time))
const i2cbus = spawn('node',['-r', '@std/esm', './examples/bus'])
i2cbus.stdout.on('data', function(buf) {
console.log('[I2C BUS]', String(buf))
})
;
(async () => {
let mcpclient = new Base({id:'mcpclient', sockets:'uc#c>n', uc:{path:PATH}})
mcpclient.reply = function (packet) {
console.log('for request ',packet._header.request)
console.log('mcp status is ',packet.status)
}
await mcpclient.init()
console.log('=============sending============')
// const pins='2,3,4'
// const pins=3
// const pins='all'
// const pins=[1,3,5,7]
let packet = {cmd:'pin.cfg', pins:'all'}
await mcpclient.send(packet)
packet = {cmd:'pin.cfg', pins:'all', port:'B'}
await mcpclient.send(packet)
packet = {cmd:'pin.state.off', pins:'all' }
await mcpclient.send(packet)
packet = {cmd:'pin.state.off', pins:'all', port:'B' }
await mcpclient.send(packet)
packet = {cmd:'pin.state.on', pins:'2,7', port:'B' }
await mcpclient.send(packet)
packet = {cmd:'pin.state.on', pins:'3,6'}
await mcpclient.send(packet)
packet = {cmd:'pin.status', pins:'all'}
await mcpclient.send(packet)
packet = {cmd:'pin.status', pins:'all', port:'B'}
await mcpclient.send(packet)
process.kill(process.pid, 'SIGTERM')
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})

View File

@ -1,65 +0,0 @@
/*
*
*
*/
import { MCP230XXi } from '../src'
import { MCP230XX } from '../src'
import Base from '@uci/base'
const BUS_HOST = 'sbc' // if ihost not given will be the same as host:
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 announce = new Base({id:'switch:announce'})
let sw17 = new MCP230XXi([9,10],{id:'sw17', chip17:true, host:BUS_HOST, address:SW_ADDRESS+1})
// let sw8 = new MCP230XXi([24],{id:'sw8', host:BUS_HOST, address:SW_ADDRESS})
// let ry8 = new MCP230XX({id:'ry8', host:BUS_HOST, address:RY_ADDRESS})
const reply = { reply: () => {} }
// ry8.c = reply;
sw17.c=reply
// sw8.c= reply
function iprocess(details) {
console.log('--common interrupt processor--')
console.log(details)
announce.push()
// action function can do whatever but best would be to push the details to any attached client (mqtt or some database that then pushes
// local_action(details)
}
// just something to do
async function local_action (details) {
if (details.id === 'sw17') {
await ry8.pin.state.toggle({pins:'2,4,6,8'})
}
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()
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)
})

View File

@ -1,23 +0,0 @@
/*
* i2c bus with both unix and tcp socket using defaults. For TCP that is host OS name and port 8080
*
*/
import MCP230XX from '../src/mcp230xx-packet'
// const PATH = ''
;
(async () => {
// let chip8 = new MCP230XX({id:'mcp8-27', address:0x27, nmcp: { path: '/opt/sockets/mcp2.sock' }})
let chip17 = new MCP230XX({id:'mcp17-26', chip17:true, address:0x26})
await chip17.init()
// await chip8.init()
console.log(await chip17.pin.cfg({pins:'all'}))
// console.log(await chip17.pin.cfg({pins:'all', cfg:'toggle_switch'}))
// console.log(await chip17.pin.cfg({pins:'all', port:'B', cfg:'toggle_switch'}))
// console.log(await chip8.pin.cfg({pins:'all', cfg:'toggle_switch'}))
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})

40
examples/outputs.js Normal file
View File

@ -0,0 +1,40 @@
/*
*
*
*/
import { MCP230XX } from '../src'
// const TRANSPORT = process.env.TRANSPORT || 'tcp'
const HOST = process.env.BUS_HOST || 'sbc'
const PORT = process.env.BUS_PORT || 1776
const ADDRESS = process.env.DEVICE_ADDR || 39
const CHIP17 = !!process.env.CHIP17 || false
;
(async () => {
let outputs = new MCP230XX({id:'mcp', chip17:CHIP17, address:ADDRESS, bus:{host:HOST, port:PORT}})
console.log(await outputs.socketsInit())
await new Promise((resolve) => setTimeout(resolve,50))
outputs.on('ready:mcp', async ev => {
console.log('mcpready', ev)
// all pins are outputs by default
for (var i = 0; i < 10; i++) {
console.log('pass', i)
await outputs.commands.pin.state.on({pins:'all'})
await outputs.commands.pin.state.on({port:'B', pins:'all'}) // will be ingnored on mcp23008
await new Promise((resolve) => setTimeout(resolve,50))
await outputs.commands.pin.state.off({pins:'all'})
await outputs.commands.pin.state.off({port:'B', pins:'all'}) // will be ingnored on mcp23008
}
process.kill(process.pid, 'SIGTERM')
})
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})

64
examples/switches.js Normal file
View File

@ -0,0 +1,64 @@
/*
*
*
*/
import { MCP230XXi } from '../src'
const HOST = process.env.BUS_HOST
const PATH = process.env.BUS_PATH
const PORT = process.env.BUS_PORT || 1776
const ADDRESS = process.env.DEVICE_ADDR || 0x26
const CHIP17 = !!process.env.CHIP17 || true
const LISTEN_PORT = process.env.PORT || 9001
let switches = new MCP230XXi([9,10],{id:'switches', chip17:CHIP17, path:PATH, host:HOST, port:PORT, address:ADDRESS, iport:LISTEN_PORT})
// switches.registerSocket('interrupt','c','t',{host:'switchesd.local', port:1777})
;
(async () => {
if (process.env.VERBOSE==='true') {
switches.on('log', async log => {
if (log.level!=='trace') {
console.log(
'LOG:',log.level,':',
log.msg,
'socket:',log.socketName,
)
if (log.packet) console.dir(log.packet)
}
})
switches.on('connection:socket', async ev => {
console.log('connection event: outbound > ', ev.state,'to socket',ev.socketName)// if (ev.state ==='connected') switches.duplex = true
})
switches.on('connection:consumer', async ev => {
// console.log(ev)
console.log('connection event: inbound >', ev.state,'from consumer',ev.name)// if (ev.state ==='connected') switches.duplex = true
})
}
console.log('ready observers for switches', switches.ready.observerNames)
switches.ready.addObserverDetails('bus',{msg:'this is some details related to bus observer'})
switches.ready.subscribe(x=>{
console.log('=====================switches ready================?',x ? 'YES':'NO')
console.log('what has failed: ',switches.ready.failure,' details:', switches.ready.details.get(switches.ready.failure)||'none')
})
// this.ready.subscribe('interrupt:connected',(res)=>console.log('interrupt connected............',res))
// this.ready.subscribe('mcp',(res)=>console.log('mcp............',res))
// this.ready.subscribe('interrupt:reset',(res)=>console.log('interrupt reset............',res))
let res = await switches.socketsInit()
if (res.errors) console.log(res)
})().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
})

View File

@ -1,10 +1,11 @@
{ {
"name": "@uci/mcp", "name": "@uci/mcp",
"main": "src", "main": "src",
"version": "0.1.37", "version": "0.1.38",
"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": "node -r esm examples/relays", "outputs": "./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/outputs",
"switches": "./node_modules/.bin/nodemon -r esm --preserve-symlinks examples/switches",
"swrl": "UCI_ENV=dev node -r esm examples/mcp-switch-relay", "swrl": "UCI_ENV=dev node -r esm examples/mcp-switch-relay",
"swr": "node -r esm examples/mcp-switch-relay", "swr": "node -r esm examples/mcp-switch-relay",
"test": "./node_modules/.bin/mocha --reporter list --timeout 30000", "test": "./node_modules/.bin/mocha --reporter list --timeout 30000",
@ -28,9 +29,16 @@
}, },
"homepage": "https://github.com/uCOMmandIt/uci-mcp#readme", "homepage": "https://github.com/uCOMmandIt/uci-mcp#readme",
"dependencies": { "dependencies": {
"@uci/i2c-device": "^0.1.21", "@uci-utils/bind-funcs": "^0.2.4",
"@uci-utils/logger": "^0.0.15", "@uci-utils/byte": "^0.2.3",
"@uci-utils/byte": "^0.2.3" "@uci-utils/logger": "0.0.15",
"@uci-utils/ready": "^0.1.2",
"@uci/base": "^0.1.36",
"@uci/i2c-device": "^0.1.24",
"@uci/logger": "0.0.6",
"@uci/socket": "^0.2.28",
"is-plain-object": "^3.0.0",
"merge-anything": "^2.4.4"
}, },
"devDependencies": { "devDependencies": {
"chai": "^4.2.0", "chai": "^4.2.0",

View File

@ -4,7 +4,6 @@ import logger from '@uci-utils/logger'
let log = logger({file:'/src/commands.js', package:'@uci/mcp'}) let log = logger({file:'/src/commands.js', package:'@uci/mcp'})
// TODO add uci debug logging // TODO add uci debug logging
export default { export default {
@ -37,7 +36,7 @@ export default {
} }
}, },
// Individual Pin Configurations // Pin(s) Configurations
// set is for cfg: 'custom' assume a setting is zero unless given // set is for cfg: 'custom' assume a setting is zero unless given
// packet = { pin:, port:, cfg: , set:{dir: 0, ivrt: 0, pullup: 0, intr: 0, usedef: 0,defval: 0} } // packet = { pin:, port:, cfg: , set:{dir: 0, ivrt: 0, pullup: 0, intr: 0, usedef: 0,defval: 0} }
// first get the current byte (pin) state for that setting // first get the current byte (pin) state for that setting
@ -45,9 +44,9 @@ export default {
cfg: async function(packet){ cfg: async function(packet){
let cfg = {} let cfg = {}
let reply = { cmd:'reply', status:{} } let reply = { cmd:'reply', status:{} }
packet.cfg = packet.cfg || 'output' packet.config = packet.config || packet.cfg || 'output'
if (packet.cfg==='custom') cfg = packet.set if (packet.config==='custom') cfg = packet.set
else cfg = PIN.cfgset[packet.cfg] else cfg = PIN.cfgset[packet.config]
for(let name of Object.keys(PIN.setting)) { for(let name of Object.keys(PIN.setting)) {
let op = cfg[name] ? 'on' : 'off' let op = cfg[name] ? 'on' : 'off'
log.debug({cmd:'pin.cfg', line:28, msg:'setting pin register', operation:op, registerName:name, resgisterNum:PIN.setting[name]}) log.debug({cmd:'pin.cfg', line:28, msg:'setting pin register', operation:op, registerName:name, resgisterNum:PIN.setting[name]})
@ -58,31 +57,40 @@ export default {
return reply return reply
}, },
// state is equivalent to read cfgs: async function({configs}){
let res = await Promise.all(configs.map(config => this.commands.pin.cfg(config)))
let error = res.reduce((err,cfg) => {return (err || !!cfg.error)},false)
return ({error:error, res:res})
},
// status is equivalent to read
status: async function (packet) { status: async function (packet) {
if(!this.chip17 && packet.port==='B') return {error:'sent request for port B. No such port on MCP2008'}
let reg = packet.reg ? PIN.cmd[packet.reg] : PIN.cmd.gpio let reg = packet.reg ? PIN.cmd[packet.reg] : PIN.cmd.gpio
if (!reg) return {error:`unknown register ${packet.reg}`, packet:packet } if (!reg) return {error:`unknown register ${packet.reg}`, packet:packet }
let reply = { cmd:'reply'} let pins = parsePins(packet.pins || packet.pin)
let pins = parsePins(packet.pins)
let state = new _.Byte() let state = new _.Byte()
let bus = await this.bus.read(sreg(reg, packet.port)) let bus = await this.bus.read(sreg(reg, packet.port))
if (bus.error) return bus if (bus.error) return bus
state.value = bus.response state.value = bus.response
reply.status = let reply = {
{ port:state.toFmt('ARY'), port:state.toFmt('ARY'),
pins: pins.value.map(pin => { pins: pins.value.map(pin => {
if (state.toFmt('PLC').indexOf(pin) !==-1) return [pin, 'on'] if (state.toFmt('PLC').indexOf(pin) !==-1) return [pin, 'on']
else return [pin,'off'] else return [pin,'off']
}) })
} }
if (packet.pin) reply.state = reply.pins[0][1]
return reply return reply
}, },
_state: async function(packet,op,reg){ _state: async function(packet,op,reg){
if(!this.chip17 && packet.port==='B') return {error:'sent request for port B. No such port on MCP2008'}
reg = (reg!==undefined)? reg : PIN.cmd.gpio reg = (reg!==undefined)? reg : PIN.cmd.gpio
log.debug({cmd:'pin._state', line:82, msg:'_state change request', operation:op, register:reg, packet:packet}) log.debug({cmd:'pin._state', line:82, msg:'_state change request', operation:op, register:reg, packet:packet})
let reply = { cmd:'reply'} let reply = { cmd:'reply'}
let pins = parsePins(packet.pins) let pins = parsePins(packet.pins || packet.pin)
let state = new _.Byte() let state = new _.Byte()
// TODO support setting state on both ports if non given
let bus = await this.bus.read(sreg(reg,packet.port)) let bus = await this.bus.read(sreg(reg,packet.port))
if (bus.error) return bus if (bus.error) return bus
state.value = bus.response state.value = bus.response

View File

@ -1,7 +1,5 @@
import Device from '@uci/i2c-device' import { I2CDevice as Device, map, changed, isPlainObject, to, merge} from '@uci/i2c-device'
// import Device from '../../uci-i2c-device/src/device-packet'
import commands from './commands' import commands from './commands'
import logger from '@uci-utils/logger' import logger from '@uci-utils/logger'
let log = {} let log = {}
@ -16,32 +14,30 @@ class MCP230XX extends Device {
}) })
this.chip17 = opts.chip17 this.chip17 = opts.chip17
this.chipCfg = opts.chipCfg || 'default' this.chipCfg = opts.chipCfg || 'default'
// this._configured = false this.pinsCfg = opts.pinsCfg || this.chip17 ? [{port:'A', pins:'all'},{port:'B', pins:'all'}] : [{pins:'all'}]
this.commands = this.bindFuncs(commands) this.commands = this.bindFuncs(commands)
this.addNamespace('commands', 's') // allow access to commands via socket/server this.addNamespace('commands', 's') // allow access to commands via socket/server
// this._pin = this.commands.pin // add a simplier reference for local access
// this._chipcfg = this.commands.chip.cfg // add a simplier reference for local access
this.once('ready:i2c', () =>{
this.configure()
if (this._ready) this._ready.call(this)
})
}
async registerReadyFunc(func) { if (opts.lport) this.registerSocket('mcp-t','s','t',{port:opts.lport})
this._ready = func if (opts.lpath) this.registerSocket('mcp-n','s','n',{path: opts.lpath})
}
async configure() { this.ready.addObserver('mcp',this.ready.getObserver('i2c').pipe(
map(async ready => {
if (ready) {
let res = await this.commands.chip.cfg({cfg:this.chipCfg}) let res = await this.commands.chip.cfg({cfg:this.chipCfg})
if (res.error) { if (!res.error) {
let err={level:'fatal', msg:'unable to configure mcp chip', error:res.error, cfg:this.chipCfg, address:this.address} let res = await this.commands.pin.cfgs({configs:this.pinsCfg})
log.fatal(err) return res.error? false :true
this.emit('status', err) } return false
} else {
this.emit('status', {level:'info', msg:'mcp chip was properly configured', cfg:this.chipCfg})
this.emit('ready:mcp')
}
} }
return false
})
))
} // end contructor
} // end of MCP230XX Class } // end of MCP230XX Class
export default MCP230XX export default MCP230XX
export {MCP230XX, map, changed, isPlainObject, to, merge}

View File

@ -1,5 +1,6 @@
import MCP230XX from './mcp230xx' import {MCP230XX, map, changed, isPlainObject, to, merge} from './mcp230xx'
import { byteFormat } from '@uci-utils/byte' import { byteFormat } from '@uci-utils/byte'
// import Ready from '@uci-utils/ready'
import logger from '@uci-utils/logger' import logger from '@uci-utils/logger'
let log = {} let log = {}
@ -17,11 +18,11 @@ class MCP230XXi extends MCP230XX {
if (!Array.isArray(pins)) { options = pins; pins = options.interrupt.pins} // if pins sent via .interrupt.pins if (!Array.isArray(pins)) { options = pins; pins = options.interrupt.pins} // if pins sent via .interrupt.pins
let opts = Object.assign({},options) // don't allow passed options to mutate let opts = Object.assign({},options) // don't allow passed options to mutate
if (opts.interrupt) delete opts.interrupt.pins // if .interrupt was passed then .pins must be removed if (opts.interrupt) delete opts.interrupt.pins // if .interrupt was passed then .pins must be removed
delete opts.sockets // .sockets is used by uci base so clear it if was used by enduser and sent by mistake
log.debug({method:'constructor', line:21, msg:'passed options before setting',options:opts}) log.debug({method:'constructor', line:21, msg:'passed options before setting',options:opts})
opts.lport = opts.lport || (opts.interrupt || {}).port || opts.iport
if (!opts.lport) opts.lpath = opts.lpath || (opts.interrupt || {}).ipath || opts.ipath || 'interrupt' // must has a socket litener for interrupt process
super(opts) super(opts)
this.opts = opts this.pinsCfg = opts.pinsCfg || this.chip17 ? [{port:'A', pins:'all', cfg:'input_interrupt'},{port:'B', pins:'all', cfg:'input_interrupt'}] : [{pins:'all', cfg:'input_interrupt'}]
log = logger({ log = logger({
file: 'src/mcp230xxi.js', file: 'src/mcp230xxi.js',
class: 'MCP230XXi', class: 'MCP230XXi',
@ -29,127 +30,116 @@ class MCP230XXi extends MCP230XX {
id: this.id id: this.id
}) })
log.debug({ method:'constructor', line:32, opts: opts, msg:'mcp interrupt options after calling super() on base'}) pins.forEach((pin,index) => {
pins.forEach(pin => {
this[pin] = opts['i' + pin] || {} this[pin] = opts['i' + pin] || {}
this[pin].mport = this[pin].mport || index ? 'B' : 'A'
}) })
this.pins = pins this.pins = pins
this.commands.interrupt = this.bindFuncs(icommands) // add interrupt pin commands to base set in "command.js" this.commands.interrupt = this.bindFuncs(icommands) // add interrupt pin commands to base set in "command.js"
this.addNamespace('commands', 'c') // add access via push to same commands this._interruptProcess = process.bind(this) // default processor
this._interruptProcess = process
this.ready = false
log.debug({ opts: opts, pins: pins }, 'options for mcp interrupt processor')
}
async init() {
if (this.ipath) await this.addSocket('inter-n','s','n',{path:this.ipath}) const conditionHandler = async ev => {
if (this.iport) await this.addSocket('inter-t','s','t',{port:this.iport}) if ((ev||{}).state ==='connected'){
await super.init() let data = (ev.data ||{})
// this will set default type to internal pullup, only need to to change indivial pins to external if desired if (data.type === 'interrupt' || [ev.name, data.name, data.id].some(name => (name||'').includes('interrupt')) ) {
await this.commands.pin.cfg({port:'A',pins:'all',cfg:'input_interrupt'})
let status = await this._resetInterrupt('A')
log.debug({method:'init', line:52, msg:'default configure all port A pins as interrupts. Resetting port A interrupt', status:status})
if (this.chip17) {
await this.commands.pin.cfg({port:'B',pins:'all',cfg:'input_interrupt'})
let status = await this._resetInterrupt('B')
log.debug({method:'init', line:52, msg:'default configure all port B pins as interrupts. Resetting port B interrupt', status:status})
}
}
async _readyInterrupt(port) {
let istate = await this.bus.read(port !== 'B' ? 0x07 : 0x17)
if (istate.response) {
this.ready = false
return false
}
else {
this.ready = true
return true return true
} }
} }
return false
async _resetInterrupt(port) {
await this.bus.read(port !== 'B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register
log.debug({method:'_resetInterrupt', line:72, msg: `reset interrupt for port ${port || 'A'},${this.id} arg ${port !== 'B' ? 0x08 : 0x18}`})
return(await this._readyInterrupt(port))
} }
_getPortByPin(pin) { this.ready.addObserver('interrupt:connected',this.getSocket(`mcp-${opts.lport? 't':'n'}`),{event:'connection:consumer',condition:conditionHandler})
let port = this[pin] ? this[pin].mport : null
let index = this.pins.map(pin => pin.toString()).indexOf(pin.toString()) this.ready.addObserver('interrupt:reset',this.ready.combineObservers(['mcp','interrupt:connected']).pipe(
port = port || index <= 0 ? 'A' : 'B' map(async ready=>{
return port if (ready) return await this.resetInterrupt()
return false
})
))
} // end constructor
async interruptState(pin) {
let istate = await this.bus.read(this.getPort(pin) !== 'B' ? 0x07 : 0x17)
let pullup = (this.chipCfg||'').includes('Pullup') ? true : false
let state = istate.response ? true && pullup : false || !pullup
return state
} }
interruptProcessor(func) { async resetInterrupt(pins) {
this._interruptProcess = func if (!Array.isArray(pins)) pins = pins ? [pins] : this.pins
this._ireset = (await Promise.all(pins.map(async pin => {
await this.bus.read(this.getPort(pin) !== 'B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register
return(await this.interruptState(pin))
})
)).reduce((res,val) => res && val)
return this._ireset
}
getPort(pin) {
if (pin==='A' || pin==='B') return pin
return this[pin].mport
}
registerInterruptProcessor(func) {
this._interruptProcess = func.bind(this)
} }
} // end of MCP230XXi Class } // end of MCP230XXi Class
export default MCP230XXi export default MCP230XXi
export { MCP230XXi, map, changed, isPlainObject, to, merge}
// default processor // default processor
function process(details) { function process(details) {
details.id = this.id details.id = this.id
console.log('----default interrupt processor for mcp instance----') console.log('----default interrupt processor for mcp instance----')
console.log('here is where you could either locally take some action for send/push on a message to another process') console.log('here is where you could either locally take some action or send on a message to another process')
console.log('create your own function and register it with .interruptProcesser(function)') console.log('create your own function and register it with .interruptProcesser(function)')
console.log(this.id) console.log(this.id)
console.dir(details) console.dir(details)
console.log('------------------------------------------')
} }
// commands to be added to pin packet command functions // commands to be added to pin packet command functions
const icommands = { const icommands = {
status: async function(packet) { status: async function(packet) {
// pin is interrupt pin on sbc for port let pin = packet.ipin || packet.pin
let port = packet.port || this._getPortByPin(packet.pin) let state = await this.interruptState(pin)
let res = await this._readyInterrupt(port) return {cmd:'reply', request:'interrupt.status', port:this.getPort(pin), ipin:pin, ready:state}
return {cmd:'reply', request:'interrupt.status', port:port, ipin:packet.pin, ready:res}
}, },
reset: async function(packet) { reset: async function(packet) {
// pin is interrupt pin on sbc for port let pin = packet.ipin || packet.pin
let port = packet.port || this._getPortByPin(packet.pin) let state = await this.resetInterrupt(pin)
log.error({cmd:'interrupt.reset', line:114, packet: packet, port:port, msg:`forced remote interrupt reset for port ${port}`}) let res = {level:state ? 'debug':'error', msg:`remote reset request from ${packet._header.sender.instanceID} for pin ${pin}: ${state?'ready': 'error'}` }
await this._resetInterrupt(port) this.emit('log',res)
let res = await this._readyInterrupt(port) return {state:state}
return {cmd:'reply', request:'interrupt.reset', port:port, ipin:packet.pin, ready:res}
}, },
// given a gpio interrupt then push a packet with cmd: 'pin.interrupt.find' and pin: the gpio pin number // finds which mcp pin caused the interrupt
find: async function(inter) { find: async function(inter) {
if (this.ready) { let ipin = inter.ipin || inter.pin
// protects tripped interrupt before it's fully initialized, or interrupt requests arriving before porcessing is complete if (!await this.interruptState(ipin)) { // if it's already reset then this is false trip
this.ready = false let res = await this.commands.pin.status({ pins: 'all', reg: 'intf', port:this.getPort(ipin) }) // read port interrupt status
log.debug({cmd:'interrupt.find', line:124, msg:'raw packet from interrupt, finding pin that caused interrupt', inter:inter}) let status = await this.resetInterrupt(ipin) // now reset
let packet = { pins: 'all', reg: 'intf' } let pin = byteFormat(res.port||[], { in: 'ARY', out: 'PLC' })[0]
packet.port = inter.port || this._getPortByPin(inter.pin) if (!pin) {
let res = await this.commands.pin.status(packet) // read port interrupt status
let status = await this._resetInterrupt(packet.port)
this.ready = true
log.debug({cmd:'interrupt.find', line:130, interrupt:res, reset:status, msg:'interrupt read and reset'})
if (!res.status) {
log.warn({cmd:'interrupt.find', line:132, inter:inter, msg:'no pin associated with interrupt'}) log.warn({cmd:'interrupt.find', line:132, inter:inter, msg:'no pin associated with interrupt'})
return { error: 'no pin associated with interrupt' } return { error: 'no pin associated with interrupt' }
} }
let pin = byteFormat(res.status.port, { in: 'ARY', out: 'PLC' }) else { // avoid bad interrupt (i.e. no pin caused interrupt)
res.pin = pin[0] delete inter.cmd; delete inter._header
packet.pins = pin[0] inter.ipin = ipin
packet.reg = null inter.pin = pin
if (packet.pins) { // avoid bad interrupt (i.e. no pin caused interrupt) inter.port = this[ipin].mport
res.ipin = inter.pin inter.interrupt_ready = status
res.port = packet.port inter.state = (await this.commands.pin.status({pin:pin, port:this.getPort(ipin)})).state
delete inter.cmd; delete inter._header; delete inter.pin this._interruptProcess(inter)
Object.assign(res,inter) // replying with reset command which is also a check
delete res.status return {cmd:'reset', pin:ipin}
res.interrupt_ready = status || false
res.state = (await this.commands.pin.status(packet)).status.pins[0][1]
this._interruptProcess(res)
return res
} else {
log.warn({cmd:'interrupt.find', line:151, inter:inter, msg:'no pin associated with interrupt'})
return { error: 'no pin associated with interrupt' }
} }
} }
} }
}
} // end commands