154 lines
4.5 KiB
JavaScript
154 lines
4.5 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) {
|
|
opts.path =opts.path || 'i2c-bus' // always a pipe by default
|
|
if (typeof opts.port === 'boolean') opts.port=1776
|
|
opts.name = opts.name || 'i2c-bus'
|
|
super(opts)
|
|
log = logger({
|
|
name: 'i2c-bus',
|
|
id: this.id,
|
|
file: 'src/bus.js',
|
|
class: 'Bus'
|
|
})
|
|
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 || !bus.response.length) bus.ack =false
|
|
else bus.ack = true
|
|
return bus
|
|
},
|
|
this.ackInterval = opts.ackInterval!=null ? opts.ackInterval : 5
|
|
this._queue = new PQueue({concurrency: opts.concurrency || 1})
|
|
this.ready.addObserver('bus:ack')
|
|
} // constructor
|
|
|
|
async init() {
|
|
await super.init()
|
|
let count = 0
|
|
const ack = (await this.bus.ack.call(this)).ack
|
|
this.emit('bus:ack',ack) // will be picked up by ready observer
|
|
this.autoAck(this.ackInterval) // if auto on then will notice when there is issue/connection with i2cbus
|
|
this._queue.on('active', () => {
|
|
log.debug(`Queue: working on item #${++count}. Size: ${this._queue.size} Pending: ${this._queue.pending}`)
|
|
})
|
|
}
|
|
|
|
get busFuncs() { return this._funcs}
|
|
|
|
autoAck(interval) {
|
|
if (interval>.9) this._autoAck = setInterval(async ()=> {
|
|
let ack = (await this.bus.ack.call(this)).ack
|
|
this.emit('bus:ack',ack) // will be picked up by ready observer
|
|
},interval*1000)
|
|
else clearInterval(this._autoAck)
|
|
}
|
|
|
|
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
|
|
}
|
|
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
|
|
}
|
|
}
|
|
})
|
|
// this.emit('log', {level:'i2c', packet:packet, error:packet.error, msg:'packet going to bus'})
|
|
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']}
|
|
}
|