Merge "* Add WriteBulk and ReadOnly to C++ I2C"

This commit is contained in:
Brad Miller (WPI)
2014-06-26 07:05:26 -07:00
committed by Gerrit Code Review
21 changed files with 430 additions and 1392 deletions

View File

@@ -17,7 +17,7 @@ import edu.wpi.first.wpilibj.communication.UsageReporting;
*/
public class ADXL345_I2C extends SensorBase {
private static final byte kAddress = 0x3A;
private static final byte kAddress = 0x1D;
private static final byte kPowerCtlRegister = 0x2D;
private static final byte kDataFormatRegister = 0x31;
private static final byte kDataRegister = 0x32;
@@ -76,10 +76,9 @@ public class ADXL345_I2C extends SensorBase {
*
* @param range The range (+ or -) that the accelerometer will measure.
*/
public ADXL345_I2C(DataFormat_Range range) {
DigitalModule module = DigitalModule.getInstance(1);
m_i2c = module.getI2C(kAddress);
public ADXL345_I2C(I2C.Port port, DataFormat_Range range) {
m_i2c = new I2C(port, kAddress);
// Turn on the measurements
m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure);
// Specify the data format to read

View File

@@ -526,17 +526,6 @@ public class DigitalModule extends Module {
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Return an I2C object for this digital module
*
* @param address
* The device address.
* @return The associated I2C object.
*/
public I2C getI2C(final int address) {
return new I2C(this, address);
}
/**
* Get the loop timing of the Digital Module
*

View File

@@ -1,385 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
import edu.wpi.first.wpilibj.communication.UsageReporting;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.parsing.ISensor;
import edu.wpi.first.wpilibj.tables.ITable;
/**
* HiTechnic NXT Color Sensor.
*
* This class allows access to a HiTechnic NXT Color Sensor on an I2C bus.
* These sensors do not allow changing addresses so you cannot have more
* than one on a single bus.
*
* Details on the sensor can be found here:
* http://www.hitechnic.com/index.html?lang=en-us&target=d17.html
*
*/
public class HiTechnicColorSensor extends SensorBase implements ISensor, LiveWindowSendable {
/**
* An exception dealing with connecting to and communicating with the
* HiTechnicCompass
*/
public class ColorSensorException extends RuntimeException {
/**
* Create a new exception with the given message
* @param message the message to pass with the exception
*/
public ColorSensorException(String message) {
super(message);
}
}
/**
* A set of three color values bundled into one object
*/
public class RGB {
public double red, green, blue;
public double getRed() {
return red;
}
public double getGreen() {
return green;
}
public double getBlue() {
return blue;
}
}
public static class tColorSensorMode {
public final int value;
static final int kActive_val = 0;
static final int kPassive_val = 1;
static final int kRaw_val = 3;
public static final tColorSensorMode kActive = new tColorSensorMode(kActive_val);
public static final tColorSensorMode kPassive = new tColorSensorMode(kPassive_val);
public static final tColorSensorMode kRaw = new tColorSensorMode(kRaw_val);
private tColorSensorMode(int value) {
this.value = value;
}
}
private static final byte kAddress = 0x02;
private static final byte kManufacturerBaseRegister = 0x08;
private static final byte kManufacturerSize = 0x08;
private static final byte kSensorTypeBaseRegister = 0x10;
private static final byte kSensorTypeSize = 0x08;
private static final byte kModeRegister = 0x41;
private static final byte kColorRegister = 0x42;
private static final byte kRedRegister = 0x43;
private static final byte kGreenRegister = 0x44;
private static final byte kBlueRegister = 0x45;
private static final byte kRawRedRegister = 0x43;
private static final byte kRawGreenRegister = 0x45;
private static final byte kRawBlueRegister = 0x47;
private I2C m_i2c;
private int m_mode = tColorSensorMode.kActive.value;
/**
* Constructor.
*
* @param slot The slot of the digital module that the sensor is plugged into.
*/
public HiTechnicColorSensor(int slot) {
DigitalModule module = DigitalModule.getInstance(slot);
m_i2c = module.getI2C(kAddress);
// Verify Sensor
final byte[] kExpectedManufacturer = "HiTechnc".getBytes();
final byte[] kExpectedSensorType = "ColorPD ".getBytes();
if (!m_i2c.verifySensor(kManufacturerBaseRegister, kManufacturerSize, kExpectedManufacturer)) {
throw new ColorSensorException("Invalid Color Sensor Manufacturer");
}
if (!m_i2c.verifySensor(kSensorTypeBaseRegister, kSensorTypeSize, kExpectedSensorType)) {
throw new ColorSensorException("Invalid Sensor type");
}
LiveWindow.addSensor("HiTechnicColorSensor", slot, this);
UsageReporting.report(tResourceType.kResourceType_HiTechnicColorSensor, module.getModuleNumber()-1);
}
/**
* Destructor.
*/
public void free() {
if (m_i2c != null) {
m_i2c.free();
}
m_i2c = null;
}
/**
* Get the estimated color.
*
* Gets a color estimate from the sensor corresponding to the
* table found with the sensor or at the following site:
* http://www.hitechnic.com/cgi-bin/commerce.cgi?preadd=action&key=NCO1038
*
* @return The estimated color.
*/
public byte getColor() {
byte[] color = new byte[1];
if(m_mode != tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kActive);
}
m_i2c.read(kColorRegister, (byte) color.length, color);
return color[0];
}
/**
* Get the value of all three colors from a single sensor reading.
* Using this method ensures that all three values come from the
* same sensor reading, using the individual color methods provides
* no such guarantee.
*
* The sensor must be in active mode to access the regular RGB data
* if the sensor is not in active mode, it will be placed into active
* mode by this method.
*
* @return RGB object with the three color values
*/
public RGB getRGB() {
byte[] colors = new byte[3];
RGB result = new RGB();
if(m_mode != tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kActive);
}
m_i2c.read(kRedRegister, (byte) colors.length, colors);
result.red = (colors[0]&0xFFFF);
result.green = (colors[1]&0xFFFF);
result.blue = (colors[2]&0xFFFF);
return result;
}
/**
* Get the Red value.
*
* Gets the (0-255) red value from the sensor.
*
* The sensor must be in active mode to access the regular RGB data
* if the sensor is not in active mode, it will be placed into active
* mode by this method.
*
* @return The Red sensor value.
*/
public int getRed() {
byte[] red = new byte[1];
if(m_mode != tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kActive);
}
m_i2c.read(kRedRegister, (byte) red.length, red);
return (red[0]&0xFF);
}
/**
* Get the Green value.
*
* Gets the(0-255) green value from the sensor.
*
* The sensor must be in active mode to access the regular RGB data
* if the sensor is not in active mode, it will be placed into active
* mode by this method.
*
* @return The Green sensor value.
*/
public int getGreen() {
byte[] green = new byte[1];
if(m_mode != tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kActive);
}
m_i2c.read(kGreenRegister, (byte) green.length, green);
return (green[0]&0xFF);
}
/**
* Get the Blue value.
*
* Gets the raw (0-255) blue value from the sensor.
*
* The sensor must be in active mode to access the regular RGB data
* if the sensor is not in active mode, it will be placed into active
* mode by this method.
*
* @return The Blue sensor value.
*/
public int getBlue() {
byte[] blue = new byte[1];
if(m_mode != tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kActive);
}
m_i2c.read(kBlueRegister, (byte) blue.length, blue);
return (blue[0]&0xFF);
}
/**
* Get the Raw Red value.
*
* Gets the (0-65536) raw red value from the sensor.
*
* The sensor must be in raw or passive mode to access the regular RGB data
* if the sensor is not in raw or passive mode, it will be placed into raw
* mode by this method.
*
* @return The Raw Red sensor value.
*/
public double getRawRed() {
byte[] rawRed = new byte[2];
if(m_mode == tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kRaw);
}
m_i2c.read(kRawRedRegister, (byte) rawRed.length, rawRed);
return (((int)rawRed[0]&0xFF) * (int) (1 << 8) + ((int)rawRed[1]&0xFF));
}
/**
* Get the Raw Green value.
*
* Gets the (0-65536) raw green value from the sensor.
*
* The sensor must be in raw or passive mode to access the regular RGB data
* if the sensor is not in raw or passive mode, it will be placed into raw
* mode by this method.
*
* @return The Raw Green sensor value.
*/
public double getRawGreen() {
byte[] rawGreen = new byte[2];
if(m_mode == tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kRaw);
}
m_i2c.read(kRawGreenRegister, (byte) rawGreen.length, rawGreen);
return (((int)rawGreen[0]&0xFF) * (int) (1 << 8) + ((int)rawGreen[1]&0xFF));
}
/**
* Get the Raw Blue value.
*
* Gets the (0-65536) raw blue value from the sensor.
*
* The sensor must be in raw or passive mode to access the regular RGB data
* if the sensor is not in raw or passive mode, it will be placed into raw
* mode by this method.
*
* @return The Raw Blue sensor value.
*/
public double getRawBlue() {
byte[] rawBlue = new byte[2];
if(m_mode == tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kRaw);
}
m_i2c.read(kRawBlueRegister, (byte) rawBlue.length, rawBlue);
return (((int)rawBlue[0]&0xFF) * (int) (1 << 8) + ((int)rawBlue[1]&0xFF));
}
/**
* Get the raw value of all three colors from a single sensor reading.
* Using this method ensures that all three values come from the
* same sensor reading, using the individual color methods provides
* no such guarantee.
*
* Gets the (0-65536) raw color values from the sensor.
*
* The sensor must be in raw or passive mode to access the regular RGB data
* if the sensor is not in raw or passive mode, it will be placed into raw
* mode by this method.
*
* @return An RGB object with the raw sensor values.
*/
public RGB getRawRGB() {
byte[] colors = new byte[6];
RGB result = new RGB();
if(m_mode == tColorSensorMode.kActive.value) {
setMode(tColorSensorMode.kRaw);
}
m_i2c.read(kRawRedRegister, (byte) colors.length, colors);
result.red = (((int)colors[0]&0xFF) * (int) (1 << 8) + ((int)colors[1]&0xFF));
result.green = (((int)colors[2]&0xFF) * (int) (1 << 8) + ((int)colors[3]&0xFF));
result.blue = (((int)colors[4]&0xFF) * (int) (1 << 8) + ((int)colors[5]&0xFF));
return result;
}
/**
* Set the Mode of the color sensor
* This method is used to set the color sensor to one of the three modes,
* active, passive or raw. The sensor defaults to active mode which uses the
* internal LED and returns an interpreted color value and 3 8-bit RGB channel
* values. Raw mode uses the internal LED and returns 3 16-bit RGB channel values.
* Passive mode disables the internal LED and returns 3 16-bit RGB channel values.
* @param mode The mode to set
*/
public void setMode(tColorSensorMode mode) {
m_i2c.write(kModeRegister, mode.value);
m_mode = mode.value;
}
/*
* Live Window code, only does anything if live window is activated.
* TODO: Should this have its own type?
*/
public String getSmartDashboardType() {
return "Counter";
}
private ITable m_table;
/**
* {@inheritDoc}
*/
public void initTable(ITable subtable) {
m_table = subtable;
updateTable();
}
/**
* {@inheritDoc}
*/
public ITable getTable() {
return m_table;
}
/**
* {@inheritDoc}
*/
public void updateTable() {
if (m_table != null) {
if(m_mode == tColorSensorMode.kActive.value) {
m_table.putNumber("Color", getColor());
} else {
m_table.putNumber("Color", 99);
}
}
}
/**
* {@inheritDoc}
*/
public void startLiveWindowMode() {}
/**
* {@inheritDoc}
*/
public void stopLiveWindowMode() {}
}

