brewstack/nodeDrivers/i2c/i2c_mraa.js

/**
 * I2C Driver.
 * @module i2c
 * @author Dave Leitch
 * @requires brewlog
 * @requires node-mcp23017
 * @requires child_process
 * @desc This module provides access to all I2C GPIO expansion pins via a 32 bit bus.
 * The expansion module has 2 ports and each port has 2 banks which are 8 bits wide. 
 * These are mapped onto a single 32 bit value that can be read and written.
 * http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf

Usage: i2cset [-f] [-y] [-m MASK] [-r] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]
  I2CBUS is an integer or an I2C bus name
  ADDRESS is an integer (0x03 - 0x77)
  MODE is one of:
    c (byte, no value)
    b (byte data, default)
    w (word data)
    i (I2C block data)
    s (SMBus block data)

E.g. Switch on watchdog led  =>  
	DIR:0=out: 
	i2cset -y 1 0x21 0x0  0xBF
	i2cset -y 1 0x21 0x12 0x40
     Close Valve 0
	DIR:0=out:
        i2cset -y 1 0x20 0x1  0xFE
	i2cset -y 1 0x20 0x13 0x1
     Switch On Heater
	DIR:0=out:
	i2cset -y 1 0x21 0x0 0xFD   
        i2cset -y 1 0x21 0x12 0x2	

        	chip    data    value   pin
Flow 7		0x21	0x13	0x80	31	In
Flow 6		0x21	0x13	0x40	30	In	
Flow 5		0x21	0x13	0x20	29	In	
Flow 4		0x21	0x13	0x10	28	In	
Flow 3		0x21	0x13	0x8	27	In	
Heater(was Flow 2)0x21	0x13	0x4	26	In
Flow 1		0x21	0x13	0x2	25	In
Flow 0		0x21	0x13	0x1	24	In	

                chip    data    value   pin
Watchdog Halt	0x21	0x12	0x80	23	In	
Watchdog LED	0x21	0x12	0x40	22	Out	1 = On
//Heater	0x21	0x12	0x20	21	Out	1 = On
//Heater	0x21	0x12	0x10	16	Out	1 = On
//Heater        0x21	0x12	0x02	17	Out	1 = On

Relay ?	   	0x20	0x13	0x80	15	Out	
Relay ?		0x20	0x13	0x40	14	Out	
Relay ?		0x20	0x13	0x20	13	Out	
Pump 0		0x20	0x13	0x10	12	Out	0 = On
Valve 6		0x20	0x13	0x8	11	Out	0 = Open 
Valve 4		0x20	0x13	0x4	10	Out	0 = Open 
Valve 2		0x20	0x13	0x2	9	Out	0 = Open 
valve 0		0x20	0x13	0x1	8	Out	0 = Open 

Valve 1		0x20	0x12	0x80	7	Out	0 = Open 
Valve 3		0x20	0x12	0x40	6	Out	0 = Open
Valve 5		0x20	0x12	0x20	5	Out	0 = Open 
Valve 7		0x20	0x12	0x10	4	Out	0 = Open
Pump 1		0x20	0x12	0x8	3	Out	
Relay ?		0x20	0x12	0x4	2	Out	
Relay ?		0x20	0x12	0x2	1	Out	
Relay ?		0x20	0x12	0x1	0	Out	
 */

const brewlog = require('../../../common/brewlog.js');
const brewdefs = require('../../../common/brewdefs.js');
let mraa;
let i2c;

let dataDir  = [0xFF, 0xFF, 0xFF, 0xFF];
let dataByte = [0x00, 0x00, 0x00, 0x00];

/**
 * Write a bit into the register
 | @param {Number} bankAddr 
 * @param {Number} data 
 * @param {Number} bit 
 * @param {Number} value 
 */	
function writeReg(bankAddr, data, bit, value){
	brewlog.debug("writeReg", `0x${bankAddr.toString(16)}, 0x${data.toString(16)}, ${bit}, ${value}`);
	
	const mask = 1 << bit;
	let result;
	if (value == 1){
		result = (data | mask);
	}else if (value == 0){
		result = (data & ~mask);
	}else{
		brewlog.critical("writeReg", `${value}`)	
	}
	i2c.writeReg(bankAddr, result);
	//console.log("[0x"+bankAddr.toString(16),"]<=0x"+result.toString(16))
	return result;
}

/**
 * 
 * @param {Number} byte 
 * @param {Number} bit 
 */
function getBit(byte, bit){
	const result = (byte & (1 << bit)) >> bit;
	//console.log("bit",bit,"of",byte,"=",result)
	return result; 
}

