uci-i2c-bus/src/bus.js

149 lines
4.2 KiB
JavaScript

import pify from 'pify'
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) {
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)
this.id = opts.id || 'i2c-bus'
log = logger({
name: 'i2c-bus',
id: this.id,
file: 'src/bus.js',
class: 'Bus'
})
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.addNamespace('bus')
this.bus.busFuncs = async (packet) => {
packet.functions = this.busFuncs
packet.cmd='reply'
return packet
}
this.bus.ack = async function (){
//
let bus = await this.bus.scan()
if (bus.error) return bus
let res = { cmd:'reply', ack: true, scan:bus.response}
return res
},
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() {
for (let alias in this.busFuncs) {
let func = this.busFuncs[alias]
this.addBusFunc(alias,func.name || alias, func.args)
}
}
addBusFunc(alias,name, args) {
if (!name) name=alias
if (Array.isArray(name)) {
args=name
name=alias
}
console.log(alias,name,args)
this.bus[alias] = busFunction.bind(this, alias, pify(this.i2cbus[name]), args ||[])
}
} // 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 (name, 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 invalid value ${argv} for function ${name}`
return true
}
} else {
packet.error = `missing argument, ${arg}, for function ${name}`
return true
}
}
})
if (!packet.error) {
log.trace({msg:'adding to queue', function:name,arguments:argsV})
let [err,res] = await to(this._queue.add(() => func.call(this.i2cbus,...argsV)))
if (err) packet.error = `error during call to ${name} 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']}
}