Merge "Port SPI to roboRIO. Java SPIDevice renamed to SPI and rewritten to match C++ API."

This commit is contained in:
Thomas Clark (WPI)
2014-07-17 12:16:14 -07:00
committed by Gerrit Code Review
11 changed files with 883 additions and 1150 deletions

View File

@@ -0,0 +1,165 @@
/*----------------------------------------------------------------------------*/
/* 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;
/**
*
* @author dtjones
* @author mwills
*/
public class ADXL345_SPI extends SensorBase {
private static final int kPowerCtlRegister = 0x2D;
private static final int kDataFormatRegister = 0x31;
private static final int kDataRegister = 0x32;
private static final double kGsPerLSB = 0.00390625;
private static final int kAddress_Read = 0x80;
private static final int kAddress_MultiByte = 0x40;
private static final int kPowerCtl_Link=0x20;
private static final int kPowerCtl_AutoSleep=0x10;
private static final int kPowerCtl_Measure=0x08;
private static final int kPowerCtl_Sleep=0x04;
private static final int kDataFormat_SelfTest=0x80;
private static final int kDataFormat_SPI=0x40;
private static final int kDataFormat_IntInvert=0x20;
private static final int kDataFormat_FullRes=0x08;
private static final int kDataFormat_Justify=0x04;
public static class DataFormat_Range {
/**
* The integer value representing this enumeration
*/
public final byte value;
static final byte k2G_val = 0x00;
static final byte k4G_val = 0x01;
static final byte k8G_val = 0x02;
static final byte k16G_val = 0x03;
public static final ADXL345_SPI.DataFormat_Range k2G = new ADXL345_SPI.DataFormat_Range(k2G_val);
public static final ADXL345_SPI.DataFormat_Range k4G = new ADXL345_SPI.DataFormat_Range(k4G_val);
public static final ADXL345_SPI.DataFormat_Range k8G = new ADXL345_SPI.DataFormat_Range(k8G_val);
public static final ADXL345_SPI.DataFormat_Range k16G = new ADXL345_SPI.DataFormat_Range(k16G_val);
private DataFormat_Range(byte value) {
this.value = value;
}
}
public static class Axes {
/**
* The integer value representing this enumeration
*/
public final byte value;
static final byte kX_val = 0x00;
static final byte kY_val = 0x02;
static final byte kZ_val = 0x04;
public static final ADXL345_SPI.Axes kX = new ADXL345_SPI.Axes(kX_val);
public static final ADXL345_SPI.Axes kY = new ADXL345_SPI.Axes(kY_val);
public static final ADXL345_SPI.Axes kZ = new ADXL345_SPI.Axes(kZ_val);
private Axes(byte value) {
this.value = value;
}
}
public static class AllAxes {
public double XAxis;
public double YAxis;
public double ZAxis;
}
private SPI m_spi;
/**
* Constructor. Use this when the device is the first/only device on the bus
*
* @param clk The clock channel
* @param mosi The mosi (output) channel
* @param miso The miso (input) channel
* @param cs The chip select channel
* @param range The range (+ or -) that the accelerometer will measure.
*/
public ADXL345_SPI(SPI.Port port, ADXL345_SPI.DataFormat_Range range) {
m_spi = new SPI(port);
init(range);
}
public void free(){
m_spi.free();
}
/**
* Set SPI bus parameters, bring device out of sleep and set format
*
* @param range The range (+ or -) that the accelerometer will measure.
*/
private void init(ADXL345_SPI.DataFormat_Range range){
m_spi.setClockRate(500000);
m_spi.setMSBFirst();
m_spi.setSampleDataOnFalling();
m_spi.setClockActiveLow();
m_spi.setChipSelectActiveHigh();
// Turn on the measurements
byte[] commands = new byte[2];
commands[0] = kPowerCtlRegister;
commands[1] = kPowerCtl_Measure;
m_spi.write(commands, 2);
// Specify the data format to read
commands[0] = kDataFormatRegister;
commands[1] = (byte)(kDataFormat_FullRes | range.value);
m_spi.write(commands, 2);
}
/**
* Get the acceleration of one axis in Gs.
*
* @param axis The axis to read from.
* @return Acceleration of the ADXL345 in Gs.
*/
public double getAcceleration(ADXL345_SPI.Axes axis) {
byte[] transferBuffer = new byte[3];
transferBuffer[0] = (byte)((kAddress_Read | kAddress_MultiByte | kDataRegister) + axis.value);
m_spi.transaction(transferBuffer, transferBuffer, 3);
//Sensor is little endian... swap bytes
int rawAccel = transferBuffer[2] << 8 | transferBuffer[1];
return rawAccel * kGsPerLSB;
}
/**
* Get the acceleration of all axes in Gs.
*
* @return Acceleration measured on all axes of the ADXL345 in Gs.
*/
public ADXL345_SPI.AllAxes getAccelerations() {
ADXL345_SPI.AllAxes data = new ADXL345_SPI.AllAxes();
byte dataBuffer[] = new byte[7];
int[] rawData = new int[3];
if (m_spi != null)
{
// Select the data address.
dataBuffer[0] = (byte)(kAddress_Read | kAddress_MultiByte | kDataRegister);
m_spi.transaction(dataBuffer, dataBuffer, 7);
for (int i=0; i<3; i++)
{
//Sensor is little endian... swap bytes
rawData[i] = dataBuffer[i*2+2] << 8 | dataBuffer[i*2+1];
}
data.XAxis = rawData[0] * kGsPerLSB;
data.YAxis = rawData[1] * kGsPerLSB;
data.ZAxis = rawData[2] * kGsPerLSB;
}
return data;
}
}

View File

@@ -0,0 +1,215 @@
package edu.wpi.first.wpilibj;
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;
import edu.wpi.first.wpilibj.hal.HALLibrary;
import edu.wpi.first.wpilibj.hal.HALUtil;
import edu.wpi.first.wpilibj.hal.SPIJNI;
/**
*
* Represents a SPI bus port
* @author koconnor
*/
public class SPI extends SensorBase {
public enum Port {
kOnboardCS0(0),
kOnboardCS1(1),
kOnboardCS2(2),
kOnboardCS3(3),
kMXP(4);
private int value;
private Port(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
};
private static int devices = 0;
private byte m_port;
private int bitOrder;
private int clockPolarity;
private int dataOnTrailing;
/**
* Constructor
*
* @param SPIport the physical SPI port
*/
public SPI(Port port) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = (byte)port.getValue();
devices++;
SPIJNI.spiInitialize(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
UsageReporting.report(tResourceType.kResourceType_SPI, devices);
}
/**
* Free the resources used by this object
*/
public void free(){
SPIJNI.spiClose(m_port);
}
/**
* Configure the rate of the generated clock signal.
* The default and maximum value is 500,000 Hz.
*
* @param hz The clock rate in Hertz.
*/
public final void setClockRate(int hz) {
SPIJNI.spiSetSpeed(m_port, hz);
}
/**
* Configure the order that bits are sent and received on the wire
* to be most significant bit first.
*/
public final void setMSBFirst() {
this.bitOrder = 1;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure the order that bits are sent and received on the wire
* to be least significant bit first.
*/
public final void setLSBFirst() {
this.bitOrder = 0;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure the clock output line to be active low.
* This is sometimes called clock polarity high or clock idle high.
*/
public final void setClockActiveLow() {
this.clockPolarity = 1;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure the clock output line to be active high.
* This is sometimes called clock polarity low or clock idle low.
*/
public final void setClockActiveHigh() {
this.clockPolarity = 0;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure that the data is stable on the falling edge and the data
* changes on the rising edge.
*/
public final void setSampleDataOnFalling() {
this.dataOnTrailing = 1;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure that the data is stable on the rising edge and the data
* changes on the falling edge.
*/
public final void setSampleDataOnRising() {
this.dataOnTrailing = 0;
SPIJNI.spiSetOpts(m_port, this.bitOrder, this.dataOnTrailing, this.clockPolarity);
}
/**
* Configure the chip select line to be active high.
*/
public final void setChipSelectActiveHigh() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
SPIJNI.spiSetChipSelectActiveHigh(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Configure the chip select line to be active low.
*/
public final void setChipSelectActiveLow() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
SPIJNI.spiSetChipSelectActiveLow(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Write data to the slave device. Blocks until there is space in the
* output FIFO.
*
* If not running in output only mode, also saves the data received
* on the MISO input during the transfer into the receive FIFO.
*/
public int write(byte[] dataToSend, int size) {
int retVal = 0;
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
dataToSendBuffer.put(dataToSend);
retVal = SPIJNI.spiWrite(m_port, dataToSendBuffer, (byte) size);
return retVal;
}
/**
* Read a word from the receive FIFO.
*
* Waits for the current transfer to complete if the receive FIFO is empty.
*
* If the receive FIFO is empty, there is no active transfer, and initiate
* is false, errors.
*
* @param initiate If true, this function pushes "0" into the
* transmit buffer and initiates a transfer.
* If false, this function assumes that data is
* already in the receive FIFO from a previous write.
*/
public int read(boolean initiate, byte[] dataReceived, int size) {
int retVal = 0;
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
if(initiate)
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
else
retVal = SPIJNI.spiRead(m_port, dataReceivedBuffer, (byte) size);
dataReceivedBuffer.get(dataReceived);
return retVal;
}
/**
* Perform a simultaneous read/write transaction with the device
*
* @param dataToSend The data to be written out to the device
* @param dataReceived Buffer to receive data from the device
* @param size The length of the transaction, in bytes
*/
public int transaction(byte[] dataToSend, byte[] dataReceived, int size) {
int retVal = 0;
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(size);
dataToSendBuffer.put(dataToSend);
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(size);
retVal = SPIJNI.spiTransaction(m_port, dataToSendBuffer, dataReceivedBuffer, (byte) size);
dataReceivedBuffer.get(dataReceived);
return retVal;
}
}

View File

@@ -4,29 +4,14 @@ import java.nio.ByteBuffer;
import java.nio.IntBuffer;
public class SPIJNI extends JNIWrapper {
public static native ByteBuffer initializeSPI(byte sclk_routing_module, int sclk_routing_pin, byte mosi_routing_module, int mosi_routing_pin, byte miso_routing_module, int miso_routing_pin, IntBuffer status);
public static native void cleanSPI(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPIBitsPerWord(ByteBuffer spi_pointer, int bits, IntBuffer status);
public static native int getSPIBitsPerWord(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPIClockRate(ByteBuffer spi_pointer, double hz, IntBuffer status);
public static native void setSPIMSBFirst(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPILSBFirst(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPISampleDataOnFalling(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPISampleDataOnRising(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPISlaveSelect(ByteBuffer spi_pointer, byte ss_routing_module, int ss_routing_pin, IntBuffer status);
public static native void setSPILatchMode(ByteBuffer spi_pointer, int mode, IntBuffer status);
public static native int getSPILatchMode(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPIFramePolarity(ByteBuffer spi_pointer, byte activeLow, IntBuffer status);
public static native byte getSPIFramePolarity(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPIClockActiveLow(ByteBuffer spi_pointer, IntBuffer status);
public static native void setSPIClockActiveHigh(ByteBuffer spi_pointer, IntBuffer status);
public static native void applySPIConfig(ByteBuffer spi_pointer, IntBuffer status);
public static native short getSPIOutputFIFOAvailable(ByteBuffer spi_pointer, IntBuffer status);
public static native short getSPINumReceived(ByteBuffer spi_pointer, IntBuffer status);
public static native byte isSPIDone(ByteBuffer spi_pointer, IntBuffer status);
public static native byte hadSPIReceiveOverflow(ByteBuffer spi_pointer, IntBuffer status);
public static native void writeSPI(ByteBuffer spi_pointer, int data, IntBuffer status);
public static native int readSPI(ByteBuffer spi_pointer, byte initiate, IntBuffer status);
public static native void resetSPI(ByteBuffer spi_pointer, IntBuffer status);
public static native void clearSPIReceivedData(ByteBuffer spi_pointer, IntBuffer status);
public static native void spiInitialize(byte port, IntBuffer status);
public static native int spiTransaction(byte port, ByteBuffer dataToSend, ByteBuffer dataReceived, byte size);
public static native int spiWrite(byte port, ByteBuffer dataToSend, byte sendSize);
public static native int spiRead(byte port, ByteBuffer dataReceived, byte size);
public static native void spiClose(byte port);
public static native void spiSetSpeed(byte port, int speed);
public static native void spiSetBitsPerWord(byte port, byte bpw);
public static native void spiSetOpts(byte port, int msb_first, int sample_on_trailing, int clk_idle_high);
public static native void spiSetChipSelectActiveHigh(byte port, IntBuffer status);
public static native void spiSetChipSelectActiveLow(byte port, IntBuffer status);
}