package org.myrobotlab.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceType;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.myrobotlab.service.interfaces.DeviceControl;
import org.myrobotlab.service.interfaces.DeviceController;
import org.myrobotlab.service.interfaces.I2CControl;
import org.myrobotlab.service.interfaces.I2CController;
import org.myrobotlab.service.interfaces.VoltageSensorControl;
import org.myrobotlab.service.interfaces.ServiceInterface;
import org.slf4j.Logger;
//import com.pi4j.io.i2c.I2CBus;
/**
* AdaFruit Ina219 Shield Controller Service
*
* @author Mats
*
* References : https://www.adafruit.com/products/904
*/
public class AdafruitIna219 extends Service implements I2CControl, VoltageSensorControl{
private static final long serialVersionUID = 1L;
public final static Logger log = LoggerFactory.getLogger(AdafruitIna219.class);
transient I2CController controller;
public static final byte INA219_SHUNTVOLTAGE = 0x01;
public static final byte INA219_BUSVOLTAGE = 0x02;
public List<String> deviceAddressList = Arrays.asList("0x40", "0x41", "0x42", "0x43", "0x44", "0x45", "0x46", "0x47", "0x48", "0x49", "0x4A", "0x4B", "0x4C", "0x4D", "0x4E",
"0x4F");
public String deviceAddress = "0x40";
public List<String> deviceBusList = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7");
public String deviceBus = "1";
public int busVoltage = 0;
public double shuntVoltage = 0;
public double current = 0.0;
public double power = 0.0;
// TODO Add methods to calibrate
// Currently only supports setting the shunt resistance to a different
// value than the default, in case it has been exchanged to measure
// a different range of current
public double shuntResistance = 0.1; // expressed in Ohms
public int scaleRange = 32; // 32V = bus full-scale range
public int pga = 8; // 320 mV = shunt full-scale range
public List<String> controllers;
public String controllerName;
private boolean isAttached = false;
public static void main(String[] args) {
LoggingFactory.getInstance().configure();
LoggingFactory.getInstance().setLevel(Level.INFO);
try {
AdafruitIna219 adafruitINA219 = (AdafruitIna219) Runtime.start("AdafruitIna219", "AdafruitIna219");
Runtime.start("gui", "GUIService");
byte msb = (byte)0x83;
byte lsb = (byte)0x00;
double test = (double)((((int)msb) << 8 | (int)lsb & 0xff)) * .01;
log.info(String.format("msb = %s, lsb = %s, test = %s", msb, lsb, test));
// (((int)(readbuffer[0] & 0xff) << 5)) | ((int)(readbuffer[1] >> 3));
} catch (Exception e) {
Logging.logError(e);
}
}
public AdafruitIna219(String n) {
super(n);
refreshControllers();
subscribe(Runtime.getInstance().getName(), "registered", this.getName(), "onRegistered");
}
public void onRegistered(ServiceInterface s) {
refreshControllers();
broadcastState();
}
public List<String> refreshControllers() {
controllers = Runtime.getServiceNamesFromInterface(I2CController.class);
return controllers;
}
/**
* This methods sets the i2c Controller that will be used to communicate with
* the i2c device
*/
// @Override
public boolean setController(String controllerName, String deviceBus, String deviceAddress) {
return setController((I2CController) Runtime.getService(controllerName), deviceBus, deviceAddress);
}
public boolean setController(String controllerName) {
return setController((I2CController) Runtime.getService(controllerName), this.deviceBus, this.deviceAddress);
}
public boolean setController(I2CController controller) {
return setController(controller, this.deviceBus, this.deviceAddress);
}
@Override
public void setController(DeviceController controller) {
setController(controller);
}
/**
* This methods sets the i2c Controller that will be used to communicate with
* the i2c device
*/
public boolean setController(I2CController controller, String deviceBus, String deviceAddress) {
if (controller == null) {
error("setting null as controller");
return false;
}
controllerName = controller.getName();
this.controller = controller;
this.deviceBus = deviceBus;
this.deviceAddress = deviceAddress;
createDevice();
isAttached = true;
log.info(String.format("%s setController %s", getName(), controllerName));
broadcastState();
return true;
}
public void unsetController() {
controller = null;
controllerName = null;
this.deviceBus = null;
this.deviceAddress = null;
isAttached = false;
broadcastState();
}
/**
* This method creates the i2c device
*/
boolean createDevice() {
if (controller != null) {
// controller.releaseI2cDevice(this, Integer.parseInt(deviceBus),
// Integer.decode(deviceAddress));
controller.createI2cDevice(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress));
}
log.info(String.format("Creating device on bus: %s address %s", deviceBus, deviceAddress));
return true;
}
public I2CController getController() {
return controller;
}
public String getControllerName() {
String controlerName = null;
if (controller != null) {
controlerName = controller.getName();
}
return controlerName;
}
public void setDeviceBus(String deviceBus) {
this.deviceBus = deviceBus;
broadcastState();
}
public boolean SetDeviceAddress(String deviceAddress) {
this.deviceAddress = deviceAddress;
broadcastState();
return true;
}
/**
* This method creates the i2c device
*/
public void setDeviceAddress(String DeviceAddress) {
if (controller != null) {
if (deviceAddress != DeviceAddress) {
controller.releaseI2cDevice(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress));
controller.createI2cDevice(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress));
}
}
log.info(String.format("Setting device address to %s", deviceAddress));
this.deviceAddress = DeviceAddress;
}
/**
* This method sets the shunt resistance in ohms Default value is .1 Ohms (
* R100 )
*/
// @Override
public void setShuntResistance(double shuntResistance) {
this.shuntResistance = shuntResistance;
}
// @Override
public double getShuntResistance() {
return shuntResistance;
}
/**
* This method reads and returns the power in milliWatts
*/
public void refresh() {
power = getPower();
broadcastState();
}
// @Override
public double getPower() {
power = getBusVoltage() * getCurrent() / 1000;
return power;
}
/**
* This method reads and returns the shunt current in milliAmperes
*/
// @Override
public double getCurrent() {
current = getShuntVoltage() / shuntResistance;
return current;
}
/**
* This method reads and returns the shunt Voltage in milliVolts
*/
// @Override
public double getShuntVoltage() {
byte[] writebuffer = { INA219_SHUNTVOLTAGE };
byte[] readbuffer = { 0x0, 0x0 };
controller.i2cWrite(this,Integer.parseInt(deviceBus), Integer.decode(deviceAddress), writebuffer, writebuffer.length);
controller.i2cRead(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), readbuffer, readbuffer.length);
// log.info(String.format("getShuntVoltage x%02X x%02X", readbuffer[0],
// readbuffer[1]));
// The shuntVoltage is signed so the MSB can have sign bits, that needs to remain
shuntVoltage = (double)((((int)readbuffer[0]) << 8 | (int)readbuffer[1] & 0xff)) * .01;
return shuntVoltage;
}
/**
* This method reads and returns the bus Voltage in milliVolts
*/
// @Override
public double getBusVoltage() {
byte[] writebuffer = { INA219_BUSVOLTAGE };
byte[] readbuffer = { 0x0, 0x0 };
controller.i2cWrite(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), writebuffer, writebuffer.length);
controller.i2cRead(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), readbuffer, readbuffer.length);
// A bit tricky conversion. The LSB needs to be right shifted 3 bits, so the MSB needs to be left shifted (8-3) = 5 bits
// And bytes are signed in Java so first a mask of 0xff needs to be applied to the MSB to remove the sign
int rawBusVoltage = (((int)readbuffer[0] & 0xff) << 8 | (int)readbuffer[1] & 0xff) >> 3;
log.debug(String.format("Busvoltage high byte = %s, low byte = %s, rawBusVoltagee = %s", readbuffer[0], readbuffer[1], rawBusVoltage));
// LSB = 4mV, so multiply wit 4 to get the volatage in mV
busVoltage = rawBusVoltage * 4;
return busVoltage ;
}
/**
* This static method returns all the details of the class without it having
* to be constructed. It has description, categories, dependencies, and peer
* definitions.
*
* @return ServiceType - returns all the data
*
*/
static public ServiceType getMetaData() {
ServiceType meta = new ServiceType(AdafruitIna219.class.getCanonicalName());
meta.addDescription("Adafruit INA219 Voltage and Current sensor Service");
meta.addCategory("shield", "sensor");
meta.setSponsor("Mats");
return meta;
}
@Override
public boolean isAttached() {
// TODO Auto-generated method stub
return isAttached;
}
}