'use strict' const Device = require('uci-dev').Device, Port = require('uci-gpio').Port, _u = require('uci-utils') class MCP23008 extends Device { constructor(busObj, i2cAddress, opts) { super(busObj, i2cAddress, opts) // opts could pass in array of custom pin config, or single for all, or anything // this.registers = registers // load in register database this.ports = {} opts.portID = 'A' this.ports.A = new Port(opts) // if not specified there RPi is not managing the interrupt // pin number on RPi that is connected to and services the interrupt. 4/17/27/22 = 7/11/13/15 if (opts.interPin) { this.ports.A.interPin = opts.interPin.A ? opts.interPin.A : opts.interPin } } // end constructor init() { // console.log('chip configuration', chip_config.cmd, chipSetByte()) // console.log(super.write.toString()) return super.write(chip_config.cmd, chipSetByte()) // configure chip .then(() => { return this.writePinsCfg() }) } pin(id) { return this.ports.A.pin(id) } // get a reference to a particular pin's object // pin configurations should already be set before calling writePinsCfg() { let jobs = []; for (let port in this.ports) { for (let setting in registers.pin_config) { let reg = registers.pin_config[setting] if (port === 'B') { reg = reg + 0x10 } 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(reg, byte) //.then(() => console.log(`done writing config`)) ) } } return _u.pSeries(jobs) } // end writePinsCfg // reads all pins in all ports readPins(cmd, fmt) { let jobs = [] cmd = cmd ? cmd : 'gpio' let reg = registers.pin_cmd[cmd] for (let port in this.ports) { jobs.push(() => super.read(reg)) reg += 0x10 } return _u.pSeries(jobs) } pinRead(id, opts) { let mcpdev = this; return new Promise(function (resolve, reject) { let cmd = opts.cmd ? opts.cmd : 'gpio' let fmt = opts.fmt ? opts.fmt : { in: 'PLC', out: 'PLC' } let reg = registers.pin_cmd[cmd] let gpio = mcpdev.pin(id) if (!gpio) { reject('no pin found for given id') } if (gpio.port === 'B') { reg = reg + 16 } // call device class read (response is always decimal) console.log('port - reg', gpio.port, reg) return mcpdev.read(reg).then(resp => { resp = _u.byteFormat(resp, { in: 'DEC', out: 'ARY' }) let addr = gpio.pin.address.toFmt('ARY') console.log(addr) console.log(resp) resolve(_u.sum(_u.and(addr, resp))) // resolve 1 or 0 }) }) .then(state => console.log(`pin state ${state}`)) .catch(err => console.log(err)) // end Promise } // end pinRead pinWrite(id, opts) { let mcpdev = this; return new Promise(function (resolve, reject) { let cmd = opts.cmd ? opts.cmd : 'gpio' let reg = registers.pin_cmd[cmd] let gpio = mcpdev.pin(id, opts.port) if (!gpio) { reject('no pin found for given id') } if (gpio.port === 'B') { reg = reg + 16 } // call device class read console.log('port - reg', gpio.port, reg) return mcpdev.read(reg).then(resp => { resp = _u.byteFormat(resp, { in: 'DEC', out: 'ARY' }) let addr = gpio.pin.address.toFmt('ARY') console.log(addr) console.log(resp) resolve(_u.sum(_u.and(addr, resp))) // resolve 1 or 0 }) }) .then(state => console.log(`pin state ${state}`)) .catch(err => console.log(err)) // end Promise } // end pinRead } // end 23008 module.exports.MCP23008 = MCP23008 class MCP23017 extends MCP23008 { constructor(busObj, i2cAddress, opts) { super(busObj, i2cAddress, opts) // add a second port opts.portID = 'B' this.ports.B = new Port(opts) if (opts.interPin) { this.ports.B.interPin = opts.interPin.B ? opts.interPin.B : opts.interPin } } 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) } } // end MCP23017 Class module.exports.MCP23017 = MCP23017 /* 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 cConfiguration to be used with Register 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 default: { val: '10000000', // int pins connected, port A + 0x10 = Port B -- ignored by 23008 fmt: 'STR' }, twoints: { val: '00000001', // int pins separate, port A + 0x10 = Port B -- ignored by 23008 fmt: 'STR' } } function chipSetByte(setting = 'default') { setting = chip_config[setting] return _u.byteFormat(setting.val, { in: setting.fmt, out: 'DEC' }) } 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 } }