uci-i2c-bus/src/bus.js

138 lines
3.9 KiB
JavaScript

import pify from 'pify'
// import btc from 'better-try-catch'
import to from 'await-to-js'
import i2c from 'i2c-bus'
import PQueue from 'p-queue'
import Base from '@uci/base'
import logger from '@uci-utils/logger'
let log = {}
class I2CBus extends Base {
constructor(opts) {
log = logger({
name: 'i2c-bus',
id: opts.id,
file: 'src/bus.js',
class: 'Bus'
})
if (opts.path) opts.ns = { path: opts.path }
if (!opts.ns) opts.ns = { path: 'i2c-bus' }
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'ns#s>n'
// TODO if port is passed as option then set up tcp with that port
if (opts.tcp) {
if (typeof opts.tcp === 'number') opts.ts = { port: opts.tcp }
else opts.ts = { port: 1776 }
opts.sockets = (opts.sockets ? opts.sockets + ',' : '') + 'ts#s>t'
}
super(opts)
log.debug({ opts: opts }, 'created bus with these opts')
this.busnum = opts.busnum || 1
this.i2cbus = i2c.open(this.busnum, () => {})
this._funcs = bus_funcs
this.bus = {}
this.addBusFuncs(this._funcs)
this.addNamespace('bus')
this.bus.busFuncs = async (packet) => {
packet.functions = this.busFuncs
packet.cmd='reply'
return packet
}
this._queue = new PQueue({concurrency: opts.concurrency || 1})
}
async init() {
await super.init()
let count = 0
this._queue.on('active', () => {
log.debug(`Queue: working on item #${++count}. Size: ${this._queue.size} Pending: ${this._queue.pending}`)
})
}
get busFuncs() { return this._funcs}
addBusFuncs(funcs) {
for (let name in funcs) {
let func = funcs[name]
this.addBusFunc(name,func)
}
}
addBusFunc(name,func) {
this.bus[name] = busFunction.bind(this, func.name || name , func.args || [])
this._funcs[name]=func
}
} // end of Bus Packet Class
export default I2CBus
const validateArg = function (arg,value) {
let valid = false
switch (arg) {
case 'address':
valid = Number.isInteger(value) && value >=0 && value <= 119
break
case 'length':
case 'cmd':
valid = Number.isInteger(value)
break
case 'byte':
valid = Number.isInteger(value) && value >= 0 && value <= 255
break
case 'word':
valid = Number.isInteger(value) && value >= 0 && value <= 65535
break
case 'bit':
valid = Number.isInteger(value) && (value === 0 || value === 1)
break
case 'buffer':
valid = Buffer.isBuffer(value)
}
return valid
}
async function busFunction (func,args,packet) {
let argsV = []
args.some(arg => {
if (packet.args) {
let argv = packet.args[arg]
if (argv != null) {
if(validateArg(arg,argv)) argsV.push(argv)
else {
packet.error = `argument ${arg} has an invalide value ${argv} for function ${func}`
return true
}
} else {
packet.error = `missing argument, ${arg}, for function ${func}`
return true
}
}
})
if (!packet.error) {
log.trace({msg:'adding to queue', function:func,arguments:argsV})
let busfunc = pify(this.i2cbus[func].bind(this.i2cbus,...argsV))
let [err,res] = await to(this._queue.add(busfunc))
if (err) packet.error = `error during call to ${func} with arguments ${JSON.stringify(packet.args)}: ${err}`
else packet.response = res
}
packet.cmd = 'reply'
return packet
}
// default function set
const bus_funcs = {
scan: {},
close: {},
methods: {name:'i2cFuncs'},
deviceId: {args:['address']},
readRaw: {name:'i2cRead', args:['address','length','buffer']},
writeRaw: {name:'i2cWrite', args:['address','length','buffer']},
read: {name:'readByte', args:['address','cmd']},
write: {name:'writeByte', args:['address','cmd','byte']},
read2: {name:'readWord', args:['address','cmd']},
write2: {name:'writeWord', args:['address','cmd','word']},
receive: {name:'receiveByte', args:['address']},
send: {name:'sendByte', args:['address','byte']}
}