node-red-mcp23xxx
Version:
Library to use the MCP23008 and MCP23017 I/O Expanders with the Raspberry Pi
197 lines (173 loc) • 6.46 kB
JavaScript
/**
* Copyright 2015 Sorin Chitu.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var DIRECTION_GPIO = 0x00,
FROM_GPIO = 0x09,
TO_GPIO = 0x0A,
i2c = require('i2c-bus'),
i2c1;
var MCP23008 = (function() {
MCP23008.prototype.HIGH = 1;
MCP23008.prototype.LOW = 0;
MCP23008.prototype.INPUT = 1;
MCP23008.prototype.OUTPUT = 0;
MCP23008.prototype.address = 0x20; //if the mcp has all adress lines pulled low
MCP23008.prototype.oldDir = 0xff; //initial state of GPIO A
MCP23008.prototype.oldGpio = 0x0; //initial state of GPIO A
function MCP23008(config) {
if (config.reverse) {
this.HIGH = 0;
this.LOW = 1;
}
this.address = config.address;
this.mode = this.INPUT;
this.debug = config.debug === true ? true : false;
this.bus = config.bus !== null ? config.bus : 1;
this.i2c1 = i2c.open(this.bus, function (err) {
if (err) {
console.error(err);
}
});
this._initGpio();
}
//inits both registers as an input
MCP23008.prototype.reset = function() {
this.oldDir = 0xff;
this._initGpio();;
};
/*
sets an pin as an INPUT or OUTPUT
*/
MCP23008.prototype.pinMode = function(pin, dir) {
if (dir !== this.INPUT && dir !== this.OUTPUT) {
console.error('invalid value', dir);
return;
}
if (isNaN(pin)) {
console.error('pin is not a number:', pin);
return;
} else if (pin > 15 || pin < 0) {
console.error('invalid pin:', pin);
}
//delegate to funktion that handles low level stuff
this._setGpioDir(pin, dir, DIRECTION_GPIO);
};
/*
internally used to set the direction registers
*/
MCP23008.prototype._setGpioDir = function(pin, dir, register) {
var pinHexMask = Math.pow(2, pin),
registerValue;
if (register === DIRECTION_GPIO) {
registerValue = this.oldDir;
if (dir === this.OUTPUT) {
if ((this.oldDir & pinHexMask) === pinHexMask) {
this.log('setting pin \'' + pin + '\' as an OUTPUT');
this.oldDir = this.oldDir ^ pinHexMask;
registerValue = this.oldDir;
} else {
this.log('pin \'' + pin + '\' already an OUTPUT');
}
} else if (dir === this.INPUT) {
if ((this.oldDir & pinHexMask) !== pinHexMask) {
this.log('setting pin \'' + pin + '\' as an INPUT');
this.oldDir = this.oldDir ^ pinHexMask;
registerValue = this.oldDir;
} else {
this.log('pin \'' + pin + '\' already an INPUT');
}
}
}
this._send(register, registerValue);
this.log('register: ' + register + ', value: ' + registerValue);
};
MCP23008.prototype._setGpioPinValue = function(pin, value) {
var pinHexMask = Math.pow(2, pin);
if (value === 0) {
if ((this.oldGpio & pinHexMask) === pinHexMask) {
this.oldGpio = this.oldGpio ^ pinHexMask;
this._send(TO_GPIO, this.oldGpio);
}
}
if (value === 1) {
if ((this.oldGpio & pinHexMask) !== pinHexMask) {
this.oldGpio = this.oldGpio ^ pinHexMask;
this._send(TO_GPIO, this.oldGpio);
}
}
};
var allowedValues = [0, 1, true, false];
MCP23008.prototype.digitalWrite = function(pin, value) {
if (allowedValues.indexOf(value) < 0) {
console.error('invalid value', value);
return;
} else if (value === false) {
value = this.LOW;
} else if (value === true) {
value = this.HIGH;
}
if (isNaN(pin)) {
console.error('pin is not a number:', pin);
return;
} else if (pin > 7 || pin < 0) {
console.error('invalid pin:', pin);
} else {
this._setGpioPinValue(pin, value);
}
};
MCP23008.prototype.digitalRead = function(pin, callback) {
var pinHexMask = Math.pow(2, pin); //create a hexMask
//read one byte from the right register (A or B)
this._read(FROM_GPIO, function(err, registerValue) {
if (err) {
console.error(err);
callback(err, null);
} else if ((registerValue & pinHexMask) === pinHexMask) {
//Check if the requested bit is set in the byte returned from the register
callback(null, true);
} else {
callback(null, false);
}
});
};
MCP23008.prototype._initGpio = function() {
this._send(DIRECTION_GPIO, this.oldDir); //Set Direction to Output
this._send(TO_GPIO, 0x0); //clear all output states
};
MCP23008.prototype._send = function(cmd, value) {
this.i2c1.writeByte(this.address, cmd, value, function(err) {
if (err) {
console.error(err);
}
});
};
MCP23008.prototype._read = function(cmd, callback) {
this.i2c1.readByte(this.address, cmd, function(err, res) {
if (err) {
console.error(err);
callback(err, null);
} else {
callback(null, res);
}
});
};
MCP23008.prototype.log = function(msg) {
if (this.debug) {
console.log(msg);
}
};
return MCP23008;
})();
module.exports = MCP23008;