first commit of packet based mcp code.
incoming packet interpreted and sent on to bus listens for response and processes and sends back to requestor Working pin.test examplemaster
parent
35605352bf
commit
71bd508a0c
|
@ -0,0 +1,33 @@
|
||||||
|
module.exports = {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"modules": true,
|
||||||
|
"spread" : true,
|
||||||
|
"restParams" : true
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"es6": true,
|
||||||
|
"node": true,
|
||||||
|
"mocha": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2017,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"rules": {
|
||||||
|
"indent": [
|
||||||
|
"error",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"no-console": 0,
|
||||||
|
"semi": ["error", "never"],
|
||||||
|
"linebreak-style": [
|
||||||
|
"error",
|
||||||
|
"unix"
|
||||||
|
],
|
||||||
|
"quotes": [
|
||||||
|
"error",
|
||||||
|
"single"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/coverage/
|
/coverage/
|
||||||
|
/syncd/
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* i2c bus unix socket and client in one for demo
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Base from '../../uci-base/src/base'
|
||||||
|
|
||||||
|
const PATH = '/opt/sockets/mcp.sock'
|
||||||
|
|
||||||
|
const delay = time => new Promise(res=>setTimeout(()=>res(),time))
|
||||||
|
;
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
let mcpclient = new Base({id:'mcpclient', sockets:'uc#c>n', uc:{path:PATH}})
|
||||||
|
|
||||||
|
await mcpclient.init()
|
||||||
|
console.log('=============sending============')
|
||||||
|
let packet = {cmd:'pin.test'}
|
||||||
|
console.dir(packet)
|
||||||
|
await mcpclient.send(packet)
|
||||||
|
|
||||||
|
await delay(3000)
|
||||||
|
process.kill(process.pid, 'SIGTERM')
|
||||||
|
|
||||||
|
|
||||||
|
})().catch(err => {
|
||||||
|
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||||
|
})
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* i2c bus with both unix and tcp socket using defaults. For TCP that is host OS name and port 8080
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import MCP230XX from '../src/mcp230xx-packet'
|
||||||
|
// const PATH = ''
|
||||||
|
|
||||||
|
;
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
let mcp_chip = new MCP230XX({id:'mcp23008-27', address:'0x27', bus:{host:'sbc'} })
|
||||||
|
|
||||||
|
await mcp_chip.init()
|
||||||
|
|
||||||
|
})().catch(err => {
|
||||||
|
console.error('FATAL: UNABLE TO START SYSTEM!\n',err)
|
||||||
|
})
|
|
@ -4,6 +4,8 @@
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"description": "Classes and Helper Functions for using the MCP chip on I2C Bus",
|
"description": "Classes and Helper Functions for using the MCP chip on I2C Bus",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"mcp": "SOCKETS_DIR=/opt/sockets node_modules/.bin/nodemon --require @std/esm examples/mcp",
|
||||||
|
"mcpl": "DEBUG=true SOCKETS_DIR=/opt/sockets node_modules/.bin/nodemon --require @std/esm examples/mcp",
|
||||||
"test": "./node_modules/.bin/mocha --reporter list --timeout 30000",
|
"test": "./node_modules/.bin/mocha --reporter list --timeout 30000",
|
||||||
"testw": "./node_modules/.bin/mocha --reporter list -- watch --timeout 30000",
|
"testw": "./node_modules/.bin/mocha --reporter list -- watch --timeout 30000",
|
||||||
"testd": "DEBUG='1:*' ./node_modules/.bin/mocha --reporter list --watch --timeout 30000",
|
"testd": "DEBUG='1:*' ./node_modules/.bin/mocha --reporter list --watch --timeout 30000",
|
||||||
|
@ -33,11 +35,14 @@
|
||||||
"@uci/utils": "^0.1.0",
|
"@uci/utils": "^0.1.0",
|
||||||
"aggregation": "^1.2.0"
|
"aggregation": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
"@std/esm": "cjs",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@std/esm": "^0.20.0",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"codecov": "^1.0.1",
|
"codecov": "^1.0.1",
|
||||||
"debug": "^2.6.8",
|
"debug": "^2.6.8",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"mocha": "^3.4.2"
|
"mocha": "^3.4.2",
|
||||||
|
"nodemon": "^1.14.12"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const Device = require('@uci/i2c').Device,
|
||||||
|
portpin = require('./port-pin'), // classes for MCP port and pins
|
||||||
|
EventEmitter = require('events'),
|
||||||
|
_ = require('@uci/utils'),
|
||||||
|
aggregate = require('aggregation/es6')
|
||||||
|
|
||||||
|
const
|
||||||
|
Port = portpin.Port,
|
||||||
|
pinConfigs = portpin.configs, // for export so pinConfigs can be accessed at runtime
|
||||||
|
pause = _.pPause,
|
||||||
|
debug = _.debug('mcp:23008-17')
|
||||||
|
|
||||||
|
class MCP23008 extends aggregate(Device, EventEmitter) {
|
||||||
|
constructor(busObj, i2cAddress, opts = {}) {
|
||||||
|
super(busObj, i2cAddress, opts)
|
||||||
|
// opts could include options passed on to ports and pin including custom pin config, pin ids...see gpio.js
|
||||||
|
this.chip_config = opts.chip_config // TODO allow opts.chip_config to be a byte instead of a string pointer
|
||||||
|
this.ports = {}
|
||||||
|
opts.portID = 'A'
|
||||||
|
opts.pids = opts.pids ? opts.pids : opts.pidsA
|
||||||
|
this.ports.A = new Port(opts)
|
||||||
|
this.ports.A.state = new _.Byte(opts.stateA)
|
||||||
|
this.ports.A.interrupt = opts.interruptA ? opts.interruptA : opts.interrupt
|
||||||
|
} // end constructor
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
pin(id) { return this.ports.A.pin(id) } // get a reference to a particular pin's object
|
||||||
|
|
||||||
|
pid(address) { return this.ports.A.pid(address) } // return pin id for a given address on a port
|
||||||
|
|
||||||
|
pid(num) { return this.ports.A.pins[num - 1].id }
|
||||||
|
|
||||||
|
portByPin(id) {
|
||||||
|
if (this.ports.A.pin(id)) { return 'A' }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
state(port = 'A') {
|
||||||
|
return this.ports[port].state.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// get a handle to the ports interrupt
|
||||||
|
inter(port = 'A') {
|
||||||
|
return this.ports[port].interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must call after instantiating.
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
debug.L1(`\n=======\nInitializing ${this.id}`)
|
||||||
|
await this.writeChipCfg(this.chip_config) // chip settings
|
||||||
|
await this.writePinsCfg()
|
||||||
|
// write out any initial state(s)
|
||||||
|
for (let port in this.ports) {
|
||||||
|
if (this.state(port)) {
|
||||||
|
debug.L1(`writing initial port state ${port} ${this.state(port)}`)
|
||||||
|
await this.writePort(this.state(port), 'force', port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// must call after init if using interrupts
|
||||||
|
async start() {
|
||||||
|
debug.L1(`starting ${ this.id }`)
|
||||||
|
for (let port in this.ports) {
|
||||||
|
// if there are interrupts being used then start them and listeners
|
||||||
|
if (this.inter(port)) {
|
||||||
|
this.startInterrupt(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async startInterrupt(port) {
|
||||||
|
await this.interruptReset(port)
|
||||||
|
debug.L1(`starting interrupt on port ${ port }`)
|
||||||
|
await this.inter(port).start()
|
||||||
|
let chip = this // scope `this` for use in the listener below
|
||||||
|
// bind handler to the chip so handler can read/write to chip/bank when interrupt is emitted
|
||||||
|
debug.L3('handler', this.inter(port).handler)
|
||||||
|
let ihandler = this.inter(port).handler.bind(this)
|
||||||
|
// inside the listener `this` is the interrupt not the chip/bank
|
||||||
|
this.inter(port).on('fired', async function () {
|
||||||
|
debug.L1(`interrupt from ${this.pin_number}`)
|
||||||
|
let data = await ihandler(port)
|
||||||
|
debug.L2(`port interrupt event 'fired' data => ${data.bank} on port ${data.port} pin# ${data.pin} pid ${data.pid}`)
|
||||||
|
chip.emit('fired', data) // emit up the class chain
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async interruptReset(port = 'A') {
|
||||||
|
await this.read(portReg(0x08, port))
|
||||||
|
await pause(100) // give enough time for mcp to reset its interupt
|
||||||
|
debug.L1(`interrupt reset on ${this.id} port ${port}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async interruptPin(port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port ? port : null
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
let result = await this.read(portReg(0x07, port))
|
||||||
|
return format ? _.byteFormat(result, { in: 'DEC', out: format }) : result
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeChipCfg(cfg = 'default') {
|
||||||
|
let setting = chip_config[cfg]
|
||||||
|
let byte = _.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' })
|
||||||
|
debug.L1(`writing mcp chip config ${setting.val}`)
|
||||||
|
await this.write(chip_config.cmd, byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pin configurations should already be set before calling
|
||||||
|
async writePinsCfg() {
|
||||||
|
debug.L1('writing mcp pins config')
|
||||||
|
for (let port in this.ports) {
|
||||||
|
for (let setting in registers.pin_config) {
|
||||||
|
let reg = registers.pin_config[setting]
|
||||||
|
// TODO 0x10 should be based on chip config
|
||||||
|
let byte = 0
|
||||||
|
for (let pin of this.ports[port].pins) {
|
||||||
|
byte += pin.address * pin.cfg[setting]
|
||||||
|
debug.L3(`port: ${ port } pin: ${pin.id} setting: ${ setting } reg: ${ reg } byte: ${ byte }`)
|
||||||
|
}
|
||||||
|
await this.write(portReg(reg, port), byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug.L1('done writing mcp pins config')
|
||||||
|
} // end writePinsCfg
|
||||||
|
|
||||||
|
async readPort(port, opts = {}) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
opts = port ? port : {}
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
let cmd = opts.cmd ? opts.cmd : 'gpio'
|
||||||
|
let result = await this.read(portReg(registers.pin_cmd[cmd], port))
|
||||||
|
debug.L2('read prev ', this.ports[port].state.toFmtPrev('ARY'))
|
||||||
|
debug.L2('read result', _.byteFormat(result, { in: 'DEC', out: 'ARY' }))
|
||||||
|
debug.L2('read state ', this.ports[port].state.toFmt('ARY'))
|
||||||
|
// if port pins changed without a write then update state
|
||||||
|
if (_.bitChanges(_.byteFormat(result, { in: 'DEC', out: 'ARY' }), this.ports[port].state.toFmt('ARY'))) {
|
||||||
|
this.ports[port].state.value = result
|
||||||
|
}
|
||||||
|
return opts.format ? this.ports[port].state.toFmt(opts.format) : result
|
||||||
|
}
|
||||||
|
|
||||||
|
async readPin(pin, port, opts = {}) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
opts = port ? port : {}
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
await this.readPort(port, opts)
|
||||||
|
// TODO return just true or false not the decimal of pin - will need new version on npm
|
||||||
|
return this.ports[port].state.bwOp(Math.pow(2, pin - 1), 'check') ? true : false
|
||||||
|
}
|
||||||
|
|
||||||
|
async writePort(byte, op, port = 'A') {
|
||||||
|
// byte MUST be a decimal
|
||||||
|
debug.L2(`port:${port}, op:${op}, current pins state\n ${this.ports[port].state.toFmt('PLC') }`)
|
||||||
|
debug.L2(`byte passed \n [${ _.byteFormat(byte, { in: 'DEC', out: 'PLC'})}]:${byte}`)
|
||||||
|
if (op !== 'force') {
|
||||||
|
byte = this.ports[port].state.bwOp(byte, op)
|
||||||
|
}
|
||||||
|
debug.L2(`byte to write\n [${ _.byteFormat(byte, { in: 'DEC', out: 'PLC' })}]:${byte}\n=======`)
|
||||||
|
await this.write(portReg(registers.pin_cmd.gpio, port), byte)
|
||||||
|
//update to the saved state
|
||||||
|
this.ports[port].state.value = byte
|
||||||
|
}
|
||||||
|
|
||||||
|
async pinsOn(pins, port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
if (format) { pins = _.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'on', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async allOn(port = 'A') {
|
||||||
|
let pins = 255
|
||||||
|
await this.writePort(pins, 'force', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async pinsOff(pins, port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
if (format) { pins = _.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'off', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async allOff(port = 'A') {
|
||||||
|
let pins = 0
|
||||||
|
await this.writePort(pins, 'force', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggle(pins, port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
if (format) { pins = _.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'toggle', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async allToggle(port = 'A') {
|
||||||
|
let pins = 255
|
||||||
|
await this.writePort(pins, 'toggle', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async force(pins, port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
if (format) { pins = _.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'force', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end 23008
|
||||||
|
|
||||||
|
class MCP23017 extends MCP23008 {
|
||||||
|
constructor(busObj, i2cAddress, opts = {}) {
|
||||||
|
super(busObj, i2cAddress, opts)
|
||||||
|
// add a second port
|
||||||
|
opts.portID = 'B'
|
||||||
|
opts.pids = opts.pidsB
|
||||||
|
this.ports.B = new Port(opts)
|
||||||
|
this.ports.B.state = new _.Byte(opts.stateB)
|
||||||
|
this.ports.B.interrupt = opts.interruptB ? opts.interruptB : opts.interrupt
|
||||||
|
}
|
||||||
|
|
||||||
|
pin(id, port) {
|
||||||
|
if (!port) {
|
||||||
|
return this.ports.A.pin(id) ? this.ports.A.pin(id) : this.ports.B.pin(id)
|
||||||
|
}
|
||||||
|
return this.ports[port].pin(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pid(num, port) {
|
||||||
|
console.log('pin for pid',this.ports[port].pins[num - 1])
|
||||||
|
return this.ports[port].pins[num - 1].id
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end MCP23017 Class
|
||||||
|
|
||||||
|
// EXPORTS
|
||||||
|
module.exports = {
|
||||||
|
MCP23008,
|
||||||
|
MCP23017,
|
||||||
|
pinConfigs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local Functions and Settings=============================
|
||||||
|
|
||||||
|
function portReg(reg, port) {
|
||||||
|
// TODO check chip configuartion to know what to add for port B. CUrrenly assume IOCON=1
|
||||||
|
// index 0,1 ==== 'A','B'
|
||||||
|
if ((port === 'B') || (port === 1)) { return reg += 0x10 } else { return reg }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
|
||||||
|
* or see MCP23017.pdf and MCP 23008.pdf in /docs
|
||||||
|
* see table 1.5 and details in sections 1.6.x following
|
||||||
|
* !!! for 23017 MUST initialize with bit 7 "BANK" of IOCON = 1 for the addresses below
|
||||||
|
* then for all registers add 16 (0x10) to each reg address to talk to PortB pins
|
||||||
|
* this will make reg addresses be equilvant for 23008 and PortA of 23017
|
||||||
|
* reg addresses in the config objects are all in Hexidecminal
|
||||||
|
*/
|
||||||
|
// Chip Configuration to be used with Register See Page 18 of 23017 doc
|
||||||
|
let chip_config = {
|
||||||
|
// byte: ['NULL','INTPOL','ODR','HAEN','DISSLW','SEQOP','MIRROR','BANK'] // see page 18 of 23017 datasheet for 8 setting details
|
||||||
|
cmd: 0x0A, // IOCON.BANK=0 (msb) at powerup so need to use 0x0A, if set to 1 then use
|
||||||
|
default: {
|
||||||
|
val: '10100010', // Split Banks port A + 0x10 = Port B,(ignored by 23008), Sequential operation disabled, active high=pulldown
|
||||||
|
fmt: 'STR'
|
||||||
|
},
|
||||||
|
oneint: {
|
||||||
|
val: '11100100', // same as default execpt int pins connected
|
||||||
|
fmt: 'STR'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let registers = {
|
||||||
|
pin_config: {
|
||||||
|
dir: 0,
|
||||||
|
ivrt: 1,
|
||||||
|
pullup: 6,
|
||||||
|
intr: 2,
|
||||||
|
usedef: 4,
|
||||||
|
defval: 3,
|
||||||
|
},
|
||||||
|
pin_cmd: {
|
||||||
|
intf: 7, // readonly
|
||||||
|
intcap: 8, // readonly
|
||||||
|
gpio: 9, // read/write
|
||||||
|
olat: 10 // read only
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
// import Base from '@uci/base'
|
||||||
|
import Base from '../../uci-base/src/base'
|
||||||
|
import pin from './pin'
|
||||||
|
import _ from '@uci/utils/src/byte'
|
||||||
|
|
||||||
|
import logger from '../../uci-logger/src/logger'
|
||||||
|
let log = {}
|
||||||
|
const LOG_OPTS = {
|
||||||
|
repo:'uci-mcp',
|
||||||
|
npm:'@uci/mcp',
|
||||||
|
file:'src/mcp230xx-packet.mjs',
|
||||||
|
class:'MCP230XX',
|
||||||
|
id:this.id,
|
||||||
|
instance_created:new Date().getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MCP230XX extends Base {
|
||||||
|
constructor(opts) {
|
||||||
|
log = logger.child(LOG_OPTS)
|
||||||
|
if (opts.bus) {
|
||||||
|
if (opts.bus.host) {
|
||||||
|
opts.bus.socket = 'bus#c>t'
|
||||||
|
opts.bus.port = opts.bus.port || 1776
|
||||||
|
}
|
||||||
|
if (opts.bus.path) opts.bus.socket = 'bus#c>n'
|
||||||
|
} else {
|
||||||
|
opts.bus = { path : (process.env.SOCKETS_DIR || __dirname) + '/i2c-bus.sock' }
|
||||||
|
opts.bus.socket = 'bus#c>n'
|
||||||
|
}
|
||||||
|
opts.nmcp = opts.nmcp || {path: (process.env.SOCKETS_DIR || __dirname) + '/mcp.sock'}
|
||||||
|
opts.sockets = 'nmcp#s>n,tmcp#s>t,'+ opts.bus.socket
|
||||||
|
console.log(opts)
|
||||||
|
super(opts)
|
||||||
|
if (!opts.address) log.fatal({opts:opts},'no i2c bus address supplied' )
|
||||||
|
this.address = opts.address
|
||||||
|
this.pin = pin
|
||||||
|
this.busSend = this.busSend.bind(this)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(){
|
||||||
|
await super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
async busSend(packet) {
|
||||||
|
return await this.socket.bus.send(packet)}
|
||||||
|
|
||||||
|
reply (packet) {
|
||||||
|
console.log('in bus reply', packet)
|
||||||
|
// this.emit('bus', packet)
|
||||||
|
this.emit(packet.id, packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setBusListener(packet) {
|
||||||
|
// // this.on(packet.cmd+Math.random().toString().slice(1))
|
||||||
|
// }
|
||||||
|
|
||||||
|
} // end of MCP230XX Class
|
|
@ -0,0 +1,56 @@
|
||||||
|
// All the pin functions for corresponding packet cmd:'pin'
|
||||||
|
// every function should return a packet ready to send to the i2c-bus socket
|
||||||
|
// export {pin}
|
||||||
|
|
||||||
|
const pin = {
|
||||||
|
cfg: function(packet){
|
||||||
|
return new Promise( async (resolve) => {
|
||||||
|
console.log(packet)
|
||||||
|
return resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
test: function(packet){
|
||||||
|
return new Promise( async (resolve, reject) => {
|
||||||
|
setTimeout(() => {reject({error:'no response from bus in 2000ms'})},2000)
|
||||||
|
let id = Math.random().toString().slice(2)
|
||||||
|
let buspacket = {cmd:'scan', id:id}
|
||||||
|
console.log('packet for bus', buspacket)
|
||||||
|
this.busSend(buspacket)
|
||||||
|
this.on(buspacket.id,function(busreply){
|
||||||
|
console.log('reply emitted',busreply)
|
||||||
|
this.removeAllListeners(busreply.id)
|
||||||
|
let res = { cmd:'reply', _req:packet, _reqBus:buspacket}
|
||||||
|
if (busreply.response.indexOf(parseInt(this.address,16))!=-1) res.ready = true
|
||||||
|
res.address = this.address
|
||||||
|
console.log(res)
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
status: function(packet){
|
||||||
|
return new Promise( async (resolve) => {
|
||||||
|
console.log(packet)
|
||||||
|
return resolve()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// // state is equivalent to read
|
||||||
|
// status: packet => {
|
||||||
|
// },
|
||||||
|
// // threse three only for output pins
|
||||||
|
// state : {
|
||||||
|
// on: packet => {
|
||||||
|
// },
|
||||||
|
// off: packet => {
|
||||||
|
// },
|
||||||
|
// toggle: packet => {
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// // will create packet to determin pin caused interrupt, packet will come from interrupt module
|
||||||
|
// interrupt: {
|
||||||
|
// find: packet =>{},
|
||||||
|
// report: packet=>{} // come here after determining which pin to report to requester
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default pin
|
|
@ -0,0 +1,80 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const expect = require('chai').expect,
|
||||||
|
_u = require('@uci/utils'),
|
||||||
|
MCP = require('../lib/mcp23008-17')
|
||||||
|
|
||||||
|
const bus = {}
|
||||||
|
|
||||||
|
const config_sets = {
|
||||||
|
output: {
|
||||||
|
dir: 0, // 0 output,1 input
|
||||||
|
ivrt: 0,
|
||||||
|
pullup: 0,
|
||||||
|
intr: 0, // if intr = 0 usedef,deval not used
|
||||||
|
usedef: 0, // if usedef = 0 defval not used
|
||||||
|
defval: 0
|
||||||
|
},
|
||||||
|
toggle_switch: {
|
||||||
|
dir: 1, // 0 output,1 input
|
||||||
|
ivrt: 1, // for reading let 1 be zero and vice versa
|
||||||
|
pullup: 1,
|
||||||
|
intr: 1, // if intr = 0 usedef,deval not used
|
||||||
|
usedef: 0, // if usedef = 0 defval not used
|
||||||
|
defval: 0
|
||||||
|
},
|
||||||
|
momentary_switch: {
|
||||||
|
dir: 1, // 0 output,1 input
|
||||||
|
ivrt: 1, // for reading let 1 be zero and vice versa
|
||||||
|
pullup: 1,
|
||||||
|
intr: 1, // if intr = 0 usedef,deval not used
|
||||||
|
usedef: 1, // if usedef = 0 defval not used
|
||||||
|
defval: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(bus1)
|
||||||
|
// bus1.scan((devs)=>{console.log('devices: ', devs)})
|
||||||
|
//bus1.scan().then(results=>console.log(results))
|
||||||
|
|
||||||
|
describe('I2C Device Classes - ', function () {
|
||||||
|
|
||||||
|
let mcp17 = new MCP.MCP23017(bus, 0x20, {
|
||||||
|
pin_cfg_default: 'momentary_switch',
|
||||||
|
name: 'switches 1-16'
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('MCP23017 Class - ', function () {
|
||||||
|
|
||||||
|
it('can set and get a single pin config on both ports', function () {
|
||||||
|
expect(mcp17.pin(1).cfg, 'pin configs getter failed').to.deep.equal(config_sets.momentary_switch)
|
||||||
|
expect(mcp17.pin(8).cfg.dir, 'pin config getter failed').to.equal(1)
|
||||||
|
mcp17.pin(8).cfg.dir = 0
|
||||||
|
expect(mcp17.pin(8).cfg.dir, 'pin address setter failed').to.equal(0)
|
||||||
|
expect(mcp17.pin(8, 'B').cfg.dir, 'pin address getter port B failed').to.equal(1)
|
||||||
|
mcp17.pin(8, 'B').cfg.dir = 0
|
||||||
|
expect(mcp17.pin(8, 'B').config.dir, 'pin address setter failed').to.equal(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
let mcp8 = new MCP.MCP23008(bus, 0x21, {
|
||||||
|
pin_cfg_default: 'toggle_switch',
|
||||||
|
name: 'test 1-8'
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('MCP23008 Class - ', function () {
|
||||||
|
|
||||||
|
it('can set and get a single pin config', function () {
|
||||||
|
expect(mcp8.pin(1).cfg, 'pin configs getter failed').to.deep.equal(config_sets.toggle_switch)
|
||||||
|
expect(mcp8.pin(8).cfg.dir, 'pin address getter failed').to.equal(1)
|
||||||
|
expect(mcp8.pin(8).cfg.ivrt, 'pin address getter failed').to.equal(1)
|
||||||
|
expect(mcp8.pin(8).cfg.usedef, 'pin address getter failed').to.equal(0)
|
||||||
|
mcp8.pin(8).cfg.dir = 0
|
||||||
|
expect(mcp8.pin(8).cfg.dir, 'pin address setter failed').to.equal(0)
|
||||||
|
expect(mcp8.pin(8).cfg.ivrt, 'pin address getter failed').to.equal(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
Loading…
Reference in New Issue