View File

@@ -1,140 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
import edu.wpi.first.wpilibj.communication.UsageReporting;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.parsing.ISensor;
import edu.wpi.first.wpilibj.tables.ITable;
/**
* HiTechnic NXT Compass.
*
* This class alows access to a HiTechnic NXT Compass on an I2C bus.
* These sensors to not allow changing addresses so you cannot have more
* than one on a single bus.
*
* Details on the sensor can be found here:
* http://www.hitechnic.com/index.html?lang=en-us&target=d17.html
*
*/
public class HiTechnicCompass extends SensorBase implements ISensor, LiveWindowSendable {
/**
* An exception dealing with connecting to and communicating with the
* HiTechnicCompass
*/
public class CompassException extends RuntimeException {
/**
* Create a new exception with the given message
* @param message the message to pass with the exception
*/
public CompassException(String message) {
super(message);
}
}
private static final byte kAddress = 0x02;
private static final byte kManufacturerBaseRegister = 0x08;
private static final byte kManufacturerSize = 0x08;
private static final byte kSensorTypeBaseRegister = 0x10;
private static final byte kSensorTypeSize = 0x08;
private static final byte kHeadingRegister = 0x44;
private I2C m_i2c;
/**
* Constructor.
*/
public HiTechnicCompass() {
DigitalModule module = DigitalModule.getInstance(1);
m_i2c = module.getI2C(kAddress);
// Verify Sensor
final byte[] kExpectedManufacturer = "HiTechnc".getBytes();
final byte[] kExpectedSensorType = "Compass ".getBytes();
if (!m_i2c.verifySensor(kManufacturerBaseRegister, kManufacturerSize, kExpectedManufacturer)) {
throw new CompassException("Invalid Compass Manufacturer");
}
if (!m_i2c.verifySensor(kSensorTypeBaseRegister, kSensorTypeSize, kExpectedSensorType)) {
throw new CompassException("Invalid Sensor type");
}
UsageReporting.report(tResourceType.kResourceType_HiTechnicCompass, 1);
LiveWindow.addSensor("HiTechnicCompass", 1, this);
}
/**
* Destructor.
*/
public void free() {
if (m_i2c != null) {
m_i2c.free();
}
m_i2c = null;
}
/**
* Get the compass angle in degrees.
*
* The resolution of this reading is 1 degree.
*
* @return Angle of the compass in degrees.
*/
public double getAngle() {
byte[] heading = new byte[2];
m_i2c.read(kHeadingRegister, (byte) heading.length, heading);
return ((int) heading[0] + (int) heading[1] * (int) (1 << 8));
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Compass";
}
private ITable m_table;
/**
* {@inheritDoc}
*/
public void initTable(ITable subtable) {
m_table = subtable;
updateTable();
}
/**
* {@inheritDoc}
*/
public ITable getTable() {
return m_table;
}
/**
* {@inheritDoc}
*/
public void updateTable() {
if (m_table != null) {
m_table.putNumber("Value", getAngle());
}
}
/**
* {@inheritDoc}
*/
public void startLiveWindowMode() {}
/**
* {@inheritDoc}
*/
public void stopLiveWindowMode() {}
}