module.exports = { 
	start({sim}) {
		if (sim.simulate){
			// @ts-ignore
			mraa = require('../../../sim/mraa.js');
		}else{
			// @ts-ignore
			mraa = require('mraa');
		}
		i2c = new mraa.I2c(0);

		//Initialise all as inputs 
		i2c.address(0x20);
		i2c.writeReg(0x0, dataDir[0]);
		i2c.writeReg(0x1, dataDir[1]);
		i2c.address(0x21);
		i2c.writeReg(0x0, dataDir[2]);
		i2c.writeReg(0x1, dataDir[3]);

		module.exports.DIR_INPUT =  mraa.DIR_IN;
		module.exports.DIR_OUTPUT = mraa.DIR_OUT;
		module.exports.Gpio = mraa.Gpio;

		//console.log("i2c started");
	},
	
	/** Set or clear any bit
	 * @param {number} bit - Bit number [0:31]
	 * @param {number} value - 0 or 1
	 */
    writeBit(bit, value) {
		brewlog.debug("writeBit", `${bit}, ${value}`);
		if (bit < 16){
			i2c.address(0x20);
			if (bit < 8){
				dataByte[0] = writeReg(0x12, dataByte[0], bit, value);	
			}else{		
				dataByte[1] = writeReg(0x13, dataByte[1], bit-8, value);	
			}
		}else{	
			i2c.address(0x21);
			if (bit < 24){
				dataByte[2] = writeReg(0x12, dataByte[2], bit-16, value);		
			}else{		
				dataByte[3] = writeReg(0x13, dataByte[3], bit-24, value);		
			}
		}
	},
	
	/** Read any single bit
	 * @param {number} bit - Bit number [0:31]
	 */
    readBit(bit) {
		let result;
		if (bit < 16){
			i2c.address(0x20);
			if (bit < 8){
				dataByte[0] = i2c.readReg(0x12);
				//console.log("[byte0]=>"+dataByte[0])
				result = getBit(dataByte[0], bit); 
			}else{		
				dataByte[1] = i2c.readReg(0x13);
				//console.log("[byte1]=>"+dataByte[1])
				result = getBit(dataByte[1], bit-8); 
			}
		}else{	
			i2c.address(0x21);
			if (bit < 24){
				dataByte[2] = i2c.readReg(0x12);		
				//console.log("[byte2]=>"+dataByte[2])
				result = getBit(dataByte[2], bit-16); 
			}else{		
				dataByte[3] = i2c.readReg(0x13);		
				//console.log("[byte3]=>"+dataByte[3])
				result = getBit(dataByte[3], bit-24); 
			}
		}

		//console.log("bit[",bit,"]=>"+result)
		
		return result;
	},
	
	/** Toggle any bit
	 * @param {number} n - Bit number [0:31]
	 */
	toggleBit(n) {
		const b = this.readBit(n);
		if (b === 0){
			this.writeBit(n, 1);
		}else{
			this.writeBit(n, 0);
		}
	},
	
	/** Set direction of a single bit
	 * @param {number} bit - Bit number [0:31]
	 * @param {number} value - DIR_INPUT | DIR_OUTPUT
	 */
	setDir(bit, value) {
		brewlog.debug("setDir", `${bit} = ${value}`);

		if (bit < 16){
			i2c.address(0x20);
			if (bit < 8){
				dataDir[0] = writeReg(0x0, dataDir[0], bit, value); 
			}else{		
				dataDir[1] = writeReg(0x1, dataDir[1], bit-8, value); 
			}
		}else {
			i2c.address(0x21);
			if (bit < 24){
				dataDir[2] = writeReg(0x0, dataDir[2], bit-16, value); 
			}else{		
				dataDir[3] = writeReg(0x1, dataDir[3], bit-24, value); 
			}
		}
	},
  
  
    /**
     * @desc Initialise an individual bit.
	 */
    init(bitInfo) {
		//console.log(bitInfo);
		brewlog.debug("init");
		
		this.setDir(bitInfo.number, bitInfo.dir);
		
		if (bitInfo.dir === this.DIR_INPUT){
			this.setDir(bitInfo.number, bitInfo.dir);
		}else 
		if (bitInfo.dir === this.DIR_OUTPUT){
			this.writeBit(bitInfo.number, bitInfo.value);
			this.setDir(bitInfo.number, bitInfo.dir);
		}else{
			brewlog.error("Error initialising i2c", bitInfo);
		}	
	},
	
	getWord() {
		i2c.address(0x20);
		const byte0 = i2c.readReg(0x12);
		const byte1 = i2c.readReg(0x13);
		i2c.address(0x21);
		const byte2 = i2c.readReg(0x12);		
		const byte3 = i2c.readReg(0x13);		
	
		const word = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
	
		return word;
	}
}