UNPKG

mcp23017-promise

Version:

MCP23017 library with promises.

336 lines 13 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const async_i2c_bus_1 = require("async-i2c-bus"); exports.A0 = 1 << 0; exports.A1 = 1 << 1; exports.A2 = 1 << 2; exports.A3 = 1 << 3; exports.A4 = 1 << 4; exports.A5 = 1 << 5; exports.A6 = 1 << 6; exports.A7 = 1 << 7; exports.B0 = 1 << 8; exports.B1 = 1 << 9; exports.B2 = 1 << 10; exports.B3 = 1 << 11; exports.B4 = 1 << 12; exports.B5 = 1 << 13; exports.B6 = 1 << 14; exports.B7 = 1 << 15; const PINS_A = 0xFF; const PINS_B = 0xFF00; /** Direction of the I/O pins */ var Direction; (function (Direction) { /** Output pin */ Direction[Direction["OUT"] = 0] = "OUT"; /** Input pin without pull-up */ Direction[Direction["IN"] = 1] = "IN"; /** Input pin with pull-up */ Direction[Direction["IN_UP"] = 2] = "IN_UP"; })(Direction = exports.Direction || (exports.Direction = {})); /** Interupt mode */ var InteruptMode; (function (InteruptMode) { /** No interupt (used to reset) */ InteruptMode[InteruptMode["INT_None"] = 0] = "INT_None"; /** Interupt when not one */ InteruptMode[InteruptMode["INT_One"] = 1] = "INT_One"; /** Interupt when not zero */ InteruptMode[InteruptMode["INT_Zero"] = 2] = "INT_Zero"; /** Interupt on change */ InteruptMode[InteruptMode["INT_Change"] = 3] = "INT_Change"; })(InteruptMode = exports.InteruptMode || (exports.InteruptMode = {})); /** Pin value */ var Level; (function (Level) { /** Low or 0 */ Level[Level["LOW"] = 0] = "LOW"; /** High or 1 */ Level[Level["HIGH"] = 1] = "HIGH"; })(Level = exports.Level || (exports.Level = {})); exports.IOCON_INTPOL = 1 << 1; exports.IOCON_ODR = 1 << 2; exports.IOCON_HAEN = 1 << 3; exports.IOCON_DISSLW = 1 << 4; exports.IOCON_SEQOP = 1 << 5; exports.IOCON_MIRROR = 1 << 6; exports.IOCON_BANK = 1 << 7; const bankSeparate = { DEFVAL: { A: 0x03, B: 0x13 }, GPINTEN: { A: 0x02, B: 0x12 }, GPIO: { A: 0x09, B: 0x19 }, GPPU: { A: 0x06, B: 0x16 }, INTCAP: { A: 0x08, B: 0x18 }, INTCON: { A: 0x04, B: 0x14 }, INTF: { A: 0x07, B: 0x17 }, IOCON: 0x05, IODIR: { A: 0x00, B: 0x10 }, IPOL: { A: 0x01, B: 0x11 }, OLAT: { A: 0x0A, B: 0x1A }, }; const bankInterleaved = { DEFVAL: { A: 0x06, B: 0x07 }, GPINTEN: { A: 0x04, B: 0x05 }, GPIO: { A: 0x12, B: 0x13 }, GPPU: { A: 0x0C, B: 0x0D }, INTCAP: { A: 0x10, B: 0x11 }, INTCON: { A: 0x08, B: 0x09 }, INTF: { A: 0x0E, B: 0x0F }, IOCON: 0x0A, IODIR: { A: 0x00, B: 0x01 }, IPOL: { A: 0x02, B: 0x03 }, OLAT: { A: 0x14, B: 0x15 }, }; /** This class drives a single MCP23017 GPIO extender */ class MCP23017 { /** Constructor. * * @param bus an instance of i2c bus. May be closed at this point * @param options options for the driver. */ constructor(bus, options = {}) { this.device = async_i2c_bus_1.Device({ bus, address: options.address || 0x20 }); this.separate = options.separate || false; this.bank = this.separate ? bankSeparate : bankInterleaved; this.cache = Buffer.allocUnsafe(0); } /** Initialize the class * * Must be called with an open bus */ init() { return __awaiter(this, void 0, void 0, function* () { this.cache = yield this.initCache(); }); } /** Reads the configuration byte of the chip * @return the value of the configuration as a byte in a promise. */ readConfigByte() { return this.device.readByte(this.bank.IOCON); } /** Change the way register banks are organize. * @param separate set to true for registers organized as two * independent banks and false for interleaved (default) * @return a promisse fullfilled when the operation is performed. */ setSeparate(separate) { return __awaiter(this, void 0, void 0, function* () { const iocon = this.bank.IOCON; if (this.separate !== separate) { this.separate = separate; this.bank = this.separate ? bankSeparate : bankInterleaved; const ioconVal = yield this.device.readByte(iocon); yield this.writeByte(iocon, ioconVal ^ exports.IOCON_BANK); this.cache = yield this.initCache(); } }); } /** Sets the direction of a set of GPI/O pins and eventually pull-up status. * @param pins: the set of pins (number used as a bit set) * @param direction: the direction of the pin (can be IN OUT or IN_UP) * @return a promisse fullfilled when the operation is performed. */ setDirection(pins, direction) { return __awaiter(this, void 0, void 0, function* () { const iodir = this.readCache(this.bank.IODIR); const newIodir = direction === Direction.OUT ? iodir & ~pins : iodir | pins; const changesIodir = newIodir ^ iodir; yield this.writeBanks(newIodir, changesIodir, this.bank.IODIR); if (direction !== Direction.OUT) { const pullup = this.readCache(this.bank.GPPU); const newPullup = (direction === Direction.IN_UP ? pullup | pins : pullup & ~pins); const changesPullup = pullup ^ newPullup; yield this.writeBanks(newPullup, changesPullup, this.bank.GPPU); } }); } /** Set the polarity of the output (ie XOR with it) * @param polarity of each pin as a bit array */ setPolarity(pins) { return __awaiter(this, void 0, void 0, function* () { const ipol = this.readCache(this.bank.IPOL); const changes = ipol ^ pins; yield this.writeBanks(pins, changes, this.bank.IPOL); }); } /** Reads the GPIO * @return the value of the GPIO Pin in a promise. */ read() { return __awaiter(this, void 0, void 0, function* () { return yield this.readBanks(true, true, this.bank.GPIO); }); } /** Modify the GPIO * @param set: bits to set as a bit field * @param unset: bits to set as a bit field */ write(set, unset) { return __awaiter(this, void 0, void 0, function* () { const gpio = this.readCache(this.bank.OLAT); const newGpio = (gpio | set) & ~unset; const changesGpio = gpio ^ newGpio; yield this.writeBanks(newGpio, changesGpio, this.bank.OLAT); }); } /** Register changes to the interupt handling * @param intDefs: a list of interupt handling description that * will be (dis)activated * @param handler: an optional interupt handler that was in place * @return the new interupt handler. */ register(intDefs, handler = {}) { return __awaiter(this, void 0, void 0, function* () { function addDef(intState, intDef) { switch (intDef.mode) { case InteruptMode.INT_None: intState.inten &= ~intDef.pin; delete intState.handler[intDef.pin]; break; case InteruptMode.INT_Change: intState.inten |= intDef.pin; intState.intcon &= ~intDef.pin; if (intDef.callback) { intState.handler[intDef.pin] = intDef.callback; } break; case InteruptMode.INT_Zero: intState.inten |= intDef.pin; intState.intcon |= intDef.pin; intState.defval &= ~intDef.pin; if (intDef.callback) { intState.handler[intDef.pin] = intDef.callback; } break; case InteruptMode.INT_One: intState.inten |= intDef.pin; intState.intcon |= intDef.pin; intState.defval |= intDef.pin; if (intDef.callback) { intState.handler[intDef.pin] = intDef.callback; } break; } return intState; } const inten = this.readCache(this.bank.GPINTEN); const intcon = this.readCache(this.bank.INTCON); const defval = this.readCache(this.bank.DEFVAL); const state = intDefs.reduce(addDef, { inten, intcon, defval, handler }); yield this.writeBanks(state.defval, defval ^ state.defval, this.bank.DEFVAL); yield this.writeBanks(state.defval, intcon ^ state.intcon, this.bank.INTCON); yield this.writeBanks(state.defval, inten ^ state.inten, this.bank.GPINTEN); return state.handler; }); } /** Handle interupts received. * @param handler: an interupt handler built during the registration. */ handle(handler) { return __awaiter(this, void 0, void 0, function* () { const intf = yield this.readBanks(true, true, this.bank.INTF); const intcap = yield this.readBanks(true, true, this.bank.INTCAP); let mask = 1; for (let pin = 0; pin < 16; pin++) { if (mask & intf) { const callback = handler[pin]; if (callback) { callback(mask & intcap ? Level.HIGH : Level.LOW); } } mask <<= 1; } }); } readCache(regs) { return this.cache[regs.A] | (this.cache[regs.B] << 8); } initCache() { return __awaiter(this, void 0, void 0, function* () { const buffer = Buffer.alloc(0x1B); if (this.separate) { const bufA = yield this.readBuffer(0, 0xA); const bufB = yield this.readBuffer(0x10, 0xA); bufA.copy(buffer, 0); bufB.copy(buffer, 0x10); } else { const buf = yield this.readBuffer(0, 0x16); buf.copy(buffer, 0); } return buffer; }); } readBuffer(register, len) { return __awaiter(this, void 0, void 0, function* () { const buffer = Buffer.alloc(len); const lenRes = yield this.device.readI2cBlock(register, len, buffer); if (lenRes !== len) { throw new Error("Bad length"); } return buffer; }); } writeByte(register, byte) { return __awaiter(this, void 0, void 0, function* () { yield this.device.writeByte(register, byte); this.cache[register] = byte; }); } writeWord(register, word) { return __awaiter(this, void 0, void 0, function* () { yield this.device.writeWord(register, word); this.cache[register] = word & 0xff; this.cache[register + 1] = (word >> 8) & 0xff; }); } writeBanks(pins, changes, regs) { return __awaiter(this, void 0, void 0, function* () { const needsA = (changes & PINS_A) !== 0; const needsB = (changes & PINS_B) !== 0; if (this.separate) { if (needsA) { yield this.writeByte(regs.A, pins & PINS_A); } if (needsB) { yield this.writeByte(regs.B, (pins & PINS_B) >> 8); } } else { yield this.writeWord(regs.A, pins & 0xFFFF); } }); } readBanks(needsA, needsB, regs) { return __awaiter(this, void 0, void 0, function* () { if (this.separate) { let valA = 0; if (needsA) { valA = yield this.device.readByte(regs.A); } let valB = 0; if (needsB) { valB = yield this.device.readByte(regs.B); } return valA | (valB << 8); } else { return yield this.device.readWord(regs.A); } }); } } exports.MCP23017 = MCP23017; //# sourceMappingURL=index.js.map