View File

@@ -6,8 +6,10 @@
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ByteBuffer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
import edu.wpi.first.wpilibj.communication.UsageReporting;
@@ -22,14 +24,22 @@ import edu.wpi.first.wpilibj.util.BoundaryException;
* This class is intended to be used by sensor (and other I2C device) drivers.
* It probably should not be used directly.
*
* It is constructed by calling DigitalModule::GetI2C() on a DigitalModule
* object.
*/
public class I2C extends SensorBase {
public enum Port {kOnboard(0), kMXP(1);
private int value;
private Port(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
};
private DigitalModule m_module;
private Port m_port;
private int m_deviceAddress;
private boolean m_compatibilityMode;
/**
* Constructor.
@@ -39,14 +49,16 @@ public class I2C extends SensorBase {
* @param deviceAddress
* The address of the device on the I2C bus.
*/
public I2C(DigitalModule module, int deviceAddress) {
if (module == null) {
throw new NullPointerException("Digital Module given was null");
}
m_module = module;
public I2C(Port port, int deviceAddress) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = port;
m_deviceAddress = deviceAddress;
m_compatibilityMode = true;
I2CJNI.i2CInitialize((byte)m_port.getValue(), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
UsageReporting.report(tResourceType.kResourceType_I2C, deviceAddress);
}
@@ -76,16 +88,15 @@ public class I2C extends SensorBase {
byte[] dataReceived, int receiveSize) {
boolean aborted = true;
ByteBuffer dataToSendBuffer = ByteBuffer.wrap(dataToSend);
ByteBuffer dataReceivedBuffer = ByteBuffer.allocate(1);
IntBuffer status = IntBuffer.allocate(1);
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(sendSize);
dataToSendBuffer.put(dataToSend);
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(receiveSize);
aborted = I2CJNI
.doI2CTransactionWithModule((byte) m_module.m_moduleNumber,
(byte) m_deviceAddress, (byte) (m_compatibilityMode ? 1
: 0), dataToSendBuffer, (byte) sendSize,
dataReceivedBuffer, (byte) receiveSize, status) != 0;
if (status.get() == HALUtil.PARAMETER_OUT_OF_RANGE) {
.i2CTransaction((byte) m_port.getValue(), (byte) m_deviceAddress,
dataToSendBuffer, (byte) sendSize,
dataReceivedBuffer, (byte) receiveSize) != 0;
/*if (status.get() == HALUtil.PARAMETER_OUT_OF_RANGE) {
if (sendSize > 6) {
throw new BoundaryException(BoundaryException.getMessage(
sendSize, 0, 6));
@@ -97,7 +108,7 @@ public class I2C extends SensorBase {
HALLibrary.PARAMETER_OUT_OF_RANGE_MESSAGE);
}
}
HALUtil.checkStatus(status);
HALUtil.checkStatus(status);*/
dataReceivedBuffer.get(dataReceived);
return aborted;
}
@@ -129,7 +140,27 @@ public class I2C extends SensorBase {
byte[] buffer = new byte[2];
buffer[0] = (byte) registerAddress;
buffer[1] = (byte) data;
return transaction(buffer, buffer.length, null, 0);
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(2);
dataToSendBuffer.put(buffer);
return I2CJNI.i2CWrite((byte)m_port.getValue(), (byte) m_deviceAddress, dataToSendBuffer, (byte)buffer.length) < 0;
}
/**
* Execute a write transaction with the device.
*
* Write multiple bytes to a register on a device and wait until the
* transaction is complete.
*
* @param data
* The data to write to the device.
*/
public synchronized boolean writeBulk(byte[] data) {
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(data.length);
dataToSendBuffer.put(data);
return I2CJNI.i2CWrite((byte)m_port.getValue(), (byte) m_deviceAddress, dataToSendBuffer, (byte)data.length) < 0;
}
/**
@@ -159,6 +190,32 @@ public class I2C extends SensorBase {
return transaction(registerAddressArray, registerAddressArray.length,
buffer, count);
}
/**
* Execute a read only transaction with the device.
*
* Read 1 to 7 bytes from a device. This method does not write any data to prompt
* the device.
*
* @param buffer
* A pointer to the array of bytes to store the data read from
* the device.
* @param count
* The number of bytes to read in the transaction. [1..7]
* @return Transfer Aborted... false for success, true for aborted.
*/
public boolean readOnly(byte[] buffer, int count) {
BoundaryException.assertWithinBounds(count, 1, 7);
if (buffer == null) {
throw new NullPointerException("Null return buffer was given");
}
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(count);
int retVal = I2CJNI.i2CRead((byte)m_port.getValue(), (byte) m_deviceAddress, dataReceivedBuffer, (byte)count);
dataReceivedBuffer.get(buffer);
return retVal < 0;
}
/**
* Send a broadcast write to all devices on the I2C bus.
@@ -173,22 +230,6 @@ public class I2C extends SensorBase {
public void broadcast(int registerAddress, int data) {
}
/**
* SetCompatabilityMode
*
* Enables bitwise clock skewing detection. This will reduce the I2C
* interface speed, but will allow you to communicate with devices that skew
* the clock at abnormal times. Compatability mode is enabled by default.
*
* @param enable
* Enable compatability mode for this sensor or not.
*/
public void setCompatabilityMode(boolean enable) {
m_compatibilityMode = enable;
UsageReporting.report(tResourceType.kResourceType_I2C,
m_deviceAddress, 1, "C");
}
/**
* Verify that a device's registers contain expected values.
*

View File

@@ -4,6 +4,9 @@ import java.nio.ByteBuffer;
import java.nio.IntBuffer;
public class I2CJNI extends JNIWrapper {
public static native byte doI2CTransaction(byte address, byte compatibilityMode, ByteBuffer dataToSend, byte sendSize, ByteBuffer dataReceived, byte receiveSize, IntBuffer status);
public static native byte doI2CTransactionWithModule(byte module, byte address, byte compatibilityMode, ByteBuffer dataToSend, byte sendSize, ByteBuffer dataReceived, byte receiveSize, IntBuffer status);
public static native void i2CInitialize(byte port, IntBuffer status);
public static native byte i2CTransaction(byte port, byte address, ByteBuffer dataToSend, byte sendSize, ByteBuffer dataReceived, byte receiveSize);
public static native byte i2CWrite(byte port, byte address, ByteBuffer dataToSend, byte sendSize);
public static native byte i2CRead(byte port, byte address, ByteBuffer dataRecieved, byte receiveSize);
public static native void i2CClose(byte port);
}