package org.myrobotlab.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.data.PinData;
import org.myrobotlab.service.interfaces.DeviceController;
import org.myrobotlab.service.interfaces.I2CControl;
import org.myrobotlab.service.interfaces.I2CController;
import org.myrobotlab.service.interfaces.PinArrayControl;
import org.myrobotlab.service.interfaces.PinArrayListener;
import org.myrobotlab.service.interfaces.PinDefinition;
import org.myrobotlab.service.interfaces.PinListener;
import org.myrobotlab.service.interfaces.ServiceInterface;
import org.slf4j.Logger;
/**
* AdaFruit Ina219 Shield Controller Service
*
* @author Mats
*
* https://learn.adafruit.com/adafruit-4-channel-adc-breakouts
* /programming The code here is to a large extent based on the Adafruit
* C++ libraries here: https://github.com/adafruit/Adafruit_ADS1X15
*
* Next follows the license agreement from Adafruit that this service is
* based on. It has been converted fron C++ to Java.
*
* Software License Agreement (BSD License)
*
* Copyright (c) 2012, Adafruit Industries All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with
* the distribution. 3. Neither the name of the copyright holders nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public class Ads1115 extends Service implements I2CControl, PinArrayControl {
/**
* Publisher - Publishes pin data at a regulat interval
*
*/
public class Publisher extends Thread {
public Publisher(String name) {
super(String.format("%s.publisher", name));
}
@Override
public void run() {
log.info(String.format("New publisher instance started at a sample frequency of %s Hz", sampleFreq));
long sleepTime = 1000 / (long) sampleFreq;
isPublishing = true;
try {
while (isPublishing) {
Thread.sleep(sleepTime);
publishPinData();
}
} catch (Exception e) {
if (e instanceof InterruptedException) {
log.info("Shutting down Publisher");
} else {
isPublishing = false;
logException(e);
}
}
}
void publishPinData() {
PinData[] pinArray = new PinData[pinDataCnt];
for (int i = 0; i < pinArray.length; ++i) {
PinData pinData = new PinData(i, read(i));
pinArray[i] = pinData;
int address = pinData.getAddress();
// handle individual pins
if (pinListeners.containsKey(address)) {
List<PinListener> list = pinListeners.get(address);
for (int j = 0; j < list.size(); ++j) {
PinListener pinListner = list.get(j);
if (pinListner.isLocal()) {
pinListner.onPin(pinData);
} else {
invoke("publishPin", pinData);
}
}
}
}
// publish array
invoke("publishPinArray", new Object[] { pinArray });
}
}
// Publisher
boolean isPublishing = false;
transient Thread publisher = null;
int pinDataCnt = 4;
//
private static final long serialVersionUID = 1L;
public final static Logger log = LoggerFactory.getLogger(Ads1115.class);
transient I2CController controller;
/*
* public static final byte INA219_SHUNTVOLTAGE = 0x01; public static final
* byte INA219_BUSVOLTAGE = 0x02;
*/
public List<String> deviceAddressList = Arrays.asList("0x48", "0x49", "0x4A", "0x4B");
public String deviceAddress = "0x48";
public List<String> deviceBusList = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7");
public String deviceBus = "1";
public int adc0 = 0;
public int adc1 = 0;
public int adc2 = 0;
public int adc3 = 0;
public double voltage0 = 0;
public double voltage1 = 0;
public double voltage2 = 0;
public double voltage3 = 0;
private int m_conversionDelay;
private int m_bitShift;
private int m_gain = 0;
private double m_fs = 0;
public List<String> controllers;
public String controllerName;
private boolean isAttached = false;
/*
* =========================================================================
* CONVERSION DELAY (in mS)
* -----------------------------------------------------------------------
*/
static byte ADS1015_CONVERSIONDELAY = 1;
static byte ADS1115_CONVERSIONDELAY = 8;
/* ========================================================================= */
/*
* =========================================================================
* POINTER REGISTER
* -----------------------------------------------------------------------
*/
static byte ADS1015_REG_POINTER_MASK = 0x03;
static byte ADS1015_REG_POINTER_CONVERT = 0x00;
static byte ADS1015_REG_POINTER_CONFIG = 0x01;
static byte ADS1015_REG_POINTER_LOWTHRESH = 0x02;
static byte ADS1015_REG_POINTER_HITHRESH = 0x03;
/* ========================================================================= */
/*
* =========================================================================
* CONFIG REGISTER
* -----------------------------------------------------------------------
*/
static int ADS1015_REG_CONFIG_OS_MASK = 0x8000;
static int ADS1015_REG_CONFIG_OS_SINGLE = 0x8000; // Write:
// Set
// to
// start
// a
// single-conversion
static int ADS1015_REG_CONFIG_OS_BUSY = 0x0000; // Read:
// Bit
// =
// 0
// when
// conversion is in progress
static int ADS1015_REG_CONFIG_OS_NOTBUSY = 0x8000; // Read:
// Bit
// =
// 1
// when
// device is not
// performing a
// conversion
static int ADS1015_REG_CONFIG_MUX_MASK = 0x7000;
static int ADS1015_REG_CONFIG_MUX_DIFF_0_1 = 0x0000; // Differential
// P
// =
// AIN0,
// N = AIN1
// (default;
static int ADS1015_REG_CONFIG_MUX_DIFF_0_3 = 0x1000; // Differential
// P
// =
// AIN0,
// N = AIN3
static int ADS1015_REG_CONFIG_MUX_DIFF_1_3 = 0x2000; // Differential
// P
// =
// AIN1,
// N = AIN3
static int ADS1015_REG_CONFIG_MUX_DIFF_2_3 = 0x3000; // Differential
// P
// =
// AIN2,
// N = AIN3
static int ADS1015_REG_CONFIG_MUX_SINGLE_0 = 0x4000; // Single-ended
// AIN0
static int ADS1015_REG_CONFIG_MUX_SINGLE_1 = 0x5000; // Single-ended
// AIN1
static int ADS1015_REG_CONFIG_MUX_SINGLE_2 = 0x6000; // Single-ended
// AIN2
static int ADS1015_REG_CONFIG_MUX_SINGLE_3 = 0x7000; // Single-ended
// AIN3
static int ADS1015_REG_CONFIG_PGA_MASK = 0x0E00;
static final int ADS1015_REG_CONFIG_PGA_6_144V = 0x0000; // +/-6.144V
// range
// = Gain
// 2/3
static final int ADS1015_REG_CONFIG_PGA_4_096V = 0x0200; // +/-4.096V
// range
// = Gain 1
static final int ADS1015_REG_CONFIG_PGA_2_048V = 0x0400; // +/-2.048V
// range
// = Gain 2
// (default)
static final int ADS1015_REG_CONFIG_PGA_1_024V = 0x0600; // +/-1.024V
// range
// = Gain 4
static final int ADS1015_REG_CONFIG_PGA_0_512V = 0x0800; // +/-0.512V
// range
// = Gain 8
static final int ADS1015_REG_CONFIG_PGA_0_256V = 0x0A00; // +/-0.256V
// range
// = Gain
// 16
static int ADS1015_REG_CONFIG_MODE_MASK = 0x0100;
static int ADS1015_REG_CONFIG_MODE_CONTIN = 0x0000; // Continuous
// conversion
// mode
static int ADS1015_REG_CONFIG_MODE_SINGLE = 0x0100; // Power-down
// single-shot
// mode (default)
static int ADS1015_REG_CONFIG_DR_MASK = 0x00E0;
static int ADS1015_REG_CONFIG_DR_128SPS = 0x0000; // 128
// samples
// per
// second
static int ADS1015_REG_CONFIG_DR_250SPS = 0x0020; // 250
// samples
// per
// second
static int ADS1015_REG_CONFIG_DR_490SPS = 0x0040; // 490
// samples
// per
// second
static int ADS1015_REG_CONFIG_DR_920SPS = 0x0060; // 920
// samples
// per
// second
static int ADS1015_REG_CONFIG_DR_1600SPS = 0x0080; // 1600
// samples
// per
// second
// (default)
static int ADS1015_REG_CONFIG_DR_2400SPS = 0x00A0; // 2400
// samples
// per
// second
static int ADS1015_REG_CONFIG_DR_3300SPS = 0x00C0; // 3300
// samples
// per
// second
static int ADS1015_REG_CONFIG_CMODE_MASK = 0x0010;
static int ADS1015_REG_CONFIG_CMODE_TRAD = 0x0000; // Traditional
// comparator
// with hysteresis
// (default)
static int ADS1015_REG_CONFIG_CMODE_WINDOW = 0x0010; // Window
// comparator
static int ADS1015_REG_CONFIG_CPOL_MASK = 0x0008;
static int ADS1015_REG_CONFIG_CPOL_ACTVLOW = 0x0000; // ALERT/RDY
// pin
// is
// low
// when active
// (default)
static int ADS1015_REG_CONFIG_CPOL_ACTVHI = 0x0008; // ALERT/RDY
// pin
// is
// high
// when active
static int ADS1015_REG_CONFIG_CLAT_MASK = 0x0004; // Determines
// if
// ALERT/RDY
// pin latches once
// asserted
static int ADS1015_REG_CONFIG_CLAT_NONLAT = 0x0000; // Non-latching
// comparator
// (default)
static int ADS1015_REG_CONFIG_CLAT_LATCH = 0x0004; // Latching
// comparator
static int ADS1015_REG_CONFIG_CQUE_MASK = 0x0003;
static int ADS1015_REG_CONFIG_CQUE_1CONV = 0x0000; // Assert
// ALERT/RDY
// after
// one conversions
static int ADS1015_REG_CONFIG_CQUE_2CONV = 0x0001; // Assert
// ALERT/RDY
// after
// two conversions
static int ADS1015_REG_CONFIG_CQUE_4CONV = 0x0002; // Assert
// ALERT/RDY
// after
// four conversions
static int ADS1015_REG_CONFIG_CQUE_NONE = 0x0003; // Disable
// the
// comparator
// and put ALERT/RDY in
// high
// state (default)
static int GAIN_TWOTHIRDS = ADS1015_REG_CONFIG_PGA_6_144V;
static int GAIN_ONE = ADS1015_REG_CONFIG_PGA_4_096V;
static int GAIN_TWO = ADS1015_REG_CONFIG_PGA_2_048V;
static int GAIN_FOUR = ADS1015_REG_CONFIG_PGA_1_024V;
static int GAIN_EIGHT = ADS1015_REG_CONFIG_PGA_0_512V;
static int GAIN_SIXTEEN = ADS1015_REG_CONFIG_PGA_0_256V;
/* ========================================================================= */
/**
* pin named map of all the pins on the board
*/
Map<String, PinDefinition> pinMap = null;
/**
* the definitive sequence of pins - "true address"
*/
Map<Integer, PinDefinition> pinIndex = null;
transient Map<String, PinArrayListener> pinArrayListeners = new HashMap<String, PinArrayListener>();
/**
* map of pin listeners
*/
transient Map<Integer, List<PinListener>> pinListeners = new HashMap<Integer, List<PinListener>>();
/**
* the map of pins which the pin listeners are listening too - if the set is
* null they are listening to "any" published pin
*/
Map<String, Set<Integer>> pinSets = new HashMap<String, Set<Integer>>();
double sampleFreq = 1; // Set
// default
// sample
// rate
// to
// 1
// Hz
// //
// Sample
// rate
// in
// hZ.
public static void main(String[] args) {
LoggingFactory.getInstance().configure();
LoggingFactory.getInstance().setLevel(Level.INFO);
try {
Ads1115 ads1115 = (Ads1115) Runtime.start("Ads1115", "Ads1115");
Runtime.start("gui", "GUIService");
} catch (Exception e) {
Logging.logError(e);
}
}
public Ads1115(String n) {
super(n);
createPinList();
refreshControllers();
subscribe(Runtime.getInstance().getName(), "registered", this.getName(), "onRegistered");
init_ADS1115();
}
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;
isAttached = false;
broadcastState();
}
public I2CController getController() {
return controller;
}
/**
* 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 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 reads all four A/D pins
*/
public void refresh() {
adc0 = readADC_SingleEnded(0);
adc1 = readADC_SingleEnded(1);
adc2 = readADC_SingleEnded(2);
adc3 = readADC_SingleEnded(3);
convertToVoltage();
broadcastState();
}
void convertToVoltage() {
int max = 256 * 128;
voltage0 = adc0 * m_fs / max;
voltage1 = adc1 * m_fs / max;
voltage2 = adc2 * m_fs / max;
voltage3 = adc3 * m_fs / max;
}
/**
* This method initiates the ADS1015
*/
public void init_ADS1015() {
m_conversionDelay = ADS1015_CONVERSIONDELAY;
m_bitShift = 4;
m_gain = GAIN_TWOTHIRDS; /* +/- 6.144V range (limited to VDD +0.3V max!) */
this.m_fs = 6.144;
}
/**
* This method initiates the ADS1115
*/
public void init_ADS1115() {
m_conversionDelay = ADS1115_CONVERSIONDELAY;
m_bitShift = 0;
m_gain = GAIN_TWOTHIRDS; /* +/- 6.144V range (limited to VDD +0.3V max!) */
m_fs = 6.144;
}
/**
* ************************************************************************
*
* Sets the gain and input voltage range
*
* /
**************************************************************************/
public void setGain(int gain) {
m_gain = gain;
switch (gain) {
case ADS1015_REG_CONFIG_PGA_6_144V:
m_fs = 6.144;
break;
case ADS1015_REG_CONFIG_PGA_4_096V:
m_fs = 4.096;
break;
case ADS1015_REG_CONFIG_PGA_2_048V:
m_fs = 2.096;
break;
case ADS1015_REG_CONFIG_PGA_1_024V:
m_fs = 1.024;
break;
case ADS1015_REG_CONFIG_PGA_0_512V:
m_fs = 0.512;
break;
case ADS1015_REG_CONFIG_PGA_0_256V:
m_fs = 0.256;
break;
}
}
/**
* ************************************************************************
*
* Gets a gain and input voltage range
*
* /
**************************************************************************/
public int getGain() {
return m_gain;
}
/**
* This method reads and returns the Voltage in milliVolts
*/
public int readADC_SingleEnded(int channel) {
if (channel > 3) {
return 0;
}
// Start with default values
int config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator
// (default val)
ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low
// (default val)
ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator
// (default val)
ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second
// (default)
ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)
// Set PGA/voltage range
config |= m_gain;
switch (channel) {
case 0:
config |= ADS1015_REG_CONFIG_MUX_SINGLE_0;
break;
case 1:
config |= ADS1015_REG_CONFIG_MUX_SINGLE_1;
break;
case 2:
config |= ADS1015_REG_CONFIG_MUX_SINGLE_2;
break;
case 3:
config |= ADS1015_REG_CONFIG_MUX_SINGLE_3;
break;
}
// Set 'start single-conversion' bit
config |= ADS1015_REG_CONFIG_OS_SINGLE;
// Write config register to the ADC
writeRegister(ADS1015_REG_POINTER_CONFIG, config);
// Wait for the conversion to complete
sleep(m_conversionDelay);
// Read the conversion results
// Shift 12-bit results right 4 bits for the ADS1015
return readRegister(ADS1015_REG_POINTER_CONVERT) >> m_bitShift;
}
/**************************************************************************/
/*
* !
*
* @brief Reads the conversion results, measuring the voltage difference
* between the P (AIN0) and N (AIN1) input. Generates a signed value since the
* difference can be either positive or negative.
*/
/**************************************************************************/
public int readADC_Differential_0_1() {
// Start with default values
int config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator
// (default val)
ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low
// (default val)
ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator
// (default val)
ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second
// (default)
ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)
// Set PGA/voltage range
config |= m_gain;
// Set channels
config |= ADS1015_REG_CONFIG_MUX_DIFF_0_1; // AIN0 = P, AIN1 = N
// Set 'start single-conversion' bit
config |= ADS1015_REG_CONFIG_OS_SINGLE;
// Write config register to the ADC
writeRegister(ADS1015_REG_POINTER_CONFIG, config);
// Wait for the conversion to complete
sleep(m_conversionDelay);
// Read the conversion results
int res = readRegister(ADS1015_REG_POINTER_CONVERT);
if (m_bitShift == 0) {
return res;
} else {
// Shift 12-bit results right 4 bits for the ADS1015,
// making sure we keep the sign bit intact
return res / 16;
}
}
/**************************************************************************/
/*
* !
*
* @brief Reads the conversion results, measuring the voltage difference
* between the P (AIN2) and N (AIN3) input. Generates a signed value since the
* difference can be either positive or negative.
*/
/**************************************************************************/
public int readADC_Differential_2_3() {
// Start with default values
int config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator
// (default val)
ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low
// (default val)
ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator
// (default val)
ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second
// (default)
ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)
// Set PGA/voltage range
config |= m_gain;
// Set channels
config |= ADS1015_REG_CONFIG_MUX_DIFF_2_3; // AIN2 = P, AIN3 = N
// Set 'start single-conversion' bit
config |= ADS1015_REG_CONFIG_OS_SINGLE;
// Write config register to the ADC
writeRegister(ADS1015_REG_POINTER_CONFIG, config);
// Wait for the conversion to complete
sleep(m_conversionDelay);
// Read the conversion results
int res = readRegister(ADS1015_REG_POINTER_CONVERT) >> m_bitShift;
if (m_bitShift == 0) {
return res;
} else {
// Shift 12-bit results right 4 bits for the ADS1015,
// making sure we keep the sign bit intact
return res / 16;
}
}
/**************************************************************************/
/*
* !
*
* @brief Sets up the comparator to operate in basic mode, causing the
* ALERT/RDY pin to assert (go from high to low) when the ADC value exceeds
* the specified threshold. This will also set the ADC in continuous
* conversion mode.
*/
/**************************************************************************/
public void startComparator_SingleEnded(int channel, int threshold) {
// Start with default values
int config = ADS1015_REG_CONFIG_CQUE_1CONV | // Comparator enabled and
// asserts on 1 match
ADS1015_REG_CONFIG_CLAT_LATCH | // Latching mode
ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low
// (default val)
ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator
// (default val)
ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second
// (default)
ADS1015_REG_CONFIG_MODE_CONTIN | // Continuous conversion mode
ADS1015_REG_CONFIG_MODE_CONTIN; // Continuous conversion mode
// Set PGA/voltage range
config |= m_gain;
// Set single-ended input channel
switch (channel) {
case (0):
config |= ADS1015_REG_CONFIG_MUX_SINGLE_0;
break;
case (1):
config |= ADS1015_REG_CONFIG_MUX_SINGLE_1;
break;
case (2):
config |= ADS1015_REG_CONFIG_MUX_SINGLE_2;
break;
case (3):
config |= ADS1015_REG_CONFIG_MUX_SINGLE_3;
break;
}
// Set the high threshold register
// Shift 12-bit results left 4 bits for the ADS1015
writeRegister(ADS1015_REG_POINTER_HITHRESH, threshold << m_bitShift);
// Write config register to the ADC
writeRegister(ADS1015_REG_POINTER_CONFIG, config);
}
/**************************************************************************/
/*
* !
*
* @brief In order to clear the comparator, we need to read the conversion
* results. This function reads the last conversion results without changing
* the config value.
*/
/**************************************************************************/
public int getLastConversionResults() {
// Wait for the conversion to complete
sleep(ADS1115_CONVERSIONDELAY);
// Read the conversion results
int res = readRegister(ADS1015_REG_POINTER_CONVERT) >> m_bitShift;
if (m_bitShift == 0) {
return res;
} else {
// Shift 12-bit results right 4 bits for the ADS1015,
// making sure we keep the sign bit intact
return res / 16;
}
}
void i2cWrite(int reg) {
byte[] writebuffer = { (byte) reg };
controller.i2cWrite(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), writebuffer, writebuffer.length);
}
void writeRegister(int reg, int value) {
byte[] writebuffer = { (byte) reg, (byte) (value >> 8), (byte) (value & 0xff) };
controller.i2cWrite(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), writebuffer, writebuffer.length);
}
int readRegister(int reg) {
i2cWrite(ADS1015_REG_POINTER_CONVERT);
byte[] readbuffer = new byte[2];
controller.i2cRead(this, Integer.parseInt(deviceBus), Integer.decode(deviceAddress), readbuffer, readbuffer.length);
return ((int) readbuffer[0]) << 8 | (int) (readbuffer[1] & 0xff);
}
@Override
public boolean isAttached() {
return isAttached;
}
@Override
public List<PinDefinition> getPinList() {
List<PinDefinition> list = new ArrayList<PinDefinition>(pinIndex.values());
return list;
}
@Override
public int read(int address) {
pinIndex.get(address).setValue(readADC_SingleEnded(address));
return pinIndex.get(address).getValue();
}
@Override
public int read(String pinName) {
return read(pinNameToAddress(pinName));
}
@Override
public void pinMode(int address, String mode) {
if (mode != null && mode.equalsIgnoreCase("INPUT")) {
} else {
log.error("Ads1115 only supports INPUT mode");
}
}
@Override
public void write(int address, int value) {
log.error("Ads1115 only supports read, not write");
}
@Override
public PinData publishPin(PinData pinData) {
// caching last value
pinIndex.get(pinData.getAddress()).setValue(pinData.getValue());
return pinData;
}
/**
* publish all read pin data in one array at once
*/
@Override
public PinData[] publishPinArray(PinData[] pinData) {
return pinData;
}
@Override
public void attach(String listener, int pinAddress) {
attach((PinListener) Runtime.getService(listener), pinAddress);
}
@Override
public void attach(PinListener listener, int pinAddress) {
String name = listener.getName();
if (listener.isLocal()) {
List<PinListener> list = null;
if (pinListeners.containsKey(pinAddress)) {
list = pinListeners.get(pinAddress);
} else {
list = new ArrayList<PinListener>();
}
list.add(listener);
pinListeners.put(pinAddress, list);
} else {
// setup for pub sub
// FIXME - there is an architectual problem here
// locally it works - but remotely - outbox would need to know
// specifics of
// the data its sending
addListener("publishPin", name, "onPin");
}
}
@Override
public void attach(PinArrayListener listener) {
pinArrayListeners.put(listener.getName(), listener);
}
@Override
public void enablePin(int address) {
if (controller == null) {
error("must be connected to enable pins");
return;
}
log.info(String.format("enablePin %s", address));
PinDefinition pin = pinIndex.get(address);
pin.setEnabled(true);
invoke("publishPinDefinition", pin);
if (!isPublishing) {
log.info(String.format("Starting a new publisher instance"));
publisher = new Publisher(getName());
publisher.start();
}
}
@Override
public void disablePin(int address) {
if (controller == null) {
log.error("Must be connected to disable pins");
return;
}
PinDefinition pin = pinIndex.get(address);
pin.setEnabled(false);
invoke("publishPinDefinition", pin);
}
@Override
public void disablePins() {
for (int i = 0; i < pinDataCnt; i++) {
disablePin(i);
}
if (isPublishing) {
isPublishing = false;
}
}
public Map<String, PinDefinition> createPinList() {
pinMap = new HashMap<String, PinDefinition>();
pinIndex = new HashMap<Integer, PinDefinition>();
for (int i = 0; i < pinDataCnt; ++i) {
PinDefinition pindef = new PinDefinition();
String name = String.format("A%d", i);
pindef.setRx(false);
pindef.setTx(false);
pindef.setAnalog(true);
pindef.setPwm(false);
pindef.setName(name);
pindef.setAddress(i);
pindef.setMode("INPUT");
pinMap.put(name, pindef);
pinIndex.put(i, pindef);
}
return pinMap;
}
public Integer pinNameToAddress(String pinName) {
if (!pinMap.containsKey(pinName)) {
error("no pin %s exists", pinName);
return null;
}
return pinMap.get(pinName).getAddress();
}
/**
* Set the sample rate in Hz, I.e the number of polls per second
*
* @param rate
* @return
*/
public double setSampleRate(double rate) {
if (rate < 0) {
log.error(String.format("setSampleRate. Rate must be > 0. Ignored %s, returning to %s", rate, this.sampleFreq));
return this.sampleFreq;
}
this.sampleFreq = rate;
return rate;
}
/**
* method to communicate changes in pinmode or state changes
* @param pinDef
* @return
*/
public PinDefinition publishPinDefinition(PinDefinition pinDef){
return pinDef;
}
/**
* 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(Ads1115.class.getCanonicalName());
meta.addDescription("Adafruit ADS1115 AD Converter");
meta.addCategory("shield", "sensor");
meta.setSponsor("Mats");
return meta;
}
@Override
// TODO Implement individula sample rates per pin
public void enablePin(int address, int rate) {
setSampleRate(rate);
enablePin(address);
}
}