uci-mcp/src/commands.js

136 lines
5.4 KiB
JavaScript

import * as _ from '@uci-utils/byte'
import { CHIP, PIN } from './config'
import logger from '@uci-utils/logger'
let log = logger({file:'/src/commands.js', package:'@uci/mcp'})
// TODO add uci debug logging
export default {
chip:{
// for custom chip configuration set packet.cfg='custom' then packet.setting should be a
// configuration byte with given format ('STR' by defaul).
cfg: async function(packet){
// first make sure chip is in set to BANK=0 if not already
let bus = await this.bus.write(0x05,0)
if (bus.error) return bus
let setting = {}
let cfg = packet.cfg || 'default'
if (cfg === 'custom') setting = {val:packet.setting, fmt:packet.fmt || 'STR'}
else {
if (CHIP[cfg]) setting = CHIP[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
log.debug ({cmd:'chip.cfg', line:28, msg:'writing chip configuration', chip17:this.chip17, register:reg, id:this.id, address: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
if (!this.chip17) bus.response = bus.response + 128
let res = _.byteFormat(bus.response,{in:'DEC',out:'STR'})
if (res !== setting.val) return { cmd:'reply', error:`chip configuration failed ${res} != ${setting.val} (${cfg})`}
return { cmd:'reply', response:res }
}
},
// Pin(s) 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
pin:{
cfg: async function(packet){
let cfg = {}
let reply = { cmd:'reply', status:{} }
packet.config = packet.config || packet.cfg || 'output'
if (packet.config==='custom') cfg = packet.set
else cfg = PIN.cfgset[packet.config]
for(let name of Object.keys(PIN.setting)) {
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]})
let busreply = await this.commands.pin._state(packet,op,PIN.setting[name])
if (busreply.error) return busreply
reply.status[name] = busreply.status
}
return reply
},
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) {
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
if (!reg) return {error:`unknown register ${packet.reg}`, packet:packet }
let pins = parsePins(packet.pins || packet.pin)
let state = new _.Byte()
let bus = await this.bus.read(sreg(reg, packet.port))
if (bus.error) return bus
state.value = bus.response
let reply = {
port:state.toFmt('ARY'),
pins: pins.value.map(pin => {
if (state.toFmt('PLC').indexOf(pin) !==-1) return [pin, 'on']
else return [pin,'off']
})
}
if (packet.pin) reply.state = reply.pins[0][1]
return reply
},
_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
log.debug({cmd:'pin._state', line:82, msg:'_state change request', operation:op, register:reg, packet:packet})
let reply = { cmd:'reply'}
let pins = parsePins(packet.pins || packet.pin)
let state = new _.Byte()
// TODO support setting state on both ports if non given
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
log.debug({cmd:'pin._state', line:94, msg:'after setting pin state', prev:state.prv, new:state.value})
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.commands.pin._state(packet,'on')
},
off: async function (packet) {
return this.commands.pin._state(packet,'off')
},
toggle: async function (packet) {
return this.commands.pin._state(packet,'toggle')
}
}
} // end pin.
}
const parsePins = function(pins) {
if (typeof pins==='number') pins = [pins]
if (typeof pins==='string') {
if (pins==='all') pins = _.byteFormat(255,{in:'DEC', out:'PLC'})
else {
pins = pins.split(/[,:\s]+/).map(Number).filter( (x) => !Number.isNaN(x))
}
}
return new _.Byte(pins,'PLC')
}
const sreg = (reg,port) => {
return reg + ((port==='B') ? 0x10 : 0)
}