parent
a0eb28fdc0
commit
1497491d9c
|
@ -1,3 +1,4 @@
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/coverage/
|
/coverage/
|
||||||
/syncd/
|
/syncd/
|
||||||
|
*.lock
|
||||||
|
|
|
@ -2,3 +2,4 @@ tests/
|
||||||
test/
|
test/
|
||||||
*.test.js
|
*.test.js
|
||||||
testing/
|
testing/
|
||||||
|
examples
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
// to try this demo
|
|
||||||
// npm install @uci/interrupt
|
|
||||||
// Connect 5V MCP interrupt pin via 3.3 V logic level!!!!! converter to a gpio pin
|
|
||||||
// Set your SETTINGS below
|
|
||||||
// npm run inter
|
|
||||||
|
|
||||||
const Bus = require('@uci/i2c').Bus,
|
|
||||||
MCP = require('../src/mcp23008-17'),
|
|
||||||
// use this require when using your own code
|
|
||||||
// MCP = require('@uci/mcp')
|
|
||||||
Interrupt = require('@uci/interrupt')
|
|
||||||
|
|
||||||
let bus = new Bus()
|
|
||||||
|
|
||||||
// SETTINGS
|
|
||||||
let ADDR = 0x20
|
|
||||||
let CHIP = 'MCP23017'
|
|
||||||
let MS = 300 // so humans can watch the light otherwise set to zero
|
|
||||||
let pinA = 12
|
|
||||||
let pinB = 16
|
|
||||||
|
|
||||||
let id = `${CHIP} at I2C bus address of 0x${ADDR.toString(16)}`
|
|
||||||
|
|
||||||
let mcp = new MCP[CHIP](bus, ADDR, {
|
|
||||||
pin_cfg_default: 'toggle_switch',
|
|
||||||
id: id,
|
|
||||||
interruptA: new Interrupt(pinA, ihandler),
|
|
||||||
interruptB: new Interrupt(pinB, ihandler),
|
|
||||||
stateA: 128,
|
|
||||||
pidsA: ['sw1', 'sw2', 'sw3', 'sw4', 'sw5', 'sw6', 'sw7', 'sw8'],
|
|
||||||
pidsB: ['sw9', 'sw10', 'sw11', 'sw12', 'sw13', 'sw14', 'sw15', 'sw16']
|
|
||||||
}); // must have ; for async immediate function following
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
|
|
||||||
await mcp.init()
|
|
||||||
await mcp.start()
|
|
||||||
|
|
||||||
mcp.on('fired', (data) => {
|
|
||||||
console.log(`bank event 'fired' data => ${data.bank} on port ${data.port} pin# ${data.pin} pid ${data.pid}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
})()
|
|
||||||
|
|
||||||
//=================================//
|
|
||||||
|
|
||||||
async function ihandler(port) {
|
|
||||||
let pin = await this.interruptPin(port, 'PLC')
|
|
||||||
await this.interruptReset(port)
|
|
||||||
let data = { bank: this.id, port: port, pin: pin, pid: this.pid(pin, port) }
|
|
||||||
// console.log('data in handler', data)
|
|
||||||
return data
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
const Bus = require('@uci/i2c').Bus,
|
|
||||||
MCP = require('../src/mcp23008-17'),
|
|
||||||
// use this require when using your own code
|
|
||||||
// MCP = require('@uci/mcp')
|
|
||||||
pause = require('@uci/utils').pPause
|
|
||||||
|
|
||||||
let bus = new Bus()
|
|
||||||
|
|
||||||
let ADDR = 0x27
|
|
||||||
let CHIP = 'MCP23017'
|
|
||||||
let MS = 300 // so humans can watch the light otherwise set to zero
|
|
||||||
let PORT = 'B'
|
|
||||||
|
|
||||||
let mcp = new MCP[CHIP](bus, ADDR);
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
|
|
||||||
await mcp.init()
|
|
||||||
await mcp.allOff(PORT) // start clean
|
|
||||||
console.log('all pins off')
|
|
||||||
await pause(MS)
|
|
||||||
|
|
||||||
let pins = [1, 7, 8]
|
|
||||||
await mcp.pinsOn(pins, PORT, 'PLC')
|
|
||||||
let result = await mcp.readPort(PORT, { format: 'PLC' })
|
|
||||||
console.log(`${pins} on = current state: ${result.sort()}`)
|
|
||||||
await pause(MS)
|
|
||||||
|
|
||||||
pins = [2, 1, 6]
|
|
||||||
await mcp.toggle(pins, PORT, 'PLC')
|
|
||||||
result = await mcp.readPort(PORT, { format: 'PLC' })
|
|
||||||
console.log(`${pins} toggle = current state: ${result.sort()}`)
|
|
||||||
await pause(MS)
|
|
||||||
|
|
||||||
pins = [2, 1, 7]
|
|
||||||
await mcp.pinsOff(pins, PORT, 'PLC')
|
|
||||||
result = await mcp.readPort(PORT, { format: 'PLC' })
|
|
||||||
console.log(`${pins} off = current state: ${result.sort()}`)
|
|
||||||
await pause(MS)
|
|
||||||
|
|
||||||
let pin = 7
|
|
||||||
result = await mcp.readPin(pin, PORT) ? 'on' : 'off'
|
|
||||||
console.log(`Pin ${pin} is ${result}`)
|
|
||||||
|
|
||||||
pin = 6
|
|
||||||
result = await mcp.readPin(pin, PORT) ? 'on' : 'off'
|
|
||||||
console.log(`Pin ${pin} is ${result}`)
|
|
||||||
|
|
||||||
console.log('all pins off')
|
|
||||||
await mcp.allOff(PORT) // clear port after each test
|
|
||||||
|
|
||||||
})()
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@uci/mcp",
|
"name": "@uci/mcp",
|
||||||
"main": "src",
|
"main": "src",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"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": {
|
||||||
"relays": "node -r esm examples/relays",
|
"relays": "node -r esm examples/relays",
|
||||||
|
@ -28,16 +28,13 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/uCOMmandIt/uci-mcp#readme",
|
"homepage": "https://github.com/uCOMmandIt/uci-mcp#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@uci/i2c-device": "^0.1.3",
|
"@uci/i2c-device": "^0.1.4",
|
||||||
"@uci/interrupt": "^0.1.4",
|
"@uci/logger": "0.0.3",
|
||||||
"@uci/logger": "^0.0.2",
|
|
||||||
"@uci/mqtt": "^0.0.3",
|
|
||||||
"@uci/utils": "^0.1.1"
|
"@uci/utils": "^0.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.1.2",
|
"chai": "^4.1.2",
|
||||||
"codecov": "^3.0.0",
|
"codecov": "^3.0.0",
|
||||||
"debug": "^3.1.0",
|
|
||||||
"esm": "^3.0.22",
|
"esm": "^3.0.22",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"mocha": "^5.0.1",
|
"mocha": "^5.0.1",
|
||||||
|
|
|
@ -1,304 +0,0 @@
|
||||||
'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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const _ = require('@uci/utils')
|
|
||||||
|
|
||||||
class Pin {
|
|
||||||
|
|
||||||
constructor(id, address, opts = {}) {
|
|
||||||
// at a minimum a byte address is required
|
|
||||||
this.address = address
|
|
||||||
// a pin id MUST be supplied in opts 1 to 8
|
|
||||||
this.id = id
|
|
||||||
// a custom pin configuration can be passed or choosen from one of the sets, if neither than the default output config is chosen
|
|
||||||
// TODO allow custom pin configurations based on passed opts so individual pins can be configured differently
|
|
||||||
if (opts.pin_cfg_default) {
|
|
||||||
if (_.keyExists(config_sets, opts.pin_cfg_default)) {
|
|
||||||
this.config = _.clone(config_sets[opts.pin_cfg_default])
|
|
||||||
} else {
|
|
||||||
console.log(`WARNING config set ${opts.pin_cfg_default} not found using default output set`)
|
|
||||||
this.config = _.clone(config_sets.output)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.config = _.clone(config_sets.output)
|
|
||||||
}
|
|
||||||
// after setting a default overwrite part or all of pin config with custom
|
|
||||||
if (opts.pinConfig) {
|
|
||||||
this.config = Object.assign(this.config, opts.pinConfig)
|
|
||||||
}
|
|
||||||
// this.cfgSet = false // set to true when for sure the configuration has been written, changed to false when config is changed.
|
|
||||||
}
|
|
||||||
|
|
||||||
//getters and setters
|
|
||||||
get adr() {
|
|
||||||
return this.address
|
|
||||||
}
|
|
||||||
|
|
||||||
get pid() { return this.id }
|
|
||||||
|
|
||||||
set pid(pid) { this.id = pid }
|
|
||||||
|
|
||||||
// config getters and setters
|
|
||||||
get cfg() {
|
|
||||||
return this.config
|
|
||||||
}
|
|
||||||
set cfg(config) {
|
|
||||||
this.config = _.merge(this.config, config) // this merges partial changes
|
|
||||||
// write the config here.
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
console.log(`\n=====Pin ${this.id} =====\n Decimal Address ${this.address}`)
|
|
||||||
console.log('Conifguration: ', this.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End GPIO Pin
|
|
||||||
|
|
||||||
//======================
|
|
||||||
|
|
||||||
// A port of 8 GPIO pins
|
|
||||||
class Port {
|
|
||||||
|
|
||||||
constructor(opts = {}) {
|
|
||||||
|
|
||||||
this.id = opts.portID ? opts.portID : ''
|
|
||||||
this.desc = opts.portDesc ? opts.portDesc : ''
|
|
||||||
// Create group of 8 pins for port
|
|
||||||
this.pins = new Array(8)
|
|
||||||
let pid = ''
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
pid = opts.pids ? opts.pids[i] : i + 1
|
|
||||||
this.pins[i] = new Pin(pid, Math.pow(2, i), opts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return handle to a port's pin from id
|
|
||||||
pin(id) {
|
|
||||||
for (let pins of this.pins) {
|
|
||||||
if (pin.id === id) {
|
|
||||||
return pin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// return pin's id on a port from address
|
|
||||||
pid(address) {
|
|
||||||
return Math.log(address) / Math.log(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end GPIO Port CLass
|
|
||||||
|
|
||||||
//====================
|
|
||||||
|
|
||||||
// return list of all pin configs, handle to particular config or adding of custom pin configuration at runtime
|
|
||||||
function configs(cfg) {
|
|
||||||
if (_.isString(cfg)) {
|
|
||||||
if (cfg === 'list') {
|
|
||||||
return Object.keys(config_sets)
|
|
||||||
}
|
|
||||||
if (_.keyExists(config_sets, cfg)) {
|
|
||||||
return config_sets[cfg]
|
|
||||||
}
|
|
||||||
return 'configuration no found'
|
|
||||||
}
|
|
||||||
_.merge(config_sets, cfg)
|
|
||||||
// console.log(config_sets)
|
|
||||||
return `pin configuration ${Object.keys(cfg)} added to configuration set`
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
Port,
|
|
||||||
Pin,
|
|
||||||
configs
|
|
||||||
}
|
|
||||||
|
|
||||||
let 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const expect = require('chai').expect,
|
|
||||||
gpio = require('../lib/gpio')
|
|
||||||
|
|
||||||
let pin = new gpio.Pin(128)
|
|
||||||
|
|
||||||
describe('GPIO Pin Class - ', function () {
|
|
||||||
|
|
||||||
it('Verify getter and setter ', function () {
|
|
||||||
expect(pin.cfg, 'config getter failed').to.deep.equal(gpio.configs('output'))
|
|
||||||
expect(pin.cfg.intr, 'config get subkeys failed').to.equal(0)
|
|
||||||
|
|
||||||
pin.cfg = gpio.configs('toggle_switch')
|
|
||||||
expect(pin.cfg, 'config setter failed').to.deep.equal(gpio.configs('toggle_switch'))
|
|
||||||
expect(pin.adr.value, 'pin address getter failed').to.equal(128)
|
|
||||||
expect(pin.adr.fmt, 'pin address format getter failed').to.equal('DEC')
|
|
||||||
expect(pin.id, 'pin id default from address failed').to.equal(8)
|
|
||||||
pin.adr = {
|
|
||||||
'val': 20,
|
|
||||||
'fmt': 'HEX'
|
|
||||||
}
|
|
||||||
expect(pin.adr.value, 'pin address setter failed').to.equal(20)
|
|
||||||
expect(pin.adr.fmt, 'pin address format setter failed').to.equal('HEX')
|
|
||||||
pin.id = 2
|
|
||||||
expect(pin.id, 'pin id setter failed').to.equal(2)
|
|
||||||
pin.adr = 32
|
|
||||||
expect(pin.adr.value, 'pin address setter failed').to.equal(32)
|
|
||||||
expect(pin.adr.fmt, 'pin address format setter failed').to.equal('DEC')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should merge partial config change', function () {
|
|
||||||
pin.cfg = gpio.configs('output')
|
|
||||||
pin.cfg = { dir: 15 }
|
|
||||||
let merged = { dir: 15, ivrt: 0, pullup: 0, intr: 0, usedef: 0, defval: 0 }
|
|
||||||
expect(pin.cfg, 'single config value change failed').to.deep.equal(merged)
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO waiting on new clone function
|
|
||||||
// it('should clone a new Pin with change of address', function () {
|
|
||||||
// expect(newPin.adr.val, "clone pin failed").to.equal(4)
|
|
||||||
// expect(newPin.cfg.dir, "clone pin failed").to.equal(15)
|
|
||||||
// })
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
let port = new gpio.Port({ portID: 'A1' })
|
|
||||||
|
|
||||||
describe('GPIO Port Class - ', function () {
|
|
||||||
|
|
||||||
it('should set the pin ids and addresses by default', function () {
|
|
||||||
expect(port.pin(7).id, 'a pin\'s id failed').to.equal(7)
|
|
||||||
expect(port.pin(7).adr.value, 'id and address don\'t match').to.equal(64)
|
|
||||||
})
|
|
||||||
|
|
||||||
let port2 = new gpio.Port({ reverse: true })
|
|
||||||
|
|
||||||
it('reversing pin number order should work', function () {
|
|
||||||
expect(port2.pin(2).adr.value, 'reversing pin numbers failed').to.equal(64)
|
|
||||||
})
|
|
||||||
|
|
||||||
//TODO add a pin map for the port so pins could be arranged in any order
|
|
||||||
})
|
|
Loading…
Reference in New Issue