added port read and write methods to mcp class
parent
832a507204
commit
0fb62e2db1
|
@ -1,256 +1,226 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
const Device = require('uci-dev').Device,
|
const Device = require('uci-dev').Device,
|
||||||
Port = require('uci-gpio').Port,
|
Port = require('uci-gpio').Port,
|
||||||
_u = require('uci-utils'),
|
_u = require('uci-utils'),
|
||||||
pause = _u.pPause
|
pause = _u.pPause,
|
||||||
|
aseq = _u.aSeq
|
||||||
|
|
||||||
class MCP23008 extends Device {
|
class MCP23008 extends Device {
|
||||||
constructor(busObj, i2cAddress, opts = {}) {
|
constructor(busObj, i2cAddress, opts = {}) {
|
||||||
super(busObj, i2cAddress, opts)
|
super(busObj, i2cAddress, opts)
|
||||||
// opts could pass in array of custom pin config, or single for all, or anything
|
// opts could include options passed on to ports and pin including custom pin config, pin ids...see gpio.js
|
||||||
// this.registers = registers // load in register database
|
this.chip_config = opts.chip_config // TODO allow opts.chip_config to be a byte instead of a string pointer
|
||||||
this.ports = {}
|
this.ports = {}
|
||||||
opts.portID = 'A'
|
opts.portID = 'A'
|
||||||
opts.pids = opts.pids ? opts.pids : opts.pidsA
|
opts.pids = opts.pids ? opts.pids : opts.pidsA
|
||||||
this.ports.A = new Port(opts)
|
this.ports.A = new Port(opts)
|
||||||
this.chip_config = opts.chip_config // TODO allow opts.chip_config to be a byte instead of a string pointer
|
this.ports.A.state = new _u.Byte(opts.stateA)
|
||||||
this.ports.A.interrupt = opts.interruptA ? opts.interruptA : opts.interrupt
|
this.ports.A.interrupt = opts.interruptA ? opts.interruptA : opts.interrupt
|
||||||
// if (this.ports.A.interrupt) { this.ports.A.interrupt.port = 'A' }
|
} // end constructor
|
||||||
|
|
||||||
} // end constructor
|
async init() {
|
||||||
|
// console.log(`begin initialize ${this.id}`)
|
||||||
|
await this.writeChipCfg(this.chip_config) // chip settings
|
||||||
|
await this.writePinsCfg()
|
||||||
|
for (let port in this.ports) {
|
||||||
|
console.log(`init port ${port} state`)
|
||||||
|
await this.writePort(this.state(port), 'force', port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async init() {
|
async start() {
|
||||||
// console.log('chip configuration', chip_config.cmd, chipSetByte())
|
// console.log(`starting ${ this.id }`)
|
||||||
// console.log(`begin initialize ${this.id}`)
|
for (let port in this.ports) {
|
||||||
await this.writeChipCfg(this.chip_config)
|
// if there are interrupts being used then start them and listeners
|
||||||
// let jobs = [this.writeChipCfg(this.chip_config)] // configure chip
|
if (this.inter(port)) {
|
||||||
// for (let port in this.ports) {
|
await this.interruptReset(port)
|
||||||
// if (this.inter(port)) {
|
await this.inter(port).start()
|
||||||
// console.log(`initialize interrupt port ${port}`)
|
// bind handler to the chip so handler can read/write to chip/bank when interrupt is emitted
|
||||||
// jobs.push(
|
let ihandler = this.inter(port).handler.bind(this)
|
||||||
// this.inter(port).init()
|
// inside the listener `this` is the interrupt not the chip/bank
|
||||||
// .then(sbci => {
|
this.inter(port).on('fired', function () {
|
||||||
// this.inter(port).sbci = sbci
|
console.log(`interrupt from ${this.pin_number}`)
|
||||||
// console.log(`sbci ${this.inter(port).sbci}`)
|
ihandler(port)
|
||||||
// })
|
})
|
||||||
// )
|
}
|
||||||
// // sbci = single board computer interrrupt to distinguish it from interrupt on MCP
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// jobs.push(this.writePinsCfg())
|
|
||||||
await this.writePinsCfg()
|
|
||||||
|
|
||||||
// return _u.pSeries(jobs)
|
async interruptReset(port = 'A') {
|
||||||
}
|
await this.read(portReg(0x08, port))
|
||||||
|
await pause(100) // give enough time for mcp to reset its interupt
|
||||||
|
// console.log(`interrupt reset on ${this.id} port ${port}`)
|
||||||
|
}
|
||||||
|
|
||||||
async start() {
|
pin(id) { return this.ports.A.pin(id) } // get a reference to a particular pin's object
|
||||||
// console.log(`starting ${ this.id }`)
|
|
||||||
for (let port in this.ports) {
|
|
||||||
// if there are interrupts being used then start them and listeners
|
|
||||||
if (this.inter(port)) {
|
|
||||||
await this.interruptReset(port)
|
|
||||||
await this.inter(port).start()
|
|
||||||
// bind handler to the chip to handler can read/write to chip/bank when interrupt is emitted
|
|
||||||
let ihandler = this.inter(port).handler.bind(this)
|
|
||||||
// inside the listener `this` is the interrupt not the chip/bank
|
|
||||||
this.inter(port).on('fired', function () {
|
|
||||||
console.log(`interrupt from ${this.pin_number}`)
|
|
||||||
ihandler(port)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async interruptReset(port = 'A') {
|
pid(address) { return this.ports.A.pid(address) } // return pin id for a given address on a port
|
||||||
await this.read(portReg(0x08, port))
|
|
||||||
await pause(300) // give enough time for mcp to reset its interupt
|
|
||||||
console.log(`interrupt reset on ${this.id} port ${port}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start() {
|
portByPin(id) {
|
||||||
// let starts = []
|
if (this.ports.A.pin(id)) { return 'A' }
|
||||||
// for (let port in this.ports) {
|
return false
|
||||||
// if (this.inter(port)) {
|
}
|
||||||
// starts.push(
|
|
||||||
// this.read(portReg(0x08, port))
|
|
||||||
// .then(_u.pDelay(100)) // give enough time for mcp to reset its interupt
|
|
||||||
// .then(() => {
|
|
||||||
// return this.inter(port).start()
|
|
||||||
// .then(resp => {
|
|
||||||
// console.log(resp)
|
|
||||||
// // this.inter(port).on('fired', () => {
|
|
||||||
// // console.log(`
|
|
||||||
//interrupt port $ { port } hook me\ n $ { relays }
|
|
||||||
// `)
|
|
||||||
// // // hook.bind(this)(port)
|
|
||||||
// return Promise.resolve()
|
|
||||||
// })
|
|
||||||
// return Promise.resolve(`
|
|
||||||
//interrupt port $ { port } started `)
|
|
||||||
// })
|
|
||||||
// .catch(err => console.log("error:", err))
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return Promise.all(starts)
|
|
||||||
// }
|
|
||||||
|
|
||||||
portByInterPin(pin) {
|
state(port = 'A') {
|
||||||
return 'A'
|
return this.ports[port].state.value
|
||||||
}
|
}
|
||||||
|
|
||||||
pin(id) { return this.ports.A.pin(id) } // get a reference to a particular pin's object
|
// get a handle to the ports interrupt
|
||||||
|
inter(port = 'A') {
|
||||||
|
return this.ports[port].interrupt
|
||||||
|
}
|
||||||
|
|
||||||
pid(address) { return this.ports.A.pid(address) } // return pin id for a given address on a port
|
writeChipCfg(cfg = 'default') {
|
||||||
|
// console.log(`writing mcp chip config ${this.id}`)
|
||||||
|
let setting = chip_config[cfg]
|
||||||
|
let byte = _u.byteFormat(setting.val, { in: setting.fmt,
|
||||||
|
out: 'DEC'
|
||||||
|
})
|
||||||
|
return this.write(chip_config.cmd, byte)
|
||||||
|
.then(() => Promise.resolve(`mcp chip config: reg $ { chip_config.cmd } byte $ { byte } written `))
|
||||||
|
}
|
||||||
|
|
||||||
portByPin(id) {
|
// pin configurations should already be set before calling
|
||||||
if (this.ports.A.pin(id)) { return 'A' }
|
writePinsCfg() {
|
||||||
return false
|
// console.log(`writing mcp pins config ${this.id}`)
|
||||||
}
|
let jobs = [];
|
||||||
|
for (let port in this.ports) {
|
||||||
// get a handle to the ports interrupt
|
for (let setting in registers.pin_config) {
|
||||||
inter(port = 'A') {
|
let reg = registers.pin_config[setting]
|
||||||
return this.ports[port].interrupt
|
// TODO 0x10 should be based on chip config
|
||||||
}
|
let byte = 0;
|
||||||
|
let pins = this.ports[port].allPins
|
||||||
writeChipCfg(cfg = 'default') {
|
for (let i = 0; i < 8; i++) {
|
||||||
// console.log(`writing mcp chip config ${this.id}`)
|
let pin = pins[i]
|
||||||
let setting = chip_config[cfg]
|
byte += pin.address.toFmt('DEC') * pin.cfg[setting]
|
||||||
let byte = _u.byteFormat(setting.val, { in: setting.fmt,
|
}
|
||||||
out: 'DEC'
|
//console.log(`port $ { port } - setting $ { setting } - reg $ { reg } - byte $ { byte }`)
|
||||||
})
|
jobs.push(
|
||||||
return super.write(chip_config.cmd, byte)
|
this.write(portReg(reg, port), byte).then(() => Promise.resolve(`
|
||||||
.then(() => Promise.resolve(`mcp chip config: reg $ { chip_config.cmd } byte $ { byte } written `))
|
|
||||||
}
|
|
||||||
|
|
||||||
// pin configurations should already be set before calling
|
|
||||||
writePinsCfg() {
|
|
||||||
// console.log(`writing mcp pins config ${this.id}`)
|
|
||||||
let jobs = [];
|
|
||||||
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;
|
|
||||||
let pins = this.ports[port].allPins
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
let pin = pins[i]
|
|
||||||
byte += pin.address.toFmt('DEC') * pin.cfg[setting]
|
|
||||||
}
|
|
||||||
//console.log(`port $ { port } - setting $ { setting } - reg $ { reg } - byte $ { byte }`)
|
|
||||||
jobs.push(
|
|
||||||
super.write(portReg(reg, port), byte).then(() => Promise.resolve(`
|
|
||||||
config: wrote $ { byte } to register $ { reg } on port $ { port }
|
config: wrote $ { byte } to register $ { reg } on port $ { port }
|
||||||
`))
|
`))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _u.pSeries(jobs)
|
return _u.pSeries(jobs)
|
||||||
} // end writePinsCfg
|
} // end writePinsCfg
|
||||||
|
|
||||||
// reads all pins in all ports
|
// read(format = 'PLC') {
|
||||||
readPins(cmd = 'gpio', fmt) {
|
// return u_.byteFormat(this.cur, { in: this.format, out: format })
|
||||||
let jobs = []
|
// }
|
||||||
let reg = registers.pin_cmd[cmd]
|
|
||||||
for (let port in this.ports) {
|
|
||||||
jobs.push(() => super.read(portReg(reg, port)))
|
|
||||||
}
|
|
||||||
return _u.pSeries(jobs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pinRead(id, opts) {
|
async readPort(port, cmd = "gpio") {
|
||||||
let mcpdev = this;
|
if ('AB'.indexOf(port) === -1) {
|
||||||
return new Promise(function (resolve, reject) {
|
cmd = port ? port : "gpio"
|
||||||
let cmd = opts.cmd ? opts.cmd : 'gpio'
|
port = 'A'
|
||||||
let fmt = opts.fmt ? opts.fmt : { in: 'PLC', out: 'PLC' }
|
}
|
||||||
let reg = registers.pin_cmd[cmd]
|
let result = await this.read(portReg(registers.pin_cmd[cmd], port))
|
||||||
let gpio = mcpdev.pin(id)
|
this.ports[port].state.value = result
|
||||||
if (!gpio) {
|
return result
|
||||||
reject('no pin found for given id')
|
}
|
||||||
}
|
|
||||||
console.log('id of fired pin', id)
|
|
||||||
console.log('port of fired pin', mcpdev.portByPin(id))
|
|
||||||
return mcpdev.read(portReg(reg, mcpdev.portByPin(id))).then(resp => {
|
|
||||||
resp = _u.byteFormat(resp, { in: 'DEC',
|
|
||||||
out: 'ARY'
|
|
||||||
})
|
|
||||||
let addr = gpio.adr.toFmt('ARY')
|
|
||||||
// console.log(addr)
|
|
||||||
// console.log(resp)
|
|
||||||
resolve(_u.sum(_u.and(addr, resp))) // resolve 1 or 0
|
|
||||||
}).catch(err => reject(err)) // end Promise
|
|
||||||
}) // end promise
|
|
||||||
|
|
||||||
} // end pinRead
|
async writePort(byte, op, port = 'A') {
|
||||||
|
// byte MUST be a decimal
|
||||||
|
console.log(`current \n ${this.ports[port].state.toFmt('PLC')}`)
|
||||||
|
console.log(`byte passed ${op} \n ${_u.byteFormat(byte,{in: 'DEC', out:'PLC'})}`)
|
||||||
|
if (op !== 'force') {
|
||||||
|
byte = this.ports[port].state.bwOp(byte, op)
|
||||||
|
}
|
||||||
|
console.log("byte to write decimal \n", byte)
|
||||||
|
console.log(`byte to write \n ${_u.byteFormat(byte, { in: 'DEC', out: 'PLC' })}`)
|
||||||
|
|
||||||
pinWrite(id, opts) {
|
await this.write(portReg(registers.pin_cmd.gpio, port), byte)
|
||||||
let mcpdev = this;
|
//update the saved state
|
||||||
return new Promise(function (resolve, reject) {
|
this.ports[port].state.value = byte
|
||||||
let cmd = opts.cmd ? opts.cmd : 'gpio'
|
console.log("\n\n")
|
||||||
let reg = registers.pin_cmd[cmd]
|
}
|
||||||
let gpio = mcpdev.pin(id, opts.port)
|
|
||||||
if (!gpio) {
|
async on(pins, port, format) {
|
||||||
reject('no pin found for given id')
|
if ('AB'.indexOf(port) === -1) {
|
||||||
}
|
format = port
|
||||||
if (gpio.port === 'B') {
|
port = 'A'
|
||||||
reg = reg + 16
|
}
|
||||||
}
|
if (format) { pins = _u.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
// call device class read
|
await this.writePort(pins, 'on', port)
|
||||||
// console.log('port - reg', gpio.port, reg)
|
}
|
||||||
return mcpdev.read(reg).then(resp => {
|
|
||||||
resp = _u.byteFormat(resp, { in: 'DEC',
|
async allOn(port = 'A') {
|
||||||
out: 'ARY'
|
let pins = 255
|
||||||
})
|
await this.writePort(pins, 'force', port)
|
||||||
let addr = gpio.pin.address.toFmt('ARY')
|
}
|
||||||
// // console.log(addr)
|
|
||||||
// console.log(resp)
|
async off(pins, port, format) {
|
||||||
resolve(_u.sum(_u.and(addr, resp))) // resolve 1 or 0
|
if ('AB'.indexOf(port) === -1) {
|
||||||
})
|
format = port
|
||||||
})
|
port = 'A'
|
||||||
// .then(state => console.log(`pin state $ { state }`))
|
}
|
||||||
.catch(err => console.log(err)) // end Promise
|
if (format) { pins = _u.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
} // end pinRead
|
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 = _u.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'toggle', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async allToggle(port = 'A') {
|
||||||
|
let pins = 255
|
||||||
|
await this.writePort('toggle', port)
|
||||||
|
}
|
||||||
|
|
||||||
|
async force(pins, port, format) {
|
||||||
|
if ('AB'.indexOf(port) === -1) {
|
||||||
|
format = port
|
||||||
|
port = 'A'
|
||||||
|
}
|
||||||
|
if (format) { pins = _u.byteFormat(pins, { in: format, out: 'DEC' }) }
|
||||||
|
await this.writePort(pins, 'force', port)
|
||||||
|
}
|
||||||
|
|
||||||
} // end 23008
|
} // end 23008
|
||||||
|
|
||||||
module.exports.MCP23008 = MCP23008
|
module.exports.MCP23008 = MCP23008
|
||||||
|
|
||||||
class MCP23017 extends MCP23008 {
|
class MCP23017 extends MCP23008 {
|
||||||
constructor(busObj, i2cAddress, opts) {
|
constructor(busObj, i2cAddress, opts) {
|
||||||
super(busObj, i2cAddress, opts)
|
super(busObj, i2cAddress, opts)
|
||||||
// add a second port
|
// add a second port
|
||||||
opts.portID = 'B'
|
opts.portID = 'B'
|
||||||
opts.pids = opts.pidsB
|
opts.pids = opts.pidsB
|
||||||
this.ports.B = new Port(opts)
|
this.ports.B = new Port(opts)
|
||||||
this.ports.B.interrupt = opts.interruptB ? opts.interruptB : opts.interrupt
|
this.ports.B.state = new _u.Byte(opts.stateB)
|
||||||
// if (this.ports.B.interrupt) { this.ports.B.interrupt.hook = 'B' }
|
this.ports.B.interrupt = opts.interruptB ? opts.interruptB : opts.interrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
pin(id, port) {
|
pin(id, port) {
|
||||||
if (!port) {
|
if (!port) {
|
||||||
return this.ports.A.pin(id) ? this.ports.A.pin(id) : this.ports.B.pin(id)
|
return this.ports.A.pin(id) ? this.ports.A.pin(id) : this.ports.B.pin(id)
|
||||||
}
|
}
|
||||||
return this.ports[port].pin(id)
|
return this.ports[port].pin(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pid(address, port) {
|
pid(address, port) {
|
||||||
if (!port) {
|
if (!port) {
|
||||||
return this.ports.A.pid(address)
|
return this.ports.A.pid(address)
|
||||||
}
|
}
|
||||||
return this.ports[port].pid(address)
|
return this.ports[port].pid(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
portByInterPin(pin) {
|
portByPin(id) {
|
||||||
if (this.ports.A.interrupt.pin_number === pin) { return 'A' }
|
console.log('pin id in portbypin', id)
|
||||||
if (this.ports.B.interrupt.pin_number === pin) { return 'B' }
|
if (this.ports.A.pin(id)) { return 'A' }
|
||||||
return false
|
if (this.ports.B.pin(id)) { return 'B' }
|
||||||
}
|
return false
|
||||||
|
}
|
||||||
portByPin(id) {
|
|
||||||
console.log('pin id in portbypin', id)
|
|
||||||
if (this.ports.A.pin(id)) { return 'A' }
|
|
||||||
if (this.ports.B.pin(id)) { return 'B' }
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end MCP23017 Class
|
} // end MCP23017 Class
|
||||||
module.exports.MCP23017 = MCP23017
|
module.exports.MCP23017 = MCP23017
|
||||||
|
@ -258,7 +228,9 @@ module.exports.MCP23017 = MCP23017
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
function portReg(reg, port) {
|
function portReg(reg, port) {
|
||||||
if (port === 'B') { return reg += 0x10 } else { return reg }
|
// TODO what to return for port B will depend on chip configuration
|
||||||
|
// if not letter assume index 0,1.
|
||||||
|
if ((port === 'B') || (port === 1)) { return reg += 0x10 } else { return reg }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
|
/* ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
|
||||||
|
@ -271,31 +243,31 @@ function portReg(reg, port) {
|
||||||
*/
|
*/
|
||||||
// Chip Configuration to be used with Register See Page 18 of 23017 doc
|
// Chip Configuration to be used with Register See Page 18 of 23017 doc
|
||||||
let chip_config = {
|
let chip_config = {
|
||||||
// byte: ['NULL','INTPOL','ODR','HAEN','DISSLW','SEQOP','MIRROR','BANK'] // see page 18 of 23017 datasheet for 8 setting details
|
// 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
|
cmd: 0x0A, // IOCON.BANK=0 (msb) at powerup so need to use 0x0A, if set to 1 then use
|
||||||
default: {
|
default: {
|
||||||
val: '10100010', // Split Banks port A + 0x10 = Port B,(ignored by 23008), Sequential operation disabled, active high=pulldown
|
val: '10100010', // Split Banks port A + 0x10 = Port B,(ignored by 23008), Sequential operation disabled, active high=pulldown
|
||||||
fmt: 'STR'
|
fmt: 'STR'
|
||||||
},
|
},
|
||||||
oneint: {
|
oneint: {
|
||||||
val: '11100100', // same as default execpt int pins connected
|
val: '11100100', // same as default execpt int pins connected
|
||||||
fmt: 'STR'
|
fmt: 'STR'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let registers = {
|
let registers = {
|
||||||
pin_config: {
|
pin_config: {
|
||||||
dir: 0,
|
dir: 0,
|
||||||
ivrt: 1,
|
ivrt: 1,
|
||||||
pullup: 6,
|
pullup: 6,
|
||||||
intr: 2,
|
intr: 2,
|
||||||
usedef: 4,
|
usedef: 4,
|
||||||
defval: 3,
|
defval: 3,
|
||||||
},
|
},
|
||||||
pin_cmd: {
|
pin_cmd: {
|
||||||
intf: 7, // readonly
|
intf: 7, // readonly
|
||||||
intcap: 8, // readonly
|
intcap: 8, // readonly
|
||||||
gpio: 9, // read/write
|
gpio: 9, // read/write
|
||||||
olat: 10 // read only
|
olat: 10 // read only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue