package lejos.nxt;
import java.io.IOException;
import lejos.nxt.remote.ErrorMessages;
import lejos.nxt.remote.NXTCommand;
import lejos.nxt.remote.NXTProtocol;
import lejos.pc.comm.NXTCommandConnector;
/**
* A sensor wrapper to allow easy access to I2C sensors, like the ultrasonic
* sensor.
*
* This version of this class supports remote execution of I2C.
*
* @author Brian Bagnall and Lawrie Griffiths
*/
public class I2CSensor implements SensorConstants {
private static final NXTCommand nxtCommand = NXTCommandConnector
.getSingletonOpen();
protected byte address = 0x02; // the default I2C address for a port. You
// can change address of compass sensor (see
// docs) and then communicate with multiple
// sensors on same physical port.
protected static byte STOP = 0x00; // Commands don't seem to use this?
protected static String BLANK = " ";
// Port information (constants)
/**
* Returns the version number of the sensor. e.g. "V1.0" Reply length = 8.
*/
protected static byte VERSION = 0x00;
/**
* Returns the product ID of the sensor. e.g. "LEGO" Reply length = 8.
*/
protected static byte PRODUCT_ID = 0x08;
/**
* Returns the sensor type. e.g. "Sonar" Reply length = 8.
*/
protected static byte SENSOR_TYPE = 0x10;
/**
* Returns the "zero position" set at the factory for this sensor. e.g. 0
* Reply length = 1.
*
*/
byte port;
/**
*
* @param s
* A sensor. e.g. Port.S1
*/
public I2CSensor(I2CPort s, byte sensorType) {
port = (byte) s.getId();
s.setTypeAndMode(sensorType, NXTProtocol.RAWMODE);
// Flushes out any existing data
try {
nxtCommand.LSGetStatus(this.port);
nxtCommand.LSRead(this.port);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
}
public I2CSensor(I2CPort s) {
this(s, NXTProtocol.LOWSPEED);
}
public int getId() {
return port;
}
/**
* Method for retrieving data values from the sensor. BYTE0 ( is usually the
* primary data value for the sensor. Data is read from registers in the
* sensor, usually starting at 0x00 and ending around 0x49. Just supply the
* register to start reading at, and the length of bytes to read (16
* maximum). NOTE: The NXT supplies UBYTE (unsigned byte) values but Java
* converts them into signed bytes (probably more practical to return
* short/int?)
*
* @param register
* e.g. FACTORY_SCALE_DIVISOR, BYTE0, etc....
* @param length
* Length of data to read (minimum 1, maximum 16)
* @return the status
*/
public int getData(int register, byte[] buf, int length) {
byte[] txData = { address, (byte) register };
try {
nxtCommand.LSWrite(port, txData, (byte) length);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
byte[] status = null;
do {
try {
status = nxtCommand.LSGetStatus(port);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
return -1;
}
} while (status[0] == ErrorMessages.PENDING_COMMUNICATION_TRANSACTION_IN_PROGRESS
| status[0] == ErrorMessages.SPECIFIED_CHANNEL_CONNECTION_NOT_CONFIGURED_OR_BUSY);
try {
byte[] ret = nxtCommand.LSRead(port);
if (ret != null)
System.arraycopy(ret, 0, buf, 0, ret.length);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
return -1;
}
return status[0];
}
/**
* Helper method to return a single register byte.
*
* @param register
* @return the byte of data
*/
public int getData(int register) {
byte[] buf1 = new byte[1];
return getData(register, buf1, 1);
}
/**
* Sets a single byte in the I2C sensor.
*
* @param register
* A data register in the I2C sensor. e.g. ACTUAL_ZERO
* @param value
* The data value.
*/
public int sendData(int register, byte value) {
byte[] txData = { address, (byte) register, value };
try {
int ret = nxtCommand.LSWrite(this.port, txData, (byte) 0);
return ret;
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
return -1;
} catch (Exception e) {
System.out.println(e.getMessage());
return -1;
}
}
/**
* Send data top the sensor
*
* @param register
* A data register in the I2C sensor.
* @param data
* The byte to send.
* @param length
* the number of bytes
*/
public int sendData(int register, byte[] data, int length) {
byte[] txData = { address, (byte) register };
byte[] sendData = new byte[length + 2];
System.arraycopy(txData, 0, sendData, 0, 2);
System.arraycopy(data, 0, sendData, 2, length);
try {
return nxtCommand.LSWrite(this.port, sendData, (byte) 0);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
return -1;
}
}
/**
* Returns the version number of the sensor hardware. NOTE: A little
* unreliable at the moment due to a bug in firmware. Keep trying if it
* doesn't get it the first time.
*
* @return The version number. e.g. "V1.0"
*/
public String getVersion() {
return fetchString(VERSION, 8);
}
/**
* Returns the Product ID as a string. NOTE: A little unreliable at the
* moment due to a bug in firmware. Keep trying if it doesn't get it the
* first time.
*
* @return The product ID. e.g. "LEGO"
*/
public String getProductID() {
return fetchString(PRODUCT_ID, 8);
}
/**
* Returns the type of sensor as a string. NOTE: A little unreliable at the
* moment due to a bug in firmware. Keep trying if it doesn't get it the
* first time.
*
* @return The sensor type. e.g. "Sonar"
*/
public String getSensorType() {
return fetchString(SENSOR_TYPE, 8);
}
/**
* Helper method for retrieving string constants using I2C protocol.
*
* @param constantEnumeration
* e.g. I2CProtocol.VERSION
* @param rxLength
* @return the string
*/
protected String fetchString(int constantEnumeration, int rxLength) {
byte[] stringBytes = new byte[rxLength];
getData(constantEnumeration, stringBytes, rxLength);
// Get rid of everything after 0.
int zeroPos = 0;
for (zeroPos = 0; zeroPos < rxLength; zeroPos++) {
if (stringBytes[zeroPos] == 0)
break;
}
String s = new String(stringBytes).substring(0, zeroPos);
return s;
}
/**
* Set the address of the port Note that addresses are from 0x01 to 0x7F not
* even numbers from 0x02 to 0xFE as given in some I2C device
* specifications. They are 7-bit addresses not 8-bit addresses.
*
* @param addr
* 1 to 0x7F
*/
public void setAddress(int addr) {
address = (byte) (addr << 1);
}
}
|