reorganizes commands

add new server/socket namespace "commands" for server side base module
add new namespace "commands" for consumer side for interrupt version of module
master
David Kebler 2018-07-31 10:29:11 -07:00
parent 1497491d9c
commit 95926a892c
5 changed files with 162 additions and 146 deletions

View File

@ -4,31 +4,35 @@
*/ */
import { MCP230XXi } from '../src' import { MCP230XXi } from '../src'
import { MCP230XX } from '../src' import { MCP230XX } from '../src'
import Base from '@uci/base'
const BUS_HOST = 'sbc' 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 BUS_PORT = 1776 // 1776 is default port for i2c-bus module
const SW_ADDRESS = 0x25 // 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 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 announce = new Base({id:'switch:announce'})
// 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 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, iport:true}) // 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}) // let ry8 = new MCP230XX({id:'ry8', host:BUS_HOST, address:RY_ADDRESS})
sw17.reply = () => {} const reply = { reply: () => {} }
ry8.reply = () => {} // ry8.c = reply;
sw8.reply = () => {} sw17.c=reply
// sw8.c= reply
function iprocess(details) { function iprocess(details) {
console.log('--common interrupt processor--') console.log('--common interrupt processor--')
console.log(details) console.log(details)
action(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)
} }
async function action (details) { // just something to do
async function local_action (details) {
if (details.id === 'sw17') { if (details.id === 'sw17') {
await ry8.pin.state.toggle({pins:details.pin}) await ry8.pin.state.toggle({pins:'2,4,6,8'})
} }
if (details.id === 'sw8') { if (details.id === 'sw8') {
if (details.pin===1) { if (details.pin===1) {
@ -46,19 +50,15 @@ async function action (details) {
(async () => { (async () => {
await sw17.init() await sw17.init()
let cfg = {port:'B',pins:'1', cfg:'toggle_switch_pulldown'}
console.log(await sw17.pin.cfg(cfg))
sw17.interruptProcessor(iprocess) sw17.interruptProcessor(iprocess)
// await sw8.init()
// sw8.interruptProcessor(iprocess)
await sw8.init() //
sw8.interruptProcessor(iprocess) //
// await ry8.init()
// let packet = {pins:'all', cfg:'output'}
await ry8.init() // await ry8.pin.cfg(packet)
let packet = {pins:'all', cfg:'output'}
await ry8.pin.cfg(packet)
})().catch(err => { })().catch(err => {
console.error('FATAL: UNABLE TO START SYSTEM!\n',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.4", "version": "0.1.8",
"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", "relays": "node -r esm examples/relays",
"swrl": "UCI_LOG=true node -r esm examples/mcp-switch-relay | pino-colada",
"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",
"testw": "./node_modules/.bin/mocha --reporter list -- watch --timeout 30000", "testw": "./node_modules/.bin/mocha --reporter list -- watch --timeout 30000",

View File

@ -3,102 +3,105 @@
import _ from '@uci/utils/src/byte' import _ from '@uci/utils/src/byte'
import { CHIP, PIN } from './config' import { CHIP, PIN } from './config'
export const chip = { export default {
chip:{
// for custom chip configuration set packet.cfg='custom' then packet.setting should be a // for custom chip configuration set packet.cfg='custom' then packet.setting should be a
// configuration byte with given format ('STR' by defaul). // configuration byte with given format ('STR' by defaul).
cfg: async function(packet){ cfg: async function(packet){
// first make sure chip is in set to BANK=0 if not already // first make sure chip is in set to BANK=0 if not already
let bus = await this.bus.write(0x05,0) let bus = await this.bus.write(0x05,0)
if (bus.error) return bus if (bus.error) return bus
let setting = {} let setting = {}
let cfg = packet.cfg || 'default' let cfg = packet.cfg || 'default'
if (cfg === 'custom') setting = {val:packet.setting, fmt:packet.fmt || 'STR'} if (cfg === 'custom') setting = {val:packet.setting, fmt:packet.fmt || 'STR'}
else { else {
if (CHIP[cfg]) setting = CHIP[cfg] if (CHIP[cfg]) setting = CHIP[cfg]
else return {error:`no chip settings for ${cfg}`} else return {error:`no chip settings for ${cfg}`}
}
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
if (byte < 128) byte += 128 // make sure BANK=1 remains on
let reg = this.chip17 ? 0x0A : 0x05
// console.log(this.chip17, reg, this.id, this.address)
bus = await this.bus.write(reg,byte)
if (bus.error) return bus
bus = await this.bus.read(0x05)
if (bus.error) return bus
return { cmd:'reply', response:_.byteFormat(bus.response,{in:'DEC',out:'STR'}) }
} }
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
if (byte < 128) byte += 128 // make sure BANK=1 remains on
let reg = this.chip17 ? 0x0A : 0x05
// console.log(this.chip17, reg, this.id, this.address)
bus = await this.bus.write(reg,byte)
if (bus.error) return bus
bus = await this.bus.read(0x05)
if (bus.error) return bus
return { cmd:'reply', response:_.byteFormat(bus.response,{in:'DEC',out:'STR'}) }
}
}
// Individual Pin Configurations
// 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} }
// first get the current byte (pin) state for that setting
export const pin = {
cfg: async function(packet){
let cfg = {}
let reply = { cmd:'reply', status:{} }
packet.cfg = packet.cfg || 'output'
if (packet.cfg==='custom') cfg = packet.set
else cfg = PIN.cfgset[packet.cfg]
for(let name of Object.keys(PIN.setting)) {
let op = cfg[name] ? 'on' : 'off'
// console.log(name, op)
let busreply = await this.pin._state(packet,op,PIN.setting[name])
if (busreply.error) return busreply
reply.status[name] = busreply.status
}
return reply
}, },
// state is equivalent to read // Individual Pin Configurations
status: async function (packet) { // set is for cfg: 'custom' assume a setting is zero unless given
let reg = packet.reg ? PIN.cmd[packet.reg] : PIN.cmd.gpio // packet = { pin:, port:, cfg: , set:{dir: 0, ivrt: 0, pullup: 0, intr: 0, usedef: 0,defval: 0} }
if (!reg) return {error:`unknown register ${packet.reg}`, packet:packet } // first get the current byte (pin) state for that setting
let reply = { cmd:'reply'} pin:{
let pins = parsePins(packet.pins) cfg: async function(packet){
let state = new _.Byte() let cfg = {}
let bus = await this.bus.read(sreg(reg, packet.port)) let reply = { cmd:'reply', status:{} }
if (bus.error) return bus packet.cfg = packet.cfg || 'output'
state.value = bus.response if (packet.cfg==='custom') cfg = packet.set
reply.status = else cfg = PIN.cfgset[packet.cfg]
for(let name of Object.keys(PIN.setting)) {
let op = cfg[name] ? 'on' : 'off'
// console.log(name, op)
let busreply = await this.pin._state(packet,op,PIN.setting[name])
if (busreply.error) return busreply
reply.status[name] = busreply.status
}
return reply
},
// state is equivalent to read
status: async function (packet) {
let reg = packet.reg ? PIN.cmd[packet.reg] : PIN.cmd.gpio
if (!reg) return {error:`unknown register ${packet.reg}`, packet:packet }
let reply = { cmd:'reply'}
let pins = parsePins(packet.pins)
let state = new _.Byte()
let bus = await this.bus.read(sreg(reg, packet.port))
if (bus.error) return bus
state.value = bus.response
reply.status =
{ 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']
}) })
} }
return reply return reply
},
_state: async function(packet,op,reg){
reg = (reg!==undefined)? reg : PIN.cmd.gpio
// console.log(op, reg, packet)
let reply = { cmd:'reply'}
let pins = parsePins(packet.pins)
let state = new _.Byte()
let bus = await this.bus.read(sreg(reg,packet.port))
if (bus.error) return bus
state.value = bus.response
bus = await this.bus.write(sreg(reg,packet.port),state.bwOp(pins.value,op,{in:'PLC', out:'DEC'}))
if (bus.error) return bus
bus = await this.bus.read(sreg(reg,packet.port))
if (bus.error) return bus
state.value = bus.response
reply.status = state.bwOp(pins.value,'check',{in:'PLC', out:'PLC'})
return reply
},
// threse three only for output pins
state : {
on: async function (packet) {
return this.pin._state(packet,'on')
}, },
off: async function (packet) { _state: async function(packet,op,reg){
return this.pin._state(packet,'off') reg = (reg!==undefined)? reg : PIN.cmd.gpio
// console.log(op, reg, packet)
let reply = { cmd:'reply'}
let pins = parsePins(packet.pins)
let state = new _.Byte()
let bus = await this.bus.read(sreg(reg,packet.port))
if (bus.error) return bus
state.value = bus.response
bus = await this.bus.write(sreg(reg,packet.port),state.bwOp(pins.value,op,{in:'PLC', out:'DEC'}))
if (bus.error) return bus
bus = await this.bus.read(sreg(reg,packet.port))
if (bus.error) return bus
state.value = bus.response
reply.status = state.bwOp(pins.value,'check',{in:'PLC', out:'PLC'})
return reply
}, },
toggle: async function (packet) { // threse three only for output pins
return this.pin._state(packet,'toggle') state : {
on: async function (packet) {
return this.pin._state(packet,'on')
},
off: async function (packet) {
return this.pin._state(packet,'off')
},
toggle: async function (packet) {
return this.pin._state(packet,'toggle')
}
} }
} } // end pin.
} // end pin.
}
const parsePins = function(pins) { const parsePins = function(pins) {
if (typeof pins==='number') pins = [pins] if (typeof pins==='number') pins = [pins]

View File

@ -1,6 +1,6 @@
import Device from '@uci/i2c-device' import Device from '@uci/i2c-device'
// import Device from '../../uci-i2c-device/src/device-packet' // import Device from '../../uci-i2c-device/src/device-packet'
import { pin, chip } from './commands' import commands from './commands'
import logger from '@uci/logger' import logger from '@uci/logger'
let log = {} let log = {}
@ -10,13 +10,15 @@ export default class MCP230XX extends Device {
super(opts) super(opts)
log = logger({file:'src/mcp230xx.js',class:'MCP230XX',name:'mcp',id:this.id}) log = logger({file:'src/mcp230xx.js',class:'MCP230XX',name:'mcp',id:this.id})
this.chip17 = opts.chip17 this.chip17 = opts.chip17
this.pin = this.bindFuncs(pin) this.commands = this.bindFuncs(commands)
this.chip = this.bindFuncs(chip) 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
} }
async init(){ async init(){
await super.init() await super.init()
let res = await this.chip.cfg({}) let res = await this.chipcfg({})
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)}`
} }

View File

@ -4,56 +4,64 @@ import { byteFormat } from '@uci/utils/src/byte'
import logger from '@uci/logger' import logger from '@uci/logger'
let log = {} let log = {}
// sockets:'inter#s>t', inter:{port:INTERRUPT_PORT} // if opts.iport not set then will be generated based on pin number
export default class MCP230XXi extends MCP230XX { export default class MCP230XXi extends MCP230XX {
constructor(pins,opts) { constructor(pins,opts) {
if (typeof opts.iport ==='number' || opts.ipath) { if (typeof opts.iport ==='number' || opts.ipath) {
if (typeof opts.iport ==='number') { if (typeof opts.iport ==='number') {
opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#s>t' opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#c>t'
opts.inter = {port:opts.iport} opts.inter = {port:opts.iport}
opts.inter.host = opts.ihost || opts.host
} }
if (opts.ipath) { if (opts.ipath) {
opts.inter = { path: opts.ipath || 'interrupt'} opts.inter = { path: opts.ipath || 'interrupt'}
opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#s>n' opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + 'inter#c>n'
} }
} }
else { else {
pins.forEach( pin => { pins.forEach( (pin,index) => {
let ipin = 'i'+pin let ipin = 'i'+pin
opts[ipin] = opts[pin] || {} opts[ipin] = opts[pin] || {}
if (index===1) opts[ipin].mport = opts[ipin].mort || 'B'
delete(opts[pin])
if (opts[ipin].port || opts.iport !=='number') { if (opts[ipin].port || opts.iport !=='number') {
opts[ipin].port = opts[ipin].port || opts.iport opts[ipin].port = opts[ipin].port || opts.iport
if (typeof opts[ipin].port !=='number') opts[ipin].port = 9000 + pin if (typeof opts[ipin].port !=='number') opts[ipin].port = 9000 + pin
opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + ipin +'#s>t' opts[ipin].host = opts[ipin].host || opts.ihost || opts.host
opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + ipin +'#c>t'
} }
// either on the same host as bus and interrupt or not - no need for both // either on the same host as bus and interrupt or not - no need for both
else { else {
opts[pin].path = opts[pin].path || opts.ipath opts[pin].path = opts[pin].path || opts.ipath
if(!opts[pin].path) Object.assign(opts[pin],{path:'interrupt:'+pin}) if(!opts[pin].path) Object.assign(opts[pin],{path:'interrupt:'+pin})
opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + pin+'#s>n' opts.sockets = (opts.sockets ? (opts.sockets + ',') : '') + pin+'#c>n'
} }
}) })
} }
super(opts) super(opts)
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')
pins.forEach(pin => { pins.forEach(pin => {
this[pin] = opts[pin] || {} this[pin] = opts['i'+pin] || {}
}) })
this.pins = pins this.pins = pins
log = logger({file:'src/mcp230xxi.js',class:'MCP230XXi',name:'mcp',id:this.id}) Object.assign(this.commands.pin, this.bindFuncs(ipincommands)) // add interrupt pin commands to base set in "command.js"
Object.assign(this.pin, this.bindFuncs(pin)) // add interrupt pin commands to base set in "command.js" this.addNamespace('commands','c')
this._interruptProcess = null this._interruptProcess = null
this.ready = false
log.info({opts:opts, pins:pins}, 'options for mcp interrupt processor')
} }
async init(){ async init(){
await super.init() await super.init()
this.pins.forEach(async pin => { 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'}
// let cfg = {port:this[pin].mport||'A',pins:this[pin].pins||'all', cfg:this[pin].type ||'toggle_switch'} await this.pin.cfg(cfg)
// console.log(cfg) log.info('resetting mcp port for corresponding gpio pin')
await this.pin.cfg({port:this[pin].mport||'A',pins:this[pin].pins||'all', cfg:this[pin].type ||'toggle_switch'}) await this.pin.interrupt.reset(this[pin].mport)
this.pin.interrupt.reset(this[pin].mport) this.ready=true
}) })
this.on('interrupt', function (details) { this.on('interrupt', function (details) {
@ -71,32 +79,34 @@ export default class MCP230XXi extends MCP230XX {
} // end of MCP230XX Class } // end of MCP230XX Class
const pin = { interrupt: { // commands to be added to pin command functions
const ipincommands= { interrupt: {
reset: async function (port) { reset: async function (port) {
console.log('resetting interrupt for port',port || 'A',this.id) log.info(`resetting interrupt for port ${port || 'A'},${this.id}`)
return await this.bus.read(port!=='B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register return await this.bus.read(port!=='B' ? 0x08 : 0x18) // 0x08 is intcap interrupt capture register
}, },
find: async function (inter) { // given a gpio interrupt then push a packet with cmd: 'pin.interrupt.find' and pin: the gpio pin number
// console.dir(inter) find: async function (inter) { // inter is a hash packet
let packet = {pins:'all',reg:'intf'} if(this.ready){ // protects tripped interrupt before it's fully initialized and reset
packet.port = inter.port || this[inter.pin].mport || 'A' log.info({packet:inter},'finding mcp pin which caused interrupt')
// console.log(`${inter.count}th interrupt fired, pin:${inter.pin}`) let packet = {pins:'all',reg:'intf'}
// console.log('packet to read port\n',packet.port) packet.port = inter.port || this[inter.pin].mport || 'A'
let res = await this.pin.status(packet) let res = await this.pin.status(packet)
this.pin.interrupt.reset(packet.port) log.info('found pin now resetting mcp port interrupt')
if (!res.status) return {error:'no pin associated with interrupt'} await this.pin.interrupt.reset(packet.port)
let pin = byteFormat(res.status.port, { in: 'ARY', out: 'PLC' }) if (!res.status) return {error:'no pin associated with interrupt'}
// console.log('pin and port that caused the interrupt', pin, packet.port) let pin = byteFormat(res.status.port, { in: 'ARY', out: 'PLC' })
res.pin = pin[0] res.pin = pin[0]
packet.pins = pin[0] packet.pins = pin[0]
packet.reg = null packet.reg = null
res.state = (await this.pin.status(packet)).status.pins[0][1] res.state = (await this.pin.status(packet)).status.pins[0][1]
res.port = packet.port res.port = packet.port
res.count = inter.count res.count = inter.count
res.inter = inter.pin res.inter = inter.pin
delete res.status delete res.status
this.emit('interrupt',res) this.emit('interrupt',res)
return res return res
}
} }
} }
} }