diff --git a/.eslintrc.js b/.eslintrc.js index c11a1d5..2bed546 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,11 +1,17 @@ module.exports = { + "ecmaFeatures": { + "modules": true, + "spread" : true, + "restParams" : true + }, "env": { "es6": true, "node": true, "mocha": true }, "parserOptions": { - "ecmaVersion": 2017 + "ecmaVersion": 2017, + "sourceType": "module" }, "extends": "eslint:recommended", "rules": { diff --git a/.esmrc.json b/.esmrc.json new file mode 100644 index 0000000..f195c03 --- /dev/null +++ b/.esmrc.json @@ -0,0 +1,3 @@ +{ + "@std/esm": "cjs" +} diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..9ff939f --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,3 @@ +*.log +*.sock +/node_modules/ diff --git a/examples/bus.mjs b/examples/bus.mjs new file mode 100644 index 0000000..e93b7f2 --- /dev/null +++ b/examples/bus.mjs @@ -0,0 +1,20 @@ +/* +* i2c bus with both unix and tcp socket using defaults. For TCP that is host OS name and port 8080 +* +*/ + +import Bus from '../src/bus-packet' + +const delay = time => new Promise(res=>setTimeout(()=>res(),time)) + +; +(async () => { + + // let i2cbus = new Bus({id:'i2c-bus', log:true}) + let i2cbus = new Bus({id:'i2c-bus', sockets:'us,ts', log:true}) + + await i2cbus.init() + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/examples/ipc-relay.mjs b/examples/ipc-relay.mjs new file mode 100644 index 0000000..2a12334 --- /dev/null +++ b/examples/ipc-relay.mjs @@ -0,0 +1,52 @@ +/* +* A tcp customer/client to talk with the i2c bus and scan the bus for devices +* +*/ + +const PATH = '/opt/uci/uci-base/src/unix.sock' + +import Base from '../../uci-base/src/base' +// import Base from '@uci/base' + +const delay = time => new Promise(res=>setTimeout(()=>res(),time)) +; +(async () => { + + let relays = new Base({sockets:'uc', path:PATH, log:true}) + + relays.reply = function (packet) { + // console.log(packet.bus) + console.log('response from relays',packet.bus.func, packet.bus.args.cmd, packet.bus.response) + } + await relays.init() + console.log('=============sending============') + let packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd: 0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 0, byte:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 9, byte:255}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:9}} } + console.dir(packet.bus) + await relays.send(packet) + await delay(1000) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 9, byte:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:9}} } + console.dir(packet.bus) + await relays.send(packet) + + await delay(1000) + process.kill(process.pid, 'SIGTERM') + + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/examples/ipc-scan.mjs b/examples/ipc-scan.mjs new file mode 100644 index 0000000..c28fe10 --- /dev/null +++ b/examples/ipc-scan.mjs @@ -0,0 +1,30 @@ +/* +* i2c bus unix socket and client in one for demo +* +*/ + +import Bus from '../src/bus-packet' + +const delay = time => new Promise(res=>setTimeout(()=>res(),time)) +; +(async () => { + + let i2cbus = new Bus({id:'i2c-bus', sockets:'us,uc'}) + + i2cbus.reply = function (packet) { + console.log('==== response from i2cbus =>',packet.bus.response) + } + + await i2cbus.init() + console.log('=============sending============') + let packet = {cmd:'rw', bus:{func:'scan'} } + console.dir(packet) + await i2cbus.send(packet) + + await delay(1000) + process.kill(process.pid, 'SIGTERM') + + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/examples/tcp-relay.mjs b/examples/tcp-relay.mjs new file mode 100644 index 0000000..d6ac0a7 --- /dev/null +++ b/examples/tcp-relay.mjs @@ -0,0 +1,52 @@ +/* +* A tcp customer/client to talk with the i2c bus and scan the bus for devices +* +*/ + +const HOST = 'sbc' + +import Base from '../../uci-base/src/base' +// import Base from '@uci/base' + +const delay = time => new Promise(res=>setTimeout(()=>res(),time)) +; +(async () => { + + let relays = new Base({id:'tcp-i2c-client', sockets:'tc', host:HOST, log:true}) + + relays.reply = function (packet) { + // console.log(packet.bus) + console.log('response from relays',packet.bus.func, packet.bus.args.cmd, packet.bus.response) + } + await relays.init() + console.log('=============sending============') + let packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd: 0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 0, byte:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 9, byte:255}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:9}} } + console.dir(packet.bus) + await relays.send(packet) + await delay(1000) + packet = {cmd:'rw', bus:{func:'write', args:{address:39,cmd: 9, byte:0}} } + console.dir(packet.bus) + await relays.send(packet) + packet = {cmd:'rw', bus:{func:'read', args:{address:39 ,cmd:9}} } + console.dir(packet.bus) + await relays.send(packet) + + await delay(1000) + process.kill(process.pid, 'SIGTERM') + + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/examples/tcp-scan.mjs b/examples/tcp-scan.mjs new file mode 100644 index 0000000..85a735d --- /dev/null +++ b/examples/tcp-scan.mjs @@ -0,0 +1,34 @@ +/* +* A tcp customer/client to talk with the i2c bus and scan the bus for devices +* +*/ + +const HOST = 'sbc' + + + +const delay = time => new Promise(res=>setTimeout(()=>res(),time)) +; +(async () => { + + let scanner = new Base({id:'tcp-i2c-client', sockets:'tc', host:HOST}) + + scanner.reply = function (packet) { + let addresses = packet.bus.response.map(device => { + return device.toString(16)}) + console.log(packet) + console.log('==== device hex addreses on i2cbus ===\n',addresses) + } + await scanner.init() + console.log('=============sending============') + let packet = {cmd:'rw', bus:{func:'scan'} } + console.dir(packet) + await scanner.send(packet) + + await delay(3000) + process.kill(process.pid, 'SIGTERM') + + +})().catch(err => { + console.error('FATAL: UNABLE TO START SYSTEM!\n',err) +}) diff --git a/index.js b/index.js deleted file mode 100644 index f84fe28..0000000 --- a/index.js +++ /dev/null @@ -1,8 +0,0 @@ -let opts = { - dirname: __dirname + '/src', - // http://stackoverflow.com/questions/2078915/a-regular-expression-to-exclude-a-word-string - filter: /^(?!index)([^\.].*)\.js?$/, - recursive: false, - merge: true // remove or comment to have each file in /lib be a prop/key in library...see node-require-all -} -module.exports = require('@uci/require-all')(opts) diff --git a/package.json b/package.json index 4a378fe..ff0ac31 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { - "name": "@uci/i2c", - "version": "0.1.1", - "description": "Bus and Device Classes for I2C Interfacing", - "main": "index.js", + "name": "@uci/i2c-bus", + "version": "0.1.0", + "description": "I2c Bus Classes for Communication to I2C bus via socket or direct call", + "main": "src/bus", "scripts": { - "testw": "./node_modules/.bin/mocha --reporter list --recursive --watch", - "test": "istanbul cover ./node_modules/.bin/_mocha test/ --report lcovonly -- -R spec --recursive && codecov || true" + "test": "mocha -r @std/esm test/*.test.mjs", + "testw": "mocha -r @std/esm test/*.test.mjs --watch --recurse --watch-extensions mjs", + "testci": "istanbul cover ./node_modules/.bin/_mocha test/ --report lcovonly -- -R spec --recursive && codecov || true" }, "author": "David Kebler", "license": "MIT", @@ -23,11 +24,14 @@ "url": "https://github.com/uCOMmandIt/i2c/issues" }, "homepage": "https://github.com/uCOMmandIt/i2c#readme", + "@std/esm": "cjs", "dependencies": { - "@uci/require-all": "^2.x", - "i2c-bus": "^1.x" + "@uci/base": "^0.1.0", + "i2c-bus": "^1.x", + "pify": "^3.0.0" }, "devDependencies": { + "@std/esm": "^0.18.0", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", "codecov": "^1.0.1", diff --git a/src/bus-packet.mjs b/src/bus-packet.mjs new file mode 100644 index 0000000..598e0af --- /dev/null +++ b/src/bus-packet.mjs @@ -0,0 +1,76 @@ + +import i2c from 'i2c-bus' +import pify from 'pify' +// import Base from '@uci/base' +import Base from '../../uci-base/src/base' + +export default class Bus extends Base { + constructor(opts) { + opts.sockets = opts.sockets || 'us' + super(opts) + this.busnum = opts.busnum || 1 + this.i2cbus = i2c.open(this.busnum, () => {}) + this.funcs = bus_funcs + // this.init = this.init.bind(this) + } + + async init(){ + // console.log('init', this.rw) + await super.init() + } + + async rw (packet){ + // console.dir('=>',packet.bus.fusncs) + if (!packet.bus.func) return {error: 'no i2c bus function in packet', packet: packet.bus } + if (this.funcs[packet.bus.func]) { + packet.bus.response = await this.funcs[packet.bus.func].bind(this)(packet.bus.args) + packet.cmd = 'reply' + return packet + } + return {error: 'no i2c bus function available for packet function', packet: packet.bus } + } + +} // end of Bus Packet Class + +const bus_funcs = { + + scan: function () { return pify(this.i2cbus.scan).bind(this.i2cbus)() }, + close: function () { return pify(this.i2cbus.close).bind(this.i2cbus)() }, + + readRaw: function (arg) { + return pify(this.i2cbus.i2cRead).bind(this.i2cbus)(arg.address, arg.length, arg.buffer) + }, + + writeRaw: function (arg) { + return pify(this.i2cbus.i2cWrite).bind(this.i2cbus)(arg.address, arg.length, arg.buffer) + }, + + read: function (arg) { + // console.log('read: address, cmd', address, cmd) + return pify(this.i2cbus.readByte).bind(this.i2cbus)(arg.address, arg.cmd) + }, + + write: function (arg) { + // console.log('write: address, cmd, byte', arg.address, arg.cmd, arg.byte) + return pify(this.i2cbus.writeByte.bind(this.i2cbus))(arg.address, arg.cmd, arg.byte) + }, + + read2: function (arg) { + return pify(this.i2cbus.readWord.bind(this.i2cbus))(arg.address, arg.cmd) + }, + + write2: function (arg) { + return pify(this.i2cbus.writeWord.bind(this.i2cbus))(arg.address, arg.cmd, arg.bytes) + }, + + receive: function (arg) { + // console.log('receivebyte', address) + return pify(this.i2cbus.receiveByte.bind(this.i2cbus))(arg.address) + }, + + send: function (arg) { + // console.log('sendbyte', address,byte) + return pify(this.i2cbus.sendByte.bind(this.i2cbus))(arg.address, arg.byte) + } + +} diff --git a/src/bus.js b/src/bus.mjs similarity index 84% rename from src/bus.js rename to src/bus.mjs index 53d2242..a6f6f3e 100644 --- a/src/bus.js +++ b/src/bus.mjs @@ -1,12 +1,8 @@ -// Solely a promise wrapper module for the basic async functions of the fivdi/i2c-bus javascript bindings C API -// https://github.com/fivdi/i2c-bus -'use strict' +import i2c from 'i2c-bus' +import pify from 'pify' -const i2c = require('i2c-bus'), - pify = require('pify') - -class Bus { +export default class Bus { constructor(busnum=1) { this.busnum = busnum this.bus = i2c.open(this.busnum, () => {}) @@ -55,7 +51,3 @@ class Bus { } // end of Bus Class - -module.exports = { - Bus -} diff --git a/src/device.js b/src/device.js deleted file mode 100644 index e2c9425..0000000 --- a/src/device.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict' - -// ********************************** - -class Device { - // bus is i2c-bus bus object - constructor(bus, address, opts) { - this.bus = bus - this.address = address - if (opts) { - this.id = opts.id // must be unique within a bus - this.desc = opts.desc - this.channel = opts.channel // if using TAC9546A channel number on which device is attached - } - } - - async _setChannel() { - // console.log('before set',this.address,this.id,this.channel, this.bus.getState) - if (this.channel) { - if (!this.bus.address) { return Promise.reject('Channel set but no mux on bus')} - return this.bus.set(this.channel) - } - return Promise.resolve() // no channel for device either no mux or device is attached to mux bypass - } - - // for devices that need just a simple send of a byte without a register command - async receive() { - await this._setChannel() - return this.bus.receive(this.address) - } - - async send(cmd, byte) { - await this._setChannel() - return this.bus.send(this.address, cmd, byte) - } - - // for devices needing a buffer/stream - async readRaw(length, buffer) { - await this._setChannel() - return this.bus.readRaw(this.address, length, buffer) - } - - async writeRaw(length, buffer) { - await this._setChannel() - return this.bus.writeRaw(this.address, length, buffer) - } - - // both cmd and byte should be a single byte as a decimal or hex - async read(cmd) { - await this._setChannel() - // console.log('after set before read',this.address,this.id,this.channel,this.bus.getState) - return this.bus.read(this.address, cmd) - } - - async write(cmd, byte) { - await this._setChannel() - // console.log('after set, before write',this.address,this.id,this.channel,this.bus.getState) - return this.bus.write(this.address, cmd, byte) - } - - // for I2C devices that use a word length packackage - async read2(cmd) { - await this._setChannel() - return this.bus.read2(this.address, cmd) - } - - async write2(cmd, bytes) { - await this._setChannel() - return this.bus.write2(this.address, cmd, bytes) - } - -} - -module.exports = { - Device -} diff --git a/test/bus.test.js b/test/bus.test.js deleted file mode 100644 index 52fed6d..0000000 --- a/test/bus.test.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict' - -const chai = require('chai'), - chaiAsPromised = require("chai-as-promised"), - Bus = require('../lib/bus').Bus - -chai.use(chaiAsPromised) - -const expect = chai.expect - -let bus = new Bus() - -// const addresses = [0x20, 0x26, 0x27] -const addresses = [] - -describe('Bus Class - ', function () { - - it('Can scan the bus for devices', function () { - - return expect(bus.scan().catch(err => console.log("an error", err))).to.eventually.deep.equal(addresses) - - }) -}) diff --git a/test/bus.test.mjs b/test/bus.test.mjs new file mode 100644 index 0000000..6f6ecb2 --- /dev/null +++ b/test/bus.test.mjs @@ -0,0 +1,21 @@ +import Bus from '../src/bus' +import chai from 'chai' +import chaiAsPromised from 'chai-as-promised' + +chai.use(chaiAsPromised) + +const expect = chai.expect + +let bus = new Bus() + +const addresses = [0x25, 0x26, 0x27] +// const addresses = [] + +describe('Bus Class - ', function () { + + it('Can scan the bus for devices', function () { + + return expect(bus.scan().catch(err => console.log('an error', err))).to.eventually.deep.equal(addresses) + + }) +}) diff --git a/test/device.test.js b/test/device.test.js deleted file mode 100644 index 75d74c1..0000000 --- a/test/device.test.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict' - -const chai = require('chai'), - chaiAsPromised = require('chai-as-promised'), - Bus = require('@uci/i2c').Bus, - Device = require('../lib/device').Device - -chai.use(chaiAsPromised); - -const expect = chai.expect - -let bus = new Bus() -let device = new Device(bus, 0x20) - -describe('Device Class - ', function () { - - let SET = 0xff - it('Can write and read to actual device', function () { - - device.write(0x09, SET).then(expect(device.read(0x0A)).to.eventually.equal(SET)) - .then(setTimeout(() => device.write(0x09, 0), 3000)) - .catch(err => console.log('an error', err)) - }) -})