package com.systronix.devices;
import com.ajile.drivers.i2c.I2C;
import com.ajile.drivers.i2c.I2CException;
import com.ajile.jem.peripherals.Regs;
/**
* Device Driver for the Devantech CMPS03 compass module.
*
* Communicates with the compass module via the I2C bus.
*
* The default I2C connections are Port A with Pin 1 for the clock and Pin 2 for the data.
*
* You can pick your own ports and pins using the 4-arg constructor.
*
* You can also pass in a pre-initalized I2C object using the I2C object constructor.
*
*
* Example (I2C is connected on PORTB, clock=PIN1, data=PIN2):
*
* compass = new CMPS03(Regs.GPIOB_BASE,1,Regs.GPIOB_BASE,2);
* System.out.println("Compass Bearing: " + compass.getBearing());
*
*
* @see Devantech
* @author Tim White (tim@cyface.com)
* @version 1.0 (9/03/2004)
*/
public class CMPS03 {
/*** VARIABLES ***********************************************************/
//Constants
private static final int COMPASS_I2C_ADDRESS = 0xC0;
private static final int COMPASS_I2C_ADDRESS_READ = 0xC1;
private static final int COMPASS_BEARING_SINGLE_BYTE_REGISTER = 0x01;
private static final int COMPASS_BEARING_WORD_REGISTER = 0x02;
private static final int COMPASS_CALIBRATE_REGISTER = 0x0E;
private static final int COMPASS_CALIBRATE_START_BYTE = 0xFF;
private static final int COMPASS_CALIBRATE_STOP_BYTE = 0x00;
private static final int COMPASS_POSITIVE_ACK = 1;
private static final int COMPASS_NEGATIVE_ACK = 0;
private static final boolean COMPASS_CLOCK_OUT_ACTIVE_HIGH = true;
private static final boolean COMPASS_DATA_OUT_ACTIVE_HIGH = true;
//Fields
private int clockPort = Regs.GPIOA_BASE;
private int clockPin = 1;
private int dataPort = Regs.GPIOA_BASE;
private int dataPin = 2;
//I2C Driver
private I2C i2c = null;
/*** CONSTUCTORS *********************************************************/
/**
* Default constructor.
* I2C interface is set to PORTA, clock=PIN1, data=PIN2
*/
public CMPS03() {
//No Arg Constructor
}
/**
* Constructor that allows setting of I2C Ports/Pins.
* @param clockPort Port the I2C clock is connected to
* @param clockPin Pin the I2C clock is connected to
* @param dataPort Port the I2C data is connected to
* @param dataPin Pin the I2C data is connected to
* @see com.ajile.jem.peripherals.Regs#GPIOA_BASE
*/
public CMPS03(int clockPort, int clockPin, int dataPort, int dataPin) {
this.clockPort = clockPort;
this.clockPin = clockPin;
this.dataPort = dataPort;
this.dataPin = dataPin;
}
/**
* Constructor that takes a pre-initialized I2C object.
* Useful if you are using I2C elsewhere in your app.
* You need to make sure that the Ports/Pins of the I2C object have been set before calling this.
* @param i2c Already-initalized I2C object to use for communication with the compass
* @see com.ajile.drivers.i2c.I2C
*/
public CMPS03(I2C i2c) {
this.i2c = i2c;
}
/*** PUBLIC METHODS ******************************************************/
/**
* Returns the compass bearing as 0-3599, representing 0-359.9 degrees.
* This reads compass registers 2 and 3.
* @return Compass bearing 0-3599
*/
public int getBearing() throws I2CException {
initalize(); //Init the I2C bus driver
int compassBearingHigh = 0;
int compassBearingLow = 0;
//Read the compass
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS);
delay(1);
i2c.sendByte(COMPASS_BEARING_WORD_REGISTER); //Specify Register
delay(1);
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS_READ);
compassBearingHigh = i2c.readByte(COMPASS_POSITIVE_ACK);
compassBearingLow = i2c.readByte(COMPASS_NEGATIVE_ACK);
i2c.stop();
System.out.println("High Byte: " + compassBearingHigh);
System.out.println("Low Byte: " + compassBearingLow);
return ((compassBearingHigh * 256) + compassBearingLow);
}
/**
* Returns the compass bearing as 0-255.
* This reads compass register 1.
* @return Compass bearing 0-255
*/
public int getByteBearing() throws I2CException {
initalize(); //Init the I2C bus driver
int compassBearing = 0;
//Read the compass
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS);
delay(1);
i2c.sendByte(COMPASS_BEARING_SINGLE_BYTE_REGISTER); //Specify Register
delay(1);
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS_READ);
compassBearing = i2c.readByte(COMPASS_NEGATIVE_ACK);
i2c.stop();
return compassBearing;
}
/**
* Allows calibration of the compass.
* This puts the compass into calibrate mode.
* You then rotate the compass in a slow 360 degree circle within 20 seconds.
* After 20 seconds, the compass taken out of calibrate mode.
* @see Devantech Calibration Instructions
*/
public void calibrate() throws I2CException {
calibrateStart();
delay(20000);
calibrateStop();
}
/**
* Puts the compass into calibrate mode.
* This sends a 255 to compass register 15.
* You need to call calibrateStop to return to normal mode.
* @see Devantech Calibration Instructions
*/
public void calibrateStart() throws I2CException {
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS);
delay(1);
i2c.sendByte(COMPASS_CALIBRATE_REGISTER); //Specify Register
delay(1);
i2c.sendByte(COMPASS_CALIBRATE_START_BYTE);
i2c.stop();
}
/**
* Takes the compass out of calibrate mode.
* This sends a 0 to compass register 15.
* @see Devantech Calibration Instructions
*/
public void calibrateStop() throws I2CException {
i2c.start(); //Send start byte
i2c.sendByte(COMPASS_I2C_ADDRESS);
delay(1);
i2c.sendByte(COMPASS_CALIBRATE_REGISTER); //Specify Register
delay(1);
i2c.sendByte(COMPASS_CALIBRATE_STOP_BYTE);
i2c.stop();
}
/**
* Basic test routine - println's the single & double byte bearings once per second.
* @param args If specified, clockPort, clockPin, dataPort, dataPin (all as ints)
*/
public static void main(String[] args) {
System.out.println("JStamp Compass Reader Startup.");
CMPS03 compass = null;
if (args.length == 4) {
compass =
new CMPS03(
Integer.parseInt(args[0]),
Integer.parseInt(args[1]),
Integer.parseInt(args[2]),
Integer.parseInt(args[3]));
} else {
compass = new CMPS03();
}
while (true) {
delay(1000);
try {
System.out.println(
"Compass Bearing (Single Byte/Word): " + compass.getByteBearing() + "/" + compass.getBearing());
} catch (I2CException e) {
System.out.println("I2C Exception: " + e.getMessage());
}
}
}
/*** PRIVATE METHODS *****************************************************/
/**
* Initalizes the I2C bus driver by creating an I2C object, and assigning it ports and pins.
* Called automatically before any read operation
*/
private void initalize() throws I2CException {
if (this.i2c == null) {
this.i2c = new I2C();
}
this.i2c.setClockInfo(this.clockPort, this.clockPin, COMPASS_CLOCK_OUT_ACTIVE_HIGH);
this.i2c.setDataInfo(this.dataPort, this.dataPin, COMPASS_DATA_OUT_ACTIVE_HIGH);
this.i2c.reset();
}
/**
* Causes the current thread to sleep.
*
* @param msecs Number of milliseconds to sleep
*/
private static void delay(int msecs) {
try {
Thread.sleep(msecs);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Gets the currently assigned clock pin.
* @return int Pin that that I2C clock is assigned to
*/
public int getClockPin() {
return clockPin;
}
/**
* Gets the currently assigned clock port.
* @return int Port that that I2C clock is assigned to
*/
public int getClockPort() {
return clockPort;
}
/**
* Gets the currently assigned data pin
* @return int Pin that that I2C data is assigned to
*/
public int getDataPin() {
return dataPin;
}
/**
* Gets the currently assigned data port.
* @return int Pin that that I2C data is assigned to
*/
public int getDataPort() {
return dataPort;
}
/**
* Sets the I2C clock pin.
* @param clockPin Pin to set the I2C clock to
*/
public void setClockPin(int clockPin) {
this.clockPin = clockPin;
}
/**
* Sets the I2C clock port.
* @param clockPort Pin to set the I2C clock port to
* @see com.ajile.jem.peripherals.Regs#GPIOA_BASE
*/
public void setClockPort(int clockPort) {
this.clockPort = clockPort;
}
/**
* Sets the I2C data pin.
* @param dataPin Pin to set the I2C data pin to
*/
public void setDataPin(int dataPin) {
this.dataPin = dataPin;
}
/**
* Sets the I2C data port.
* @param dataPort Pin to set the I2C data port to
* @see com.ajile.jem.peripherals.Regs#GPIOA_BASE
*/
public void setDataPort(int dataPort) {
this.dataPort = dataPort;
}
}