Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- *
- * ABElectronics Expander Pi - 32 Digital IO, 8 ADC, 2 DAC and a real-time clock
- * For use with the Expander Pi
- * Version 1.0 Created 19/06/2017
- *
- * Requires rpio to be installed, install with: npm install rpio
- *
- */
- var rpio = require("rpio");
- const Constants = require("./constants");
- const Bme680Data = require("./bme680Data");
- const CalibrationData = require("./calibrationData");
- const constants = new Constants();
- const bme680Data = new Bme680Data();
- /**
- * IO Class
- */
- ExpanderPiIO = (function () {
- // Define registers values from datasheet
- const IODIRA = 0x00; // IO direction A - 1= input 0 = output
- const IODIRB = 0x01; // IO direction B - 1= input 0 = output
- // Input polarity A - If a bit is set, the corresponding GPIO register bit will reflect the inverted value on the pin.
- const IPOLA = 0x02;
- // Input polarity B - If a bit is set, the corresponding GPIO register bit will reflect the inverted value on the pin.
- const IPOLB = 0x03;
- // The GPINTEN register controls the interrupt-onchange feature for each pin on port A.
- const GPINTENA = 0x04;
- // The GPINTEN register controls the interrupt-onchange feature for each pin on port B.
- const GPINTENB = 0x05;
- // Default value for port A - These bits set the compare value for pins configured for interrupt-on-change.
- // If the associated pin level is the opposite from the register bit, an interrupt occurs.
- const DEFVALA = 0x06;
- // Default value for port B - These bits set the compare value for pins configured for interrupt-on-change. If the associated pin level is the
- // opposite from the register bit, an interrupt occurs.
- const DEFVALB = 0x07;
- // Interrupt control register for port A. If 1 interrupt is fired when the pin matches the default value, if 0 the interrupt is fired on state change
- const INTCONA = 0x08;
- // Interrupt control register for port B. If 1 interrupt is fired when the pin matches the default value, if 0 the interrupt is fired on state change
- const INTCONB = 0x09;
- const IOCON = 0x0a; // see datasheet for configuration register
- const GPPUA = 0x0c; // pull-up resistors for port A
- const GPPUB = 0x0d; // pull-up resistors for port B
- // The INTF register reflects the interrupt condition on the port A pins of any pin that is enabled for interrupts. A set bit indicates that the
- // associated pin caused the interrupt.
- const INTFA = 0x0e;
- // The INTF register reflects the interrupt condition on the port B pins of any pin that is enabled for interrupts. A set bit indicates that the
- // associated pin caused the interrupt.
- const INTFB = 0x0f;
- // The INTCAP register captures the GPIO port A value at the time the interrupt occurred.
- const INTCAPA = 0x10;
- // The INTCAP register captures the GPIO port B value at the time the interrupt occurred.
- const INTCAPB = 0x11;
- const GPIOA = 0x12; // Data port A
- const GPIOB = 0x13; // Data port B
- const OLATA = 0x14; // Output latches A
- const OLATB = 0x15; // Output latches B
- // variables
- ExpanderPiIO.prototype.portADir = 0x00; // port a direction
- ExpanderPiIO.prototype.portBDir = 0x00; // port b direction
- ExpanderPiIO.prototype.portAVal = 0x00; // port a value
- ExpanderPiIO.prototype.portBVal = 0x00; // port b value
- ExpanderPiIO.prototype.portAPullup = 0x00; // port a pull-up resistors
- ExpanderPiIO.prototype.portBPullup = 0x00; // port a pull-up resistors
- ExpanderPiIO.prototype.portAPolarity = 0x00; // input polarity for port a
- ExpanderPiIO.prototype.portBPolarity = 0x00; // input polarity for port b
- ExpanderPiIO.prototype.intA = 0x00; // interrupt control for port a
- ExpanderPiIO.prototype.intB = 0x00; // interrupt control for port a
- // initial configuration - see IOCON page in the MCP23017 datasheet for more information.
- ExpanderPiIO.prototype.config = 0x22;
- ExpanderPiIO.prototype.i2caddress = 0x20;
- /**
- * Initialize the I2C bus based on the supplied address
- * Load the default configuration, all pins are inputs with pull- ups disabled
- */
- function ExpanderPiIO() {
- rpio.i2cBegin();
- rpio.i2cSetSlaveAddress(this.i2caddress);
- this.i2cWriteByte(IOCON, this.config);
- this.portAVal = this.i2cReadByte(GPIOA);
- this.portBVal = this.i2cReadByte(GPIOB);
- this.i2cWriteByte(IODIRA, 0xff);
- this.i2cWriteByte(IODIRB, 0xff);
- this.setPortPullups(0, 0x00);
- this.setPortPullups(1, 0x00);
- this.invertPort(0, 0x00);
- this.invertPort(1, 0x00);
- }
- /**
- * private functions
- */
- ExpanderPiIO.prototype.i2cReadByte = function (val) {
- var txbuf = new Buffer([val]);
- var rxbuf = new Buffer(1);
- rpio.i2cSetSlaveAddress(this.i2caddress);
- rpio.i2cWrite(txbuf);
- rpio.i2cRead(rxbuf, 1);
- return rxbuf[0];
- };
- ExpanderPiIO.prototype.i2cWriteByte = function (register, val) {
- rpio.i2cSetSlaveAddress(this.i2caddress);
- var txbuf = new Buffer([register, val]);
- var rxbuf = new Buffer(1);
- rpio.i2cWrite(txbuf);
- };
- updateByte = function (oldByte, bit, value) {
- // internal function for setting the value of a single bit within a byte
- var newByte = 0;
- if (value == false) {
- newByte = oldByte & ~(1 << bit);
- } else {
- newByte = oldByte | (1 << bit);
- }
- return newByte;
- };
- function checkBit(num, bit) {
- return (num >> bit) % 2 != 0;
- }
- /**
- * public functions
- */
- /**
- * Set IO direction for an individual pin
- * @param {number} pin - 1 to 16
- * @param {number} direction - 1 = input, 0 = output
- */
- ExpanderPiIO.prototype.setPinDirection = function (pin, direction) {
- pin = pin - 1;
- if (pin < 8) {
- this.portADir = updateByte(this.portADir, pin, direction);
- this.i2cWriteByte(IODIRA, portADir);
- } else {
- this.portBDir = updateByte(this.portBDir, pin - 8, direction);
- this.i2cWriteByte(IODIRB, portBDir);
- }
- };
- /**
- * Set direction for an IO port
- * @param {number} port - 0 = pins 1 to 8, 1 = pins 8 to 16
- * @param {number} direction - 0 to 255. For each bit 1 = input, 0 = output
- */
- ExpanderPiIO.prototype.setPortDirection = function (port, direction) {
- if (port == 1) {
- this.i2cWriteByte(IODIRB, direction);
- this.portBDir = direction;
- } else {
- this.i2cWriteByte(IODIRA, direction);
- this.portADir = direction;
- }
- };
- /**
- * Set the internal 100K pull-up resistors for an individual pin
- * @param {number} pin - 1 to 16
- * @param {number} value - 1 = enabled, 0 = disabled
- */
- ExpanderPiIO.prototype.setPinPullup = function (pin, value) {
- pin = pin - 1;
- if (pin < 8) {
- this.portAPullup = updateByte(this.portAPullup, pin, value);
- this.i2cWriteByte(GPPUA, this.portAPullup);
- } else {
- this.portBPullup = updateByte(this.portBPullup, pin - 8, value);
- this.i2cWriteByte(GPPUB, this.portBPullup);
- }
- };
- /**
- * Set the internal 100K pull-up resistors for the selected IO port
- * @param {number} port - 0 = pins 1 to 8, 1 = pins 8 to 16
- * @param {number} value - 0 to 255. For each bit 1 = input, 0 = output
- */
- ExpanderPiIO.prototype.setPortPullups = function (port, value) {
- if (port == 1) {
- this.portBPullup = value;
- this.i2cWriteByte(GPPUB, value);
- } else {
- this.portAPullup = value;
- this.i2cWriteByte(GPPUA, value);
- }
- };
- /**
- * Write to an individual pin
- * @param {number} pin - 1 to 16
- * @param {number} value - 1 = enabled, 0 = disabled
- */
- ExpanderPiIO.prototype.writePin = function (pin, value) {
- //
- // write to an individual pin 1 - 16
- //
- pin = pin - 1;
- if (pin < 8) {
- this.portAVal = updateByte(this.portAVal, pin, value);
- this.i2cWriteByte(GPIOA, this.portAVal);
- } else {
- this.portBVal = updateByte(this.portBVal, pin - 8, value);
- this.i2cWriteByte(GPIOB, this.portBVal);
- }
- };
- /**
- * Write to all pins on the selected port
- * @param {number} port - 0 = pins 1 to 8, 1 = pins 8 to 16
- * @param {number} value - number between 0 and 255 or 0x00 and 0xFF
- */
- ExpanderPiIO.prototype.writePort = function (port, value) {
- if (port == 1) {
- this.i2cWriteByte(GPIOB, value);
- this.portBVal = value;
- } else {
- this.i2cWriteByte(GPIOA, value);
- this.portAVal = value;
- }
- };
- /**
- * read the value of an individual pin 1 - 16
- * @param {number} pin - 1 to 16
- * @returns {number} - 0 = logic level low, 1 = logic level high
- */
- ExpanderPiIO.prototype.readPin = function (pin) {
- pin = pin - 1;
- if (pin < 8) {
- this.portAVal = this.i2cReadByte(GPIOA);
- return checkBit(this.portAVal, pin);
- } else {
- pin = pin - 8;
- this.portBVal = this.i2cReadByte(GPIOB);
- return checkBit(this.portBVal, pin);
- }
- };
- /**
- * Read all pins on the selected port
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @returns {number} - number between 0 and 255 or 0x00 and 0xFF
- */
- ExpanderPiIO.prototype.readPort = function (port) {
- if (port == 1) {
- this.portBVal = this.i2cReadByte(GPIOB);
- return this.portBVal;
- } else {
- this.portAVal = this.i2cReadByte(GPIOA);
- return this.portAVal;
- }
- };
- /**
- * Invert the polarity of the pins on a selected port
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @param {number} polarity - 0 = same logic state of the input pin, 1 = inverted logic state of the input pin
- */
- ExpanderPiIO.prototype.invertPort = function (port, polarity) {
- if (port == 1) {
- this.i2cWriteByte(IPOLB, polarity);
- this.portBPolarity = polarity;
- } else {
- this.i2cWriteByte(IPOLA, polarity);
- this.portAPolarity = polarity;
- }
- };
- /**
- * Invert the polarity of the selected pin
- * @param {number} pin - 1 to 16
- * @param {number} polarity - 0 = same logic state of the input pin, 1 = inverted logic state of the input pin
- */
- ExpanderPiIO.prototype.invertPin = function (pin, polarity) {
- pin = pin - 1;
- if (pin < 8) {
- this.portAPolarity = updateByte(this.portAPolarity, pin, polarity);
- this.i2cWriteByte(IPOLA, this.portAPolarity);
- } else {
- this.portBPolarity = updateByte(this.portBPolarity, pin - 8, polarity);
- this.i2cWriteByte(IPOLB, this.portBPolarity);
- }
- };
- /**
- * Mirror interrupts across INTA and INTB
- * @param {number} value - 1 = The INT pins are internally connected, 0 = The INT pins are not connected. INTA is associated with PortA and INTB is associated with PortB
- */
- ExpanderPiIO.prototype.mirrorInterrupts = function (value) {
- if (value == 0) {
- this.config = updateByte(this.config, 6, 0);
- }
- if (value == 1) {
- this.config = updateByte(this.config, 6, 1);
- }
- this.i2cWriteByte(IOCON, this.config);
- };
- /**
- * This sets the polarity of the INT output pins
- * @param {number} value - 1 = Active-high. 0 = Active-low.
- */
- ExpanderPiIO.prototype.setInterruptPolarity = function (value) {
- if (value == 0) {
- this.config = updateByte(this.config, 1, 0);
- }
- if (value == 1) {
- this.config = updateByte(this.config, 1, 1);
- }
- this.i2cWriteByte(IOCON, this.config);
- };
- /**
- * Sets the type of interrupt for each pin on the selected port
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @param {number} value - 0 to 255. For each bit 1 = interrupt is fired when the pin matches the default value, 0 = the interrupt is fired on state change.
- */
- ExpanderPiIO.prototype.setInterruptType = function (port, value) {
- if (port == 0) {
- this.i2cWriteByte(INTCONA, value);
- } else {
- this.i2cWriteByte(INTCONB, value);
- }
- };
- /**
- * These bits set the compare value for pins configured for interrupt-on-change on the selected port.
- * If the associated pin level is the opposite from the register bit, an interrupt occurs.
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @param {number} value - 0 to 255 or 0x00 and 0xFF
- */
- ExpanderPiIO.prototype.setInterruptDefaults = function (port, value) {
- if (port == 0) {
- this.i2cWriteByte(DEFVALA, value);
- } else {
- this.i2cWriteByte(DEFVALB, value);
- }
- };
- /**
- * Enable interrupts for the pins on the selected port
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @param {number} value - 0 and 255 or 0x00 and 0xFF
- */
- ExpanderPiIO.prototype.setInterruptOnPort = function (port, value) {
- if (port == 0) {
- this.i2cWriteByte(GPINTENA, value);
- intA = value;
- } else {
- this.i2cWriteByte(GPINTENB, value);
- intB = value;
- }
- };
- /**
- * Enable interrupts for the selected pin
- * @param {number} pin - 1 to 16
- * @param {number} value - 0 = interrupt disabled, 1 = interrupt enabled
- */
- ExpanderPiIO.prototype.setInterruptOnPin = function (pin, value) {
- pin = pin - 1;
- if (pin < 8) {
- this.intA = updateByte(this.intA, pin, value);
- this.i2cWriteByte(GPINTENA, this.intA);
- } else {
- this.intB = updateByte(this.intB, pin - 8, value);
- this.i2cWriteByte(GPINTENB, this.intB);
- }
- };
- /**
- * Read the interrupt status for the pins on the selected port
- * @param {number} port - 0 = pins 1 to 8, port 1 = pins 9 to 16
- * @returns {number} - 0 to 255. Interrupt status, each pin represents one bit.
- */
- ExpanderPiIO.prototype.readInterruptStatus = function (port) {
- if (port == 0) {
- return this.i2cReadByte(INTFA);
- } else {
- return this.i2cReadByte(INTFB);
- }
- };
- /**
- * Read the value from the selected port at the time of the last interrupt trigger
- * @param {number} port - port 0 = pins 1 to 8, port 1 = pins 8 to 16
- * @returns {number} - 0 to 255. Interrupt status, each pin represents one bit.
- */
- ExpanderPiIO.prototype.readInterruptCapture = function (port) {
- if (port == 0) {
- return this.i2cReadByte(INTCAPA);
- } else {
- return this.i2cReadByte(INTCAPB);
- }
- };
- /**
- * Set the interrupts A and B to 0
- */
- ExpanderPiIO.prototype.resetInterrupts = function () {
- this.readInterruptCapture(0);
- this.readInterruptCapture(1);
- };
- return ExpanderPiIO;
- })();
- module.exports = ExpanderPiIO;
- /**
- * RTC Class
- */
- ExpanderPiRTC = (function () {
- // Define registers values from datasheet
- const SECONDS = 0x00;
- const MINUTES = 0x01;
- const HOURS = 0x02;
- const DAYOFWEEK = 0x03;
- const DAY = 0x04;
- const MONTH = 0x05;
- const YEAR = 0x06;
- const CONTROL = 0x07;
- // variables
- var rtcAddress = 0x68; // I2C address
- // initial configuration - square wave and output disabled, frequency set
- // to 32.768KHz.
- var config = 0x03;
- // the DS1307 does not store the current century so that has to be added on
- // manually.
- var century = 2000;
- /**
- * Initialise the RTC I2C connection and set the default configuration to the control register
- */
- function ExpanderPiRTC() {
- rpio.i2cBegin();
- rpio.i2cSetSlaveAddress(rtcAddress);
- i2cWriteByte(CONTROL, config);
- }
- // Private functions
- /**
- * Write a single byte to the I2C bus.
- * @param {number} register - Target register
- * @param {number} val - Value to be written
- */
- function i2cWriteByte(register, val) {
- var txbuf = new Buffer([register, val]);
- rpio.i2cSetSlaveAddress(rtcAddress);
- rpio.i2cWrite(txbuf);
- }
- /**
- * Update a single bit within a variable
- * @param {number} oldByte - Variable to be updated
- * @param {number} bit - The location of the bit to be changed
- * @param {boolean} value - The new value for the bit. true or false
- * @returns {number} - Updated value
- */
- function updateByte(oldByte, bit, value) {
- var newByte = 0;
- if (value == false) {
- newByte = oldByte & ~(1 << bit);
- } else {
- newByte = oldByte | (1 << bit);
- }
- return newByte;
- }
- /**
- * Convert a BCD formatted number to decimal.
- * @param {number} val - BCD value
- * @returns {number} - Decimal value
- */
- function bcdToDec(val) {
- return val - 6 * (val >> 4);
- }
- /**
- * Convert a decimal to BCD formatted number.
- * @param {number} val - Decimal value
- * @returns {number} - BCD value
- */
- function decToBcd(val) {
- return ((val / 10) << 4) | val % 10;
- }
- /**
- * Calculate the current century
- * @param {number} val - Year
- */
- function getCentury(val) {
- if (val.length > 2) {
- var y = val[0] + val[1];
- century = int(y) * 100;
- }
- }
- // public functions
- /**
- * Set the date and time on the RTC
- * @param {Date} date - Use a javascript Date object
- */
- ExpanderPiRTC.prototype.setDate = function (date) {
- getCentury(date.getFullYear());
- i2cWriteByte(SECONDS, decToBcd(date.getSeconds()));
- i2cWriteByte(MINUTES, decToBcd(date.getMinutes()));
- i2cWriteByte(HOURS, decToBcd(date.getHours()));
- i2cWriteByte(DAYOFWEEK, decToBcd(date.getDay()));
- i2cWriteByte(DAY, decToBcd(date.getDate()));
- i2cWriteByte(MONTH, decToBcd(date.getMonth() + 1));
- i2cWriteByte(YEAR, decToBcd(date.getFullYear() - century));
- };
- /**
- * Read the date and time from the RTC
- * @returns {Date} - Returns the date as a javascript Date object
- */
- ExpanderPiRTC.prototype.readDate = function () {
- var txbuf = new Buffer(1);
- var rxbuf = new Buffer(7);
- txbuf[0] = 0;
- rpio.i2cSetSlaveAddress(rtcAddress);
- rpio.i2cWrite(txbuf);
- rpio.i2cRead(rxbuf, 7);
- var d = new Date(
- bcdToDec(rxbuf[6]) + century,
- bcdToDec(rxbuf[5]),
- bcdToDec(rxbuf[4]),
- bcdToDec(rxbuf[2]),
- bcdToDec(rxbuf[1]),
- bcdToDec(rxbuf[0]),
- 0
- );
- return d;
- };
- /**
- * Enable the output pin
- */
- ExpanderPiRTC.prototype.enableOutput = function () {
- config = updateByte(config, 7, 1);
- config = updateByte(config, 4, 1);
- i2cWriteByte(CONTROL, config);
- };
- /**
- * Disable the output pin
- */
- ExpanderPiRTC.prototype.disableOutput = function () {
- config = updateByte(config, 7, 0);
- config = updateByte(config, 4, 0);
- i2cWriteByte(CONTROL, config);
- };
- /**
- * Set the frequency of the output pin square- wave
- * @param {number} frequency - 1 = 1Hz, 2 = 4.096KHz, 3 = 8.192KHz, 4 = 32.768KHz
- */
- ExpanderPiRTC.prototype.setFrequency = function (frequency) {
- switch (frequency) {
- case 1:
- config = updateByte(config, 0, 0);
- config = updateByte(config, 1, 0);
- break;
- case 2:
- config = updateByte(config, 0, 1);
- config = updateByte(config, 1, 0);
- break;
- case 3:
- config = updateByte(config, 0, 0);
- config = updateByte(config, 1, 1);
- break;
- case 4:
- config = updateByte(config, 0, 1);
- config = updateByte(config, 1, 1);
- break;
- default:
- throw new Error("Argument Out Of Range");
- }
- i2cWriteByte(CONTROL, config);
- };
- /**
- * Write to the memory on the DS1307
- * The DS1307 contains 56 - Byte, battery - backed RAM with Unlimited Writes
- * @param {number} address - 0x08 to 0x3F
- * @param {Uint8Array} valuearray - byte array containing data to be written to memory. Length can not exceed the avaiable address space.
- */
- ExpanderPiRTC.prototype.writeMemory = function (address, valuearray) {
- if (address + valuearray.length <= 0x3f) {
- if (address >= 0x08 && address <= 0x3f) {
- // create a new array with the address at the start of the array
- var data = new Uint8Array(valuearray.length + 1);
- data[0] = address;
- // copy the data from the valuearray into data
- for (var a = 0; a < data.length; a++) {
- data[a + 1] = valuearray[a];
- }
- // write the array to the RTC memory
- rpio.i2cSetSlaveAddress(rtcAddress);
- rpio.i2cWrite(data);
- } else {
- throw new Error("Memory address outside of range: 0x08 to 0x3F");
- }
- } else {
- throw new Error("Array is larger than the available memory space");
- }
- };
- /**
- * Read from the memory on the DS1307
- * The DS1307 contains 56 - Byte, battery - backed RAM with Unlimited Writes
- * @param {Number} address - 0x08 to 0x3F
- * @param {Number} length - Up to 32 bytes. length can not exceed the avaiable address space.
- * @returns {Uint8Array} - Returns an array of the data read from memory
- */
- ExpanderPiRTC.prototype.readMemory = function (address, length) {
- if (address >= 0x08 && address <= 0x3f) {
- if (address <= 0x3f - length) {
- var txbuf = new Uint8Array(1);
- var rxbuf = new Uint8Array(length);
- txbuf[0] = address;
- rpio.i2cSetSlaveAddress(rtcAddress);
- rpio.i2cWrite(txbuf);
- rpio.i2cRead(rxbuf, length);
- return rxbuf;
- } else {
- throw new Error("Memory overflow error: address + length exceeds 0x3F");
- }
- } else {
- throw new Error("Memory address outside of range: 0x08 to 0x3F");
- }
- };
- return ExpanderPiRTC;
- })();
- module.exports = ExpanderPiRTC;
- /**
- * RTC Class
- */
- ExpanderPiBME = (function () {
- // variables
- var bmeAddress = 0x76; // I2C address
- var chip_id = null;
- var power_mode = null;
- var ambient_temperature = null;
- var offset_temp_in_t_fine = null;
- let calibrationData = null;
- /**
- * Initialise the BME connection
- **/
- function ExpanderPiBME() {
- rpio.i2cBegin();
- rpio.i2cSetSlaveAddress(bmeAddress);
- }
- // Private functions
- function setBits(register, mask, position, value) {
- let temp = i2cReadByte(register, 1)[0];
- temp &= ~mask;
- temp |= value << position;
- i2cWriteByte(register, temp);
- }
- function i2cWriteByte(register, val) {
- var txbuf = new Buffer([register, val]);
- rpio.i2cSetSlaveAddress(bmeAddress);
- rpio.i2cWrite(txbuf);
- }
- function i2cReadByte(cmd, length) {
- var txbuf = new Buffer([cmd]);
- var rxbuf = new Buffer(length);
- rpio.i2cSetSlaveAddress(bmeAddress);
- rpio.i2cWrite(txbuf);
- rpio.i2cRead(rxbuf, length);
- return rxbuf;
- }
- function setTempOffset(value) {
- if (value === 0) {
- offset_temp_in_t_fine = 0;
- } else {
- offset_temp_in_t_fine = parseInt(
- ((parseInt(Math.abs(value) * 100) << 8) - 128) / 5
- );
- if (value < 0) {
- offset_temp_in_t_fine = -offset_temp_in_t_fine;
- }
- }
- }
- function setGasStatus(value) {
- bme680Data.gas_settings.run_gas = value;
- setBits(
- constants.CONF_ODR_RUN_GAS_NBC_ADDR,
- constants.RUN_GAS_MSK,
- constants.RUN_GAS_POS,
- value
- );
- }
- function setFilter(value) {
- bme680Data.tph_settings.filter = value;
- setBits(
- constants.CONF_ODR_FILT_ADDR,
- constants.FILTER_MSK,
- constants.FILTER_POS,
- value
- );
- }
- function setHumidityOversample(value) {
- bme680Data.tph_settings.os_hum = value;
- setBits(
- constants.CONF_OS_H_ADDR,
- constants.OSH_MSK,
- constants.OSH_POS,
- value
- );
- }
- function setPressureOversample(value) {
- bme680Data.tph_settings.os_pres = value;
- setBits(
- constants.CONF_T_P_MODE_ADDR,
- constants.OSP_MSK,
- constants.OSP_POS,
- value
- );
- }
- function setTemperatureOversample(value) {
- bme680Data.tph_settings.os_temp = value;
- setBits(
- constants.CONF_T_P_MODE_ADDR,
- constants.OST_MSK,
- constants.OST_POS,
- value
- );
- }
- function softReset() {
- i2cWriteByte(constants.SOFT_RESET_ADDR, constants.SOFT_RESET_CMD);
- }
- function getPowerMode() {
- return i2cReadByte(constants.CONF_T_P_MODE_ADDR, 1)[0];
- }
- function setPowerMode(value, blocking = false, maxPollTimeMs = null) {
- if (value !== constants.SLEEP_MODE && value !== constants.FORCED_MODE) {
- throw new Error("Power mode should be one of SLEEP_MODE or FORCED_MODE");
- }
- if (!maxPollTimeMs) {
- maxPollTimeMs = 10000 * constants.POLL_PERIOD_MS;
- }
- power_mode = value;
- bme680Data.power_mode = power_mode;
- setBits(
- constants.CONF_T_P_MODE_ADDR,
- constants.MODE_MSK,
- constants.MODE_POS,
- value
- );
- //
- let cpt = 0;
- const intervalPowerModeSwitch = setInterval(() => {
- const currentPowerMode = getPowerMode();
- if (!blocking || currentPowerMode === power_mode) {
- clearInterval(intervalPowerModeSwitch);
- return power_mode;
- }
- cpt++;
- if (cpt * constants.POLL_PERIOD_MS >= maxPollTimeMs) {
- clearInterval(intervalPowerModeSwitch);
- return new Error(
- `Power mode could not be updated after a delay of ${
- cpt * constants.POLL_PERIOD_MS
- } ms`
- );
- }
- }, constants.POLL_PERIOD_MS);
- }
- function getCalibrationData() {
- calibrationData = new CalibrationData();
- let calibration = Buffer.concat([
- i2cReadByte(constants.COEFF_ADDR1, constants.COEFF_ADDR1_LEN),
- i2cReadByte(constants.COEFF_ADDR2, constants.COEFF_ADDR2_LEN),
- ]);
- let heat_range = i2cReadByte(constants.ADDR_RES_HEAT_RANGE_ADDR, 1)[0];
- let heat_value = CalibrationData.twos_comp(
- i2cReadByte(constants.ADDR_RES_HEAT_VAL_ADDR, 1)[0],
- 8
- );
- let sw_error = CalibrationData.twos_comp(
- i2cReadByte(constants.ADDR_RANGE_SW_ERR_ADDR, 1)[0],
- 8
- );
- calibrationData.setFromArray(calibration);
- calibrationData.setOther(heat_range, heat_value, sw_error);
- }
- function calcGasResistance(gas_res_adc, gas_range) {
- let var1 = 1340.0 + 5.0 * calibrationData.range_sw_err;
- let var2 = var1 * (1.0 + constants.lookupTable1[gas_range] / 100.0);
- let var3 = 1.0 + constants.lookupTable2[gas_range] / 100.0;
- return (
- 1.0 /
- (var3 *
- 0.000000125 *
- (1 << gas_range) *
- ((gas_res_adc - 512.0) / var2 + 1.0))
- );
- }
- function calcHumidity(humidity_adc) {
- let temp_scaled = (calibrationData.t_fine * 5 + 128) >> 8;
- let var1 =
- humidity_adc -
- calibrationData.par_h1 * 16 -
- (Math.floor((temp_scaled * calibrationData.par_h3) / 100) >> 1);
- let var2 =
- (calibrationData.par_h2 *
- (Math.floor((temp_scaled * calibrationData.par_h4) / 100) +
- Math.floor(
- ((temp_scaled *
- Math.floor((temp_scaled * calibrationData.par_h5) / 100)) >>
- 6) /
- 100
- ) +
- 1 * 16384)) >>
- 10;
- let var3 = var1 * var2;
- let var4 = calibrationData.par_h6 << 7;
- var4 = Math.floor(var4 + (temp_scaled * calibrationData.par_h7) / 100) >> 4;
- let var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
- let var6 = (var4 * var5) >> 1;
- let calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
- return Math.min(Math.max(calc_hum, 0), 100000);
- }
- function calcPressure(pressure_adc) {
- let var1 = (calibrationData.t_fine >> 1) - 64000;
- let var2 =
- ((((var1 >> 2) * (var1 >> 2)) >> 11) * calibrationData.par_p6) >> 2;
- var2 = var2 + ((var1 * calibrationData.par_p5) << 1);
- var2 = (var2 >> 2) + (calibrationData.par_p4 << 16);
- var1 =
- (((((var1 >> 2) * (var1 >> 2)) >> 13) * (calibrationData.par_p3 << 5)) >>
- 3) +
- ((calibrationData.par_p2 * var1) >> 1);
- var1 = var1 >> 18;
- var1 = ((32768 + var1) * calibrationData.par_p1) >> 15;
- let calc_pressure = 1048576 - pressure_adc;
- calc_pressure = (calc_pressure - (var2 >> 12)) * 3125;
- if (calc_pressure >= 1 << 31) {
- calc_pressure = Math.floor(calc_pressure / var1) << 1;
- } else {
- calc_pressure = Math.floor((calc_pressure << 1) / var1);
- }
- var1 =
- (calibrationData.par_p9 *
- (((calc_pressure >> 3) * (calc_pressure >> 3)) >> 13)) >>
- 12;
- var2 = ((calc_pressure >> 2) * calibrationData.par_p8) >> 13;
- let var3 =
- ((calc_pressure >> 8) *
- (calc_pressure >> 8) *
- (calc_pressure >> 8) *
- calibrationData.par_p10) >>
- 17;
- calc_pressure =
- calc_pressure +
- ((var1 + var2 + var3 + (calibrationData.par_p7 << 7)) >> 4);
- return calc_pressure;
- }
- function calcHeaterDuration(duration) {
- if (duration < 0xfc0) {
- let factor = 0;
- while (duration > 0x3f) {
- duration /= 4;
- factor += 1;
- }
- return Number.parseInt(duration + factor * 64);
- }
- return 0xff;
- }
- function calcTemperature(temperature_adc) {
- const var1 = (temperature_adc >> 3) - (calibrationData.par_t1 << 1);
- const var2 = (var1 * calibrationData.par_t2) >> 11;
- let var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
- var3 = (var3 * (calibrationData.par_t3 << 4)) >> 14;
- // Save teperature data for pressure calculations
- calibrationData.t_fine = var2 + var3 + offset_temp_in_t_fine;
- return (calibrationData.t_fine * 5 + 128) >> 8;
- }
- function calcHeaterResistance(temperature) {
- temperature = Math.min(Math.max(temperature, 200), 400);
- let var1 = ((ambient_temperature * calibrationData.par_gh3) / 1000) * 256;
- let var2 =
- (calibrationData.par_gh1 + 784) *
- ((((calibrationData.par_gh2 + 154009) * temperature * 5) / 100 +
- 3276800) /
- 10);
- let var3 = var1 + var2 / 2;
- let var4 = var3 / (calibrationData.res_heat_range + 4);
- let var5 = 131 * calibrationData.res_heat_val + 65536;
- let heatr_res_x100 = (var4 / var5 - 250) * 34;
- return (heatr_res_x100 + 50) / 100;
- }
- function selectGasHeaterProfile(value) {
- if (value > constants.NBCONV_MAX || value < constants.NBCONV_MIN) {
- throw new Error(
- `Profile '${value}' should be between ${constants.NBCONV_MIN} and ${constants.NBCONV_MAX}`
- );
- }
- bme680Data.gas_settings.nb_conv = value;
- setBits(
- constants.CONF_ODR_RUN_GAS_NBC_ADDR,
- constants.NBCONV_MSK,
- constants.NBCONV_POS,
- value
- );
- }
- function setGasHeaterDuration(value, nb_profile = 0) {
- if (nb_profile > constants.NBCONV_MAX || value < constants.NBCONV_MIN) {
- throw new Error(
- `Profile '${nb_profile}' should be between ${constants.NBCONV_MIN} and ${constants.NBCONV_MAX}`
- );
- }
- bme680Data.gas_settings.heatr_dur = value;
- let temp = calcHeaterDuration(bme680Data.gas_settings.heatr_dur);
- i2cWriteByte(constants.GAS_WAIT0_ADDR + nb_profile, temp);
- }
- function setGasHeaterTemperature(value, nb_profile = 0) {
- if (nb_profile > constants.NBCONV_MAX || value < constants.NBCONV_MIN) {
- throw new Error(
- `Profile '${nb_profile}' should be between ${constants.NBCONV_MIN} and ${constants.NBCONV_MAX}`
- );
- }
- bme680Data.gas_settings.heatr_temp = value;
- let temp = Number.parseInt(
- calcHeaterResistance(bme680Data.gas_settings.heatr_temp)
- );
- i2cWriteByte(constants.RES_HEAT0_ADDR + nb_profile, temp);
- }
- async function getSensorData() {
- setPowerMode(constants.FORCED_MODE);
- let i = 0,
- status;
- do {
- status = i2cReadByte(constants.FIELD0_ADDR, 1)[0];
- await new Promise((resolve) => {
- setTimeout(() => {
- resolve();
- }, constants.POLL_PERIOD_MS);
- });
- i++;
- } while (i < 1000 && !(status & constants.NEW_DATA_MSK));
- let regs = i2cReadByte(constants.FIELD0_ADDR, constants.FIELD_LENGTH);
- bme680Data.data.status = regs[0] & constants.NEW_DATA_MSK;
- // Contains the nb_profile used to obtain the current measurement
- bme680Data.data.gas_index = regs[0] & constants.GAS_INDEX_MSK;
- bme680Data.data.meas_index = regs[1];
- const adc_pres = (regs[2] << 12) | (regs[3] << 4) | (regs[4] >> 4);
- const adc_temp = (regs[5] << 12) | (regs[6] << 4) | (regs[7] >> 4);
- const adc_hum = (regs[8] << 8) | regs[9];
- const adc_gas_res = (regs[13] << 2) | (regs[14] >> 6);
- const gas_range = regs[14] & constants.GAS_RANGE_MSK;
- bme680Data.data.status |= regs[14] & constants.GASM_VALID_MSK;
- bme680Data.data.status |= regs[14] & constants.HEAT_STAB_MSK;
- bme680Data.data.heat_stable =
- (bme680Data.data.status & constants.HEAT_STAB_MSK) > 0;
- let temperature = calcTemperature(adc_temp);
- bme680Data.data.temperature = temperature / 100.0;
- ambient_temperature = temperature; // Saved for heater calc;
- bme680Data.ambient_temperature = ambient_temperature;
- bme680Data.data.pressure = calcPressure(adc_pres) / 100.0;
- bme680Data.data.humidity = calcHumidity(adc_hum) / 1000.0;
- bme680Data.data.gas_resistance = calcGasResistance(adc_gas_res, gas_range);
- bme680Data.calibration_data = calibrationData;
- return bme680Data;
- }
- ExpanderPiBME.prototype.initialize = async function () {
- chip_id = i2cReadByte(constants.CHIP_ID_ADDR, 1)[0];
- if (chip_id !== constants.CHIP_ID) {
- const invalidChipIdError = `BME680 Not Found. Invalid CHIP ID: ${chip_id}`;
- console.error(invalidChipIdError);
- throw new Error(invalidChipIdError);
- }
- bme680Data.chip_id = constants.CHIP_ID;
- softReset();
- setPowerMode(constants.SLEEP_MODE);
- getCalibrationData();
- setHumidityOversample(constants.OS_2X);
- setPressureOversample(constants.OS_4X);
- setTemperatureOversample(constants.OS_8X);
- setFilter(constants.FILTER_SIZE_3);
- setGasStatus(constants.ENABLE_GAS_MEAS);
- setTempOffset(0);
- await getSensorData();
- setGasHeaterTemperature(320);
- setGasHeaterDuration(150);
- selectGasHeaterProfile(0);
- };
- ExpanderPiBME.prototype.getSensorData = async function () {
- return await getSensorData();
- };
- ExpanderPiBME.prototype.setTempOffset = function (temp) {
- setTempOffset(temp);
- };
- return ExpanderPiBME;
- })();
- module.exports = ExpanderPiBME;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement