mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
JNI implementation for Java
Normal vs
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author dtjones
|
||||
*/
|
||||
public class ADXL345_I2C extends SensorBase {
|
||||
|
||||
private static final byte kAddress = 0x3A;
|
||||
private static final byte kPowerCtlRegister = 0x2D;
|
||||
private static final byte kDataFormatRegister = 0x31;
|
||||
private static final byte kDataRegister = 0x32;
|
||||
private static final double kGsPerLSB = 0.00390625;
|
||||
private static final byte kPowerCtl_Link = 0x20, kPowerCtl_AutoSleep = 0x10, kPowerCtl_Measure = 0x08, kPowerCtl_Sleep = 0x04;
|
||||
private static final byte kDataFormat_SelfTest = (byte) 0x80, kDataFormat_SPI = 0x40, kDataFormat_IntInvert = 0x20, kDataFormat_FullRes = 0x08, 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 DataFormat_Range k2G = new DataFormat_Range(k2G_val);
|
||||
public static final DataFormat_Range k4G = new DataFormat_Range(k4G_val);
|
||||
public static final DataFormat_Range k8G = new DataFormat_Range(k8G_val);
|
||||
public static final DataFormat_Range k16G = new 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 Axes kX = new Axes(kX_val);
|
||||
public static final Axes kY = new Axes(kY_val);
|
||||
public static final Axes kZ = new Axes(kZ_val);
|
||||
|
||||
private Axes(byte value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AllAxes {
|
||||
|
||||
public double XAxis;
|
||||
public double YAxis;
|
||||
public double ZAxis;
|
||||
}
|
||||
private I2C m_i2c;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param module The slot of the digital module that the sensor is plugged into.
|
||||
* @param range The range (+ or -) that the accelerometer will measure.
|
||||
*/
|
||||
public ADXL345_I2C(int moduleNumber, DataFormat_Range range) {
|
||||
DigitalModule module = DigitalModule.getInstance(moduleNumber);
|
||||
m_i2c = module.getI2C(kAddress);
|
||||
|
||||
// Turn on the measurements
|
||||
m_i2c.write(kPowerCtlRegister, kPowerCtl_Measure);
|
||||
// Specify the data format to read
|
||||
m_i2c.write(kDataFormatRegister, kDataFormat_FullRes | range.value);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_I2C, moduleNumber-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(Axes axis) {
|
||||
byte[] rawAccel = new byte[2];
|
||||
m_i2c.read(kDataRegister + axis.value, rawAccel.length, rawAccel);
|
||||
|
||||
// Sensor is little endian... swap bytes
|
||||
return accelFromBytes(rawAccel[0], rawAccel[1]);
|
||||
}
|
||||
|
||||
private double accelFromBytes(byte first, byte second) {
|
||||
short tempLow = (short) (first & 0xff);
|
||||
short tempHigh = (short) ((second << 8) & 0xff00);
|
||||
return (tempLow | tempHigh) * kGsPerLSB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the acceleration of all axes in Gs.
|
||||
*
|
||||
* @return Acceleration measured on all axes of the ADXL345 in Gs.
|
||||
*/
|
||||
public AllAxes getAccelerations() {
|
||||
AllAxes data = new AllAxes();
|
||||
byte[] rawData = new byte[6];
|
||||
m_i2c.read(kDataRegister, rawData.length, rawData);
|
||||
|
||||
// Sensor is little endian... swap bytes
|
||||
data.XAxis = accelFromBytes(rawData[0], rawData[1]);
|
||||
data.YAxis = accelFromBytes(rawData[2], rawData[3]);
|
||||
data.ZAxis = accelFromBytes(rawData[4], rawData[5]);
|
||||
return data;
|
||||
}
|
||||
|
||||
// TODO: Support LiveWindow
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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;
|
||||
|
||||
|
||||
/**
|
||||
* Handle operation of the accelerometer.
|
||||
* The accelerometer reads acceleration directly through the sensor. Many sensors have
|
||||
* multiple axis and can be treated as multiple devices. Each is calibrated by finding
|
||||
* the center value over a period of time.
|
||||
*/
|
||||
public class Accelerometer extends SensorBase implements PIDSource, ISensor, LiveWindowSendable {
|
||||
|
||||
private AnalogChannel m_analogChannel;
|
||||
private double m_voltsPerG = 1.0;
|
||||
private double m_zeroGVoltage = 2.5;
|
||||
private boolean m_allocatedChannel;
|
||||
|
||||
/**
|
||||
* Common initialization
|
||||
*/
|
||||
private void initAccelerometer() {
|
||||
UsageReporting.report(tResourceType.kResourceType_Accelerometer, m_analogChannel.getChannel(), m_analogChannel.getModuleNumber()-1);
|
||||
LiveWindow.addSensor("Accelerometer", m_analogChannel.getModuleNumber(), m_analogChannel.getChannel(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of an accelerometer.
|
||||
*
|
||||
* The accelerometer is assumed to be in the first analog module in the given analog channel. The
|
||||
* constructor allocates desired analog channel.
|
||||
* @param channel the port that the accelerometer is on on the default module
|
||||
*/
|
||||
public Accelerometer(final int channel) {
|
||||
m_allocatedChannel = true;
|
||||
m_analogChannel = new AnalogChannel(channel);
|
||||
initAccelerometer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance of accelerometer.
|
||||
*
|
||||
* Make a new instance of the accelerometer given a module and channel. The constructor allocates
|
||||
* the desired analog channel from the specified module
|
||||
* @param slot the slot that the module is in
|
||||
* @param channel the port that the Accelerometer is on on the module
|
||||
*/
|
||||
public Accelerometer(final int slot, final int channel) {
|
||||
m_allocatedChannel = true;
|
||||
m_analogChannel = new AnalogChannel(slot, channel);
|
||||
initAccelerometer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of Accelerometer from an existing AnalogChannel.
|
||||
* Make a new instance of accelerometer given an AnalogChannel. This is particularly
|
||||
* useful if the port is going to be read as an analog channel as well as through
|
||||
* the Accelerometer class.
|
||||
* @param channel an already initialized analog channel
|
||||
*/
|
||||
public Accelerometer(AnalogChannel channel) {
|
||||
m_allocatedChannel = false;
|
||||
if (channel == null)
|
||||
throw new NullPointerException("Analog Channel given was null");
|
||||
m_analogChannel = channel;
|
||||
initAccelerometer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the analog components used for the accelerometer.
|
||||
*/
|
||||
public void free() {
|
||||
if (m_analogChannel != null && m_allocatedChannel) {
|
||||
m_analogChannel.free();
|
||||
}
|
||||
m_analogChannel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the acceleration in Gs.
|
||||
*
|
||||
* The acceleration is returned units of Gs.
|
||||
*
|
||||
* @return The current acceleration of the sensor in Gs.
|
||||
*/
|
||||
public double getAcceleration() {
|
||||
return (m_analogChannel.getAverageVoltage() - m_zeroGVoltage) / m_voltsPerG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the accelerometer sensitivity.
|
||||
*
|
||||
* This sets the sensitivity of the accelerometer used for calculating the acceleration.
|
||||
* The sensitivity varys by accelerometer model. There are constants defined for various models.
|
||||
*
|
||||
* @param sensitivity The sensitivity of accelerometer in Volts per G.
|
||||
*/
|
||||
public void setSensitivity(double sensitivity) {
|
||||
m_voltsPerG = sensitivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the voltage that corresponds to 0 G.
|
||||
*
|
||||
* The zero G voltage varys by accelerometer model. There are constants defined for various models.
|
||||
*
|
||||
* @param zero The zero G voltage.
|
||||
*/
|
||||
public void setZero(double zero) {
|
||||
m_zeroGVoltage = zero;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Acceleration for the PID Source parent.
|
||||
*
|
||||
* @return The current acceleration in Gs.
|
||||
*/
|
||||
public double pidGet() {
|
||||
return getAcceleration();
|
||||
}
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "Accelerometer";
|
||||
}
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
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", getAcceleration());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analog Channels don't have to do anything special when entering the LiveWindow.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {}
|
||||
|
||||
/**
|
||||
* Analog Channels don't have to do anything special when exiting the LiveWindow.
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* Structure for holding the values stored in an accumulator
|
||||
* @author brad
|
||||
*/
|
||||
public class AccumulatorResult {
|
||||
|
||||
/**
|
||||
* The total value accumulated
|
||||
*/
|
||||
public long value;
|
||||
/**
|
||||
* The number of sample vaule was accumulated over
|
||||
*/
|
||||
public long count;
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Analog channel class.
|
||||
*
|
||||
* Each analog channel is read from hardware as a 12-bit number representing
|
||||
* -10V to 10V.
|
||||
*
|
||||
* Connected to each analog channel is an averaging and oversampling engine.
|
||||
* This engine accumulates the specified ( by setAverageBits() and
|
||||
* setOversampleBits() ) number of samples before returning a new value. This is
|
||||
* not a sliding window average. The only difference between the oversampled
|
||||
* samples and the averaged samples is that the oversampled samples are simply
|
||||
* accumulated effectively increasing the resolution, while the averaged samples
|
||||
* are divided by the number of samples to retain the resolution, but get more
|
||||
* stable values.
|
||||
*/
|
||||
public class AnalogChannel extends SensorBase implements PIDSource,
|
||||
LiveWindowSendable {
|
||||
|
||||
private static final int kAccumulatorSlot = 1;
|
||||
private static Resource channels = new Resource(kAnalogModules
|
||||
* kAnalogChannels);
|
||||
private Pointer m_port;
|
||||
private int m_moduleNumber, m_channel;
|
||||
private static final int[] kAccumulatorChannels = { 1, 2 };
|
||||
private long m_accumulatorOffset;
|
||||
|
||||
/**
|
||||
* Construct an analog channel on the default module.
|
||||
*
|
||||
* @param channel
|
||||
* The channel number to represent.
|
||||
*/
|
||||
public AnalogChannel(final int channel) {
|
||||
this(getDefaultAnalogModule(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an analog channel on a specified module.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The digital module to use (1 or 2).
|
||||
* @param channel
|
||||
* The channel number to represent.
|
||||
*/
|
||||
public AnalogChannel(final int moduleNumber, final int channel) {
|
||||
System.out.println("Module Number: " + moduleNumber + " Channel: "
|
||||
+ channel);
|
||||
System.out.println(Thread.currentThread().getStackTrace());
|
||||
m_channel = channel;
|
||||
m_moduleNumber = moduleNumber;
|
||||
if (HALLibrary.checkAnalogModule((byte) moduleNumber) == 0) {
|
||||
throw new AllocationException("Analog channel " + m_channel
|
||||
+ " on module " + m_moduleNumber
|
||||
+ " cannot be allocated. Module is not present.");
|
||||
}
|
||||
if (HALLibrary.checkAnalogChannel(channel) == 0) {
|
||||
throw new AllocationException("Analog channel " + m_channel
|
||||
+ " on module " + m_moduleNumber
|
||||
+ " cannot be allocated. Channel is not present.");
|
||||
}
|
||||
try {
|
||||
channels.allocate((moduleNumber - 1) * kAnalogChannels + m_channel
|
||||
- 1);
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException("Analog channel " + m_channel
|
||||
+ " on module " + m_moduleNumber + " is already allocated");
|
||||
}
|
||||
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) channel);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
// XXX: Uncomment when Analog has been fixed
|
||||
m_port = HALLibrary.initializeAnalogPort(port_pointer, status);
|
||||
HALUtil.checkStatus(status);
|
||||
|
||||
LiveWindow.addSensor("Analog", moduleNumber, channel, this);
|
||||
UsageReporting.report(tResourceType.kResourceType_AnalogChannel,
|
||||
channel, m_moduleNumber - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel destructor.
|
||||
*/
|
||||
public void free() {
|
||||
channels.free(((m_moduleNumber - 1) * kAnalogChannels + m_channel - 1));
|
||||
m_channel = 0;
|
||||
m_moduleNumber = 0;
|
||||
m_accumulatorOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the analog module that this channel is on.
|
||||
*
|
||||
* @return The AnalogModule that this channel is on.
|
||||
*/
|
||||
public AnalogModule getModule() {
|
||||
return AnalogModule.getInstance(m_moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sample straight from this channel on the module. The sample is a
|
||||
* 12-bit value representing the -10V to 10V range of the A/D converter in
|
||||
* the module. The units are in A/D converter codes. Use GetVoltage() to get
|
||||
* the analog value in calibrated units.
|
||||
*
|
||||
* @return A sample straight from this channel on the module.
|
||||
*/
|
||||
public int getValue() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogValue(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sample from the output of the oversample and average engine for
|
||||
* this channel. The sample is 12-bit + the value configured in
|
||||
* SetOversampleBits(). The value configured in setAverageBits() will cause
|
||||
* this value to be averaged 2**bits number of samples. This is not a
|
||||
* sliding window. The sample will not change until 2**(OversamplBits +
|
||||
* AverageBits) samples have been acquired from the module on this channel.
|
||||
* Use getAverageVoltage() to get the analog value in calibrated units.
|
||||
*
|
||||
* @return A sample from the oversample and average engine for this channel.
|
||||
*/
|
||||
public int getAverageValue() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogAverageValue(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scaled sample straight from this channel on the module. The value
|
||||
* is scaled to units of Volts using the calibrated scaling data from
|
||||
* getLSBWeight() and getOffset().
|
||||
*
|
||||
* @return A scaled sample straight from this channel on the module.
|
||||
*/
|
||||
public double getVoltage() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = Float.intBitsToFloat(HALLibrary.getAnalogVoltageIntHack(m_port, status));
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scaled sample from the output of the oversample and average engine
|
||||
* for this channel. The value is scaled to units of Volts using the
|
||||
* calibrated scaling data from getLSBWeight() and getOffset(). Using
|
||||
* oversampling will cause this value to be higher resolution, but it will
|
||||
* update more slowly. Using averaging will cause this value to be more
|
||||
* stable, but it will update more slowly.
|
||||
*
|
||||
* @return A scaled sample from the output of the oversample and average
|
||||
* engine for this channel.
|
||||
*/
|
||||
public double getAverageVoltage() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = Float.intBitsToFloat(HALLibrary.getAnalogAverageVoltageIntHack(m_port, status));
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory scaling least significant bit weight constant. The least
|
||||
* significant bit weight constant for the channel that was calibrated in
|
||||
* manufacturing and stored in an eeprom in the module.
|
||||
*
|
||||
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
||||
*
|
||||
* @return Least significant bit weight.
|
||||
*/
|
||||
public long getLSBWeight() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
long value = HALLibrary.getAnalogLSBWeight(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory scaling offset constant. The offset constant for the
|
||||
* channel that was calibrated in manufacturing and stored in an eeprom in
|
||||
* the module.
|
||||
*
|
||||
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
|
||||
*
|
||||
* @return Offset constant.
|
||||
*/
|
||||
public int getOffset() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogOffset(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channel number.
|
||||
*
|
||||
* @return The channel number.
|
||||
*/
|
||||
public int getChannel() {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of the analog module this channel is on.
|
||||
*
|
||||
* @return The module number of the analog module this channel is on.
|
||||
*/
|
||||
public int getModuleNumber() {
|
||||
return m_moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of averaging bits. This sets the number of averaging bits.
|
||||
* The actual number of averaged samples is 2**bits. The averaging is done
|
||||
* automatically in the FPGA.
|
||||
*
|
||||
* @param bits
|
||||
* The number of averaging bits.
|
||||
*/
|
||||
public void setAverageBits(final int bits) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogAverageBits(m_port, bits, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of averaging bits. This gets the number of averaging bits
|
||||
* from the FPGA. The actual number of averaged samples is 2**bits. The
|
||||
* averaging is done automatically in the FPGA.
|
||||
*
|
||||
* @return The number of averaging bits.
|
||||
*/
|
||||
public int getAverageBits() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogAverageBits(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of oversample bits. This sets the number of oversample
|
||||
* bits. The actual number of oversampled values is 2**bits. The
|
||||
* oversampling is done automatically in the FPGA.
|
||||
*
|
||||
* @param bits
|
||||
* The number of oversample bits.
|
||||
*/
|
||||
public void setOversampleBits(final int bits) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogOversampleBits(m_port, bits, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of oversample bits. This gets the number of oversample
|
||||
* bits from the FPGA. The actual number of oversampled values is 2**bits.
|
||||
* The oversampling is done automatically in the FPGA.
|
||||
*
|
||||
* @return The number of oversample bits.
|
||||
*/
|
||||
public int getOversampleBits() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogOversampleBits(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the accumulator.
|
||||
*/
|
||||
public void initAccumulator() {
|
||||
if (!isAccumulatorChannel()) {
|
||||
throw new AllocationException(
|
||||
"Accumulators are only available on slot "
|
||||
+ kAccumulatorSlot + " on channels "
|
||||
+ kAccumulatorChannels[0] + ","
|
||||
+ kAccumulatorChannels[1]);
|
||||
}
|
||||
m_accumulatorOffset = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.initAccumulator(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an inital value for the accumulator.
|
||||
*
|
||||
* This will be added to all values returned to the user.
|
||||
*
|
||||
* @param initialValue
|
||||
* The value that the accumulator should start from when reset.
|
||||
*/
|
||||
public void setAccumulatorInitialValue(long initialValue) {
|
||||
m_accumulatorOffset = initialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the accumulator to the initial value.
|
||||
*/
|
||||
public void resetAccumulator() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.resetAccumulator(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the center value of the accumulator.
|
||||
*
|
||||
* The center value is subtracted from each A/D value before it is added to
|
||||
* the accumulator. This is used for the center value of devices like gyros
|
||||
* and accelerometers to make integration work and to take the device offset
|
||||
* into account when integrating.
|
||||
*
|
||||
* This center value is based on the output of the oversampled and averaged
|
||||
* source from channel 1. Because of this, any non-zero oversample bits will
|
||||
* affect the size of the value for this field.
|
||||
*/
|
||||
public void setAccumulatorCenter(int center) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAccumulatorCenter(m_port, center, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the accumulator's deadband.
|
||||
*/
|
||||
public void setAccumulatorDeadband(int deadband) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAccumulatorDeadband(m_port, deadband, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value.
|
||||
*
|
||||
* Read the value that has been accumulating on channel 1. The accumulator
|
||||
* is attached after the oversample and average engine.
|
||||
*
|
||||
* @return The 64-bit value accumulated since the last Reset().
|
||||
*/
|
||||
public long getAccumulatorValue() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
long value = HALLibrary.getAccumulatorValue(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value + m_accumulatorOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the number of accumulated values.
|
||||
*
|
||||
* Read the count of the accumulated values since the accumulator was last
|
||||
* Reset().
|
||||
*
|
||||
* @return The number of times samples from the channel were accumulated.
|
||||
*/
|
||||
public long getAccumulatorCount() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
long value = HALLibrary.getAccumulatorCount(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the accumulated value and the number of accumulated values
|
||||
* atomically.
|
||||
*
|
||||
* This function reads the value and count from the FPGA atomically. This
|
||||
* can be used for averaging.
|
||||
*
|
||||
* @param result
|
||||
* AccumulatorResult object to store the results in.
|
||||
*/
|
||||
public void getAccumulatorOutput(AccumulatorResult result) {
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("Null parameter `result'");
|
||||
}
|
||||
if (!isAccumulatorChannel()) {
|
||||
throw new IllegalArgumentException("Channel " + m_channel
|
||||
+ " on module " + m_moduleNumber
|
||||
+ " is not an accumulator channel.");
|
||||
}
|
||||
LongBuffer value = LongBuffer.allocate(1);
|
||||
IntBuffer count = IntBuffer.allocate(1);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.getAccumulatorOutput(m_port, value, count, status);
|
||||
result.value = value.get(0) + m_accumulatorOffset;
|
||||
result.count = count.get(0);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the channel attached to an accumulator.
|
||||
*
|
||||
* @return The analog channel is attached to an accumulator.
|
||||
*/
|
||||
public boolean isAccumulatorChannel() {
|
||||
if (m_moduleNumber != kAccumulatorSlot) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < kAccumulatorChannels.length; i++) {
|
||||
if (m_channel == kAccumulatorChannels[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSampleRate(final double samplesPerSecond) {
|
||||
// TODO: This will change when variable size scan lists are implemented.
|
||||
// TODO: Need float comparison with epsilon.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogSampleRate((float) samplesPerSecond, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the average value for usee with PIDController
|
||||
*
|
||||
* @return the average value
|
||||
*/
|
||||
public double pidGet() {
|
||||
return getAverageValue();
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Analog Input";
|
||||
}
|
||||
|
||||
private ITable m_table;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
if (m_table != null) {
|
||||
m_table.putNumber("Value", getAverageVoltage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analog Channels don't have to do anything special when entering the
|
||||
* LiveWindow. {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Analog Channels don't have to do anything special when exiting the
|
||||
* LiveWindow. {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tModuleType;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
|
||||
/**
|
||||
* Analog Module class.
|
||||
* Each module can independently sample its channels at a configurable rate.
|
||||
* There is a 64-bit hardware accumulator associated with channel 1 on each module.
|
||||
* The accumulator is attached to the output of the oversample and average engine so that the center
|
||||
* value can be specified in higher resolution resulting in less error.
|
||||
*/
|
||||
public class AnalogModule extends Module {
|
||||
|
||||
/**
|
||||
* The time base used by the module
|
||||
*/
|
||||
public static final int kTimebase = 40000000;
|
||||
/**
|
||||
* The default number of Oversample bits to use
|
||||
*/
|
||||
public static final int kDefaultOversampleBits = 0;
|
||||
/**
|
||||
* The default number of averaging bits to use
|
||||
*/
|
||||
public static final int kDefaultAverageBits = 7;
|
||||
/**
|
||||
* The default sample rate
|
||||
*/
|
||||
public static final double kDefaultSampleRate = 50000.0;
|
||||
private Pointer[] m_ports;
|
||||
|
||||
/**
|
||||
* Get an instance of an Analog Module.
|
||||
*
|
||||
* Singleton analog module creation where a module is allocated on the first use
|
||||
* and the same module is returned on subsequent uses.
|
||||
*
|
||||
* @param moduleNumber The index of the analog module to get (1 or 2).
|
||||
* @return The AnalogModule.
|
||||
*/
|
||||
public static synchronized AnalogModule getInstance(final int moduleNumber) {
|
||||
checkAnalogModule(moduleNumber);
|
||||
return (AnalogModule) getModule(tModuleType.kModuleType_Analog, moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of an analog module.
|
||||
*
|
||||
* Create an instance of the analog module object. Initialize all the parameters
|
||||
* to reasonable values on start.
|
||||
* Setting a global value on an analog module can be done only once unless subsequent
|
||||
* values are set the previously set value.
|
||||
* Analog modules are a singleton, so the constructor is never called outside of this class.
|
||||
*
|
||||
* @param moduleNumber The index of the analog module to create (1 or 2).
|
||||
*/
|
||||
protected AnalogModule(final int moduleNumber) {
|
||||
super(tModuleType.kModuleType_Analog, moduleNumber);
|
||||
|
||||
m_ports = new Pointer[8];
|
||||
for (int i = 0; i < SensorBase.kAnalogChannels; i++) {
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule((byte) moduleNumber, (byte) (i+1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
// XXX: Uncomment when analogchannel has been fixed
|
||||
// m_ports[i] = HALLibrary.initializeAnalogPort(port_pointer, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sample rate on the module.
|
||||
*
|
||||
* This is a global setting for the module and effects all channels.
|
||||
*
|
||||
* @param samplesPerSecond
|
||||
* The number of samples per channel per second.
|
||||
*/
|
||||
public void setSampleRate(final double samplesPerSecond) {
|
||||
// TODO: This will change when variable size scan lists are implemented.
|
||||
// TODO: Need float comparison with epsilon.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogSampleRateWithModule((byte) m_moduleNumber, (float) samplesPerSecond, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current sample rate on the module.
|
||||
*
|
||||
* This assumes one entry in the scan list. This is a global setting for the
|
||||
* module and effects all channels.
|
||||
*
|
||||
* @return Sample rate.
|
||||
*/
|
||||
public double getSampleRate() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = HALLibrary.getAnalogSampleRateWithModule((byte) m_moduleNumber, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of averaging bits.
|
||||
*
|
||||
* This sets the number of averaging bits. The actual number of averaged
|
||||
* samples is 2**bits. The averaging is done automatically in the FPGA.
|
||||
*
|
||||
* @param channel
|
||||
* Analog channel to configure.
|
||||
* @param bits
|
||||
* Number of bits to average.
|
||||
*/
|
||||
public void setAverageBits(final int channel, final int bits) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogAverageBits(m_ports[channel], bits, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of averaging bits.
|
||||
*
|
||||
* This gets the number of averaging bits from the FPGA. The actual number
|
||||
* of averaged samples is 2**bits. The averaging is done automatically in
|
||||
* the FPGA.
|
||||
*
|
||||
* @param channel Channel to address.
|
||||
* @return Bits to average.
|
||||
*/
|
||||
public int getAverageBits(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogAverageBits(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of oversample bits.
|
||||
*
|
||||
* This sets the number of oversample bits. The actual number of oversampled values is 2**bits.
|
||||
* Use oversampling to improve the resolution of your measurements at the expense of sampling rate.
|
||||
* The oversampling is done automatically in the FPGA.
|
||||
*
|
||||
* @param channel Analog channel to configure.
|
||||
* @param bits Number of bits to oversample.
|
||||
*/
|
||||
public void setOversampleBits(final int channel, final int bits) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogOversampleBits(m_ports[channel], bits, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of oversample bits.
|
||||
*
|
||||
* This gets the number of oversample bits from the FPGA. The actual number
|
||||
* of oversampled values is 2**bits. The oversampling is done automatically
|
||||
* in the FPGA.
|
||||
*
|
||||
* @param channel Channel to address.
|
||||
* @return Bits to oversample.
|
||||
*/
|
||||
public int getOversampleBits(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogOversampleBits(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw analog value.
|
||||
*
|
||||
* Get the analog value as it is returned from the D/A converter.
|
||||
*
|
||||
* @param channel Channel number to read.
|
||||
* @return Raw value.
|
||||
*/
|
||||
public int getValue(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogValue(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw averaged and oversampled value.
|
||||
*
|
||||
* @param channel Channel number to read.
|
||||
* @return The averaged and oversampled raw value.
|
||||
*/
|
||||
public int getAverageValue(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogAverageValue(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a voltage to a raw value for a specified channel.
|
||||
*
|
||||
* This process depends on the calibration of each channel, so the channel
|
||||
* must be specified.
|
||||
*
|
||||
* @todo This assumes raw values. Oversampling not supported as is.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to convert for.
|
||||
* @param voltage
|
||||
* The voltage to convert.
|
||||
* @return The raw value for the channel.
|
||||
*/
|
||||
public int voltsToValue(final int channel, final double voltage) {
|
||||
// wpi_assert(voltage >= -10.0 && voltage <= 10.0);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogVoltsToValue(m_ports[channel], (float) voltage, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the voltage.
|
||||
*
|
||||
* Return the voltage from the A/D converter.
|
||||
*
|
||||
* @param channel The channel to read.
|
||||
* @return The scaled voltage from the channel.
|
||||
*/
|
||||
public double getVoltage(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = HALLibrary.getAnalogVoltage(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the averaged voltage.
|
||||
*
|
||||
* Return the averaged voltage from the A/D converter.
|
||||
*
|
||||
* @param channel The channel to read.
|
||||
* @return The scaled averaged and oversampled voltage from the channel.
|
||||
*/
|
||||
public double getAverageVoltage(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = HALLibrary.getAnalogAverageVoltage(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LSB Weight portion of the calibration for a channel.
|
||||
*
|
||||
* @param channel The channel to get calibration data for.
|
||||
* @return LSB Weight calibration point.
|
||||
*/
|
||||
public long getLSBWeight(final int channel) {
|
||||
// TODO: add scaling to make this worth while.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
long value = HALLibrary.getAnalogLSBWeight(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Offset portion of the calibration for a channel.
|
||||
*
|
||||
* @param channel The channel to get calibration data for.
|
||||
* @return Offset calibration point.
|
||||
*/
|
||||
public int getOffset(final int channel) {
|
||||
// TODO: add scaling to make this worth while.
|
||||
// TODO: actually use this function.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getAnalogOffset(m_ports[channel], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.parsing.IInputOutput;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* Class for creating and configuring Analog Triggers
|
||||
*
|
||||
* @author dtjones
|
||||
*/
|
||||
public class AnalogTrigger implements IInputOutput {
|
||||
|
||||
/**
|
||||
* Exceptions dealing with improper operation of the Analog trigger
|
||||
*/
|
||||
public class AnalogTriggerException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create a new exception with the given message
|
||||
*
|
||||
* @param message
|
||||
* the message to pass with the exception
|
||||
*/
|
||||
public AnalogTriggerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the analog trigger is attached
|
||||
*/
|
||||
protected Pointer m_port;
|
||||
protected int m_index;
|
||||
|
||||
/**
|
||||
* Initialize an analog trigger from a module number and channel. This is
|
||||
* the common code for the two constructors that use a module number and
|
||||
* channel.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the analog module to create this trigger on.
|
||||
* @param channel
|
||||
* the port to use for the analog trigger
|
||||
*/
|
||||
protected void initTrigger(final int moduleNumber, final int channel) {
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) channel);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
IntBuffer index = IntBuffer.allocate(1);
|
||||
// XXX: Uncomment when analog has been fixed
|
||||
// m_port = HALLibrary
|
||||
// .initializeAnalogTrigger(port_pointer, index, status);
|
||||
//HALUtil.checkStatus(status);
|
||||
//m_index = index.get(0);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_AnalogTrigger,
|
||||
channel, moduleNumber-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for an analog trigger given a channel number. The default
|
||||
* module is used in this case.
|
||||
*
|
||||
* @param channel
|
||||
* the port to use for the analog trigger
|
||||
*/
|
||||
public AnalogTrigger(final int channel) {
|
||||
initTrigger(AnalogModule.getDefaultAnalogModule(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for an analog trigger given both the module number and
|
||||
* channel.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the analog module to create this trigger on.
|
||||
* @param channel
|
||||
* the port to use for the analog trigger
|
||||
*/
|
||||
public AnalogTrigger(final int moduleNumber, final int channel) {
|
||||
initTrigger(moduleNumber, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an analog trigger given an analog channel. This should be used
|
||||
* in the case of sharing an analog channel between the trigger and an
|
||||
* analog input object.
|
||||
*
|
||||
* @param channel
|
||||
* the AnalogChannel to use for the analog trigger
|
||||
*/
|
||||
public AnalogTrigger(AnalogChannel channel) {
|
||||
initTrigger(channel.getModuleNumber(), channel.getChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the resources used by this object
|
||||
*/
|
||||
public void free() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.cleanAnalogTrigger(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
m_port = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upper and lower limits of the analog trigger. The limits are
|
||||
* given in ADC codes. If oversampling is used, the units must be scaled
|
||||
* appropriately.
|
||||
*
|
||||
* @param lower
|
||||
* the lower raw limit
|
||||
* @param upper
|
||||
* the upper raw limit
|
||||
*/
|
||||
public void setLimitsRaw(final int lower, final int upper) {
|
||||
if (lower > upper) {
|
||||
throw new BoundaryException("Lower bound is greater than upper");
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogTriggerLimitsRaw(m_port, lower, upper, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upper and lower limits of the analog trigger. The limits are
|
||||
* given as floating point voltage values.
|
||||
*
|
||||
* @param lower
|
||||
* the lower voltage limit
|
||||
* @param upper
|
||||
* the upper voltage limit
|
||||
*/
|
||||
public void setLimitsVoltage(double lower, double upper) {
|
||||
if (lower > upper) {
|
||||
throw new BoundaryException(
|
||||
"Lower bound is greater than upper bound");
|
||||
}
|
||||
// TODO: This depends on the averaged setting. Only raw values will work
|
||||
// as is.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogTriggerLimitsVoltage(m_port, (float) lower,
|
||||
(float) upper, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the analog trigger to use the averaged vs. raw values. If the
|
||||
* value is true, then the averaged value is selected for the analog
|
||||
* trigger, otherwise the immediate value is used.
|
||||
*
|
||||
* @param useAveragedValue
|
||||
* true to use an averaged value, false otherwise
|
||||
*/
|
||||
public void setAveraged(boolean useAveragedValue) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogTriggerAveraged(m_port,
|
||||
(byte) (useAveragedValue ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the analog trigger to use a filtered value. The analog trigger
|
||||
* will operate with a 3 point average rejection filter. This is designed to
|
||||
* help with 360 degree pot applications for the period where the pot
|
||||
* crosses through zero.
|
||||
*
|
||||
* @param useFilteredValue
|
||||
* true to use a filterd value, false otherwise
|
||||
*/
|
||||
public void setFiltered(boolean useFilteredValue) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setAnalogTriggerFiltered(m_port,
|
||||
(byte) (useFilteredValue ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the analog trigger. This is the FPGA index of this
|
||||
* analog trigger instance.
|
||||
*
|
||||
* @return The index of the analog trigger.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InWindow output of the analog trigger. True if the analog
|
||||
* input is between the upper and lower limits.
|
||||
*
|
||||
* @return The InWindow output of the analog trigger.
|
||||
*/
|
||||
public boolean getInWindow() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
byte value = HALLibrary.getAnalogTriggerInWindow(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TriggerState output of the analog trigger. True if above upper
|
||||
* limit. False if below lower limit. If in Hysteresis, maintain previous
|
||||
* state.
|
||||
*
|
||||
* @return The TriggerState output of the analog trigger.
|
||||
*/
|
||||
public boolean getTriggerState() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
byte value = HALLibrary.getAnalogTriggerTriggerState(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AnalogTriggerOutput object. Gets an output object that can be
|
||||
* used for routing. Caller is responsible for deleting the
|
||||
* AnalogTriggerOutput object.
|
||||
*
|
||||
* @param type
|
||||
* An enum of the type of output object to create.
|
||||
* @return A pointer to a new AnalogTriggerOutput object.
|
||||
*/
|
||||
AnalogTriggerOutput createOutput(int type) {
|
||||
return new AnalogTriggerOutput(this, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.parsing.IInputOutput;
|
||||
|
||||
/**
|
||||
* Class to represent a specific output from an analog trigger. This class is
|
||||
* used to get the current output value and also as a DigitalSource to provide
|
||||
* routing of an output to digital subsystems on the FPGA such as Counter,
|
||||
* Encoder, and Interrupt.
|
||||
*
|
||||
* The TriggerState output indicates the primary output value of the trigger. If
|
||||
* the analog signal is less than the lower limit, the output is false. If the
|
||||
* analog value is greater than the upper limit, then the output is true. If the
|
||||
* analog value is in between, then the trigger output state maintains its most
|
||||
* recent value.
|
||||
*
|
||||
* The InWindow output indicates whether or not the analog signal is inside the
|
||||
* range defined by the limits.
|
||||
*
|
||||
* The RisingPulse and FallingPulse outputs detect an instantaneous transition
|
||||
* from above the upper limit to below the lower limit, and vise versa. These
|
||||
* pulses represent a rollover condition of a sensor and can be routed to an up
|
||||
* / down couter or to interrupts. Because the outputs generate a pulse, they
|
||||
* cannot be read directly. To help ensure that a rollover condition is not
|
||||
* missed, there is an average rejection filter available that operates on the
|
||||
* upper 8 bits of a 12 bit number and selects the nearest outlyer of 3 samples.
|
||||
* This will reject a sample that is (due to averaging or sampling) errantly
|
||||
* between the two limits. This filter will fail if more than one sample in a
|
||||
* row is errantly in between the two limits. You may see this problem if
|
||||
* attempting to use this feature with a mechanical rollover sensor, such as a
|
||||
* 360 degree no-stop potentiometer without signal conditioning, because the
|
||||
* rollover transition is not sharp / clean enough. Using the averaging engine
|
||||
* may help with this, but rotational speeds of the sensor will then be limited.
|
||||
*/
|
||||
public class AnalogTriggerOutput extends DigitalSource implements IInputOutput {
|
||||
|
||||
/**
|
||||
* Exceptions dealing with improper operation of the Analog trigger output
|
||||
*/
|
||||
public class AnalogTriggerOutputException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create a new exception with the given message
|
||||
*
|
||||
* @param message
|
||||
* the message to pass with the exception
|
||||
*/
|
||||
public AnalogTriggerOutputException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private AnalogTrigger m_trigger;
|
||||
private int m_outputType; // define in HALLibrary.AnalogTriggerType
|
||||
|
||||
/**
|
||||
* Create an object that represents one of the four outputs from an analog
|
||||
* trigger.
|
||||
*
|
||||
* Because this class derives from DigitalSource, it can be passed into
|
||||
* routing functions for Counter, Encoder, etc.
|
||||
*
|
||||
* @param trigger
|
||||
* The trigger for which this is an output.
|
||||
* @param outputType
|
||||
* An enum that specifies the output on the trigger to represent.
|
||||
*/
|
||||
public AnalogTriggerOutput(AnalogTrigger trigger, final int outputType) {
|
||||
if (trigger == null)
|
||||
throw new NullPointerException("Analog Trigger given was null");
|
||||
m_trigger = trigger;
|
||||
m_outputType = outputType;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_AnalogTriggerOutput,
|
||||
trigger.getIndex(), outputType);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the analog trigger output.
|
||||
*
|
||||
* @return The state of the analog trigger output.
|
||||
*/
|
||||
public boolean get() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
byte value = HALLibrary.getAnalogTriggerOutput(m_trigger.m_port,
|
||||
m_outputType, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value != 0;
|
||||
}
|
||||
|
||||
public int getChannelForRouting() {
|
||||
return (m_trigger.m_index << 2) + m_outputType;
|
||||
}
|
||||
|
||||
public int getModuleForRouting() {
|
||||
return m_trigger.m_index >> 2;
|
||||
}
|
||||
|
||||
public boolean getAnalogTriggerForRouting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler
|
||||
* the interrupt service routine
|
||||
* @param param
|
||||
* a parameter for the ISR
|
||||
*/
|
||||
// public void requestInterrupts(/*tInterruptHandler*/Object handler, Object
|
||||
// param) {
|
||||
// TODO: add interrupt support
|
||||
// TODO: throw exception
|
||||
// }
|
||||
|
||||
/**
|
||||
* Request interrupts synchronously on this digital input.
|
||||
*/
|
||||
// public void requestInterrupts() {
|
||||
// TODO: throw exception
|
||||
// }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,229 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.IDevice;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
/**
|
||||
* Compressor object.
|
||||
* The Compressor object is designed to handle the operation of the compressor, pressure sensor and
|
||||
* relay for a FIRST robot pneumatics system. The Compressor object starts a task which runs in the
|
||||
* backround and periodically polls the pressure sensor and operates the relay that controls the
|
||||
* compressor.
|
||||
*/
|
||||
public class Compressor extends SensorBase implements IDevice, LiveWindowSendable {
|
||||
|
||||
private DigitalInput m_pressureSwitch;
|
||||
private Relay m_relay;
|
||||
private boolean m_enabled;
|
||||
private Thread m_task;
|
||||
private boolean m_run = true;
|
||||
|
||||
/**
|
||||
* Internal thread.
|
||||
*
|
||||
* Task which checks the compressor pressure switch and operates the relay as necessary
|
||||
* depending on the pressure.
|
||||
*
|
||||
* Do not call this function directly.
|
||||
*/
|
||||
private class CompressorThread extends Thread {
|
||||
|
||||
Compressor m_compressor;
|
||||
|
||||
CompressorThread(Compressor comp) {
|
||||
m_compressor = comp;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (m_run) {
|
||||
if (m_compressor.enabled()) {
|
||||
m_compressor.setRelayValue(!m_compressor.getPressureSwitchValue() ? Relay.Value.kOn : Relay.Value.kOff);
|
||||
} else {
|
||||
m_compressor.setRelayValue(Relay.Value.kOff);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Compressor object.
|
||||
* This method is the common initialization code for all the constructors for the Compressor
|
||||
* object. It takes the relay channel and pressure switch channel and spawns a task that polls the
|
||||
* compressor and sensor.
|
||||
*
|
||||
* You MUST start the compressor by calling the start() method.
|
||||
*/
|
||||
private void initCompressor(final int pressureSwitchSlot,
|
||||
final int pressureSwitchChannel,
|
||||
final int compresssorRelaySlot,
|
||||
final int compressorRelayChannel) {
|
||||
|
||||
m_enabled = false;
|
||||
m_pressureSwitch = new DigitalInput(pressureSwitchSlot, pressureSwitchChannel);
|
||||
m_relay = new Relay(compresssorRelaySlot, compressorRelayChannel, Relay.Direction.kForward);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Compressor, 0);
|
||||
|
||||
m_task = new CompressorThread(this);
|
||||
m_task.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compressor constructor.
|
||||
* Given a fully specified relay channel and pressure switch channel, initialize the Compressor object.
|
||||
*
|
||||
* You MUST start the compressor by calling the start() method.
|
||||
*
|
||||
* @param pressureSwitchSlot The module that the pressure switch is attached to.
|
||||
* @param pressureSwitchChannel The GPIO channel that the pressure switch is attached to.
|
||||
* @param compresssorRelaySlot The module that the compressor relay is attached to.
|
||||
* @param compressorRelayChannel The relay channel that the compressor relay is attached to.
|
||||
*/
|
||||
public Compressor(final int pressureSwitchSlot,
|
||||
final int pressureSwitchChannel,
|
||||
final int compresssorRelaySlot,
|
||||
final int compressorRelayChannel) {
|
||||
initCompressor(pressureSwitchSlot,
|
||||
pressureSwitchChannel,
|
||||
compresssorRelaySlot,
|
||||
compressorRelayChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compressor constructor.
|
||||
* Given a relay channel and pressure switch channel (both in the default digital module), initialize
|
||||
* the Compressor object.
|
||||
*
|
||||
* You MUST start the compressor by calling the start() method.
|
||||
*
|
||||
* @param pressureSwitchChannel The GPIO channel that the pressure switch is attached to.
|
||||
* @param compressorRelayChannel The relay channel that the compressor relay is attached to.
|
||||
*/
|
||||
public Compressor(final int pressureSwitchChannel, final int compressorRelayChannel) {
|
||||
initCompressor(getDefaultDigitalModule(),
|
||||
pressureSwitchChannel,
|
||||
getDefaultDigitalModule(),
|
||||
compressorRelayChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the Compressor object.
|
||||
* Delete the allocated resources for the compressor and kill the compressor task that is polling
|
||||
* the pressure switch.
|
||||
*/
|
||||
public void free() {
|
||||
m_run = false;
|
||||
try {
|
||||
m_task.join();
|
||||
} catch (InterruptedException e) {}
|
||||
m_pressureSwitch.free();
|
||||
m_relay.free();
|
||||
m_pressureSwitch = null;
|
||||
m_relay = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operate the relay for the compressor.
|
||||
* Change the value of the relay output that is connected to the compressor motor.
|
||||
* This is only intended to be called by the internal polling thread.
|
||||
* @param relayValue the value to set the relay to
|
||||
*/
|
||||
public void setRelayValue(Relay.Value relayValue) {
|
||||
m_relay.set(relayValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pressure switch value.
|
||||
* Read the pressure switch digital input.
|
||||
*
|
||||
* @return The current state of the pressure switch.
|
||||
*/
|
||||
public boolean getPressureSwitchValue() {
|
||||
return m_pressureSwitch.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the compressor.
|
||||
* This method will allow the polling loop to actually operate the compressor. The
|
||||
* is stopped by default and won't operate until starting it.
|
||||
*/
|
||||
public void start() {
|
||||
m_enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the compressor.
|
||||
* This method will stop the compressor from turning on.
|
||||
*/
|
||||
public void stop() {
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of the enabled flag.
|
||||
* Return the state of the enabled flag for the compressor and pressure switch
|
||||
* combination.
|
||||
*
|
||||
* @return The state of the compressor thread's enable flag.
|
||||
*/
|
||||
public boolean enabled() {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Compressor";
|
||||
}
|
||||
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.putBoolean("Enabled", m_enabled);
|
||||
m_table.putBoolean("Pressure Switch", getPressureSwitchValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
/**
|
||||
* An interface for controllers. Controllers run control loops, the most command
|
||||
* are PID controllers and there variants, but this includes anything that is
|
||||
* controlling an actuator in a separate thread.
|
||||
*
|
||||
* @author alex
|
||||
*/
|
||||
interface Controller {
|
||||
/**
|
||||
* Allows the control loop to run.
|
||||
*/
|
||||
public void enable();
|
||||
|
||||
/**
|
||||
* Stops the control loop from running until explicitly re-enabled by calling
|
||||
* {@link enable()}.
|
||||
*/
|
||||
public void disable();
|
||||
}
|
||||
@@ -0,0 +1,731 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* Class for counting the number of ticks on a digital input channel. This is a
|
||||
* general purpose class for counting repetitive events. It can return the
|
||||
* number of counts, the period of the most recent cycle, and detect when the
|
||||
* signal being counted has stopped by supplying a maximum cycle time.
|
||||
*/
|
||||
public class Counter extends SensorBase implements CounterBase,
|
||||
LiveWindowSendable, PIDSource {
|
||||
|
||||
/**
|
||||
* Mode determines how and what the counter counts
|
||||
*/
|
||||
public static class Mode {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kTwoPulse_val = 0;
|
||||
static final int kSemiperiod_val = 1;
|
||||
static final int kPulseLength_val = 2;
|
||||
static final int kExternalDirection_val = 3;
|
||||
/**
|
||||
* mode: two pulse
|
||||
*/
|
||||
public static final Mode kTwoPulse = new Mode(kTwoPulse_val);
|
||||
/**
|
||||
* mode: semi period
|
||||
*/
|
||||
public static final Mode kSemiperiod = new Mode(kSemiperiod_val);
|
||||
/**
|
||||
* mode: pulse length
|
||||
*/
|
||||
public static final Mode kPulseLength = new Mode(kPulseLength_val);
|
||||
/**
|
||||
* mode: external direction
|
||||
*/
|
||||
public static final Mode kExternalDirection = new Mode(
|
||||
kExternalDirection_val);
|
||||
|
||||
private Mode(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private DigitalSource m_upSource; // /< What makes the counter count up.
|
||||
private DigitalSource m_downSource; // /< What makes the counter count down.
|
||||
private boolean m_allocatedUpSource;
|
||||
private boolean m_allocatedDownSource;
|
||||
private Pointer m_counter; // /< The FPGA counter object.
|
||||
private int m_index; // /< The index of this counter.
|
||||
private PIDSourceParameter m_pidSource;
|
||||
private double m_distancePerPulse; // distance of travel for each tick
|
||||
|
||||
private void initCounter(final Mode mode) {
|
||||
IntBuffer status = IntBuffer.allocate(1), index = IntBuffer.allocate(1);
|
||||
m_counter = HALLibrary.initializeCounter(mode.value, index, status);
|
||||
HALUtil.checkStatus(status);
|
||||
m_index = index.get();
|
||||
|
||||
m_allocatedUpSource = false;
|
||||
m_allocatedDownSource = false;
|
||||
m_upSource = null;
|
||||
m_downSource = null;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Counter, m_index,
|
||||
mode.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a counter where no sources are selected. Then they
|
||||
* all must be selected by calling functions to specify the upsource and the
|
||||
* downsource independently.
|
||||
*/
|
||||
public Counter() {
|
||||
initCounter(Mode.kTwoPulse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a counter from a Digital Input. This is used if an
|
||||
* existing digital input is to be shared by multiple other objects such as
|
||||
* encoders.
|
||||
*
|
||||
* @param source
|
||||
* the digital source to count
|
||||
*/
|
||||
public Counter(DigitalSource source) {
|
||||
if (source == null)
|
||||
throw new NullPointerException("Source given was null");
|
||||
initCounter(Mode.kTwoPulse);
|
||||
setUpSource(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an up-Counter instance
|
||||
* given a channel. The default digital module is assumed.
|
||||
*
|
||||
* @param channel
|
||||
* the digital input channel to count
|
||||
*/
|
||||
public Counter(int channel) {
|
||||
initCounter(Mode.kTwoPulse);
|
||||
setUpSource(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an instance of an
|
||||
* up-Counter given a digital module and a channel.
|
||||
*
|
||||
* @param slot
|
||||
* The cRIO chassis slot for the digital module used
|
||||
* @param channel
|
||||
* The channel in the digital module
|
||||
*/
|
||||
public Counter(int slot, int channel) {
|
||||
initCounter(Mode.kTwoPulse);
|
||||
setUpSource(slot, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an instance of a simple
|
||||
* up-Counter given an analog trigger. Use the trigger state output from the
|
||||
* analog trigger.
|
||||
*
|
||||
* @param encodingType
|
||||
* which edges to count
|
||||
* @param upSource
|
||||
* first source to count
|
||||
* @param downSource
|
||||
* second source for direction
|
||||
* @param inverted
|
||||
* true to invert the count
|
||||
*/
|
||||
public Counter(EncodingType encodingType, DigitalSource upSource,
|
||||
DigitalSource downSource, boolean inverted) {
|
||||
initCounter(Mode.kExternalDirection);
|
||||
if (encodingType != EncodingType.k1X
|
||||
&& encodingType != EncodingType.k2X) {
|
||||
throw new RuntimeException(
|
||||
"Counters only support 1X and 2X quadreature decoding!");
|
||||
}
|
||||
if (upSource == null)
|
||||
throw new NullPointerException("Up Source given was null");
|
||||
setUpSource(upSource);
|
||||
if (downSource == null)
|
||||
throw new NullPointerException("Down Source given was null");
|
||||
setDownSource(downSource);
|
||||
|
||||
if (encodingType == null)
|
||||
throw new NullPointerException("Encoding type given was null");
|
||||
|
||||
if (encodingType == EncodingType.k1X) {
|
||||
setUpSourceEdge(true, false);
|
||||
} else {
|
||||
setUpSourceEdge(true, true);
|
||||
}
|
||||
|
||||
setDownSourceEdge(inverted, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an instance of a simple
|
||||
* up-Counter given an analog trigger. Use the trigger state output from the
|
||||
* analog trigger.
|
||||
*
|
||||
* @param trigger
|
||||
* the analog trigger to count
|
||||
*/
|
||||
public Counter(AnalogTrigger trigger) {
|
||||
initCounter(Mode.kTwoPulse);
|
||||
setUpSource(trigger.createOutput(HALLibrary.AnalogTriggerType.kState));
|
||||
}
|
||||
|
||||
public void free() {
|
||||
setUpdateWhenEmpty(true);
|
||||
|
||||
clearUpSource();
|
||||
clearDownSource();
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.freeCounter(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
|
||||
m_upSource = null;
|
||||
m_downSource = null;
|
||||
m_counter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the up source for the counter as digital input channel and slot.
|
||||
*
|
||||
* @param slot
|
||||
* the location of the digital module to use
|
||||
* @param channel
|
||||
* the digital port to count
|
||||
*/
|
||||
public void setUpSource(int slot, int channel) {
|
||||
setUpSource(new DigitalInput(slot, channel));
|
||||
m_allocatedUpSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upsource for the counter as a digital input channel. The slot
|
||||
* will be the default digital module slot.
|
||||
*
|
||||
* @param channel
|
||||
* the digital port to count
|
||||
*/
|
||||
public void setUpSource(int channel) {
|
||||
setUpSource(new DigitalInput(channel));
|
||||
m_allocatedUpSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count up. Set the up
|
||||
* counting DigitalSource.
|
||||
*
|
||||
* @param source
|
||||
* the digital source to count
|
||||
*/
|
||||
public void setUpSource(DigitalSource source) {
|
||||
if (m_upSource != null && m_allocatedUpSource) {
|
||||
m_upSource.free();
|
||||
m_allocatedUpSource = false;
|
||||
}
|
||||
m_upSource = source;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterUpSourceWithModule(m_counter,
|
||||
(byte) source.getModuleForRouting(),
|
||||
source.getChannelForRouting(),
|
||||
(byte) (source.getAnalogTriggerForRouting() ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the up counting source to be an analog trigger.
|
||||
*
|
||||
* @param analogTrigger
|
||||
* The analog trigger object that is used for the Up Source
|
||||
* @param triggerType
|
||||
* The analog trigger output that will trigger the counter.
|
||||
*/
|
||||
public void setUpSource(AnalogTrigger analogTrigger, int triggerType) {
|
||||
analogTrigger.createOutput(triggerType);
|
||||
m_allocatedUpSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on an up counting source. Set the up source to
|
||||
* either detect rising edges or falling edges.
|
||||
*
|
||||
* @param risingEdge
|
||||
* true to count rising edge
|
||||
* @param fallingEdge
|
||||
* true to count falling edge
|
||||
*/
|
||||
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_upSource == null)
|
||||
throw new RuntimeException(
|
||||
"Up Source must be set before setting the edge!");
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterUpSourceEdge(m_counter,
|
||||
(byte) (risingEdge ? 1 : 0), (byte) (fallingEdge ? 1 : 0),
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the up counting source to the counter.
|
||||
*/
|
||||
public void clearUpSource() {
|
||||
if (m_upSource != null && m_allocatedUpSource) {
|
||||
m_upSource.free();
|
||||
m_allocatedUpSource = false;
|
||||
}
|
||||
m_upSource = null;
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.clearCounterUpSource(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the down counting source to be a digital input channel. The slot will
|
||||
* be set to the default digital module slot.
|
||||
*
|
||||
* @param channel
|
||||
* the digital port to count
|
||||
*/
|
||||
public void setDownSource(int channel) {
|
||||
setDownSource(new DigitalInput(channel));
|
||||
m_allocatedDownSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the down counting source to be a digital input slot and channel.
|
||||
*
|
||||
* @param slot
|
||||
* the location of the digital module to use
|
||||
* @param channel
|
||||
* the digital port to count
|
||||
*/
|
||||
public void setDownSource(int slot, int channel) {
|
||||
setDownSource(new DigitalInput(slot, channel));
|
||||
m_allocatedDownSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count down. Set the down
|
||||
* counting DigitalSource.
|
||||
*
|
||||
* @param source
|
||||
* the digital source to count
|
||||
*/
|
||||
public void setDownSource(DigitalSource source) {
|
||||
if (m_downSource != null && m_allocatedDownSource) {
|
||||
m_downSource.free();
|
||||
m_allocatedDownSource = false;
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterDownSourceWithModule(m_counter,
|
||||
(byte) source.getModuleForRouting(),
|
||||
source.getChannelForRouting(),
|
||||
(byte) (source.getAnalogTriggerForRouting() ? 1 : 0), status);
|
||||
if (status.get() == HALLibrary.PARAMETER_OUT_OF_RANGE) {
|
||||
throw new IllegalArgumentException(
|
||||
"Counter only supports DownSource in TwoPulse and ExternalDirection modes.");
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
m_downSource = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the down counting source to be an analog trigger.
|
||||
*
|
||||
* @param analogTrigger
|
||||
* The analog trigger object that is used for the Down Source
|
||||
* @param triggerType
|
||||
* The analog trigger output that will trigger the counter.
|
||||
*/
|
||||
public void setDownSource(AnalogTrigger analogTrigger, int triggerType) {
|
||||
setDownSource(analogTrigger.createOutput(triggerType));
|
||||
m_allocatedDownSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on a down counting source. Set the down source
|
||||
* to either detect rising edges or falling edges.
|
||||
*
|
||||
* @param risingEdge
|
||||
* true to count the rising edge
|
||||
* @param fallingEdge
|
||||
* true to count the falling edge
|
||||
*/
|
||||
public void setDownSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_downSource == null)
|
||||
throw new RuntimeException(
|
||||
" Down Source must be set before setting the edge!");
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterDownSourceEdge(m_counter, (byte) (risingEdge ? 1
|
||||
: 0), (byte) (fallingEdge ? 0 : 1), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the down counting source to the counter.
|
||||
*/
|
||||
public void clearDownSource() {
|
||||
if (m_downSource != null && m_allocatedDownSource) {
|
||||
m_downSource.free();
|
||||
m_allocatedDownSource = false;
|
||||
}
|
||||
m_downSource = null;
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.clearCounterDownSource(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set standard up / down counting mode on this counter. Up and down counts
|
||||
* are sourced independently from two inputs.
|
||||
*/
|
||||
public void setUpDownCounterMode() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterUpDownMode(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set external direction mode on this counter. Counts are sourced on the Up
|
||||
* counter input. The Down counter input represents the direction to count.
|
||||
*/
|
||||
public void setExternalDirectionMode() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterExternalDirectionMode(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Semi-period mode on this counter. Counts up on both rising and
|
||||
* falling edges.
|
||||
*
|
||||
* @param highSemiPeriod
|
||||
* true to count up on both rising and falling
|
||||
*/
|
||||
public void setSemiPeriodMode(boolean highSemiPeriod) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterSemiPeriodMode(m_counter,
|
||||
(byte) (highSemiPeriod ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the counter to count in up or down based on the length of the
|
||||
* input pulse. This mode is most useful for direction sensitive gear tooth
|
||||
* sensors.
|
||||
*
|
||||
* @param threshold
|
||||
* The pulse length beyond which the counter counts the opposite
|
||||
* direction. Units are seconds.
|
||||
*/
|
||||
public void setPulseLengthMode(double threshold) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterPulseLengthMode(m_counter, (float) threshold,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the Counter counting. This enables the counter and it starts
|
||||
* accumulating counts from the associated input channel. The counter value
|
||||
* is not reset on starting, and still has the previous value.
|
||||
*/
|
||||
public void start() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.startCounter(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current counter value. Read the value at this instant. It may
|
||||
* still be running, so it reflects the current value. Next time it is read,
|
||||
* it might have a different value.
|
||||
*/
|
||||
public int get() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getCounter(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current scaled counter value. Read the value at this instant,
|
||||
* scaled by the distance per pulse (defaults to 1).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public double getDistance() {
|
||||
return get() * m_distancePerPulse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Counter to zero. Set the counter value to zero. This doesn't
|
||||
* effect the running state of the counter, just sets the current value to
|
||||
* zero.
|
||||
*/
|
||||
public void reset() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.resetCounter(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the Counter. Stops the counting but doesn't effect the current
|
||||
* value.
|
||||
*/
|
||||
public void stop() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.stopCounter(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum period where the device is still considered "moving".
|
||||
* Sets the maximum period where the device is considered moving. This value
|
||||
* is used to determine the "stopped" state of the counter using the
|
||||
* GetStopped method.
|
||||
*
|
||||
* @param maxPeriod
|
||||
* The maximum period where the counted device is considered
|
||||
* moving in seconds.
|
||||
*/
|
||||
public void setMaxPeriod(double maxPeriod) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterMaxPeriod(m_counter, maxPeriod, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select whether you want to continue updating the event timer output when
|
||||
* there are no samples captured. The output of the event timer has a buffer
|
||||
* of periods that are averaged and posted to a register on the FPGA. When
|
||||
* the timer detects that the event source has stopped (based on the
|
||||
* MaxPeriod) the buffer of samples to be averaged is emptied. If you enable
|
||||
* the update when empty, you will be notified of the stopped source and the
|
||||
* event time will report 0 samples. If you disable update when empty, the
|
||||
* most recent average will remain on the output until a new sample is
|
||||
* acquired. You will never see 0 samples output (except when there have
|
||||
* been no events since an FPGA reset) and you will likely not see the
|
||||
* stopped bit become true (since it is updated at the end of an average and
|
||||
* there are no samples to average).
|
||||
*
|
||||
* @param enabled
|
||||
* true to continue updating
|
||||
*/
|
||||
public void setUpdateWhenEmpty(boolean enabled) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterUpdateWhenEmpty(m_counter,
|
||||
(byte) (enabled ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the clock is stopped. Determine if the clocked input is
|
||||
* stopped based on the MaxPeriod value set using the SetMaxPeriod method.
|
||||
* If the clock exceeds the MaxPeriod, then the device (and counter) are
|
||||
* assumed to be stopped and it returns true.
|
||||
*
|
||||
* @return Returns true if the most recent counter period exceeds the
|
||||
* MaxPeriod value set by SetMaxPeriod.
|
||||
*/
|
||||
public boolean getStopped() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getCounterStopped(m_counter, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last direction the counter value changed.
|
||||
*
|
||||
* @return The last direction the counter value changed.
|
||||
*/
|
||||
public boolean getDirection() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getCounterDirection(m_counter, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Counter to return reversed sensing on the direction. This allows
|
||||
* counters to change the direction they are counting in the case of 1X and
|
||||
* 2X quadrature encoding only. Any other counter mode isn't supported.
|
||||
*
|
||||
* @param reverseDirection
|
||||
* true if the value counted should be negated.
|
||||
*/
|
||||
public void setReverseDirection(boolean reverseDirection) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterReverseDirection(m_counter,
|
||||
(byte) (reverseDirection ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Period of the most recent count. Returns the time interval of the
|
||||
* most recent count. This can be used for velocity calculations to
|
||||
* determine shaft speed.
|
||||
*
|
||||
* @returns The period of the last two pulses in units of seconds.
|
||||
*/
|
||||
public double getPeriod() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double value = HALLibrary.getCounterPeriod(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current rate of the Counter. Read the current rate of the counter
|
||||
* accounting for the distance per pulse value. The default value for
|
||||
* distance per pulse (1) yields units of pulses per second.
|
||||
*
|
||||
* @return The rate in units/sec
|
||||
*/
|
||||
public double getRate() {
|
||||
return m_distancePerPulse / getPeriod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Samples to Average which specifies the number of samples of the
|
||||
* timer to average when calculating the period. Perform averaging to
|
||||
* account for mechanical imperfections or as oversampling to increase
|
||||
* resolution.
|
||||
*
|
||||
* @param samplesToAverage
|
||||
* The number of samples to average from 1 to 127.
|
||||
*/
|
||||
public void setSamplesToAverage(int samplesToAverage) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setCounterSamplesToAverage(m_counter, samplesToAverage,
|
||||
status);
|
||||
if (status.get() == HALLibrary.PARAMETER_OUT_OF_RANGE) {
|
||||
throw new BoundaryException(BoundaryException.getMessage(
|
||||
samplesToAverage, 1, 127));
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Samples to Average which specifies the number of samples of the
|
||||
* timer to average when calculating the period. Perform averaging to
|
||||
* account for mechanical imperfections or as oversampling to increase
|
||||
* resolution.
|
||||
*
|
||||
* @return SamplesToAverage The number of samples being averaged (from 1 to
|
||||
* 127)
|
||||
*/
|
||||
public int getSamplesToAverage() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getCounterSamplesToAverage(m_counter, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance per pulse for this counter. This sets the multiplier
|
||||
* used to determine the distance driven based on the count value from the
|
||||
* encoder. Set this value based on the Pulses per Revolution and factor in
|
||||
* any gearing reductions. This distance can be in any units you like,
|
||||
* linear or angular.
|
||||
*
|
||||
* @param distancePerPulse
|
||||
* The scale factor that will be used to convert pulses to useful
|
||||
* units.
|
||||
*/
|
||||
public void setDistancePerPulse(double distancePerPulse) {
|
||||
m_distancePerPulse = distancePerPulse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which parameter of the encoder you are using as a process control
|
||||
* variable. The counter class supports the rate and distance parameters.
|
||||
*
|
||||
* @param pidSource
|
||||
* An enum to select the parameter.
|
||||
*/
|
||||
public void setPIDSourceParameter(PIDSourceParameter pidSource) {
|
||||
BoundaryException.assertWithinBounds(pidSource.value, 0, 1);
|
||||
m_pidSource = pidSource;
|
||||
}
|
||||
|
||||
public double pidGet() {
|
||||
switch (m_pidSource.value) {
|
||||
case PIDSourceParameter.kDistance_val:
|
||||
return getDistance();
|
||||
case PIDSourceParameter.kRate_val:
|
||||
return getRate();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
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) {
|
||||
m_table.putNumber("Value", get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* Interface for counting the number of ticks on a digital input channel.
|
||||
* Encoders, Gear tooth sensors, and counters should all subclass this so it can be used to
|
||||
* build more advanced classes for control and driving.
|
||||
*/
|
||||
public interface CounterBase {
|
||||
|
||||
/**
|
||||
* The number of edges for the counterbase to increment or decrement on
|
||||
*/
|
||||
public static class EncodingType {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int k1X_val = 0;
|
||||
static final int k2X_val = 1;
|
||||
static final int k4X_val = 2;
|
||||
/**
|
||||
* Count only the rising edge
|
||||
*/
|
||||
public static final EncodingType k1X = new EncodingType(k1X_val);
|
||||
/**
|
||||
* Count both the rising and falling edge
|
||||
*/
|
||||
public static final EncodingType k2X = new EncodingType(k2X_val);
|
||||
/**
|
||||
* Count rising and falling on both channels
|
||||
*/
|
||||
public static final EncodingType k4X = new EncodingType(k4X_val);
|
||||
|
||||
private EncodingType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the counter
|
||||
*/
|
||||
public void start();
|
||||
|
||||
/**
|
||||
* Get the count
|
||||
* @return the count
|
||||
*/
|
||||
int get();
|
||||
|
||||
/**
|
||||
* Reset the count to zero
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Stop counting
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Get the time between the last two edges counted
|
||||
* @return the time beteween the last two ticks in seconds
|
||||
*/
|
||||
double getPeriod();
|
||||
|
||||
/**
|
||||
* Set the maximum time between edges to be considered stalled
|
||||
* @param maxPeriod the maximum period in seconds
|
||||
*/
|
||||
void setMaxPeriod(double maxPeriod);
|
||||
|
||||
/**
|
||||
* Determine if the counter is not moving
|
||||
* @return true if the counter has not changed for the max period
|
||||
*/
|
||||
boolean getStopped();
|
||||
|
||||
/**
|
||||
* Determine which direction the counter is going
|
||||
* @return true for one direction, false for the other
|
||||
*/
|
||||
boolean getDirection();
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.util.Stack;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
|
||||
/**
|
||||
* Pack data into the "user data" field that gets sent to the dashboard laptop
|
||||
* via the driver station.
|
||||
*/
|
||||
public class Dashboard implements IDashboard, IInputOutput {
|
||||
|
||||
protected class MemAccess {
|
||||
|
||||
byte[] m_bytes;
|
||||
|
||||
protected MemAccess(byte[] bytes) {
|
||||
m_bytes = bytes;
|
||||
}
|
||||
|
||||
protected MemAccess(int length) {
|
||||
m_bytes = new byte[length];
|
||||
}
|
||||
|
||||
public void setByte(int index, byte value) {
|
||||
m_bytes[index] = value;
|
||||
}
|
||||
|
||||
public void setShort(int index, short value) {
|
||||
setByte(index++, (byte) (value >>> 8));
|
||||
setByte(index++, (byte) (value));
|
||||
}
|
||||
|
||||
public void setInt(int index, int value) {
|
||||
setByte(index++, (byte) (value >>> 24));
|
||||
setByte(index++, (byte) (value >>> 16));
|
||||
setByte(index++, (byte) (value >>> 8));
|
||||
setByte(index++, (byte) (value));
|
||||
}
|
||||
|
||||
public void setFloat(int index, float value) {
|
||||
setInt(index, Float.floatToIntBits(value));
|
||||
}
|
||||
|
||||
public void setDouble(int index, double value) {
|
||||
setInt(index, (int) (Double.doubleToLongBits(value) >>> 32));
|
||||
setInt(index + 4, (int) Double.doubleToLongBits(value));
|
||||
}
|
||||
|
||||
public void setString(int index, String value) {
|
||||
setBytes(index, value.getBytes(), 0, value.length());
|
||||
}
|
||||
|
||||
public void setBytes(int index, byte[] value, int offset, int number) {
|
||||
for (int i = 0; i < number; i++) {
|
||||
m_bytes[i + index] = value[i + offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
private static final String kArray = "Array";
|
||||
private static final String kCluster = "Cluster";
|
||||
private static final Integer kByte = new Integer(0);
|
||||
private static final Integer kShort = new Integer(1);
|
||||
private static final Integer kInt = new Integer(2);
|
||||
private static final Integer kFloat = new Integer(3);
|
||||
private static final Integer kDouble = new Integer(4);
|
||||
private static final Integer kString = new Integer(5);
|
||||
private static final Integer kOther = new Integer(6);
|
||||
private static final Integer kBoolean = new Integer(7);
|
||||
private static final int kMaxDashboardDataSize = DriverStation.USER_STATUS_DATA_SIZE -
|
||||
4 * 3 - 1; // 13 bytes needed for 3 size parameters and the sequence number
|
||||
private static boolean m_reported = false;
|
||||
protected MemAccess m_userStatus;
|
||||
protected int m_userStatusSize = 0;
|
||||
private MemAccess m_localBuffer;
|
||||
private int m_packPtr;
|
||||
private Stack m_expectedArrayElementType = new Stack();
|
||||
private Stack m_arrayElementCount = new Stack();
|
||||
private Stack m_arraySizePtr = new Stack();
|
||||
private Stack m_complexTypeStack = new Stack();
|
||||
private final Object m_statusDataSemaphore;
|
||||
|
||||
/**
|
||||
* Dashboard constructor.
|
||||
*
|
||||
* This is only called once when the DriverStation constructor is called.
|
||||
* @param statusDataSemaphore the object to synchronize on
|
||||
*/
|
||||
protected Dashboard(Object statusDataSemaphore) {
|
||||
m_userStatus = new MemAccess(kMaxDashboardDataSize);
|
||||
m_localBuffer = new MemAccess(kMaxDashboardDataSize);
|
||||
m_packPtr = 0;
|
||||
m_statusDataSemaphore = statusDataSemaphore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a signed 8-bit int into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addByte(byte value) {
|
||||
if (!validateAdd(1)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setByte(m_packPtr, value);
|
||||
m_packPtr += 1;
|
||||
return addedElement(kByte);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a signed 16-bit int into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addShort(short value) {
|
||||
if (!validateAdd(2)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setShort(m_packPtr, value);
|
||||
m_packPtr += 2;
|
||||
return addedElement(kShort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a signed 32-bit int into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addInt(int value) {
|
||||
if (!validateAdd(4)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setInt(m_packPtr, value);
|
||||
m_packPtr += 4;
|
||||
return addedElement(kInt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a 32-bit floating point number into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addFloat(float value) {
|
||||
if (!validateAdd(4)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setFloat(m_packPtr, value);
|
||||
m_packPtr += 4;
|
||||
return addedElement(kFloat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a 64-bit floating point number into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addDouble(double value) {
|
||||
if (!validateAdd(8)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setDouble(m_packPtr, value);
|
||||
m_packPtr += 8;
|
||||
return addedElement(kDouble);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a boolean into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addBoolean(boolean value) {
|
||||
if (!validateAdd(1)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setByte(m_packPtr, (byte) (value ? 1 : 0));
|
||||
m_packPtr += 1;
|
||||
return addedElement(kBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a NULL-terminated string of 8-bit characters into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addString(String value) {
|
||||
if (!validateAdd(value.length() + 4)) {
|
||||
return false;
|
||||
}
|
||||
m_localBuffer.setInt(m_packPtr, value.length());
|
||||
m_packPtr += 4;
|
||||
m_localBuffer.setString(m_packPtr, value);
|
||||
m_packPtr += value.length();
|
||||
return addedElement(kString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a string of 8-bit characters of specified length into the dashboard data structure.
|
||||
* @param value Data to be packed into the structure.
|
||||
* @param length The number of bytes in the string to pack.
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addString(String value, int length) {
|
||||
return addString(value.substring(0, length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an array in the packed dashboard data structure.
|
||||
*
|
||||
* After calling addArray(), call the appropriate Add method for each element of the array.
|
||||
* Make sure you call the same add each time. An array must contain elements of the same type.
|
||||
* You can use clusters inside of arrays to make each element of the array contain a structure of values.
|
||||
* You can also nest arrays inside of other arrays.
|
||||
* Every call to addArray() must have a matching call to finalizeArray().
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addArray() {
|
||||
if (!validateAdd(4)) {
|
||||
return false;
|
||||
}
|
||||
m_complexTypeStack.push(kArray);
|
||||
m_arrayElementCount.push(new Integer(0));
|
||||
m_arraySizePtr.push(new Integer(m_packPtr));
|
||||
m_packPtr += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the end of an array packed into the dashboard data structure.
|
||||
*
|
||||
* After packing data into the array, call finalizeArray().
|
||||
* Every call to addArray() must have a matching call to finalizeArray().
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean finalizeArray() {
|
||||
if (m_complexTypeStack.peek() != kArray) {
|
||||
System.err.println("Attempted to finalize an array in the middle of a cluster or without starting the array");
|
||||
return false;
|
||||
}
|
||||
m_complexTypeStack.pop();
|
||||
m_localBuffer.setInt(((Integer) m_arraySizePtr.pop()).intValue(),
|
||||
((Integer) m_arrayElementCount.peek()).intValue());
|
||||
|
||||
|
||||
if (((Integer) m_arrayElementCount.peek()).intValue() != 0) {
|
||||
m_expectedArrayElementType.pop();
|
||||
}
|
||||
m_arrayElementCount.pop();
|
||||
return addedElement(kOther);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a cluster in the packed dashboard data structure.
|
||||
*
|
||||
* After calling addCluster(), call the appropriate Add method for each element of the cluster.
|
||||
* You can use clusters inside of arrays to make each element of the array contain a structure of values.
|
||||
* Every call to addCluster() must have a matching call to finalizeCluster().
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean addCluster() {
|
||||
m_complexTypeStack.push(kCluster);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate the end of a cluster packed into the dashboard data structure.
|
||||
*
|
||||
* After packing data into the cluster, call finalizeCluster().
|
||||
* Every call to addCluster() must have a matching call to finalizeCluster
|
||||
* @return True on success
|
||||
*/
|
||||
public boolean finalizeCluster() {
|
||||
if (m_complexTypeStack.peek() != kCluster) {
|
||||
System.err.println("Attempted to close a cluster on an open array or without starting the cluster");
|
||||
return false;
|
||||
}
|
||||
m_complexTypeStack.pop();
|
||||
return addedElement(kOther);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the packing is complete and commit the buffer to the DriverStation.
|
||||
*
|
||||
* The packing of the dashboard packet is complete.
|
||||
* If you are not using the packed dashboard data, you can call commit() to commit the Printf() buffer and the error string buffer.
|
||||
* In effect, you are packing an empty structure.
|
||||
* Prepares a packet to go to the dashboard...
|
||||
* Pack the sequence number, Printf() buffer, the errors messages (not implemented yet), and packed dashboard data buffer.
|
||||
* @return The total size of the data packed into the userData field of the status packet.
|
||||
*/
|
||||
public synchronized int commit() {
|
||||
|
||||
if (!m_complexTypeStack.empty()) {
|
||||
System.err.println("didn't finish complex type");
|
||||
m_packPtr = 0;
|
||||
System.err.println("didn't finish complex type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!m_reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_Dashboard, 0);
|
||||
m_reported = true;
|
||||
}
|
||||
|
||||
synchronized (m_statusDataSemaphore) {
|
||||
// Sequence number
|
||||
DriverStation.getInstance().incrementUpdateNumber();
|
||||
|
||||
// Packed Dashboard Data
|
||||
m_userStatusSize = m_packPtr;
|
||||
m_userStatus.setBytes(0, m_localBuffer.m_bytes, 0, m_userStatusSize);
|
||||
m_packPtr = 0;
|
||||
|
||||
}
|
||||
return m_userStatusSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the data being packed will fit in the buffer.
|
||||
*/
|
||||
private boolean validateAdd(int size) {
|
||||
if (m_packPtr + size > kMaxDashboardDataSize) {
|
||||
m_packPtr = 0;
|
||||
System.err.println("Dashboard data is too long to send");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for consistent types when adding elements to an array and keep track of the number of elements in the array.
|
||||
*/
|
||||
private boolean addedElement(Integer type) {
|
||||
if (isArrayRoot()) {
|
||||
if (((Integer) m_arrayElementCount.peek()).intValue() == 0) {
|
||||
m_expectedArrayElementType.push(type);
|
||||
} else {
|
||||
if (type != m_expectedArrayElementType.peek()) {
|
||||
System.err.println("Attempted to add multiple datatypes to the same array");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_arrayElementCount.push(new Integer(((Integer) m_arrayElementCount.pop()).intValue() + 1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the top of the type stack an array?
|
||||
*/
|
||||
private boolean isArrayRoot() {
|
||||
return !m_complexTypeStack.empty() && m_complexTypeStack.peek() == kArray;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return m_userStatus.m_bytes;
|
||||
}
|
||||
|
||||
public int getBytesLength() {
|
||||
return m_userStatusSize;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary.InterruptHandlerFunction;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Class to read a digital input. This class will read digital inputs and return
|
||||
* the current value on the channel. Other devices such as encoders, gear tooth
|
||||
* sensors, etc. that are implemented elsewhere will automatically allocate
|
||||
* digital inputs and outputs as required. This class is only for devices like
|
||||
* switches etc. that aren't implemented anywhere else.
|
||||
*/
|
||||
public class DigitalInput extends DigitalSource implements IInputOutput,
|
||||
LiveWindowSendable {
|
||||
|
||||
/**
|
||||
* Create an instance of a Digital Input class. Creates a digital input
|
||||
* given a channel and uses the default module.
|
||||
*
|
||||
* @param channel
|
||||
* the port for the digital input
|
||||
*/
|
||||
public DigitalInput(int channel) {
|
||||
this(getDefaultDigitalModule(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Digital Input class. Creates a digital input
|
||||
* given an channel and module.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use for this input
|
||||
* @param channel
|
||||
* the port for the digital input
|
||||
*/
|
||||
public DigitalInput(int moduleNumber, int channel) {
|
||||
initDigitalPort(moduleNumber, channel, true);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_DigitalInput,
|
||||
channel, moduleNumber - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value from a digital input channel. Retrieve the value of a
|
||||
* single digital input channel from the FPGA.
|
||||
*
|
||||
* @return the stats of the digital input
|
||||
*/
|
||||
public boolean get() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getDIO(m_port, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channel of the digital input
|
||||
*
|
||||
* @return The GPIO channel number that this object represents.
|
||||
*/
|
||||
public int getChannel() {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
public boolean getAnalogTriggerForRouting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler
|
||||
* The address of the interrupt handler function of type
|
||||
* tInterruptHandler that will be called whenever there is an
|
||||
* interrupt on the digitial input port. Request interrupts in
|
||||
* synchronus mode where the user program interrupt handler will
|
||||
* be called when an interrupt occurs. The default is interrupt
|
||||
* on rising edges only.
|
||||
*/
|
||||
public void requestInterrupts(InterruptHandlerFunction handler) {
|
||||
// TODO: add interrupt support
|
||||
|
||||
try {
|
||||
m_interruptIndex = interrupts.allocate();
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"No interrupts are left to be allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(false);
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.requestInterrupts(m_interrupt, (byte) getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status);
|
||||
setUpSourceEdge(true, false);
|
||||
HALLibrary.attachInterruptHandler(m_interrupt, handler, null, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request interrupts synchronously on this digital input. Request
|
||||
* interrupts in synchronus mode where the user program will have to
|
||||
* explicitly wait for the interrupt to occur. The default is interrupt on
|
||||
* rising edges only.
|
||||
*/
|
||||
public void requestInterrupts() {
|
||||
try {
|
||||
m_interruptIndex = interrupts.allocate();
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"No interrupts are left to be allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(true);
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.requestInterrupts(m_interrupt, (byte) getModuleForRouting(),
|
||||
getChannelForRouting(),
|
||||
(byte) (getAnalogTriggerForRouting() ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
setUpSourceEdge(true, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which edge to trigger interrupts on
|
||||
*
|
||||
* @param risingEdge
|
||||
* true to interrupt on rising edge
|
||||
* @param fallingEdge
|
||||
* true to interrupt on falling edge
|
||||
*/
|
||||
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_interrupt != null) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setInterruptUpSourceEdge(m_interrupt,
|
||||
(byte) (risingEdge ? 1 : 0), (byte) (fallingEdge ? 1 : 0),
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"You must call RequestInterrupts before setUpSourceEdge");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Digital Input";
|
||||
}
|
||||
|
||||
private ITable m_table;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
if (m_table != null) {
|
||||
m_table.putBoolean("Value", get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tModuleType;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
|
||||
/**
|
||||
* Class representing a digital module
|
||||
*
|
||||
* @author dtjones
|
||||
*/
|
||||
public class DigitalModule extends Module {
|
||||
|
||||
/**
|
||||
* Expected loop timing
|
||||
*/
|
||||
public static final int kExpectedLoopTiming = 260;
|
||||
private int m_module;
|
||||
private Pointer[] m_digital_ports;
|
||||
private Pointer[] m_relay_ports;
|
||||
private Pointer[] m_pwm_ports;
|
||||
|
||||
/**
|
||||
* Get an instance of an Digital Module. Singleton digital module creation
|
||||
* where a module is allocated on the first use and the same module is
|
||||
* returned on subsequent uses.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to access.
|
||||
* @return The digital module of the specified number.
|
||||
*/
|
||||
public static synchronized DigitalModule getInstance(final int moduleNumber) {
|
||||
SensorBase.checkDigitalModule(moduleNumber);
|
||||
return (DigitalModule) getModule(tModuleType.kModuleType_Digital,
|
||||
moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Convert a channel to its fpga reference
|
||||
*
|
||||
* @param channel
|
||||
* the channel to convert
|
||||
* @return the converted channel
|
||||
*/
|
||||
public static int remapDigitalChannel(final int channel) {
|
||||
System.err.println("This is going away for compatability reasons. Don't use it.");
|
||||
return SensorBase.kDigitalChannels - channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Convert a channel from it's fpga reference
|
||||
*
|
||||
* @param channel
|
||||
* the channel to convert
|
||||
* @return the converted channel
|
||||
*/
|
||||
public static int unmapDigitalChannel(final int channel) {
|
||||
System.err.println("This is going away for compatability reasons. Don't use it.");
|
||||
return SensorBase.kDigitalChannels - channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new digital module
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use (1 or 2)
|
||||
*/
|
||||
protected DigitalModule(final int moduleNumber) {
|
||||
super(tModuleType.kModuleType_Digital, moduleNumber);
|
||||
m_module = moduleNumber;
|
||||
|
||||
m_digital_ports = new Pointer[SensorBase.kDigitalChannels];
|
||||
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) (i + 1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_digital_ports[i] = HALLibrary.initializeDigitalPort(port_pointer,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
m_relay_ports = new Pointer[SensorBase.kRelayChannels];
|
||||
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) (i + 1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_relay_ports[i] = HALLibrary.initializeDigitalPort(port_pointer,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
m_pwm_ports = new Pointer[SensorBase.kPwmChannels];
|
||||
for (int i = 0; i < SensorBase.kPwmChannels; i++) {
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) (i + 1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_pwm_ports[i] = HALLibrary.initializeDigitalPort(port_pointer,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a PWM channel to the desired value. The values range from 0 to 255
|
||||
* and the period is controlled by the PWM Period and MinHigh registers.
|
||||
*
|
||||
* @param channel
|
||||
* The PWM channel to set.
|
||||
* @param value
|
||||
* The PWM value to set.
|
||||
*/
|
||||
public void setPWM(final int channel, final int value) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setPWM(m_pwm_ports[channel - 1], (short) value, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from a PWM channel. The values range from 0 to 255.
|
||||
*
|
||||
* @param channel
|
||||
* The PWM channel to read from.
|
||||
* @return The raw PWM value.
|
||||
*/
|
||||
public int getPWM(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = (int) HALLibrary.getPWM(m_pwm_ports[channel - 1], status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how how often the PWM signal is squelched, thus scaling the period.
|
||||
*
|
||||
* @param channel
|
||||
* The PWM channel to configure.
|
||||
* @param squelchMask
|
||||
* The 2-bit mask of outputs to squelch.
|
||||
*/
|
||||
public void setPWMPeriodScale(final int channel, final int squelchMask) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setPWMPeriodScale(m_pwm_ports[channel - 1], squelchMask,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of a relay. Set the state of a relay output to be forward.
|
||||
* Relays have two outputs and each is independently set to 0v or 12v.
|
||||
*
|
||||
* @param channel
|
||||
* The Relay channel.
|
||||
* @param on
|
||||
* Indicates whether to set the relay to the On state.
|
||||
*/
|
||||
public void setRelayForward(final int channel, final boolean on) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setRelayForward(m_relay_ports[channel - 1], (byte) (on ? 1
|
||||
: 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of a relay. Set the state of a relay output to be reverse.
|
||||
* Relays have two outputs and each is independently set to 0v or 12v.
|
||||
*
|
||||
* @param channel
|
||||
* The Relay channel.
|
||||
* @param on
|
||||
* Indicates whether to set the relay to the On state.
|
||||
*/
|
||||
public void setRelayReverse(final int channel, final boolean on) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setRelayReverse(m_relay_ports[channel - 1], (byte) (on ? 1
|
||||
: 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of the forward relay channel
|
||||
*
|
||||
* @param channel
|
||||
* the channel of the relay to get
|
||||
* @return The current state of the relay.
|
||||
*/
|
||||
public boolean getRelayForward(int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getRelayForward(m_relay_ports[channel - 1],
|
||||
status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of all of the forward relay channels on this
|
||||
* module.
|
||||
*
|
||||
* @return The state of all forward relay channels as a byte.
|
||||
*/
|
||||
public byte getRelayForward() {
|
||||
byte value = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
|
||||
value |= HALLibrary.getRelayForward(m_relay_ports[i], status) << i;
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of the reverse relay channel
|
||||
*
|
||||
* @param channel
|
||||
* the channel of the relay to get
|
||||
* @return The current statte of the relay
|
||||
*/
|
||||
public boolean getRelayReverse(int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getRelayReverse(m_relay_ports[channel - 1],
|
||||
status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current state of all of the reverse relay channels on this
|
||||
* module.
|
||||
*
|
||||
* @return The state of all forward relay channels as a byte.
|
||||
*/
|
||||
public byte getRelayReverse() {
|
||||
byte value = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
|
||||
value |= HALLibrary.getRelayReverse(m_relay_ports[i], status) << i;
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate Digital I/O channels. Allocate channels so that they are not
|
||||
* accidently reused. Also the direction is set at the time of the
|
||||
* allocation.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to allocate.
|
||||
* @param input
|
||||
* Indicates whether the I/O pin is an input (true) or an output
|
||||
* (false).
|
||||
* @return True if the I/O pin was allocated, false otherwise.
|
||||
*/
|
||||
public boolean allocateDIO(final int channel, final boolean input) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean allocated = HALLibrary.allocateDIO(
|
||||
m_digital_ports[channel - 1], (byte) (input ? 1 : 0), status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resource associated with a digital I/O channel.
|
||||
*
|
||||
* @param channel
|
||||
* The channel whose resources should be freed.
|
||||
*/
|
||||
public void freeDIO(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.freeDIO(m_digital_ports[channel - 1], status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a digital I/O bit to the FPGA. Set a single value on a digital I/O
|
||||
* channel.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to set.
|
||||
* @param value
|
||||
* The value to set.
|
||||
*/
|
||||
public void setDIO(final int channel, final boolean value) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setDIO(m_digital_ports[channel - 1], (byte) (value ? 1 : 0),
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a digital I/O bit from the FPGA. Get a single value from a digital
|
||||
* I/O channel.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to read
|
||||
* @return The value of the selected channel
|
||||
*/
|
||||
public boolean getDIO(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getDIO(m_digital_ports[channel - 1], status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the state of all the Digital I/O lines from the FPGA These are not
|
||||
* remapped to logical order. They are still in hardware order.
|
||||
*
|
||||
* @return The state of all the Digital IO lines in hardware order
|
||||
*/
|
||||
public short getAllDIO() {
|
||||
byte value = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
|
||||
value |= HALLibrary.getDIO(m_digital_ports[i], status) << i;
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the direction of a digital I/O line
|
||||
*
|
||||
* @param channel
|
||||
* The channel of the DIO to get the direction of.
|
||||
* @return True if the digital channel is configured as an output, false if
|
||||
* it is an input
|
||||
*/
|
||||
public boolean getDIODirection(int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getDIODirection(
|
||||
m_digital_ports[channel - 1], status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the direction of all the Digital I/O lines from the FPGA A 1 bit
|
||||
* means output and a 0 bit means input. These are not remapped to logical
|
||||
* order. They are still in hardware order.
|
||||
*
|
||||
* @return The direction of all the Digital IO lines in hardware order
|
||||
*/
|
||||
public short getDIODirection() {
|
||||
byte value = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
|
||||
value |= HALLibrary.getDIODirection(m_digital_ports[i], status) << i;
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a single pulse. Write a pulse to the specified digital output
|
||||
* channel. There can only be a single pulse going at any time.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to pulse.
|
||||
* @param pulseLength
|
||||
* The length of the pulse.
|
||||
*/
|
||||
public void pulse(final int channel, final float pulseLength) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.pulse(m_digital_ports[channel - 1], pulseLength, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Generate a single pulse. Write a pulse to the specified
|
||||
* digital output channel. There can only be a single pulse
|
||||
* going at any time.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to pulse.
|
||||
* @param pulseLength
|
||||
* The length of the pulse.
|
||||
*/
|
||||
public void pulse(final int channel, final int pulseLength) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
float convertedPulse = (float) (pulseLength / 1.0e9 * (HALLibrary
|
||||
.getLoopTiming(status) * 25));
|
||||
System.err
|
||||
.println("You should use the float version of pulse for portability. This is deprecated");
|
||||
HALLibrary.pulse(m_digital_ports[channel - 1], convertedPulse, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a DIO line to see if it is currently generating a pulse.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to check.
|
||||
* @return True if the channel is pulsing, false otherwise.
|
||||
*/
|
||||
public boolean isPulsing(final int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.isPulsing(m_digital_ports[channel - 1],
|
||||
status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any DIO line is currently generating a pulse.
|
||||
*
|
||||
* @return True if any channel is pulsing, false otherwise.
|
||||
*/
|
||||
public boolean isPulsing() {
|
||||
boolean value;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
value = HALLibrary.isAnyPulsingWithModule((byte) m_module, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a DO PWM Generator. Allocate PWM generators so that they are not
|
||||
* accidently reused.
|
||||
*/
|
||||
public int allocateDO_PWM() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.allocatePWMWithModule((byte) m_module, status)
|
||||
.getInt(0); // XXX: Hacky, needs heavy testing
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resource associated with a DO PWM generator.
|
||||
*/
|
||||
public void freeDO_PWM(int pwmGenerator) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
Pointer pointer = new IntByReference(pwmGenerator).getPointer();
|
||||
HALLibrary.freePWMWithModule((byte) m_module, pointer, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the frequency of the DO PWM generator.
|
||||
*
|
||||
* The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is
|
||||
* logarithmic.
|
||||
*
|
||||
* @param rate
|
||||
* The frequency to output all digital output PWM signals on this
|
||||
* module.
|
||||
*/
|
||||
public void setDO_PWMRate(double rate) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setPWMRateWithModuleIntHack((byte) m_module, Float.floatToIntBits((float) rate), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure which DO channel the PWM siganl is output on
|
||||
*
|
||||
* @param pwmGenerator
|
||||
* The generator index reserved by allocateDO_PWM()
|
||||
* @param channel
|
||||
* The Digital Output channel to output on
|
||||
*/
|
||||
public void setDO_PWMOutputChannel(int pwmGenerator, int channel) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
Pointer pointer = new IntByReference(pwmGenerator).getPointer();
|
||||
HALLibrary.setPWMOutputChannelWithModule((byte) m_module, pointer,
|
||||
channel, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the duty-cycle of the PWM generator
|
||||
*
|
||||
* @param pwmGenerator
|
||||
* The generator index reserved by allocateDO_PWM()
|
||||
* @param dutyCycle
|
||||
* The percent duty cycle to output [0..1].
|
||||
*/
|
||||
public void setDO_PWMDutyCycle(int pwmGenerator, double dutyCycle) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
Pointer pointer = new IntByReference(pwmGenerator).getPointer();
|
||||
HALLibrary.setPWMDutyCycleWithModuleIntHack((byte) m_module, pointer,
|
||||
Float.floatToIntBits((float) dutyCycle), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @return The number of clock ticks per DIO loop
|
||||
*/
|
||||
public int getLoopTiming() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getLoopTiming(status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
|
||||
/**
|
||||
* Class to write digital outputs. This class will wrtie digital outputs. Other
|
||||
* devices that are implemented elsewhere will automatically allocate digital
|
||||
* inputs and outputs as required.
|
||||
*/
|
||||
public class DigitalOutput extends DigitalSource implements IInputOutput,
|
||||
LiveWindowSendable {
|
||||
|
||||
private Pointer m_pwmGenerator;
|
||||
|
||||
/**
|
||||
* Create an instance of a digital output. Create an instance of a digital
|
||||
* output given a module number and channel.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use
|
||||
* @param channel
|
||||
* the port to use for the digital output
|
||||
*/
|
||||
public DigitalOutput(int moduleNumber, int channel) {
|
||||
initDigitalPort(moduleNumber, channel, false);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_DigitalOutput,
|
||||
channel, moduleNumber - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a digital output. Create a digital output given a
|
||||
* channel. The default module is used.
|
||||
*
|
||||
* @param channel
|
||||
* the port to use for the digital output
|
||||
*/
|
||||
public DigitalOutput(int channel) {
|
||||
this(getDefaultDigitalModule(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resources associated with a digital output.
|
||||
*/
|
||||
public void free() {
|
||||
// disable the pwm only if we have allocated it
|
||||
if (m_pwmGenerator != null) {
|
||||
disablePWM();
|
||||
}
|
||||
super.free();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a digital output.
|
||||
*
|
||||
* @param value
|
||||
* true is on, off is false
|
||||
*/
|
||||
public void set(boolean value) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setDIO(m_port, (short) (value ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The GPIO channel number that this object represents.
|
||||
*/
|
||||
public int getChannel() {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a single pulse. Write a pulse to the specified digital output
|
||||
* channel. There can only be a single pulse going at any time.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to pulse.
|
||||
* @param pulseLength
|
||||
* The length of the pulse.
|
||||
*/
|
||||
public void pulse(final int channel, final float pulseLength) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.pulse(m_port, pulseLength, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Generate a single pulse. Write a pulse to the specified
|
||||
* digital output channel. There can only be a single pulse
|
||||
* going at any time.
|
||||
*
|
||||
* @param channel
|
||||
* The channel to pulse.
|
||||
* @param pulseLength
|
||||
* The length of the pulse.
|
||||
*/
|
||||
public void pulse(final int channel, final int pulseLength) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
float convertedPulse = (float) (pulseLength / 1.0e9 * (HALLibrary
|
||||
.getLoopTiming(status) * 25));
|
||||
System.err
|
||||
.println("You should use the float version of pulse for portability. This is deprecated");
|
||||
HALLibrary.pulse(m_port, convertedPulse, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the pulse is still going. Determine if a previously started
|
||||
* pulse is still going.
|
||||
*
|
||||
* @return true if pulsing
|
||||
*/
|
||||
public boolean isPulsing() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.isPulsing(m_port, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the PWM frequency of the PWM output on a Digital Output line.
|
||||
*
|
||||
* The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is
|
||||
* logarithmic.
|
||||
*
|
||||
* There is only one PWM frequency per digital module.
|
||||
*
|
||||
* @param rate
|
||||
* The frequency to output all digital output PWM signals on this
|
||||
* module.
|
||||
*/
|
||||
public void setPWMRate(double rate) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setPWMRateWithModule((byte) m_moduleNumber, (float) rate,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a PWM Output on this line.
|
||||
*
|
||||
* Allocate one of the 4 DO PWM generator resources from this module.
|
||||
*
|
||||
* Supply the initial duty-cycle to output so as to avoid a glitch when
|
||||
* first starting.
|
||||
*
|
||||
* The resolution of the duty cycle is 8-bit for low frequencies (1kHz or
|
||||
* less) but is reduced the higher the frequency of the PWM signal is.
|
||||
*
|
||||
* @param initialDutyCycle
|
||||
* The duty-cycle to start generating. [0..1]
|
||||
*/
|
||||
public void enablePWM(double initialDutyCycle) {
|
||||
if (m_pwmGenerator == null)
|
||||
return;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_pwmGenerator = HALLibrary.allocatePWMWithModule(
|
||||
(byte) m_moduleNumber, status);
|
||||
HALUtil.checkStatus(status);
|
||||
HALLibrary.setPWMDutyCycle(m_pwmGenerator, (float) initialDutyCycle,
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
HALLibrary.setPWMOutputChannelWithModule((byte) m_moduleNumber,
|
||||
m_pwmGenerator, m_channel, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change this line from a PWM output back to a static Digital Output line.
|
||||
*
|
||||
* Free up one of the 4 DO PWM generator resources that were in use.
|
||||
*/
|
||||
public void disablePWM() {
|
||||
// Disable the output by routing to a dead bit.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary
|
||||
.setPWMOutputChannel(m_pwmGenerator, kDigitalChannels, status);
|
||||
HALUtil.checkStatus(status);
|
||||
HALLibrary.freePWMWithModule((byte) m_moduleNumber, m_pwmGenerator,
|
||||
status);
|
||||
m_pwmGenerator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the duty-cycle that is being generated on the line.
|
||||
*
|
||||
* The resolution of the duty cycle is 8-bit for low frequencies (1kHz or
|
||||
* less) but is reduced the higher the frequency of the PWM signal is.
|
||||
*
|
||||
* @param dutyCycle
|
||||
* The duty-cycle to change to. [0..1]
|
||||
*/
|
||||
public void updateDutyCycle(double dutyCycle) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setPWMDutyCycleWithModule((byte) m_moduleNumber,
|
||||
m_pwmGenerator, (float) dutyCycle, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Digital Output";
|
||||
}
|
||||
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
// TODO: Put current value.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value,
|
||||
boolean bln) {
|
||||
set(((Boolean) value).booleanValue());
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* DigitalSource Interface. The DigitalSource represents all the possible inputs
|
||||
* for a counter or a quadrature encoder. The source may be either a digital
|
||||
* input or an analog input. If the caller just provides a channel, then a
|
||||
* digital input will be constructed and freed when finished for the source. The
|
||||
* source can either be a digital input or analog trigger but not both.
|
||||
*/
|
||||
public abstract class DigitalSource extends InterruptableSensorBase {
|
||||
|
||||
protected static Resource channels = new Resource(kDigitalChannels
|
||||
* kDigitalModules);
|
||||
protected Pointer m_port;
|
||||
protected int m_moduleNumber, m_channel;
|
||||
|
||||
protected void initDigitalPort(int moduleNumber, int channel, boolean input) {
|
||||
|
||||
m_channel = channel;
|
||||
m_moduleNumber = moduleNumber;
|
||||
if (HALLibrary.checkDigitalModule((byte) m_moduleNumber) != 1) {
|
||||
throw new AllocationException("Digital input " + m_channel
|
||||
+ " on module " + m_moduleNumber
|
||||
+ " cannot be allocated. Module is not present.");
|
||||
}
|
||||
checkDigitalChannel(m_channel); // XXX: Replace with
|
||||
// HALLibrary.checkDigitalChannel when
|
||||
// implemented
|
||||
|
||||
try {
|
||||
channels.allocate((m_moduleNumber - 1) * kDigitalChannels
|
||||
+ m_channel - 1);
|
||||
} catch (CheckedAllocationException ex) {
|
||||
throw new AllocationException("Digital input " + m_channel
|
||||
+ " on module " + m_moduleNumber + " is already allocated");
|
||||
}
|
||||
|
||||
Pointer port_pointer = HALLibrary.getPortWithModule(
|
||||
(byte) moduleNumber, (byte) channel);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_port = HALLibrary.initializeDigitalPort(port_pointer, status);
|
||||
HALUtil.checkStatus(status);
|
||||
HALLibrary.allocateDIO(m_port, (byte) (input ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
channels.free(((m_moduleNumber - 1) * kDigitalChannels + m_channel - 1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.freeDIO(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
m_channel = 0;
|
||||
m_moduleNumber = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channel routing number
|
||||
*
|
||||
* @return channel routing number
|
||||
*/
|
||||
public int getChannelForRouting() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int channel = HALLibrary.remapDigitalChannel(m_channel - 1, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module routing number
|
||||
*
|
||||
* @return module routing number
|
||||
*/
|
||||
public int getModuleForRouting() {
|
||||
return m_moduleNumber - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an analog trigger
|
||||
*
|
||||
* @return true if this is an analog trigger
|
||||
*/
|
||||
public boolean getAnalogTriggerForRouting() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* DoubleSolenoid class for running 2 channels of high voltage Digital Output
|
||||
* (9472 module).
|
||||
*
|
||||
* The DoubleSolenoid class is typically used for pneumatics solenoids that
|
||||
* have two positions controlled by two separate channels.
|
||||
*/
|
||||
public class DoubleSolenoid extends SolenoidBase implements LiveWindowSendable {
|
||||
|
||||
/**
|
||||
* Possible values for a DoubleSolenoid
|
||||
*/
|
||||
public static class Value {
|
||||
|
||||
public final int value;
|
||||
public static final int kOff_val = 0;
|
||||
public static final int kForward_val = 1;
|
||||
public static final int kReverse_val = 2;
|
||||
public static final Value kOff = new Value(kOff_val);
|
||||
public static final Value kForward = new Value(kForward_val);
|
||||
public static final Value kReverse = new Value(kReverse_val);
|
||||
|
||||
private Value(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
private int m_forwardChannel; ///< The forward channel on the module to control.
|
||||
private int m_reverseChannel; ///< The reverse channel on the module to control.
|
||||
private byte m_forwardMask; ///< The mask for the forward channel.
|
||||
private byte m_reverseMask; ///< The mask for the reverse channel.
|
||||
|
||||
/**
|
||||
* Common function to implement constructor behavior.
|
||||
*/
|
||||
private synchronized void initSolenoid() {
|
||||
checkSolenoidModule(m_moduleNumber);
|
||||
checkSolenoidChannel(m_forwardChannel);
|
||||
checkSolenoidChannel(m_reverseChannel);
|
||||
|
||||
try {
|
||||
m_allocated.allocate((m_moduleNumber - 1) * kSolenoidChannels + m_forwardChannel - 1);
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"Solenoid channel " + m_forwardChannel + " on module " + m_moduleNumber + " is already allocated");
|
||||
}
|
||||
try {
|
||||
m_allocated.allocate((m_moduleNumber - 1) * kSolenoidChannels + m_reverseChannel - 1);
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"Solenoid channel " + m_reverseChannel + " on module " + m_moduleNumber + " is already allocated");
|
||||
}
|
||||
m_forwardMask = (byte) (1 << (m_forwardChannel - 1));
|
||||
m_reverseMask = (byte) (1 << (m_reverseChannel - 1));
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Solenoid, m_forwardChannel, m_moduleNumber-1);
|
||||
UsageReporting.report(tResourceType.kResourceType_Solenoid, m_reverseChannel, m_moduleNumber-1);
|
||||
LiveWindow.addActuator("DoubleSolenoid", m_moduleNumber, m_forwardChannel, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param forwardChannel The forward channel on the module to control.
|
||||
* @param reverseChannel The reverse channel on the module to control.
|
||||
*/
|
||||
public DoubleSolenoid(final int forwardChannel, final int reverseChannel) {
|
||||
super(getDefaultSolenoidModule());
|
||||
m_forwardChannel = forwardChannel;
|
||||
m_reverseChannel = reverseChannel;
|
||||
initSolenoid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moduleNumber The module number of the solenoid module to use.
|
||||
* @param forwardChannel The forward channel on the module to control.
|
||||
* @param reverseChannel The reverse channel on the module to control.
|
||||
*/
|
||||
public DoubleSolenoid(final int moduleNumber, final int forwardChannel, final int reverseChannel) {
|
||||
super(moduleNumber);
|
||||
m_forwardChannel = forwardChannel;
|
||||
m_reverseChannel = reverseChannel;
|
||||
initSolenoid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public synchronized void free() {
|
||||
m_allocated.free((m_moduleNumber - 1) * kSolenoidChannels + m_forwardChannel - 1);
|
||||
m_allocated.free((m_moduleNumber - 1) * kSolenoidChannels + m_reverseChannel - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a solenoid.
|
||||
*
|
||||
* @param value Move the solenoid to forward, reverse, or don't move it.
|
||||
*/
|
||||
public void set(final Value value) {
|
||||
byte rawValue = 0;
|
||||
|
||||
switch (value.value) {
|
||||
case Value.kOff_val:
|
||||
rawValue = 0x00;
|
||||
break;
|
||||
case Value.kForward_val:
|
||||
rawValue = m_forwardMask;
|
||||
break;
|
||||
case Value.kReverse_val:
|
||||
rawValue = m_reverseMask;
|
||||
break;
|
||||
}
|
||||
|
||||
set(rawValue, m_forwardMask | m_reverseMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current value of the solenoid.
|
||||
*
|
||||
* @return The current value of the solenoid.
|
||||
*/
|
||||
public Value get() {
|
||||
byte value = getAll();
|
||||
|
||||
if ((value & m_forwardMask) != 0) return Value.kForward;
|
||||
if ((value & m_reverseMask) != 0) return Value.kReverse;
|
||||
return Value.kOff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Double Solenoid";
|
||||
}
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@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) {
|
||||
//TODO: this is bad
|
||||
m_table.putString("Value", (get() == Value.kForward ? "Forward" : (get() == Value.kReverse ? "Reverse" : "Off")));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
set(Value.kOff); // Stop for safety
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value, boolean bln) {
|
||||
//TODO: this is bad also
|
||||
if (value.toString().equals("Reverse"))
|
||||
set(Value.kReverse);
|
||||
else if (value.toString().equals("Forward"))
|
||||
set(Value.kForward);
|
||||
else
|
||||
set(Value.kOff);
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
set(Value.kOff); // Stop for safety
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,648 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.*;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
|
||||
/**
|
||||
* Provide access to the network communication data to / from the Driver Station.
|
||||
*/
|
||||
public class DriverStation implements IInputOutput {
|
||||
|
||||
/**
|
||||
* The size of the user status data
|
||||
*/
|
||||
public static final int USER_STATUS_DATA_SIZE = FRC_NetworkCommunicationsLibrary.USER_STATUS_DATA_SIZE;
|
||||
/**
|
||||
* Slot for the analog module to read the battery
|
||||
*/
|
||||
public static final int kBatterySlot = 1;
|
||||
/**
|
||||
* Analog channel to read the battery
|
||||
*/
|
||||
public static final int kBatteryChannel = 8;
|
||||
/**
|
||||
* Number of Joystick Ports
|
||||
*/
|
||||
public static final int kJoystickPorts = 4;
|
||||
/**
|
||||
* Number of Joystick Axes
|
||||
*/
|
||||
public static final int kJoystickAxes = 6;
|
||||
/**
|
||||
* Convert from raw values to volts
|
||||
*/
|
||||
public static final double kDSAnalogInScaling = 5.0 / 1023.0;
|
||||
|
||||
/**
|
||||
* The robot alliance that the robot is a part of
|
||||
*/
|
||||
public static class Alliance {
|
||||
|
||||
/** The integer value representing this enumeration. */
|
||||
public final int value;
|
||||
/** The Alliance name. */
|
||||
public final String name;
|
||||
public static final int kRed_val = 0;
|
||||
public static final int kBlue_val = 1;
|
||||
public static final int kInvalid_val = 2;
|
||||
/** alliance: Red */
|
||||
public static final Alliance kRed = new Alliance(kRed_val, "Red");
|
||||
/** alliance: Blue */
|
||||
public static final Alliance kBlue = new Alliance(kBlue_val, "Blue");
|
||||
/** alliance: Invalid */
|
||||
public static final Alliance kInvalid = new Alliance(kInvalid_val, "invalid");
|
||||
|
||||
private Alliance(int value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
} /* Alliance */
|
||||
|
||||
|
||||
private static class DriverStationTask implements Runnable {
|
||||
|
||||
private DriverStation m_ds;
|
||||
|
||||
DriverStationTask(DriverStation ds) {
|
||||
m_ds = ds;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
m_ds.task();
|
||||
}
|
||||
} /* DriverStationTask */
|
||||
|
||||
private static DriverStation instance = new DriverStation();
|
||||
private FRCCommonControlData m_controlData;
|
||||
private AnalogChannel m_batteryChannel;
|
||||
private Thread m_thread;
|
||||
private final Object m_semaphore;
|
||||
private final Object m_dataSem;
|
||||
private int m_digitalOut;
|
||||
private volatile boolean m_thread_keepalive = true;
|
||||
private final Dashboard m_dashboardDefaultHigh;
|
||||
private final Dashboard m_dashboardDefaultLow;
|
||||
private IDashboard m_dashboardInUseHigh;
|
||||
private IDashboard m_dashboardInUseLow;
|
||||
private int m_updateNumber = 0;
|
||||
private double m_approxMatchTimeOffset = -1.0;
|
||||
private boolean m_userInDisabled = false;
|
||||
private boolean m_userInAutonomous = false;
|
||||
private boolean m_userInTeleop = false;
|
||||
private boolean m_userInTest = false;
|
||||
private boolean m_newControlData;
|
||||
private final Pointer m_packetDataAvailableSem;
|
||||
// XXX: Add DriverStationEnhancedIO back
|
||||
// private DriverStationEnhancedIO m_enhancedIO = new DriverStationEnhancedIO();
|
||||
|
||||
/**
|
||||
* Gets an instance of the DriverStation
|
||||
*
|
||||
* @return The DriverStation.
|
||||
*/
|
||||
public static DriverStation getInstance() {
|
||||
return DriverStation.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* DriverStation constructor.
|
||||
*
|
||||
* The single DriverStation instance is created statically with the
|
||||
* instance static member variable.
|
||||
*/
|
||||
protected DriverStation() {
|
||||
m_controlData = new FRCCommonControlData();
|
||||
m_semaphore = new Object();
|
||||
m_dataSem = new Object();
|
||||
|
||||
m_dashboardInUseHigh = m_dashboardDefaultHigh = new Dashboard(m_semaphore);
|
||||
m_dashboardInUseLow = m_dashboardDefaultLow = new Dashboard(m_semaphore);
|
||||
|
||||
// m_controlData is initialized in constructor FRCCommonControlData.
|
||||
|
||||
// XXX: Uncomment when analogChannel is fixed
|
||||
//m_batteryChannel = new AnalogChannel(kBatterySlot, kBatteryChannel);
|
||||
|
||||
m_packetDataAvailableSem = HALLibrary.initializeMutex(HALLibrary.SEMAPHORE_Q_PRIORITY.get());
|
||||
FRC_NetworkCommunicationsLibrary.setNewDataSem(m_packetDataAvailableSem);
|
||||
|
||||
m_thread = new Thread(new DriverStationTask(this), "FRCDriverStation");
|
||||
m_thread.setPriority((Thread.NORM_PRIORITY + Thread.MAX_PRIORITY) / 2);
|
||||
|
||||
m_thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill the thread
|
||||
*/
|
||||
public void release() {
|
||||
m_thread_keepalive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the service routine for the DS polling thread.
|
||||
*/
|
||||
private void task() {
|
||||
int safetyCounter = 0;
|
||||
while (m_thread_keepalive) {
|
||||
HALLibrary.takeMutex(m_packetDataAvailableSem, HALLibrary.SEMAPHORE_WAIT_FOREVER.get());
|
||||
synchronized (this) {
|
||||
getData();
|
||||
// XXX: Add DriverStationEnhancedIO back
|
||||
// m_enhancedIO.updateData();
|
||||
setData();
|
||||
}
|
||||
synchronized (m_dataSem) {
|
||||
m_dataSem.notifyAll();
|
||||
}
|
||||
if (++safetyCounter >= 5) {
|
||||
// System.out.println("Checking safety");
|
||||
MotorSafetyHelper.checkMotors();
|
||||
safetyCounter = 0;
|
||||
}
|
||||
if (m_userInDisabled) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramDisabled();
|
||||
}
|
||||
if (m_userInAutonomous) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramAutonomous();
|
||||
}
|
||||
if (m_userInTeleop) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramTeleop();
|
||||
}
|
||||
if (m_userInTest) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for new data from the driver station.
|
||||
*/
|
||||
public void waitForData() {
|
||||
waitForData(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for new data or for timeout, which ever comes first. If timeout is
|
||||
* 0, wait for new data only.
|
||||
*
|
||||
* @param timeout The maximum time in milliseconds to wait.
|
||||
*/
|
||||
public void waitForData(long timeout) {
|
||||
synchronized (m_dataSem) {
|
||||
try {
|
||||
m_dataSem.wait(timeout);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
private static boolean lastEnabled = false;
|
||||
|
||||
/**
|
||||
* Copy data from the DS task for the user.
|
||||
* If no new data exists, it will just be returned, otherwise
|
||||
* the data will be copied from the DS polling loop.
|
||||
*/
|
||||
protected synchronized void getData() {
|
||||
FRC_NetworkCommunicationsLibrary.getCommonControlData(m_controlData, HALLibrary.SEMAPHORE_WAIT_FOREVER.get());
|
||||
|
||||
if (!lastEnabled && isEnabled()) {
|
||||
// If starting teleop, assume that autonomous just took up 15 seconds
|
||||
if (isAutonomous()) {
|
||||
m_approxMatchTimeOffset = Timer.getFPGATimestamp();
|
||||
} else {
|
||||
m_approxMatchTimeOffset = Timer.getFPGATimestamp() - 15.0;
|
||||
}
|
||||
} else if (lastEnabled && !isEnabled()) {
|
||||
m_approxMatchTimeOffset = -1.0;
|
||||
}
|
||||
lastEnabled = isEnabled();
|
||||
|
||||
m_newControlData = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy status data from the DS task for the user.
|
||||
* This is used primarily to set digital outputs on the DS.
|
||||
*/
|
||||
protected void setData() {
|
||||
synchronized (m_semaphore) {
|
||||
FRC_NetworkCommunicationsLibrary.setStatusData((float) getBatteryVoltage(),
|
||||
(byte) m_digitalOut,
|
||||
(byte) m_updateNumber,
|
||||
new String(m_dashboardInUseHigh.getBytes()),
|
||||
m_dashboardInUseHigh.getBytesLength(),
|
||||
new String(m_dashboardInUseLow.getBytes()),
|
||||
m_dashboardInUseLow.getBytesLength(),
|
||||
HALLibrary.SEMAPHORE_WAIT_FOREVER.get());
|
||||
m_dashboardInUseHigh.flush();
|
||||
m_dashboardInUseLow.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the battery voltage from the specified AnalogChannel.
|
||||
*
|
||||
* This accessor assumes that the battery voltage is being measured
|
||||
* through the voltage divider on an analog breakout.
|
||||
*
|
||||
* @return The battery voltage.
|
||||
*/
|
||||
public double getBatteryVoltage() {
|
||||
// The Analog bumper has a voltage divider on the battery source.
|
||||
// Vbatt *--/\/\/\--* Vsample *--/\/\/\--* Gnd
|
||||
// 680 Ohms 1000 Ohms
|
||||
// XXX: Uncomment this when analog channel is fixed
|
||||
//return m_batteryChannel.getAverageVoltage() * (1680.0 / 1000.0);
|
||||
return 12.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the axis on a joystick.
|
||||
* This depends on the mapping of the joystick connected to the specified port.
|
||||
*
|
||||
* @param stick The joystick to read.
|
||||
* @param axis The analog axis value to read from the joystick.
|
||||
* @return The value of the axis on the joystick.
|
||||
*/
|
||||
public double getStickAxis(int stick, int axis) {
|
||||
if (axis < 1 || axis > kJoystickAxes) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int value;
|
||||
switch (stick) {
|
||||
case 1:
|
||||
value = m_controlData.field2.stick0Axes[axis - 1];
|
||||
break;
|
||||
case 2:
|
||||
value = m_controlData.field3.stick1Axes[axis - 1];
|
||||
break;
|
||||
case 3:
|
||||
value = m_controlData.field4.stick2Axes[axis - 1];
|
||||
break;
|
||||
case 4:
|
||||
value = m_controlData.field5.stick3Axes[axis - 1];
|
||||
break;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double result;
|
||||
if (value < 0) {
|
||||
result = ((double) value) / 128.0;
|
||||
} else {
|
||||
result = ((double) value) / 127.0;
|
||||
}
|
||||
|
||||
// wpi_assert(result <= 1.0 && result >= -1.0);
|
||||
if (result > 1.0) {
|
||||
result = 1.0;
|
||||
} else if (result < -1.0) {
|
||||
result = -1.0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of the buttons on the joystick.
|
||||
* 12 buttons (4 msb are unused) from the joystick.
|
||||
*
|
||||
* @param stick The joystick to read.
|
||||
* @return The state of the buttons on the joystick.
|
||||
*/
|
||||
public int getStickButtons(final int stick) {
|
||||
switch (stick) {
|
||||
case 1:
|
||||
return m_controlData.stick0Buttons;
|
||||
case 2:
|
||||
return m_controlData.stick1Buttons;
|
||||
case 3:
|
||||
return m_controlData.stick2Buttons;
|
||||
case 4:
|
||||
return m_controlData.stick3Buttons;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an analog voltage from the Driver Station.
|
||||
* The analog values are returned as voltage values for the Driver Station analog inputs.
|
||||
* These inputs are typically used for advanced operator interfaces consisting of potentiometers
|
||||
* or resistor networks representing values on a rotary switch.
|
||||
*
|
||||
* @param channel The analog input channel on the driver station to read from. Valid range is 1 - 4.
|
||||
* @return The analog voltage on the input.
|
||||
*/
|
||||
public double getAnalogIn(final int channel) {
|
||||
switch (channel) {
|
||||
case 1:
|
||||
return kDSAnalogInScaling * m_controlData.analog1;
|
||||
case 2:
|
||||
return kDSAnalogInScaling * m_controlData.analog2;
|
||||
case 3:
|
||||
return kDSAnalogInScaling * m_controlData.analog3;
|
||||
case 4:
|
||||
return kDSAnalogInScaling * m_controlData.analog4;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values from the digital inputs on the Driver Station.
|
||||
* Return digital values from the Drivers Station. These values are typically used for buttons
|
||||
* and switches on advanced operator interfaces.
|
||||
* @param channel The digital input to get. Valid range is 1 - 8.
|
||||
* @return The value of the digital input
|
||||
*/
|
||||
public boolean getDigitalIn(final int channel) {
|
||||
return ((m_controlData.dsDigitalIn >> (channel - 1)) & 0x1) == 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value for the digital outputs on the Driver Station.
|
||||
*
|
||||
* Control digital outputs on the Drivers Station. These values are typically used for
|
||||
* giving feedback on a custom operator station such as LEDs.
|
||||
*
|
||||
* @param channel The digital output to set. Valid range is 1 - 8.
|
||||
* @param value The state to set the digital output.
|
||||
*/
|
||||
public void setDigitalOut(final int channel, final boolean value) {
|
||||
m_digitalOut &= ~(0x1 << (channel - 1));
|
||||
m_digitalOut |= ((value ? 1 : 0) << (channel - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value that was set for the digital outputs on the Driver Station.
|
||||
* @param channel The digital ouput to monitor. Valid range is 1 through 8.
|
||||
* @return A digital value being output on the Drivers Station.
|
||||
*/
|
||||
public boolean getDigitalOut(final int channel) {
|
||||
return ((m_digitalOut >> (channel - 1)) & 0x1) == 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the Driver Station requires the
|
||||
* robot to be enabled.
|
||||
*
|
||||
* @return True if the robot is enabled, false otherwise.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return (m_controlData.field1.control & FRCCommonControlMasks.ENABLED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the Driver Station requires the
|
||||
* robot to be disabled.
|
||||
*
|
||||
* @return True if the robot should be disabled, false otherwise.
|
||||
*/
|
||||
public boolean isDisabled() {
|
||||
return !isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the Driver Station requires the
|
||||
* robot to be running in autonomous mode.
|
||||
*
|
||||
* @return True if autonomous mode should be enabled, false otherwise.
|
||||
*/
|
||||
public boolean isAutonomous() {
|
||||
return (m_controlData.field1.control & FRCCommonControlMasks.AUTONOMOUS) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the Driver Station requires the
|
||||
* robot to be running in test mode.
|
||||
* @return True if test mode should be enabled, false otherwise.
|
||||
*/
|
||||
public boolean isTest() {
|
||||
return (m_controlData.field1.control & FRCCommonControlMasks.TEST) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the Driver Station requires the
|
||||
* robot to be running in operator-controlled mode.
|
||||
*
|
||||
* @return True if operator-controlled mode should be enabled, false otherwise.
|
||||
*/
|
||||
public boolean isOperatorControl() {
|
||||
return !(isAutonomous() || isTest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Has a new control packet from the driver station arrived since the last time this function was called?
|
||||
* @return True if the control data has been updated since the last call.
|
||||
*/
|
||||
public synchronized boolean isNewControlData() {
|
||||
boolean result = m_newControlData;
|
||||
m_newControlData = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DS packet number.
|
||||
* The packet number is the index of this set of data returned by the driver station.
|
||||
* Each time new data is received, the packet number (included with the sent data) is returned.
|
||||
*
|
||||
* @return The DS packet number.
|
||||
*/
|
||||
public int getPacketNumber() {
|
||||
return m_controlData.packetIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current alliance from the FMS
|
||||
* @return the current alliance
|
||||
*/
|
||||
public Alliance getAlliance() {
|
||||
switch (m_controlData.dsID_Alliance) {
|
||||
case 'R':
|
||||
return Alliance.kRed;
|
||||
case 'B':
|
||||
return Alliance.kBlue;
|
||||
default:
|
||||
return Alliance.kInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of the team's driver station controls.
|
||||
*
|
||||
* @return the location of the team's driver station controls: 1, 2, or 3
|
||||
*/
|
||||
public int getLocation() {
|
||||
return m_controlData.dsID_Position - '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the team number that the Driver Station is configured for
|
||||
* @return The team number
|
||||
*/
|
||||
public int getTeamNumber() {
|
||||
return m_controlData.teamID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dashboard packer to use for sending high priority user data to a
|
||||
* dashboard receiver. This can idle or restore the default packer.
|
||||
* (Initializing SmartDashboard sets the high priority packer in use, so
|
||||
* beware that the default packer will then be idle. You can restore the
|
||||
* default high priority packer by calling
|
||||
* {@code setDashboardPackerToUseHigh(getDashboardPackerHigh())}.)
|
||||
*
|
||||
* @param dashboard any kind of IDashboard object
|
||||
*/
|
||||
public void setDashboardPackerToUseHigh(IDashboard dashboard) {
|
||||
m_dashboardInUseHigh = dashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default dashboard packer for sending high priority user data to
|
||||
* a dashboard receiver. This instance stays around even after a call to
|
||||
* {@link #setDashboardPackerToUseHigh} changes which packer is in use.
|
||||
*
|
||||
* @return the default Dashboard object; it may be idle
|
||||
*/
|
||||
public Dashboard getDashboardPackerHigh() {
|
||||
return m_dashboardDefaultHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dashboard packer that's currently in use for sending high
|
||||
* priority user data to a dashboard receiver. This can be any kind of
|
||||
* IDashboard.
|
||||
*
|
||||
* @return the current IDashboard object
|
||||
*/
|
||||
public IDashboard getDashboardPackerInUseHigh() {
|
||||
return m_dashboardInUseHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the dashboard packer to use for sending low priority user data to a
|
||||
* dashboard receiver. This can idle or restore the default packer.
|
||||
*
|
||||
* @param dashboard any kind of IDashboard object
|
||||
*/
|
||||
public void setDashboardPackerToUseLow(IDashboard dashboard) {
|
||||
m_dashboardInUseLow = dashboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default dashboard packer for sending low priority user data to
|
||||
* a dashboard receiver. This instance stays around even after a call to
|
||||
* {@link #setDashboardPackerToUseLow} changes which packer is in use.
|
||||
*
|
||||
* @return the default Dashboard object; it may be idle
|
||||
*/
|
||||
public Dashboard getDashboardPackerLow() {
|
||||
return m_dashboardDefaultLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the dashboard packer that's currently in use for sending low
|
||||
* priority user data to a dashboard receiver. This can be any kind of
|
||||
* IDashboard.
|
||||
*
|
||||
* @return the current IDashboard object
|
||||
*/
|
||||
public IDashboard getDashboardPackerInUseLow() {
|
||||
return m_dashboardInUseLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status data monitor
|
||||
* @return The status data monitor for use with IDashboard objects which must
|
||||
* send data across the network.
|
||||
*/
|
||||
public Object getStatusDataMonitor() {
|
||||
return m_semaphore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the internal update number sent across the network along with
|
||||
* status data.
|
||||
*/
|
||||
void incrementUpdateNumber() {
|
||||
synchronized (m_semaphore) {
|
||||
m_updateNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the driver station attached to a Field Management System?
|
||||
* Note: This does not work with the Blue DS.
|
||||
* @return True if the robot is competing on a field being controlled by a Field Management System
|
||||
*/
|
||||
public boolean isFMSAttached() {
|
||||
return (m_controlData.field1.control & FRCCommonControlMasks.FMS_ATTATCHED) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the interface to the enhanced IO of the new driver station.
|
||||
* @return An enhanced IO object for the advanced features of the driver
|
||||
* station.
|
||||
*/
|
||||
// XXX: Add DriverStationEnhancedIO back
|
||||
// public DriverStationEnhancedIO getEnhancedIO() {
|
||||
// return m_enhancedIO;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Return the approximate match time
|
||||
* The FMS does not currently send the official match time to the robots
|
||||
* This returns the time since the enable signal sent from the Driver Station
|
||||
* At the beginning of autonomous, the time is reset to 0.0 seconds
|
||||
* At the beginning of teleop, the time is reset to +15.0 seconds
|
||||
* If the robot is disabled, this returns 0.0 seconds
|
||||
* Warning: This is not an official time (so it cannot be used to argue with referees)
|
||||
* @return Match time in seconds since the beginning of autonomous
|
||||
*/
|
||||
public double getMatchTime() {
|
||||
if (m_approxMatchTimeOffset < 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
return Timer.getFPGATimestamp() - m_approxMatchTimeOffset;
|
||||
}
|
||||
|
||||
/** Only to be used to tell the Driver Station what code you claim to be executing
|
||||
* for diagnostic purposes only
|
||||
* @param entering If true, starting disabled code; if false, leaving disabled code */
|
||||
public void InDisabled(boolean entering) {
|
||||
m_userInDisabled=entering;
|
||||
}
|
||||
|
||||
/** Only to be used to tell the Driver Station what code you claim to be executing
|
||||
* for diagnostic purposes only
|
||||
* @param entering If true, starting autonomous code; if false, leaving autonomous code */
|
||||
public void InAutonomous(boolean entering) {
|
||||
m_userInAutonomous=entering;
|
||||
}
|
||||
|
||||
/** Only to be used to tell the Driver Station what code you claim to be executing
|
||||
* for diagnostic purposes only
|
||||
* @param entering If true, starting teleop code; if false, leaving teleop code */
|
||||
public void InOperatorControl(boolean entering) {
|
||||
m_userInTeleop=entering;
|
||||
}
|
||||
|
||||
/** Only to be used to tell the Driver Station what code you claim to be executing
|
||||
* for diagnostic purposes only
|
||||
* @param entering If true, starting test code; if false, leaving test code */
|
||||
public void InTest(boolean entering) {
|
||||
m_userInTeleop = entering;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,198 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
|
||||
/**
|
||||
* Provide access to "LCD" on the Driver Station.
|
||||
* This is the Messages box on the DS Operation tab.
|
||||
*
|
||||
* Buffer the printed data locally and then send it
|
||||
* when UpdateLCD is called.
|
||||
*/
|
||||
public class DriverStationLCD extends SensorBase implements IInputOutput {
|
||||
|
||||
private static DriverStationLCD m_instance;
|
||||
/**
|
||||
* Driver station timeout in milliseconds
|
||||
*/
|
||||
public static final int kSyncTimeout_ms = 20;
|
||||
/**
|
||||
* Command to display text
|
||||
*/
|
||||
public static final int kFullDisplayTextCommand = 0x9FFF;
|
||||
/**
|
||||
* Maximum line length for Driver Station display
|
||||
*/
|
||||
public static final int kLineLength = 21;
|
||||
/**
|
||||
* Total number of lines available
|
||||
*/
|
||||
public static final int kNumLines = 6;
|
||||
|
||||
/**
|
||||
* The line number on the Driver Station LCD
|
||||
*/
|
||||
public static class Line {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kMain6_val = 0;
|
||||
static final int kUser1_val = 0;
|
||||
static final int kUser2_val = 1;
|
||||
static final int kUser3_val = 2;
|
||||
static final int kUser4_val = 3;
|
||||
static final int kUser5_val = 4;
|
||||
static final int kUser6_val = 5;
|
||||
/**
|
||||
* @deprecated Use kUser1
|
||||
* Line at the Top of the screen
|
||||
*/
|
||||
public static final Line kMain6 = new Line(kMain6_val);
|
||||
/**
|
||||
* Line at the Top of the screen
|
||||
*/
|
||||
public static final Line kUser1 = new Line(kUser1_val);
|
||||
/**
|
||||
* Line on the user screen
|
||||
*/
|
||||
public static final Line kUser2 = new Line(kUser2_val);
|
||||
/**
|
||||
* Line on the user screen
|
||||
*/
|
||||
public static final Line kUser3 = new Line(kUser3_val);
|
||||
/**
|
||||
* Line on the user screen
|
||||
*/
|
||||
public static final Line kUser4 = new Line(kUser4_val);
|
||||
/**
|
||||
* Line on the user screen
|
||||
*/
|
||||
public static final Line kUser5 = new Line(kUser5_val);
|
||||
/**
|
||||
* Bottom line on the user screen
|
||||
*/
|
||||
public static final Line kUser6 = new Line(kUser6_val);
|
||||
|
||||
private Line(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] m_textBuffer;
|
||||
|
||||
/**
|
||||
* Get an instance of the DriverStationLCD
|
||||
* @return an instance of the DriverStationLCD
|
||||
*/
|
||||
public static synchronized DriverStationLCD getInstance() {
|
||||
if (m_instance == null)
|
||||
m_instance = new DriverStationLCD();
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* DriverStationLCD constructor.
|
||||
*
|
||||
* This is only called once the first time GetInstance() is called
|
||||
*/
|
||||
private DriverStationLCD() {
|
||||
m_textBuffer = new byte[FRC_NetworkCommunicationsLibrary.USER_DS_LCD_DATA_SIZE];
|
||||
|
||||
for (int i = 0; i < FRC_NetworkCommunicationsLibrary.USER_DS_LCD_DATA_SIZE; i++) {
|
||||
m_textBuffer[i] = ' ';
|
||||
}
|
||||
|
||||
m_textBuffer[0] = (byte) (kFullDisplayTextCommand >> 8);
|
||||
m_textBuffer[1] = (byte) kFullDisplayTextCommand;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_DriverStationLCD, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the text data to the Driver Station.
|
||||
*/
|
||||
public synchronized void updateLCD() {
|
||||
FRC_NetworkCommunicationsLibrary.setUserDsLcdData(new String(m_textBuffer), FRC_NetworkCommunicationsLibrary.USER_DS_LCD_DATA_SIZE, kSyncTimeout_ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print formatted text to the Driver Station LCD text buffer.
|
||||
*
|
||||
* Use UpdateLCD() periodically to actually send the test to the Driver Station.
|
||||
*
|
||||
* @param line The line on the LCD to print to.
|
||||
* @param startingColumn The column to start printing to. This is a 1-based number.
|
||||
* @param text the text to print
|
||||
*/
|
||||
public void println(Line line, int startingColumn, String text) {
|
||||
int start = startingColumn - 1;
|
||||
int maxLength = kLineLength - start;
|
||||
|
||||
if (startingColumn < 1 || startingColumn > kLineLength) {
|
||||
throw new IndexOutOfBoundsException("Column must be between 1 and " + kLineLength + ", inclusive");
|
||||
}
|
||||
|
||||
int length = text.length();
|
||||
int finalLength = (length < maxLength ? length : maxLength);
|
||||
synchronized (this) {
|
||||
for (int i = 0; i < finalLength; i++) {
|
||||
m_textBuffer[i + start + line.value * kLineLength + 2] = (byte)text.charAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print formatted text to the Driver Station LCD text buffer.
|
||||
*
|
||||
* Use UpdateLCD() periodically to actually send the test to the Driver Station.
|
||||
*
|
||||
* @param line The line on the LCD to print to.
|
||||
* @param startingColumn The column to start printing to. This is a 1-based number.
|
||||
* @param text the text to print
|
||||
*/
|
||||
public void println(Line line, int startingColumn, StringBuffer text) {
|
||||
int start = startingColumn - 1;
|
||||
int maxLength = kLineLength - start;
|
||||
|
||||
if (startingColumn < 1 || startingColumn > kLineLength) {
|
||||
throw new IndexOutOfBoundsException("Column must be between 1 and " + kLineLength + ", inclusive");
|
||||
}
|
||||
|
||||
int length = text.length();
|
||||
int finalLength = (length < maxLength ? length : maxLength);
|
||||
synchronized (this) {
|
||||
for (int i = 0; i < finalLength; i++) {
|
||||
m_textBuffer[i + start + line.value * kLineLength + 2] = (byte) text.charAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear User Messages box on DS Operations Tab
|
||||
*
|
||||
* This method will clear all text currently displayed in the message box
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (this) {
|
||||
for (int i=0; i < kLineLength*kNumLines; i++) {
|
||||
m_textBuffer[i+2] = ' ';
|
||||
}
|
||||
}
|
||||
updateLCD();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,887 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.ISensor;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* Class to read quad encoders. Quadrature encoders are devices that count shaft
|
||||
* rotation and can sense direction. The output of the QuadEncoder class is an
|
||||
* integer that can count either up or down, and can go negative for reverse
|
||||
* direction counting. When creating QuadEncoders, a direction is supplied that
|
||||
* changes the sense of the output to make code more readable if the encoder is
|
||||
* mounted such that forward movement generates negative values. Quadrature
|
||||
* encoders have two digital outputs, an A Channel and a B Channel that are out
|
||||
* of phase with each other to allow the FPGA to do direction sensing.
|
||||
*/
|
||||
public class Encoder extends SensorBase implements CounterBase, PIDSource,
|
||||
ISensor, LiveWindowSendable {
|
||||
|
||||
/**
|
||||
* The a source
|
||||
*/
|
||||
protected DigitalSource m_aSource; // the A phase of the quad encoder
|
||||
/**
|
||||
* The b source
|
||||
*/
|
||||
protected DigitalSource m_bSource; // the B phase of the quad encoder
|
||||
/**
|
||||
* The index source
|
||||
*/
|
||||
protected DigitalSource m_indexSource = null; // Index on some encoders
|
||||
private Pointer m_encoder;
|
||||
private int m_index;
|
||||
private double m_distancePerPulse; // distance of travel for each encoder
|
||||
// tick
|
||||
private Counter m_counter; // Counter object for 1x and 2x encoding
|
||||
private EncodingType m_encodingType = EncodingType.k4X;
|
||||
private boolean m_allocatedA;
|
||||
private boolean m_allocatedB;
|
||||
private boolean m_allocatedI;
|
||||
private PIDSourceParameter m_pidSource;
|
||||
|
||||
/**
|
||||
* Common initialization code for Encoders. This code allocates resources
|
||||
* for Encoders and is common to all constructors.
|
||||
*
|
||||
* @param reverseDirection
|
||||
* If true, counts down instead of up (this is all relative)
|
||||
* @param encodingType
|
||||
* either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If
|
||||
* 4X is selected, then an encoder FPGA object is used and the
|
||||
* returned counts will be 4x the encoder spec'd value since all
|
||||
* rising and falling edges are counted. If 1X or 2X are selected
|
||||
* then a counter object will be used and the returned value will
|
||||
* either exactly match the spec'd count or be double (2x) the
|
||||
* spec'd count.
|
||||
*/
|
||||
private void initEncoder(boolean reverseDirection) {
|
||||
switch (m_encodingType.value) {
|
||||
case EncodingType.k4X_val:
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
IntBuffer index = IntBuffer.allocate(1);
|
||||
m_encoder = HALLibrary.initializeEncoder(
|
||||
(byte) m_aSource.getModuleForRouting(),
|
||||
m_aSource.getChannelForRouting(),
|
||||
(byte) (m_aSource.getAnalogTriggerForRouting() ? 1 : 0),
|
||||
(byte) m_bSource.getModuleForRouting(),
|
||||
m_bSource.getChannelForRouting(),
|
||||
(byte) (m_bSource.getAnalogTriggerForRouting() ? 1 : 0),
|
||||
(byte) (reverseDirection ? 1 : 0), index, status);
|
||||
HALUtil.checkStatus(status);
|
||||
m_index = index.get();
|
||||
m_counter = null;
|
||||
break;
|
||||
case EncodingType.k2X_val:
|
||||
case EncodingType.k1X_val:
|
||||
m_counter = new Counter(m_encodingType, m_aSource, m_bSource,
|
||||
reverseDirection);
|
||||
break;
|
||||
}
|
||||
m_distancePerPulse = 1.0;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Encoder,
|
||||
m_index, m_encodingType.value);
|
||||
LiveWindow.addSensor("Encoder", m_aSource.getModuleForRouting(),
|
||||
m_aSource.getChannelForRouting(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b modules and
|
||||
* channels fully specified.
|
||||
*
|
||||
* @param aSlot
|
||||
* The a channel digital input module.
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bSlot
|
||||
* The b channel digital input module.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(final int aSlot, final int aChannel, final int bSlot,
|
||||
final int bChannel, boolean reverseDirection) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = false;
|
||||
m_aSource = new DigitalInput(aSlot, aChannel);
|
||||
m_bSource = new DigitalInput(bSlot, bChannel);
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b modules and
|
||||
* channels fully specified.
|
||||
*
|
||||
* @param aSlot
|
||||
* The a channel digital input module.
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bSlot
|
||||
* The b channel digital input module.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
*/
|
||||
public Encoder(final int aSlot, final int aChannel, final int bSlot,
|
||||
final int bChannel) {
|
||||
this(aSlot, aChannel, bSlot, bChannel, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b modules and
|
||||
* channels fully specified.
|
||||
*
|
||||
* @param aSlot
|
||||
* The a channel digital input module.
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bSlot
|
||||
* The b channel digital input module.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
* @param encodingType
|
||||
* either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If
|
||||
* 4X is selected, then an encoder FPGA object is used and the
|
||||
* returned counts will be 4x the encoder spec'd value since all
|
||||
* rising and falling edges are counted. If 1X or 2X are selected
|
||||
* then a counter object will be used and the returned value will
|
||||
* either exactly match the spec'd count or be double (2x) the
|
||||
* spec'd count.
|
||||
*/
|
||||
public Encoder(final int aSlot, final int aChannel, final int bSlot,
|
||||
final int bChannel, boolean reverseDirection,
|
||||
final EncodingType encodingType) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = false;
|
||||
m_aSource = new DigitalInput(aSlot, aChannel);
|
||||
m_bSource = new DigitalInput(bSlot, bChannel);
|
||||
if (encodingType == null)
|
||||
throw new NullPointerException("Given encoding type was null");
|
||||
m_encodingType = encodingType;
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b modules and
|
||||
* channels fully specified. Using the index pulse forces 4x encoding.
|
||||
*
|
||||
* @param aSlot
|
||||
* The a channel digital input module.
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bSlot
|
||||
* The b channel digital input module.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param indexSlot
|
||||
* The index channel digital input module.
|
||||
* @param indexChannel
|
||||
* The index channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(final int aSlot, final int aChannel, final int bSlot,
|
||||
final int bChannel, final int indexSlot, final int indexChannel,
|
||||
boolean reverseDirection) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = true;
|
||||
m_aSource = new DigitalInput(aSlot, aChannel);
|
||||
m_bSource = new DigitalInput(bSlot, bChannel);
|
||||
m_indexSource = new DigitalInput(indexSlot, indexChannel);
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b modules and
|
||||
* channels fully specified. Using the index pulse forces 4x encoding.
|
||||
*
|
||||
* @param aSlot
|
||||
* The a channel digital input module.
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bSlot
|
||||
* The b channel digital input module.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param indexSlot
|
||||
* The index channel digital input module.
|
||||
* @param indexChannel
|
||||
* The index channel digital input channel.
|
||||
*/
|
||||
public Encoder(final int aSlot, final int aChannel, final int bSlot,
|
||||
final int bChannel, final int indexSlot, final int indexChannel) {
|
||||
this(aSlot, aChannel, bSlot, bChannel, indexSlot, indexChannel, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels assuming
|
||||
* the default module.
|
||||
*
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(final int aChannel, final int bChannel,
|
||||
boolean reverseDirection) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = false;
|
||||
m_aSource = new DigitalInput(aChannel);
|
||||
m_bSource = new DigitalInput(bChannel);
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels assuming
|
||||
* the default module.
|
||||
*
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
*/
|
||||
public Encoder(final int aChannel, final int bChannel) {
|
||||
this(aChannel, bChannel, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels assuming
|
||||
* the default module.
|
||||
*
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
* @param encodingType
|
||||
* either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If
|
||||
* 4X is selected, then an encoder FPGA object is used and the
|
||||
* returned counts will be 4x the encoder spec'd value since all
|
||||
* rising and falling edges are counted. If 1X or 2X are selected
|
||||
* then a counter object will be used and the returned value will
|
||||
* either exactly match the spec'd count or be double (2x) the
|
||||
* spec'd count.
|
||||
*/
|
||||
public Encoder(final int aChannel, final int bChannel,
|
||||
boolean reverseDirection, final EncodingType encodingType) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = false;
|
||||
if (encodingType == null)
|
||||
throw new NullPointerException("Given encoding type was null");
|
||||
m_encodingType = encodingType;
|
||||
m_aSource = new DigitalInput(aChannel);
|
||||
m_bSource = new DigitalInput(bChannel);
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels assuming
|
||||
* the default module. Using an index pulse forces 4x encoding
|
||||
*
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param indexChannel
|
||||
* The index channel digital input channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(final int aChannel, final int bChannel,
|
||||
final int indexChannel, boolean reverseDirection) {
|
||||
m_allocatedA = true;
|
||||
m_allocatedB = true;
|
||||
m_allocatedI = true;
|
||||
m_aSource = new DigitalInput(aChannel);
|
||||
m_bSource = new DigitalInput(bChannel);
|
||||
m_indexSource = new DigitalInput(indexChannel);
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels assuming
|
||||
* the default module. Using an index pulse forces 4x encoding
|
||||
*
|
||||
* @param aChannel
|
||||
* The a channel digital input channel.
|
||||
* @param bChannel
|
||||
* The b channel digital input channel.
|
||||
* @param indexChannel
|
||||
* The index channel digital input channel.
|
||||
*/
|
||||
public Encoder(final int aChannel, final int bChannel,
|
||||
final int indexChannel) {
|
||||
this(aChannel, bChannel, indexChannel, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels as
|
||||
* digital inputs. This is used in the case where the digital inputs are
|
||||
* shared. The Encoder class will not allocate the digital inputs and assume
|
||||
* that they already are counted.
|
||||
*
|
||||
* @param aSource
|
||||
* The source that should be used for the a channel.
|
||||
* @param bSource
|
||||
* the source that should be used for the b channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(DigitalSource aSource, DigitalSource bSource,
|
||||
boolean reverseDirection) {
|
||||
m_allocatedA = false;
|
||||
m_allocatedB = false;
|
||||
m_allocatedI = false;
|
||||
if (aSource == null)
|
||||
throw new NullPointerException("Digital Source A was null");
|
||||
m_aSource = aSource;
|
||||
if (bSource == null)
|
||||
throw new NullPointerException("Digital Source B was null");
|
||||
m_bSource = bSource;
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels as
|
||||
* digital inputs. This is used in the case where the digital inputs are
|
||||
* shared. The Encoder class will not allocate the digital inputs and assume
|
||||
* that they already are counted.
|
||||
*
|
||||
* @param aSource
|
||||
* The source that should be used for the a channel.
|
||||
* @param bSource
|
||||
* the source that should be used for the b channel.
|
||||
*/
|
||||
public Encoder(DigitalSource aSource, DigitalSource bSource) {
|
||||
this(aSource, bSource, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels as
|
||||
* digital inputs. This is used in the case where the digital inputs are
|
||||
* shared. The Encoder class will not allocate the digital inputs and assume
|
||||
* that they already are counted.
|
||||
*
|
||||
* @param aSource
|
||||
* The source that should be used for the a channel.
|
||||
* @param bSource
|
||||
* the source that should be used for the b channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
* @param encodingType
|
||||
* either k1X, k2X, or k4X to indicate 1X, 2X or 4X decoding. If
|
||||
* 4X is selected, then an encoder FPGA object is used and the
|
||||
* returned counts will be 4x the encoder spec'd value since all
|
||||
* rising and falling edges are counted. If 1X or 2X are selected
|
||||
* then a counter object will be used and the returned value will
|
||||
* either exactly match the spec'd count or be double (2x) the
|
||||
* spec'd count.
|
||||
*/
|
||||
public Encoder(DigitalSource aSource, DigitalSource bSource,
|
||||
boolean reverseDirection, final EncodingType encodingType) {
|
||||
m_allocatedA = false;
|
||||
m_allocatedB = false;
|
||||
m_allocatedI = false;
|
||||
if (encodingType == null)
|
||||
throw new NullPointerException("Given encoding type was null");
|
||||
m_encodingType = encodingType;
|
||||
if (aSource == null)
|
||||
throw new NullPointerException("Digital Source A was null");
|
||||
m_aSource = aSource;
|
||||
if (bSource == null)
|
||||
throw new NullPointerException("Digital Source B was null");
|
||||
m_aSource = aSource;
|
||||
m_bSource = bSource;
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels as
|
||||
* digital inputs. This is used in the case where the digital inputs are
|
||||
* shared. The Encoder class will not allocate the digital inputs and assume
|
||||
* that they already are counted.
|
||||
*
|
||||
* @param aSource
|
||||
* The source that should be used for the a channel.
|
||||
* @param bSource
|
||||
* the source that should be used for the b channel.
|
||||
* @param indexSource
|
||||
* the source that should be used for the index channel.
|
||||
* @param reverseDirection
|
||||
* represents the orientation of the encoder and inverts the
|
||||
* output values if necessary so forward represents positive
|
||||
* values.
|
||||
*/
|
||||
public Encoder(DigitalSource aSource, DigitalSource bSource,
|
||||
DigitalSource indexSource, boolean reverseDirection) {
|
||||
m_allocatedA = false;
|
||||
m_allocatedB = false;
|
||||
m_allocatedI = false;
|
||||
if (aSource == null)
|
||||
throw new NullPointerException("Digital Source A was null");
|
||||
m_aSource = aSource;
|
||||
if (bSource == null)
|
||||
throw new NullPointerException("Digital Source B was null");
|
||||
m_aSource = aSource;
|
||||
m_bSource = bSource;
|
||||
m_indexSource = indexSource;
|
||||
initEncoder(reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder constructor. Construct a Encoder given a and b channels as
|
||||
* digital inputs. This is used in the case where the digital inputs are
|
||||
* shared. The Encoder class will not allocate the digital inputs and assume
|
||||
* that they already are counted.
|
||||
*
|
||||
* @param aSource
|
||||
* The source that should be used for the a channel.
|
||||
* @param bSource
|
||||
* the source that should be used for the b channel.
|
||||
* @param indexSource
|
||||
* the source that should be used for the index channel.
|
||||
*/
|
||||
public Encoder(DigitalSource aSource, DigitalSource bSource,
|
||||
DigitalSource indexSource) {
|
||||
this(aSource, bSource, indexSource, false);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
if (m_aSource != null && m_allocatedA) {
|
||||
m_aSource.free();
|
||||
m_allocatedA = false;
|
||||
}
|
||||
if (m_bSource != null && m_allocatedB) {
|
||||
m_bSource.free();
|
||||
m_allocatedB = false;
|
||||
}
|
||||
if (m_indexSource != null && m_allocatedI) {
|
||||
m_indexSource.free();
|
||||
m_allocatedI = false;
|
||||
}
|
||||
|
||||
m_aSource = null;
|
||||
m_bSource = null;
|
||||
m_indexSource = null;
|
||||
if (m_counter != null) {
|
||||
m_counter.free();
|
||||
m_counter = null;
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.freeEncoder(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the Encoder. Starts counting pulses on the Encoder device.
|
||||
*/
|
||||
public void start() {
|
||||
if (m_counter != null) {
|
||||
m_counter.start();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.startEncoder(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops counting pulses on the Encoder device. The value is not changed.
|
||||
*/
|
||||
public void stop() {
|
||||
if (m_counter != null) {
|
||||
m_counter.stop();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.stopEncoder(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw value from the encoder. The raw value is the actual count
|
||||
* unscaled by the 1x, 2x, or 4x scale factor.
|
||||
*
|
||||
* @return Current raw count from the encoder
|
||||
*/
|
||||
public int getRaw() {
|
||||
int value;
|
||||
if (m_counter != null) {
|
||||
value = m_counter.get();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
value = HALLibrary.getEncoder(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current count. Returns the current count on the Encoder. This
|
||||
* method compensates for the decoding type.
|
||||
*
|
||||
* @return Current count from the Encoder adjusted for the 1x, 2x, or 4x
|
||||
* scale factor.
|
||||
*/
|
||||
public int get() {
|
||||
return (int) (getRaw() * decodingScaleFactor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Encoder distance to zero. Resets the current count to zero on
|
||||
* the encoder.
|
||||
*/
|
||||
public void reset() {
|
||||
if (m_counter != null) {
|
||||
m_counter.reset();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.resetEncoder(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the period of the most recent pulse. Returns the period of the
|
||||
* most recent Encoder pulse in seconds. This method compensates for the
|
||||
* decoding type.
|
||||
*
|
||||
* @deprecated Use getRate() in favor of this method. This returns unscaled
|
||||
* periods and getRate() scales using value from
|
||||
* setDistancePerPulse().
|
||||
*
|
||||
* @return Period in seconds of the most recent pulse.
|
||||
*/
|
||||
public double getPeriod() {
|
||||
double measuredPeriod;
|
||||
if (m_counter != null) {
|
||||
measuredPeriod = m_counter.getPeriod();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
measuredPeriod = HALLibrary.getEncoderPeriod(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
return measuredPeriod / decodingScaleFactor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum period for stopped detection. Sets the value that
|
||||
* represents the maximum period of the Encoder before it will assume that
|
||||
* the attached device is stopped. This timeout allows users to determine if
|
||||
* the wheels or other shaft has stopped rotating. This method compensates
|
||||
* for the decoding type.
|
||||
*
|
||||
*
|
||||
* @param maxPeriod
|
||||
* The maximum time between rising and falling edges before the
|
||||
* FPGA will report the device stopped. This is expressed in
|
||||
* seconds.
|
||||
*/
|
||||
public void setMaxPeriod(double maxPeriod) {
|
||||
if (m_counter != null) {
|
||||
m_counter.setMaxPeriod(maxPeriod * decodingScaleFactor());
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary
|
||||
.setEncoderMaxPeriod(m_encoder, (float) maxPeriod, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the encoder is stopped. Using the MaxPeriod value, a boolean
|
||||
* is returned that is true if the encoder is considered stopped and false
|
||||
* if it is still moving. A stopped encoder is one where the most recent
|
||||
* pulse width exceeds the MaxPeriod.
|
||||
*
|
||||
* @return True if the encoder is considered stopped.
|
||||
*/
|
||||
public boolean getStopped() {
|
||||
if (m_counter != null) {
|
||||
return m_counter.getStopped();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getEncoderStopped(m_encoder, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The last direction the encoder value changed.
|
||||
*
|
||||
* @return The last direction the encoder value changed.
|
||||
*/
|
||||
public boolean getDirection() {
|
||||
if (m_counter != null) {
|
||||
return m_counter.getDirection();
|
||||
} else {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getEncoderDirection(m_encoder, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The scale needed to convert a raw counter value into a number of encoder
|
||||
* pulses.
|
||||
*/
|
||||
private double decodingScaleFactor() {
|
||||
switch (m_encodingType.value) {
|
||||
case EncodingType.k1X_val:
|
||||
return 1.0;
|
||||
case EncodingType.k2X_val:
|
||||
return 0.5;
|
||||
case EncodingType.k4X_val:
|
||||
return 0.25;
|
||||
default:
|
||||
// This is never reached, EncodingType enum limits values
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance the robot has driven since the last reset.
|
||||
*
|
||||
* @return The distance driven since the last reset as scaled by the value
|
||||
* from setDistancePerPulse().
|
||||
*/
|
||||
public double getDistance() {
|
||||
return getRaw() * decodingScaleFactor() * m_distancePerPulse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current rate of the encoder. Units are distance per second as
|
||||
* scaled by the value from setDistancePerPulse().
|
||||
*
|
||||
* @return The current rate of the encoder.
|
||||
*/
|
||||
public double getRate() {
|
||||
return m_distancePerPulse / getPeriod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum rate of the device before the hardware reports it
|
||||
* stopped.
|
||||
*
|
||||
* @param minRate
|
||||
* The minimum rate. The units are in distance per second as
|
||||
* scaled by the value from setDistancePerPulse().
|
||||
*/
|
||||
public void setMinRate(double minRate) {
|
||||
setMaxPeriod(m_distancePerPulse / minRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance per pulse for this encoder. This sets the multiplier
|
||||
* used to determine the distance driven based on the count value from the
|
||||
* encoder. Do not include the decoding type in this scale. The library
|
||||
* already compensates for the decoding type. Set this value based on the
|
||||
* encoder's rated Pulses per Revolution and factor in gearing reductions
|
||||
* following the encoder shaft. This distance can be in any units you like,
|
||||
* linear or angular.
|
||||
*
|
||||
* @param distancePerPulse
|
||||
* The scale factor that will be used to convert pulses to useful
|
||||
* units.
|
||||
*/
|
||||
public void setDistancePerPulse(double distancePerPulse) {
|
||||
m_distancePerPulse = distancePerPulse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction sensing for this encoder. This sets the direction
|
||||
* sensing on the encoder so that it could count in the correct software
|
||||
* direction regardless of the mounting.
|
||||
*
|
||||
* @param reverseDirection
|
||||
* true if the encoder direction should be reversed
|
||||
*/
|
||||
public void setReverseDirection(boolean reverseDirection) {
|
||||
if (m_counter != null) {
|
||||
m_counter.setReverseDirection(reverseDirection);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Samples to Average which specifies the number of samples of the
|
||||
* timer to average when calculating the period. Perform averaging to
|
||||
* account for mechanical imperfections or as oversampling to increase
|
||||
* resolution.
|
||||
*
|
||||
* TODO: Should this throw a checked exception, so that the user has to deal
|
||||
* with giving an incorrect value?
|
||||
*
|
||||
* @param samplesToAverage
|
||||
* The number of samples to average from 1 to 127.
|
||||
*/
|
||||
public void setSamplesToAverage(int samplesToAverage) {
|
||||
switch (m_encodingType.value) {
|
||||
case EncodingType.k4X_val:
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setEncoderSamplesToAverage(m_encoder, samplesToAverage,
|
||||
status);
|
||||
if (status.get() == HALLibrary.PARAMETER_OUT_OF_RANGE) {
|
||||
throw new BoundaryException(BoundaryException.getMessage(
|
||||
samplesToAverage, 1, 127));
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
break;
|
||||
case EncodingType.k1X_val:
|
||||
case EncodingType.k2X_val:
|
||||
m_counter.setSamplesToAverage(samplesToAverage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Samples to Average which specifies the number of samples of the
|
||||
* timer to average when calculating the period. Perform averaging to
|
||||
* account for mechanical imperfections or as oversampling to increase
|
||||
* resolution.
|
||||
*
|
||||
* @return SamplesToAverage The number of samples being averaged (from 1 to
|
||||
* 127)
|
||||
*/
|
||||
public int getSamplesToAverage() {
|
||||
switch (m_encodingType.value) {
|
||||
case EncodingType.k4X_val:
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary
|
||||
.getEncoderSamplesToAverage(m_encoder, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
case EncodingType.k1X_val:
|
||||
case EncodingType.k2X_val:
|
||||
return m_counter.getSamplesToAverage();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which parameter of the encoder you are using as a process control
|
||||
* variable. The encoder class supports the rate and distance parameters.
|
||||
*
|
||||
* @param pidSource
|
||||
* An enum to select the parameter.
|
||||
*/
|
||||
public void setPIDSourceParameter(PIDSourceParameter pidSource) {
|
||||
BoundaryException.assertWithinBounds(pidSource.value, 0, 1);
|
||||
m_pidSource = pidSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the PIDSource interface.
|
||||
*
|
||||
* @return The current value of the selected source parameter.
|
||||
*/
|
||||
public double pidGet() {
|
||||
switch (m_pidSource.value) {
|
||||
case PIDSourceParameter.kDistance_val:
|
||||
return getDistance();
|
||||
case PIDSourceParameter.kRate_val:
|
||||
return getRate();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
switch (m_encodingType.value) {
|
||||
case EncodingType.k4X_val:
|
||||
return "Quadrature Encoder";
|
||||
default:
|
||||
return "Encoder";
|
||||
}
|
||||
}
|
||||
|
||||
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("Speed", getRate());
|
||||
m_table.putNumber("Distance", getDistance());
|
||||
m_table.putNumber("Distance per Tick", m_distancePerPulse);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.parsing.ISensor;
|
||||
|
||||
/**
|
||||
* Alias for counter class.
|
||||
* Implement the gear tooth sensor supplied by FIRST. Currently there is no reverse sensing on
|
||||
* the gear tooth sensor, but in future versions we might implement the necessary timing in the
|
||||
* FPGA to sense direction.
|
||||
*/
|
||||
public class GearTooth extends Counter implements ISensor {
|
||||
|
||||
private static final double kGearToothThreshold = 55e-6;
|
||||
|
||||
/**
|
||||
* Common code called by the constructors.
|
||||
*/
|
||||
public void enableDirectionSensing(boolean directionSensitive) {
|
||||
if (directionSensitive) {
|
||||
setPulseLengthMode(kGearToothThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a channel.
|
||||
*
|
||||
* The default module is assumed.
|
||||
*
|
||||
* @param channel The GPIO channel on the digital module that the sensor is connected to.
|
||||
* @param directionSensitive Enable the pulse length decoding in hardware to specify count direction.
|
||||
*/
|
||||
public GearTooth(final int channel, boolean directionSensitive) {
|
||||
super(channel);
|
||||
enableDirectionSensing(directionSensitive);
|
||||
if(directionSensitive) {
|
||||
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1, "D");
|
||||
} else {
|
||||
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a channel.
|
||||
*
|
||||
* The default module is assumed.
|
||||
* No direction sensing is assumed.
|
||||
*
|
||||
* @param channel The GPIO channel on the digital module that the sensor is connected to.
|
||||
*/
|
||||
public GearTooth(final int channel) {
|
||||
this(channel,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a channel and module.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged in to.
|
||||
* @param channel The GPIO channel on the digital module that the sensor is connected to.
|
||||
* @param directionSensitive Enable the pulse length decoding in hardware to specify count direction.
|
||||
*/
|
||||
public GearTooth(final int slot, final int channel, boolean directionSensitive) {
|
||||
super(slot, channel);
|
||||
enableDirectionSensing(directionSensitive);
|
||||
if(directionSensitive) {
|
||||
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1, "D");
|
||||
} else {
|
||||
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1);
|
||||
}
|
||||
LiveWindow.addSensor("GearTooth", slot, channel, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a channel and module.
|
||||
*
|
||||
* No direction sensing is assumed.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged in to.
|
||||
* @param channel The GPIO channel on the digital module that the sensor is connected to.
|
||||
*/
|
||||
public GearTooth(final int slot, final int channel) {
|
||||
this(slot, channel,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a digital input.
|
||||
* This should be used when sharing digial inputs.
|
||||
*
|
||||
* @param source An object that fully descibes the input that the sensor is connected to.
|
||||
* @param directionSensitive Enable the pulse length decoding in hardware to specify count direction.
|
||||
*/
|
||||
public GearTooth(DigitalSource source, boolean directionSensitive) {
|
||||
super(source);
|
||||
enableDirectionSensing(directionSensitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a GearTooth sensor given a digital input.
|
||||
* This should be used when sharing digial inputs.
|
||||
*
|
||||
* No direction sensing is assumed.
|
||||
*
|
||||
* @param source An object that fully descibes the input that the sensor is connected to.
|
||||
*/
|
||||
public GearTooth(DigitalSource source) {
|
||||
this(source,false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Gear Tooth";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* GenericHID Interface
|
||||
*/
|
||||
public abstract class GenericHID {
|
||||
|
||||
/**
|
||||
* Which hand the Human Interface Device is associated with.
|
||||
*/
|
||||
public static class Hand {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kLeft_val = 0;
|
||||
static final int kRight_val = 1;
|
||||
/**
|
||||
* hand: left
|
||||
*/
|
||||
public static final Hand kLeft = new Hand(kLeft_val);
|
||||
/**
|
||||
* hand: right
|
||||
*/
|
||||
public static final Hand kRight = new Hand(kRight_val);
|
||||
|
||||
private Hand(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x position of the HID
|
||||
* @return the x position of the HID
|
||||
*/
|
||||
public final double getX() {
|
||||
return getX(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x position of HID
|
||||
* @param hand which hand, left or right
|
||||
* @return the x position
|
||||
*/
|
||||
public abstract double getX(Hand hand);
|
||||
|
||||
/**
|
||||
* Get the y position of the HID
|
||||
* @return the y position
|
||||
*/
|
||||
public final double getY() {
|
||||
return getY(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y position of the HID
|
||||
* @param hand which hand, left or right
|
||||
* @return the y position
|
||||
*/
|
||||
public abstract double getY(Hand hand);
|
||||
|
||||
/**
|
||||
* Get the z position of the HID
|
||||
* @return the z position
|
||||
*/
|
||||
public final double getZ() {
|
||||
return getZ(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the z position of the HID
|
||||
* @param hand which hand, left or right
|
||||
* @return the z position
|
||||
*/
|
||||
public abstract double getZ(Hand hand);
|
||||
|
||||
/**
|
||||
* Get the twist value
|
||||
* @return the twist value
|
||||
*/
|
||||
public abstract double getTwist();
|
||||
|
||||
/**
|
||||
* Get the throttle
|
||||
* @return the throttle value
|
||||
*/
|
||||
public abstract double getThrottle();
|
||||
|
||||
/**
|
||||
* Get the raw axis
|
||||
* @param which index of the axis
|
||||
* @return the raw value of the selected axis
|
||||
*/
|
||||
public abstract double getRawAxis(int which);
|
||||
|
||||
/**
|
||||
* Is the trigger pressed
|
||||
* @return true if pressed
|
||||
*/
|
||||
public final boolean getTrigger() {
|
||||
return getTrigger(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the trigger pressed
|
||||
* @param hand which hand
|
||||
* @return true if the trigger for the given hand is pressed
|
||||
*/
|
||||
public abstract boolean getTrigger(Hand hand);
|
||||
|
||||
/**
|
||||
* Is the top button pressed
|
||||
* @return true if the top button is pressed
|
||||
*/
|
||||
public final boolean getTop() {
|
||||
return getTop(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the top button pressed
|
||||
* @param hand which hand
|
||||
* @return true if hte top button for the given hand is pressed
|
||||
*/
|
||||
public abstract boolean getTop(Hand hand);
|
||||
|
||||
/**
|
||||
* Is the bumper pressed
|
||||
* @return true if the bumper is pressed
|
||||
*/
|
||||
public final boolean getBumper() {
|
||||
return getBumper(Hand.kRight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the bumper pressed
|
||||
* @param hand which hand
|
||||
* @return true if hte bumper is pressed
|
||||
*/
|
||||
public abstract boolean getBumper(Hand hand);
|
||||
|
||||
/**
|
||||
* Is the given button pressed
|
||||
* @param button which button number
|
||||
* @return true if the button is pressed
|
||||
*/
|
||||
public abstract boolean getRawButton(int button);
|
||||
}
|
||||
290
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/Gyro.java
Normal file
290
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/Gyro.java
Normal file
@@ -0,0 +1,290 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* Use a rate gyro to return the robots heading relative to a starting position.
|
||||
* The Gyro class tracks the robots heading based on the starting position. As
|
||||
* the robot rotates the new heading is computed by integrating the rate of
|
||||
* rotation returned by the sensor. When the class is instantiated, it does a
|
||||
* short calibration routine where it samples the gyro while at rest to
|
||||
* determine the default offset. This is subtracted from each sample to
|
||||
* determine the heading.
|
||||
*/
|
||||
public class Gyro extends SensorBase implements PIDSource, ISensor,
|
||||
LiveWindowSendable {
|
||||
|
||||
static final int kOversampleBits = 10;
|
||||
static final int kAverageBits = 0;
|
||||
static final double kSamplesPerSecond = 50.0;
|
||||
static final double kCalibrationSampleTime = 5.0;
|
||||
static final double kDefaultVoltsPerDegreePerSecond = 0.007;
|
||||
AnalogChannel m_analog;
|
||||
double m_voltsPerDegreePerSecond;
|
||||
double m_offset;
|
||||
int m_center;
|
||||
boolean m_channelAllocated;
|
||||
AccumulatorResult result;
|
||||
private PIDSourceParameter m_pidSource;
|
||||
|
||||
/**
|
||||
* Initialize the gyro. Calibrate the gyro by running for a number of
|
||||
* samples and computing the center value for this part. Then use the center
|
||||
* value as the Accumulator center value for subsequent measurements. It's
|
||||
* important to make sure that the robot is not moving while the centering
|
||||
* calculations are in progress, this is typically done when the robot is
|
||||
* first turned on while it's sitting at rest before the competition starts.
|
||||
*/
|
||||
private void initGyro() {
|
||||
result = new AccumulatorResult();
|
||||
if (m_analog == null) {
|
||||
System.out.println("Null m_analog");
|
||||
}
|
||||
m_voltsPerDegreePerSecond = kDefaultVoltsPerDegreePerSecond;
|
||||
m_analog.setAverageBits(kAverageBits);
|
||||
m_analog.setOversampleBits(kOversampleBits);
|
||||
double sampleRate = kSamplesPerSecond
|
||||
* (1 << (kAverageBits + kOversampleBits));
|
||||
m_analog.setSampleRate(sampleRate);
|
||||
|
||||
Timer.delay(1.0);
|
||||
m_analog.initAccumulator();
|
||||
|
||||
Timer.delay(kCalibrationSampleTime);
|
||||
|
||||
m_analog.getAccumulatorOutput(result);
|
||||
|
||||
m_center = (int) ((double) result.value / (double) result.count + .5);
|
||||
|
||||
m_offset = ((double) result.value / (double) result.count)
|
||||
- (double) m_center;
|
||||
|
||||
m_analog.setAccumulatorCenter(m_center);
|
||||
|
||||
m_analog.setAccumulatorDeadband(0); // /< TODO: compute / parameterize
|
||||
// this
|
||||
m_analog.resetAccumulator();
|
||||
|
||||
setPIDSourceParameter(PIDSourceParameter.kAngle);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Gyro,
|
||||
m_analog.getChannel(), m_analog.getModuleNumber() - 1);
|
||||
LiveWindow.addSensor("Gyro", m_analog.getModuleNumber(),
|
||||
m_analog.getChannel(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gyro constructor given a slot and a channel. .
|
||||
*
|
||||
* @param slot
|
||||
* The cRIO slot for the analog module the gyro is connected to.
|
||||
* @param channel
|
||||
* The analog channel the gyro is connected to.
|
||||
*/
|
||||
public Gyro(int slot, int channel) {
|
||||
m_analog = new AnalogChannel(slot, channel);
|
||||
m_channelAllocated = true;
|
||||
initGyro();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gyro constructor with only a channel.
|
||||
*
|
||||
* Use the default analog module slot.
|
||||
*
|
||||
* @param channel
|
||||
* The analog channel the gyro is connected to.
|
||||
*/
|
||||
public Gyro(int channel) {
|
||||
m_analog = new AnalogChannel(channel);
|
||||
m_channelAllocated = true;
|
||||
initGyro();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gyro constructor with a precreated analog channel object. Use this
|
||||
* constructor when the analog channel needs to be shared. There is no
|
||||
* reference counting when an AnalogChannel is passed to the gyro.
|
||||
*
|
||||
* @param channel
|
||||
* The AnalogChannel object that the gyro is connected to.
|
||||
*/
|
||||
public Gyro(AnalogChannel channel) {
|
||||
m_analog = channel;
|
||||
if (m_analog == null) {
|
||||
System.err
|
||||
.println("Analog channel supplied to Gyro constructor is null");
|
||||
} else {
|
||||
m_channelAllocated = false;
|
||||
initGyro();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the gyro. Resets the gyro to a heading of zero. This can be used if
|
||||
* there is significant drift in the gyro and it needs to be recalibrated
|
||||
* after it has been running.
|
||||
*/
|
||||
public void reset() {
|
||||
if (m_analog != null) {
|
||||
m_analog.resetAccumulator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete (free) the accumulator and the analog components used for the
|
||||
* gyro.
|
||||
*/
|
||||
public void free() {
|
||||
if (m_analog != null && m_channelAllocated) {
|
||||
m_analog.free();
|
||||
}
|
||||
m_analog = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual angle in degrees that the robot is currently facing.
|
||||
*
|
||||
* The angle is based on the current accumulator value corrected by the
|
||||
* oversampling rate, the gyro type and the A/D calibration values. The
|
||||
* angle is continuous, that is can go beyond 360 degrees. This make
|
||||
* algorithms that wouldn't want to see a discontinuity in the gyro output
|
||||
* as it sweeps past 0 on the second time around.
|
||||
*
|
||||
* @return the current heading of the robot in degrees. This heading is
|
||||
* based on integration of the returned rate from the gyro.
|
||||
*/
|
||||
public double getAngle() {
|
||||
if (m_analog == null) {
|
||||
return 0.0;
|
||||
} else {
|
||||
m_analog.getAccumulatorOutput(result);
|
||||
|
||||
long value = result.value - (long) (result.count * m_offset);
|
||||
|
||||
double scaledValue = value
|
||||
* 1e-9
|
||||
* m_analog.getLSBWeight()
|
||||
* (1 << m_analog.getAverageBits())
|
||||
/ (m_analog.getModule().getSampleRate() * m_voltsPerDegreePerSecond);
|
||||
|
||||
return scaledValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rate of rotation of the gyro
|
||||
*
|
||||
* The rate is based on the most recent reading of the gyro analog value
|
||||
*
|
||||
* @return the current rate in degrees per second
|
||||
*/
|
||||
public double getRate() {
|
||||
if (m_analog == null) {
|
||||
return 0.0;
|
||||
} else {
|
||||
return (m_analog.getAverageValue() - ((double) m_center + m_offset))
|
||||
* 1e-9
|
||||
* m_analog.getLSBWeight()
|
||||
/ ((1 << m_analog.getOversampleBits()) * m_voltsPerDegreePerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gyro type based on the sensitivity. This takes the number of
|
||||
* volts/degree/second sensitivity of the gyro and uses it in subsequent
|
||||
* calculations to allow the code to work with multiple gyros.
|
||||
*
|
||||
* @param voltsPerDegreePerSecond
|
||||
* The type of gyro specified as the voltage that represents one
|
||||
* degree/second.
|
||||
*/
|
||||
public void setSensitivity(double voltsPerDegreePerSecond) {
|
||||
m_voltsPerDegreePerSecond = voltsPerDegreePerSecond;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set which parameter of the encoder you are using as a process control
|
||||
* variable. The Gyro class supports the rate and angle parameters
|
||||
*
|
||||
* @param pidSource
|
||||
* An enum to select the parameter.
|
||||
*/
|
||||
public void setPIDSourceParameter(PIDSourceParameter pidSource) {
|
||||
BoundaryException.assertWithinBounds(pidSource.value, 1, 2);
|
||||
m_pidSource = pidSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angle of the gyro for use with PIDControllers
|
||||
*
|
||||
* @return the current angle according to the gyro
|
||||
*/
|
||||
public double pidGet() {
|
||||
switch (m_pidSource.value) {
|
||||
case PIDSourceParameter.kRate_val:
|
||||
return getRate();
|
||||
case PIDSourceParameter.kAngle_val:
|
||||
return getAngle();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Gyro";
|
||||
}
|
||||
|
||||
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() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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, 0, 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() {}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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.
|
||||
*
|
||||
* @param slot The slot of the digital module that the sensor is plugged into.
|
||||
*/
|
||||
public HiTechnicCompass(int slot) {
|
||||
DigitalModule module = DigitalModule.getInstance(slot);
|
||||
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, module.getModuleNumber()-1);
|
||||
LiveWindow.addSensor("HiTechnicCompass", slot, 0, 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() {}
|
||||
}
|
||||
229
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/I2C.java
Normal file
229
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/I2C.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* I2C bus interface class.
|
||||
*
|
||||
* 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 {
|
||||
|
||||
private DigitalModule m_module;
|
||||
private int m_deviceAddress;
|
||||
private boolean m_compatibilityMode;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param module
|
||||
* The Digital Module to which the device is connected.
|
||||
* @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;
|
||||
m_deviceAddress = deviceAddress;
|
||||
m_compatibilityMode = true;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_I2C, deviceAddress,
|
||||
module.getModuleNumber()-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public void free() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic transaction.
|
||||
*
|
||||
* This is a lower-level interface to the I2C hardware giving you more
|
||||
* control over each transaction.
|
||||
*
|
||||
* @param dataToSend
|
||||
* Buffer of data to send as part of the transaction.
|
||||
* @param sendSize
|
||||
* Number of bytes to send as part of the transaction. [0..6]
|
||||
* @param dataReceived
|
||||
* Buffer to read data into.
|
||||
* @param receiveSize
|
||||
* Number of bytes to read from the device. [0..7]
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public synchronized boolean transaction(byte[] dataToSend, int sendSize,
|
||||
byte[] dataReceived, int receiveSize) {
|
||||
boolean aborted = true;
|
||||
|
||||
ByteBuffer dataToSendBuffer = ByteBuffer.wrap(dataToSend);
|
||||
ByteBuffer dataReceivedBuffer = ByteBuffer.allocate(1);
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
|
||||
aborted = HALLibrary
|
||||
.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() == HALLibrary.PARAMETER_OUT_OF_RANGE) {
|
||||
if (sendSize > 6) {
|
||||
throw new BoundaryException(BoundaryException.getMessage(
|
||||
sendSize, 0, 6));
|
||||
} else if (receiveSize > 7) {
|
||||
throw new BoundaryException(BoundaryException.getMessage(
|
||||
receiveSize, 0, 7));
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
HALLibrary.PARAMETER_OUT_OF_RANGE_MESSAGE);
|
||||
}
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
dataReceivedBuffer.get(dataReceived);
|
||||
return aborted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to address a device on the I2C bus.
|
||||
*
|
||||
* This allows you to figure out if there is a device on the I2C bus that
|
||||
* responds to the address specified in the constructor.
|
||||
*
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public boolean addressOnly() {
|
||||
return transaction(null, (byte) 0, null, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a write transaction with the device.
|
||||
*
|
||||
* Write a single byte to a register on a device and wait until the
|
||||
* transaction is complete.
|
||||
*
|
||||
* @param registerAddress
|
||||
* The address of the register on the device to be written.
|
||||
* @param data
|
||||
* The byte to write to the register on the device.
|
||||
*/
|
||||
public synchronized boolean write(int registerAddress, int data) {
|
||||
byte[] buffer = new byte[2];
|
||||
buffer[0] = (byte) registerAddress;
|
||||
buffer[1] = (byte) data;
|
||||
return transaction(buffer, buffer.length, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a read transaction with the device.
|
||||
*
|
||||
* Read 1 to 7 bytes from a device. Most I2C devices will auto-increment the
|
||||
* register pointer internally allowing you to read up to 7 consecutive
|
||||
* registers on a device in a single transaction.
|
||||
*
|
||||
* @param registerAddress
|
||||
* The register to read first in the transaction.
|
||||
* @param count
|
||||
* The number of bytes to read in the transaction. [1..7]
|
||||
* @param buffer
|
||||
* A pointer to the array of bytes to store the data read from
|
||||
* the device.
|
||||
* @return Transfer Aborted... false for success, true for aborted.
|
||||
*/
|
||||
public boolean read(int registerAddress, int count, byte[] buffer) {
|
||||
BoundaryException.assertWithinBounds(count, 1, 7);
|
||||
if (buffer == null) {
|
||||
throw new NullPointerException("Null return buffer was given");
|
||||
}
|
||||
byte[] registerAddressArray = new byte[1];
|
||||
registerAddressArray[0] = (byte) registerAddress;
|
||||
|
||||
return transaction(registerAddressArray, registerAddressArray.length,
|
||||
buffer, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a broadcast write to all devices on the I2C bus.
|
||||
*
|
||||
* This is not currently implemented!
|
||||
*
|
||||
* @param registerAddress
|
||||
* The register to write on all devices on the bus.
|
||||
* @param data
|
||||
* The value to write to the devices.
|
||||
*/
|
||||
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, m_module.getModuleNumber() - 1, "C");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a device's registers contain expected values.
|
||||
*
|
||||
* Most devices will have a set of registers that contain a known value that
|
||||
* can be used to identify them. This allows an I2C device driver to easily
|
||||
* verify that the device contains the expected value.
|
||||
*
|
||||
* @pre The device must support and be configured to use register
|
||||
* auto-increment.
|
||||
*
|
||||
* @param registerAddress
|
||||
* The base register to start reading from the device.
|
||||
* @param count
|
||||
* The size of the field to be verified.
|
||||
* @param expected
|
||||
* A buffer containing the values expected from the device.
|
||||
* @return true if the sensor was verified to be connected
|
||||
*/
|
||||
public boolean verifySensor(int registerAddress, int count, byte[] expected) {
|
||||
// TODO: Make use of all 7 read bytes
|
||||
byte[] deviceData = new byte[4];
|
||||
for (int i = 0, curRegisterAddress = registerAddress; i < count; i += 4, curRegisterAddress += 4) {
|
||||
int toRead = count - i < 4 ? count - i : 4;
|
||||
// Read the chunk of data. Return false if the sensor does not
|
||||
// respond.
|
||||
if (read(curRegisterAddress, toRead, deviceData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (byte j = 0; j < toRead; j++) {
|
||||
if (deviceData[j] != expected[i + j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* Represents a Dashboard which can provide data to be sent by the DriverStation
|
||||
* class.
|
||||
* @author pmalmsten
|
||||
*/
|
||||
public interface IDashboard {
|
||||
/**
|
||||
* Gets a reference to the current data to be sent to the dashboard.
|
||||
* @return Byte array of data.
|
||||
*/
|
||||
public byte[] getBytes();
|
||||
|
||||
/**
|
||||
* Gets the length of the current data to be sent to the
|
||||
* dashboard.
|
||||
* @return The length of the data array to be sent to the dashboard.
|
||||
*/
|
||||
public int getBytesLength();
|
||||
|
||||
/**
|
||||
* If the dashboard had data buffered to be sent, calling this method
|
||||
* will reset the output buffer.
|
||||
*/
|
||||
public void flush();
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary.InterruptHandlerFunction;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
|
||||
/**
|
||||
* Base for sensors to be used with interrupts
|
||||
*/
|
||||
public abstract class InterruptableSensorBase extends SensorBase {
|
||||
|
||||
/**
|
||||
* The interrupt resource
|
||||
*/
|
||||
protected Pointer m_interrupt;
|
||||
/**
|
||||
* The interrupt manager resource
|
||||
*/
|
||||
protected InterruptHandlerFunction m_manager;
|
||||
/**
|
||||
* The index of the interrupt
|
||||
*/
|
||||
protected int m_interruptIndex;
|
||||
/**
|
||||
* Resource manager
|
||||
*/
|
||||
protected static Resource interrupts = new Resource(HALLibrary.interrupt_kNumSystems.get());
|
||||
|
||||
/**
|
||||
* Create a new InterrupatableSensorBase
|
||||
*/
|
||||
public InterruptableSensorBase() {
|
||||
m_manager = null;
|
||||
m_interrupt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate the interrupt
|
||||
*
|
||||
* @param watcher
|
||||
*/
|
||||
public void allocateInterrupts(boolean watcher) {
|
||||
if (!watcher) {
|
||||
throw new IllegalArgumentException(
|
||||
"Interrupt callbacks not yet supported");
|
||||
}
|
||||
// Expects the calling leaf class to allocate an interrupt index.
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_interrupt = HALLibrary.initializeInterrupts(m_interruptIndex,
|
||||
(byte) (watcher ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel interrupts on this device. This deallocates all the chipobject
|
||||
* structures and disables any interrupts.
|
||||
*/
|
||||
public void cancelInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.cleanInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* In synchronous mode, wait for the defined interrupt to occur.
|
||||
*
|
||||
* @param timeout
|
||||
* Timeout in seconds
|
||||
*/
|
||||
public void waitForInterrupt(double timeout) {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.waitForInterrupt(m_interrupt, (float) timeout, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable interrupts to occur on this input. Interrupts are disabled when
|
||||
* the RequestInterrupt call is made. This gives time to do the setup of the
|
||||
* other options before starting to field interrupts.
|
||||
*/
|
||||
public void enableInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.enableInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Interrupts without without deallocating structures.
|
||||
*/
|
||||
public void disableInterrupts() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.disableInterrupts(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the timestamp for the interrupt that occurred most recently. This
|
||||
* is in the same time domain as getClock().
|
||||
*
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
public double readInterruptTimestamp() {
|
||||
if (m_interrupt == null || m_manager == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
double timestamp = HALLibrary.readInterruptTimestamp(m_interrupt, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
|
||||
/**
|
||||
* IterativeRobot implements a specific type of Robot Program framework, extending the RobotBase class.
|
||||
*
|
||||
* The IterativeRobot class is intended to be subclassed by a user creating a robot program.
|
||||
*
|
||||
* This class is intended to implement the "old style" default code, by providing
|
||||
* the following functions which are called by the main loop, startCompetition(), at the appropriate times:
|
||||
*
|
||||
* robotInit() -- provide for initialization at robot power-on
|
||||
*
|
||||
* init() functions -- each of the following functions is called once when the
|
||||
* appropriate mode is entered:
|
||||
* - DisabledInit() -- called only when first disabled
|
||||
* - AutonomousInit() -- called each and every time autonomous is entered from another mode
|
||||
* - TeleopInit() -- called each and every time teleop is entered from another mode
|
||||
* - TestInit() -- called each and every time test mode is entered from anothermode
|
||||
*
|
||||
* Periodic() functions -- each of these functions is called iteratively at the
|
||||
* appropriate periodic rate (aka the "slow loop"). The period of
|
||||
* the iterative robot is synced to the driver station control packets,
|
||||
* giving a periodic frequency of about 50Hz (50 times per second).
|
||||
* - disabledPeriodic()
|
||||
* - autonomousPeriodic()
|
||||
* - teleopPeriodic()
|
||||
* - testPeriodoc()
|
||||
*
|
||||
*/
|
||||
public class IterativeRobot extends RobotBase {
|
||||
private boolean m_disabledInitialized;
|
||||
private boolean m_autonomousInitialized;
|
||||
private boolean m_teleopInitialized;
|
||||
private boolean m_testInitialized;
|
||||
|
||||
/**
|
||||
* Constructor for RobotIterativeBase
|
||||
*
|
||||
* The constructor initializes the instance variables for the robot to indicate
|
||||
* the status of initialization for disabled, autonomous, and teleop code.
|
||||
*/
|
||||
public IterativeRobot() {
|
||||
// set status for initialization of disabled, autonomous, and teleop code.
|
||||
m_disabledInitialized = false;
|
||||
m_autonomousInitialized = false;
|
||||
m_teleopInitialized = false;
|
||||
m_testInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an alternate "main loop" via startCompetition().
|
||||
*
|
||||
*/
|
||||
public void startCompetition() {
|
||||
UsageReporting.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
|
||||
|
||||
robotInit();
|
||||
|
||||
// tracing support:
|
||||
final int TRACE_LOOP_MAX = 100;
|
||||
int loopCount = TRACE_LOOP_MAX;
|
||||
Object marker = null;
|
||||
boolean didDisabledPeriodic = false;
|
||||
boolean didAutonomousPeriodic = false;
|
||||
boolean didTeleopPeriodic = false;
|
||||
boolean didTestPeriodic = false;
|
||||
|
||||
// loop forever, calling the appropriate mode-dependent function
|
||||
LiveWindow.setEnabled(false);
|
||||
while (true) {
|
||||
// Call the appropriate function depending upon the current robot mode
|
||||
if (isDisabled()) {
|
||||
// call DisabledInit() if we are now just entering disabled mode from
|
||||
// either a different mode or from power-on
|
||||
if (!m_disabledInitialized) {
|
||||
LiveWindow.setEnabled(false);
|
||||
disabledInit();
|
||||
m_disabledInitialized = true;
|
||||
// reset the initialization flags for the other modes
|
||||
m_autonomousInitialized = false;
|
||||
m_teleopInitialized = false;
|
||||
m_testInitialized = false;
|
||||
}
|
||||
if (nextPeriodReady()) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramDisabled();
|
||||
disabledPeriodic();
|
||||
didDisabledPeriodic = true;
|
||||
}
|
||||
} else if (isTest()) {
|
||||
// call TestInit() if we are now just entering test mode from either
|
||||
// a different mode or from power-on
|
||||
if (!m_testInitialized) {
|
||||
LiveWindow.setEnabled(true);
|
||||
testInit();
|
||||
m_testInitialized = true;
|
||||
m_autonomousInitialized = false;
|
||||
m_teleopInitialized = false;
|
||||
m_disabledInitialized = false;
|
||||
}
|
||||
if (nextPeriodReady()) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramTest();
|
||||
testPeriodic();
|
||||
didTestPeriodic = true;
|
||||
}
|
||||
} else if (isAutonomous()) {
|
||||
// call Autonomous_Init() if this is the first time
|
||||
// we've entered autonomous_mode
|
||||
if (!m_autonomousInitialized) {
|
||||
LiveWindow.setEnabled(false);
|
||||
// KBS NOTE: old code reset all PWMs and relays to "safe values"
|
||||
// whenever entering autonomous mode, before calling
|
||||
// "Autonomous_Init()"
|
||||
autonomousInit();
|
||||
m_autonomousInitialized = true;
|
||||
m_testInitialized = false;
|
||||
m_teleopInitialized = false;
|
||||
m_disabledInitialized = false;
|
||||
}
|
||||
if (nextPeriodReady()) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramAutonomous();
|
||||
autonomousPeriodic();
|
||||
didAutonomousPeriodic = true;
|
||||
}
|
||||
} else {
|
||||
// call Teleop_Init() if this is the first time
|
||||
// we've entered teleop_mode
|
||||
if (!m_teleopInitialized) {
|
||||
LiveWindow.setEnabled(false);
|
||||
teleopInit();
|
||||
m_teleopInitialized = true;
|
||||
m_testInitialized = false;
|
||||
m_autonomousInitialized = false;
|
||||
m_disabledInitialized = false;
|
||||
}
|
||||
if (nextPeriodReady()) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramTeleop();
|
||||
teleopPeriodic();
|
||||
didTeleopPeriodic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the appropriate next periodic function should be called.
|
||||
* Call the periodic functions whenever a packet is received from the Driver Station, or about every 20ms.
|
||||
*/
|
||||
private boolean nextPeriodReady() {
|
||||
return m_ds.isNewControlData();
|
||||
}
|
||||
|
||||
/* ----------- Overridable initialization code -----------------*/
|
||||
|
||||
/**
|
||||
* Robot-wide initialization code should go here.
|
||||
*
|
||||
* Users should override this method for default Robot-wide initialization which will
|
||||
* be called when the robot is first powered on. It will be called exactly 1 time.
|
||||
*/
|
||||
public void robotInit() {
|
||||
System.out.println("Default IterativeRobot.robotInit() method... Overload me!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization code for disabled mode should go here.
|
||||
*
|
||||
* Users should override this method for initialization code which will be called each time
|
||||
* the robot enters disabled mode.
|
||||
*/
|
||||
public void disabledInit() {
|
||||
System.out.println("Default IterativeRobot.disabledInit() method... Overload me!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization code for autonomous mode should go here.
|
||||
*
|
||||
* Users should override this method for initialization code which will be called each time
|
||||
* the robot enters autonomous mode.
|
||||
*/
|
||||
public void autonomousInit() {
|
||||
System.out.println("Default IterativeRobot.autonomousInit() method... Overload me!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization code for teleop mode should go here.
|
||||
*
|
||||
* Users should override this method for initialization code which will be called each time
|
||||
* the robot enters teleop mode.
|
||||
*/
|
||||
public void teleopInit() {
|
||||
System.out.println("Default IterativeRobot.teleopInit() method... Overload me!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization code for test mode should go here.
|
||||
*
|
||||
* Users should override this method for initialization code which will be called each time
|
||||
* the robot enters test mode.
|
||||
*/
|
||||
public void testInit() {
|
||||
System.out.println("Default IterativeRobot.testInit() method... Overload me!");
|
||||
}
|
||||
|
||||
/* ----------- Overridable periodic code -----------------*/
|
||||
|
||||
private boolean dpFirstRun = true;
|
||||
/**
|
||||
* Periodic code for disabled mode should go here.
|
||||
*
|
||||
* Users should override this method for code which will be called periodically at a regular
|
||||
* rate while the robot is in disabled mode.
|
||||
*/
|
||||
public void disabledPeriodic() {
|
||||
if (dpFirstRun) {
|
||||
System.out.println("Default IterativeRobot.disabledPeriodic() method... Overload me!");
|
||||
dpFirstRun = false;
|
||||
}
|
||||
Timer.delay(0.001);
|
||||
}
|
||||
|
||||
private boolean apFirstRun = true;
|
||||
|
||||
/**
|
||||
* Periodic code for autonomous mode should go here.
|
||||
*
|
||||
* Users should override this method for code which will be called periodically at a regular
|
||||
* rate while the robot is in autonomous mode.
|
||||
*/
|
||||
public void autonomousPeriodic() {
|
||||
if (apFirstRun) {
|
||||
System.out.println("Default IterativeRobot.autonomousPeriodic() method... Overload me!");
|
||||
apFirstRun = false;
|
||||
}
|
||||
Timer.delay(0.001);
|
||||
}
|
||||
|
||||
private boolean tpFirstRun = true;
|
||||
|
||||
/**
|
||||
* Periodic code for teleop mode should go here.
|
||||
*
|
||||
* Users should override this method for code which will be called periodically at a regular
|
||||
* rate while the robot is in teleop mode.
|
||||
*/
|
||||
public void teleopPeriodic() {
|
||||
if (tpFirstRun) {
|
||||
System.out.println("Default IterativeRobot.teleopPeriodic() method... Overload me!");
|
||||
tpFirstRun = false;
|
||||
}
|
||||
Timer.delay(0.001);
|
||||
}
|
||||
|
||||
private boolean tmpFirstRun = true;
|
||||
|
||||
/**
|
||||
* Periodic code for test mode should go here
|
||||
*
|
||||
* Users should override this method for code which will be called periodically at a regular rate
|
||||
* while the robot is in test mode.
|
||||
*/
|
||||
public void testPeriodic() {
|
||||
if (tmpFirstRun) {
|
||||
System.out.println("Default IterativeRobot.testPeriodic() method... Overload me!");
|
||||
tmpFirstRun = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.parsing.IDeviceController;
|
||||
|
||||
/**
|
||||
* VEX Robotics Jaguar Speed Control
|
||||
*/
|
||||
public class Jaguar extends SafePWM implements SpeedController, IDeviceController {
|
||||
|
||||
/**
|
||||
* Common initialization code called by all constructors.
|
||||
*/
|
||||
private void initJaguar() {
|
||||
/*
|
||||
* Input profile defined by Luminary Micro.
|
||||
*
|
||||
* Full reverse ranges from 0.671325ms to 0.6972211ms
|
||||
* Proportional reverse ranges from 0.6972211ms to 1.4482078ms
|
||||
* Neutral ranges from 1.4482078ms to 1.5517922ms
|
||||
* Proportional forward ranges from 1.5517922ms to 2.3027789ms
|
||||
* Full forward ranges from 2.3027789ms to 2.328675ms
|
||||
*/
|
||||
setBounds(2.31, 1.55, 1.507, 1.454, .697);
|
||||
setPeriodMultiplier(PeriodMultiplier.k1X);
|
||||
setRaw(m_centerPwm);
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Jaguar, getChannel(), getModuleNumber()-1);
|
||||
LiveWindow.addActuator("Jaguar", getModuleNumber(), getChannel(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assumes the default digital module.
|
||||
*
|
||||
* @param channel The PWM channel on the digital module that the Jaguar is attached to.
|
||||
*/
|
||||
public Jaguar(final int channel) {
|
||||
super(channel);
|
||||
initJaguar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that specifies the digital module.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged into.
|
||||
* @param channel The PWM channel on the digital module that the Jaguar is attached to.
|
||||
*/
|
||||
public Jaguar(final int slot, final int channel) {
|
||||
super(slot, channel);
|
||||
initJaguar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* @deprecated For compatibility with CANJaguar
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed to set. Value should be between -1.0 and 1.0.
|
||||
* @param syncGroup The update group to add this Set() to, pending UpdateSyncGroup(). If 0, update immediately.
|
||||
*/
|
||||
public void set(double speed, byte syncGroup) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed value between -1.0 and 1.0 to set.
|
||||
*/
|
||||
public void set(double speed) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recently set value of the PWM.
|
||||
*
|
||||
* @return The most recently set value for the PWM between -1.0 and 1.0.
|
||||
*/
|
||||
public double get() {
|
||||
return getSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the PID value as seen in the PIDOutput base object.
|
||||
*
|
||||
* @param output Write out the PWM value as was found in the PIDController
|
||||
*/
|
||||
public void pidWrite(double output) {
|
||||
set(output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.parsing.IInputOutput;
|
||||
|
||||
/**
|
||||
* Handle input from standard Joysticks connected to the Driver Station.
|
||||
* This class handles standard input that comes from the Driver Station. Each time a value is requested
|
||||
* the most recent value is returned. There is a single class instance for each joystick and the mapping
|
||||
* of ports to hardware buttons depends on the code in the driver station.
|
||||
*/
|
||||
public class Joystick extends GenericHID implements IInputOutput {
|
||||
|
||||
static final byte kDefaultXAxis = 1;
|
||||
static final byte kDefaultYAxis = 2;
|
||||
static final byte kDefaultZAxis = 3;
|
||||
static final byte kDefaultTwistAxis = 3;
|
||||
static final byte kDefaultThrottleAxis = 4;
|
||||
static final int kDefaultTriggerButton = 1;
|
||||
static final int kDefaultTopButton = 2;
|
||||
|
||||
/**
|
||||
* Represents an analog axis on a joystick.
|
||||
*/
|
||||
public static class AxisType {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kX_val = 0;
|
||||
static final int kY_val = 1;
|
||||
static final int kZ_val = 2;
|
||||
static final int kTwist_val = 3;
|
||||
static final int kThrottle_val = 4;
|
||||
static final int kNumAxis_val = 5;
|
||||
/**
|
||||
* axis: x-axis
|
||||
*/
|
||||
public static final AxisType kX = new AxisType(kX_val);
|
||||
/**
|
||||
* axis: y-axis
|
||||
*/
|
||||
public static final AxisType kY = new AxisType(kY_val);
|
||||
/**
|
||||
* axis: z-axis
|
||||
*/
|
||||
public static final AxisType kZ = new AxisType(kZ_val);
|
||||
/**
|
||||
* axis: twist
|
||||
*/
|
||||
public static final AxisType kTwist = new AxisType(kTwist_val);
|
||||
/**
|
||||
* axis: throttle
|
||||
*/
|
||||
public static final AxisType kThrottle = new AxisType(kThrottle_val);
|
||||
/**
|
||||
* axis: number of axis
|
||||
*/
|
||||
public static final AxisType kNumAxis = new AxisType(kNumAxis_val);
|
||||
|
||||
private AxisType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a digital button on the JoyStick
|
||||
*/
|
||||
public static class ButtonType {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kTrigger_val = 0;
|
||||
static final int kTop_val = 1;
|
||||
static final int kNumButton_val = 2;
|
||||
/**
|
||||
* button: trigger
|
||||
*/
|
||||
public static final ButtonType kTrigger = new ButtonType((kTrigger_val));
|
||||
/**
|
||||
* button: top button
|
||||
*/
|
||||
public static final ButtonType kTop = new ButtonType(kTop_val);
|
||||
/**
|
||||
* button: num button types
|
||||
*/
|
||||
public static final ButtonType kNumButton = new ButtonType((kNumButton_val));
|
||||
|
||||
private ButtonType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
private DriverStation m_ds;
|
||||
private final int m_port;
|
||||
private final byte[] m_axes;
|
||||
private final byte[] m_buttons;
|
||||
|
||||
/**
|
||||
* Construct an instance of a joystick.
|
||||
* The joystick index is the usb port on the drivers station.
|
||||
*
|
||||
* @param port The port on the driver station that the joystick is plugged into.
|
||||
*/
|
||||
public Joystick(final int port) {
|
||||
this(port, AxisType.kNumAxis.value, ButtonType.kNumButton.value);
|
||||
|
||||
m_axes[AxisType.kX.value] = kDefaultXAxis;
|
||||
m_axes[AxisType.kY.value] = kDefaultYAxis;
|
||||
m_axes[AxisType.kZ.value] = kDefaultZAxis;
|
||||
m_axes[AxisType.kTwist.value] = kDefaultTwistAxis;
|
||||
m_axes[AxisType.kThrottle.value] = kDefaultThrottleAxis;
|
||||
|
||||
m_buttons[ButtonType.kTrigger.value] = kDefaultTriggerButton;
|
||||
m_buttons[ButtonType.kTop.value] = kDefaultTopButton;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Joystick, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected version of the constructor to be called by sub-classes.
|
||||
*
|
||||
* This constructor allows the subclass to configure the number of constants
|
||||
* for axes and buttons.
|
||||
*
|
||||
* @param port The port on the driver station that the joystick is plugged into.
|
||||
* @param numAxisTypes The number of axis types in the enum.
|
||||
* @param numButtonTypes The number of button types in the enum.
|
||||
*/
|
||||
protected Joystick(int port, int numAxisTypes, int numButtonTypes) {
|
||||
m_ds = DriverStation.getInstance();
|
||||
m_axes = new byte[numAxisTypes];
|
||||
m_buttons = new byte[numButtonTypes];
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X value of the joystick.
|
||||
* This depends on the mapping of the joystick connected to the current port.
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The X value of the joystick.
|
||||
*/
|
||||
public double getX(Hand hand) {
|
||||
return getRawAxis(m_axes[AxisType.kX.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y value of the joystick.
|
||||
* This depends on the mapping of the joystick connected to the current port.
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The Y value of the joystick.
|
||||
*/
|
||||
public double getY(Hand hand) {
|
||||
return getRawAxis(m_axes[AxisType.kY.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Z value of the joystick.
|
||||
* This depends on the mapping of the joystick connected to the current port.
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The Z value of the joystick.
|
||||
*/
|
||||
public double getZ(Hand hand) {
|
||||
return getRawAxis(m_axes[AxisType.kZ.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the twist value of the current joystick.
|
||||
* This depends on the mapping of the joystick connected to the current port.
|
||||
*
|
||||
* @return The Twist value of the joystick.
|
||||
*/
|
||||
public double getTwist() {
|
||||
return getRawAxis(m_axes[AxisType.kTwist.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the throttle value of the current joystick.
|
||||
* This depends on the mapping of the joystick connected to the current port.
|
||||
*
|
||||
* @return The Throttle value of the joystick.
|
||||
*/
|
||||
public double getThrottle() {
|
||||
return getRawAxis(m_axes[AxisType.kThrottle.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the axis.
|
||||
*
|
||||
* @param axis The axis to read [1-6].
|
||||
* @return The value of the axis.
|
||||
*/
|
||||
public double getRawAxis(final int axis) {
|
||||
return m_ds.getStickAxis(m_port, axis);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the current joystick, return the axis determined by the argument.
|
||||
*
|
||||
* This is for cases where the joystick axis is returned programatically, otherwise one of the
|
||||
* previous functions would be preferable (for example getX()).
|
||||
*
|
||||
* @param axis The axis to read.
|
||||
* @return The value of the axis.
|
||||
*/
|
||||
public double getAxis(final AxisType axis) {
|
||||
switch (axis.value) {
|
||||
case AxisType.kX_val:
|
||||
return getX();
|
||||
case AxisType.kY_val:
|
||||
return getY();
|
||||
case AxisType.kZ_val:
|
||||
return getZ();
|
||||
case AxisType.kTwist_val:
|
||||
return getTwist();
|
||||
case AxisType.kThrottle_val:
|
||||
return getThrottle();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the state of the trigger on the joystick.
|
||||
*
|
||||
* Look up which button has been assigned to the trigger and read its state.
|
||||
*
|
||||
* @param hand This parameter is ignored for the Joystick class and is only here to complete the GenericHID interface.
|
||||
* @return The state of the trigger.
|
||||
*/
|
||||
public boolean getTrigger(Hand hand) {
|
||||
return getRawButton(m_buttons[ButtonType.kTrigger.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the state of the top button on the joystick.
|
||||
*
|
||||
* Look up which button has been assigned to the top and read its state.
|
||||
*
|
||||
* @param hand This parameter is ignored for the Joystick class and is only here to complete the GenericHID interface.
|
||||
* @return The state of the top button.
|
||||
*/
|
||||
public boolean getTop(Hand hand) {
|
||||
return getRawButton(m_buttons[ButtonType.kTop.value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not supported for the Joystick.
|
||||
* This method is only here to complete the GenericHID interface.
|
||||
*
|
||||
* @param hand This parameter is ignored for the Joystick class and is only here to complete the GenericHID interface.
|
||||
* @return The state of the bumper (always false)
|
||||
*/
|
||||
public boolean getBumper(Hand hand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the button value for buttons 1 through 12.
|
||||
*
|
||||
* The buttons are returned in a single 16 bit value with one bit representing the state
|
||||
* of each button. The appropriate button is returned as a boolean value.
|
||||
*
|
||||
* @param button The button number to be read.
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getRawButton(final int button) {
|
||||
return ((0x1 << (button - 1)) & m_ds.getStickButtons(m_port)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get buttons based on an enumerated type.
|
||||
*
|
||||
* The button type will be looked up in the list of buttons and then read.
|
||||
*
|
||||
* @param button The type of button to read.
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getButton(ButtonType button) {
|
||||
switch (button.value) {
|
||||
case ButtonType.kTrigger_val:
|
||||
return getTrigger();
|
||||
case ButtonType.kTop_val:
|
||||
return getTop();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the magnitude of the direction vector formed by the joystick's
|
||||
* current position relative to its origin
|
||||
*
|
||||
* @return The magnitude of the direction vector
|
||||
*/
|
||||
public double getMagnitude() {
|
||||
return Math.sqrt(Math.pow(getX(), 2) + Math.pow(getY(), 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direction of the vector formed by the joystick and its origin
|
||||
* in radians
|
||||
*
|
||||
* @return The direction of the vector in radians
|
||||
*/
|
||||
public double getDirectionRadians() {
|
||||
return Math.atan2(getX(), -getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direction of the vector formed by the joystick and its origin
|
||||
* in degrees
|
||||
*
|
||||
* uses acos(-1) to represent Pi due to absence of readily accessable Pi
|
||||
* constant in C++
|
||||
*
|
||||
* @return The direction of the vector in degrees
|
||||
*/
|
||||
public double getDirectionDegrees() {
|
||||
return Math.toDegrees(getDirectionRadians());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channel currently associated with the specified axis.
|
||||
*
|
||||
* @param axis The axis to look up the channel for.
|
||||
* @return The channel fr the axis.
|
||||
*/
|
||||
public int getAxisChannel(AxisType axis) {
|
||||
return m_axes[axis.value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channel associated with a specified axis.
|
||||
*
|
||||
* @param axis The axis to set the channel for.
|
||||
* @param channel The channel to set the axis to.
|
||||
*/
|
||||
public void setAxisChannel(AxisType axis, int channel) {
|
||||
m_axes[axis.value] = (byte) channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 com.sun.jna.Pointer;
|
||||
import com.sun.jna.Structure;
|
||||
import edu.wpi.first.wpilibj.communication.FRCControl;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
|
||||
/**
|
||||
* @author bradmiller
|
||||
* Handles raw data input from the FRC Kinect Server
|
||||
* when used with a Kinect device connected to the Driver Station.
|
||||
* Each time a value is requested the most recent value is returned.
|
||||
* See Getting Started with Microsoft Kinect for FRC and the Kinect
|
||||
* for Windows SDK API reference for more information
|
||||
*
|
||||
*/
|
||||
public class Kinect {
|
||||
|
||||
private static Kinect m_instance;
|
||||
|
||||
/**
|
||||
* Gets an instance of the Kinect device
|
||||
*
|
||||
* @return The Kinect.
|
||||
*/
|
||||
public static synchronized Kinect getInstance() {
|
||||
if(m_instance == null)
|
||||
m_instance = new Kinect();
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of 4 coordinates (x,y,z,w) bundled into one object
|
||||
*/
|
||||
public class Point4 {
|
||||
public float x, y, z, w;
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
public float getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
static class header_t extends Structure {
|
||||
|
||||
byte[] version = new byte[11];
|
||||
byte players;
|
||||
int flags;
|
||||
float[] floorClipPlane = new float[4];
|
||||
float[] gravityNormalVector = new float[3];
|
||||
|
||||
final static int size = 44;
|
||||
|
||||
header_t(Pointer backingMemory) {
|
||||
useMemory(backingMemory);
|
||||
}
|
||||
|
||||
public void read() {
|
||||
backingNativeMemory.getBytes(0, version, 0, version.length);
|
||||
players = backingNativeMemory.getByte(11);
|
||||
flags = backingNativeMemory.getInt(12);
|
||||
backingNativeMemory.getFloats(16, floorClipPlane, 0, floorClipPlane.length);
|
||||
backingNativeMemory.getFloats(32, gravityNormalVector, 0, gravityNormalVector.length);
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setBytes(0, version, 0, version.length);
|
||||
backingNativeMemory.setByte(11, players);
|
||||
backingNativeMemory.setInt(12, flags);
|
||||
backingNativeMemory.setFloats(16, floorClipPlane, 0, floorClipPlane.length);
|
||||
backingNativeMemory.setFloats(32, gravityNormalVector, 0, gravityNormalVector.length);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
static class skeletonExtra_t extends Structure {
|
||||
byte[] trackingState = new byte[20];
|
||||
float[] position = new float[3];
|
||||
int quality;
|
||||
int trackState;
|
||||
|
||||
final static int size = 40;
|
||||
|
||||
skeletonExtra_t(Pointer backingMemory) {
|
||||
useMemory(backingMemory);
|
||||
}
|
||||
|
||||
public void read() {
|
||||
backingNativeMemory.getBytes(0, trackingState, 0, trackingState.length);
|
||||
backingNativeMemory.getFloats(20, position, 0, position.length);
|
||||
quality = backingNativeMemory.getInt(32);
|
||||
trackState = backingNativeMemory.getInt(36);
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setBytes(0, trackingState, 0, trackingState.length);
|
||||
backingNativeMemory.setFloats(20, position, 0, position.length);
|
||||
backingNativeMemory.setInt(32, quality);
|
||||
backingNativeMemory.setInt(36, trackState);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
static class skeleton_t extends Structure {
|
||||
float[] vertices = new float[60];
|
||||
|
||||
final static int size = 240;
|
||||
|
||||
skeleton_t(Pointer backingMemory) {
|
||||
useMemory(backingMemory);
|
||||
}
|
||||
|
||||
public void read() {
|
||||
backingNativeMemory.getFloats(0, vertices, 0, vertices.length);
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setFloats(0, vertices, 0, vertices.length);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
class header_block_t extends FRCControl.DynamicControlData {
|
||||
byte size = 45;
|
||||
byte id = kHeaderBlockID;
|
||||
header_t data;
|
||||
|
||||
{
|
||||
allocateMemory();
|
||||
data = new header_t(
|
||||
new Pointer(backingNativeMemory.address().toUWord().toPrimitive() + 2,
|
||||
header_t.size));
|
||||
}
|
||||
|
||||
public void read() {
|
||||
|
||||
size = backingNativeMemory.getByte(0);
|
||||
id = backingNativeMemory.getByte(1);
|
||||
data.read();
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setByte(0, size);
|
||||
backingNativeMemory.setByte(1, id);
|
||||
data.write();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 46;
|
||||
}
|
||||
|
||||
public void copy(header_block_t dest) {
|
||||
write();
|
||||
Pointer.copyBytes(backingNativeMemory, 0, dest.backingNativeMemory, 0, size());
|
||||
dest.read();
|
||||
}
|
||||
}
|
||||
|
||||
class skeletonExtra_block_t extends FRCControl.DynamicControlData {
|
||||
byte size = 41;
|
||||
byte id = kSkeletonExtraBlockID;
|
||||
skeletonExtra_t data;
|
||||
|
||||
{
|
||||
allocateMemory();
|
||||
data = new skeletonExtra_t(
|
||||
new Pointer(backingNativeMemory.address().toUWord().toPrimitive() + 2,
|
||||
skeletonExtra_t.size));
|
||||
}
|
||||
|
||||
public void read() {
|
||||
|
||||
size = backingNativeMemory.getByte(0);
|
||||
id = backingNativeMemory.getByte(1);
|
||||
data.read();
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setByte(0, size);
|
||||
backingNativeMemory.setByte(1, id);
|
||||
data.write();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
public void copy(skeletonExtra_block_t dest) {
|
||||
write();
|
||||
Pointer.copyBytes(backingNativeMemory, 0, dest.backingNativeMemory, 0, size());
|
||||
dest.read();
|
||||
}
|
||||
}
|
||||
|
||||
class skeleton_block_t extends FRCControl.DynamicControlData {
|
||||
byte size = -15; //temporary hack for 241
|
||||
byte id = kSkeletonBlockID;
|
||||
skeleton_t data;
|
||||
|
||||
{
|
||||
allocateMemory();
|
||||
data = new skeleton_t(
|
||||
new Pointer(backingNativeMemory.address().toUWord().toPrimitive() + 2,
|
||||
skeleton_t.size));
|
||||
}
|
||||
|
||||
public void read() {
|
||||
size = backingNativeMemory.getByte(0);
|
||||
id = backingNativeMemory.getByte(1);
|
||||
data.read();
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setByte(0, size);
|
||||
backingNativeMemory.setByte(1, id);
|
||||
data.write();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return 242;
|
||||
}
|
||||
|
||||
public void copy(skeleton_block_t dest) {
|
||||
write();
|
||||
Pointer.copyBytes(backingNativeMemory, 0, dest.backingNativeMemory, 0, size());
|
||||
dest.read();
|
||||
}
|
||||
}
|
||||
|
||||
static final byte kHeaderBlockID = 19;
|
||||
static final byte kSkeletonExtraBlockID = 20;
|
||||
static final byte kSkeletonBlockID = 21;
|
||||
|
||||
header_block_t m_headerData;
|
||||
skeletonExtra_block_t m_skeletonExtraData;
|
||||
skeleton_block_t m_skeletonData;
|
||||
boolean m_headerValid = false;
|
||||
boolean m_skeletonExtraValid = false;
|
||||
boolean m_skeletonValid = false;
|
||||
final Object m_headerDataSemaphore;
|
||||
final Object m_skeletonExtraDataSemaphore;
|
||||
final Object m_skeletonDataSemaphore;
|
||||
int m_recentPacketNumber = 0;
|
||||
|
||||
/**
|
||||
* Kinect constructor.
|
||||
*
|
||||
* This is only called once on the first call of getInstance()
|
||||
*/
|
||||
Kinect() {
|
||||
m_headerData = new header_block_t();
|
||||
m_skeletonExtraData = new skeletonExtra_block_t();
|
||||
m_skeletonData = new skeleton_block_t();
|
||||
m_headerDataSemaphore = new Object();
|
||||
m_skeletonExtraDataSemaphore = new Object();
|
||||
m_skeletonDataSemaphore = new Object();
|
||||
|
||||
UsageReporting.report(UsageReporting.kResourceType_Kinect, 0);
|
||||
}
|
||||
header_block_t tempHeaderData = new header_block_t();
|
||||
skeletonExtra_block_t tempSkeletonExtraData = new skeletonExtra_block_t();
|
||||
skeleton_block_t tempSkeletonData = new skeleton_block_t();
|
||||
|
||||
|
||||
/**
|
||||
* Called by the other Kinect functions to check for the latest data
|
||||
* This function will update the internal data structures
|
||||
* with the most recent Kinect input
|
||||
*/
|
||||
void updateData() {
|
||||
int retVal;
|
||||
|
||||
if (m_recentPacketNumber != DriverStation.getInstance().getPacketNumber()) {
|
||||
m_recentPacketNumber = DriverStation.getInstance().getPacketNumber();
|
||||
synchronized (m_headerDataSemaphore) {
|
||||
retVal = FRCControl.getDynamicControlData(kHeaderBlockID, tempHeaderData, tempHeaderData.size(), 5);
|
||||
if (retVal == 0) {
|
||||
tempHeaderData.copy(m_headerData);
|
||||
m_headerValid = true;
|
||||
} else {
|
||||
m_headerValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (m_skeletonExtraDataSemaphore) {
|
||||
retVal = FRCControl.getDynamicControlData(kSkeletonExtraBlockID, tempSkeletonExtraData, tempSkeletonExtraData.size(), 5);
|
||||
if (retVal == 0) {
|
||||
tempSkeletonExtraData.copy(m_skeletonExtraData);
|
||||
m_skeletonExtraValid = true;
|
||||
} else {
|
||||
m_skeletonExtraValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (m_skeletonDataSemaphore) {
|
||||
retVal = FRCControl.getDynamicControlData(kSkeletonBlockID, tempSkeletonData, tempSkeletonData.size(), 5);
|
||||
if (retVal == 0) {
|
||||
tempSkeletonData.copy(m_skeletonData);
|
||||
m_skeletonValid = true;
|
||||
} else {
|
||||
m_skeletonValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the number of players detected by the Kinect
|
||||
*
|
||||
* @return The current number of players
|
||||
*/
|
||||
public int getNumberOfPlayers() {
|
||||
updateData();
|
||||
if (!m_headerValid) {
|
||||
return 0;
|
||||
}
|
||||
synchronized (m_headerDataSemaphore) {
|
||||
return (int)m_headerData.data.players;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the FloorClipPlane from the Kinect device
|
||||
*
|
||||
* @return The FloorClipPlane
|
||||
*/
|
||||
public Point4 getFloorClipPlane() {
|
||||
updateData();
|
||||
Point4 tempClipPlane = new Point4();
|
||||
|
||||
if (!m_headerValid) {
|
||||
return tempClipPlane;
|
||||
}
|
||||
|
||||
synchronized(m_headerDataSemaphore) {
|
||||
tempClipPlane.x = m_headerData.data.floorClipPlane[0];
|
||||
tempClipPlane.y = m_headerData.data.floorClipPlane[1];
|
||||
tempClipPlane.z = m_headerData.data.floorClipPlane[2];
|
||||
tempClipPlane.w = m_headerData.data.floorClipPlane[3];
|
||||
}
|
||||
return tempClipPlane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the GravityNormal vector from the Kinect device
|
||||
* The w value returned from this method is always 0
|
||||
* @return The GravityNormal vector
|
||||
*/
|
||||
public Point4 getGravityNormal() {
|
||||
updateData();
|
||||
Point4 tempGravityNormal = new Point4();
|
||||
|
||||
if (!m_headerValid) {
|
||||
return tempGravityNormal;
|
||||
}
|
||||
|
||||
synchronized(m_headerDataSemaphore) {
|
||||
tempGravityNormal.x = m_headerData.data.gravityNormalVector[0];
|
||||
tempGravityNormal.y = m_headerData.data.gravityNormalVector[1];
|
||||
tempGravityNormal.z = m_headerData.data.gravityNormalVector[2];
|
||||
tempGravityNormal.w = 0;
|
||||
}
|
||||
return tempGravityNormal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the position of the detected skeleton
|
||||
* The w value returned from this method is always 1
|
||||
* @return The position of the skeleton
|
||||
*/
|
||||
public Point4 getPosition() {
|
||||
updateData();
|
||||
Point4 tempPosition = new Point4();
|
||||
|
||||
if (!m_skeletonExtraValid) {
|
||||
return tempPosition;
|
||||
}
|
||||
|
||||
synchronized(m_headerDataSemaphore) {
|
||||
tempPosition.x = m_skeletonExtraData.data.position[0];
|
||||
tempPosition.y = m_skeletonExtraData.data.position[1];
|
||||
tempPosition.z = m_skeletonExtraData.data.position[2];
|
||||
tempPosition.w = 1;
|
||||
}
|
||||
return tempPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the detected skeleton from the Kinect device
|
||||
*
|
||||
* @return The skeleton
|
||||
*/
|
||||
public Skeleton getSkeleton() {
|
||||
updateData();
|
||||
Skeleton tempSkeleton = new Skeleton();
|
||||
|
||||
if (!m_skeletonValid) {
|
||||
return tempSkeleton;
|
||||
}
|
||||
|
||||
synchronized (m_skeletonDataSemaphore) {
|
||||
for(int i=0; i<20; i++) {
|
||||
tempSkeleton.skeleton[i].x = m_skeletonData.data.vertices[i*3];
|
||||
tempSkeleton.skeleton[i].y = m_skeletonData.data.vertices[i*3+1];
|
||||
tempSkeleton.skeleton[i].z = m_skeletonData.data.vertices[i*3+2];
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (m_skeletonExtraDataSemaphore) {
|
||||
for(int i=0; i<20; i++) {
|
||||
tempSkeleton.skeleton[i].trackingState = m_skeletonExtraData.data.trackingState[i];
|
||||
}
|
||||
switch(m_skeletonExtraData.data.trackState) {
|
||||
case 0:
|
||||
tempSkeleton.trackState = Skeleton.tTrackState.kNotTracked;
|
||||
break;
|
||||
case 1:
|
||||
tempSkeleton.trackState = Skeleton.tTrackState.kPositionOnly;
|
||||
break;
|
||||
case 2:
|
||||
tempSkeleton.trackState = Skeleton.tTrackState.kTracked;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return tempSkeleton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 com.sun.jna.Pointer;
|
||||
import com.sun.jna.Structure;
|
||||
import edu.wpi.first.wpilibj.communication.FRCControl;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
|
||||
/**
|
||||
* @author bradmiller
|
||||
* Handles input from the Joystick data sent by the FRC Kinect Server
|
||||
* when used with a Kinect device connected to the Driver Station.
|
||||
* Each time a value is requested the most recent value is returned.
|
||||
* Default gestures embedded in the FRC Kinect Server are described
|
||||
* in the document Getting Started with Microsoft Kinect for FRC.
|
||||
*/
|
||||
public class KinectStick extends GenericHID {
|
||||
|
||||
private final static byte kJoystickDataID = 24;
|
||||
private final static byte kJoystickDataSize = 18;
|
||||
private int m_recentPacketNumber;
|
||||
|
||||
private int m_id;
|
||||
|
||||
static class JoystickDataBlock extends Structure {
|
||||
|
||||
byte joystick1[] = new byte[6];
|
||||
short button1;
|
||||
byte joystick2[] = new byte[6];
|
||||
short button2;
|
||||
|
||||
public static final int size = kJoystickDataSize - 2;
|
||||
|
||||
JoystickDataBlock(Pointer backingMemory) {
|
||||
useMemory(backingMemory);
|
||||
}
|
||||
|
||||
public void read() {
|
||||
backingNativeMemory.getBytes(0, joystick1, 0, 6);
|
||||
button1 = backingNativeMemory.getShort(6);
|
||||
backingNativeMemory.getBytes(8, joystick2, 0, 6);
|
||||
button2 = backingNativeMemory.getShort(14);
|
||||
}
|
||||
|
||||
public void write() {
|
||||
backingNativeMemory.setBytes(0, joystick1, 0, 6);
|
||||
backingNativeMemory.setShort(6, button1);
|
||||
backingNativeMemory.setBytes(8, joystick2, 0, 6);
|
||||
backingNativeMemory.setShort(14, button2);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
class JoystickData extends FRCControl.DynamicControlData {
|
||||
|
||||
JoystickDataBlock data;
|
||||
|
||||
{
|
||||
allocateMemory();
|
||||
data = new JoystickDataBlock(
|
||||
new Pointer(backingNativeMemory.address().toUWord().toPrimitive() + 2,
|
||||
JoystickDataBlock.size));
|
||||
}
|
||||
|
||||
public void read() {
|
||||
data.read();
|
||||
}
|
||||
|
||||
public void write() {
|
||||
data.write();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return kJoystickDataSize;
|
||||
}
|
||||
|
||||
public void copy(JoystickData dest) {
|
||||
write();
|
||||
Pointer.copyBytes(backingNativeMemory, 0, dest.backingNativeMemory, 0, size());
|
||||
dest.read();
|
||||
}
|
||||
}
|
||||
JoystickData tempOutputData = new JoystickData();
|
||||
|
||||
/**
|
||||
* Construct an instance of a KinectStick.
|
||||
* @param id which KinectStick to read, in the default gestures
|
||||
* an id of 1 corresponds to the left arm and 2 to the right arm.
|
||||
*/
|
||||
public KinectStick(int id) {
|
||||
m_id = id;
|
||||
|
||||
UsageReporting.report(UsageReporting.kResourceType_KinectStick, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the data in this class with the latest data from the
|
||||
* Driver Station.
|
||||
*/
|
||||
private void getData() {
|
||||
if (m_recentPacketNumber != DriverStation.getInstance().getPacketNumber()) {
|
||||
m_recentPacketNumber = DriverStation.getInstance().getPacketNumber();
|
||||
int retVal = FRCControl.getDynamicControlData(kJoystickDataID, tempOutputData, tempOutputData.size(), 5);
|
||||
if (retVal != 0) {
|
||||
System.err.println("Bad retval: " + retVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value from a byte to a double in the
|
||||
* -1 to 1 range
|
||||
* @param rawValue the value to convert
|
||||
* @return the normalized value
|
||||
*/
|
||||
private double normalize(byte rawValue) {
|
||||
if(rawValue >= 0)
|
||||
return rawValue / 127.0;
|
||||
else
|
||||
return rawValue / 128.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the X value of the KinectStick. This axis
|
||||
* is unimplemented in the default gestures but can
|
||||
* be populated by teams editing the Kinect Server.
|
||||
* See (@link Joystick for axis number mapping)
|
||||
* @param hand Unused
|
||||
* @return The X value of the KinectStick
|
||||
*/
|
||||
public double getX(Hand hand) {
|
||||
getData();
|
||||
return getRawAxis(Joystick.kDefaultXAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Y value of the KinectStick. This axis
|
||||
* represents arm angle in the default gestures
|
||||
* See (@link Joystick for axis number mapping)
|
||||
* @param hand Unused
|
||||
* @return The Y value of the KinectStick
|
||||
*/
|
||||
public double getY(Hand hand) {
|
||||
getData();
|
||||
return getRawAxis(Joystick.kDefaultYAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Z value of the KinectStick. This axis
|
||||
* is unimplemented in the default gestures but can
|
||||
* be populated by teams editing the Kinect Server.
|
||||
* See (@link Joystick for axis number mapping)
|
||||
* @param hand Unused
|
||||
* @return The Z value of the KinectStick
|
||||
*/
|
||||
public double getZ(Hand hand) {
|
||||
getData();
|
||||
return getRawAxis(Joystick.kDefaultZAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Twist value of the KinectStick. This axis
|
||||
* is unimplemented in the default gestures but can
|
||||
* be populated by teams editing the Kinect Server.
|
||||
* See (@link Joystick for axis number mapping)
|
||||
* @return The Twist value of the KinectStick
|
||||
*/
|
||||
public double getTwist() {
|
||||
getData();
|
||||
return getRawAxis(Joystick.kDefaultTwistAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Throttle value of the KinectStick. This axis
|
||||
* is unimplemented in the default gestures but can
|
||||
* be populated by teams editing the Kinect Server.
|
||||
* See (@link Joystick for axis number mapping)
|
||||
* @return The Throttle value of the KinectStick
|
||||
*/
|
||||
public double getThrottle() {
|
||||
getData();
|
||||
return getRawAxis(Joystick.kDefaultThrottleAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the KinectStick axis.
|
||||
*
|
||||
* @param axis The axis to read [1-6].
|
||||
* @return The value of the axis
|
||||
*/
|
||||
public double getRawAxis(int axis) {
|
||||
if (axis < 1 || axis > DriverStation.kJoystickAxes)
|
||||
return 0.0;
|
||||
|
||||
getData();
|
||||
if (m_id == 1) {
|
||||
return normalize(tempOutputData.data.joystick1[axis-1]);
|
||||
} else {
|
||||
return normalize(tempOutputData.data.joystick2[axis-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the button value for the button set as the default trigger in
|
||||
* (@link Joystick)
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getTrigger(Hand hand) {
|
||||
getData();
|
||||
return (tempOutputData.data.button1 & (short) Joystick.kDefaultTriggerButton) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the button value for the button set as the default top in
|
||||
* (@link Joystick)
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getTop(Hand hand) {
|
||||
getData();
|
||||
return (tempOutputData.data.button1 & (short) Joystick.kDefaultTopButton) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the button value for the button set as the default bumper in
|
||||
* (@link Joystick)
|
||||
*
|
||||
* @param hand Unused
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getBumper(Hand hand) {
|
||||
getData();
|
||||
return (tempOutputData.data.button1 & (short) 4) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the button value for buttons 1 through 12. The default gestures
|
||||
* implement only 9 buttons.
|
||||
*
|
||||
* The appropriate button is returned as a boolean value.
|
||||
*
|
||||
* @param button The button number to be read.
|
||||
* @return The state of the button.
|
||||
*/
|
||||
public boolean getRawButton(int button) {
|
||||
getData();
|
||||
return (tempOutputData.data.button1 & (short) (1 << (button - 1))) != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tModuleType;
|
||||
|
||||
/**
|
||||
* Base class for AnalogModule and DigitalModule.
|
||||
*
|
||||
* @author dtjones
|
||||
*/
|
||||
public class Module extends SensorBase {
|
||||
|
||||
/**
|
||||
* An array holding the object representing each module
|
||||
*/
|
||||
protected static Module[] m_modules = new Module[tModuleType.kModuleType_Solenoid * FRC_NetworkCommunicationsLibrary.kMaxModuleNumber + (FRC_NetworkCommunicationsLibrary.kMaxModuleNumber - 1)];
|
||||
/**
|
||||
* The module number of the module
|
||||
*/
|
||||
protected int m_moduleNumber;
|
||||
protected int m_moduleType;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moduleNumber The number of this module (1 or 2).
|
||||
*/
|
||||
protected Module(int moduleType, final int moduleNumber) {
|
||||
m_modules[toIndex(moduleType, moduleNumber)] = this;
|
||||
m_moduleNumber = moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module number associated with a module.
|
||||
*
|
||||
* @return The module's number.
|
||||
*/
|
||||
public int getModuleNumber() {
|
||||
return m_moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module type associated with a module.
|
||||
*
|
||||
* @return The module's type.
|
||||
*/
|
||||
public int getModuleType() {
|
||||
return m_moduleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static module singleton factory.
|
||||
*
|
||||
* @param moduleType The type of the module represented.
|
||||
* @param moduleNumber The module index within the module type.
|
||||
* @return the module
|
||||
*/
|
||||
public static Module getModule(int moduleType, int moduleNumber) {
|
||||
if(m_modules[toIndex(moduleType, moduleNumber)] == null) {
|
||||
if(moduleType == tModuleType.kModuleType_Analog) {
|
||||
new AnalogModule(moduleNumber);
|
||||
} else if (moduleType == tModuleType.kModuleType_Digital) {
|
||||
new DigitalModule(moduleNumber);
|
||||
/* } else if (moduleType.equals(ModulePresence.ModuleType.kSolenoid)) {
|
||||
new Sol
|
||||
*/
|
||||
} else {
|
||||
throw new RuntimeException("A module of type "+moduleType+" with module index "+moduleNumber);
|
||||
}
|
||||
}
|
||||
return m_modules[toIndex(moduleType, moduleNumber)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an index into m_modules based on type and number
|
||||
*
|
||||
* @param moduleType The type of the module represented.
|
||||
* @param moduleNumber The module index within the module type.
|
||||
* @return The index into m_modules.
|
||||
*/
|
||||
private static int toIndex(int moduleType, int moduleNumber) {
|
||||
if(moduleNumber == 0 || moduleNumber > FRC_NetworkCommunicationsLibrary.kMaxModuleNumber)
|
||||
return 0;
|
||||
return moduleType * FRC_NetworkCommunicationsLibrary.kMaxModuleNumber + (moduleNumber - 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 brad
|
||||
*/
|
||||
public interface MotorSafety {
|
||||
public static final double DEFAULT_SAFETY_EXPIRATION = 0.1;
|
||||
void setExpiration(double timeout);
|
||||
double getExpiration();
|
||||
boolean isAlive();
|
||||
void stopMotor();
|
||||
void setSafetyEnabled(boolean enabled);
|
||||
boolean isSafetyEnabled();
|
||||
String getDescription();
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* The MotorSafetyHelper object is constructed for every object that wants to implement the Motor
|
||||
* Safety protocol. The helper object has the code to actually do the timing and call the
|
||||
* motors Stop() method when the timeout expires. The motor object is expected to call the
|
||||
* Feed() method whenever the motors value is updated.
|
||||
*
|
||||
* @author brad
|
||||
*/
|
||||
public class MotorSafetyHelper {
|
||||
|
||||
double m_expiration;
|
||||
boolean m_enabled;
|
||||
double m_stopTime;
|
||||
MotorSafety m_safeObject;
|
||||
MotorSafetyHelper m_nextHelper;
|
||||
static MotorSafetyHelper m_headHelper = null;
|
||||
|
||||
/**
|
||||
* The constructor for a MotorSafetyHelper object.
|
||||
* The helper object is constructed for every object that wants to implement the Motor
|
||||
* Safety protocol. The helper object has the code to actually do the timing and call the
|
||||
* motors Stop() method when the timeout expires. The motor object is expected to call the
|
||||
* Feed() method whenever the motors value is updated.
|
||||
*
|
||||
* @param safeObject a pointer to the motor object implementing MotorSafety. This is used
|
||||
* to call the Stop() method on the motor.
|
||||
*/
|
||||
public MotorSafetyHelper(MotorSafety safeObject) {
|
||||
m_safeObject = safeObject;
|
||||
m_enabled = false;
|
||||
m_expiration = MotorSafety.DEFAULT_SAFETY_EXPIRATION;
|
||||
m_stopTime = Timer.getFPGATimestamp();
|
||||
m_nextHelper = m_headHelper;
|
||||
m_headHelper = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed the motor safety object.
|
||||
* Resets the timer on this object that is used to do the timeouts.
|
||||
*/
|
||||
public void feed() {
|
||||
m_stopTime = Timer.getFPGATimestamp() + m_expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expiration time for the corresponding motor safety object.
|
||||
* @param expirationTime The timeout value in seconds.
|
||||
*/
|
||||
public void setExpiration(double expirationTime) {
|
||||
m_expiration = expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the timeout value for the corresponding motor safety object.
|
||||
* @return the timeout value in seconds.
|
||||
*/
|
||||
public double getExpiration() {
|
||||
return m_expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine of the motor is still operating or has timed out.
|
||||
* @return a true value if the motor is still operating normally and hasn't timed out.
|
||||
*/
|
||||
public boolean isAlive() {
|
||||
return !m_enabled || m_stopTime > Timer.getFPGATimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this motor has exceeded its timeout.
|
||||
* This method is called periodically to determine if this motor has exceeded its timeout
|
||||
* value. If it has, the stop method is called, and the motor is shut down until its value is
|
||||
* updated again.
|
||||
*/
|
||||
public void check() {
|
||||
DriverStation ds = DriverStation.getInstance();
|
||||
if (!m_enabled || ds.isDisabled() || ds.isTest())
|
||||
return;
|
||||
if (m_stopTime < Timer.getFPGATimestamp()) {
|
||||
System.err.println(m_safeObject.getDescription() + "... Output not updated often enough.");
|
||||
|
||||
m_safeObject.stopMotor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/disable motor safety for this device
|
||||
* Turn on and off the motor safety option for this PWM object.
|
||||
* @param enabled True if motor safety is enforced for this object
|
||||
*/
|
||||
public void setSafetyEnabled(boolean enabled) {
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the state of the motor safety enabled flag
|
||||
* Return if the motor safety is currently enabled for this devicce.
|
||||
* @return True if motor safety is enforced for this device
|
||||
*/
|
||||
public boolean isSafetyEnabled() {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the motors to see if any have timed out.
|
||||
* This static method is called periodically to poll all the motors and stop any that have
|
||||
* timed out.
|
||||
*/
|
||||
//TODO: these should be synchronized with the setting methods in case it's called from a different thread
|
||||
public static void checkMotors() {
|
||||
for (MotorSafetyHelper msh = m_headHelper; msh != null; msh = msh.m_nextHelper) {
|
||||
msh.check();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
|
||||
/**
|
||||
* The interface for sendable objects that gives the sendable a default name in the Smart Dashboard
|
||||
*
|
||||
*/
|
||||
public interface NamedSendable extends Sendable {
|
||||
|
||||
/**
|
||||
* @return the name of the subtable of SmartDashboard that the Sendable object will use
|
||||
*/
|
||||
public String getName();
|
||||
}
|
||||
@@ -0,0 +1,591 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.util.TimerTask;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.IUtility;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
/**
|
||||
* Class implements a PID Control Loop.
|
||||
*
|
||||
* Creates a separate thread which reads the given PIDSource and takes
|
||||
* care of the integral calculations, as well as writing the given
|
||||
* PIDOutput
|
||||
*/
|
||||
public class PIDController implements IUtility, LiveWindowSendable, Controller {
|
||||
|
||||
public static final double kDefaultPeriod = .05;
|
||||
private static int instances = 0;
|
||||
private double m_P; // factor for "proportional" control
|
||||
private double m_I; // factor for "integral" control
|
||||
private double m_D; // factor for "derivative" control
|
||||
private double m_F; // factor for feedforward term
|
||||
private double m_maximumOutput = 1.0; // |maximum output|
|
||||
private double m_minimumOutput = -1.0; // |minimum output|
|
||||
private double m_maximumInput = 0.0; // maximum input - limit setpoint to this
|
||||
private double m_minimumInput = 0.0; // minimum input - limit setpoint to this
|
||||
private boolean m_continuous = false; // do the endpoints wrap around? eg. Absolute encoder
|
||||
private boolean m_enabled = false; //is the pid controller enabled
|
||||
private double m_prevError = 0.0; // the prior sensor input (used to compute velocity)
|
||||
private double m_totalError = 0.0; //the sum of the errors for use in the integral calc
|
||||
private Tolerance m_tolerance; //the tolerance object used to check if on target
|
||||
private double m_setpoint = 0.0;
|
||||
private double m_error = 0.0;
|
||||
private double m_result = 0.0;
|
||||
private double m_period = kDefaultPeriod;
|
||||
PIDSource m_pidInput;
|
||||
PIDOutput m_pidOutput;
|
||||
java.util.Timer m_controlLoop;
|
||||
private boolean m_usingPercentTolerance;
|
||||
|
||||
/**
|
||||
* Tolerance is the type of tolerance used to specify if the PID controller is on target.
|
||||
* The various implementations of this class such as PercentageTolerance and AbsoluteTolerance
|
||||
* specify types of tolerance specifications to use.
|
||||
*/
|
||||
public interface Tolerance {
|
||||
public boolean onTarget();
|
||||
}
|
||||
|
||||
public class PercentageTolerance implements Tolerance {
|
||||
double percentage;
|
||||
|
||||
PercentageTolerance(double value) {
|
||||
percentage = value;
|
||||
}
|
||||
|
||||
public boolean onTarget() {
|
||||
return (Math.abs(getError()) < percentage / 100
|
||||
* (m_maximumInput - m_minimumInput));
|
||||
}
|
||||
}
|
||||
|
||||
public class AbsoluteTolerance implements Tolerance {
|
||||
double value;
|
||||
|
||||
AbsoluteTolerance(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean onTarget() {
|
||||
return Math.abs(getError()) < value;
|
||||
}
|
||||
}
|
||||
|
||||
public class NullTolerance implements Tolerance {
|
||||
|
||||
public boolean onTarget() {
|
||||
throw new RuntimeException("No tolerance value set when using PIDController.onTarget()");
|
||||
}
|
||||
}
|
||||
|
||||
private class PIDTask extends TimerTask {
|
||||
|
||||
private PIDController m_controller;
|
||||
|
||||
public PIDTask(PIDController controller) {
|
||||
if (controller == null) {
|
||||
throw new NullPointerException("Given PIDController was null");
|
||||
}
|
||||
m_controller = controller;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
m_controller.calculate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PID object with the given constants for P, I, D, and F
|
||||
* @param Kp the proportional coefficient
|
||||
* @param Ki the integral coefficient
|
||||
* @param Kd the derivative coefficient
|
||||
* @param Kf the feed forward term
|
||||
* @param source The PIDSource object that is used to get values
|
||||
* @param output The PIDOutput object that is set to the output percentage
|
||||
* @param period the loop time for doing calculations. This particularly effects calculations of the
|
||||
* integral and differential terms. The default is 50ms.
|
||||
*/
|
||||
public PIDController(double Kp, double Ki, double Kd, double Kf,
|
||||
PIDSource source, PIDOutput output,
|
||||
double period) {
|
||||
|
||||
if (source == null) {
|
||||
throw new NullPointerException("Null PIDSource was given");
|
||||
}
|
||||
if (output == null) {
|
||||
throw new NullPointerException("Null PIDOutput was given");
|
||||
}
|
||||
|
||||
m_controlLoop = new java.util.Timer();
|
||||
|
||||
|
||||
m_P = Kp;
|
||||
m_I = Ki;
|
||||
m_D = Kd;
|
||||
m_F = Kf;
|
||||
|
||||
m_pidInput = source;
|
||||
m_pidOutput = output;
|
||||
m_period = period;
|
||||
|
||||
m_controlLoop.schedule(new PIDTask(this), 0L, (long) (m_period * 1000));
|
||||
|
||||
instances++;
|
||||
UsageReporting.report(tResourceType.kResourceType_PIDController, instances);
|
||||
m_tolerance = new NullTolerance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PID object with the given constants for P, I, D and period
|
||||
* @param Kp
|
||||
* @param Ki
|
||||
* @param Kd
|
||||
* @param source
|
||||
* @param output
|
||||
* @param period
|
||||
*/
|
||||
public PIDController(double Kp, double Ki, double Kd,
|
||||
PIDSource source, PIDOutput output,
|
||||
double period) {
|
||||
this(Kp, Ki, Kd, 0.0, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PID object with the given constants for P, I, D, using a 50ms period.
|
||||
* @param Kp the proportional coefficient
|
||||
* @param Ki the integral coefficient
|
||||
* @param Kd the derivative coefficient
|
||||
* @param source The PIDSource object that is used to get values
|
||||
* @param output The PIDOutput object that is set to the output percentage
|
||||
*/
|
||||
public PIDController(double Kp, double Ki, double Kd,
|
||||
PIDSource source, PIDOutput output) {
|
||||
this(Kp, Ki, Kd, source, output, kDefaultPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PID object with the given constants for P, I, D, using a 50ms period.
|
||||
* @param Kp the proportional coefficient
|
||||
* @param Ki the integral coefficient
|
||||
* @param Kd the derivative coefficient
|
||||
* @param source The PIDSource object that is used to get values
|
||||
* @param output The PIDOutput object that is set to the output percentage
|
||||
*/
|
||||
public PIDController(double Kp, double Ki, double Kd, double Kf,
|
||||
PIDSource source, PIDOutput output) {
|
||||
this(Kp, Ki, Kd, Kf, source, output, kDefaultPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the PID object
|
||||
*/
|
||||
public void free() {
|
||||
m_controlLoop.cancel();
|
||||
m_controlLoop = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the input, calculate the output accordingly, and write to the output.
|
||||
* This should only be called by the PIDTask
|
||||
* and is created during initialization.
|
||||
*/
|
||||
protected void calculate() {
|
||||
boolean enabled;
|
||||
PIDSource pidInput;
|
||||
|
||||
synchronized (this) {
|
||||
if (m_pidInput == null) {
|
||||
return;
|
||||
}
|
||||
if (m_pidOutput == null) {
|
||||
return;
|
||||
}
|
||||
enabled = m_enabled; // take snapshot of these values...
|
||||
pidInput = m_pidInput;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
double input = pidInput.pidGet();
|
||||
double result;
|
||||
PIDOutput pidOutput = null;
|
||||
|
||||
synchronized (this) {
|
||||
m_error = m_setpoint - input;
|
||||
if (m_continuous) {
|
||||
if (Math.abs(m_error)
|
||||
> (m_maximumInput - m_minimumInput) / 2) {
|
||||
if (m_error > 0) {
|
||||
m_error = m_error - m_maximumInput + m_minimumInput;
|
||||
} else {
|
||||
m_error = m_error
|
||||
+ m_maximumInput - m_minimumInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_I != 0) {
|
||||
double potentialIGain = (m_totalError + m_error) * m_I;
|
||||
if (potentialIGain < m_maximumOutput) {
|
||||
if (potentialIGain > m_minimumOutput) {
|
||||
m_totalError += m_error;
|
||||
} else {
|
||||
m_totalError = m_minimumOutput / m_I;
|
||||
}
|
||||
} else {
|
||||
m_totalError = m_maximumOutput / m_I;
|
||||
}
|
||||
}
|
||||
|
||||
m_result = m_P * m_error + m_I * m_totalError + m_D * (m_error - m_prevError) + m_setpoint * m_F;
|
||||
m_prevError = m_error;
|
||||
|
||||
if (m_result > m_maximumOutput) {
|
||||
m_result = m_maximumOutput;
|
||||
} else if (m_result < m_minimumOutput) {
|
||||
m_result = m_minimumOutput;
|
||||
}
|
||||
pidOutput = m_pidOutput;
|
||||
result = m_result;
|
||||
}
|
||||
|
||||
pidOutput.pidWrite(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PID Controller gain parameters.
|
||||
* Set the proportional, integral, and differential coefficients.
|
||||
* @param p Proportional coefficient
|
||||
* @param i Integral coefficient
|
||||
* @param d Differential coefficient
|
||||
*/
|
||||
public synchronized void setPID(double p, double i, double d) {
|
||||
m_P = p;
|
||||
m_I = i;
|
||||
m_D = d;
|
||||
|
||||
if (table != null) {
|
||||
table.putNumber("p", p);
|
||||
table.putNumber("i", i);
|
||||
table.putNumber("d", d);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PID Controller gain parameters.
|
||||
* Set the proportional, integral, and differential coefficients.
|
||||
* @param p Proportional coefficient
|
||||
* @param i Integral coefficient
|
||||
* @param d Differential coefficient
|
||||
* @param f Feed forward coefficient
|
||||
*/
|
||||
public synchronized void setPID(double p, double i, double d, double f) {
|
||||
m_P = p;
|
||||
m_I = i;
|
||||
m_D = d;
|
||||
m_F = f;
|
||||
|
||||
if (table != null) {
|
||||
table.putNumber("p", p);
|
||||
table.putNumber("i", i);
|
||||
table.putNumber("d", d);
|
||||
table.putNumber("f", f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Proportional coefficient
|
||||
* @return proportional coefficient
|
||||
*/
|
||||
public double getP() {
|
||||
return m_P;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Integral coefficient
|
||||
* @return integral coefficient
|
||||
*/
|
||||
public double getI() {
|
||||
return m_I;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Differential coefficient
|
||||
* @return differential coefficient
|
||||
*/
|
||||
public synchronized double getD() {
|
||||
return m_D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Feed forward coefficient
|
||||
* @return feed forward coefficient
|
||||
*/
|
||||
public synchronized double getF() {
|
||||
return m_F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current PID result
|
||||
* This is always centered on zero and constrained the the max and min outs
|
||||
* @return the latest calculated output
|
||||
*/
|
||||
public synchronized double get() {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PID controller to consider the input to be continuous,
|
||||
* Rather then using the max and min in as constraints, it considers them to
|
||||
* be the same point and automatically calculates the shortest route to
|
||||
* the setpoint.
|
||||
* @param continuous Set to true turns on continuous, false turns off continuous
|
||||
*/
|
||||
public synchronized void setContinuous(boolean continuous) {
|
||||
m_continuous = continuous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PID controller to consider the input to be continuous,
|
||||
* Rather then using the max and min in as constraints, it considers them to
|
||||
* be the same point and automatically calculates the shortest route to
|
||||
* the setpoint.
|
||||
*/
|
||||
public synchronized void setContinuous() {
|
||||
this.setContinuous(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum and minimum values expected from the input.
|
||||
*
|
||||
* @param minimumInput the minimum percentage expected from the input
|
||||
* @param maximumInput the maximum percentage expected from the output
|
||||
*/
|
||||
public synchronized void setInputRange(double minimumInput, double maximumInput) {
|
||||
if (minimumInput > maximumInput) {
|
||||
throw new BoundaryException("Lower bound is greater than upper bound");
|
||||
}
|
||||
m_minimumInput = minimumInput;
|
||||
m_maximumInput = maximumInput;
|
||||
setSetpoint(m_setpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum and maximum values to write.
|
||||
*
|
||||
* @param minimumOutput the minimum percentage to write to the output
|
||||
* @param maximumOutput the maximum percentage to write to the output
|
||||
*/
|
||||
public synchronized void setOutputRange(double minimumOutput, double maximumOutput) {
|
||||
if (minimumOutput > maximumOutput) {
|
||||
throw new BoundaryException("Lower bound is greater than upper bound");
|
||||
}
|
||||
m_minimumOutput = minimumOutput;
|
||||
m_maximumOutput = maximumOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the setpoint for the PIDController
|
||||
* @param setpoint the desired setpoint
|
||||
*/
|
||||
public synchronized void setSetpoint(double setpoint) {
|
||||
if (m_maximumInput > m_minimumInput) {
|
||||
if (setpoint > m_maximumInput) {
|
||||
m_setpoint = m_maximumInput;
|
||||
} else if (setpoint < m_minimumInput) {
|
||||
m_setpoint = m_minimumInput;
|
||||
} else {
|
||||
m_setpoint = setpoint;
|
||||
}
|
||||
} else {
|
||||
m_setpoint = setpoint;
|
||||
}
|
||||
|
||||
if (table != null)
|
||||
table.putNumber("setpoint", m_setpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current setpoint of the PIDController
|
||||
* @return the current setpoint
|
||||
*/
|
||||
public synchronized double getSetpoint() {
|
||||
return m_setpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current difference of the input from the setpoint
|
||||
* @return the current error
|
||||
*/
|
||||
public synchronized double getError() {
|
||||
//return m_error;
|
||||
return getSetpoint() - m_pidInput.pidGet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the percentage error which is considered tolerable for use with
|
||||
* OnTarget. (Input of 15.0 = 15 percent)
|
||||
* @param percent error which is tolerable
|
||||
* @deprecated Use setTolerance(Tolerance), i.e. setTolerance(new PIDController.PercentageTolerance(15))
|
||||
*/
|
||||
public synchronized void setTolerance(double percent) {
|
||||
m_tolerance = new PercentageTolerance(percent);
|
||||
}
|
||||
|
||||
/** Set the PID tolerance using a Tolerance object.
|
||||
* Tolerance can be specified as a percentage of the range or as an absolute
|
||||
* value. The Tolerance object encapsulates those options in an object. Use it by
|
||||
* creating the type of tolerance that you want to use: setTolerance(new PIDController.AbsoluteTolerance(0.1))
|
||||
* @param tolerance a tolerance object of the right type, e.g. PercentTolerance
|
||||
* or AbsoluteTolerance
|
||||
*/
|
||||
private void setTolerance(Tolerance tolerance) {
|
||||
m_tolerance = tolerance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute error which is considered tolerable for use with
|
||||
* OnTarget.
|
||||
* @param absolute error which is tolerable in the units of the input object
|
||||
*/
|
||||
public synchronized void setAbsoluteTolerance(double absvalue) {
|
||||
m_tolerance = new AbsoluteTolerance(absvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the percentage error which is considered tolerable for use with
|
||||
* OnTarget. (Input of 15.0 = 15 percent)
|
||||
* @param percent error which is tolerable
|
||||
*/
|
||||
public synchronized void setPercentTolerance(double percentage) {
|
||||
m_tolerance = new PercentageTolerance(percentage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the error is within the percentage of the total input range,
|
||||
* determined by setTolerance. This assumes that the maximum and minimum input
|
||||
* were set using setInput.
|
||||
* @return true if the error is less than the tolerance
|
||||
*/
|
||||
public synchronized boolean onTarget() {
|
||||
return m_tolerance.onTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin running the PIDController
|
||||
*/
|
||||
public synchronized void enable() {
|
||||
m_enabled = true;
|
||||
|
||||
if (table != null) {
|
||||
table.putBoolean("enabled", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop running the PIDController, this sets the output to zero before stopping.
|
||||
*/
|
||||
public synchronized void disable() {
|
||||
m_pidOutput.pidWrite(0);
|
||||
m_enabled = false;
|
||||
|
||||
if (table != null) {
|
||||
table.putBoolean("enabled", false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if PIDController is enabled.
|
||||
*/
|
||||
public synchronized boolean isEnable() {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the previous error,, the integral term, and disable the controller.
|
||||
*/
|
||||
public synchronized void reset() {
|
||||
disable();
|
||||
m_prevError = 0;
|
||||
m_totalError = 0;
|
||||
m_result = 0;
|
||||
}
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "PIDController";
|
||||
}
|
||||
|
||||
private ITableListener listener = new ITableListener() {
|
||||
public void valueChanged(ITable table, String key, Object value, boolean isNew) {
|
||||
if (key.equals("p") || key.equals("i") || key.equals("d") || key.equals("f")) {
|
||||
if (m_P != table.getNumber("p", 0.0) || m_I != table.getNumber("i", 0.0) ||
|
||||
m_D != table.getNumber("d", 0.0) || m_F != table.getNumber("f", 0.0))
|
||||
setPID(table.getNumber("p", 0.0), table.getNumber("i", 0.0), table.getNumber("d", 0.0), table.getNumber("f", 0.0));
|
||||
} else if (key.equals("setpoint")) {
|
||||
if (m_setpoint != ((Double) value).doubleValue())
|
||||
setSetpoint(((Double) value).doubleValue());
|
||||
} else if (key.equals("enabled")) {
|
||||
if (m_enabled != ((Boolean) value).booleanValue()) {
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
enable();
|
||||
} else {
|
||||
disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private ITable table;
|
||||
public void initTable(ITable table) {
|
||||
if(this.table!=null)
|
||||
this.table.removeTableListener(listener);
|
||||
this.table = table;
|
||||
if(table!=null) {
|
||||
table.putNumber("p", getP());
|
||||
table.putNumber("i", getI());
|
||||
table.putNumber("d", getD());
|
||||
table.putNumber("f", getF());
|
||||
table.putNumber("setpoint", getSetpoint());
|
||||
table.putBoolean("enabled", isEnable());
|
||||
table.addTableListener(listener, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* This interface allows PIDController to write it's results to its output.
|
||||
* @author dtjones
|
||||
*/
|
||||
public interface PIDOutput {
|
||||
|
||||
/**
|
||||
* Set the output to the value calculated by PIDController
|
||||
* @param output the value calculated by PIDController
|
||||
*/
|
||||
public void pidWrite(double output);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* This interface allows for PIDController to automatically read from this
|
||||
* object
|
||||
* @author dtjones
|
||||
*/
|
||||
public interface PIDSource {
|
||||
|
||||
/**
|
||||
* A description for the type of output value to provide to a PIDController
|
||||
*/
|
||||
public static class PIDSourceParameter {
|
||||
public final int value;
|
||||
static final int kDistance_val = 0;
|
||||
static final int kRate_val = 1;
|
||||
static final int kAngle_val = 2;
|
||||
public static final PIDSourceParameter kDistance = new PIDSourceParameter(kDistance_val);
|
||||
public static final PIDSourceParameter kRate = new PIDSourceParameter(kRate_val);
|
||||
public static final PIDSourceParameter kAngle = new PIDSourceParameter(kAngle_val);
|
||||
|
||||
private PIDSourceParameter(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result to use in PIDController
|
||||
* @return the result to use in PIDController
|
||||
*/
|
||||
public double pidGet();
|
||||
}
|
||||
481
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/PWM.java
Normal file
481
wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/PWM.java
Normal file
@@ -0,0 +1,481 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Class implements the PWM generation in the FPGA.
|
||||
* Values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped
|
||||
* to the hardware dependent values, in this case 0-255 for the FPGA.
|
||||
* Changes are immediately sent to the FPGA, and the update occurs at the next
|
||||
* FPGA cycle. There is no delay.
|
||||
*
|
||||
* As of revision 0.1.4 of the FPGA, the FPGA interprets the 0-255 values as follows:
|
||||
* 255 = full "forward"
|
||||
* 254 to 129 = linear scaling from "full forward" to "center"
|
||||
* 128 = center value
|
||||
* 127 to 2 = linear scaling from "center" to "full reverse"
|
||||
* 1 = full "reverse"
|
||||
* 0 = disabled (i.e. PWM output is held low)
|
||||
*/
|
||||
public class PWM extends SensorBase implements LiveWindowSendable {
|
||||
|
||||
/*
|
||||
* XXX: Refactor to no longer depend on the DigitalModule, and move all
|
||||
* resource tracking into the HAL. This will wait until we get the unit
|
||||
* tests running for the first time.
|
||||
*/
|
||||
|
||||
private static Resource allocated = new Resource((HALLibrary.dio_kNumSystems.get() * kPwmChannels));
|
||||
|
||||
/**
|
||||
* Represents the amount to multiply the minimum servo-pulse pwm period by.
|
||||
*/
|
||||
public static class PeriodMultiplier {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int k1X_val = 1;
|
||||
static final int k2X_val = 2;
|
||||
static final int k4X_val = 4;
|
||||
/**
|
||||
* Period Multiplier: don't skip pulses
|
||||
*/
|
||||
public static final PeriodMultiplier k1X = new PeriodMultiplier(k1X_val);
|
||||
/**
|
||||
* Period Multiplier: skip every other pulse
|
||||
*/
|
||||
public static final PeriodMultiplier k2X = new PeriodMultiplier(k2X_val);
|
||||
/**
|
||||
* Period Multiplier: skip three out of four pulses
|
||||
*/
|
||||
public static final PeriodMultiplier k4X = new PeriodMultiplier(k4X_val);
|
||||
|
||||
private PeriodMultiplier(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
private int m_channel;
|
||||
private DigitalModule m_module;
|
||||
/**
|
||||
* kDefaultPwmPeriod is in ms
|
||||
*
|
||||
* - 20ms periods (50 Hz) are the "safest" setting in that this works for all devices
|
||||
* - 20ms periods seem to be desirable for Vex Motors
|
||||
* - 20ms periods are the specified period for HS-322HD servos, but work reliably down
|
||||
* to 10.0 ms; starting at about 8.5ms, the servo sometimes hums and get hot;
|
||||
* by 5.0ms the hum is nearly continuous
|
||||
* - 10ms periods work well for Victor 884
|
||||
* - 5ms periods allows higher update rates for Luminary Micro Jaguar speed controllers.
|
||||
* Due to the shipping firmware on the Jaguar, we can't run the update period less
|
||||
* than 5.05 ms.
|
||||
*
|
||||
* kDefaultPwmPeriod is the 1x period (5.05 ms). In hardware, the period scaling is implemented as an
|
||||
* output squelch to get longer periods for old devices.
|
||||
*/
|
||||
protected static final double kDefaultPwmPeriod = 5.05;
|
||||
/**
|
||||
* kDefaultPwmCenter is the PWM range center in ms
|
||||
*/
|
||||
protected static final double kDefaultPwmCenter = 1.5;
|
||||
/**
|
||||
* kDefaultPWMStepsDown is the number of PWM steps below the centerpoint
|
||||
*/
|
||||
protected static final int kDefaultPwmStepsDown = 1000;
|
||||
public static final int kPwmDisabled = 0;
|
||||
boolean m_eliminateDeadband;
|
||||
int m_maxPwm;
|
||||
int m_deadbandMaxPwm;
|
||||
int m_centerPwm;
|
||||
int m_deadbandMinPwm;
|
||||
int m_minPwm;
|
||||
|
||||
/**
|
||||
* Initialize PWMs given an module and channel.
|
||||
*
|
||||
* This method is private and is the common path for all the constructors for creating PWM
|
||||
* instances. Checks module and channel value ranges and allocates the appropriate channel.
|
||||
* The allocation is only done to help users ensure that they don't double assign channels.
|
||||
*/
|
||||
private void initPWM(final int moduleNumber, final int channel) {
|
||||
checkPWMModule(moduleNumber);
|
||||
checkPWMChannel(channel);
|
||||
try {
|
||||
allocated.allocate((moduleNumber - 1) * kPwmChannels + channel - 1);
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"PWM channel " + channel + " on module " + moduleNumber + " is already allocated");
|
||||
}
|
||||
m_channel = channel;
|
||||
m_module = DigitalModule.getInstance(moduleNumber);
|
||||
m_module.setPWM(m_channel, kPwmDisabled);
|
||||
m_eliminateDeadband = false;
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_PWM, channel, moduleNumber-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PWM given a module and channel.
|
||||
* Allocate a PWM using a module and channel number.
|
||||
*
|
||||
* @param moduleNumber The module number of the digital module to use.
|
||||
* @param channel The PWM channel on the digital module.
|
||||
*/
|
||||
public PWM(final int moduleNumber, final int channel) {
|
||||
initPWM(moduleNumber, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a PWM in the default module given a channel.
|
||||
*
|
||||
* Using a default module allocate a PWM given the channel number.
|
||||
*
|
||||
* @param channel The PWM channel on the digital module.
|
||||
*/
|
||||
public PWM(final int channel) {
|
||||
initPWM(getDefaultDigitalModule(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the PWM channel.
|
||||
*
|
||||
* Free the resource associated with the PWM channel and set the value to 0.
|
||||
*/
|
||||
public void free() {
|
||||
m_module.setPWM(m_channel, kPwmDisabled);
|
||||
m_module.freeDIO(m_channel);
|
||||
allocated.free((m_module.getModuleNumber() - 1) * kPwmChannels + m_channel - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally eliminate the deadband from a speed controller.
|
||||
* @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate
|
||||
* the deadband in the middle of the range. Otherwise, keep the full range without
|
||||
* modifying any values.
|
||||
*/
|
||||
public void enableDeadbandElimination(boolean eliminateDeadband) {
|
||||
m_eliminateDeadband = eliminateDeadband;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds on the PWM values.
|
||||
* This sets the bounds on the PWM values for a particular each type of controller. The values
|
||||
* determine the upper and lower speeds as well as the deadband bracket.
|
||||
* @deprecated Recommended to set bounds in ms using {@link #setBounds(double, double, double, double, double)}
|
||||
* @param max The Minimum pwm value
|
||||
* @param deadbandMax The high end of the deadband range
|
||||
* @param center The center speed (off)
|
||||
* @param deadbandMin The low end of the deadband range
|
||||
* @param min The minimum pwm value
|
||||
*/
|
||||
public void setBounds(final int max, final int deadbandMax, final int center, final int deadbandMin, final int min) {
|
||||
m_maxPwm = max;
|
||||
m_deadbandMaxPwm = deadbandMax;
|
||||
m_centerPwm = center;
|
||||
m_deadbandMinPwm = deadbandMin;
|
||||
m_minPwm = min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bounds on the PWM pulse widths.
|
||||
* This sets the bounds on the PWM values for a particular type of controller. The values
|
||||
* determine the upper and lower speeds as well as the deadband bracket.
|
||||
* @param max The max PWM pulse width in ms
|
||||
* @param deadbandMax The high end of the deadband range pulse width in ms
|
||||
* @param center The center (off) pulse width in ms
|
||||
* @param deadbandMin The low end of the deadband pulse width in ms
|
||||
* @param min The minimum pulse width in ms
|
||||
*/
|
||||
void setBounds(double max, double deadbandMax, double center, double deadbandMin, double min) {
|
||||
double loopTime = m_module.getLoopTiming()/(kSystemClockTicksPerMicrosecond*1e3);
|
||||
|
||||
m_maxPwm = (int)((max-kDefaultPwmCenter)/loopTime+kDefaultPwmStepsDown-1);
|
||||
m_deadbandMaxPwm = (int)((deadbandMax-kDefaultPwmCenter)/loopTime+kDefaultPwmStepsDown-1);
|
||||
m_centerPwm = (int)((center-kDefaultPwmCenter)/loopTime+kDefaultPwmStepsDown-1);
|
||||
m_deadbandMinPwm = (int)((deadbandMin-kDefaultPwmCenter)/loopTime+kDefaultPwmStepsDown-1);
|
||||
m_minPwm = (int)((min-kDefaultPwmCenter)/loopTime+kDefaultPwmStepsDown-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the module number associated with the PWM Object.
|
||||
*
|
||||
* @return The module's number.
|
||||
*/
|
||||
public int getModuleNumber() {
|
||||
return m_module.getModuleNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel number associated with the PWM Object.
|
||||
*
|
||||
* @return The channel number.
|
||||
*/
|
||||
public int getChannel() {
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value based on a position.
|
||||
*
|
||||
* This is intended to be used by servos.
|
||||
*
|
||||
* @pre SetMaxPositivePwm() called.
|
||||
* @pre SetMinNegativePwm() called.
|
||||
*
|
||||
* @param pos The position to set the servo between 0.0 and 1.0.
|
||||
*/
|
||||
public void setPosition(double pos) {
|
||||
if (pos < 0.0) {
|
||||
pos = 0.0;
|
||||
} else if (pos > 1.0) {
|
||||
pos = 1.0;
|
||||
}
|
||||
|
||||
int rawValue;
|
||||
// note, need to perform the multiplication below as floating point before converting to int
|
||||
rawValue = (int) ((pos * (double)getFullRangeScaleFactor()) + getMinNegativePwm());
|
||||
|
||||
// send the computed pwm value to the FPGA
|
||||
setRaw(rawValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PWM value in terms of a position.
|
||||
*
|
||||
* This is intended to be used by servos.
|
||||
*
|
||||
* @pre SetMaxPositivePwm() called.
|
||||
* @pre SetMinNegativePwm() called.
|
||||
*
|
||||
* @return The position the servo is set to between 0.0 and 1.0.
|
||||
*/
|
||||
public double getPosition() {
|
||||
int value = getRaw();
|
||||
if (value < getMinNegativePwm()) {
|
||||
return 0.0;
|
||||
} else if (value > getMaxPositivePwm()) {
|
||||
return 1.0;
|
||||
} else {
|
||||
return (double)(value - getMinNegativePwm()) / (double)getFullRangeScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value based on a speed.
|
||||
*
|
||||
* This is intended to be used by speed controllers.
|
||||
*
|
||||
* @pre SetMaxPositivePwm() called.
|
||||
* @pre SetMinPositivePwm() called.
|
||||
* @pre SetCenterPwm() called.
|
||||
* @pre SetMaxNegativePwm() called.
|
||||
* @pre SetMinNegativePwm() called.
|
||||
*
|
||||
* @param speed The speed to set the speed controller between -1.0 and 1.0.
|
||||
*/
|
||||
final void setSpeed(double speed) {
|
||||
// clamp speed to be in the range 1.0 >= speed >= -1.0
|
||||
if (speed < -1.0) {
|
||||
speed = -1.0;
|
||||
} else if (speed > 1.0) {
|
||||
speed = 1.0;
|
||||
}
|
||||
|
||||
// calculate the desired output pwm value by scaling the speed appropriately
|
||||
int rawValue;
|
||||
if (speed == 0.0) {
|
||||
rawValue = getCenterPwm();
|
||||
} else if (speed > 0.0) {
|
||||
rawValue = (int) (speed * ((double)getPositiveScaleFactor()) +
|
||||
((double)getMinPositivePwm()) + 0.5);
|
||||
} else {
|
||||
rawValue = (int) (speed * ((double)getNegativeScaleFactor()) +
|
||||
((double)getMaxNegativePwm()) + 0.5);
|
||||
}
|
||||
|
||||
// send the computed pwm value to the FPGA
|
||||
setRaw(rawValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PWM value in terms of speed.
|
||||
*
|
||||
* This is intended to be used by speed controllers.
|
||||
*
|
||||
* @pre SetMaxPositivePwm() called.
|
||||
* @pre SetMinPositivePwm() called.
|
||||
* @pre SetMaxNegativePwm() called.
|
||||
* @pre SetMinNegativePwm() called.
|
||||
*
|
||||
* @return The most recently set speed between -1.0 and 1.0.
|
||||
*/
|
||||
public double getSpeed() {
|
||||
int value = getRaw();
|
||||
if (value > getMaxPositivePwm()) {
|
||||
return 1.0;
|
||||
} else if (value < getMinNegativePwm()) {
|
||||
return -1.0;
|
||||
} else if (value > getMinPositivePwm()) {
|
||||
return (double) (value - getMinPositivePwm()) / (double)getPositiveScaleFactor();
|
||||
} else if (value < getMaxNegativePwm()) {
|
||||
return (double) (value - getMaxNegativePwm()) / (double)getNegativeScaleFactor();
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value directly to the hardware.
|
||||
*
|
||||
* Write a raw value to a PWM channel.
|
||||
*
|
||||
* @param value Raw PWM value. Range 0 - 255.
|
||||
*/
|
||||
public void setRaw(int value) {
|
||||
m_module.setPWM(m_channel, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PWM value directly from the hardware.
|
||||
*
|
||||
* Read a raw value from a PWM channel.
|
||||
*
|
||||
* @return Raw PWM control value. Range: 0 - 255.
|
||||
*/
|
||||
public int getRaw() {
|
||||
return m_module.getPWM(m_channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Slow down the PWM signal for old devices.
|
||||
*
|
||||
* @param mult The period multiplier to apply to this channel
|
||||
*/
|
||||
public void setPeriodMultiplier(PeriodMultiplier mult) {
|
||||
switch (mult.value) {
|
||||
case PeriodMultiplier.k4X_val:
|
||||
m_module.setPWMPeriodScale(m_channel, 3); // Squelch 3 out of 4 outputs
|
||||
break;
|
||||
case PeriodMultiplier.k2X_val:
|
||||
m_module.setPWMPeriodScale(m_channel, 1); // Squelch 1 out of 2 outputs
|
||||
break;
|
||||
case PeriodMultiplier.k1X_val:
|
||||
m_module.setPWMPeriodScale(m_channel, 0); // Don't squelch any outputs
|
||||
break;
|
||||
default:
|
||||
//Cannot hit this, limited by PeriodMultiplier enum
|
||||
}
|
||||
}
|
||||
|
||||
private int getMaxPositivePwm() {
|
||||
return m_maxPwm;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private int getMinPositivePwm() {
|
||||
return m_eliminateDeadband ? m_deadbandMaxPwm : m_centerPwm + 1;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private int getCenterPwm() {
|
||||
return m_centerPwm;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private int getMaxNegativePwm() {
|
||||
return m_eliminateDeadband ? m_deadbandMinPwm : m_centerPwm - 1;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private int getMinNegativePwm() {
|
||||
return m_minPwm;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private int getPositiveScaleFactor() {
|
||||
return getMaxPositivePwm() - getMinPositivePwm();
|
||||
} ///< The scale for positive speeds.
|
||||
|
||||
private int getNegativeScaleFactor() {
|
||||
return getMaxNegativePwm() - getMinNegativePwm();
|
||||
} ///< The scale for negative speeds.
|
||||
|
||||
private int getFullRangeScaleFactor() {
|
||||
return getMaxPositivePwm() - getMinNegativePwm();
|
||||
} ///< The scale for positions.
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Speed Controller";
|
||||
}
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
if (m_table != null) {
|
||||
m_table.putNumber("Value", getSpeed());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
setSpeed(0); // Stop for safety
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value, boolean bln) {
|
||||
setSpeed(((Double) value).doubleValue());
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
setSpeed(0); // Stop for safety
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,828 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.networktables.NetworkTable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
|
||||
/**
|
||||
* The preferences class provides a relatively simple way to save important
|
||||
* values to the cRIO to access the next time the cRIO is booted.
|
||||
*
|
||||
* <p>This class loads and saves from a file inside the cRIO. The user can not
|
||||
* access the file directly, but may modify values at specific fields which will
|
||||
* then be saved to the file when {@link Preferences#save() save()} is
|
||||
* called.</p>
|
||||
*
|
||||
* <p>This class is thread safe.</p>
|
||||
*
|
||||
* <p>This will also interact with {@link NetworkTable} by creating a table
|
||||
* called "Preferences" with all the key-value pairs. To save using
|
||||
* {@link NetworkTable}, simply set the boolean at position ~S A V E~ to true.
|
||||
* Also, if the value of any variable is " in the {@link NetworkTable}, then
|
||||
* that represents non-existence in the {@link Preferences} table</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public class Preferences {
|
||||
|
||||
/**
|
||||
* The Preferences table name
|
||||
*/
|
||||
private static final String TABLE_NAME = "Preferences";
|
||||
/**
|
||||
* The value of the save field
|
||||
*/
|
||||
private static final String SAVE_FIELD = "~S A V E~";
|
||||
/**
|
||||
* The file to save to
|
||||
*/
|
||||
private static final String FILE_NAME = "file:///wpilib-preferences.ini";
|
||||
/**
|
||||
* The characters to put between a field and value
|
||||
*/
|
||||
private static final byte[] VALUE_PREFIX = {'=', '\"'};
|
||||
/**
|
||||
* The characters to put after the value
|
||||
*/
|
||||
private static final byte[] VALUE_SUFFIX = {'\"', '\n'};
|
||||
/**
|
||||
* The newline character
|
||||
*/
|
||||
private static final byte[] NEW_LINE = {'\n'};
|
||||
/**
|
||||
* The singleton instance
|
||||
*/
|
||||
private static Preferences instance;
|
||||
|
||||
/**
|
||||
* Returns the preferences instance.
|
||||
*
|
||||
* @return the preferences instance
|
||||
*/
|
||||
public synchronized static Preferences getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Preferences();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
/**
|
||||
* The semaphore for beginning reads and writes to the file
|
||||
*/
|
||||
private final Object fileLock = new Object();
|
||||
/**
|
||||
* The semaphore for reading from the table
|
||||
*/
|
||||
private final Object lock = new Object();
|
||||
/**
|
||||
* The actual values (String->String)
|
||||
*/
|
||||
private Hashtable values;
|
||||
/**
|
||||
* The keys in the order they were read from the file
|
||||
*/
|
||||
private Vector keys;
|
||||
/**
|
||||
* The comments that were in the file sorted by which key they appeared over
|
||||
* (String->Comment)
|
||||
*/
|
||||
private Hashtable comments;
|
||||
/**
|
||||
* The comment at the end of the file
|
||||
*/
|
||||
private Comment endComment;
|
||||
|
||||
/**
|
||||
* Creates a preference class that will automatically read the file in a
|
||||
* different thread. Any call to its methods will be blocked until the
|
||||
* thread is finished reading.
|
||||
*/
|
||||
private Preferences() {
|
||||
values = new Hashtable();
|
||||
keys = new Vector();
|
||||
|
||||
// We synchronized on fileLock and then wait
|
||||
// for it to know that the reading thread has started
|
||||
synchronized (fileLock) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
read();
|
||||
}
|
||||
} .start();
|
||||
try {
|
||||
fileLock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Preferences, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a vector of the keys
|
||||
*/
|
||||
public Vector getKeys() {
|
||||
synchronized (lock) {
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given value into the given key position
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains an illegal
|
||||
* character
|
||||
*/
|
||||
private void put(String key, String value) {
|
||||
synchronized (lock) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
ImproperPreferenceKeyException.confirmString(key);
|
||||
if (values.put(key, value) == null) {
|
||||
keys.addElement(key);
|
||||
}
|
||||
NetworkTable.getTable(TABLE_NAME).putString(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given string into the preferences table.
|
||||
*
|
||||
* <p>The value may not have quotation marks, nor may the key have any
|
||||
* whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care). at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws NullPointerException if value is null
|
||||
* @throws IllegalArgumentException if value contains a quotation mark
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putString(String key, String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (value.indexOf('"') != -1) {
|
||||
throw new IllegalArgumentException("Can not put string:" + value + " because it contains quotation marks");
|
||||
}
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given int into the preferences table.
|
||||
*
|
||||
* <p>The key may not have any whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care) at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putInt(String key, int value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given double into the preferences table.
|
||||
*
|
||||
* <p>The key may not have any whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care) at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putDouble(String key, double value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given float into the preferences table.
|
||||
*
|
||||
* <p>The key may not have any whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care) at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putFloat(String key, float value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given boolean into the preferences table.
|
||||
*
|
||||
* <p>The key may not have any whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care) at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putBoolean(String key, boolean value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given long into the preferences table.
|
||||
*
|
||||
* <p>The key may not have any whitespace nor an equals sign</p>
|
||||
*
|
||||
* <p>This will <b>NOT</b> save the value to memory between power cycles, to
|
||||
* do that you must call {@link Preferences#save() save()} (which must be
|
||||
* used with care) at some point after calling this.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws ImproperPreferenceKeyException if the key contains any whitespace
|
||||
* or an equals sign
|
||||
*/
|
||||
public void putLong(String key, long value) {
|
||||
put(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value at the given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return the value (or null if none exists)
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
private String get(String key) {
|
||||
synchronized (lock) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return (String) values.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not there is a key with the given name.
|
||||
*
|
||||
* @param key the key
|
||||
* @return if there is a value at the given key
|
||||
* @throws NullPointerException if key is null
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a preference
|
||||
*
|
||||
* @param key the key
|
||||
* @throws NullPointerException if key is null
|
||||
*/
|
||||
public void remove(String key) {
|
||||
synchronized (lock) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
values.remove(key);
|
||||
keys.removeElement(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string at the given key. If this table does not have a value
|
||||
* for that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public String getString(String key, String backup) {
|
||||
String value = get(key);
|
||||
return value == null ? backup : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the int at the given key. If this table does not have a value for
|
||||
* that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws IncompatibleTypeException if the value in the table can not be
|
||||
* converted to an int
|
||||
*/
|
||||
public int getInt(String key, int backup) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return backup;
|
||||
} else {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IncompatibleTypeException(value, "int");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the double at the given key. If this table does not have a value
|
||||
* for that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws IncompatibleTypeException if the value in the table can not be
|
||||
* converted to an double
|
||||
*/
|
||||
public double getDouble(String key, double backup) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return backup;
|
||||
} else {
|
||||
try {
|
||||
return Double.parseDouble(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IncompatibleTypeException(value, "double");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean at the given key. If this table does not have a value
|
||||
* for that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws IncompatibleTypeException if the value in the table can not be
|
||||
* converted to a boolean
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean backup) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return backup;
|
||||
} else {
|
||||
if (value.equalsIgnoreCase("true")) {
|
||||
return true;
|
||||
} else if (value.equalsIgnoreCase("false")) {
|
||||
return false;
|
||||
} else {
|
||||
throw new IncompatibleTypeException(value, "boolean");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the float at the given key. If this table does not have a value
|
||||
* for that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws IncompatibleTypeException if the value in the table can not be
|
||||
* converted to a float
|
||||
*/
|
||||
public float getFloat(String key, float backup) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return backup;
|
||||
} else {
|
||||
try {
|
||||
return Float.parseFloat(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IncompatibleTypeException(value, "float");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the long at the given key. If this table does not have a value
|
||||
* for that position, then the given backup value will be returned.
|
||||
*
|
||||
* @param key the key
|
||||
* @param backup the value to return if none exists in the table
|
||||
* @return either the value in the table, or the backup
|
||||
* @throws IncompatibleTypeException if the value in the table can not be
|
||||
* converted to a long
|
||||
*/
|
||||
public long getLong(String key, long backup) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
put(key, String.valueOf(backup));
|
||||
return backup;
|
||||
} else {
|
||||
try {
|
||||
return Long.parseLong(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IncompatibleTypeException(value, "long");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the preferences to a file on the cRIO.
|
||||
*
|
||||
* <p>This should <b>NOT</b> be called often. Too many writes can damage the
|
||||
* cRIO's flash memory. While it is ok to save once or twice a match, this
|
||||
* should never be called every run of
|
||||
* {@link IterativeRobot#teleopPeriodic()}.</p>
|
||||
*
|
||||
* <p>The actual writing of the file is done in a separate thread. However,
|
||||
* any call to a get or put method will wait until the table is fully saved
|
||||
* before continuing.</p>
|
||||
*/
|
||||
public void save() {
|
||||
synchronized (fileLock) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
write();
|
||||
}
|
||||
} .start();
|
||||
try {
|
||||
fileLock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method that actually writes the table to a file. This is called
|
||||
* in its own thread when {@link Preferences#save() save()} is called.
|
||||
*/
|
||||
private void write() {
|
||||
synchronized (lock) {
|
||||
synchronized (fileLock) {
|
||||
fileLock.notifyAll();
|
||||
}
|
||||
|
||||
File file = null;
|
||||
FileOutputStream output = null;
|
||||
try {
|
||||
file = new File(FILE_NAME);
|
||||
|
||||
if (file.exists())
|
||||
file.delete();
|
||||
|
||||
file.createNewFile();
|
||||
|
||||
output = new FileOutputStream(file);
|
||||
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = (String) keys.elementAt(i);
|
||||
String value = (String) values.get(key);
|
||||
|
||||
if (comments != null) {
|
||||
Comment comment = (Comment) comments.get(key);
|
||||
if (comment != null) {
|
||||
comment.write(output);
|
||||
}
|
||||
}
|
||||
|
||||
output.write(key.getBytes());
|
||||
output.write(VALUE_PREFIX);
|
||||
output.write(value.getBytes());
|
||||
output.write(VALUE_SUFFIX);
|
||||
}
|
||||
|
||||
if (endComment != null) {
|
||||
endComment.write(output);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
if (output != null) {
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
NetworkTable.getTable(TABLE_NAME).putBoolean(SAVE_FIELD, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The internal method to read from a file. This will be called in its own
|
||||
* thread when the preferences singleton is first created.
|
||||
*/
|
||||
private void read() {
|
||||
class EndOfStreamException extends Exception {
|
||||
}
|
||||
|
||||
class Reader {
|
||||
|
||||
InputStream stream;
|
||||
|
||||
Reader(InputStream stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public char read() throws IOException, EndOfStreamException {
|
||||
int input = stream.read();
|
||||
if (input == -1) {
|
||||
throw new EndOfStreamException();
|
||||
} else {
|
||||
// Check for carriage returns
|
||||
return input == '\r' ? '\n' : (char) input;
|
||||
}
|
||||
}
|
||||
|
||||
char readWithoutWhitespace() throws IOException, EndOfStreamException {
|
||||
while (true) {
|
||||
char value = read();
|
||||
switch (value) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
continue;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
synchronized (fileLock) {
|
||||
fileLock.notifyAll();
|
||||
}
|
||||
|
||||
Comment comment = null;
|
||||
|
||||
|
||||
|
||||
File file = null;
|
||||
FileInputStream input = null;
|
||||
try {
|
||||
file = new File(FILE_NAME);
|
||||
|
||||
if (file.exists()) {
|
||||
input = new FileInputStream(file);
|
||||
Reader reader = new Reader(input);
|
||||
|
||||
StringBuffer buffer;
|
||||
|
||||
while (true) {
|
||||
char value = reader.readWithoutWhitespace();
|
||||
|
||||
if (value == '\n' || value == ';') {
|
||||
if (comment == null) {
|
||||
comment = new Comment();
|
||||
}
|
||||
|
||||
if (value == '\n') {
|
||||
comment.addBytes(NEW_LINE);
|
||||
} else {
|
||||
buffer = new StringBuffer(30);
|
||||
for (; value != '\n'; value = reader.read()) {
|
||||
buffer.append(value);
|
||||
}
|
||||
buffer.append('\n');
|
||||
comment.addBytes(buffer.toString().getBytes());
|
||||
}
|
||||
} else {
|
||||
buffer = new StringBuffer(30);
|
||||
for (; value != '='; value = reader.readWithoutWhitespace()) {
|
||||
buffer.append(value);
|
||||
}
|
||||
String name = buffer.toString();
|
||||
buffer = new StringBuffer(30);
|
||||
|
||||
boolean shouldBreak = false;
|
||||
|
||||
value = reader.readWithoutWhitespace();
|
||||
if (value == '"') {
|
||||
for (value = reader.read(); value != '"'; value = reader.read()) {
|
||||
buffer.append(value);
|
||||
}
|
||||
// Clear the line
|
||||
while (reader.read() != '\n');
|
||||
} else {
|
||||
try {
|
||||
for (; value != '\n'; value = reader.readWithoutWhitespace()) {
|
||||
buffer.append(value);
|
||||
}
|
||||
} catch (EndOfStreamException e) {
|
||||
shouldBreak = true;
|
||||
}
|
||||
}
|
||||
|
||||
String result = buffer.toString();
|
||||
|
||||
keys.addElement(name);
|
||||
values.put(name, result);
|
||||
NetworkTable.getTable(TABLE_NAME).putString(name, result);
|
||||
|
||||
if (comment != null) {
|
||||
if (comments == null) {
|
||||
comments = new Hashtable();
|
||||
}
|
||||
comments.put(name, comment);
|
||||
comment = null;
|
||||
}
|
||||
|
||||
System.out.println(name + "=" + values.get(name));
|
||||
|
||||
if (shouldBreak) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
} catch (EndOfStreamException ex) {
|
||||
System.out.println("Done Reading");
|
||||
}
|
||||
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
if (comment != null) {
|
||||
endComment = comment;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkTable.getTable(TABLE_NAME).putBoolean(SAVE_FIELD, false);
|
||||
// TODO: Verify that this works even though it changes with subtables.
|
||||
// Should work since preferences shouldn't have subtables.
|
||||
NetworkTable.getTable(TABLE_NAME).addTableListener(new ITableListener() {
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew) {
|
||||
if (key.equals(SAVE_FIELD)) {
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
save();
|
||||
}
|
||||
} else {
|
||||
synchronized (lock) {
|
||||
if (!ImproperPreferenceKeyException.isAcceptable(key) || value.toString().indexOf('"') != -1) {
|
||||
if (values.contains(key) || keys.contains(key)) {
|
||||
values.remove(key);
|
||||
keys.removeElement(key);
|
||||
NetworkTable.getTable(TABLE_NAME).putString(key, "\"");
|
||||
}
|
||||
} else {
|
||||
if (values.put(key, value.toString()) == null) {
|
||||
keys.addElement(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A class representing some comment lines in the ini file. This is used so
|
||||
* that if a programmer ever directly modifies the ini file, then his/her
|
||||
* comments will still be there after {@link Preferences#save() save()} is
|
||||
* called.
|
||||
*/
|
||||
private static class Comment {
|
||||
|
||||
/**
|
||||
* A vector of byte arrays. Each array represents a line to write
|
||||
*/
|
||||
private Vector bytes = new Vector();
|
||||
|
||||
/**
|
||||
* Appends the given bytes to the comment.
|
||||
*
|
||||
* @param bytes the bytes to add
|
||||
*/
|
||||
private void addBytes(byte[] bytes) {
|
||||
this.bytes.addElement(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes this comment to the given stream
|
||||
*
|
||||
* @param stream the stream to write to
|
||||
* @throws IOException if the stream has a problem
|
||||
*/
|
||||
private void write(OutputStream stream) throws IOException {
|
||||
for (int i = 0; i < bytes.size(); i++) {
|
||||
stream.write((byte[]) bytes.elementAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This exception is thrown if the a value requested cannot be converted to
|
||||
* the requested type.
|
||||
*/
|
||||
public static class IncompatibleTypeException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates an exception with a description based on the input
|
||||
*
|
||||
* @param value the value that can not be converted
|
||||
* @param type the type that the value can not be converted to
|
||||
*/
|
||||
public IncompatibleTypeException(String value, String type) {
|
||||
super("Cannot convert \"" + value + "\" into " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be thrown if a string can not be used as a key in the preferences
|
||||
* file. This happens if the string contains a new line, a space, a tab, or
|
||||
* an equals sign.
|
||||
*/
|
||||
public static class ImproperPreferenceKeyException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Instantiates an exception with a descriptive message based on the
|
||||
* input.
|
||||
*
|
||||
* @param value the illegal key
|
||||
* @param letter the specific character that made it illegal
|
||||
*/
|
||||
public ImproperPreferenceKeyException(String value, char letter) {
|
||||
super("Preference key \""
|
||||
+ value + "\" is not allowed to contain letter with ASCII code:" + (byte) letter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the given string is ok to use as a key in the preference
|
||||
* table. If not, then a {@link ImproperPreferenceKeyException} will be
|
||||
* thrown.
|
||||
*
|
||||
* @param value the value to test
|
||||
*/
|
||||
public static void confirmString(String value) {
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char letter = value.charAt(i);
|
||||
switch (letter) {
|
||||
case '=':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ' ':
|
||||
case '\t':
|
||||
throw new ImproperPreferenceKeyException(value, letter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the given string is ok to use in the
|
||||
* preference table.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean isAcceptable(String value) {
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char letter = value.charAt(i);
|
||||
switch (letter) {
|
||||
case '=':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ' ':
|
||||
case '\t':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,440 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.parsing.IDeviceController;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Class for VEX Robotics Spike style relay outputs. Relays are intended to be
|
||||
* connected to Spikes or similar relays. The relay channels controls a pair of
|
||||
* pins that are either both off, one on, the other on, or both on. This
|
||||
* translates into two Spike outputs at 0v, one at 12v and one at 0v, one at 0v
|
||||
* and the other at 12v, or two Spike outputs at 12V. This allows off, full
|
||||
* forward, or full reverse control of motors without variable speed. It also
|
||||
* allows the two channels (forward and reverse) to be used independently for
|
||||
* something that does not care about voltage polarity (like a solenoid).
|
||||
*/
|
||||
public class Relay extends SensorBase implements IDeviceController,
|
||||
LiveWindowSendable {
|
||||
|
||||
/*
|
||||
* XXX: Refactor to no longer depend on the DigitalModule, and move all
|
||||
* resource tracking into the HAL. This will wait until we get the unit
|
||||
* tests running for the first time.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents errors in trying to set relay values contradictory
|
||||
* to the direction to which the relay is set.
|
||||
*/
|
||||
public class InvalidValueException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Create a new exception with the given message
|
||||
*
|
||||
* @param message
|
||||
* the message to pass with the exception
|
||||
*/
|
||||
public InvalidValueException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The state to drive a Relay to.
|
||||
*/
|
||||
public static class Value {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kOff_val = 0;
|
||||
static final int kOn_val = 1;
|
||||
static final int kForward_val = 2;
|
||||
static final int kReverse_val = 3;
|
||||
/**
|
||||
* value: off
|
||||
*/
|
||||
public static final Value kOff = new Value(kOff_val);
|
||||
/**
|
||||
* value: on for relays with defined direction
|
||||
*/
|
||||
public static final Value kOn = new Value(kOn_val);
|
||||
/**
|
||||
* value: forward
|
||||
*/
|
||||
public static final Value kForward = new Value(kForward_val);
|
||||
/**
|
||||
* value: reverse
|
||||
*/
|
||||
public static final Value kReverse = new Value(kReverse_val);
|
||||
|
||||
private Value(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Direction(s) that a relay is configured to operate in.
|
||||
*/
|
||||
public static class Direction {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kBoth_val = 0;
|
||||
static final int kForward_val = 1;
|
||||
static final int kReverse_val = 2;
|
||||
/**
|
||||
* direction: both directions are valid
|
||||
*/
|
||||
public static final Direction kBoth = new Direction(kBoth_val);
|
||||
/**
|
||||
* direction: Only forward is valid
|
||||
*/
|
||||
public static final Direction kForward = new Direction(kForward_val);
|
||||
/**
|
||||
* direction: only reverse is valid
|
||||
*/
|
||||
public static final Direction kReverse = new Direction(kReverse_val);
|
||||
|
||||
private Direction(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int m_channel;
|
||||
private Direction m_direction;
|
||||
private DigitalModule m_module;
|
||||
private static Resource relayChannels = new Resource(
|
||||
HALLibrary.dio_kNumSystems.get() * kRelayChannels * 2);
|
||||
|
||||
/**
|
||||
* Common relay initialization method. This code is common to all Relay
|
||||
* constructors and initializes the relay and reserves all resources that
|
||||
* need to be locked. Initially the relay is set to both lines at 0v.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use.
|
||||
*/
|
||||
private void initRelay(final int moduleNumber) {
|
||||
SensorBase.checkRelayModule(moduleNumber);
|
||||
SensorBase.checkRelayChannel(m_channel);
|
||||
try {
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kForward) {
|
||||
relayChannels.allocate(((moduleNumber - 1) * kRelayChannels
|
||||
+ m_channel - 1) * 2);
|
||||
UsageReporting.report(tResourceType.kResourceType_Relay,
|
||||
m_channel, moduleNumber - 1);
|
||||
}
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kReverse) {
|
||||
relayChannels.allocate(((moduleNumber - 1) * kRelayChannels
|
||||
+ m_channel - 1) * 2 + 1);
|
||||
UsageReporting.report(tResourceType.kResourceType_Relay,
|
||||
m_channel + 128, moduleNumber - 1);
|
||||
}
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException("Relay channel " + m_channel
|
||||
+ " on module " + moduleNumber + " is already allocated");
|
||||
}
|
||||
m_module = DigitalModule.getInstance(moduleNumber);
|
||||
m_module.setRelayForward(m_channel, false);
|
||||
m_module.setRelayReverse(m_channel, false);
|
||||
LiveWindow.addActuator("Relay", moduleNumber, m_channel, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relay constructor given the module and the channel.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use.
|
||||
* @param channel
|
||||
* The channel number within the module for this relay.
|
||||
* @param direction
|
||||
* The direction that the Relay object will control.
|
||||
*/
|
||||
public Relay(final int moduleNumber, final int channel, Direction direction) {
|
||||
if (direction == null)
|
||||
throw new NullPointerException("Null Direction was given");
|
||||
m_channel = channel;
|
||||
m_direction = direction;
|
||||
initRelay(moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relay constructor given a channel only where the default digital module
|
||||
* is used.
|
||||
*
|
||||
* @param channel
|
||||
* The channel number within the default module for this relay.
|
||||
* @param direction
|
||||
* The direction that the Relay object will control.
|
||||
*/
|
||||
public Relay(final int channel, Direction direction) {
|
||||
if (direction == null)
|
||||
throw new NullPointerException("Null Direction was given");
|
||||
m_channel = channel;
|
||||
m_direction = direction;
|
||||
initRelay(getDefaultDigitalModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* Relay constructor given the module and the channel, allowing both
|
||||
* directions.
|
||||
*
|
||||
* @param moduleNumber
|
||||
* The number of the digital module to use.
|
||||
* @param channel
|
||||
* The channel number within the module for this relay.
|
||||
*/
|
||||
public Relay(final int moduleNumber, final int channel) {
|
||||
m_channel = channel;
|
||||
m_direction = Direction.kBoth;
|
||||
initRelay(moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relay constructor given a channel only where the default digital module
|
||||
* is used, allowing both directions.
|
||||
*
|
||||
* @param channel
|
||||
* The channel number within the default module for this relay.
|
||||
*/
|
||||
public Relay(final int channel) {
|
||||
m_channel = channel;
|
||||
m_direction = Direction.kBoth;
|
||||
initRelay(getDefaultDigitalModule());
|
||||
}
|
||||
|
||||
public void free() {
|
||||
m_module.setRelayForward(m_channel, false);
|
||||
m_module.setRelayReverse(m_channel, false);
|
||||
|
||||
if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
|
||||
relayChannels.free(((m_module.getModuleNumber() - 1)
|
||||
* kRelayChannels + m_channel - 1) * 2);
|
||||
m_module.freeDIO(((m_module.getModuleNumber() - 1) * kRelayChannels
|
||||
+ m_channel - 1) * 2);
|
||||
}
|
||||
if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
|
||||
relayChannels.free(((m_module.getModuleNumber() - 1)
|
||||
* kRelayChannels + m_channel - 1) * 2 + 1);
|
||||
m_module.freeDIO(((m_module.getModuleNumber() - 1) * kRelayChannels
|
||||
+ m_channel - 1) * 2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the relay state.
|
||||
*
|
||||
* Valid values depend on which directions of the relay are controlled by
|
||||
* the object.
|
||||
*
|
||||
* When set to kBothDirections, the relay can be set to any of the four
|
||||
* states: 0v-0v, 12v-0v, 0v-12v, 12v-12v
|
||||
*
|
||||
* When set to kForwardOnly or kReverseOnly, you can specify the constant
|
||||
* for the direction or you can simply specify kOff_val and kOn_val. Using
|
||||
* only kOff_val and kOn_val is recommended.
|
||||
*
|
||||
* @param value
|
||||
* The state to set the relay.
|
||||
*/
|
||||
public void set(Value value) {
|
||||
switch (value.value) {
|
||||
case Value.kOff_val:
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kForward) {
|
||||
m_module.setRelayForward(m_channel, false);
|
||||
}
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kReverse) {
|
||||
m_module.setRelayReverse(m_channel, false);
|
||||
}
|
||||
break;
|
||||
case Value.kOn_val:
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kForward) {
|
||||
m_module.setRelayForward(m_channel, true);
|
||||
}
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kReverse) {
|
||||
m_module.setRelayReverse(m_channel, true);
|
||||
}
|
||||
break;
|
||||
case Value.kForward_val:
|
||||
if (m_direction == Direction.kReverse)
|
||||
throw new InvalidValueException(
|
||||
"A relay configured for reverse cannot be set to forward");
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kForward) {
|
||||
m_module.setRelayForward(m_channel, true);
|
||||
}
|
||||
if (m_direction == Direction.kBoth) {
|
||||
m_module.setRelayReverse(m_channel, false);
|
||||
}
|
||||
break;
|
||||
case Value.kReverse_val:
|
||||
if (m_direction == Direction.kForward)
|
||||
throw new InvalidValueException(
|
||||
"A relay configured for forward cannot be set to reverse");
|
||||
if (m_direction == Direction.kBoth) {
|
||||
m_module.setRelayForward(m_channel, false);
|
||||
}
|
||||
if (m_direction == Direction.kBoth
|
||||
|| m_direction == Direction.kReverse) {
|
||||
m_module.setRelayReverse(m_channel, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Cannot hit this, limited by Value enum
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Relay State
|
||||
*
|
||||
* Gets the current state of the relay.
|
||||
*
|
||||
* When set to kForwardOnly or kReverseOnly, value is returned as kOn/kOff
|
||||
* not kForward/kReverse (per the recommendation in Set)
|
||||
*
|
||||
* @return The current state of the relay as a Relay::Value
|
||||
*/
|
||||
public Value get() {
|
||||
if (m_module.getRelayForward(m_channel)) {
|
||||
if (m_module.getRelayReverse(m_channel)) {
|
||||
return Value.kOn;
|
||||
} else {
|
||||
if (m_direction == Direction.kForward) {
|
||||
return Value.kOn;
|
||||
} else {
|
||||
return Value.kForward;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_module.getRelayReverse(m_channel)) {
|
||||
if (m_direction == Direction.kForward) {
|
||||
return Value.kOn;
|
||||
} else {
|
||||
return Value.kReverse;
|
||||
}
|
||||
} else {
|
||||
return Value.kOff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Relay Direction
|
||||
*
|
||||
* Changes which values the relay can be set to depending on which direction
|
||||
* is used
|
||||
*
|
||||
* Valid inputs are kBothDirections, kForwardOnly, and kReverseOnly
|
||||
*
|
||||
* @param direction
|
||||
* The direction for the relay to operate in
|
||||
*/
|
||||
public void setDirection(Direction direction) {
|
||||
if (direction == null)
|
||||
throw new NullPointerException("Null Direction was given");
|
||||
if (m_direction == direction) {
|
||||
return;
|
||||
}
|
||||
|
||||
free();
|
||||
|
||||
m_direction = direction;
|
||||
|
||||
initRelay(m_module.getModuleNumber());
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Relay";
|
||||
}
|
||||
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@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 (get() == Value.kOn) {
|
||||
m_table.putString("Value", "On");
|
||||
} else if (get() == Value.kForward) {
|
||||
m_table.putString("Value", "Forward");
|
||||
} else if (get() == Value.kReverse) {
|
||||
m_table.putString("Value", "Reverse");
|
||||
} else {
|
||||
m_table.putString("Value", "Off");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value,
|
||||
boolean bln) {
|
||||
String val = ((String) value);
|
||||
if (val.equals("Off")) {
|
||||
set(Value.kOff);
|
||||
} else if (val.equals("Forward")) {
|
||||
set(Value.kForward);
|
||||
} else if (val.equals("Reverse")) {
|
||||
set(Value.kReverse);
|
||||
}
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Track resources in the program.
|
||||
* The Resource class is a convenient way of keeping track of allocated arbitrary resources
|
||||
* in the program. Resources are just indicies that have an lower and upper bound that are
|
||||
* tracked by this class. In the library they are used for tracking allocation of hardware channels
|
||||
* but this is purely arbitrary. The resource class does not do any actual allocation, but
|
||||
* simply tracks if a given index is currently in use.
|
||||
*
|
||||
* WARNING: this should only be statically allocated. When the program loads into memory all the
|
||||
* static constructors are called. At that time a linked list of all the "Resources" is created.
|
||||
* Then when the program actually starts - in the Robot constructor, all resources are initialized.
|
||||
* This ensures that the program is restartable in memory without having to unload/reload.
|
||||
*/
|
||||
public class Resource {
|
||||
|
||||
private static Resource m_resourceList = null;
|
||||
private final boolean m_numAllocated[];
|
||||
private final int m_size;
|
||||
private final Resource m_nextResource;
|
||||
|
||||
/**
|
||||
* Clears all allocated resources
|
||||
*/
|
||||
public static void restartProgram() {
|
||||
for (Resource r = Resource.m_resourceList; r != null; r = r.m_nextResource) {
|
||||
for (int i = 0; i < r.m_size; i++) {
|
||||
r.m_numAllocated[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate storage for a new instance of Resource.
|
||||
* Allocate a bool array of values that will get initialized to indicate that no resources
|
||||
* have been allocated yet. The indicies of the resources are 0..size-1.
|
||||
*
|
||||
* @param size The number of blocks to allocate
|
||||
*/
|
||||
public Resource(final int size) {
|
||||
m_size = size;
|
||||
m_numAllocated = new boolean[m_size];
|
||||
for (int i = 0; i < m_size; i++) {
|
||||
m_numAllocated[i] = false;
|
||||
}
|
||||
m_nextResource = Resource.m_resourceList;
|
||||
Resource.m_resourceList = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a resource.
|
||||
* When a resource is requested, mark it allocated. In this case, a free resource value
|
||||
* within the range is located and returned after it is marked allocated.
|
||||
*
|
||||
* @return The index of the allocated block.
|
||||
* @throws CheckedAllocationException If there are no resources available to be allocated.
|
||||
*/
|
||||
public int allocate() throws CheckedAllocationException {
|
||||
for (int i = 0; i < m_size; i++) {
|
||||
if (m_numAllocated[i] == false) {
|
||||
m_numAllocated[i] = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new CheckedAllocationException("No available resources");
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a specific resource value.
|
||||
* The user requests a specific resource value, i.e. channel number and it is verified
|
||||
* unallocated, then returned.
|
||||
*
|
||||
* @param index The resource to allocate
|
||||
* @return The index of the allocated block
|
||||
* @throws CheckedAllocationException If there are no resources available to be allocated.
|
||||
*/
|
||||
public int allocate(final int index) throws CheckedAllocationException {
|
||||
if (index >= m_size) {
|
||||
throw new CheckedAllocationException("Index " + index + " out of range");
|
||||
}
|
||||
if (m_numAllocated[index] == true) {
|
||||
throw new CheckedAllocationException("Resource at index " + index + " already allocated");
|
||||
}
|
||||
m_numAllocated[index] = true;
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an allocated resource.
|
||||
* After a resource is no longer needed, for example a destructor is called for a channel assignment
|
||||
* class, Free will release the resource value so it can be reused somewhere else in the program.
|
||||
*
|
||||
* @param index The index of the resource to free.
|
||||
*/
|
||||
public void free(final int index) {
|
||||
if (m_numAllocated[index] == false)
|
||||
throw new AllocationException("No resource available to be freed");
|
||||
m_numAllocated[index] = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.networktables.NetworkTable;
|
||||
|
||||
/**
|
||||
* Implement a Robot Program framework.
|
||||
* The RobotBase class is intended to be subclassed by a user creating a robot program.
|
||||
* Overridden autonomous() and operatorControl() methods are called at the appropriate time
|
||||
* as the match proceeds. In the current implementation, the Autonomous code will run to
|
||||
* completion before the OperatorControl code could start. In the future the Autonomous code
|
||||
* might be spawned as a task, then killed at the end of the Autonomous period.
|
||||
*/
|
||||
public abstract class RobotBase {
|
||||
/**
|
||||
* The VxWorks priority that robot code should work at (so Java code should run at)
|
||||
*/
|
||||
public static final int ROBOT_TASK_PRIORITY = 101;
|
||||
|
||||
/**
|
||||
* Boolean System property. If true (default), send System.err messages to the driver station.
|
||||
*/
|
||||
public final static String ERRORS_TO_DRIVERSTATION_PROP = "first.driverstation.senderrors";
|
||||
|
||||
protected final DriverStation m_ds;
|
||||
|
||||
/**
|
||||
* Constructor for a generic robot program.
|
||||
* User code should be placed in the constructor that runs before the Autonomous or Operator
|
||||
* Control period starts. The constructor will run to completion before Autonomous is entered.
|
||||
*
|
||||
* This must be used to ensure that the communications code starts. In the future it would be
|
||||
* nice to put this code into it's own task that loads on boot so ensure that it runs.
|
||||
*/
|
||||
protected RobotBase() {
|
||||
// TODO: StartCAPI();
|
||||
// TODO: See if the next line is necessary
|
||||
// Resource.RestartProgram();
|
||||
|
||||
// if (getBooleanProperty(ERRORS_TO_DRIVERSTATION_PROP, true)) {
|
||||
// Utility.sendErrorStreamToDriverStation(true);
|
||||
// }
|
||||
NetworkTable.setServerMode();//must be before b
|
||||
m_ds = DriverStation.getInstance();
|
||||
NetworkTable.getTable(""); // forces network tables to initialize
|
||||
NetworkTable.getTable("LiveWindow").getSubTable("~STATUS~").putBoolean("LW Enabled", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resources for a RobotBase class.
|
||||
*/
|
||||
public void free() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This has been deprecated in favor of {@link #isEnabled()}
|
||||
* Check on the overall status of the system.
|
||||
*
|
||||
* @return Is the system active (i.e. PWM motor outputs, etc. enabled)?
|
||||
*/
|
||||
public boolean isSystemActive() {
|
||||
return isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the Robot is currently disabled.
|
||||
* @return True if the Robot is currently disabled by the field controls.
|
||||
*/
|
||||
public boolean isDisabled() {
|
||||
return m_ds.isDisabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the Robot is currently enabled.
|
||||
* @return True if the Robot is currently enabled by the field controls.
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return m_ds.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Autonomous mode.
|
||||
* @return True if the robot is currently operating Autonomously as determined by the field controls.
|
||||
*/
|
||||
public boolean isAutonomous() {
|
||||
return m_ds.isAutonomous();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Test mode
|
||||
* @return True if the robot is currently operating in Test mode as determined by the driver station.
|
||||
*/
|
||||
public boolean isTest() {
|
||||
return m_ds.isTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the robot is currently in Operator Control mode.
|
||||
* @return True if the robot is currently operating in Tele-Op mode as determined by the field controls.
|
||||
*/
|
||||
public boolean isOperatorControl() {
|
||||
return m_ds.isOperatorControl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if new data is available from the driver station.
|
||||
* @return Has new data arrived over the network since the last time this function was called?
|
||||
*/
|
||||
public boolean isNewDataAvailable() {
|
||||
return m_ds.isNewControlData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an alternate "main loop" via startCompetition().
|
||||
*/
|
||||
public abstract void startCompetition();
|
||||
|
||||
public static boolean getBooleanProperty(String name, boolean defaultValue) {
|
||||
String propVal = System.getProperty(name);
|
||||
if (propVal == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (propVal.equalsIgnoreCase("false")) {
|
||||
return false;
|
||||
} else if (propVal.equalsIgnoreCase("true")) {
|
||||
return true;
|
||||
} else {
|
||||
throw new IllegalStateException(propVal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting point for the applications. Starts the OtaServer and then runs
|
||||
* the robot.
|
||||
* @throws javax.microedition.midlet.MIDletStateChangeException
|
||||
*/
|
||||
public static void main(String args[]) { // TODO: expose main to teams?{
|
||||
boolean errorOnExit = false;
|
||||
|
||||
HALLibrary.FRC_NetworkCommunication_Reserve();
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_observeUserProgramStarting();
|
||||
|
||||
UsageReporting.report(tResourceType.kResourceType_Language, tInstances.kLanguage_Java);
|
||||
|
||||
String robotName = "";
|
||||
Enumeration<URL> resources = null;
|
||||
try {
|
||||
resources = RobotBase.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
|
||||
} catch (IOException e) {e.printStackTrace();}
|
||||
while (resources != null && resources.hasMoreElements()) {
|
||||
try {
|
||||
Manifest manifest = new Manifest(resources.nextElement().openStream());
|
||||
robotName = manifest.getMainAttributes().getValue("Robot-Class");
|
||||
} catch (IOException e) {e.printStackTrace();}
|
||||
}
|
||||
|
||||
RobotBase robot;
|
||||
try {
|
||||
robot = (RobotBase) Class.forName(robotName).newInstance();
|
||||
} catch (InstantiationException|IllegalAccessException|ClassNotFoundException e) {
|
||||
System.err.println("WARNING: Robots don't quit!");
|
||||
System.err.println("ERROR: Could not instantiate robot "+robotName+"!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
robot.startCompetition();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
errorOnExit = true;
|
||||
} finally {
|
||||
// startCompetition never returns unless exception occurs....
|
||||
System.err.println("WARNING: Robots don't quit!");
|
||||
if (errorOnExit) {
|
||||
System.err.println("---> The startCompetition() method (or methods called by it) should have handled the exception above.");
|
||||
} else {
|
||||
System.err.println("---> Unexpected return from startCompetition() method.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,760 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can.CANNotInitializedException;
|
||||
import edu.wpi.first.wpilibj.can.CANTimeoutException;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.parsing.IUtility;
|
||||
|
||||
/**
|
||||
* Utility class for handling Robot drive based on a definition of the motor configuration.
|
||||
* The robot drive class handles basic driving for a robot. Currently, 2 and 4 motor standard
|
||||
* drive trains are supported. In the future other drive types like swerve and meccanum might
|
||||
* be implemented. Motor channel numbers are passed supplied on creation of the class. Those are
|
||||
* used for either the drive function (intended for hand created drive code, such as autonomous)
|
||||
* or with the Tank/Arcade functions intended to be used for Operator Control driving.
|
||||
*/
|
||||
public class RobotDrive implements MotorSafety, IUtility {
|
||||
|
||||
protected MotorSafetyHelper m_safetyHelper;
|
||||
|
||||
/**
|
||||
* The location of a motor on the robot for the purpose of driving
|
||||
*/
|
||||
public static class MotorType {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kFrontLeft_val = 0;
|
||||
static final int kFrontRight_val = 1;
|
||||
static final int kRearLeft_val = 2;
|
||||
static final int kRearRight_val = 3;
|
||||
/**
|
||||
* motortype: front left
|
||||
*/
|
||||
public static final MotorType kFrontLeft = new MotorType(kFrontLeft_val);
|
||||
/**
|
||||
* motortype: front right
|
||||
*/
|
||||
public static final MotorType kFrontRight = new MotorType(kFrontRight_val);
|
||||
/**
|
||||
* motortype: rear left
|
||||
*/
|
||||
public static final MotorType kRearLeft = new MotorType(kRearLeft_val);
|
||||
/**
|
||||
* motortype: rear right
|
||||
*/
|
||||
public static final MotorType kRearRight = new MotorType(kRearRight_val);
|
||||
|
||||
private MotorType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
public static final double kDefaultExpirationTime = 0.1;
|
||||
public static final double kDefaultSensitivity = 0.5;
|
||||
public static final double kDefaultMaxOutput = 1.0;
|
||||
protected static final int kMaxNumberOfMotors = 4;
|
||||
protected final int m_invertedMotors[] = new int[4];
|
||||
protected double m_sensitivity;
|
||||
protected double m_maxOutput;
|
||||
protected SpeedController m_frontLeftMotor;
|
||||
protected SpeedController m_frontRightMotor;
|
||||
protected SpeedController m_rearLeftMotor;
|
||||
protected SpeedController m_rearRightMotor;
|
||||
protected boolean m_allocatedSpeedControllers;
|
||||
protected boolean m_isCANInitialized = true;
|
||||
protected static boolean kArcadeRatioCurve_Reported = false;
|
||||
protected static boolean kTank_Reported = false;
|
||||
protected static boolean kArcadeStandard_Reported = false;
|
||||
protected static boolean kMecanumCartesian_Reported = false;
|
||||
protected static boolean kMecanumPolar_Reported = false;
|
||||
|
||||
/** Constructor for RobotDrive with 2 motors specified with channel numbers.
|
||||
* Set up parameters for a two wheel drive system where the
|
||||
* left and right motor pwm channels are specified in the call.
|
||||
* This call assumes Jaguars for controlling the motors.
|
||||
* @param leftMotorChannel The PWM channel number on the default digital module that drives the left motor.
|
||||
* @param rightMotorChannel The PWM channel number on the default digital module that drives the right motor.
|
||||
*/
|
||||
public RobotDrive(final int leftMotorChannel, final int rightMotorChannel) {
|
||||
m_sensitivity = kDefaultSensitivity;
|
||||
m_maxOutput = kDefaultMaxOutput;
|
||||
m_frontLeftMotor = null;
|
||||
m_rearLeftMotor = new Jaguar(leftMotorChannel);
|
||||
m_frontRightMotor = null;
|
||||
m_rearRightMotor = new Jaguar(rightMotorChannel);
|
||||
for (int i = 0; i < kMaxNumberOfMotors; i++) {
|
||||
m_invertedMotors[i] = 1;
|
||||
}
|
||||
m_allocatedSpeedControllers = true;
|
||||
setupMotorSafety();
|
||||
drive(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for RobotDrive with 4 motors specified with channel numbers.
|
||||
* Set up parameters for a four wheel drive system where all four motor
|
||||
* pwm channels are specified in the call.
|
||||
* This call assumes Jaguars for controlling the motors.
|
||||
* @param frontLeftMotor Front left motor channel number on the default digital module
|
||||
* @param rearLeftMotor Rear Left motor channel number on the default digital module
|
||||
* @param frontRightMotor Front right motor channel number on the default digital module
|
||||
* @param rearRightMotor Rear Right motor channel number on the default digital module
|
||||
*/
|
||||
public RobotDrive(final int frontLeftMotor, final int rearLeftMotor,
|
||||
final int frontRightMotor, final int rearRightMotor) {
|
||||
m_sensitivity = kDefaultSensitivity;
|
||||
m_maxOutput = kDefaultMaxOutput;
|
||||
m_rearLeftMotor = new Jaguar(rearLeftMotor);
|
||||
m_rearRightMotor = new Jaguar(rearRightMotor);
|
||||
m_frontLeftMotor = new Jaguar(frontLeftMotor);
|
||||
m_frontRightMotor = new Jaguar(frontRightMotor);
|
||||
for (int i = 0; i < kMaxNumberOfMotors; i++) {
|
||||
m_invertedMotors[i] = 1;
|
||||
}
|
||||
m_allocatedSpeedControllers = true;
|
||||
setupMotorSafety();
|
||||
drive(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for RobotDrive with 2 motors specified as SpeedController objects.
|
||||
* The SpeedController version of the constructor enables programs to use the RobotDrive classes with
|
||||
* subclasses of the SpeedController objects, for example, versions with ramping or reshaping of
|
||||
* the curve to suit motor bias or dead-band elimination.
|
||||
* @param leftMotor The left SpeedController object used to drive the robot.
|
||||
* @param rightMotor the right SpeedController object used to drive the robot.
|
||||
*/
|
||||
public RobotDrive(SpeedController leftMotor, SpeedController rightMotor) {
|
||||
if (leftMotor == null || rightMotor == null) {
|
||||
m_rearLeftMotor = m_rearRightMotor = null;
|
||||
throw new NullPointerException("Null motor provided");
|
||||
}
|
||||
m_frontLeftMotor = null;
|
||||
m_rearLeftMotor = leftMotor;
|
||||
m_frontRightMotor = null;
|
||||
m_rearRightMotor = rightMotor;
|
||||
m_sensitivity = kDefaultSensitivity;
|
||||
m_maxOutput = kDefaultMaxOutput;
|
||||
for (int i = 0; i < kMaxNumberOfMotors; i++) {
|
||||
m_invertedMotors[i] = 1;
|
||||
}
|
||||
m_allocatedSpeedControllers = false;
|
||||
setupMotorSafety();
|
||||
drive(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for RobotDrive with 4 motors specified as SpeedController objects.
|
||||
* Speed controller input version of RobotDrive (see previous comments).
|
||||
* @param rearLeftMotor The back left SpeedController object used to drive the robot.
|
||||
* @param frontLeftMotor The front left SpeedController object used to drive the robot
|
||||
* @param rearRightMotor The back right SpeedController object used to drive the robot.
|
||||
* @param frontRightMotor The front right SpeedController object used to drive the robot.
|
||||
*/
|
||||
public RobotDrive(SpeedController frontLeftMotor, SpeedController rearLeftMotor,
|
||||
SpeedController frontRightMotor, SpeedController rearRightMotor) {
|
||||
if (frontLeftMotor == null || rearLeftMotor == null || frontRightMotor == null || rearRightMotor == null) {
|
||||
m_frontLeftMotor = m_rearLeftMotor = m_frontRightMotor = m_rearRightMotor = null;
|
||||
throw new NullPointerException("Null motor provided");
|
||||
}
|
||||
m_frontLeftMotor = frontLeftMotor;
|
||||
m_rearLeftMotor = rearLeftMotor;
|
||||
m_frontRightMotor = frontRightMotor;
|
||||
m_rearRightMotor = rearRightMotor;
|
||||
m_sensitivity = kDefaultSensitivity;
|
||||
m_maxOutput = kDefaultMaxOutput;
|
||||
for (int i = 0; i < kMaxNumberOfMotors; i++) {
|
||||
m_invertedMotors[i] = 1;
|
||||
}
|
||||
m_allocatedSpeedControllers = false;
|
||||
setupMotorSafety();
|
||||
drive(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive the motors at "speed" and "curve".
|
||||
*
|
||||
* The speed and curve are -1.0 to +1.0 values where 0.0 represents stopped and
|
||||
* not turning. The algorithm for adding in the direction attempts to provide a constant
|
||||
* turn radius for differing speeds.
|
||||
*
|
||||
* This function will most likely be used in an autonomous routine.
|
||||
*
|
||||
* @param outputMagnitude The forward component of the output magnitude to send to the motors.
|
||||
* @param curve The rate of turn, constant for different forward speeds.
|
||||
*/
|
||||
public void drive(double outputMagnitude, double curve) {
|
||||
double leftOutput, rightOutput;
|
||||
|
||||
if(!kArcadeRatioCurve_Reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_RobotDrive, getNumMotors(), tInstances.kRobotDrive_ArcadeRatioCurve);
|
||||
kArcadeRatioCurve_Reported = true;
|
||||
}
|
||||
if (curve < 0) {
|
||||
double value = Math.log(-curve);
|
||||
double ratio = (value - m_sensitivity) / (value + m_sensitivity);
|
||||
if (ratio == 0) {
|
||||
ratio = .0000000001;
|
||||
}
|
||||
leftOutput = outputMagnitude / ratio;
|
||||
rightOutput = outputMagnitude;
|
||||
} else if (curve > 0) {
|
||||
double value = Math.log(curve);
|
||||
double ratio = (value - m_sensitivity) / (value + m_sensitivity);
|
||||
if (ratio == 0) {
|
||||
ratio = .0000000001;
|
||||
}
|
||||
leftOutput = outputMagnitude;
|
||||
rightOutput = outputMagnitude / ratio;
|
||||
} else {
|
||||
leftOutput = outputMagnitude;
|
||||
rightOutput = outputMagnitude;
|
||||
}
|
||||
setLeftRightMotorOutputs(leftOutput, rightOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* drive the robot using two joystick inputs. The Y-axis will be selected from
|
||||
* each Joystick object.
|
||||
* @param leftStick The joystick to control the left side of the robot.
|
||||
* @param rightStick The joystick to control the right side of the robot.
|
||||
*/
|
||||
public void tankDrive(GenericHID leftStick, GenericHID rightStick) {
|
||||
if (leftStick == null || rightStick == null) {
|
||||
throw new NullPointerException("Null HID provided");
|
||||
}
|
||||
tankDrive(leftStick.getY(), rightStick.getY(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* drive the robot using two joystick inputs. The Y-axis will be selected from
|
||||
* each Joystick object.
|
||||
* @param leftStick The joystick to control the left side of the robot.
|
||||
* @param rightStick The joystick to control the right side of the robot.
|
||||
* @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
|
||||
*/
|
||||
public void tankDrive(GenericHID leftStick, GenericHID rightStick, boolean squaredInputs) {
|
||||
if (leftStick == null || rightStick == null) {
|
||||
throw new NullPointerException("Null HID provided");
|
||||
}
|
||||
tankDrive(leftStick.getY(), rightStick.getY(), squaredInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* This function lets you pick the axis to be used on each Joystick object for the left
|
||||
* and right sides of the robot.
|
||||
* @param leftStick The Joystick object to use for the left side of the robot.
|
||||
* @param leftAxis The axis to select on the left side Joystick object.
|
||||
* @param rightStick The Joystick object to use for the right side of the robot.
|
||||
* @param rightAxis The axis to select on the right side Joystick object.
|
||||
*/
|
||||
public void tankDrive(GenericHID leftStick, final int leftAxis,
|
||||
GenericHID rightStick, final int rightAxis) {
|
||||
if (leftStick == null || rightStick == null) {
|
||||
throw new NullPointerException("Null HID provided");
|
||||
}
|
||||
tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* This function lets you pick the axis to be used on each Joystick object for the left
|
||||
* and right sides of the robot.
|
||||
* @param leftStick The Joystick object to use for the left side of the robot.
|
||||
* @param leftAxis The axis to select on the left side Joystick object.
|
||||
* @param rightStick The Joystick object to use for the right side of the robot.
|
||||
* @param rightAxis The axis to select on the right side Joystick object.
|
||||
* @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
|
||||
*/
|
||||
public void tankDrive(GenericHID leftStick, final int leftAxis,
|
||||
GenericHID rightStick, final int rightAxis, boolean squaredInputs) {
|
||||
if (leftStick == null || rightStick == null) {
|
||||
throw new NullPointerException("Null HID provided");
|
||||
}
|
||||
tankDrive(leftStick.getRawAxis(leftAxis), rightStick.getRawAxis(rightAxis), squaredInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* This function lets you directly provide joystick values from any source.
|
||||
* @param leftValue The value of the left stick.
|
||||
* @param rightValue The value of the right stick.
|
||||
* @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
|
||||
*/
|
||||
public void tankDrive(double leftValue, double rightValue, boolean squaredInputs) {
|
||||
|
||||
if(!kTank_Reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_RobotDrive, getNumMotors(), tInstances.kRobotDrive_Tank);
|
||||
kTank_Reported = true;
|
||||
}
|
||||
|
||||
// square the inputs (while preserving the sign) to increase fine control while permitting full power
|
||||
leftValue = limit(leftValue);
|
||||
rightValue = limit(rightValue);
|
||||
if(squaredInputs) {
|
||||
if (leftValue >= 0.0) {
|
||||
leftValue = (leftValue * leftValue);
|
||||
} else {
|
||||
leftValue = -(leftValue * leftValue);
|
||||
}
|
||||
if (rightValue >= 0.0) {
|
||||
rightValue = (rightValue * rightValue);
|
||||
} else {
|
||||
rightValue = -(rightValue * rightValue);
|
||||
}
|
||||
}
|
||||
setLeftRightMotorOutputs(leftValue, rightValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide tank steering using the stored robot configuration.
|
||||
* This function lets you directly provide joystick values from any source.
|
||||
* @param leftValue The value of the left stick.
|
||||
* @param rightValue The value of the right stick.
|
||||
*/
|
||||
public void tankDrive(double leftValue, double rightValue) {
|
||||
tankDrive(leftValue, rightValue, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* Given a single Joystick, the class assumes the Y axis for the move value and the X axis
|
||||
* for the rotate value.
|
||||
* (Should add more information here regarding the way that arcade drive works.)
|
||||
* @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be selected
|
||||
* for forwards/backwards and the X-axis will be selected for rotation rate.
|
||||
* @param squaredInputs If true, the sensitivity will be decreased for small values
|
||||
*/
|
||||
public void arcadeDrive(GenericHID stick, boolean squaredInputs) {
|
||||
// simply call the full-featured arcadeDrive with the appropriate values
|
||||
arcadeDrive(stick.getY(), stick.getX(), squaredInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* Given a single Joystick, the class assumes the Y axis for the move value and the X axis
|
||||
* for the rotate value.
|
||||
* (Should add more information here regarding the way that arcade drive works.)
|
||||
* @param stick The joystick to use for Arcade single-stick driving. The Y-axis will be selected
|
||||
* for forwards/backwards and the X-axis will be selected for rotation rate.
|
||||
*/
|
||||
public void arcadeDrive(GenericHID stick) {
|
||||
this.arcadeDrive(stick, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* Given two joystick instances and two axis, compute the values to send to either two
|
||||
* or four motors.
|
||||
* @param moveStick The Joystick object that represents the forward/backward direction
|
||||
* @param moveAxis The axis on the moveStick object to use for forwards/backwards (typically Y_AXIS)
|
||||
* @param rotateStick The Joystick object that represents the rotation value
|
||||
* @param rotateAxis The axis on the rotation object to use for the rotate right/left (typically X_AXIS)
|
||||
* @param squaredInputs Setting this parameter to true decreases the sensitivity at lower speeds
|
||||
*/
|
||||
public void arcadeDrive(GenericHID moveStick, final int moveAxis,
|
||||
GenericHID rotateStick, final int rotateAxis,
|
||||
boolean squaredInputs) {
|
||||
double moveValue = moveStick.getRawAxis(moveAxis);
|
||||
double rotateValue = rotateStick.getRawAxis(rotateAxis);
|
||||
|
||||
arcadeDrive(moveValue, rotateValue, squaredInputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* Given two joystick instances and two axis, compute the values to send to either two
|
||||
* or four motors.
|
||||
* @param moveStick The Joystick object that represents the forward/backward direction
|
||||
* @param moveAxis The axis on the moveStick object to use for forwards/backwards (typically Y_AXIS)
|
||||
* @param rotateStick The Joystick object that represents the rotation value
|
||||
* @param rotateAxis The axis on the rotation object to use for the rotate right/left (typically X_AXIS)
|
||||
*/
|
||||
public void arcadeDrive(GenericHID moveStick, final int moveAxis,
|
||||
GenericHID rotateStick, final int rotateAxis) {
|
||||
this.arcadeDrive(moveStick, moveAxis, rotateStick, rotateAxis, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* This function lets you directly provide joystick values from any source.
|
||||
* @param moveValue The value to use for forwards/backwards
|
||||
* @param rotateValue The value to use for the rotate right/left
|
||||
* @param squaredInputs If set, decreases the sensitivity at low speeds
|
||||
*/
|
||||
public void arcadeDrive(double moveValue, double rotateValue, boolean squaredInputs) {
|
||||
// local variables to hold the computed PWM values for the motors
|
||||
if(!kArcadeStandard_Reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_RobotDrive, getNumMotors(), tInstances.kRobotDrive_ArcadeStandard);
|
||||
kArcadeStandard_Reported = true;
|
||||
}
|
||||
|
||||
double leftMotorSpeed;
|
||||
double rightMotorSpeed;
|
||||
|
||||
moveValue = limit(moveValue);
|
||||
rotateValue = limit(rotateValue);
|
||||
|
||||
if (squaredInputs) {
|
||||
// square the inputs (while preserving the sign) to increase fine control while permitting full power
|
||||
if (moveValue >= 0.0) {
|
||||
moveValue = (moveValue * moveValue);
|
||||
} else {
|
||||
moveValue = -(moveValue * moveValue);
|
||||
}
|
||||
if (rotateValue >= 0.0) {
|
||||
rotateValue = (rotateValue * rotateValue);
|
||||
} else {
|
||||
rotateValue = -(rotateValue * rotateValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (moveValue > 0.0) {
|
||||
if (rotateValue > 0.0) {
|
||||
leftMotorSpeed = moveValue - rotateValue;
|
||||
rightMotorSpeed = Math.max(moveValue, rotateValue);
|
||||
} else {
|
||||
leftMotorSpeed = Math.max(moveValue, -rotateValue);
|
||||
rightMotorSpeed = moveValue + rotateValue;
|
||||
}
|
||||
} else {
|
||||
if (rotateValue > 0.0) {
|
||||
leftMotorSpeed = -Math.max(-moveValue, rotateValue);
|
||||
rightMotorSpeed = moveValue + rotateValue;
|
||||
} else {
|
||||
leftMotorSpeed = moveValue - rotateValue;
|
||||
rightMotorSpeed = -Math.max(-moveValue, -rotateValue);
|
||||
}
|
||||
}
|
||||
|
||||
setLeftRightMotorOutputs(leftMotorSpeed, rightMotorSpeed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Arcade drive implements single stick driving.
|
||||
* This function lets you directly provide joystick values from any source.
|
||||
* @param moveValue The value to use for fowards/backwards
|
||||
* @param rotateValue The value to use for the rotate right/left
|
||||
*/
|
||||
public void arcadeDrive(double moveValue, double rotateValue) {
|
||||
this.arcadeDrive(moveValue, rotateValue, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive method for Mecanum wheeled robots.
|
||||
*
|
||||
* A method for driving with Mecanum wheeled robots. There are 4 wheels
|
||||
* on the robot, arranged so that the front and back wheels are toed in 45 degrees.
|
||||
* When looking at the wheels from the top, the roller axles should form an X across the robot.
|
||||
*
|
||||
* This is designed to be directly driven by joystick axes.
|
||||
*
|
||||
* @param x The speed that the robot should drive in the X direction. [-1.0..1.0]
|
||||
* @param y The speed that the robot should drive in the Y direction.
|
||||
* This input is inverted to match the forward == -1.0 that joysticks produce. [-1.0..1.0]
|
||||
* @param rotation The rate of rotation for the robot that is completely independent of
|
||||
* the translation. [-1.0..1.0]
|
||||
* @param gyroAngle The current angle reading from the gyro. Use this to implement field-oriented controls.
|
||||
*/
|
||||
public void mecanumDrive_Cartesian(double x, double y, double rotation, double gyroAngle) {
|
||||
if(!kMecanumCartesian_Reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_RobotDrive, getNumMotors(), tInstances.kRobotDrive_MecanumCartesian);
|
||||
kMecanumCartesian_Reported = true;
|
||||
}
|
||||
double xIn = x;
|
||||
double yIn = y;
|
||||
// Negate y for the joystick.
|
||||
yIn = -yIn;
|
||||
// Compenstate for gyro angle.
|
||||
double rotated[] = rotateVector(xIn, yIn, gyroAngle);
|
||||
xIn = rotated[0];
|
||||
yIn = rotated[1];
|
||||
|
||||
double wheelSpeeds[] = new double[kMaxNumberOfMotors];
|
||||
wheelSpeeds[MotorType.kFrontLeft_val] = xIn + yIn + rotation;
|
||||
wheelSpeeds[MotorType.kFrontRight_val] = -xIn + yIn - rotation;
|
||||
wheelSpeeds[MotorType.kRearLeft_val] = -xIn + yIn + rotation;
|
||||
wheelSpeeds[MotorType.kRearRight_val] = xIn + yIn - rotation;
|
||||
|
||||
normalize(wheelSpeeds);
|
||||
|
||||
byte syncGroup = (byte)0x80;
|
||||
|
||||
m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft_val] * m_invertedMotors[MotorType.kFrontLeft_val] * m_maxOutput, syncGroup);
|
||||
m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight_val] * m_invertedMotors[MotorType.kFrontRight_val] * m_maxOutput, syncGroup);
|
||||
m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft_val] * m_invertedMotors[MotorType.kRearLeft_val] * m_maxOutput, syncGroup);
|
||||
m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight_val] * m_invertedMotors[MotorType.kRearRight_val] * m_maxOutput, syncGroup);
|
||||
|
||||
if (m_isCANInitialized) {
|
||||
try {
|
||||
CANJaguar.updateSyncGroup(syncGroup);
|
||||
} catch (CANNotInitializedException e) {
|
||||
m_isCANInitialized = false;
|
||||
} catch (CANTimeoutException e) {}
|
||||
}
|
||||
|
||||
if (m_safetyHelper != null) m_safetyHelper.feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive method for Mecanum wheeled robots.
|
||||
*
|
||||
* A method for driving with Mecanum wheeled robots. There are 4 wheels
|
||||
* on the robot, arranged so that the front and back wheels are toed in 45 degrees.
|
||||
* When looking at the wheels from the top, the roller axles should form an X across the robot.
|
||||
*
|
||||
* @param magnitude The speed that the robot should drive in a given direction.
|
||||
* @param direction The direction the robot should drive in degrees. The direction and maginitute are
|
||||
* independent of the rotation rate.
|
||||
* @param rotation The rate of rotation for the robot that is completely independent of
|
||||
* the magnitute or direction. [-1.0..1.0]
|
||||
*/
|
||||
public void mecanumDrive_Polar(double magnitude, double direction, double rotation) {
|
||||
if(!kMecanumPolar_Reported) {
|
||||
UsageReporting.report(tResourceType.kResourceType_RobotDrive, getNumMotors(), tInstances.kRobotDrive_MecanumPolar);
|
||||
kMecanumPolar_Reported = true;
|
||||
}
|
||||
double frontLeftSpeed, rearLeftSpeed, frontRightSpeed, rearRightSpeed;
|
||||
// Normalized for full power along the Cartesian axes.
|
||||
magnitude = limit(magnitude) * Math.sqrt(2.0);
|
||||
// The rollers are at 45 degree angles.
|
||||
double dirInRad = (direction + 45.0) * 3.14159 / 180.0;
|
||||
double cosD = Math.cos(dirInRad);
|
||||
double sinD = Math.sin(dirInRad);
|
||||
|
||||
double wheelSpeeds[] = new double[kMaxNumberOfMotors];
|
||||
wheelSpeeds[MotorType.kFrontLeft_val] = (sinD * magnitude + rotation);
|
||||
wheelSpeeds[MotorType.kFrontRight_val] = (cosD * magnitude - rotation);
|
||||
wheelSpeeds[MotorType.kRearLeft_val] = (cosD * magnitude + rotation);
|
||||
wheelSpeeds[MotorType.kRearRight_val] = (sinD * magnitude - rotation);
|
||||
|
||||
normalize(wheelSpeeds);
|
||||
|
||||
byte syncGroup = (byte)0x80;
|
||||
|
||||
m_frontLeftMotor.set(wheelSpeeds[MotorType.kFrontLeft_val] * m_invertedMotors[MotorType.kFrontLeft_val] * m_maxOutput, syncGroup);
|
||||
m_frontRightMotor.set(wheelSpeeds[MotorType.kFrontRight_val] * m_invertedMotors[MotorType.kFrontRight_val] * m_maxOutput, syncGroup);
|
||||
m_rearLeftMotor.set(wheelSpeeds[MotorType.kRearLeft_val] * m_invertedMotors[MotorType.kRearLeft_val] * m_maxOutput, syncGroup);
|
||||
m_rearRightMotor.set(wheelSpeeds[MotorType.kRearRight_val] * m_invertedMotors[MotorType.kRearRight_val] * m_maxOutput, syncGroup);
|
||||
|
||||
if (m_isCANInitialized) {
|
||||
try {
|
||||
CANJaguar.updateSyncGroup(syncGroup);
|
||||
} catch (CANNotInitializedException e) {
|
||||
m_isCANInitialized = false;
|
||||
} catch (CANTimeoutException e) {}
|
||||
}
|
||||
|
||||
if (m_safetyHelper != null) m_safetyHelper.feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Holonomic Drive method for Mecanum wheeled robots.
|
||||
*
|
||||
* This is an alias to mecanumDrive_Polar() for backward compatability
|
||||
*
|
||||
* @param magnitude The speed that the robot should drive in a given direction. [-1.0..1.0]
|
||||
* @param direction The direction the robot should drive. The direction and maginitute are
|
||||
* independent of the rotation rate.
|
||||
* @param rotation The rate of rotation for the robot that is completely independent of
|
||||
* the magnitute or direction. [-1.0..1.0]
|
||||
*/
|
||||
void holonomicDrive(float magnitude, float direction, float rotation) {
|
||||
mecanumDrive_Polar(magnitude, direction, rotation);
|
||||
}
|
||||
|
||||
/** Set the speed of the right and left motors.
|
||||
* This is used once an appropriate drive setup function is called such as
|
||||
* twoWheelDrive(). The motors are set to "leftSpeed" and "rightSpeed"
|
||||
* and includes flipping the direction of one side for opposing motors.
|
||||
* @param leftOutput The speed to send to the left side of the robot.
|
||||
* @param rightOutput The speed to send to the right side of the robot.
|
||||
*/
|
||||
public void setLeftRightMotorOutputs(double leftOutput, double rightOutput) {
|
||||
if (m_rearLeftMotor == null || m_rearRightMotor == null) {
|
||||
throw new NullPointerException("Null motor provided");
|
||||
}
|
||||
|
||||
byte syncGroup = (byte)0x80;
|
||||
|
||||
if (m_frontLeftMotor != null) {
|
||||
m_frontLeftMotor.set(limit(leftOutput) * m_invertedMotors[MotorType.kFrontLeft_val] * m_maxOutput, syncGroup);
|
||||
}
|
||||
m_rearLeftMotor.set(limit(leftOutput) * m_invertedMotors[MotorType.kRearLeft_val] * m_maxOutput, syncGroup);
|
||||
|
||||
if (m_frontRightMotor != null) {
|
||||
m_frontRightMotor.set(-limit(rightOutput) * m_invertedMotors[MotorType.kFrontRight_val] * m_maxOutput, syncGroup);
|
||||
}
|
||||
m_rearRightMotor.set(-limit(rightOutput) * m_invertedMotors[MotorType.kRearRight_val] * m_maxOutput, syncGroup);
|
||||
|
||||
if (m_isCANInitialized) {
|
||||
try {
|
||||
CANJaguar.updateSyncGroup(syncGroup);
|
||||
} catch (CANNotInitializedException e) {
|
||||
m_isCANInitialized = false;
|
||||
} catch (CANTimeoutException e) {}
|
||||
}
|
||||
|
||||
if (m_safetyHelper != null) m_safetyHelper.feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit motor values to the -1.0 to +1.0 range.
|
||||
*/
|
||||
protected static double limit(double num) {
|
||||
if (num > 1.0) {
|
||||
return 1.0;
|
||||
}
|
||||
if (num < -1.0) {
|
||||
return -1.0;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize all wheel speeds if the magnitude of any wheel is greater than 1.0.
|
||||
*/
|
||||
protected static void normalize(double wheelSpeeds[]) {
|
||||
double maxMagnitude = Math.abs(wheelSpeeds[0]);
|
||||
int i;
|
||||
for (i=1; i<kMaxNumberOfMotors; i++) {
|
||||
double temp = Math.abs(wheelSpeeds[i]);
|
||||
if (maxMagnitude < temp) maxMagnitude = temp;
|
||||
}
|
||||
if (maxMagnitude > 1.0) {
|
||||
for (i=0; i<kMaxNumberOfMotors; i++) {
|
||||
wheelSpeeds[i] = wheelSpeeds[i] / maxMagnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate a vector in Cartesian space.
|
||||
*/
|
||||
protected static double[] rotateVector(double x, double y, double angle) {
|
||||
double cosA = Math.cos(angle * (3.14159 / 180.0));
|
||||
double sinA = Math.sin(angle * (3.14159 / 180.0));
|
||||
double out[] = new double[2];
|
||||
out[0] = x * cosA - y * sinA;
|
||||
out[1] = x * sinA + y * cosA;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert a motor direction.
|
||||
* This is used when a motor should run in the opposite direction as the drive
|
||||
* code would normally run it. Motors that are direct drive would be inverted, the
|
||||
* drive code assumes that the motors are geared with one reversal.
|
||||
* @param motor The motor index to invert.
|
||||
* @param isInverted True if the motor should be inverted when operated.
|
||||
*/
|
||||
public void setInvertedMotor(MotorType motor, boolean isInverted) {
|
||||
m_invertedMotors[motor.value] = isInverted ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the turning sensitivity.
|
||||
*
|
||||
* This only impacts the drive() entry-point.
|
||||
* @param sensitivity Effectively sets the turning sensitivity (or turn radius for a given value)
|
||||
*/
|
||||
public void setSensitivity(double sensitivity) {
|
||||
m_sensitivity = sensitivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the scaling factor for using RobotDrive with motor controllers in a mode other than PercentVbus.
|
||||
* @param maxOutput Multiplied with the output percentage computed by the drive functions.
|
||||
*/
|
||||
public void setMaxOutput(double maxOutput) {
|
||||
m_maxOutput = maxOutput;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the speed controllers if they were allocated locally
|
||||
*/
|
||||
public void free() {
|
||||
if (m_allocatedSpeedControllers) {
|
||||
if (m_frontLeftMotor != null) {
|
||||
((PWM) m_frontLeftMotor).free();
|
||||
}
|
||||
if (m_frontRightMotor != null) {
|
||||
((PWM) m_frontRightMotor).free();
|
||||
}
|
||||
if (m_rearLeftMotor != null) {
|
||||
((PWM) m_rearLeftMotor).free();
|
||||
}
|
||||
if (m_rearRightMotor != null) {
|
||||
((PWM) m_rearRightMotor).free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setExpiration(double timeout) {
|
||||
m_safetyHelper.setExpiration(timeout);
|
||||
}
|
||||
|
||||
public double getExpiration() {
|
||||
return m_safetyHelper.getExpiration();
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return m_safetyHelper.isAlive();
|
||||
}
|
||||
|
||||
public boolean isSafetyEnabled() {
|
||||
return m_safetyHelper.isSafetyEnabled();
|
||||
}
|
||||
|
||||
public void setSafetyEnabled(boolean enabled) {
|
||||
m_safetyHelper.setSafetyEnabled(enabled);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "Robot Drive";
|
||||
}
|
||||
|
||||
public void stopMotor() {
|
||||
if (m_frontLeftMotor != null) {
|
||||
m_frontLeftMotor.set(0.0);
|
||||
}
|
||||
if (m_frontRightMotor != null) {
|
||||
m_frontRightMotor.set(0.0);
|
||||
}
|
||||
if (m_rearLeftMotor != null) {
|
||||
m_rearLeftMotor.set(0.0);
|
||||
}
|
||||
if (m_rearRightMotor != null) {
|
||||
m_rearRightMotor.set(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMotorSafety() {
|
||||
m_safetyHelper = new MotorSafetyHelper(this);
|
||||
m_safetyHelper.setExpiration(kDefaultExpirationTime);
|
||||
m_safetyHelper.setSafetyEnabled(true);
|
||||
}
|
||||
|
||||
protected int getNumMotors() {
|
||||
int motors = 0;
|
||||
if (m_frontLeftMotor != null) motors++;
|
||||
if (m_frontRightMotor != null) motors++;
|
||||
if (m_rearLeftMotor != null) motors++;
|
||||
if (m_rearRightMotor != null) motors++;
|
||||
return motors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 brad
|
||||
*/
|
||||
public class SafePWM extends PWM implements MotorSafety {
|
||||
|
||||
private MotorSafetyHelper m_safetyHelper;
|
||||
|
||||
/**
|
||||
* Initialize a SafePWM object by setting defaults
|
||||
*/
|
||||
void initSafePWM() {
|
||||
m_safetyHelper = new MotorSafetyHelper(this);
|
||||
m_safetyHelper.setExpiration(0.0);
|
||||
m_safetyHelper.setSafetyEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for a SafePWM object taking a channel number
|
||||
* @param channel The channel number to be used for the underlying PWM object
|
||||
*/
|
||||
public SafePWM(final int channel) {
|
||||
super(channel);
|
||||
initSafePWM();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a SafePWM object taking channel and slot numbers.
|
||||
* @param slot The slot number of the digital module for this PWM object
|
||||
* @param channel The channel number in the module for this PWM object
|
||||
*/
|
||||
public SafePWM(final int slot, final int channel) {
|
||||
super(slot, channel);
|
||||
initSafePWM();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the expiration time for the PWM object
|
||||
* @param timeout The timeout (in seconds) for this motor object
|
||||
*/
|
||||
public void setExpiration(double timeout) {
|
||||
m_safetyHelper.setExpiration(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the expiration time for the PWM object.
|
||||
* @return The expiration time value.
|
||||
*/
|
||||
public double getExpiration() {
|
||||
return m_safetyHelper.getExpiration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the PWM object is currently alive or stopped due to a timeout.
|
||||
* @return a bool value that is true if the motor has NOT timed out and should still
|
||||
* be running.
|
||||
*/
|
||||
public boolean isAlive() {
|
||||
return m_safetyHelper.isAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the motor associated with this PWM object.
|
||||
* This is called by the MotorSafetyHelper object when it has a timeout for this PWM and needs to
|
||||
* stop it from running.
|
||||
*/
|
||||
public void stopMotor() {
|
||||
disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if motor safety is enabled for this object
|
||||
* @return True if motor safety is enforced for this object
|
||||
*/
|
||||
public boolean isSafetyEnabled() {
|
||||
return m_safetyHelper.isSafetyEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed the MotorSafety timer.
|
||||
* This method is called by the subclass motor whenever it updates its speed, thereby reseting
|
||||
* the timeout value.
|
||||
*/
|
||||
public void Feed() {
|
||||
m_safetyHelper.feed();
|
||||
}
|
||||
|
||||
public void setSafetyEnabled(boolean enabled) {
|
||||
m_safetyHelper.setSafetyEnabled(enabled);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "PWM "+getChannel()+" on module "+getModuleNumber();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
setRaw(kPwmDisabled);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
|
||||
/**
|
||||
* The base interface for objects that can be sent over the network
|
||||
* through network tables.
|
||||
*/
|
||||
public interface Sendable {
|
||||
/**
|
||||
* Initializes a table for this sendable object.
|
||||
* @param subtable The table to put the values in.
|
||||
*/
|
||||
public void initTable(ITable subtable);
|
||||
|
||||
/**
|
||||
* @return the table that is currently associated with the sendable
|
||||
*/
|
||||
public ITable getTable();
|
||||
|
||||
/**
|
||||
* @return the string representation of the named data type that will be used by the smart dashboard for this sendable
|
||||
*/
|
||||
public String getSmartDashboardType();
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.hal.HALLibrary;
|
||||
|
||||
/**
|
||||
* Base class for all sensors.
|
||||
* Stores most recent status information as well as containing utility functions for checking
|
||||
* channels and error processing.
|
||||
*
|
||||
* XXX: Wait, there's no exception thrown if we try to allocate a non-existent module? It that behavior correct?
|
||||
*/
|
||||
public abstract class SensorBase { // TODO: Refactor
|
||||
|
||||
// TODO: Move this to the HAL
|
||||
|
||||
/**
|
||||
* Ticks per microsecond
|
||||
*/
|
||||
public static final int kSystemClockTicksPerMicrosecond = 40;
|
||||
/**
|
||||
* Number of digital channels per digital sidecar
|
||||
*/
|
||||
public static final int kDigitalChannels = 14;
|
||||
/**
|
||||
* Number of digital modules
|
||||
* XXX: This number is incorrect. We need to find the correct number.
|
||||
*/
|
||||
public static final int kDigitalModules = 2;
|
||||
/**
|
||||
* Number of analog channels per module
|
||||
*/
|
||||
public static final int kAnalogChannels = 8;
|
||||
/**
|
||||
* Number of analog modules
|
||||
*/
|
||||
public static final int kAnalogModules = 2;
|
||||
/**
|
||||
* Number of solenoid channels per module
|
||||
*/
|
||||
public static final int kSolenoidChannels = 8;
|
||||
/**
|
||||
* Number of analog modules
|
||||
*/
|
||||
public static final int kSolenoidModules = 2;
|
||||
/**
|
||||
* Number of PWM channels per sidecar
|
||||
*/
|
||||
public static final int kPwmChannels = 10;
|
||||
/**
|
||||
* Number of relay channels per sidecar
|
||||
*/
|
||||
public static final int kRelayChannels = 8;
|
||||
|
||||
private static int m_defaultAnalogModule = 1;
|
||||
private static int m_defaultDigitalModule = 1;
|
||||
private static int m_defaultSolenoidModule = 1;
|
||||
|
||||
/**
|
||||
* Creates an instance of the sensor base and gets an FPGA handle
|
||||
*/
|
||||
public SensorBase() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default Digital Module.
|
||||
* This sets the default digital module to use for objects that are created without
|
||||
* specifying the digital module in the constructor. The default module is initialized
|
||||
* to the first module in the chassis.
|
||||
*
|
||||
* @param moduleNumber The number of the digital module to use.
|
||||
*/
|
||||
public static void setDefaultDigitalModule(final int moduleNumber) {
|
||||
checkDigitalModule(moduleNumber);
|
||||
SensorBase.m_defaultDigitalModule = moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default Analog module.
|
||||
* This sets the default analog module to use for objects that are created without
|
||||
* specifying the analog module in the constructor. The default module is initialized
|
||||
* to the first module in the chassis.
|
||||
*
|
||||
* @param moduleNumber The number of the analog module to use.
|
||||
*/
|
||||
public static void setDefaultAnalogModule(final int moduleNumber) {
|
||||
checkAnalogModule(moduleNumber);
|
||||
SensorBase.m_defaultAnalogModule = moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default location for the Solenoid (9472) module.
|
||||
*
|
||||
* @param moduleNumber The number of the solenoid module to use.
|
||||
*/
|
||||
public static void setDefaultSolenoidModule(final int moduleNumber) {
|
||||
checkSolenoidModule(moduleNumber);
|
||||
SensorBase.m_defaultSolenoidModule = moduleNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital module number is valid.
|
||||
* Module numbers are 1 or 2 (they are no longer real cRIO slots).
|
||||
*
|
||||
* @param moduleNumber The digital module module number to check.
|
||||
*/
|
||||
protected static void checkDigitalModule(final int moduleNumber) {
|
||||
if(HALLibrary.checkDigitalModule((byte) moduleNumber) != 1)
|
||||
System.err.println("Digital module " + moduleNumber + " is not present.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital module number is valid.
|
||||
* Module numbers are 1 or 2 (they are no longer real cRIO slots).
|
||||
*
|
||||
* @param moduleNumber The digital module module number to check.
|
||||
*/
|
||||
protected static void checkRelayModule(final int moduleNumber) {
|
||||
checkDigitalModule(moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital module number is valid.
|
||||
* Module numbers are 1 or 2 (they are no longer real cRIO slots).
|
||||
*
|
||||
* @param moduleNumber The digital module module number to check.
|
||||
*/
|
||||
protected static void checkPWMModule(final int moduleNumber) {
|
||||
checkDigitalModule(moduleNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the analog module number is valid.
|
||||
* Module numbers are 1 or 2 (they are no longer real cRIO slots).
|
||||
*
|
||||
* @param moduleNumber The analog module module number to check.
|
||||
*/
|
||||
protected static void checkAnalogModule(final int moduleNumber) {
|
||||
if(HALLibrary.checkAnalogModule((byte) (moduleNumber - 1)) != 0) {
|
||||
System.err.println("Analog module " + moduleNumber + " is not present.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the solenoid module is correct.
|
||||
* Module numbers are 1 or 2 (they are no longer real cRIO slots).
|
||||
*
|
||||
* @param moduleNumber The solenoid module module number to check.
|
||||
*/
|
||||
protected static void checkSolenoidModule(final int moduleNumber) {
|
||||
if(HALLibrary.checkSolenoidModule((byte) (moduleNumber - 1)) != 0) {
|
||||
System.err.println("Solenoid module " + moduleNumber + " is not present.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital channel number is valid.
|
||||
* Verify that the channel number is one of the legal channel numbers. Channel numbers are
|
||||
* 1-based.
|
||||
*
|
||||
* @param channel The channel number to check.
|
||||
*/
|
||||
protected static void checkDigitalChannel(final int channel) {
|
||||
if (channel <= 0 || channel > kDigitalChannels) {
|
||||
System.err.println("Requested digital channel number is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital channel number is valid.
|
||||
* Verify that the channel number is one of the legal channel numbers. Channel numbers are
|
||||
* 1-based.
|
||||
*
|
||||
* @param channel The channel number to check.
|
||||
*/
|
||||
protected static void checkRelayChannel(final int channel) {
|
||||
if (channel <= 0 || channel > kRelayChannels) {
|
||||
System.err.println("Requested relay channel number is out of range.");
|
||||
throw new IndexOutOfBoundsException("Requested relay channel number is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the digital channel number is valid.
|
||||
* Verify that the channel number is one of the legal channel numbers. Channel numbers are
|
||||
* 1-based.
|
||||
*
|
||||
* @param channel The channel number to check.
|
||||
*/
|
||||
protected static void checkPWMChannel(final int channel) {
|
||||
if (channel <= 0 || channel > kPwmChannels) {
|
||||
System.err.println("Requested PWM channel number is out of range.");
|
||||
throw new IndexOutOfBoundsException("Requested PWM channel number is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the analog channel number is value.
|
||||
* Verify that the analog channel number is one of the legal channel numbers. Channel numbers
|
||||
* are 1-based.
|
||||
*
|
||||
* @param channel The channel number to check.
|
||||
*/
|
||||
protected static void checkAnalogChannel(final int channel) {
|
||||
if (channel <= 0 || channel > kAnalogChannels) {
|
||||
System.err.println("Requested analog channel number is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the solenoid channel number is within limits. Channel numbers
|
||||
* are 1-based.
|
||||
*
|
||||
* @param channel The channel number to check.
|
||||
*/
|
||||
protected static void checkSolenoidChannel(final int channel) {
|
||||
if (channel <= 0 || channel > kSolenoidChannels) {
|
||||
System.err.println("Requested solenoid channel number is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of the default analog module.
|
||||
*
|
||||
* @return The number of the default analog module.
|
||||
*/
|
||||
public static int getDefaultAnalogModule() {
|
||||
return SensorBase.m_defaultAnalogModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of the default analog module.
|
||||
*
|
||||
* @return The number of the default analog module.
|
||||
*/
|
||||
public static int getDefaultDigitalModule() {
|
||||
return SensorBase.m_defaultDigitalModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of the default analog module.
|
||||
*
|
||||
* @return The number of the default analog module.
|
||||
*/
|
||||
public static int getDefaultSolenoidModule() {
|
||||
return SensorBase.m_defaultSolenoidModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the resources used by this object
|
||||
*/
|
||||
public void free() {}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.io.UnsupportedEncodingException;
|
||||
|
||||
import edu.wpi.first.wpilibj.visa.Visa;
|
||||
import edu.wpi.first.wpilibj.visa.VisaException;
|
||||
|
||||
/**
|
||||
* Driver for the RS-232 serial port on the cRIO.
|
||||
*
|
||||
* The current implementation uses the VISA formatted I/O mode. This means that
|
||||
* all traffic goes through the formatted buffers. This allows the intermingled
|
||||
* use of print(), readString(), and the raw buffer accessors read() and write().
|
||||
*
|
||||
* More information can be found in the NI-VISA User Manual here:
|
||||
* http://www.ni.com/pdf/manuals/370423a.pdf
|
||||
* and the NI-VISA Programmer's Reference Manual here:
|
||||
* http://www.ni.com/pdf/manuals/370132c.pdf
|
||||
*/
|
||||
public class SerialPort {
|
||||
|
||||
private int m_resourceManagerHandle;
|
||||
private int m_portHandle;
|
||||
|
||||
/**
|
||||
* Represents the parity to use for serial communications
|
||||
*/
|
||||
public static class Parity {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kNone_val = 0;
|
||||
static final int kOdd_val = 1;
|
||||
static final int kEven_val = 2;
|
||||
static final int kMark_val = 3;
|
||||
static final int kSpace_val = 4;
|
||||
/**
|
||||
* parity: Use no parity
|
||||
*/
|
||||
public static final Parity kNone = new Parity(kNone_val);
|
||||
/**
|
||||
* parity: Use odd parity
|
||||
*/
|
||||
public static final Parity kOdd = new Parity(kOdd_val);
|
||||
/**
|
||||
* parity: Use even parity
|
||||
*/
|
||||
public static final Parity kEven = new Parity(kEven_val);
|
||||
/**
|
||||
* parity: Use mark parity
|
||||
*/
|
||||
public static final Parity kMark = new Parity(kMark_val);
|
||||
/**
|
||||
* parity: Use space parity
|
||||
*/
|
||||
public static final Parity kSpace = new Parity((kSpace_val));
|
||||
|
||||
private Parity(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the number of stop bits to use for Serial Communication
|
||||
*/
|
||||
public static class StopBits {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kOne_val = 10;
|
||||
static final int kOnePointFive_val = 15;
|
||||
static final int kTwo_val = 20;
|
||||
/**
|
||||
* stopBits: use 1
|
||||
*/
|
||||
public static final StopBits kOne = new StopBits(kOne_val);
|
||||
/**
|
||||
* stopBits: use 1.5
|
||||
*/
|
||||
public static final StopBits kOnePointFive = new StopBits(kOnePointFive_val);
|
||||
/**
|
||||
* stopBits: use 2
|
||||
*/
|
||||
public static final StopBits kTwo = new StopBits(kTwo_val);
|
||||
|
||||
private StopBits(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents what type of flow control to use for serial communication
|
||||
*/
|
||||
public static class FlowControl {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kNone_val = 0;
|
||||
static final int kXonXoff_val = 1;
|
||||
static final int kRtsCts_val = 2;
|
||||
static final int kDtrDsr_val = 4;
|
||||
/**
|
||||
* flowControl: use none
|
||||
*/
|
||||
public static final FlowControl kNone = new FlowControl(kNone_val);
|
||||
/**
|
||||
* flowcontrol: use on/off
|
||||
*/
|
||||
public static final FlowControl kXonXoff = new FlowControl(kXonXoff_val);
|
||||
/**
|
||||
* flowcontrol: use rts cts
|
||||
*/
|
||||
public static final FlowControl kRtsCts = new FlowControl(kRtsCts_val);
|
||||
/**
|
||||
* flowcontrol: use dts dsr
|
||||
*/
|
||||
public static final FlowControl kDtrDsr = new FlowControl(kDtrDsr_val);
|
||||
|
||||
private FlowControl(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents which type of buffer mode to use when writing to a serial port
|
||||
*/
|
||||
public static class WriteBufferMode {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kFlushOnAccess_val = 1;
|
||||
static final int kFlushWhenFull_val = 2;
|
||||
/**
|
||||
* Flush on access
|
||||
*/
|
||||
public static final WriteBufferMode kFlushOnAccess = new WriteBufferMode(kFlushOnAccess_val);
|
||||
/**
|
||||
* Flush when full
|
||||
*/
|
||||
public static final WriteBufferMode kFlushWhenFull = new WriteBufferMode(kFlushWhenFull_val);
|
||||
|
||||
private WriteBufferMode(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Serial Port class.
|
||||
*
|
||||
* @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud.
|
||||
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
|
||||
* @param parity Select the type of parity checking to use.
|
||||
* @param stopBits The number of stop bits to use as defined by the enum StopBits.
|
||||
*/
|
||||
public SerialPort(final int baudRate, final int dataBits, Parity parity, StopBits stopBits) throws VisaException {
|
||||
m_resourceManagerHandle = 0;
|
||||
m_portHandle = 0;
|
||||
|
||||
m_resourceManagerHandle = Visa.viOpenDefaultRM();
|
||||
|
||||
m_portHandle = Visa.viOpen(m_resourceManagerHandle, "ASRL1::INSTR", 0, 0);
|
||||
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_BAUD, baudRate);
|
||||
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_DATA_BITS, dataBits);
|
||||
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_PARITY, parity.value);
|
||||
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_STOP_BITS, stopBits.value);
|
||||
|
||||
// Set the default read buffer size to 1 to return bytes immediately
|
||||
setReadBufferSize(1);
|
||||
|
||||
// Set the default timeout to 5 seconds.
|
||||
setTimeout(5.0f);
|
||||
|
||||
// Don't wait until the buffer is full to transmit.
|
||||
setWriteBufferMode(WriteBufferMode.kFlushOnAccess);
|
||||
|
||||
disableTermination();
|
||||
|
||||
//viInstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this);
|
||||
//viEnableEvent(m_portHandle, VI_EVENT_IO_COMPLETION, VI_HNDLR, VI_NULL);
|
||||
|
||||
// XXX: Resource Reporting Fixes
|
||||
// UsageReporting.report(UsageReporting.kResourceType_SerialPort,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Serial Port class. Defaults to one stop bit.
|
||||
*
|
||||
* @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud.
|
||||
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
|
||||
* @param parity Select the type of parity checking to use.
|
||||
*/
|
||||
public SerialPort(final int baudRate, final int dataBits, Parity parity) throws VisaException {
|
||||
this(baudRate, dataBits, parity, StopBits.kOne);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Serial Port class. Defaults to no parity and one
|
||||
* stop bit.
|
||||
*
|
||||
* @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud.
|
||||
* @param dataBits The number of data bits per transfer. Valid values are between 5 and 8 bits.
|
||||
*/
|
||||
public SerialPort(final int baudRate, final int dataBits) throws VisaException {
|
||||
this(baudRate, dataBits, Parity.kNone, StopBits.kOne);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Serial Port class. Defaults to 8 databits,
|
||||
* no parity, and one stop bit.
|
||||
*
|
||||
* @param baudRate The baud rate to configure the serial port. The cRIO-9074 supports up to 230400 Baud.
|
||||
*/
|
||||
public SerialPort(final int baudRate) throws VisaException {
|
||||
this(baudRate, 8, Parity.kNone, StopBits.kOne);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public void free() {
|
||||
//viUninstallHandler(m_portHandle, VI_EVENT_IO_COMPLETION, ioCompleteHandler, this);
|
||||
Visa.viClose(m_portHandle);
|
||||
Visa.viClose(m_resourceManagerHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of flow control to enable on this port.
|
||||
*
|
||||
* By default, flow control is disabled.
|
||||
* @param flowControl
|
||||
*/
|
||||
public void setFlowControl(FlowControl flowControl) throws VisaException {
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_FLOW_CNTRL, flowControl.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable termination and specify the termination character.
|
||||
*
|
||||
* Termination is currently only implemented for receive.
|
||||
* When the the terminator is received, the read() or readString() will return
|
||||
* fewer bytes than requested, stopping after the terminator.
|
||||
*
|
||||
* @param terminator The character to use for termination.
|
||||
*/
|
||||
public void enableTermination(char terminator) throws VisaException {
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, true);
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR, terminator);
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_TERMCHAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable termination and specify the termination character.
|
||||
*
|
||||
* Termination is currently only implemented for receive.
|
||||
* When the the terminator is received, the read() or readString() will return
|
||||
* fewer bytes than requested, stopping after the terminator.
|
||||
*
|
||||
* The default terminator is '\n'
|
||||
*/
|
||||
public void enableTermination() throws VisaException {
|
||||
this.enableTermination('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable termination behavior.
|
||||
*/
|
||||
public void disableTermination() throws VisaException {
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TERMCHAR_EN, false);
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_END_IN, Visa.VI_ASRL_END_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes currently available to read from the serial port.
|
||||
*
|
||||
* @return The number of bytes available to read.
|
||||
*/
|
||||
public int getBytesReceived() throws VisaException {
|
||||
return Visa.viGetAttribute(m_portHandle, Visa.VI_ATTR_ASRL_AVAIL_NUM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output formatted text to the serial port.
|
||||
*
|
||||
* @deprecated use write(string.getBytes()) instead
|
||||
* @bug All pointer-based parameters seem to return an error.
|
||||
*
|
||||
* @param write A string to write
|
||||
*/
|
||||
public void print(String write) throws VisaException {
|
||||
Visa.viVPrintf(m_portHandle, write);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a string out of the buffer. Reads the entire contents of the buffer
|
||||
*
|
||||
* @return The read string
|
||||
*/
|
||||
public String readString() throws VisaException {
|
||||
return readString(getBytesReceived());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a string out of the buffer. Reads the entire contents of the buffer
|
||||
*
|
||||
* @param count the number of characters to read into the string
|
||||
* @return The read string
|
||||
*/
|
||||
public String readString(int count) throws VisaException {
|
||||
byte[] out = Visa.viBufRead(m_portHandle, count);
|
||||
try {
|
||||
return new String(out, 0, count, "US-ASCII");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
ex.printStackTrace();
|
||||
return new String();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read raw bytes out of the buffer.
|
||||
*
|
||||
* @param count The maximum number of bytes to read.
|
||||
* @return An array of the read bytes
|
||||
*/
|
||||
public byte[] read(final int count) throws VisaException {
|
||||
return Visa.viBufRead(m_portHandle, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write raw bytes to the buffer.
|
||||
*
|
||||
* @param buffer the buffer to read the bytes from.
|
||||
* @param count The maximum number of bytes to write.
|
||||
* @return The number of bytes actually written into the port.
|
||||
*/
|
||||
public int write(byte[] buffer, int count) throws VisaException {
|
||||
return Visa.viBufWrite(m_portHandle, buffer, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the timeout of the serial port.
|
||||
*
|
||||
* This defines the timeout for transactions with the hardware.
|
||||
* It will affect reads if less bytes are available than the
|
||||
* read buffer size (defaults to 1) and very large writes.
|
||||
*
|
||||
* @param timeout The number of seconds to to wait for I/O.
|
||||
*/
|
||||
public void setTimeout(double timeout) throws VisaException {
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_TMO_VALUE, (int) (timeout * 1e3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the size of the input buffer.
|
||||
*
|
||||
* Specify the amount of data that can be stored before data
|
||||
* from the device is returned to Read. If you want
|
||||
* data that is received to be returned immediately, set this to 1.
|
||||
*
|
||||
* It the buffer is not filled before the read timeout expires, all
|
||||
* data that has been received so far will be returned.
|
||||
*
|
||||
* @param size The read buffer size.
|
||||
*/
|
||||
void setReadBufferSize(int size) throws VisaException {
|
||||
Visa.viSetBuf(m_portHandle, Visa.VI_READ_BUF, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the size of the output buffer.
|
||||
*
|
||||
* Specify the amount of data that can be stored before being
|
||||
* transmitted to the device.
|
||||
*
|
||||
* @param size The write buffer size.
|
||||
*/
|
||||
void setWriteBufferSize(int size) throws VisaException {
|
||||
Visa.viSetBuf(m_portHandle, Visa.VI_WRITE_BUF, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the flushing behavior of the output buffer.
|
||||
*
|
||||
* When set to kFlushOnAccess, data is synchronously written to the serial port
|
||||
* after each call to either print() or write().
|
||||
*
|
||||
* When set to kFlushWhenFull, data will only be written to the serial port when
|
||||
* the buffer is full or when flush() is called.
|
||||
*
|
||||
* @param mode The write buffer mode.
|
||||
*/
|
||||
public void setWriteBufferMode(WriteBufferMode mode) throws VisaException {
|
||||
Visa.viSetAttribute(m_portHandle, Visa.VI_ATTR_WR_BUF_OPER_MODE, mode.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force the output buffer to be written to the port.
|
||||
*
|
||||
* This is used when setWriteBufferMode() is set to kFlushWhenFull to force a
|
||||
* flush before the buffer is full.
|
||||
*/
|
||||
public void flush() throws VisaException {
|
||||
Visa.viFlush(m_portHandle, Visa.VI_WRITE_BUF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the serial port driver to a known state.
|
||||
*
|
||||
* Empty the transmit and receive buffers in the device and formatted I/O.
|
||||
*/
|
||||
public void reset() throws VisaException {
|
||||
Visa.viClear(m_portHandle);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.parsing.IDevice;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
|
||||
/**
|
||||
* Standard hobby style servo.
|
||||
*
|
||||
* The range parameters default to the appropriate values for the Hitec HS-322HD servo provided
|
||||
* in the FIRST Kit of Parts in 2008.
|
||||
*/
|
||||
public class Servo extends PWM implements IDevice {
|
||||
|
||||
private static final double kMaxServoAngle = 170.0;
|
||||
private static final double kMinServoAngle = 0.0;
|
||||
|
||||
/**
|
||||
* Common initialization code called by all constructors.
|
||||
*
|
||||
* InitServo() assigns defaults for the period multiplier for the servo PWM control signal, as
|
||||
* well as the minimum and maximum PWM values supported by the servo.
|
||||
*/
|
||||
private void initServo() {
|
||||
setBounds(2.27, 0, 0, 0, .743);
|
||||
setPeriodMultiplier(PeriodMultiplier.k4X);
|
||||
|
||||
LiveWindow.addActuator("Servo", getModuleNumber(), getChannel(), this);
|
||||
UsageReporting.report(tResourceType.kResourceType_Servo, getChannel(), getModuleNumber()-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assumes the default digital module.
|
||||
*
|
||||
* @param channel The PWM channel on the digital module to which the servo is attached.
|
||||
*/
|
||||
public Servo(final int channel) {
|
||||
super(channel);
|
||||
initServo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that specifies the digital module.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged into.
|
||||
* @param channel The PWM channel on the digital module to which the servo is attached.
|
||||
*/
|
||||
public Servo(final int slot, final int channel) {
|
||||
super(slot, channel);
|
||||
initServo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the servo position.
|
||||
*
|
||||
* Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right.
|
||||
*
|
||||
* @param value Position from 0.0 to 1.0.
|
||||
*/
|
||||
public void set(double value) {
|
||||
setPosition(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the servo position.
|
||||
*
|
||||
* Servo values range from 0.0 to 1.0 corresponding to the range of full left to full right.
|
||||
*
|
||||
* @return Position from 0.0 to 1.0.
|
||||
*/
|
||||
public double get() {
|
||||
return getPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the servo angle.
|
||||
*
|
||||
* Assume that the servo angle is linear with respect to the PWM value (big assumption, need to test).
|
||||
*
|
||||
* Servo angles that are out of the supported range of the servo simply "saturate" in that direction
|
||||
* In other words, if the servo has a range of (X degrees to Y degrees) than angles of less than X
|
||||
* result in an angle of X being set and angles of more than Y degrees result in an angle of Y being set.
|
||||
*
|
||||
* @param degrees The angle in degrees to set the servo.
|
||||
*/
|
||||
public void setAngle(double degrees) {
|
||||
if (degrees < kMinServoAngle) {
|
||||
degrees = kMinServoAngle;
|
||||
} else if (degrees > kMaxServoAngle) {
|
||||
degrees = kMaxServoAngle;
|
||||
}
|
||||
|
||||
setPosition(((degrees - kMinServoAngle)) / getServoAngleRange());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the servo angle.
|
||||
*
|
||||
* Assume that the servo angle is linear with respect to the PWM value (big assumption, need to test).
|
||||
* @return The angle in degrees to which the servo is set.
|
||||
*/
|
||||
public double getAngle() {
|
||||
return getPosition() * getServoAngleRange() + kMinServoAngle;
|
||||
}
|
||||
|
||||
private double getServoAngleRange() {
|
||||
return kMaxServoAngle - kMinServoAngle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Servo";
|
||||
}
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void updateTable() {
|
||||
if (m_table != null) {
|
||||
m_table.putNumber("Value", get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value, boolean bln) {
|
||||
set(((Double) value).doubleValue());
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
|
||||
/**
|
||||
* A simple robot base class that knows the standard FRC competition states (disabled, autonomous, or operator controlled).
|
||||
*
|
||||
* You can build a simple robot program off of this by overriding the
|
||||
* robotinit(), disabled(), autonomous() and operatorControl() methods. The startCompetition() method will calls these methods
|
||||
* (sometimes repeatedly).
|
||||
* depending on the state of the competition.
|
||||
*
|
||||
* Alternatively you can override the robotMain() method and manage all aspects of the robot yourself.
|
||||
*/
|
||||
public class SimpleRobot extends RobotBase {
|
||||
|
||||
private boolean m_robotMainOverridden;
|
||||
|
||||
/**
|
||||
* Create a new SimpleRobot
|
||||
*/
|
||||
public SimpleRobot() {
|
||||
super();
|
||||
m_robotMainOverridden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Robot-wide initialization code should go here.
|
||||
*
|
||||
* Users should override this method for default Robot-wide initialization which will
|
||||
* be called when the robot is first powered on.
|
||||
*
|
||||
* Called exactly 1 time when the competition starts.
|
||||
*/
|
||||
protected void robotInit() {
|
||||
System.out.println("Default robotInit() method running, consider providing your own");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disabled should go here.
|
||||
* Users should overload this method to run code that should run while the field is
|
||||
* disabled.
|
||||
*
|
||||
* Called once each time the robot enters the disabled state.
|
||||
*/
|
||||
protected void disabled() {
|
||||
System.out.println("Default disabled() method running, consider providing your own");
|
||||
}
|
||||
|
||||
/**
|
||||
* Autonomous should go here.
|
||||
* Users should add autonomous code to this method that should run while the field is
|
||||
* in the autonomous period.
|
||||
*
|
||||
* Called once each time the robot enters the autonomous state.
|
||||
*/
|
||||
public void autonomous() {
|
||||
System.out.println("Default autonomous() method running, consider providing your own");
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator control (tele-operated) code should go here.
|
||||
* Users should add Operator Control code to this method that should run while the field is
|
||||
* in the Operator Control (tele-operated) period.
|
||||
*
|
||||
* Called once each time the robot enters the operator-controlled state.
|
||||
*/
|
||||
public void operatorControl() {
|
||||
System.out.println("Default operatorControl() method running, consider providing your own");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test code should go here.
|
||||
* Users should add test code to this method that should run while the robot is in test mode.
|
||||
*/
|
||||
public void test() {
|
||||
System.out.println("Default test() method running, consider providing your own");
|
||||
}
|
||||
|
||||
/**
|
||||
* Robot main program for free-form programs.
|
||||
*
|
||||
* This should be overridden by user subclasses if the intent is to not use the autonomous() and
|
||||
* operatorControl() methods. In that case, the program is responsible for sensing when to run
|
||||
* the autonomous and operator control functions in their program.
|
||||
*
|
||||
* This method will be called immediately after the constructor is called. If it has not been
|
||||
* overridden by a user subclass (i.e. the default version runs), then the robotInit(), disabled(), autonomous() and
|
||||
* operatorControl() methods will be called.
|
||||
*/
|
||||
public void robotMain() {
|
||||
m_robotMainOverridden = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a competition.
|
||||
* This code tracks the order of the field starting to ensure that everything happens
|
||||
* in the right order. Repeatedly run the correct method, either Autonomous or OperatorControl
|
||||
* when the robot is enabled. After running the correct method, wait for some state to change,
|
||||
* either the other mode starts or the robot is disabled. Then go back and wait for the robot
|
||||
* to be enabled again.
|
||||
*/
|
||||
public void startCompetition() {
|
||||
UsageReporting.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Simple);
|
||||
|
||||
robotMain();
|
||||
if (!m_robotMainOverridden) {
|
||||
// first and one-time initialization
|
||||
LiveWindow.setEnabled(false);
|
||||
robotInit();
|
||||
|
||||
while (true) {
|
||||
if (isDisabled()) {
|
||||
m_ds.InDisabled(true);
|
||||
disabled();
|
||||
m_ds.InDisabled(false);
|
||||
while (isDisabled()) {
|
||||
Timer.delay(0.01);
|
||||
}
|
||||
} else if (isAutonomous()) {
|
||||
m_ds.InAutonomous(true);
|
||||
autonomous();
|
||||
m_ds.InAutonomous(false);
|
||||
while (isAutonomous() && !isDisabled()) {
|
||||
Timer.delay(0.01);
|
||||
}
|
||||
} else if (isTest()) {
|
||||
LiveWindow.setEnabled(true);
|
||||
m_ds.InTest(true);
|
||||
test();
|
||||
m_ds.InTest(false);
|
||||
while (isTest() && isEnabled())
|
||||
Timer.delay(0.01);
|
||||
LiveWindow.setEnabled(false);
|
||||
} else {
|
||||
m_ds.InOperatorControl(true);
|
||||
operatorControl();
|
||||
m_ds.InOperatorControl(false);
|
||||
while (isOperatorControl() && !isDisabled()) {
|
||||
Timer.delay(0.01);
|
||||
}
|
||||
}
|
||||
} /* while loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* A Skeleton object to be used with Kinect data from the
|
||||
* FRC Kinect server on the DriverStation
|
||||
* @author koconnor
|
||||
*/
|
||||
public class Skeleton {
|
||||
|
||||
/**
|
||||
* The TrackState of the skeleton
|
||||
*/
|
||||
public static class tTrackState {
|
||||
|
||||
/** The integer value representing this enumeration. */
|
||||
public final int value;
|
||||
|
||||
protected static final int kNotTracked_val = 0;
|
||||
protected static final int kPositionOnly_val = 1;
|
||||
protected static final int kTracked_val = 2;
|
||||
|
||||
/** TrackState: Not Tracked */
|
||||
public static final tTrackState kNotTracked = new tTrackState(kNotTracked_val);
|
||||
/** TrackState: Position Only */
|
||||
public static final tTrackState kPositionOnly = new tTrackState(kPositionOnly_val);
|
||||
/** TrackState: Tracked */
|
||||
public static final tTrackState kTracked = new tTrackState(kTracked_val);
|
||||
|
||||
private tTrackState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Joint TrackingState
|
||||
*/
|
||||
public static class tJointTrackingState {
|
||||
/** The integer value representing this enumeration. */
|
||||
public final int value;
|
||||
|
||||
protected static final int kNotTracked_val = 0;
|
||||
protected static final int kInferred_val = 1;
|
||||
protected static final int kTracked_val = 2;
|
||||
|
||||
/** Joint TrackingState: Not Tracked */
|
||||
public static final tJointTrackingState kNotTracked = new tJointTrackingState(kNotTracked_val);
|
||||
/** Joint TrackingState: Inferred */
|
||||
public static final tJointTrackingState kInferred = new tJointTrackingState(kInferred_val);
|
||||
/** Joint TrackingState: Tracked */
|
||||
public static final tJointTrackingState kTracked = new tJointTrackingState(kTracked_val);
|
||||
|
||||
private tJointTrackingState(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An individual Joint from Kinect data
|
||||
*/
|
||||
public class Joint {
|
||||
protected float x, y, z;
|
||||
protected byte trackingState;
|
||||
|
||||
Joint() {
|
||||
x = y = z = 0;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
public tJointTrackingState getTrackingState() {
|
||||
switch(trackingState) {
|
||||
case 1:
|
||||
return tJointTrackingState.kInferred;
|
||||
case 2:
|
||||
return tJointTrackingState.kTracked;
|
||||
default:
|
||||
return tJointTrackingState.kNotTracked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class used to index the joints in a (@link Skeleton)
|
||||
*/
|
||||
public static class tJointTypes {
|
||||
public final int value;
|
||||
|
||||
protected static final int kHipCenter_val = 0;
|
||||
protected static final int kSpine_val = 1;
|
||||
protected static final int kShoulderCenter_val = 2;
|
||||
protected static final int kHead_val = 3;
|
||||
protected static final int kShoulderLeft_val = 4;
|
||||
protected static final int kElbowLeft_val = 5;
|
||||
protected static final int kWristLeft_val = 6;
|
||||
protected static final int kHandLeft_val = 7;
|
||||
protected static final int kShoulderRight_val = 8;
|
||||
protected static final int kElbowRight_val = 9;
|
||||
protected static final int kWristRight_val = 10;
|
||||
protected static final int kHandRight_val = 11;
|
||||
protected static final int kHipLeft_val = 12;
|
||||
protected static final int kKneeLeft_val = 13;
|
||||
protected static final int kAnkleLeft_val = 14;
|
||||
protected static final int kFootLeft_val = 15;
|
||||
protected static final int kHipRight_val = 16;
|
||||
protected static final int kKneeRight_val = 17;
|
||||
protected static final int kAnkleRight_val = 18;
|
||||
protected static final int kFootRight_val = 19;
|
||||
protected static final int kCount_val = 20;
|
||||
|
||||
public static final tJointTypes kHipCenter = new tJointTypes(kHipCenter_val);
|
||||
public static final tJointTypes kSpine = new tJointTypes(kSpine_val);
|
||||
public static final tJointTypes kShoulderCenter = new tJointTypes(kShoulderCenter_val);
|
||||
public static final tJointTypes kHead = new tJointTypes(kHead_val);
|
||||
public static final tJointTypes kShoulderLeft = new tJointTypes(kShoulderLeft_val);
|
||||
public static final tJointTypes kElbowLeft = new tJointTypes(kElbowLeft_val);
|
||||
public static final tJointTypes kWristLeft = new tJointTypes(kWristLeft_val);
|
||||
public static final tJointTypes kHandLeft = new tJointTypes(kHandLeft_val);
|
||||
public static final tJointTypes kShoulderRight = new tJointTypes(kShoulderRight_val);
|
||||
public static final tJointTypes kElbowRight = new tJointTypes(kElbowRight_val);
|
||||
public static final tJointTypes kWristRight = new tJointTypes(kWristRight_val);
|
||||
public static final tJointTypes kHandRight = new tJointTypes(kHandRight_val);
|
||||
public static final tJointTypes kHipLeft = new tJointTypes(kHipLeft_val);
|
||||
public static final tJointTypes kKneeLeft = new tJointTypes(kKneeLeft_val);
|
||||
public static final tJointTypes kAnkleLeft = new tJointTypes(kAnkleLeft_val);
|
||||
public static final tJointTypes kFootLeft = new tJointTypes(kFootLeft_val);
|
||||
public static final tJointTypes kHipRight = new tJointTypes(kHipRight_val);
|
||||
public static final tJointTypes kKneeRight = new tJointTypes(kKneeRight_val);
|
||||
public static final tJointTypes kAnkleRight = new tJointTypes(kAnkleRight_val);
|
||||
public static final tJointTypes kFootRight = new tJointTypes(kFootRight_val);
|
||||
public static final tJointTypes kCount = new tJointTypes(kCount_val);
|
||||
|
||||
private tJointTypes(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Joint GetHandRight() {
|
||||
return skeleton[tJointTypes.kHandRight.value];
|
||||
}
|
||||
public Joint GetHandLeft() {
|
||||
return skeleton[tJointTypes.kHandLeft.value];
|
||||
}
|
||||
public Joint GetWristRight() {
|
||||
return skeleton[tJointTypes.kWristRight.value];
|
||||
}
|
||||
public Joint GetWristLeft() {
|
||||
return skeleton[tJointTypes.kWristLeft.value];
|
||||
}
|
||||
public Joint GetElbowLeft() {
|
||||
return skeleton[tJointTypes.kElbowLeft.value];
|
||||
}
|
||||
public Joint GetElbowRight() {
|
||||
return skeleton[tJointTypes.kElbowRight.value];
|
||||
}
|
||||
public Joint GetShoulderLeft() {
|
||||
return skeleton[tJointTypes.kShoulderLeft.value];
|
||||
}
|
||||
public Joint GetShoulderRight() {
|
||||
return skeleton[tJointTypes.kShoulderRight.value];
|
||||
}
|
||||
public Joint GetShoulderCenter() {
|
||||
return skeleton[tJointTypes.kShoulderCenter.value];
|
||||
}
|
||||
public Joint GetHead() {
|
||||
return skeleton[tJointTypes.kHead.value];
|
||||
}
|
||||
public Joint GetSpine() {
|
||||
return skeleton[tJointTypes.kSpine.value];
|
||||
}
|
||||
public Joint GetHipCenter() {
|
||||
return skeleton[tJointTypes.kHipCenter.value];
|
||||
}
|
||||
public Joint GetHipRight() {
|
||||
return skeleton[tJointTypes.kHipRight.value];
|
||||
}
|
||||
public Joint GetHipLeft() {
|
||||
return skeleton[tJointTypes.kHipLeft.value];
|
||||
}
|
||||
public Joint GetKneeLeft() {
|
||||
return skeleton[tJointTypes.kKneeLeft.value];
|
||||
}
|
||||
public Joint GetKneeRight() {
|
||||
return skeleton[tJointTypes.kKneeRight.value];
|
||||
}
|
||||
public Joint GetAnkleLeft() {
|
||||
return skeleton[tJointTypes.kAnkleLeft.value];
|
||||
}
|
||||
public Joint GetAnkleRight() {
|
||||
return skeleton[tJointTypes.kAnkleRight.value];
|
||||
}
|
||||
public Joint GetFootLeft() {
|
||||
return skeleton[tJointTypes.kFootLeft.value];
|
||||
}
|
||||
public Joint GetFootRight() {
|
||||
return skeleton[tJointTypes.kFootRight.value];
|
||||
}
|
||||
public Joint GetJoint(tJointTypes index) {
|
||||
return skeleton[index.value];
|
||||
}
|
||||
|
||||
public tTrackState GetTrackState() {
|
||||
return trackState;
|
||||
}
|
||||
|
||||
Skeleton() {
|
||||
for(int i=0; i<20; i++) {
|
||||
skeleton[i] = new Joint();
|
||||
}
|
||||
}
|
||||
|
||||
protected Joint[] skeleton = new Joint[20];
|
||||
protected tTrackState trackState;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.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.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import edu.wpi.first.wpilibj.util.AllocationException;
|
||||
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
|
||||
|
||||
/**
|
||||
* Solenoid class for running high voltage Digital Output (9472 module).
|
||||
*
|
||||
* The Solenoid class is typically used for pneumatics solenoids, but could be used
|
||||
* for any device within the current spec of the 9472 module.
|
||||
*/
|
||||
public class Solenoid extends SolenoidBase implements LiveWindowSendable {
|
||||
|
||||
private int m_channel; ///< The channel on the module to control.
|
||||
private Pointer m_port;
|
||||
|
||||
/**
|
||||
* Common function to implement constructor behavior.
|
||||
*/
|
||||
private synchronized void initSolenoid() {
|
||||
checkSolenoidModule(m_moduleNumber);
|
||||
checkSolenoidChannel(m_channel);
|
||||
|
||||
try {
|
||||
m_allocated.allocate((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1);
|
||||
} catch (CheckedAllocationException e) {
|
||||
throw new AllocationException(
|
||||
"Solenoid channel " + m_channel + " on module " + m_moduleNumber + " is already allocated");
|
||||
}
|
||||
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_port = HALLibrary.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
|
||||
HALUtil.checkStatus(status);
|
||||
HALLibrary.initializeSolenoidPort(m_port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
|
||||
LiveWindow.addActuator("Solenoid", m_moduleNumber, m_channel, this);
|
||||
UsageReporting.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param channel The channel on the module to control.
|
||||
*/
|
||||
public Solenoid(final int channel) {
|
||||
super(getDefaultSolenoidModule());
|
||||
m_channel = channel;
|
||||
initSolenoid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moduleNumber The module number of the solenoid module to use.
|
||||
* @param channel The channel on the module to control.
|
||||
*/
|
||||
public Solenoid(final int moduleNumber, final int channel) {
|
||||
super(moduleNumber);
|
||||
m_channel = channel;
|
||||
initSolenoid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public synchronized void free() {
|
||||
m_allocated.free((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a solenoid.
|
||||
*
|
||||
* @param on Turn the solenoid output off or on.
|
||||
*/
|
||||
public void set(boolean on) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
HALLibrary.setSolenoid(m_port, (byte) (on ? 1 : 0), status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current value of the solenoid.
|
||||
*
|
||||
* @return The current value of the solenoid.
|
||||
*/
|
||||
public boolean get() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
boolean value = HALLibrary.getSolenoid(m_port, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Solenoid";
|
||||
}
|
||||
private ITable m_table;
|
||||
private ITableListener m_table_listener;
|
||||
|
||||
/**
|
||||
* {@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.putBoolean("Value", get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
set(false); // Stop for safety
|
||||
m_table_listener = new ITableListener() {
|
||||
public void valueChanged(ITable itable, String key, Object value, boolean bln) {
|
||||
set(((Boolean) value).booleanValue());
|
||||
}
|
||||
};
|
||||
m_table.addTableListener("Value", m_table_listener, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
set(false); // Stop for safety
|
||||
// TODO: Broken, should only remove the listener from "Value" only.
|
||||
m_table.removeTableListener(m_table_listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.parsing.IDeviceController;
|
||||
|
||||
/**
|
||||
* SolenoidBase class is the common base class for the Solenoid and
|
||||
* DoubleSolenoid classes.
|
||||
*/
|
||||
public abstract class SolenoidBase extends SensorBase implements IDeviceController {
|
||||
|
||||
private Pointer[] m_ports;
|
||||
protected int m_moduleNumber; ///< The number of the solenoid module being used.
|
||||
// XXX: Move this to be both HAL calls
|
||||
protected Resource m_allocated = new Resource(HALLibrary.solenoid_kNumDO7_0Elements.get() * SensorBase.kSolenoidChannels);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param moduleNumber The number of the solenoid module to use.
|
||||
*/
|
||||
public SolenoidBase(final int moduleNumber) {
|
||||
m_moduleNumber = moduleNumber;
|
||||
m_ports = new Pointer[SensorBase.kSolenoidChannels];
|
||||
for (int i = 0; i < SensorBase.kSolenoidChannels; i++) {
|
||||
Pointer port = HALLibrary.getPortWithModule((byte) moduleNumber, (byte) (i+1));
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
m_ports[i] = HALLibrary.initializeSolenoidPort(port, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a solenoid.
|
||||
*
|
||||
* @param value The value you want to set on the module.
|
||||
* @param mask The channels you want to be affected.
|
||||
*/
|
||||
protected synchronized void set(int value, int mask) {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kSolenoidChannels; i++) {
|
||||
int local_mask = 1 << i;
|
||||
if ((mask & local_mask) != 0)
|
||||
HALLibrary.setSolenoid(m_ports[i], (byte) (value & local_mask), status);
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all 8 solenoids from the module used by this solenoid as a single byte
|
||||
*
|
||||
* @return The current value of all 8 solenoids on this module.
|
||||
*/
|
||||
public byte getAll() {
|
||||
byte value = 0;
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
for (int i = 0; i < SensorBase.kSolenoidChannels; i++) {
|
||||
value |= HALLibrary.getSolenoid(m_ports[i], status) << i;
|
||||
}
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all 8 solenoids in the default solenoid module as a single byte
|
||||
*
|
||||
* @return The current value of all 8 solenoids on the default module.
|
||||
*/
|
||||
public static byte getAllFromDefaultModule() {
|
||||
return getAllFromModule(getDefaultSolenoidModule());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read all 8 solenoids in the specified solenoid module as a single byte
|
||||
*
|
||||
* @return The current value of all 8 solenoids on the specified module.
|
||||
*/
|
||||
public static byte getAllFromModule(int moduleNumber) {
|
||||
checkSolenoidModule(moduleNumber);
|
||||
throw new RuntimeException("Not supported right now.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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;
|
||||
|
||||
/**
|
||||
* Interface for speed controlling devices.
|
||||
*/
|
||||
public interface SpeedController extends PIDOutput {
|
||||
|
||||
/**
|
||||
* Common interface for getting the current set speed of a speed controller.
|
||||
*
|
||||
* @return The current set speed. Value is between -1.0 and 1.0.
|
||||
*/
|
||||
double get();
|
||||
|
||||
/**
|
||||
* Common interface for setting the speed of a speed controller.
|
||||
*
|
||||
* @param speed The speed to set. Value should be between -1.0 and 1.0.
|
||||
* @param syncGroup The update group to add this Set() to, pending UpdateSyncGroup(). If 0, update immediately.
|
||||
*/
|
||||
void set(double speed, byte syncGroup);
|
||||
|
||||
/**
|
||||
* Common interface for setting the speed of a speed controller.
|
||||
*
|
||||
* @param speed The speed to set. Value should be between -1.0 and 1.0.
|
||||
*/
|
||||
void set(double speed);
|
||||
|
||||
/**
|
||||
* Disable the speed controller
|
||||
*/
|
||||
void disable();
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.parsing.IDeviceController;
|
||||
|
||||
/**
|
||||
* CTRE Talon Speed Controller
|
||||
*/
|
||||
public class Talon extends SafePWM implements SpeedController, IDeviceController {
|
||||
|
||||
/**
|
||||
* Common initialization code called by all constructors.
|
||||
*
|
||||
* Note that the Talon uses the following bounds for PWM values. These values should work reasonably well for
|
||||
* most controllers, but if users experience issues such as asymmetric behavior around
|
||||
* the deadband or inability to saturate the controller in either direction, calibration is recommended.
|
||||
* The calibration procedure can be found in the Talon User Manual available from CTRE.
|
||||
*
|
||||
* - 2.037ms = full "forward"
|
||||
* - 1.539ms = the "high end" of the deadband range
|
||||
* - 1.513ms = center of the deadband range (off)
|
||||
* - 1.487ms = the "low end" of the deadband range
|
||||
* - .989ms = full "reverse"
|
||||
*/
|
||||
private void initTalon() {
|
||||
setBounds(2.037, 1.539, 1.513, 1.487, .989);
|
||||
setPeriodMultiplier(PeriodMultiplier.k2X);
|
||||
setRaw(m_centerPwm);
|
||||
|
||||
LiveWindow.addActuator("Talon", getModuleNumber(), getChannel(), this);
|
||||
UsageReporting.report(tResourceType.kResourceType_Talon, getChannel(), getModuleNumber()-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assumes the default digital module.
|
||||
*
|
||||
* @param channel The PWM channel on the digital module that the Victor is attached to.
|
||||
*/
|
||||
public Talon(final int channel) {
|
||||
super(channel);
|
||||
initTalon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that specifies the digital module.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged into.
|
||||
* @param channel The PWM channel on the digital module that the Victor is attached to.
|
||||
*/
|
||||
public Talon(final int slot, final int channel) {
|
||||
super(slot, channel);
|
||||
initTalon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* @deprecated For compatibility with CANJaguar
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed to set. Value should be between -1.0 and 1.0.
|
||||
* @param syncGroup The update group to add this Set() to, pending UpdateSyncGroup(). If 0, update immediately.
|
||||
*/
|
||||
public void set(double speed, byte syncGroup) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed value between -1.0 and 1.0 to set.
|
||||
*/
|
||||
public void set(double speed) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recently set value of the PWM.
|
||||
*
|
||||
* @return The most recently set value for the PWM between -1.0 and 1.0.
|
||||
*/
|
||||
public double get() {
|
||||
return getSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the PID value as seen in the PIDOutput base object.
|
||||
*
|
||||
* @param output Write out the PWM value as was found in the PIDController
|
||||
*/
|
||||
public void pidWrite(double output) {
|
||||
set(output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.parsing.IUtility;
|
||||
|
||||
/**
|
||||
* Timer objects measure accumulated time in milliseconds.
|
||||
* The timer object functions like a stopwatch. It can be started, stopped, and cleared. When the
|
||||
* timer is running its value counts up in milliseconds. When stopped, the timer holds the current
|
||||
* value. The implementation simply records the time when started and subtracts the current time
|
||||
* whenever the value is requested.
|
||||
*/
|
||||
public class Timer implements IUtility {
|
||||
|
||||
private long m_startTime;
|
||||
private double m_accumulatedTime;
|
||||
private boolean m_running;
|
||||
|
||||
/**
|
||||
* Pause the thread for a specified time. Pause the execution of the
|
||||
* thread for a specified period of time given in seconds. Motors will
|
||||
* continue to run at their last assigned values, and sensors will continue
|
||||
* to update. Only the task containing the wait will pause until the wait
|
||||
* time is expired.
|
||||
*
|
||||
* @param seconds Length of time to pause
|
||||
*/
|
||||
public static void delay(final double seconds) {
|
||||
try {
|
||||
Thread.sleep((long) (seconds * 1e3));
|
||||
} catch (final InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system clock time in microseconds. Return the time from the
|
||||
* FPGA hardware clock in microseconds since the FPGA started.
|
||||
*
|
||||
* @deprecated Use getFPGATimestamp instead.
|
||||
* @return Robot running time in microseconds.
|
||||
*/
|
||||
public static long getUsClock() {
|
||||
return Utility.getFPGATime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system clock time in milliseconds. Return the time from the
|
||||
* FPGA hardware clock in milliseconds since the FPGA started.
|
||||
*
|
||||
* @deprecated Use getFPGATimestamp instead.
|
||||
* @return Robot running time in milliseconds.
|
||||
*/
|
||||
static long getMsClock() {
|
||||
return getUsClock() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system clock time in seconds. Return the time from the
|
||||
* FPGA hardware clock in seconds since the FPGA started.
|
||||
*
|
||||
* @return Robot running time in seconds.
|
||||
*/
|
||||
public static double getFPGATimestamp() {
|
||||
return Utility.getFPGATime() / 1000000.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new timer object.
|
||||
* Create a new timer object and reset the time to zero. The timer is initially not running and
|
||||
* must be started.
|
||||
*/
|
||||
public Timer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current time from the timer. If the clock is running it is derived from
|
||||
* the current system clock the start time stored in the timer class. If the clock
|
||||
* is not running, then return the time when it was last stopped.
|
||||
*
|
||||
* @return Current time value for this timer in seconds
|
||||
*/
|
||||
public synchronized double get() {
|
||||
if (m_running) {
|
||||
return ((double) ((getMsClock() - m_startTime) + m_accumulatedTime)) / 1000.0;
|
||||
} else {
|
||||
return m_accumulatedTime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the timer by setting the time to 0.
|
||||
* Make the timer startTime the current time so new requests will be relative now
|
||||
*/
|
||||
public synchronized void reset() {
|
||||
m_accumulatedTime = 0;
|
||||
m_startTime = getMsClock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the timer running.
|
||||
* Just set the running flag to true indicating that all time requests should be
|
||||
* relative to the system clock.
|
||||
*/
|
||||
public synchronized void start() {
|
||||
m_startTime = getMsClock();
|
||||
m_running = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the timer.
|
||||
* This computes the time as of now and clears the running flag, causing all
|
||||
* subsequent time requests to be read from the accumulated time rather than
|
||||
* looking at the system clock.
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
final double temp = get();
|
||||
m_accumulatedTime = temp;
|
||||
m_running = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.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;
|
||||
|
||||
/**
|
||||
* Ultrasonic rangefinder class. The Ultrasonic rangefinder measures absolute
|
||||
* distance based on the round-trip time of a ping generated by the controller.
|
||||
* These sensors use two transducers, a speaker and a microphone both tuned to
|
||||
* the ultrasonic range. A common ultrasonic sensor, the Daventech SRF04
|
||||
* requires a short pulse to be generated on a digital channel. This causes the
|
||||
* chirp to be emmitted. A second line becomes high as the ping is transmitted
|
||||
* and goes low when the echo is received. The time that the line is high
|
||||
* determines the round trip distance (time of flight).
|
||||
*/
|
||||
public class Ultrasonic extends SensorBase implements PIDSource, ISensor,
|
||||
LiveWindowSendable {
|
||||
|
||||
/**
|
||||
* The units to return when PIDGet is called
|
||||
*/
|
||||
public static class Unit {
|
||||
|
||||
/**
|
||||
* The integer value representing this enumeration
|
||||
*/
|
||||
public final int value;
|
||||
static final int kInches_val = 0;
|
||||
static final int kMillimeters_val = 1;
|
||||
/**
|
||||
* Use inches for PIDGet
|
||||
*/
|
||||
public static final Unit kInches = new Unit(kInches_val);
|
||||
/**
|
||||
* Use millimeters for PIDGet
|
||||
*/
|
||||
public static final Unit kMillimeter = new Unit(kMillimeters_val);
|
||||
|
||||
private Unit(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static final double kPingTime = 10 * 1e-6; // /< Time (sec) for the
|
||||
// ping trigger pulse.
|
||||
private static final int kPriority = 90; // /< Priority that the ultrasonic
|
||||
// round robin task runs.
|
||||
private static final double kMaxUltrasonicTime = 0.1; // /< Max time (ms)
|
||||
// between readings.
|
||||
private static final double kSpeedOfSoundInchesPerSec = 1130.0 * 12.0;
|
||||
private static Ultrasonic m_firstSensor = null; // head of the ultrasonic
|
||||
// sensor list
|
||||
private static boolean m_automaticEnabled = false; // automatic round robin
|
||||
// mode
|
||||
private DigitalInput m_echoChannel = null;
|
||||
private DigitalOutput m_pingChannel = null;
|
||||
private boolean m_allocatedChannels;
|
||||
private boolean m_enabled = false;
|
||||
private Counter m_counter = null;
|
||||
private Ultrasonic m_nextSensor = null;
|
||||
private static Thread m_task = null; // task doing the round-robin automatic
|
||||
// sensing
|
||||
private Unit m_units;
|
||||
private static int m_instances = 0;
|
||||
|
||||
/**
|
||||
* Background task that goes through the list of ultrasonic sensors and
|
||||
* pings each one in turn. The counter is configured to read the timing of
|
||||
* the returned echo pulse.
|
||||
*
|
||||
* DANGER WILL ROBINSON, DANGER WILL ROBINSON: This code runs as a task and
|
||||
* assumes that none of the ultrasonic sensors will change while it's
|
||||
* running. If one does, then this will certainly break. Make sure to
|
||||
* disable automatic mode before changing anything with the sensors!!
|
||||
*/
|
||||
private class UltrasonicChecker extends Thread {
|
||||
|
||||
public synchronized void run() {
|
||||
Ultrasonic u = null;
|
||||
while (m_automaticEnabled) {
|
||||
if (u == null) {
|
||||
u = m_firstSensor;
|
||||
}
|
||||
if (u == null) {
|
||||
return;
|
||||
}
|
||||
if (u.isEnabled()) {
|
||||
u.m_pingChannel.pulse(m_pingChannel.m_channel,
|
||||
(float) kPingTime); // do the ping
|
||||
}
|
||||
u = u.m_nextSensor;
|
||||
Timer.delay(.1); // wait for ping to return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Ultrasonic Sensor. This is the common code that
|
||||
* initializes the ultrasonic sensor given that there are two digital I/O
|
||||
* channels allocated. If the system was running in automatic mode (round
|
||||
* robin) when the new sensor is added, it is stopped, the sensor is added,
|
||||
* then automatic mode is restored.
|
||||
*/
|
||||
private synchronized void initialize() {
|
||||
if (m_task == null) {
|
||||
m_task = new UltrasonicChecker();
|
||||
}
|
||||
boolean originalMode = m_automaticEnabled;
|
||||
setAutomaticMode(false); // kill task when adding a new sensor
|
||||
m_nextSensor = m_firstSensor;
|
||||
m_firstSensor = this;
|
||||
|
||||
m_counter = new Counter(m_echoChannel); // set up counter for this
|
||||
// sensor
|
||||
m_counter.setMaxPeriod(1.0);
|
||||
m_counter.setSemiPeriodMode(true);
|
||||
m_counter.reset();
|
||||
m_counter.start();
|
||||
m_enabled = true; // make it available for round robin scheduling
|
||||
setAutomaticMode(originalMode);
|
||||
|
||||
m_instances++;
|
||||
UsageReporting.report(tResourceType.kResourceType_Ultrasonic,
|
||||
m_instances);
|
||||
LiveWindow.addSensor("Ultrasonic", m_echoChannel.getModuleForRouting(),
|
||||
m_echoChannel.getChannel(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Ultrasonic Sensor using the default module.
|
||||
* This is designed to supchannel the Daventech SRF04 and Vex ultrasonic
|
||||
* sensors. This constructor assumes that both digital I/O channels are in
|
||||
* the default digital module.
|
||||
*
|
||||
* @param pingChannel
|
||||
* The digital output channel that sends the pulse to initiate
|
||||
* the sensor sending the ping.
|
||||
* @param echoChannel
|
||||
* The digital input channel that receives the echo. The length
|
||||
* of time that the echo is high represents the round trip time
|
||||
* of the ping, and the distance.
|
||||
* @param units
|
||||
* The units returned in either kInches or kMilliMeters
|
||||
*/
|
||||
public Ultrasonic(final int pingChannel, final int echoChannel, Unit units) {
|
||||
m_pingChannel = new DigitalOutput(pingChannel);
|
||||
m_echoChannel = new DigitalInput(echoChannel);
|
||||
m_allocatedChannels = true;
|
||||
m_units = units;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Ultrasonic Sensor using the default module.
|
||||
* This is designed to supchannel the Daventech SRF04 and Vex ultrasonic
|
||||
* sensors. This constructor assumes that both digital I/O channels are in
|
||||
* the default digital module. Default unit is inches.
|
||||
*
|
||||
* @param pingChannel
|
||||
* The digital output channel that sends the pulse to initiate
|
||||
* the sensor sending the ping.
|
||||
* @param echoChannel
|
||||
* The digital input channel that receives the echo. The length
|
||||
* of time that the echo is high represents the round trip time
|
||||
* of the ping, and the distance.
|
||||
*/
|
||||
public Ultrasonic(final int pingChannel, final int echoChannel) {
|
||||
this(pingChannel, echoChannel, Unit.kInches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of an Ultrasonic Sensor from a DigitalInput for the
|
||||
* echo channel and a DigitalOutput for the ping channel.
|
||||
*
|
||||
* @param pingChannel
|
||||
* The digital output object that starts the sensor doing a ping.
|
||||
* Requires a 10uS pulse to start.
|
||||
* @param echoChannel
|
||||
* The digital input object that times the return pulse to
|
||||
* determine the range.
|
||||
* @param units
|
||||
* The units returned in either kInches or kMilliMeters
|
||||
*/
|
||||
public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel,
|
||||
Unit units) {
|
||||
if (pingChannel == null || echoChannel == null) {
|
||||
throw new NullPointerException("Null Channel Provided");
|
||||
}
|
||||
m_allocatedChannels = false;
|
||||
m_pingChannel = pingChannel;
|
||||
m_echoChannel = echoChannel;
|
||||
m_units = units;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of an Ultrasonic Sensor from a DigitalInput for the
|
||||
* echo channel and a DigitalOutput for the ping channel. Default unit is
|
||||
* inches.
|
||||
*
|
||||
* @param pingChannel
|
||||
* The digital output object that starts the sensor doing a ping.
|
||||
* Requires a 10uS pulse to start.
|
||||
* @param echoChannel
|
||||
* The digital input object that times the return pulse to
|
||||
* determine the range.
|
||||
*/
|
||||
public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel) {
|
||||
this(pingChannel, echoChannel, Unit.kInches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Ultrasonic sensor using specified modules. This
|
||||
* is designed to supchannel the Daventech SRF04 and Vex ultrasonic sensors.
|
||||
* This constructors takes the channel and module slot for each of the
|
||||
* required digital I/O channels.
|
||||
*
|
||||
* @param pingSlot
|
||||
* The digital module that the pingChannel is in.
|
||||
* @param pingChannel
|
||||
* The digital output channel that sends the pulse to initiate
|
||||
* the sensor sending the ping.
|
||||
* @param echoSlot
|
||||
* The digital module that the echoChannel is in.
|
||||
* @param echoChannel
|
||||
* The digital input channel that receives the echo. The length
|
||||
* of time that the echo is high represents the round trip time
|
||||
* of the ping, and the distance.
|
||||
* @param units
|
||||
* The units returned in either kInches or kMilliMeters
|
||||
*/
|
||||
public Ultrasonic(final int pingSlot, final int pingChannel,
|
||||
final int echoSlot, final int echoChannel, Unit units) {
|
||||
m_pingChannel = new DigitalOutput(pingSlot, pingChannel);
|
||||
m_echoChannel = new DigitalInput(echoSlot, echoChannel);
|
||||
m_allocatedChannels = true;
|
||||
m_units = units;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Ultrasonic sensor using specified modules. This
|
||||
* is designed to supchannel the Daventech SRF04 and Vex ultrasonic sensors.
|
||||
* This constructors takes the channel and module slot for each of the
|
||||
* required digital I/O channels. Defualt unit is inches.
|
||||
*
|
||||
* @param pingSlot
|
||||
* The digital module that the pingChannel is in.
|
||||
* @param pingChannel
|
||||
* The digital output channel that sends the pulse to initiate
|
||||
* the sensor sending the ping.
|
||||
* @param echoSlot
|
||||
* The digital module that the echoChannel is in.
|
||||
* @param echoChannel
|
||||
* The digital input channel that receives the echo. The length
|
||||
* of time that the echo is high represents the round trip time
|
||||
* of the ping, and the distance.
|
||||
*/
|
||||
public Ultrasonic(final int pingSlot, final int pingChannel,
|
||||
final int echoSlot, final int echoChannel) {
|
||||
this(pingSlot, pingChannel, echoSlot, echoChannel, Unit.kInches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for the ultrasonic sensor. Delete the instance of the
|
||||
* ultrasonic sensor by freeing the allocated digital channels. If the
|
||||
* system was in automatic mode (round robin), then it is stopped, then
|
||||
* started again after this sensor is removed (provided this wasn't the last
|
||||
* sensor).
|
||||
*/
|
||||
public synchronized void free() {
|
||||
boolean wasAutomaticMode = m_automaticEnabled;
|
||||
setAutomaticMode(false);
|
||||
if (m_allocatedChannels) {
|
||||
if (m_pingChannel != null) {
|
||||
m_pingChannel.free();
|
||||
}
|
||||
if (m_echoChannel != null) {
|
||||
m_echoChannel.free();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_counter != null) {
|
||||
m_counter.free();
|
||||
m_counter = null;
|
||||
}
|
||||
|
||||
m_pingChannel = null;
|
||||
m_echoChannel = null;
|
||||
|
||||
if (this == m_firstSensor) {
|
||||
m_firstSensor = m_nextSensor;
|
||||
if (m_firstSensor == null) {
|
||||
setAutomaticMode(false);
|
||||
}
|
||||
} else {
|
||||
for (Ultrasonic s = m_firstSensor; s != null; s = s.m_nextSensor) {
|
||||
if (this == s.m_nextSensor) {
|
||||
s.m_nextSensor = s.m_nextSensor.m_nextSensor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_firstSensor != null && wasAutomaticMode) {
|
||||
setAutomaticMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn Automatic mode on/off. When in Automatic mode, all sensors will fire
|
||||
* in round robin, waiting a set time between each sensor.
|
||||
*
|
||||
* @param enabling
|
||||
* Set to true if round robin scheduling should start for all the
|
||||
* ultrasonic sensors. This scheduling method assures that the
|
||||
* sensors are non-interfering because no two sensors fire at the
|
||||
* same time. If another scheduling algorithm is preffered, it
|
||||
* can be implemented by pinging the sensors manually and waiting
|
||||
* for the results to come back.
|
||||
*/
|
||||
public void setAutomaticMode(boolean enabling) {
|
||||
if (enabling == m_automaticEnabled) {
|
||||
return; // ignore the case of no change
|
||||
}
|
||||
m_automaticEnabled = enabling;
|
||||
|
||||
if (enabling) {
|
||||
// enabling automatic mode.
|
||||
// Clear all the counters so no data is valid
|
||||
for (Ultrasonic u = m_firstSensor; u != null; u = u.m_nextSensor) {
|
||||
u.m_counter.reset();
|
||||
}
|
||||
// Start round robin task
|
||||
m_task.start();
|
||||
} else {
|
||||
// disabling automatic mode. Wait for background task to stop
|
||||
// running.
|
||||
while (m_task.isAlive()) {
|
||||
Timer.delay(.15); // just a little longer than the ping time for
|
||||
// round-robin to stop
|
||||
}
|
||||
// clear all the counters (data now invalid) since automatic mode is
|
||||
// stopped
|
||||
for (Ultrasonic u = m_firstSensor; u != null; u = u.m_nextSensor) {
|
||||
u.m_counter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single ping to ultrasonic sensor. Send out a single ping to the
|
||||
* ultrasonic sensor. This only works if automatic (round robin) mode is
|
||||
* disabled. A single ping is sent out, and the counter should count the
|
||||
* semi-period when it comes in. The counter is reset to make the current
|
||||
* value invalid.
|
||||
*/
|
||||
public void ping() {
|
||||
setAutomaticMode(false); // turn off automatic round robin if pinging
|
||||
// single sensor
|
||||
m_counter.reset(); // reset the counter to zero (invalid data now)
|
||||
m_pingChannel.pulse(m_pingChannel.m_channel, (float) kPingTime); // do
|
||||
// the
|
||||
// ping
|
||||
// to
|
||||
// start
|
||||
// getting
|
||||
// a
|
||||
// single
|
||||
// range
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is a valid range measurement. The ranges are accumulated
|
||||
* in a counter that will increment on each edge of the echo (return)
|
||||
* signal. If the count is not at least 2, then the range has not yet been
|
||||
* measured, and is invalid.
|
||||
*
|
||||
* @return true if the range is valid
|
||||
*/
|
||||
public boolean isRangeValid() {
|
||||
return m_counter.get() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range in inches from the ultrasonic sensor.
|
||||
*
|
||||
* @return double Range in inches of the target returned from the ultrasonic
|
||||
* sensor. If there is no valid value yet, i.e. at least one
|
||||
* measurement hasn't completed, then return 0.
|
||||
*/
|
||||
public double getRangeInches() {
|
||||
if (isRangeValid()) {
|
||||
return m_counter.getPeriod() * kSpeedOfSoundInchesPerSec / 2.0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range in millimeters from the ultrasonic sensor.
|
||||
*
|
||||
* @return double Range in millimeters of the target returned by the
|
||||
* ultrasonic sensor. If there is no valid value yet, i.e. at least
|
||||
* one measurement hasn't complted, then return 0.
|
||||
*/
|
||||
public double getRangeMM() {
|
||||
return getRangeInches() * 25.4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range in the current DistanceUnit for the PIDSource base object.
|
||||
*
|
||||
* @return The range in DistanceUnit
|
||||
*/
|
||||
public double pidGet() {
|
||||
switch (m_units.value) {
|
||||
case Unit.kInches_val:
|
||||
return getRangeInches();
|
||||
case Unit.kMillimeters_val:
|
||||
return getRangeMM();
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current DistanceUnit that should be used for the PIDSource base
|
||||
* object.
|
||||
*
|
||||
* @param units
|
||||
* The DistanceUnit that should be used.
|
||||
*/
|
||||
public void setDistanceUnits(Unit units) {
|
||||
m_units = units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current DistanceUnit that is used for the PIDSource base object.
|
||||
*
|
||||
* @return The type of DistanceUnit that is being used.
|
||||
*/
|
||||
public Unit getDistanceUnits() {
|
||||
return m_units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the ultrasonic enabled
|
||||
*
|
||||
* @return true if the ultrasonic is enabled
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the ultrasonic is enabled
|
||||
*
|
||||
* @param enable
|
||||
* set to true to enable the ultrasonic
|
||||
*/
|
||||
public void setEnabled(boolean enable) {
|
||||
m_enabled = enable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Live Window code, only does anything if live window is activated.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Ultrasonic";
|
||||
}
|
||||
|
||||
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", getRangeInches());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void startLiveWindowMode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stopLiveWindowMode() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.nio.IntBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.HALLibrary;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.parsing.IUtility;
|
||||
|
||||
/**
|
||||
* Contains global utility functions
|
||||
*/
|
||||
public class Utility implements IUtility {
|
||||
|
||||
private Utility() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FPGA Version number. For now, expect this to be 2009.
|
||||
*
|
||||
* @return FPGA Version number.
|
||||
*/
|
||||
int getFPGAVersion() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getFPGAVersion(status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the FPGA Revision number. The format of the revision is 3 numbers.
|
||||
* The 12 most significant bits are the Major Revision. the next 8 bits are
|
||||
* the Minor Revision. The 12 least significant bits are the Build Number.
|
||||
*
|
||||
* @return FPGA Revision number.
|
||||
*/
|
||||
long getFPGARevision() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getFPGARevision(status);
|
||||
HALUtil.checkStatus(status);
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the microsecond timer from the FPGA.
|
||||
*
|
||||
* @return The current time in microseconds according to the FPGA.
|
||||
*/
|
||||
public static long getFPGATime() {
|
||||
IntBuffer status = IntBuffer.allocate(1);
|
||||
int value = HALLibrary.getFPGATime(status);
|
||||
HALUtil.checkStatus(status);
|
||||
return (long) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Control whether to send System.err output to the driver station's error
|
||||
* pane.
|
||||
*
|
||||
* @param enabled
|
||||
* if true, send error stream to driver station, otherwise
|
||||
* disable sending error stream
|
||||
*/
|
||||
public static void sendErrorStreamToDriverStation(boolean enabled) {
|
||||
final String url = "dserror:edu.wpi.first.wpilibj.Utility"; // the path
|
||||
// is just a
|
||||
// comment.
|
||||
/* XXX: Code Review!
|
||||
Isolate isolate = VM.getCurrentIsolate();
|
||||
if (enabled) {
|
||||
isolate.addErr(url);
|
||||
} else {
|
||||
isolate.removeErr(url);
|
||||
} */
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
|
||||
import edu.wpi.first.wpilibj.parsing.IDeviceController;
|
||||
|
||||
/**
|
||||
* VEX Robotics Victor Speed Controller
|
||||
*/
|
||||
public class Victor extends SafePWM implements SpeedController, IDeviceController {
|
||||
|
||||
/**
|
||||
* Common initialization code called by all constructors.
|
||||
*
|
||||
* Note that the Victor uses the following bounds for PWM values. These values were determined
|
||||
* empirically and optimized for the Victor 888. These values should work reasonably well for
|
||||
* Victor 884 controllers also but if users experience issues such as asymmetric behavior around
|
||||
* the deadband or inability to saturate the controller in either direction, calibration is recommended.
|
||||
* The calibration procedure can be found in the Victor 884 User Manual available from VEX Robotics:
|
||||
* http://content.vexrobotics.com/docs/ifi-v884-users-manual-9-25-06.pdf
|
||||
*
|
||||
* - 2.027ms = full "forward"
|
||||
* - 1.525ms = the "high end" of the deadband range
|
||||
* - 1.507ms = center of the deadband range (off)
|
||||
* - 1.49ms = the "low end" of the deadband range
|
||||
* - 1.026ms = full "reverse"
|
||||
*/
|
||||
private void initVictor() {
|
||||
setBounds(2.027, 1.525, 1.507, 1.49, 1.026);
|
||||
setPeriodMultiplier(PeriodMultiplier.k2X);
|
||||
setRaw(m_centerPwm);
|
||||
|
||||
LiveWindow.addActuator("Victor", getModuleNumber(), getChannel(), this);
|
||||
UsageReporting.report(tResourceType.kResourceType_Victor, getChannel(), getModuleNumber()-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that assumes the default digital module.
|
||||
*
|
||||
* @param channel The PWM channel on the digital module that the Victor is attached to.
|
||||
*/
|
||||
public Victor(final int channel) {
|
||||
super(channel);
|
||||
initVictor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that specifies the digital module.
|
||||
*
|
||||
* @param slot The slot in the chassis that the digital module is plugged into.
|
||||
* @param channel The PWM channel on the digital module that the Victor is attached to.
|
||||
*/
|
||||
public Victor(final int slot, final int channel) {
|
||||
super(slot, channel);
|
||||
initVictor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* @deprecated For compatibility with CANJaguar
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed to set. Value should be between -1.0 and 1.0.
|
||||
* @param syncGroup The update group to add this Set() to, pending UpdateSyncGroup(). If 0, update immediately.
|
||||
*/
|
||||
public void set(double speed, byte syncGroup) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PWM value.
|
||||
*
|
||||
* The PWM value is set using a range of -1.0 to 1.0, appropriately
|
||||
* scaling the value for the FPGA.
|
||||
*
|
||||
* @param speed The speed value between -1.0 and 1.0 to set.
|
||||
*/
|
||||
public void set(double speed) {
|
||||
setSpeed(speed);
|
||||
Feed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recently set value of the PWM.
|
||||
*
|
||||
* @return The most recently set value for the PWM between -1.0 and 1.0.
|
||||
*/
|
||||
public double get() {
|
||||
return getSpeed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the PID value as seen in the PIDOutput base object.
|
||||
*
|
||||
* @param output Write out the PWM value as was found in the PIDController
|
||||
*/
|
||||
public void pidWrite(double output) {
|
||||
set(output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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 java.util.logging.*;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
//import com.sun.jna.Pointer;
|
||||
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.WatchdogJNI;
|
||||
import edu.wpi.first.wpilibj.hal.HALUtil;
|
||||
import edu.wpi.first.wpilibj.parsing.IUtility;
|
||||
|
||||
/**
|
||||
* Watchdog timer class. The watchdog timer is designed to keep the robots safe.
|
||||
* The idea is that the robot program must constantly "feed" the watchdog
|
||||
* otherwise it will shut down all the motor outputs. That way if a program
|
||||
* breaks, rather than having the robot continue to operate at the last known
|
||||
* speed, the motors will be shut down.
|
||||
*
|
||||
* This is serious business. Don't just disable the watchdog. You can't afford
|
||||
* it!
|
||||
*
|
||||
* http://thedailywtf.com/Articles/_0x2f__0x2f_TODO_0x3a__Uncomment_Later.aspx
|
||||
*/
|
||||
public class Watchdog extends SensorBase implements IUtility {
|
||||
private static Logger logger = Logger.getLogger("Watchdog");
|
||||
private static ConsoleHandler ch = new ConsoleHandler();
|
||||
private static Watchdog m_instance;
|
||||
private ByteBuffer m_watchDog;
|
||||
|
||||
static
|
||||
{
|
||||
logger.addHandler(ch);
|
||||
logger.setLevel(Level.ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Watchdog is born.
|
||||
*/
|
||||
protected Watchdog() {
|
||||
// allocate direct
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_watchDog = WatchdogJNI.initializeWatchdog(status.asIntBuffer());
|
||||
// set the byte order for the return value
|
||||
m_watchDog.order(ByteOrder.LITTLE_ENDIAN);
|
||||
logger.info("Initialize Watchdog Status = " + status.getInt(0) );
|
||||
logger.info("Watchdog Handle Length = " + m_watchDog.capacity() );
|
||||
logger.info("Watchdog Handle Value:" + m_watchDog.getInt(0));
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of the watchdog
|
||||
*
|
||||
* @return an instance of the watchdog
|
||||
*/
|
||||
public static synchronized Watchdog getInstance() {
|
||||
if (m_instance == null) {
|
||||
m_instance = new Watchdog();
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw the dog a bone.
|
||||
*
|
||||
* When everything is going well, you feed your dog when you get home. Let's
|
||||
* hope you don't drive your car off a bridge on the way home... Your dog
|
||||
* won't get fed and he will starve to death.
|
||||
*
|
||||
* By the way, it's not cool to ask the neighbor (some random task) to feed
|
||||
* your dog for you. He's your responsibility!
|
||||
*/
|
||||
public void feed() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
WatchdogJNI.feedWatchdog(m_watchDog, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the watchdog out of its misery.
|
||||
*
|
||||
* Don't wait for your dying robot to starve when there is a problem. Kill
|
||||
* it quickly, cleanly, and humanely.
|
||||
*/
|
||||
public void kill() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
WatchdogJNI.killWatchdog(m_watchDog, status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read how long it has been since the watchdog was last fed.
|
||||
*
|
||||
* @return The number of seconds since last meal.
|
||||
*/
|
||||
public double getTimer() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
double value = WatchdogJNI.getWatchdogLastFed(m_watchDog, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read what the current expiration is.
|
||||
*
|
||||
* @return The number of seconds before starvation following a meal
|
||||
* (watchdog starves if it doesn't eat this often).
|
||||
*/
|
||||
public double getExpiration() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
double value = WatchdogJNI.getWatchdogExpiration(m_watchDog, status);
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure how many seconds your watchdog can be neglected before it
|
||||
* starves to death.
|
||||
*
|
||||
* @param expiration
|
||||
* The number of seconds before starvation following a meal
|
||||
* (watchdog starves if it doesn't eat this often).
|
||||
*/
|
||||
public void setExpiration(double expiration) {
|
||||
// allocate direct
|
||||
ByteBuffer status = ByteBuffer.allocateDirect(4);
|
||||
// set to c++ byte order
|
||||
status.order(ByteOrder.LITTLE_ENDIAN);
|
||||
WatchdogJNI.setWatchdogExpiration(m_watchDog, expiration, status.asIntBuffer());
|
||||
HALUtil.checkStatus(status.asIntBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if the watchdog is currently enabled or disabled (mortal or
|
||||
* immortal).
|
||||
*
|
||||
* @return Enabled or disabled.
|
||||
*/
|
||||
public boolean getEnabled() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
boolean value = WatchdogJNI.getWatchdogEnabled(m_watchDog, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the watchdog timer.
|
||||
*
|
||||
* When enabled, you must keep feeding the watchdog timer to keep the
|
||||
* watchdog active, and hence the dangerous parts (motor outputs, etc.) can
|
||||
* keep functioning. When disabled, the watchdog is immortal and will remain
|
||||
* active even without being fed. It will also ignore any kill commands
|
||||
* while disabled.
|
||||
*
|
||||
* @param enabled
|
||||
* Enable or disable the watchdog.
|
||||
*/
|
||||
public void setEnabled(final boolean enabled) {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
WatchdogJNI.setWatchdogEnabled(m_watchDog, (byte) (enabled ? 1 : 0),
|
||||
status);
|
||||
HALUtil.checkStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check in on the watchdog and make sure he's still kicking.
|
||||
*
|
||||
* This indicates that your watchdog is allowing the system to operate. It
|
||||
* is still possible that the network communications is not allowing the
|
||||
* system to run, but you can check this to make sure it's not your fault.
|
||||
* Check isSystemActive() for overall system status.
|
||||
*
|
||||
* If the watchdog is disabled, then your watchdog is immortal.
|
||||
*
|
||||
* @return Is the watchdog still alive?
|
||||
*/
|
||||
public boolean isAlive() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
boolean value = WatchdogJNI.isWatchdogAlive(m_watchDog, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check on the overall status of the system.
|
||||
*
|
||||
* @return Is the system active (i.e. PWM motor outputs, etc. enabled)?
|
||||
*/
|
||||
public boolean isSystemActive() {
|
||||
IntBuffer status = ByteBuffer.allocateDirect(4).asIntBuffer();
|
||||
boolean value = WatchdogJNI.isWatchdogSystemActive(m_watchDog, status) != 0;
|
||||
HALUtil.checkStatus(status);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStationEnhancedIO.EnhancedIOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Greg
|
||||
*/
|
||||
public class AnalogIOButton extends Trigger {
|
||||
|
||||
public static double THRESHOLD = 0.5;
|
||||
|
||||
int port;
|
||||
|
||||
public AnalogIOButton(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
try {
|
||||
return DriverStation.getInstance().getEnhancedIO().getAnalogIn(port) < THRESHOLD;
|
||||
} catch (EnhancedIOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.command.Command;
|
||||
|
||||
/**
|
||||
* This class provides an easy way to link commands to OI inputs.
|
||||
*
|
||||
* It is very easy to link a button to a command. For instance, you could
|
||||
* link the trigger button of a joystick to a "score" command.
|
||||
*
|
||||
* This class represents a subclass of Trigger that is specifically aimed at
|
||||
* buttons on an operator interface as a common use case of the more generalized
|
||||
* Trigger objects. This is a simple wrapper around Trigger with the method names
|
||||
* renamed to fit the Button object use.
|
||||
*
|
||||
* @author brad
|
||||
*/
|
||||
public abstract class Button extends Trigger {
|
||||
|
||||
/**
|
||||
* Starts the given command whenever the button is newly pressed.
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whenPressed(final Command command) {
|
||||
whenActive(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constantly starts the given command while the button is held.
|
||||
*
|
||||
* {@link Command#start()} will be called repeatedly while the button is held,
|
||||
* and will be canceled when the button is released.
|
||||
*
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whileHeld(final Command command) {
|
||||
whileActive(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the command when the button is released
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whenReleased(final Command command) {
|
||||
whenInactive(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the command whenever the button is pressed (on then off then on)
|
||||
* @param command
|
||||
*/
|
||||
public void toggleWhenPressed(final Command command) {
|
||||
toggleWhenActive(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the command when the button is pressed
|
||||
* @param command
|
||||
*/
|
||||
public void cancelWhenPressed(final Command command) {
|
||||
cancelWhenActive(command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStationEnhancedIO.EnhancedIOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Greg
|
||||
*/
|
||||
public class DigitalIOButton extends Button {
|
||||
public final static boolean ACTIVE_STATE = false;
|
||||
|
||||
int port;
|
||||
|
||||
public DigitalIOButton(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
try {
|
||||
return DriverStation.getInstance().getEnhancedIO().getDigital(port) == ACTIVE_STATE;
|
||||
} catch (EnhancedIOException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
/**
|
||||
* This class is intended to be used within a program. The programmer can manually set its value.
|
||||
* Also includes a setting for whether or not it should invert its value.
|
||||
*
|
||||
* @author Joe
|
||||
*/
|
||||
public class InternalButton extends Button {
|
||||
|
||||
boolean pressed;
|
||||
boolean inverted;
|
||||
|
||||
/**
|
||||
* Creates an InternalButton that is not inverted.
|
||||
*/
|
||||
public InternalButton() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an InternalButton which is inverted depending on the input.
|
||||
*
|
||||
* @param inverted if false, then this button is pressed when set to true, otherwise it is pressed when set to false.
|
||||
*/
|
||||
public InternalButton(boolean inverted) {
|
||||
this.pressed = this.inverted = inverted;
|
||||
}
|
||||
|
||||
public void setInverted(boolean inverted) {
|
||||
this.inverted = inverted;
|
||||
}
|
||||
|
||||
public void setPressed(boolean pressed) {
|
||||
this.pressed = pressed;
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
return pressed ^ inverted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.GenericHID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author bradmiller
|
||||
*/
|
||||
public class JoystickButton extends Button {
|
||||
|
||||
GenericHID m_joystick;
|
||||
int m_buttonNumber;
|
||||
|
||||
/**
|
||||
* Create a joystick button for triggering commands
|
||||
* @param joystick The GenericHID object that has the button (e.g. Joystick, KinectStick, etc)
|
||||
* @param buttonNumber The button number (see {@link GenericHID#getRawButton(int) }
|
||||
*/
|
||||
public JoystickButton(GenericHID joystick, int buttonNumber) {
|
||||
m_joystick = joystick;
|
||||
m_buttonNumber = buttonNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the joystick button
|
||||
* @return The value of the joystick button
|
||||
*/
|
||||
public boolean get() {
|
||||
return m_joystick.getRawButton(m_buttonNumber);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables.NetworkTable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joe
|
||||
*/
|
||||
public class NetworkButton extends Button {
|
||||
|
||||
NetworkTable table;
|
||||
String field;
|
||||
|
||||
public NetworkButton(String table, String field) {
|
||||
this(NetworkTable.getTable(table), field);
|
||||
}
|
||||
|
||||
public NetworkButton(NetworkTable table, String field) {
|
||||
this.table = table;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
public boolean get() {
|
||||
return table.isConnected() && table.getBoolean(field, false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.buttons;
|
||||
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
import edu.wpi.first.wpilibj.command.Command;
|
||||
import edu.wpi.first.wpilibj.command.Scheduler;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
/**
|
||||
* This class provides an easy way to link commands to inputs.
|
||||
*
|
||||
* It is very easy to link a button to a command. For instance, you could
|
||||
* link the trigger button of a joystick to a "score" command.
|
||||
*
|
||||
* It is encouraged that teams write a subclass of Trigger if they want to have
|
||||
* something unusual (for instance, if they want to react to the user holding
|
||||
* a button while the robot is reading a certain sensor input). For this, they
|
||||
* only have to write the {@link Trigger#get()} method to get the full functionality
|
||||
* of the Trigger class.
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public abstract class Trigger implements Sendable {
|
||||
|
||||
/**
|
||||
* Returns whether or not the trigger is active
|
||||
*
|
||||
* This method will be called repeatedly a command is linked to the Trigger.
|
||||
*
|
||||
* @return whether or not the trigger condition is active.
|
||||
*/
|
||||
public abstract boolean get();
|
||||
|
||||
/**
|
||||
* Returns whether get() return true or the internal table for SmartDashboard use is pressed.
|
||||
* @return whether get() return true or the internal table for SmartDashboard use is pressed
|
||||
*/
|
||||
private boolean grab() {
|
||||
return get() || (table != null /*&& table.isConnected()*/ && table.getBoolean("pressed", false));//FIXME make is connected work?
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the given command whenever the trigger just becomes active.
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whenActive(final Command command) {
|
||||
new ButtonScheduler() {
|
||||
|
||||
boolean pressedLast = grab();
|
||||
|
||||
public void execute() {
|
||||
if (grab()) {
|
||||
if (!pressedLast) {
|
||||
pressedLast = true;
|
||||
command.start();
|
||||
}
|
||||
} else {
|
||||
pressedLast = false;
|
||||
}
|
||||
}
|
||||
} .start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constantly starts the given command while the button is held.
|
||||
*
|
||||
* {@link Command#start()} will be called repeatedly while the trigger is active,
|
||||
* and will be canceled when the trigger becomes inactive.
|
||||
*
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whileActive(final Command command) {
|
||||
new ButtonScheduler() {
|
||||
|
||||
boolean pressedLast = grab();
|
||||
|
||||
public void execute() {
|
||||
if (grab()) {
|
||||
pressedLast = true;
|
||||
command.start();
|
||||
} else {
|
||||
if (pressedLast) {
|
||||
pressedLast = false;
|
||||
command.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
} .start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the command when the trigger becomes inactive
|
||||
* @param command the command to start
|
||||
*/
|
||||
public void whenInactive(final Command command) {
|
||||
new ButtonScheduler() {
|
||||
|
||||
boolean pressedLast = grab();
|
||||
|
||||
public void execute() {
|
||||
if (grab()) {
|
||||
pressedLast = true;
|
||||
} else {
|
||||
if (pressedLast) {
|
||||
pressedLast = false;
|
||||
command.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
} .start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a command when the trigger becomes active
|
||||
* @param command the command to toggle
|
||||
*/
|
||||
public void toggleWhenActive(final Command command) {
|
||||
new ButtonScheduler() {
|
||||
|
||||
boolean pressedLast = grab();
|
||||
|
||||
public void execute() {
|
||||
if (grab()) {
|
||||
if (!pressedLast) {
|
||||
pressedLast = true;
|
||||
if (command.isRunning()) {
|
||||
command.cancel();
|
||||
} else {
|
||||
command.start();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pressedLast = false;
|
||||
}
|
||||
}
|
||||
} .start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a command when the trigger becomes active
|
||||
* @param command the command to cancel
|
||||
*/
|
||||
public void cancelWhenActive(final Command command) {
|
||||
new ButtonScheduler() {
|
||||
|
||||
boolean pressedLast = grab();
|
||||
|
||||
public void execute() {
|
||||
if (grab()) {
|
||||
if (!pressedLast) {
|
||||
pressedLast = true;
|
||||
command.cancel();
|
||||
}
|
||||
} else {
|
||||
pressedLast = false;
|
||||
}
|
||||
}
|
||||
} .start();
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal class of {@link Trigger}. The user should ignore this, it is
|
||||
* only public to interface between packages.
|
||||
*/
|
||||
public abstract class ButtonScheduler {
|
||||
public abstract void execute();
|
||||
|
||||
protected void start() {
|
||||
Scheduler.getInstance().addButton(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These methods continue to return the "Button" SmartDashboard type until we decided
|
||||
* to create a Trigger widget type for the dashboard.
|
||||
*/
|
||||
public String getSmartDashboardType() {
|
||||
return "Button";
|
||||
}
|
||||
private ITable table;
|
||||
public void initTable(ITable table) {
|
||||
this.table = table;
|
||||
if(table!=null) {
|
||||
table.putBoolean("pressed", get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,489 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.camera;
|
||||
|
||||
import com.sun.jna.BlockingFunction;
|
||||
import com.sun.jna.Function;
|
||||
import com.sun.jna.NativeLibrary;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.TaskExecutor;
|
||||
import com.sun.squawk.VM;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.image.ColorImage;
|
||||
import edu.wpi.first.wpilibj.image.HSLImage;
|
||||
import edu.wpi.first.wpilibj.image.NIVisionException;
|
||||
import edu.wpi.first.wpilibj.parsing.ISensor;
|
||||
import edu.wpi.first.wpilibj.util.BoundaryException;
|
||||
|
||||
//TODO figure out where to use finally to free resources
|
||||
//TODO go through old camera code and make sure all features are implemented
|
||||
//TODO make work with all three passwords
|
||||
//TODO get images of different types
|
||||
//TODO continue attempting to connect until succesful
|
||||
//TODO optimize and use Pointers in all locations which make sense - possibly JNA memcpy?
|
||||
/**
|
||||
* This class is a singleton used to configure and get images from the axis camera.
|
||||
* @author dtjones
|
||||
*/
|
||||
public class AxisCamera implements ISensor {
|
||||
|
||||
private static AxisCamera m_instance = null;
|
||||
|
||||
/**
|
||||
* Enumaration representing the different values which exposure may be set to.
|
||||
*/
|
||||
public static class ExposureT {
|
||||
|
||||
/**
|
||||
* The integer value of the enumeration.
|
||||
*/
|
||||
public final int value;
|
||||
static final ExposureT[] allValues = new ExposureT[4];
|
||||
/**
|
||||
* The Axis camera automatically determines what exposure level to use.
|
||||
*/
|
||||
public static final ExposureT automatic = new ExposureT(0);
|
||||
/**
|
||||
* Hold the current exposure level.
|
||||
*/
|
||||
public static final ExposureT hold = new ExposureT(1);
|
||||
/**
|
||||
* Set exposure for flicker free 50 hz.
|
||||
*/
|
||||
public static final ExposureT flickerfree50 = new ExposureT(2);
|
||||
/**
|
||||
* Set exposure for flicker free 60 hz.
|
||||
*/
|
||||
public static final ExposureT flickerfree60 = new ExposureT(3);
|
||||
|
||||
private ExposureT(int value) {
|
||||
this.value = value;
|
||||
allValues[value] = this;
|
||||
}
|
||||
|
||||
private static ExposureT get(int val) {
|
||||
return allValues[val];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration representing the different values which white balence may be
|
||||
* set to.
|
||||
*/
|
||||
public static class WhiteBalanceT {
|
||||
|
||||
/**
|
||||
* The integer value of the enumeration.
|
||||
*/
|
||||
public final int value;
|
||||
static final WhiteBalanceT[] allValues = new WhiteBalanceT[7];
|
||||
/**
|
||||
* The axis camera automatically adjusts the whit balance.
|
||||
*/
|
||||
public static final WhiteBalanceT automatic = new WhiteBalanceT(0);
|
||||
/**
|
||||
* Hold the current white balance.
|
||||
*/
|
||||
public static final WhiteBalanceT hold = new WhiteBalanceT(1);
|
||||
/**
|
||||
* White balance for outdoors.
|
||||
*/
|
||||
public static final WhiteBalanceT fixedOutdoor1 = new WhiteBalanceT(2);
|
||||
/**
|
||||
* White balance for outdoors.
|
||||
*/
|
||||
public static final WhiteBalanceT fixedOutdoor2 = new WhiteBalanceT(3);
|
||||
/**
|
||||
* White balance for indoors.
|
||||
*/
|
||||
public static final WhiteBalanceT fixedIndoor = new WhiteBalanceT(4);
|
||||
/**
|
||||
* White balance for fourescent lighting.
|
||||
*/
|
||||
public static final WhiteBalanceT fixedFlour1 = new WhiteBalanceT(5);
|
||||
/**
|
||||
* White balance for fourescent lighting.
|
||||
*/
|
||||
public static final WhiteBalanceT fixedFlour2 = new WhiteBalanceT(6);
|
||||
|
||||
private WhiteBalanceT(int value) {
|
||||
this.value = value;
|
||||
allValues[value] = this;
|
||||
}
|
||||
|
||||
private static WhiteBalanceT get(int value) {
|
||||
return allValues[value];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration representing the image resoultion provided by the camera.
|
||||
*/
|
||||
public static class ResolutionT {
|
||||
|
||||
/**
|
||||
* The integer value of the enumeration.
|
||||
*/
|
||||
public final int value;
|
||||
/**
|
||||
* Number of pixels wide.
|
||||
*/
|
||||
public final int width;
|
||||
/**
|
||||
* Number of pixels tall.
|
||||
*/
|
||||
public final int height;
|
||||
static final ResolutionT[] allValues = new ResolutionT[4];
|
||||
/**
|
||||
* Image is 640 pixels wide by 480 tall
|
||||
*/
|
||||
public static final ResolutionT k640x480 = new ResolutionT(0, 640, 480);
|
||||
/**
|
||||
* Image is 640 pixels wide by 360 tall
|
||||
*/
|
||||
public static final ResolutionT k640x360 = new ResolutionT(1, 640, 360);
|
||||
/**
|
||||
* Image is 320 pixels wide by 240 tall
|
||||
*/
|
||||
public static final ResolutionT k320x240 = new ResolutionT(2, 320, 240);
|
||||
/**
|
||||
* Image is 160 pixels wide by 120 tall
|
||||
*/
|
||||
public static final ResolutionT k160x120 = new ResolutionT(3, 160, 120);
|
||||
|
||||
private ResolutionT(int value, int horizontal, int vertical) {
|
||||
this.value = value;
|
||||
this.width = horizontal;
|
||||
this.height = vertical;
|
||||
allValues[value] = this;
|
||||
}
|
||||
|
||||
private static ResolutionT get(int value) {
|
||||
return allValues[value];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration representing the orientation of the picture.
|
||||
*/
|
||||
public static class RotationT {
|
||||
|
||||
/**
|
||||
* The integer value of the enumeration.
|
||||
*/
|
||||
public final int value;
|
||||
static final RotationT[] allValues = new RotationT[2];
|
||||
/**
|
||||
* Picture is right side up.
|
||||
*/
|
||||
public static final RotationT k0 = new RotationT(0);
|
||||
/**
|
||||
* Picture is rotated 180 degrees.
|
||||
*/
|
||||
public static final RotationT k180 = new RotationT(1);
|
||||
|
||||
private RotationT(int value) {
|
||||
this.value = value;
|
||||
allValues[value] = this;
|
||||
}
|
||||
|
||||
private static RotationT get(int value) {
|
||||
return allValues[value];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration representing the exposure priority.
|
||||
*/
|
||||
public static class ExposurePriorityT {
|
||||
|
||||
/**
|
||||
* The integer value of the enumeration.
|
||||
*/
|
||||
public final int value;
|
||||
static final ExposurePriorityT[] allValues = new ExposurePriorityT[3];
|
||||
/**
|
||||
* Prioritize image quality.
|
||||
*/
|
||||
public static final ExposurePriorityT imageQuality = new ExposurePriorityT(0);
|
||||
/**
|
||||
* No prioritization.
|
||||
*/
|
||||
public static final ExposurePriorityT none = new ExposurePriorityT(50);
|
||||
/**
|
||||
* Prioritize frame rate.
|
||||
*/
|
||||
public static final ExposurePriorityT frameRate = new ExposurePriorityT(100);
|
||||
|
||||
private ExposurePriorityT(int value) {
|
||||
this.value = value;
|
||||
allValues[value / 50] = this;
|
||||
}
|
||||
|
||||
private static ExposurePriorityT get(int value) {
|
||||
return allValues[value / 50];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the AxisCamera, or initialize the AxisCamera if it
|
||||
* has not yet been initialized. If the camera is connected to the
|
||||
* Ethernet switch on the robot, then this address should be 10.x.y.11
|
||||
* where x.y are your team number subnet address (same as the other IP
|
||||
* addresses on the robot network).
|
||||
* @param address A string containing the IP address for the camera in the
|
||||
* form "10.x.y.2" for cameras on the Ethernet switch or "192.168.0.90"
|
||||
* for cameras connected to the 2nd Ethernet port on an 8-slot cRIO.
|
||||
* @return A reference to the AxisCamera.
|
||||
*/
|
||||
public static synchronized AxisCamera getInstance(String address) {
|
||||
if (m_instance == null) {
|
||||
m_instance = new AxisCamera(address);
|
||||
// XXX: Resource Reporting Fixes
|
||||
// UsageReporting.report(UsageReporting.kResourceType_AxisCamera, 2);
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reference to the AxisCamera, or initialize the AxisCamera if it
|
||||
* has not yet been initialized. By default this will connect to a camera
|
||||
* with an IP address of 10.x.y.11 with the preference that the camera be
|
||||
* connected to the Ethernet switch on the robot rather than port 2 of the
|
||||
* 8-slot cRIO.
|
||||
* @return A reference to the AxisCamera.
|
||||
*/
|
||||
public static synchronized AxisCamera getInstance() {
|
||||
if (m_instance == null) {
|
||||
DriverStation.getInstance().waitForData();
|
||||
int teamNumber = DriverStation.getInstance().getTeamNumber();
|
||||
String address = "10."+(teamNumber/100)+"."+(teamNumber%100)+".11";
|
||||
m_instance = new AxisCamera(address);
|
||||
UsageReporting.report(UsageReporting.kResourceType_AxisCamera, 1);
|
||||
}
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
private static final Function cameraStartFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraStart");
|
||||
|
||||
/**
|
||||
* Axis camera constructor that calls the C++ library to actually create the instance.
|
||||
* @param IPAddress
|
||||
*/
|
||||
AxisCamera(String IPAddress) {
|
||||
Pointer ptr = Pointer.createStringBuffer(IPAddress);
|
||||
cameraStartFn.call1(ptr);
|
||||
}
|
||||
private static final TaskExecutor cameraTaskExecutor = new TaskExecutor("camera task executor");
|
||||
private static final BlockingFunction getImageFn = NativeLibrary.getDefaultInstance().getBlockingFunction("AxisCameraGetImage");
|
||||
|
||||
static {
|
||||
getImageFn.setTaskExecutor(cameraTaskExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an image from the camera. Be sure to free the image when you are done with it.
|
||||
* @return A new image from the camera.
|
||||
*/
|
||||
public ColorImage getImage() throws AxisCameraException, NIVisionException {
|
||||
ColorImage image = new HSLImage();
|
||||
if (getImageFn.call1(image.image) == 0) {
|
||||
image.free();
|
||||
throw new AxisCameraException("No image available");
|
||||
}
|
||||
return image;
|
||||
}
|
||||
// Mid-stream gets & writes
|
||||
private static final Function writeBrightnessFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteBrightness");
|
||||
|
||||
/**
|
||||
* Write the brightness for the camera to use.
|
||||
* @param brightness This must be an integer between 0 and 100, with 100 being the brightest
|
||||
*/
|
||||
public void writeBrightness(int brightness) {
|
||||
BoundaryException.assertWithinBounds(brightness, 0, 100);
|
||||
writeBrightnessFn.call1(brightness);
|
||||
}
|
||||
private static final Function getBrightnessFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetBrightness");
|
||||
|
||||
/**
|
||||
* Get the current brightness of the AxisCamera
|
||||
* @return An integer representing the current brightness of the axis
|
||||
* camera with 0 being the darkest and 100 being the brightest.
|
||||
*/
|
||||
public int getBrightness() {
|
||||
return getBrightnessFn.call0();
|
||||
}
|
||||
private static final Function writeWhiteBalenceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteWhiteBalance");
|
||||
|
||||
/**
|
||||
* Write the WhiteBalance for the camera to use.
|
||||
* @param whiteBalance The value to set the white balance to on the camera.
|
||||
*/
|
||||
public void writeWhiteBalance(WhiteBalanceT whiteBalance) {
|
||||
writeWhiteBalenceFn.call1(whiteBalance.value);
|
||||
}
|
||||
private static final Function getWhiteBalanceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetWhiteBalance");
|
||||
|
||||
/**
|
||||
* Get the white balance set on the camera.
|
||||
* @return The white balance currently set on the camera.
|
||||
*/
|
||||
public WhiteBalanceT getWhiteBalance() {
|
||||
return WhiteBalanceT.get(getWhiteBalanceFn.call0());
|
||||
}
|
||||
private static final Function writeColorLevelFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteColorLevel");
|
||||
|
||||
/**
|
||||
* Set the color level of images returned from the camera.
|
||||
* @param value This must be an integer from 0 to 100 with 0 being black and white.
|
||||
*/
|
||||
public void writeColorLevel(int value) {
|
||||
BoundaryException.assertWithinBounds(value, 0, 100);
|
||||
writeColorLevelFn.call1(value);
|
||||
}
|
||||
private static final Function getColorLevelFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetColorLevel");
|
||||
|
||||
/**
|
||||
* Get the color level of images being retunred from the camera.
|
||||
* @return The color level of images being returned from the camera. 0 is black and white.
|
||||
*/
|
||||
public int getColorLevel() {
|
||||
return getColorLevelFn.call0();
|
||||
}
|
||||
private static final Function writeExposureControlFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteExposureControl");
|
||||
|
||||
/**
|
||||
* Write the exposure mode for the camera to use.
|
||||
* @param value The expsure mode for the camera to use.
|
||||
*/
|
||||
public void writeExposureControl(ExposureT value) {
|
||||
writeExposureControlFn.call1(value.value);
|
||||
}
|
||||
private static final Function getExposureControlFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetExposureControl");
|
||||
|
||||
/**
|
||||
* Get the exposure mode that the camera is using.
|
||||
* @return The exposure mode that the camera is using.
|
||||
*/
|
||||
public ExposureT getExposureControl() {
|
||||
return ExposureT.get(getExposureControlFn.call0());
|
||||
}
|
||||
private static final Function writeExposurePriorityFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteExposurePriority");
|
||||
|
||||
/**
|
||||
* Write the exposure priority for the camera to use.
|
||||
* @param value The exposure priority to use.
|
||||
*/
|
||||
public void writeExposurePriority(ExposurePriorityT value) {
|
||||
writeExposurePriorityFn.call1(value.value);
|
||||
}
|
||||
private static final Function getExposurePriorityFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetExposurePriority");
|
||||
|
||||
/**
|
||||
* Get the exposure priority that the camera is using.
|
||||
* @return The exposure priority that the camera is using
|
||||
*/
|
||||
public ExposurePriorityT getExposurePriority() {
|
||||
return ExposurePriorityT.get(getExposurePriorityFn.call0());
|
||||
}
|
||||
// New-Stream gets & writes
|
||||
private static final Function writeResolutionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteResolution");
|
||||
|
||||
/**
|
||||
* Set the resolution of the images to return.
|
||||
* @param value The resolution imaga for the camera to return.
|
||||
*/
|
||||
public void writeResolution(ResolutionT value) {
|
||||
writeResolutionFn.call1(value.value);
|
||||
}
|
||||
private static final Function getResolutionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetResolution");
|
||||
|
||||
/**
|
||||
* Get the resolution fo the images that the camera is returning.
|
||||
* @return The resolution of the images that the camera is returning.
|
||||
*/
|
||||
public ResolutionT getResolution() {
|
||||
return ResolutionT.get(getResolutionFn.call0());
|
||||
}
|
||||
private static final Function writeCompressionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteCompression");
|
||||
|
||||
/**
|
||||
* Write the level of JPEG compression to use on images returned from the camera.
|
||||
* @param value The level of JPEG compression to use from 0 to 100 with 0 being the least compression.
|
||||
*/
|
||||
public void writeCompression(int value) {
|
||||
BoundaryException.assertWithinBounds(value, 0, 100);
|
||||
writeCompressionFn.call1(value);
|
||||
}
|
||||
private static final Function getCompressionFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetCompression");
|
||||
|
||||
/**
|
||||
* Get the compression of the images eing returned by the camera.
|
||||
* @return The level of compression of the image being returned from the
|
||||
* camera with 0 being the least and 100 being the greatest.
|
||||
*/
|
||||
public int getCompression() {
|
||||
return getCompressionFn.call0();
|
||||
}
|
||||
private static final Function writeRotationFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteRotation");
|
||||
|
||||
/**
|
||||
* Write the rotation of images for the camera to return.
|
||||
* @param value The rotation to be applied to images from the camera.
|
||||
*/
|
||||
public void writeRotation(RotationT value) {
|
||||
writeRotationFn.call1(value.value);
|
||||
}
|
||||
private static final Function getRotationFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetRotation");
|
||||
|
||||
/**
|
||||
* Get the rotation of the images returned from the camera.
|
||||
* @return The rotation of the images returned from the camera.
|
||||
*/
|
||||
public RotationT getRotation() {
|
||||
return RotationT.get(getRotationFn.call0());
|
||||
}
|
||||
private static final Function freshImageFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraFreshImage");
|
||||
|
||||
/**
|
||||
* Has the current image from the camera been retrieved yet.
|
||||
* @return true if the latest image from the camera has not been retrieved yet.
|
||||
*/
|
||||
public boolean freshImage() {
|
||||
return freshImageFn.call0() == 0 ? false : true;
|
||||
}
|
||||
private static final Function getMaxFPSFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraGetMaxFPS");
|
||||
|
||||
/**
|
||||
* Get the maximum frames per second that the camera will generate.
|
||||
* @return the max fps.
|
||||
*/
|
||||
public int getMaxFPS() {
|
||||
return getMaxFPSFn.call0();
|
||||
}
|
||||
private static final Function writeMaxFPSFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraWriteMaxFPS");
|
||||
|
||||
/**
|
||||
* Set the maximum frames per second that the camera will generate.
|
||||
* @param value the new max fps
|
||||
*/
|
||||
public void writeMaxFPS(int value) {
|
||||
writeMaxFPSFn.call1(value);
|
||||
}
|
||||
private static final Function deleteInstanceFn = NativeLibrary.getDefaultInstance().getFunction("AxisCameraDeleteInstance");
|
||||
|
||||
static {
|
||||
VM.addShutdownHook(new Thread() {
|
||||
|
||||
public void run() {
|
||||
deleteInstanceFn.call0();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.camera;
|
||||
|
||||
/**
|
||||
* An exception representing a problem with communicating with the camera.
|
||||
* @author dtjones
|
||||
*/
|
||||
public class AxisCameraException extends Exception {
|
||||
/**
|
||||
* Create a new AxisCameraException.
|
||||
* @param msg The message to pass with the AxisCameraException.
|
||||
*/
|
||||
public AxisCameraException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>FRC Camera Library</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=MacRoman">
|
||||
</head>
|
||||
<body>
|
||||
Provides classes for interfacing to the camera.
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,48 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
import edu.wpi.first.wpilibj.communication.NIRioStatus;
|
||||
import edu.wpi.first.wpilibj.util.UncleanStatusException;
|
||||
|
||||
/**
|
||||
* Exception indicating that the Jaguar CAN Driver layer refused to send a
|
||||
* restricted message ID to the CAN bus.
|
||||
*/
|
||||
public class CANExceptionFactory {
|
||||
// FRC Error codes
|
||||
static final int ERR_JaguarCANDriver_InvalidBuffer = -44086;
|
||||
static final int ERR_JaguarCANDriver_TimedOut = -44087;
|
||||
static final int ERR_JaguarCANDriver_NotAllowed = -44088;
|
||||
static final int ERR_JaguarCANDriver_NotInitialized = -44089;
|
||||
|
||||
public static void checkStatus(int status, int messageID) throws
|
||||
CANInvalidBufferException, CANTimeoutException,
|
||||
CANMessageNotAllowedException, CANNotInitializedException,
|
||||
UncleanStatusException {
|
||||
switch (status) {
|
||||
case NIRioStatus.kRioStatusSuccess:
|
||||
// Everything is ok... don't throw.
|
||||
return;
|
||||
case ERR_JaguarCANDriver_InvalidBuffer:
|
||||
case NIRioStatus.kRIOStatusBufferInvalidSize:
|
||||
throw new CANInvalidBufferException();
|
||||
case ERR_JaguarCANDriver_TimedOut:
|
||||
case NIRioStatus.kRIOStatusOperationTimedOut:
|
||||
throw new CANTimeoutException();
|
||||
case ERR_JaguarCANDriver_NotAllowed:
|
||||
case NIRioStatus.kRIOStatusFeatureNotSupported:
|
||||
throw new CANMessageNotAllowedException("MessageID = " + Integer.toString(messageID));
|
||||
case ERR_JaguarCANDriver_NotInitialized:
|
||||
case NIRioStatus.kRIOStatusResourceNotInitialized:
|
||||
throw new CANNotInitializedException();
|
||||
default:
|
||||
throw new UncleanStatusException("Fatal status code detected: " + Integer.toString(status));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
/**
|
||||
* Exception indicating that a CAN driver library entry-point
|
||||
* was passed an invalid buffer. Typically, this is due to a
|
||||
* buffer being too small to include the needed safety token.
|
||||
*/
|
||||
public class CANInvalidBufferException extends RuntimeException {
|
||||
public CANInvalidBufferException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
package edu.wpi.first.wpilibj.can;
|
||||
//import com.ochafik.lang.jnaerator.runtime.LibraryExtractor;
|
||||
//import com.ochafik.lang.jnaerator.runtime.MangledFunctionMapper;
|
||||
//import com.sun.jna.Library;
|
||||
//import com.sun.jna.Native;
|
||||
//import com.sun.jna.NativeLibrary;
|
||||
//import com.sun.jna.Pointer;
|
||||
//import com.sun.jna.ptr.IntByReference;
|
||||
import edu.wpi.first.wpilibj.hal.JNIWrapper;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
/**
|
||||
* JNA Wrapper for library <b>CAN</b><br>
|
||||
* This file was autogenerated by <a href="http://jnaerator.googlecode.com/">JNAerator</a>,<br>
|
||||
* a tool written by <a href="http://ochafik.com/">Olivier Chafik</a> that <a href="http://code.google.com/p/jnaerator/wiki/CreditsAndLicense">uses a few opensource projects.</a>.<br>
|
||||
* For help, please visit <a href="http://nativelibs4java.googlecode.com/">NativeLibs4Java</a> , <a href="http://rococoa.dev.java.net/">Rococoa</a>, or <a href="http://jna.dev.java.net/">JNA</a>.
|
||||
*/
|
||||
public class CANJNI extends JNIWrapper{
|
||||
//public static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("CAN", true, CANLibrary.class);
|
||||
//public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(CANLibrary.JNA_LIBRARY_NAME, MangledFunctionMapper.DEFAULT_OPTIONS);
|
||||
//static {
|
||||
// System.loadLibrary("JNIWrappers");
|
||||
//Native.register(CANLibrary.class, CANLibrary.JNA_NATIVE_LIB);
|
||||
//}
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_REV = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_MAX_VOUT = ((0x00020000 | 0x02000000 | 0x00001c00) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_CANERR_B0 = 30;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_DIS = ((0x00020000 | 0x02000000 | 0x00000400) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_ACCEL = 0x05000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_FAULT = ((0x00020000 | 0x02000000 | 0x00001400) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_FIRMVER = 0x00000200;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_EN = ((0x00020000 | 0x02000000 | 0x00001000) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_ENUMERATE = 0x00000240;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_EN = ((0x00020000 | 0x02000000 | 0x00000400) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_LIMIT_REV = ((0x00020000 | 0x02000000 | 0x00001c00) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_POS_B2 = 11;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_POS_B3 = 12;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_EN = ((0x00020000 | 0x02000000 | 0x00000800) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_POS_B0 = 9;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_POS_B1 = 10;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_HWVER = ((0x00020000 | 0x1f000000) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_FAULT_ILIMIT = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_DC = ((0x00020000 | 0x02000000 | 0x00001000) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT = (0x00020000 | 0x02000000 | 0x00000000);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_VCOMP = 0x00000800;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_END = 0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_LIMIT_FWD = ((0x00020000 | 0x02000000 | 0x00001c00) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_M = 0x1f000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_ICTRL = 0x00001000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_CFG = 0x00001c00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_MFR_DEKA = 0x00030000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_SYSRST = 0x00000040;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_REF_QUAD_ENCODER = 0x03;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SYNC_PEND_NOW = 0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_CMODE_CURRENT = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_TEMP = ((0x00020000 | 0x02000000 | 0x00001400) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_DC = ((0x00020000 | 0x02000000 | 0x00000400) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_POS = 0x00000c00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_SFWD = 0x04;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_DIS = ((0x00020000 | 0x02000000 | 0x00001000) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_SET = ((0x00020000 | 0x02000000 | 0x00000000) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_HEARTBEAT = 0x00000140;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_FAULT_CURRENT = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_GYRO = 0x04000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_FAULT_TLIMIT = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_MFR_S = 16;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_T_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000400) | (10 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_MFR_M = 0x00ff0000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_CMODE_POS = 0x03;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_REF_POT = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_HWVER_UNKNOWN = 0x00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_BRAKE_COAST = ((0x00020000 | 0x02000000 | 0x00001c00) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_HWVER_JAG_1_0 = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DEVNO_BCAST = 0x00000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_T_SET = ((0x00020000 | 0x02000000 | 0x00000000) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_STKY_SREV = 0x80;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_IC = ((0x00020000 | 0x02000000 | 0x00001000) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_FAULT_COMM = 0x10;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_T_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00001000) | (9 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_SPD_B2 = 15;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_SPD_B1 = 14;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_STKY_FLT_CLR = 21;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_SPD_B3 = 16;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_MFG_S = 16;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000400) | (11 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_LIMIT = ((0x00020000 | 0x02000000 | 0x00001400) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_EN = ((0x00020000 | 0x02000000 | 0x00000000) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_RAMP_DIS = 0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_TEMP_B0 = 7;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_TEMP_B1 = 8;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_IC = ((0x00020000 | 0x02000000 | 0x00000c00) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_MOTOR = 0x02000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_T_EN = ((0x00020000 | 0x02000000 | 0x00000400) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DEVNO_M = 0x0000003f;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOLTBUS_B1 = 4;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_PING = ((0x00020000 | 0x1f000000) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_T_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000c00) | (10 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DEVNO_S = 0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_TRUST_HEARTBEAT = ((0x00020000 | 0x1f000000) | (13 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOLTBUS_B0 = 3;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_SPD_B0 = 13;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG = (0x00020000 | 0x02000000 | 0x00001c00);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FLT_COUNT_COMM = 28;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_SYSHALT = 0x00000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_DOWNLOAD = ((0x00020000 | 0x1f000000) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_CMODE = ((0x00020000 | 0x02000000 | 0x00001400) | (9 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_IN_RAMP = ((0x00020000 | 0x02000000 | 0x00000800) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_FAULT_VLIMIT = 0x04;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_SREV = 0x08;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_S = 24;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FLT_COUNT_VOLTBUS = 26;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_STATUS = 0x00001400;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_T_EN = ((0x00020000 | 0x02000000 | 0x00000000) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_VOLTBUS = ((0x00020000 | 0x02000000 | 0x00001400) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD = (0x00020000 | 0x1f000000);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_REQUEST = ((0x00020000 | 0x1f000000) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_VOLTAGE = 0x00000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_PER_EN_S3 = ((0x00020000 | 0x02000000 | 0x00001800) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_PER_EN_S2 = ((0x00020000 | 0x02000000 | 0x00001800) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_PSTAT = 0x00001800;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_CANERR_B1 = 31;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_PER_EN_S1 = ((0x00020000 | 0x02000000 | 0x00001800) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_REF_ENCODER = 0x00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_PER_EN_S0 = ((0x00020000 | 0x02000000 | 0x00001800) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_CURRENT = ((0x00020000 | 0x02000000 | 0x00001400) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_SET = ((0x00020000 | 0x02000000 | 0x00000c00) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_STKY_FWD = 0x10;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL = (0x00020000 | 0x02000000 | 0x00001000);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_HWVER_JAG_2_0 = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_MFG_M = 0x00ff0000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_LIMIT_CLR = 18;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_POT_TURNS = ((0x00020000 | 0x02000000 | 0x00001c00) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_REF = ((0x00020000 | 0x02000000 | 0x00000c00) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_PC = ((0x00020000 | 0x02000000 | 0x00000400) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_VOUT = ((0x00020000 | 0x02000000 | 0x00001400) | (10 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_SYSRESUME = 0x00000280;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UNTRUST_EN = ((0x00020000 | 0x1f000000) | (11 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_CANSTS = 29;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_DC = ((0x00020000 | 0x02000000 | 0x00000c00) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_POS = ((0x00020000 | 0x02000000 | 0x00001400) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_SET = ((0x00020000 | 0x02000000 | 0x00000400) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_FULL_M = 0x1fffffff;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_SPD = ((0x00020000 | 0x02000000 | 0x00001400) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_STKY_FLT_NCLR = 20;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS = (0x00020000 | 0x02000000 | 0x00001400);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_TRUST_EN = ((0x00020000 | 0x1f000000) | (12 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_T_SET = ((0x00020000 | 0x02000000 | 0x00001000) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_CODE_M = 0x0000ffff;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_CODE_S = 0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_T_EN = ((0x00020000 | 0x02000000 | 0x00000c00) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT = (0x00020000 | 0x02000000 | 0x00001800);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FAULT = 19;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FLT_COUNT_GATE = 27;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_T_EN = ((0x00020000 | 0x02000000 | 0x00001000) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_DEVQUERY = 0x000000c0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_USONIC = 0x06000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_CMODE_VCOMP = 0x04;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_T_SET = ((0x00020000 | 0x02000000 | 0x00000400) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_EN = ((0x00020000 | 0x02000000 | 0x00000c00) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_DIS = ((0x00020000 | 0x02000000 | 0x00000000) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_FWD = 0x01;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_DIS = ((0x00020000 | 0x02000000 | 0x00000800) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_REF_INV_ENCODER = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_NUM_BRUSHES = ((0x00020000 | 0x02000000 | 0x00001c00) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_RELAY = 0x03000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_DEVASSIGN = 0x00000080;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_T_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000000) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_SPD = 0x00000400;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_ENC_LINES = ((0x00020000 | 0x02000000 | 0x00001c00) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_REF_NONE = 0xff;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_FAULT_VBUS = 0x04;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_SET_RAMP = ((0x00020000 | 0x02000000 | 0x00000000) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_REF = ((0x00020000 | 0x02000000 | 0x00000400) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_POWER = ((0x00020000 | 0x02000000 | 0x00001400) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOLTOUT_B1 = 2;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000800) | (9 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOLTOUT_B0 = 1;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_LIMIT_MODE = ((0x00020000 | 0x02000000 | 0x00001c00) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOUT_B1 = 23;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_SEND_DATA = ((0x00020000 | 0x1f000000) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FLT_COUNT_CURRENT = 24;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_VOUT_B0 = 22;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_CFG_S0 = ((0x00020000 | 0x02000000 | 0x00001800) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_LIMIT_NCLR = 17;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_CFG_S1 = ((0x00020000 | 0x02000000 | 0x00001800) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_CFG_S2 = ((0x00020000 | 0x02000000 | 0x00001800) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_CFG_S3 = ((0x00020000 | 0x02000000 | 0x00001800) | (7 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_SET = ((0x00020000 | 0x02000000 | 0x00000800) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_UPDATE = 0x000001c0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_CFG_FAULT_TIME = ((0x00020000 | 0x02000000 | 0x00001c00) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_VOLTOUT = ((0x00020000 | 0x02000000 | 0x00001400) | (0 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_SET = ((0x00020000 | 0x02000000 | 0x00001000) | (2 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_M = 0x0000ffc0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_CMODE_SPEED = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_CLASS_M = 0x0000fc00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_DATA_S3 = ((0x00020000 | 0x02000000 | 0x00001800) | (11 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_S = 6;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_FLT_COUNT = ((0x00020000 | 0x02000000 | 0x00001400) | (12 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_DATA_S2 = ((0x00020000 | 0x02000000 | 0x00001800) | (10 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_DATA_S1 = ((0x00020000 | 0x02000000 | 0x00001800) | (9 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_PSTAT_DATA_S0 = ((0x00020000 | 0x02000000 | 0x00001800) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_PC = ((0x00020000 | 0x02000000 | 0x00001000) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_PC = ((0x00020000 | 0x02000000 | 0x00000c00) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_MFR_LM = 0x00020000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_DIS = ((0x00020000 | 0x02000000 | 0x00000c00) | (1 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_BCAST = 0x00000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_CMODE_VOLT = 0x00;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_DTYPE_S = 24;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000c00) | (11 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_FAULT_GATE_DRIVE = 0x08;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_STATUS_DTYPE_M = 0x1f000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_STKY_REV = 0x20;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_ROBOT = 0x01000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_API_MC_ACK = 0x00002000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP = (0x00020000 | 0x02000000 | 0x00000800);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_ACK = ((0x00020000 | 0x1f000000) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_COMP_RAMP = ((0x00020000 | 0x02000000 | 0x00000800) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_T_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000800) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS = (0x00020000 | 0x02000000 | 0x00000c00);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_SYNC = 0x00000180;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ICTRL_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00001000) | (10 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_CURRENT_B1 = 6;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD = (0x00020000 | 0x02000000 | 0x00000400);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_CURRENT_B0 = 5;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_UPDATE = 0x1f000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_SPD_IC = ((0x00020000 | 0x02000000 | 0x00000400) | (4 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_ACK = (0x00020000 | 0x02000000 | 0x00002000);
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_FAULT_TEMP = 0x02;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_T_SET = ((0x00020000 | 0x02000000 | 0x00000800) | (6 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_PSTAT_FLT_COUNT_TEMP = 25;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VOLT_SET_NO_ACK = ((0x00020000 | 0x02000000 | 0x00000000) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_DTYPE_GEART = 0x07000000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_MFR_NI = 0x00010000;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_POS_T_SET = ((0x00020000 | 0x02000000 | 0x00000c00) | (8 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_STATUS_STKY_FLT = ((0x00020000 | 0x02000000 | 0x00001400) | (11 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_UPD_RESET = ((0x00020000 | 0x1f000000) | (3 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int CAN_MSGID_API_ID_M = 0x000003c0;
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_API_VCOMP_T_EN = ((0x00020000 | 0x02000000 | 0x00000800) | (5 << 6));
|
||||
/** <i>native declaration : src\main\include\CAN\can_proto.h</i> */
|
||||
public static final int LM_STATUS_LIMIT_STKY_SFWD = 0x40;
|
||||
|
||||
public static native void FRCNetworkCommunicationJaguarCANDriverSendMessage(int messageID, ByteBuffer data, IntBuffer status);
|
||||
public static native ByteBuffer FRCNetworkCommunicationJaguarCANDriverReceiveMessage(IntBuffer messageID, int timeoutMs, IntBuffer status);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
/**
|
||||
* Exception indicating that the CAN driver layer has not been initialized.
|
||||
* This happens when an entry-point is called before a CAN driver plugin
|
||||
* has been installed.
|
||||
*/
|
||||
public class CANJaguarVersionException extends RuntimeException {
|
||||
|
||||
public static final int kMinLegalFIRSTFirmwareVersion = 101;
|
||||
// 3330 was the first shipping RDK firmware version for the Jaguar
|
||||
public static final int kMinRDKFirmwareVersion = 3330;
|
||||
|
||||
public CANJaguarVersionException(int deviceNumber, int fwVersion) {
|
||||
super(getString(deviceNumber, fwVersion));
|
||||
System.out.println("fwVersion[" + deviceNumber + "]: " + fwVersion);
|
||||
}
|
||||
|
||||
static String getString(int deviceNumber, int fwVersion) {
|
||||
String msg;
|
||||
if (fwVersion < kMinRDKFirmwareVersion) {
|
||||
msg = "Jaguar " + deviceNumber +
|
||||
" firmware is too old. It must be updated to at least version " +
|
||||
Integer.toString(kMinLegalFIRSTFirmwareVersion) +
|
||||
" of the FIRST approved firmware!";
|
||||
} else {
|
||||
msg = "Jaguar " + deviceNumber +
|
||||
" firmware is not FIRST approved. It must be updated to at least version " +
|
||||
Integer.toString(kMinLegalFIRSTFirmwareVersion) +
|
||||
" of the FIRST approved firmware!";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
/**
|
||||
* Exception indicating that the Jaguar CAN Driver layer refused to send a
|
||||
* restricted message ID to the CAN bus.
|
||||
*/
|
||||
public class CANMessageNotAllowedException extends RuntimeException {
|
||||
public CANMessageNotAllowedException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
/**
|
||||
* Exception indicating that the CAN driver layer has not been initialized.
|
||||
* This happens when an entry-point is called before a CAN driver plugin
|
||||
* has been installed.
|
||||
*/
|
||||
public class CANNotInitializedException extends RuntimeException {
|
||||
public CANNotInitializedException() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.can;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception indicating that the CAN device did not respond
|
||||
* within the timeout period specified.
|
||||
*/
|
||||
public class CANTimeoutException extends IOException {
|
||||
public CANTimeoutException() {
|
||||
super();
|
||||
}
|
||||
public CANTimeoutException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.NamedSendable;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* The Command class is at the very core of the entire command framework.
|
||||
* Every command can be started with a call to {@link Command#start() start()}.
|
||||
* Once a command is started it will call {@link Command#initialize() initialize()}, and then
|
||||
* will repeatedly call {@link Command#execute() execute()} until the {@link Command#isFinished() isFinished()}
|
||||
* returns true. Once it does, {@link Command#end() end()} will be called.
|
||||
*
|
||||
* <p>However, if at any point while it is running {@link Command#cancel() cancel()} is called, then
|
||||
* the command will be stopped and {@link Command#interrupted() interrupted()} will be called.</p>
|
||||
*
|
||||
* <p>If a command uses a {@link Subsystem}, then it should specify that it does so by
|
||||
* calling the {@link Command#requires(Subsystem) requires(...)} method
|
||||
* in its constructor. Note that a Command may have multiple requirements, and
|
||||
* {@link Command#requires(Subsystem) requires(...)} should be
|
||||
* called for each one.</p>
|
||||
*
|
||||
* <p>If a command is running and a new command with shared requirements is started,
|
||||
* then one of two things will happen. If the active command is interruptible,
|
||||
* then {@link Command#cancel() cancel()} will be called and the command will be removed
|
||||
* to make way for the new one. If the active command is not interruptible, the
|
||||
* other one will not even be started, and the active one will continue functioning.</p>
|
||||
*
|
||||
* @author Brad Miller
|
||||
* @author Joe Grinstead
|
||||
* @see Subsystem
|
||||
* @see CommandGroup
|
||||
* @see IllegalUseOfCommandException
|
||||
*/
|
||||
public abstract class Command implements NamedSendable {
|
||||
|
||||
/** The name of this command */
|
||||
private String m_name;
|
||||
/** The time since this command was initialized */
|
||||
private double m_startTime = -1;
|
||||
/** The time (in seconds) before this command "times out" (or -1 if no timeout) */
|
||||
private double m_timeout = -1;
|
||||
/** Whether or not this command has been initialized */
|
||||
private boolean m_initialized = false;
|
||||
/** The requirements (or null if no requirements) */
|
||||
private Set m_requirements;
|
||||
/** Whether or not it is running */
|
||||
private boolean m_running = false;
|
||||
/** Whether or not it is interruptible*/
|
||||
private boolean m_interruptible = true;
|
||||
/** Whether or not it has been canceled */
|
||||
private boolean m_canceled = false;
|
||||
/** Whether or not it has been locked */
|
||||
private boolean m_locked = false;
|
||||
/** Whether this command should run when the robot is disabled */
|
||||
private boolean m_runWhenDisabled = false;
|
||||
/** The {@link CommandGroup} this is in */
|
||||
private CommandGroup m_parent;
|
||||
|
||||
/**
|
||||
* Creates a new command.
|
||||
* The name of this command will be set to its class name.
|
||||
*/
|
||||
public Command() {
|
||||
m_name = getClass().getName();
|
||||
m_name = m_name.substring(m_name.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new command with the given name.
|
||||
* @param name the name for this command
|
||||
* @throws IllegalArgumentException if name is null
|
||||
*/
|
||||
public Command(String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("Name must not be null.");
|
||||
}
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new command with the given timeout and a default name.
|
||||
* The default name is the name of the class.
|
||||
* @param timeout the time (in seconds) before this command "times out"
|
||||
* @throws IllegalArgumentException if given a negative timeout
|
||||
* @see Command#isTimedOut() isTimedOut()
|
||||
*/
|
||||
public Command(double timeout) {
|
||||
this();
|
||||
if (timeout < 0) {
|
||||
throw new IllegalArgumentException("Timeout must not be negative. Given:" + timeout);
|
||||
}
|
||||
m_timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new command with the given name and timeout.
|
||||
* @param name the name of the command
|
||||
* @param timeout the time (in seconds) before this command "times out"
|
||||
* @throws IllegalArgumentException if given a negative timeout or name was null.
|
||||
* @see Command#isTimedOut() isTimedOut()
|
||||
*/
|
||||
public Command(String name, double timeout) {
|
||||
this(name);
|
||||
if (timeout < 0) {
|
||||
throw new IllegalArgumentException("Timeout must not be negative. Given:" + timeout);
|
||||
}
|
||||
m_timeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this command.
|
||||
* If no name was specified in the constructor,
|
||||
* then the default is the name of the class.
|
||||
* @return the name of this command
|
||||
*/
|
||||
public String getName() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timeout of this command.
|
||||
* @param seconds the timeout (in seconds)
|
||||
* @throws IllegalArgumentException if seconds is negative
|
||||
* @see Command#isTimedOut() isTimedOut()
|
||||
*/
|
||||
protected synchronized final void setTimeout(double seconds) {
|
||||
if (seconds < 0) {
|
||||
throw new IllegalArgumentException("Seconds must be positive. Given:" + seconds);
|
||||
}
|
||||
m_timeout = seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time since this command was initialized (in seconds).
|
||||
* This function will work even if there is no specified timeout.
|
||||
* @return the time since this command was initialized (in seconds).
|
||||
*/
|
||||
public synchronized final double timeSinceInitialized() {
|
||||
return m_startTime < 0 ? 0 : Timer.getFPGATimestamp() - m_startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method specifies that the given {@link Subsystem} is used by this command.
|
||||
* This method is crucial to the functioning of the Command System in general.
|
||||
*
|
||||
* <p>Note that the recommended way to call this method is in the constructor.</p>
|
||||
*
|
||||
* @param subsystem the {@link Subsystem} required
|
||||
* @throws IllegalArgumentException if subsystem is null
|
||||
* @throws IllegalUseOfCommandException if this command has started before or if it has been given to a {@link CommandGroup}
|
||||
* @see Subsystem
|
||||
*/
|
||||
protected synchronized void requires(Subsystem subsystem) {
|
||||
validate("Can not add new requirement to command");
|
||||
if (subsystem != null) {
|
||||
if (m_requirements == null) {
|
||||
m_requirements = new Set();
|
||||
}
|
||||
m_requirements.add(subsystem);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Subsystem must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the command has been removed.
|
||||
* This will call {@link Command#interrupted() interrupted()} or {@link Command#end() end()}.
|
||||
*/
|
||||
synchronized void removed() {
|
||||
if (m_initialized) {
|
||||
if (isCanceled()) {
|
||||
interrupted();
|
||||
_interrupted();
|
||||
} else {
|
||||
end();
|
||||
_end();
|
||||
}
|
||||
}
|
||||
m_initialized = false;
|
||||
m_canceled = false;
|
||||
m_running = false;
|
||||
if (table != null) {
|
||||
table.putBoolean("running", false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The run method is used internally to actually run the commands.
|
||||
* @return whether or not the command should stay within the {@link Scheduler}.
|
||||
*/
|
||||
synchronized boolean run() {
|
||||
if (!m_runWhenDisabled && m_parent == null && DriverStation.getInstance().isDisabled()) {
|
||||
cancel();
|
||||
}
|
||||
if (isCanceled()) {
|
||||
return false;
|
||||
}
|
||||
if (!m_initialized) {
|
||||
m_initialized = true;
|
||||
startTiming();
|
||||
_initialize();
|
||||
initialize();
|
||||
}
|
||||
_execute();
|
||||
execute();
|
||||
return !isFinished();
|
||||
}
|
||||
|
||||
/**
|
||||
* The initialize method is called the first time this Command is run after
|
||||
* being started.
|
||||
*/
|
||||
protected abstract void initialize();
|
||||
|
||||
/** A shadow method called before {@link Command#initialize() initialize()} */
|
||||
void _initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The execute method is called repeatedly until this Command either finishes
|
||||
* or is canceled.
|
||||
*/
|
||||
protected abstract void execute();
|
||||
|
||||
/** A shadow method called before {@link Command#execute() execute()} */
|
||||
void _execute() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this command is finished.
|
||||
* If it is, then the command will be removed
|
||||
* and {@link Command#end() end()} will be called.
|
||||
*
|
||||
* <p>It may be useful for a team to reference the {@link Command#isTimedOut() isTimedOut()} method
|
||||
* for time-sensitive commands.</p>
|
||||
* @return whether this command is finished.
|
||||
* @see Command#isTimedOut() isTimedOut()
|
||||
*/
|
||||
protected abstract boolean isFinished();
|
||||
|
||||
/**
|
||||
* Called when the command ended peacefully. This is where you may want
|
||||
* to wrap up loose ends, like shutting off a motor that was being used
|
||||
* in the command.
|
||||
*/
|
||||
protected abstract void end();
|
||||
|
||||
/** A shadow method called after {@link Command#end() end()}. */
|
||||
void _end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the command ends because somebody called {@link Command#cancel() cancel()}
|
||||
* or another command shared the same requirements as this one, and booted
|
||||
* it out.
|
||||
*
|
||||
* <p>This is where you may want
|
||||
* to wrap up loose ends, like shutting off a motor that was being used
|
||||
* in the command.</p>
|
||||
*
|
||||
* <p>Generally, it is useful to simply call the {@link Command#end() end()} method
|
||||
* within this method</p>
|
||||
*/
|
||||
protected abstract void interrupted();
|
||||
|
||||
/** A shadow method called after {@link Command#interrupted() interrupted()}. */
|
||||
void _interrupted() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to indicate that the timer should start.
|
||||
* This is called right before {@link Command#initialize() initialize()} is, inside the
|
||||
* {@link Command#run() run()} method.
|
||||
*/
|
||||
private void startTiming() {
|
||||
m_startTime = Timer.getFPGATimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@link Command#timeSinceInitialized() timeSinceInitialized()}
|
||||
* method returns a number which is greater than or equal to the timeout for the command.
|
||||
* If there is no timeout, this will always return false.
|
||||
* @return whether the time has expired
|
||||
*/
|
||||
protected synchronized boolean isTimedOut() {
|
||||
return m_timeout != -1 && timeSinceInitialized() >= m_timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requirements (as an {@link Enumeration Enumeration} of {@link Subsystem Subsystems}) of this command
|
||||
* @return the requirements (as an {@link Enumeration Enumeration} of {@link Subsystem Subsystems}) of this command
|
||||
*/
|
||||
synchronized Enumeration getRequirements() {
|
||||
return m_requirements == null ? emptyEnumeration : m_requirements.getElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents further changes from being made
|
||||
*/
|
||||
synchronized void lockChanges() {
|
||||
m_locked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If changes are locked, then this will throw an {@link IllegalUseOfCommandException}.
|
||||
* @param message the message to say (it is appended by a default message)
|
||||
*/
|
||||
synchronized void validate(String message) {
|
||||
if (m_locked) {
|
||||
throw new IllegalUseOfCommandException(message + " after being started or being added to a command group");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent of this command. No actual change is made to the group.
|
||||
* @param parent the parent
|
||||
* @throws IllegalUseOfCommandException if this {@link Command} already is already in a group
|
||||
*/
|
||||
synchronized void setParent(CommandGroup parent) {
|
||||
if (this.m_parent != null) {
|
||||
throw new IllegalUseOfCommandException("Can not give command to a command group after already being put in a command group");
|
||||
}
|
||||
lockChanges();
|
||||
this.m_parent = parent;
|
||||
if (table != null) {
|
||||
table.putBoolean("isParented", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the command. Gets the command ready to start.
|
||||
* <p>Note that the command will eventually start, however it will not necessarily
|
||||
* do so immediately, and may in fact be canceled before initialize is even called.</p>
|
||||
* @throws IllegalUseOfCommandException if the command is a part of a CommandGroup
|
||||
*/
|
||||
public synchronized void start() {
|
||||
lockChanges();
|
||||
if (m_parent != null) {
|
||||
throw new IllegalUseOfCommandException("Can not start a command that is a part of a command group");
|
||||
}
|
||||
Scheduler.getInstance().add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used internally to mark that the command has been started.
|
||||
* The lifecycle of a command is:
|
||||
*
|
||||
* startRunning() is called.
|
||||
* run() is called (multiple times potentially)
|
||||
* removed() is called
|
||||
*
|
||||
* It is very important that startRunning and removed be called in order or some assumptions
|
||||
* of the code will be broken.
|
||||
*/
|
||||
synchronized void startRunning() {
|
||||
m_running = true;
|
||||
m_startTime = -1;
|
||||
if (table != null) {
|
||||
table.putBoolean("running", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the command is running.
|
||||
* This may return true even if the command has just been canceled, as it may
|
||||
* not have yet called {@link Command#interrupted()}.
|
||||
* @return whether or not the command is running
|
||||
*/
|
||||
public synchronized boolean isRunning() {
|
||||
return m_running;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will cancel the current command.
|
||||
* <p>This will cancel the current command eventually. It can be called multiple times.
|
||||
* And it can be called when the command is not running. If the command is running though,
|
||||
* then the command will be marked as canceled and eventually removed.</p>
|
||||
* <p>A command can not be canceled
|
||||
* if it is a part of a command group, you must cancel the command group instead.</p>
|
||||
* @throws IllegalUseOfCommandException if this command is a part of a command group
|
||||
*/
|
||||
public synchronized void cancel() {
|
||||
if (m_parent != null) {
|
||||
throw new IllegalUseOfCommandException("Can not manually cancel a command in a command group");
|
||||
}
|
||||
_cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* This works like cancel(), except that it doesn't throw an exception if it is a part
|
||||
* of a command group. Should only be called by the parent command group.
|
||||
*/
|
||||
synchronized void _cancel() {
|
||||
if (isRunning()) {
|
||||
m_canceled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this has been canceled.
|
||||
* @return whether or not this has been canceled
|
||||
*/
|
||||
public synchronized boolean isCanceled() {
|
||||
return m_canceled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this command can be interrupted.
|
||||
* @return whether or not this command can be interrupted
|
||||
*/
|
||||
public synchronized boolean isInterruptible() {
|
||||
return m_interruptible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this command can be interrupted.
|
||||
* @param interruptible whether or not this command can be interrupted
|
||||
*/
|
||||
protected synchronized void setInterruptible(boolean interruptible) {
|
||||
this.m_interruptible = interruptible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the command requires the given {@link Subsystem}.
|
||||
* @param system the system
|
||||
* @return whether or not the subsystem is required, or false if given null
|
||||
*/
|
||||
public synchronized boolean doesRequire(Subsystem system) {
|
||||
return m_requirements != null && m_requirements.contains(system);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link CommandGroup} that this command is a part of.
|
||||
* Will return null if this {@link Command} is not in a group.
|
||||
* @return the {@link CommandGroup} that this command is a part of (or null if not in group)
|
||||
*/
|
||||
public synchronized CommandGroup getGroup() {
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this {@link Command} should run when the robot is disabled.
|
||||
*
|
||||
* <p>By default a command will not run when the robot is disabled, and will in fact be canceled.</p>
|
||||
* @param run whether or not this command should run when the robot is disabled
|
||||
*/
|
||||
public void setRunWhenDisabled(boolean run) {
|
||||
m_runWhenDisabled = run;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this {@link Command} will run when the robot is disabled, or if it will cancel itself.
|
||||
* @return whether or not this {@link Command} will run when the robot is disabled, or if it will cancel itself
|
||||
*/
|
||||
public boolean willRunWhenDisabled() {
|
||||
return m_runWhenDisabled;
|
||||
}
|
||||
/** An empty enumeration given whenever there are no requirements */
|
||||
private static Enumeration emptyEnumeration = new Enumeration() {
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The string representation for a {@link Command} is by default its name.
|
||||
* @return the string representation of this object
|
||||
*/
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "Command";
|
||||
}
|
||||
private ITableListener listener = new ITableListener() {
|
||||
public void valueChanged(ITable table, String key, Object value, boolean isNew) {
|
||||
if (((Boolean) value).booleanValue()) {
|
||||
start();
|
||||
} else {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
};
|
||||
private ITable table;
|
||||
public void initTable(ITable table) {
|
||||
if(this.table!=null)
|
||||
this.table.removeTableListener(listener);
|
||||
this.table = table;
|
||||
if(table!=null) {
|
||||
table.putString("name", getName());
|
||||
table.putBoolean("running", isRunning());
|
||||
table.putBoolean("isParented", m_parent != null);
|
||||
table.addTableListener("running", listener, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* A {@link CommandGroup} is a list of commands which are executed in sequence.
|
||||
*
|
||||
* <p>Commands in a {@link CommandGroup} are added using the {@link CommandGroup#addSequential(Command) addSequential(...)} method
|
||||
* and are called sequentially.
|
||||
* {@link CommandGroup CommandGroups} are themselves {@link Command commands}
|
||||
* and can be given to other {@link CommandGroup CommandGroups}.</p>
|
||||
*
|
||||
* <p>{@link CommandGroup CommandGroups} will carry all of the requirements of their {@link Command subcommands}. Additional
|
||||
* requirements can be specified by calling {@link CommandGroup#requires(Subsystem) requires(...)}
|
||||
* normally in the constructor.</P>
|
||||
*
|
||||
* <p>CommandGroups can also execute commands in parallel, simply by adding them
|
||||
* using {@link CommandGroup#addParallel(Command) addParallel(...)}.</p>
|
||||
*
|
||||
* @author Brad Miller
|
||||
* @author Joe Grinstead
|
||||
* @see Command
|
||||
* @see Subsystem
|
||||
* @see IllegalUseOfCommandException
|
||||
*/
|
||||
public class CommandGroup extends Command {
|
||||
|
||||
/** The commands in this group (stored in entries) */
|
||||
private Vector m_commands = new Vector();
|
||||
/** The active children in this group (stored in entries) */
|
||||
Vector m_children = new Vector();
|
||||
/** The current command, -1 signifies that none have been run */
|
||||
private int m_currentCommandIndex = -1;
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandGroup CommandGroup}.
|
||||
* The name of this command will be set to its class name.
|
||||
*/
|
||||
public CommandGroup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link CommandGroup CommandGroup} with the given name.
|
||||
* @param name the name for this command group
|
||||
* @throws IllegalArgumentException if name is null
|
||||
*/
|
||||
public CommandGroup(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new {@link Command Command} to the group. The {@link Command Command} will be started after
|
||||
* all the previously added {@link Command Commands}.
|
||||
*
|
||||
* <p>Note that any requirements the given {@link Command Command} has will be added to the
|
||||
* group. For this reason, a {@link Command Command's} requirements can not be changed after
|
||||
* being added to a group.</p>
|
||||
*
|
||||
* <p>It is recommended that this method be called in the constructor.</p>
|
||||
*
|
||||
* @param command The {@link Command Command} to be added
|
||||
* @throws IllegalUseOfCommandException if the group has been started before or been given to another group
|
||||
* @throws IllegalArgumentException if command is null
|
||||
*/
|
||||
public synchronized final void addSequential(Command command) {
|
||||
validate("Can not add new command to command group");
|
||||
if (command == null) {
|
||||
throw new IllegalArgumentException("Given null command");
|
||||
}
|
||||
|
||||
command.setParent(this);
|
||||
|
||||
m_commands.addElement(new Entry(command, Entry.IN_SEQUENCE));
|
||||
for (Enumeration e = command.getRequirements(); e.hasMoreElements();) {
|
||||
requires((Subsystem) e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new {@link Command Command} to the group with a given timeout.
|
||||
* The {@link Command Command} will be started after all the previously added commands.
|
||||
*
|
||||
* <p>Once the {@link Command Command} is started, it will be run until it finishes or the time
|
||||
* expires, whichever is sooner. Note that the given {@link Command Command} will have no
|
||||
* knowledge that it is on a timer.</p>
|
||||
*
|
||||
* <p>Note that any requirements the given {@link Command Command} has will be added to the
|
||||
* group. For this reason, a {@link Command Command's} requirements can not be changed after
|
||||
* being added to a group.</p>
|
||||
*
|
||||
* <p>It is recommended that this method be called in the constructor.</p>
|
||||
*
|
||||
* @param command The {@link Command Command} to be added
|
||||
* @param timeout The timeout (in seconds)
|
||||
* @throws IllegalUseOfCommandException if the group has been started before or been given to another group or
|
||||
* if the {@link Command Command} has been started before or been given to another group
|
||||
* @throws IllegalArgumentException if command is null or timeout is negative
|
||||
*/
|
||||
public synchronized final void addSequential(Command command, double timeout) {
|
||||
validate("Can not add new command to command group");
|
||||
if (command == null) {
|
||||
throw new IllegalArgumentException("Given null command");
|
||||
}
|
||||
if (timeout < 0) {
|
||||
throw new IllegalArgumentException("Can not be given a negative timeout");
|
||||
}
|
||||
|
||||
command.setParent(this);
|
||||
|
||||
m_commands.addElement(new Entry(command, Entry.IN_SEQUENCE, timeout));
|
||||
for (Enumeration e = command.getRequirements(); e.hasMoreElements();) {
|
||||
requires((Subsystem) e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new child {@link Command} to the group. The {@link Command} will be started after
|
||||
* all the previously added {@link Command Commands}.
|
||||
*
|
||||
* <p>Instead of waiting for the child to finish, a {@link CommandGroup} will have it
|
||||
* run at the same time as the subsequent {@link Command Commands}. The child will run until either
|
||||
* it finishes, a new child with conflicting requirements is started, or
|
||||
* the main sequence runs a {@link Command} with conflicting requirements. In the latter
|
||||
* two cases, the child will be canceled even if it says it can't be
|
||||
* interrupted.</p>
|
||||
*
|
||||
* <p>Note that any requirements the given {@link Command Command} has will be added to the
|
||||
* group. For this reason, a {@link Command Command's} requirements can not be changed after
|
||||
* being added to a group.</p>
|
||||
*
|
||||
* <p>It is recommended that this method be called in the constructor.</p>
|
||||
*
|
||||
* @param command The command to be added
|
||||
* @throws IllegalUseOfCommandException if the group has been started before or been given to another command group
|
||||
* @throws IllegalArgumentException if command is null
|
||||
*/
|
||||
public synchronized final void addParallel(Command command) {
|
||||
validate("Can not add new command to command group");
|
||||
if (command == null) {
|
||||
throw new NullPointerException("Given null command");
|
||||
}
|
||||
|
||||
command.setParent(this);
|
||||
|
||||
m_commands.addElement(new Entry(command, Entry.BRANCH_CHILD));
|
||||
for (Enumeration e = command.getRequirements(); e.hasMoreElements();) {
|
||||
requires((Subsystem) e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new child {@link Command} to the group with the given timeout. The {@link Command} will be started after
|
||||
* all the previously added {@link Command Commands}.
|
||||
*
|
||||
* <p>Once the {@link Command Command} is started, it will run until it finishes, is interrupted,
|
||||
* or the time expires, whichever is sooner. Note that the given {@link Command Command} will have no
|
||||
* knowledge that it is on a timer.</p>
|
||||
*
|
||||
* <p>Instead of waiting for the child to finish, a {@link CommandGroup} will have it
|
||||
* run at the same time as the subsequent {@link Command Commands}. The child will run until either
|
||||
* it finishes, the timeout expires, a new child with conflicting requirements is started, or
|
||||
* the main sequence runs a {@link Command} with conflicting requirements. In the latter
|
||||
* two cases, the child will be canceled even if it says it can't be
|
||||
* interrupted.</p>
|
||||
*
|
||||
* <p>Note that any requirements the given {@link Command Command} has will be added to the
|
||||
* group. For this reason, a {@link Command Command's} requirements can not be changed after
|
||||
* being added to a group.</p>
|
||||
*
|
||||
* <p>It is recommended that this method be called in the constructor.</p>
|
||||
*
|
||||
* @param command The command to be added
|
||||
* @param timeout The timeout (in seconds)
|
||||
* @throws IllegalUseOfCommandException if the group has been started before or been given to another command group
|
||||
* @throws IllegalArgumentException if command is null
|
||||
*/
|
||||
public synchronized final void addParallel(Command command, double timeout) {
|
||||
validate("Can not add new command to command group");
|
||||
if (command == null) {
|
||||
throw new NullPointerException("Given null command");
|
||||
}
|
||||
if (timeout < 0) {
|
||||
throw new IllegalArgumentException("Can not be given a negative timeout");
|
||||
}
|
||||
|
||||
command.setParent(this);
|
||||
|
||||
m_commands.addElement(new Entry(command, Entry.BRANCH_CHILD, timeout));
|
||||
for (Enumeration e = command.getRequirements(); e.hasMoreElements();) {
|
||||
requires((Subsystem) e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
void _initialize() {
|
||||
m_currentCommandIndex = -1;
|
||||
}
|
||||
|
||||
void _execute() {
|
||||
Entry entry = null;
|
||||
Command cmd = null;
|
||||
boolean firstRun = false;
|
||||
if (m_currentCommandIndex == -1) {
|
||||
firstRun = true;
|
||||
m_currentCommandIndex = 0;
|
||||
}
|
||||
|
||||
while (m_currentCommandIndex < m_commands.size()) {
|
||||
|
||||
if (cmd != null) {
|
||||
if (entry.isTimedOut()) {
|
||||
cmd._cancel();
|
||||
}
|
||||
if (cmd.run()) {
|
||||
break;
|
||||
} else {
|
||||
cmd.removed();
|
||||
m_currentCommandIndex++;
|
||||
firstRun = true;
|
||||
cmd = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
entry = (Entry) m_commands.elementAt(m_currentCommandIndex);
|
||||
cmd = null;
|
||||
|
||||
switch (entry.state) {
|
||||
case Entry.IN_SEQUENCE:
|
||||
cmd = entry.command;
|
||||
if (firstRun) {
|
||||
cmd.startRunning();
|
||||
cancelConflicts(cmd);
|
||||
}
|
||||
firstRun = false;
|
||||
break;
|
||||
case Entry.BRANCH_PEER:
|
||||
m_currentCommandIndex++;
|
||||
entry.command.start();
|
||||
break;
|
||||
case Entry.BRANCH_CHILD:
|
||||
m_currentCommandIndex++;
|
||||
cancelConflicts(entry.command);
|
||||
entry.command.startRunning();
|
||||
m_children.addElement(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Run Children
|
||||
for (int i = 0; i < m_children.size(); i++) {
|
||||
entry = (Entry) m_children.elementAt(i);
|
||||
Command child = entry.command;
|
||||
if (entry.isTimedOut()) {
|
||||
child._cancel();
|
||||
}
|
||||
if (!child.run()) {
|
||||
child.removed();
|
||||
m_children.removeElementAt(i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _end() {
|
||||
// Theoretically, we don't have to check this, but we do if teams override the isFinished method
|
||||
if (m_currentCommandIndex != -1 && m_currentCommandIndex < m_commands.size()) {
|
||||
Command cmd = ((Entry) m_commands.elementAt(m_currentCommandIndex)).command;
|
||||
cmd._cancel();
|
||||
cmd.removed();
|
||||
}
|
||||
|
||||
Enumeration children = m_children.elements();
|
||||
while (children.hasMoreElements()) {
|
||||
Command cmd = ((Entry) children.nextElement()).command;
|
||||
cmd._cancel();
|
||||
cmd.removed();
|
||||
}
|
||||
m_children.removeAllElements();
|
||||
}
|
||||
|
||||
void _interrupted() {
|
||||
_end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all the {@link Command Commands} in this group
|
||||
* have been started and have finished.
|
||||
*
|
||||
* <p>Teams may override this method, although they should probably
|
||||
* reference super.isFinished() if they do.</p>
|
||||
*
|
||||
* @return whether this {@link CommandGroup} is finished
|
||||
*/
|
||||
protected boolean isFinished() {
|
||||
return m_currentCommandIndex >= m_commands.size() && m_children.isEmpty();
|
||||
}
|
||||
|
||||
// Can be overwritten by teams
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
// Can be overwritten by teams
|
||||
protected void execute() {
|
||||
}
|
||||
|
||||
// Can be overwritten by teams
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
// Can be overwritten by teams
|
||||
protected void interrupted() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this group is interruptible.
|
||||
* A command group will be uninterruptible if {@link CommandGroup#setInterruptible(boolean) setInterruptable(false)}
|
||||
* was called or if it is currently running an uninterruptible command
|
||||
* or child.
|
||||
*
|
||||
* @return whether or not this {@link CommandGroup} is interruptible.
|
||||
*/
|
||||
public synchronized boolean isInterruptible() {
|
||||
if (!super.isInterruptible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_currentCommandIndex != -1 && m_currentCommandIndex < m_commands.size()) {
|
||||
Command cmd = ((Entry) m_commands.elementAt(m_currentCommandIndex)).command;
|
||||
if (!cmd.isInterruptible()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_children.size(); i++) {
|
||||
if (!((Entry) m_children.elementAt(i)).command.isInterruptible()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cancelConflicts(Command command) {
|
||||
for (int i = 0; i < m_children.size(); i++) {
|
||||
Command child = ((Entry) m_children.elementAt(i)).command;
|
||||
|
||||
Enumeration requirements = command.getRequirements();
|
||||
|
||||
while (requirements.hasMoreElements()) {
|
||||
Object requirement = requirements.nextElement();
|
||||
if (child.doesRequire((Subsystem) requirement)) {
|
||||
child._cancel();
|
||||
child.removed();
|
||||
m_children.removeElementAt(i--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Entry {
|
||||
|
||||
private static final int IN_SEQUENCE = 0;
|
||||
private static final int BRANCH_PEER = 1;
|
||||
private static final int BRANCH_CHILD = 2;
|
||||
Command command;
|
||||
int state;
|
||||
double timeout;
|
||||
|
||||
Entry(Command command, int state) {
|
||||
this.command = command;
|
||||
this.state = state;
|
||||
this.timeout = -1;
|
||||
}
|
||||
|
||||
Entry(Command command, int state, double timeout) {
|
||||
this.command = command;
|
||||
this.state = state;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
boolean isTimedOut() {
|
||||
if (timeout == -1) {
|
||||
return false;
|
||||
} else {
|
||||
double time = command.timeSinceInitialized();
|
||||
return time == 0 ? false : time >= timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
* This exception will be thrown if a command is used illegally. There are
|
||||
* several ways for this to happen.
|
||||
*
|
||||
* <p>Basically, a command becomes "locked" after it is first started or added
|
||||
* to a command group.</p>
|
||||
*
|
||||
* <p>This exception should be thrown if (after a command has been locked) its requirements
|
||||
* change, it is put into multiple command groups,
|
||||
* it is started from outside its command group, or it adds a new child.</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public class IllegalUseOfCommandException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Instantiates an {@link IllegalUseOfCommandException}.
|
||||
*/
|
||||
public IllegalUseOfCommandException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates an {@link IllegalUseOfCommandException} with the given message.
|
||||
* @param message the message
|
||||
*/
|
||||
public IllegalUseOfCommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Greg
|
||||
*/
|
||||
class LinkedListElement {
|
||||
private LinkedListElement next;
|
||||
private LinkedListElement previous;
|
||||
private Command data;
|
||||
|
||||
public LinkedListElement() {
|
||||
}
|
||||
|
||||
public void setData(Command newData) {
|
||||
data = newData;
|
||||
}
|
||||
|
||||
public Command getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public LinkedListElement getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
public LinkedListElement getPrevious() {
|
||||
return previous;
|
||||
}
|
||||
|
||||
public void add(LinkedListElement l) {
|
||||
if(next == null) {
|
||||
next = l;
|
||||
next.previous = this;
|
||||
} else {
|
||||
next.previous = l;
|
||||
l.next = next;
|
||||
l.previous = this;
|
||||
next = l;
|
||||
}
|
||||
}
|
||||
|
||||
public LinkedListElement remove() {
|
||||
if(previous == null && next == null) {
|
||||
|
||||
} else if(next == null) {
|
||||
previous.next = null;
|
||||
} else if(previous == null) {
|
||||
next.previous = null;
|
||||
} else {
|
||||
next.previous = previous;
|
||||
previous.next = next;
|
||||
}
|
||||
LinkedListElement n = next;
|
||||
next = null;
|
||||
previous = null;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import edu.wpi.first.wpilibj.PIDController;
|
||||
import edu.wpi.first.wpilibj.PIDOutput;
|
||||
import edu.wpi.first.wpilibj.PIDSource;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
/**
|
||||
* This class defines a {@link Command} which interacts heavily with a PID loop.
|
||||
*
|
||||
* <p>It provides some convenience methods to run an internal {@link PIDController}.
|
||||
* It will also start and stop said {@link PIDController} when the {@link PIDCommand} is
|
||||
* first initialized and ended/interrupted.</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public abstract class PIDCommand extends Command implements Sendable {
|
||||
|
||||
/** The internal {@link PIDController} */
|
||||
private PIDController controller;
|
||||
/** An output which calls {@link PIDCommand#usePIDOutput(double)} */
|
||||
private PIDOutput output = new PIDOutput() {
|
||||
|
||||
public void pidWrite(double output) {
|
||||
usePIDOutput(output);
|
||||
}
|
||||
};
|
||||
/** A source which calls {@link PIDCommand#returnPIDInput()} */
|
||||
private PIDSource source = new PIDSource() {
|
||||
|
||||
public double pidGet() {
|
||||
return returnPIDInput();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDCommand} that will use the given p, i and d values.
|
||||
* @param name the name of the command
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
*/
|
||||
public PIDCommand(String name, double p, double i, double d) {
|
||||
super(name);
|
||||
controller = new PIDController(p, i, d, source, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDCommand} that will use the given p, i and d values. It will also space the time
|
||||
* between PID loop calculations to be equal to the given period.
|
||||
* @param name the name
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param period the time (in seconds) between calculations
|
||||
*/
|
||||
public PIDCommand(String name, double p, double i, double d, double period) {
|
||||
super(name);
|
||||
controller = new PIDController(p, i, d, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDCommand} that will use the given p, i and d values.
|
||||
* It will use the class name as its name.
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
*/
|
||||
public PIDCommand(double p, double i, double d) {
|
||||
controller = new PIDController(p, i, d, source, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDCommand} that will use the given p, i and d values.
|
||||
* It will use the class name as its name..
|
||||
* It will also space the time
|
||||
* between PID loop calculations to be equal to the given period.
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param period the time (in seconds) between calculations
|
||||
*/
|
||||
public PIDCommand(double p, double i, double d, double period) {
|
||||
controller = new PIDController(p, i, d, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PIDController} used by this {@link PIDCommand}.
|
||||
* Use this if you would like to fine tune the pid loop.
|
||||
*
|
||||
* <p>Notice that calling {@link PIDController#setSetpoint(double) setSetpoint(...)} on the controller
|
||||
* will not result in the setpoint being trimmed to be in
|
||||
* the range defined by {@link PIDCommand#setSetpointRange(double, double) setSetpointRange(...)}.</p>
|
||||
*
|
||||
* @return the {@link PIDController} used by this {@link PIDCommand}
|
||||
*/
|
||||
protected PIDController getPIDController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
void _initialize() {
|
||||
controller.enable();
|
||||
}
|
||||
|
||||
void _end() {
|
||||
controller.disable();
|
||||
}
|
||||
|
||||
void _interrupted() {
|
||||
_end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given value to the setpoint.
|
||||
* If {@link PIDCommand#setRange(double, double) setRange(...)} was used,
|
||||
* then the bounds will still be honored by this method.
|
||||
* @param deltaSetpoint the change in the setpoint
|
||||
*/
|
||||
public void setSetpointRelative(double deltaSetpoint) {
|
||||
setSetpoint(getSetpoint() + deltaSetpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setpoint to the given value. If {@link PIDCommand#setRange(double, double) setRange(...)}
|
||||
* was called,
|
||||
* then the given setpoint
|
||||
* will be trimmed to fit within the range.
|
||||
* @param setpoint the new setpoint
|
||||
*/
|
||||
protected void setSetpoint(double setpoint) {
|
||||
controller.setSetpoint(setpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setpoint.
|
||||
* @return the setpoint
|
||||
*/
|
||||
protected double getSetpoint() {
|
||||
return controller.getSetpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position
|
||||
* @return the current position
|
||||
*/
|
||||
protected double getPosition() {
|
||||
return returnPIDInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input for the pid loop.
|
||||
*
|
||||
* <p>It returns the input for the pid loop, so if this command was based
|
||||
* off of a gyro, then it should return the angle of the gyro</p>
|
||||
*
|
||||
* <p>All subclasses of {@link PIDCommand} must override this method.</p>
|
||||
*
|
||||
* <p>This method will be called in a different thread then the {@link Scheduler} thread.</p>
|
||||
*
|
||||
* @return the value the pid loop should use as input
|
||||
*/
|
||||
protected abstract double returnPIDInput();
|
||||
|
||||
/**
|
||||
* Uses the value that the pid loop calculated. The calculated value is the "output" parameter.
|
||||
* This method is a good time to set motor values, maybe something along the lines of <code>driveline.tankDrive(output, -output)</code>
|
||||
*
|
||||
* <p>All subclasses of {@link PIDCommand} must override this method.</p>
|
||||
*
|
||||
* <p>This method will be called in a different thread then the {@link Scheduler} thread.</p>
|
||||
*
|
||||
* @param output the value the pid loop calculated
|
||||
*/
|
||||
protected abstract void usePIDOutput(double output);
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "PIDCommand";
|
||||
}
|
||||
public void initTable(ITable table) {
|
||||
controller.initTable(table);
|
||||
super.initTable(table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import edu.wpi.first.wpilibj.PIDController;
|
||||
import edu.wpi.first.wpilibj.PIDOutput;
|
||||
import edu.wpi.first.wpilibj.PIDSource;
|
||||
import edu.wpi.first.wpilibj.Sendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
/**
|
||||
* This class is designed to handle the case where there is a {@link Subsystem}
|
||||
* which uses a single {@link PIDController} almost constantly (for instance,
|
||||
* an elevator which attempts to stay at a constant height).
|
||||
*
|
||||
* <p>It provides some convenience methods to run an internal {@link PIDController}.
|
||||
* It also allows access to the internal {@link PIDController} in order to give total control
|
||||
* to the programmer.</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public abstract class PIDSubsystem extends Subsystem implements Sendable {
|
||||
|
||||
/** The internal {@link PIDController} */
|
||||
private PIDController controller;
|
||||
/** An output which calls {@link PIDCommand#usePIDOutput(double)} */
|
||||
private PIDOutput output = new PIDOutput() {
|
||||
|
||||
public void pidWrite(double output) {
|
||||
usePIDOutput(output);
|
||||
}
|
||||
};
|
||||
/** A source which calls {@link PIDCommand#returnPIDInput()} */
|
||||
private PIDSource source = new PIDSource() {
|
||||
|
||||
public double pidGet() {
|
||||
return returnPIDInput();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
|
||||
* @param name the name
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
*/
|
||||
public PIDSubsystem(String name, double p, double i, double d) {
|
||||
super(name);
|
||||
controller = new PIDController(p, i, d, source, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
|
||||
* @param name the name
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param f the feed forward value
|
||||
*/
|
||||
public PIDSubsystem(String name, double p, double i, double d, double f) {
|
||||
super(name);
|
||||
controller = new PIDController(p, i, d, f, source, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will also space the time
|
||||
* between PID loop calculations to be equal to the given period.
|
||||
* @param name the name
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param period the time (in seconds) between calculations
|
||||
*/
|
||||
public PIDSubsystem(String name, double p, double i, double d, double f, double period) {
|
||||
super(name);
|
||||
controller = new PIDController(p, i, d, f, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
|
||||
* It will use the class name as its name.
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
*/
|
||||
public PIDSubsystem(double p, double i, double d) {
|
||||
controller = new PIDController(p, i, d, source, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
|
||||
* It will use the class name as its name.
|
||||
* It will also space the time
|
||||
* between PID loop calculations to be equal to the given period.
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param f the feed forward coefficient
|
||||
* @param period the time (in seconds) between calculations
|
||||
*/
|
||||
public PIDSubsystem(double p, double i, double d, double period, double f) {
|
||||
controller = new PIDController(p, i, d, f, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
|
||||
* It will use the class name as its name.
|
||||
* It will also space the time
|
||||
* between PID loop calculations to be equal to the given period.
|
||||
* @param p the proportional value
|
||||
* @param i the integral value
|
||||
* @param d the derivative value
|
||||
* @param period the time (in seconds) between calculations
|
||||
*/
|
||||
public PIDSubsystem(double p, double i, double d, double period) {
|
||||
controller = new PIDController(p, i, d, source, output, period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PIDController} used by this {@link PIDSubsystem}.
|
||||
* Use this if you would like to fine tune the pid loop.
|
||||
*
|
||||
* <p>Notice that calling {@link PIDController#setSetpoint(double) setSetpoint(...)} on the controller
|
||||
* will not result in the setpoint being trimmed to be in
|
||||
* the range defined by {@link PIDSubsystem#setSetpointRange(double, double) setSetpointRange(...)}.</p>
|
||||
*
|
||||
* @return the {@link PIDController} used by this {@link PIDSubsystem}
|
||||
*/
|
||||
public PIDController getPIDController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given value to the setpoint.
|
||||
* If {@link PIDCommand#setRange(double, double) setRange(...)} was used,
|
||||
* then the bounds will still be honored by this method.
|
||||
* @param deltaSetpoint the change in the setpoint
|
||||
*/
|
||||
public void setSetpointRelative(double deltaSetpoint) {
|
||||
setSetpoint(getPosition() + deltaSetpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setpoint to the given value. If {@link PIDCommand#setRange(double, double) setRange(...)}
|
||||
* was called,
|
||||
* then the given setpoint
|
||||
* will be trimmed to fit within the range.
|
||||
* @param setpoint the new setpoint
|
||||
*/
|
||||
public void setSetpoint(double setpoint) {
|
||||
controller.setSetpoint(setpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the setpoint.
|
||||
* @return the setpoint
|
||||
*/
|
||||
public double getSetpoint() {
|
||||
return controller.getSetpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position
|
||||
* @return the current position
|
||||
*/
|
||||
public double getPosition() {
|
||||
return returnPIDInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum and minimum values expected from the input.
|
||||
*
|
||||
* @param minimumInput the minimum value expected from the input
|
||||
* @param maximumInput the maximum value expected from the output
|
||||
*/
|
||||
public void setInputRange(double minimumInput, double maximumInput) {
|
||||
controller.setInputRange(minimumInput, maximumInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the absolute error which is considered tolerable for use with
|
||||
* OnTarget. The value is in the same range as the PIDInput values.
|
||||
* @param t A PIDController.Tolerance object instance that is for example
|
||||
* AbsoluteTolerance or PercentageTolerance. E.g. setTolerance(new PIDController.AbsoluteTolerance(0.1))
|
||||
*/
|
||||
public void setAbsoluteTolerance(double t) {
|
||||
controller.setAbsoluteTolerance(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the percentage error which is considered tolerable for use with
|
||||
* OnTarget. (Value of 15.0 == 15 percent)
|
||||
* @param t A PIDController.Tolerance object instance that is for example
|
||||
* AbsoluteTolerance or PercentageTolerance. E.g. setTolerance(new PIDController.AbsoluteTolerance(0.1))
|
||||
*/
|
||||
public void setPercentTolerance(double p) {
|
||||
controller.setPercentTolerance(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the error is within the percentage of the total input range,
|
||||
* determined by setTolerance. This assumes that the maximum and minimum input
|
||||
* were set using setInput.
|
||||
* @return true if the error is less than the tolerance
|
||||
*/
|
||||
public boolean onTarget() {
|
||||
return controller.onTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the input for the pid loop.
|
||||
*
|
||||
* <p>It returns the input for the pid loop, so if this Subsystem was based
|
||||
* off of a gyro, then it should return the angle of the gyro</p>
|
||||
*
|
||||
* <p>All subclasses of {@link PIDSubsystem} must override this method.</p>
|
||||
*
|
||||
* @return the value the pid loop should use as input
|
||||
*/
|
||||
protected abstract double returnPIDInput();
|
||||
|
||||
/**
|
||||
* Uses the value that the pid loop calculated. The calculated value is the "output" parameter.
|
||||
* This method is a good time to set motor values, maybe something along the lines of <code>driveline.tankDrive(output, -output)</code>
|
||||
*
|
||||
* <p>All subclasses of {@link PIDSubsystem} must override this method.</p>
|
||||
*
|
||||
* @param output the value the pid loop calculated
|
||||
*/
|
||||
protected abstract void usePIDOutput(double output);
|
||||
|
||||
/**
|
||||
* Enables the internal {@link PIDController}
|
||||
*/
|
||||
public void enable() {
|
||||
controller.enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the internal {@link PIDController}
|
||||
*/
|
||||
public void disable() {
|
||||
controller.disable();
|
||||
}
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "PIDSubsystem";
|
||||
}
|
||||
public void initTable(ITable table) {
|
||||
controller.initTable(table);
|
||||
super.initTable(table);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
* A {@link PrintCommand} is a command which prints out a string when it is initialized, and then immediately finishes.
|
||||
* It is useful if you want a {@link CommandGroup} to print out a string when it reaches a certain point.
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public class PrintCommand extends Command {
|
||||
|
||||
/** The message to print out */
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Instantiates a {@link PrintCommand} which will print the given message when it is run.
|
||||
* @param message the message to print
|
||||
*/
|
||||
public PrintCommand(String message) {
|
||||
super("Print(\"" + message + "\"");
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
protected void execute() {
|
||||
}
|
||||
|
||||
protected boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
protected void interrupted() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
import edu.wpi.first.wpilibj.NamedSendable;
|
||||
import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tInstances;
|
||||
import edu.wpi.first.wpilibj.communication.FRC_NetworkCommunicationsLibrary.tResourceType;
|
||||
import edu.wpi.first.wpilibj.communication.UsageReporting;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.NumberArray;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.StringArray;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
|
||||
/**
|
||||
* The {@link Scheduler} is a singleton which holds the top-level running
|
||||
* commands. It is in charge of both calling the command's
|
||||
* {@link Command#run() run()} method and to make sure that there are no two
|
||||
* commands with conflicting requirements running.
|
||||
*
|
||||
* <p>It is fine if teams wish to take control of the {@link Scheduler}
|
||||
* themselves, all that needs to be done is to call
|
||||
* {@link Scheduler#getInstance() Scheduler.getInstance()}.{@link Scheduler#run() run()}
|
||||
* often to have {@link Command Commands} function correctly. However, this is
|
||||
* already done for you if you use the CommandBased Robot template.</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
* @see Command
|
||||
*/
|
||||
public class Scheduler implements NamedSendable {
|
||||
|
||||
/**
|
||||
* The Singleton Instance
|
||||
*/
|
||||
private static Scheduler instance;
|
||||
|
||||
/**
|
||||
* Returns the {@link Scheduler}, creating it if one does not exist.
|
||||
*
|
||||
* @return the {@link Scheduler}
|
||||
*/
|
||||
public synchronized static Scheduler getInstance() {
|
||||
return instance == null ? instance = new Scheduler() : instance;
|
||||
}
|
||||
/**
|
||||
* A hashtable of active {@link Command Commands} to their
|
||||
* {@link LinkedListElement}
|
||||
*/
|
||||
private Hashtable commandTable = new Hashtable();
|
||||
/**
|
||||
* The {@link Set} of all {@link Subsystem Subsystems}
|
||||
*/
|
||||
private Set subsystems = new Set();
|
||||
/**
|
||||
* The first {@link Command} in the list
|
||||
*/
|
||||
private LinkedListElement firstCommand;
|
||||
/**
|
||||
* The last {@link Command} in the list
|
||||
*/
|
||||
private LinkedListElement lastCommand;
|
||||
/**
|
||||
* Whether or not we are currently adding a command
|
||||
*/
|
||||
private boolean adding = false;
|
||||
/**
|
||||
* Whether or not we are currently disabled
|
||||
*/
|
||||
private boolean disabled = false;
|
||||
/**
|
||||
* A list of all {@link Command Commands} which need to be added
|
||||
*/
|
||||
private Vector additions = new Vector();
|
||||
private ITable m_table;
|
||||
/**
|
||||
* A list of all
|
||||
* {@link edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler Buttons}. It
|
||||
* is created lazily.
|
||||
*/
|
||||
private Vector buttons;
|
||||
private boolean m_runningCommandsChanged;
|
||||
|
||||
/**
|
||||
* Instantiates a {@link Scheduler}.
|
||||
*/
|
||||
private Scheduler() {
|
||||
UsageReporting.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the command to the {@link Scheduler}. This will not add the
|
||||
* {@link Command} immediately, but will instead wait for the proper time in
|
||||
* the {@link Scheduler#run()} loop before doing so. The command returns
|
||||
* immediately and does nothing if given null.
|
||||
*
|
||||
* <p>Adding a {@link Command} to the {@link Scheduler} involves the
|
||||
* {@link Scheduler} removing any {@link Command} which has shared
|
||||
* requirements.</p>
|
||||
*
|
||||
* @param command the command to add
|
||||
*/
|
||||
public void add(Command command) {
|
||||
if (command != null) {
|
||||
additions.addElement(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a button to the {@link Scheduler}. The {@link Scheduler} will poll
|
||||
* the button during its {@link Scheduler#run()}.
|
||||
*
|
||||
* @param button the button to add
|
||||
*/
|
||||
public void addButton(ButtonScheduler button) {
|
||||
if (buttons == null) {
|
||||
buttons = new Vector();
|
||||
}
|
||||
buttons.addElement(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a command immediately to the {@link Scheduler}. This should only be
|
||||
* called in the {@link Scheduler#run()} loop. Any command with conflicting
|
||||
* requirements will be removed, unless it is uninterruptable. Giving
|
||||
* <code>null</code> does nothing.
|
||||
*
|
||||
* @param command the {@link Command} to add
|
||||
*/
|
||||
private void _add(Command command) {
|
||||
if (command == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to make sure no adding during adding
|
||||
if (adding) {
|
||||
System.err.println("WARNING: Can not start command from cancel method. Ignoring:" + command);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only add if not already in
|
||||
if (!commandTable.containsKey(command)) {
|
||||
|
||||
// Check that the requirements can be had
|
||||
Enumeration requirements = command.getRequirements();
|
||||
while (requirements.hasMoreElements()) {
|
||||
Subsystem lock = (Subsystem) requirements.nextElement();
|
||||
if (lock.getCurrentCommand() != null && !lock.getCurrentCommand().isInterruptible()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Give it the requirements
|
||||
adding = true;
|
||||
requirements = command.getRequirements();
|
||||
while (requirements.hasMoreElements()) {
|
||||
Subsystem lock = (Subsystem) requirements.nextElement();
|
||||
if (lock.getCurrentCommand() != null) {
|
||||
lock.getCurrentCommand().cancel();
|
||||
remove(lock.getCurrentCommand());
|
||||
}
|
||||
lock.setCurrentCommand(command);
|
||||
}
|
||||
adding = false;
|
||||
|
||||
// Add it to the list
|
||||
LinkedListElement element = new LinkedListElement();
|
||||
element.setData(command);
|
||||
if (firstCommand == null) {
|
||||
firstCommand = lastCommand = element;
|
||||
} else {
|
||||
lastCommand.add(element);
|
||||
lastCommand = element;
|
||||
}
|
||||
commandTable.put(command, element);
|
||||
|
||||
m_runningCommandsChanged = true;
|
||||
|
||||
command.startRunning();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a single iteration of the loop. This method should be called often
|
||||
* in order to have a functioning {@link Command} system. The loop has five
|
||||
* stages:
|
||||
*
|
||||
* <ol> <li> Poll the Buttons </li> <li> Execute/Remove the Commands </li>
|
||||
* <li> Send values to SmartDashboard </li> <li> Add Commands </li> <li> Add
|
||||
* Defaults </li> </ol>
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
m_runningCommandsChanged = false;
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
} // Don't run when disabled
|
||||
|
||||
// Get button input (going backwards preserves button priority)
|
||||
if (buttons != null) {
|
||||
for (int i = buttons.size() - 1; i >= 0; i--) {
|
||||
((ButtonScheduler) buttons.elementAt(i)).execute();
|
||||
}
|
||||
}
|
||||
// Loop through the commands
|
||||
LinkedListElement e = firstCommand;
|
||||
while (e != null) {
|
||||
Command c = e.getData();
|
||||
e = e.getNext();
|
||||
if (!c.run()) {
|
||||
remove(c);
|
||||
m_runningCommandsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new things
|
||||
for (int i = 0; i < additions.size(); i++) {
|
||||
_add((Command) additions.elementAt(i));
|
||||
}
|
||||
additions.removeAllElements();
|
||||
|
||||
// Add in the defaults
|
||||
Enumeration locks = subsystems.getElements();
|
||||
while (locks.hasMoreElements()) {
|
||||
Subsystem lock = (Subsystem) locks.nextElement();
|
||||
if (lock.getCurrentCommand() == null) {
|
||||
_add(lock.getDefaultCommand());
|
||||
}
|
||||
lock.confirmCommand();
|
||||
}
|
||||
|
||||
updateTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link Subsystem} to this {@link Scheduler}, so that the
|
||||
* {@link Scheduler} might know if a default {@link Command} needs to be
|
||||
* run. All {@link Subsystem Subsystems} should call this.
|
||||
*
|
||||
* @param system the system
|
||||
*/
|
||||
void registerSubsystem(Subsystem system) {
|
||||
if (system != null) {
|
||||
subsystems.add(system);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@link Command} from the {@link Scheduler}.
|
||||
*
|
||||
* @param command the command to remove
|
||||
*/
|
||||
void remove(Command command) {
|
||||
if (command == null || !commandTable.containsKey(command)) {
|
||||
return;
|
||||
}
|
||||
LinkedListElement e = (LinkedListElement) commandTable.get(command);
|
||||
commandTable.remove(command);
|
||||
|
||||
if (e.equals(lastCommand)) {
|
||||
lastCommand = e.getPrevious();
|
||||
}
|
||||
if (e.equals(firstCommand)) {
|
||||
firstCommand = e.getNext();
|
||||
}
|
||||
e.remove();
|
||||
|
||||
Enumeration requirements = command.getRequirements();
|
||||
while (requirements.hasMoreElements()) {
|
||||
((Subsystem) requirements.nextElement()).setCurrentCommand(null);
|
||||
}
|
||||
|
||||
command.removed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all commands
|
||||
*/
|
||||
public void removeAll() {
|
||||
// TODO: Confirm that this works with "uninteruptible" commands
|
||||
while (firstCommand != null) {
|
||||
remove(firstCommand.getData());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the command scheduler.
|
||||
*/
|
||||
public void disable() {
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the command scheduler.
|
||||
*/
|
||||
public void enable() {
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "Scheduler";
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return "Scheduler";
|
||||
}
|
||||
private StringArray commands;
|
||||
private NumberArray ids, toCancel;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void initTable(ITable subtable) {
|
||||
m_table = subtable;
|
||||
commands = new StringArray();
|
||||
ids = new NumberArray();
|
||||
toCancel = new NumberArray();
|
||||
|
||||
m_table.putValue("Names", commands);
|
||||
m_table.putValue("Ids", ids);
|
||||
m_table.putValue("Cancel", toCancel);
|
||||
}
|
||||
|
||||
private void updateTable() {
|
||||
if (m_table != null) {
|
||||
// Get the commands to cancel
|
||||
m_table.retrieveValue("Cancel", toCancel);
|
||||
if (toCancel.size() > 0) {
|
||||
for (LinkedListElement e = firstCommand; e != null; e = e.getNext()) {
|
||||
for (int i = 0; i < toCancel.size(); i++) {
|
||||
if (e.getData().hashCode() == toCancel.get(i)) {
|
||||
e.getData().cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
toCancel.setSize(0);
|
||||
m_table.putValue("Cancel", toCancel);
|
||||
}
|
||||
|
||||
if (m_runningCommandsChanged) {
|
||||
commands.setSize(0);
|
||||
ids.setSize(0);
|
||||
// Set the the running commands
|
||||
for (LinkedListElement e = firstCommand; e != null; e = e.getNext()) {
|
||||
commands.add(e.getData().getName());
|
||||
ids.add(e.getData().hashCode());
|
||||
}
|
||||
m_table.putValue("Names", commands);
|
||||
m_table.putValue("Ids", ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return m_table;
|
||||
}
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "Scheduler";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Greg
|
||||
*/
|
||||
class Set {
|
||||
Vector set = new Vector();
|
||||
|
||||
public Set() {
|
||||
}
|
||||
|
||||
public void add(Object o) {
|
||||
if(set.contains(o)) return;
|
||||
set.addElement(o);
|
||||
}
|
||||
|
||||
public void add(Set s) {
|
||||
Enumeration stuff = s.getElements();
|
||||
for(Enumeration e = stuff; e.hasMoreElements();) {
|
||||
add(e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return set.contains(o);
|
||||
}
|
||||
|
||||
public Enumeration getElements() {
|
||||
return set.elements();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
* A {@link StartCommand} will call the {@link Command#start() start()} method of another command when it is initialized
|
||||
* and will finish immediately.
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public class StartCommand extends Command {
|
||||
|
||||
/** The command to fork */
|
||||
private Command m_commandToFork;
|
||||
|
||||
/**
|
||||
* Instantiates a {@link StartCommand} which will start the
|
||||
* given command whenever its {@link Command#initialize() initialize()} is called.
|
||||
* @param commandToStart the {@link Command} to start
|
||||
*/
|
||||
public StartCommand(Command commandToStart) {
|
||||
super("Start(" + commandToStart + ")");
|
||||
m_commandToFork = commandToStart;
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
m_commandToFork.start();
|
||||
}
|
||||
|
||||
protected void execute() {
|
||||
}
|
||||
|
||||
protected boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
protected void interrupted() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import edu.wpi.first.wpilibj.NamedSendable;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class defines a major component of the robot.
|
||||
*
|
||||
* <p>A good example of a subsystem is the driveline, or a claw if the robot has one.</p>
|
||||
*
|
||||
* <p>All motors should be a part of a subsystem. For instance, all the wheel motors should be
|
||||
* a part of some kind of "Driveline" subsystem.</p>
|
||||
*
|
||||
* <p>Subsystems are used within the command system as requirements for {@link Command}.
|
||||
* Only one command which requires a subsystem can run at a time. Also, subsystems
|
||||
* can have default commands which are started if there is no command running which
|
||||
* requires this subsystem.</p>
|
||||
*
|
||||
* @author Joe Grinstead
|
||||
* @see Command
|
||||
*/
|
||||
public abstract class Subsystem implements NamedSendable {
|
||||
|
||||
/** Whether or not getDefaultCommand() was called */
|
||||
private boolean initializedDefaultCommand = false;
|
||||
/** The current command */
|
||||
private Command currentCommand;
|
||||
private boolean currentCommandChanged;
|
||||
|
||||
/** The default command */
|
||||
private Command defaultCommand;
|
||||
/** The name */
|
||||
private String name;
|
||||
/** List of all subsystems created */
|
||||
private static Vector allSubsystems = new Vector();
|
||||
|
||||
/**
|
||||
* Creates a subsystem with the given name
|
||||
* @param name the name of the subsystem
|
||||
*/
|
||||
public Subsystem(String name) {
|
||||
this.name = name;
|
||||
Scheduler.getInstance().registerSubsystem(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a subsystem. This will set the name to the name of the class.
|
||||
*/
|
||||
public Subsystem() {
|
||||
this.name = getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1);
|
||||
Scheduler.getInstance().registerSubsystem(this);
|
||||
currentCommandChanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the default command for a subsystem
|
||||
* By default subsystems have no default command, but if they do, the default command is set
|
||||
* with this method. It is called on all Subsystems by CommandBase in the users program after
|
||||
* all the Subsystems are created.
|
||||
*/
|
||||
protected abstract void initDefaultCommand();
|
||||
|
||||
/**
|
||||
* Sets the default command. If this is not called or is called with null,
|
||||
* then there will be no default command for the subsystem.
|
||||
*
|
||||
* <p><b>WARNING:</b> This should <b>NOT</b> be called in a constructor if the subsystem is a
|
||||
* singleton.</p>
|
||||
*
|
||||
* @param command the default command (or null if there should be none)
|
||||
* @throws IllegalUseOfCommandException if the command does not require the subsystem
|
||||
*/
|
||||
protected void setDefaultCommand(Command command) {
|
||||
if (command == null) {
|
||||
defaultCommand = null;
|
||||
} else {
|
||||
boolean found = false;
|
||||
Enumeration requirements = command.getRequirements();
|
||||
while (requirements.hasMoreElements()) {
|
||||
if (requirements.nextElement().equals(this)) {
|
||||
found = true;
|
||||
// } else {
|
||||
// throw new IllegalUseOfCommandException("A default command cannot require multiple subsystems");
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
throw new IllegalUseOfCommandException("A default command must require the subsystem");
|
||||
}
|
||||
defaultCommand = command;
|
||||
}
|
||||
if (table != null) {
|
||||
if (defaultCommand != null) {
|
||||
table.putBoolean("hasDefault", true);
|
||||
table.putString("default", defaultCommand.getName());
|
||||
} else {
|
||||
table.putBoolean("hasDefault", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default command (or null if there is none).
|
||||
* @return the default command
|
||||
*/
|
||||
protected Command getDefaultCommand() {
|
||||
if (!initializedDefaultCommand) {
|
||||
initializedDefaultCommand = true;
|
||||
initDefaultCommand();
|
||||
}
|
||||
return defaultCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current command
|
||||
* @param command the new current command
|
||||
*/
|
||||
void setCurrentCommand(Command command) {
|
||||
currentCommand = command;
|
||||
currentCommandChanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this to alert Subsystem that the current command is actually the command.
|
||||
* Sometimes, the {@link Subsystem} is told that it has no command while the {@link Scheduler}
|
||||
* is going through the loop, only to be soon after given a new one. This will avoid that situation.
|
||||
*/
|
||||
void confirmCommand() {
|
||||
if (currentCommandChanged) {
|
||||
if (table != null) {
|
||||
if (currentCommand != null) {
|
||||
table.putBoolean("hasCommand", true);
|
||||
table.putString("command", currentCommand.getName());
|
||||
} else {
|
||||
table.putBoolean("hasCommand", false);
|
||||
}
|
||||
}
|
||||
currentCommandChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the command which currently claims this subsystem.
|
||||
* @return the command which currently claims this subsystem
|
||||
*/
|
||||
public Command getCurrentCommand() {
|
||||
return currentCommand;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this subsystem, which is by default the class name.
|
||||
* @return the name of this subsystem
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSmartDashboardType() {
|
||||
return "Subsystem";
|
||||
}
|
||||
private ITable table;
|
||||
public void initTable(ITable table) {
|
||||
this.table = table;
|
||||
if(table!=null) {
|
||||
if (defaultCommand != null) {
|
||||
table.putBoolean("hasDefault", true);
|
||||
table.putString("default", defaultCommand.getName());
|
||||
} else {
|
||||
table.putBoolean("hasDefault", false);
|
||||
}
|
||||
if (currentCommand != null) {
|
||||
table.putBoolean("hasCommand", true);
|
||||
table.putString("command", currentCommand.getName());
|
||||
} else {
|
||||
table.putBoolean("hasCommand", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ITable getTable() {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
* A {@link WaitCommand} will wait for a certain amount of time before finishing.
|
||||
* It is useful if you want a {@link CommandGroup} to pause for a moment.
|
||||
* @author Joe Grinstead
|
||||
* @see CommandGroup
|
||||
*/
|
||||
public class WaitCommand extends Command {
|
||||
|
||||
/**
|
||||
* Instantiates a {@link WaitCommand} with the given timeout.
|
||||
* @param timeout the time the command takes to run
|
||||
*/
|
||||
public WaitCommand(double timeout) {
|
||||
this("Wait(" + timeout + ")", timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a {@link WaitCommand} with the given timeout.
|
||||
* @param name the name of the command
|
||||
* @param timeout the time the command takes to run
|
||||
*/
|
||||
public WaitCommand(String name, double timeout) {
|
||||
super(name, timeout);
|
||||
}
|
||||
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
protected void execute() {
|
||||
}
|
||||
|
||||
protected boolean isFinished() {
|
||||
return isTimedOut();
|
||||
}
|
||||
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
protected void interrupted() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
/**
|
||||
* This command will only finish if whatever {@link CommandGroup} it is in has no active children.
|
||||
* If it is not a part of a {@link CommandGroup}, then it will finish immediately. If it is itself an
|
||||
* active child, then the {@link CommandGroup} will never end.
|
||||
*
|
||||
* <p>This class is useful for the situation where you want to allow anything running in parallel to finish, before continuing
|
||||
* in the main {@link CommandGroup} sequence.</p>
|
||||
* @author Joe Grinstead
|
||||
*/
|
||||
public class WaitForChildren extends Command {
|
||||
|
||||
protected void initialize() {
|
||||
}
|
||||
|
||||
protected void execute() {
|
||||
}
|
||||
|
||||
protected void end() {
|
||||
}
|
||||
|
||||
protected void interrupted() {
|
||||
}
|
||||
|
||||
protected boolean isFinished() {
|
||||
return getGroup() == null || getGroup().m_children.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* 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.command;
|
||||
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
|
||||
/**
|
||||
* WaitUntilCommand - waits until an absolute game time.
|
||||
* This will wait until the game clock reaches some value, then continue to the next command.
|
||||
* @author brad
|
||||
*
|
||||
*/
|
||||
public class WaitUntilCommand extends Command {
|
||||
|
||||
private double m_time;
|
||||
|
||||
public WaitUntilCommand(double time) {
|
||||
super("WaitUntil(" + time + ")");
|
||||
m_time = time;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we've reached the actual finish time.
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return DriverStation.getInstance().getMatchTime() >= m_time;
|
||||
}
|
||||
|
||||
public void end() {
|
||||
}
|
||||
|
||||
public void interrupted() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
package edu.wpi.first.wpilibj.communication;
|
||||
import com.ochafik.lang.jnaerator.runtime.Structure;
|
||||
import com.ochafik.lang.jnaerator.runtime.Union;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
/**
|
||||
* <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:29</i><br>
|
||||
* This file was autogenerated by <a href="http://jnaerator.googlecode.com/">JNAerator</a>,<br>
|
||||
* a tool written by <a href="http://ochafik.com/">Olivier Chafik</a> that <a href="http://code.google.com/p/jnaerator/wiki/CreditsAndLicense">uses a few opensource projects.</a>.<br>
|
||||
* For help, please visit <a href="http://nativelibs4java.googlecode.com/">NativeLibs4Java</a> , <a href="http://rococoa.dev.java.net/">Rococoa</a>, or <a href="http://jna.dev.java.net/">JNA</a>.
|
||||
*/
|
||||
public class FRCCommonControlData extends Structure<FRCCommonControlData, FRCCommonControlData.ByValue, FRCCommonControlData.ByReference > {
|
||||
public short packetIndex;
|
||||
/** C type : field1_union */
|
||||
public field1_union field1;
|
||||
public byte dsDigitalIn;
|
||||
public short teamID;
|
||||
public byte dsID_Alliance;
|
||||
public byte dsID_Position;
|
||||
/** C type : field2_union */
|
||||
public field2_union field2;
|
||||
/** Left-most 4 bits are unused */
|
||||
public short stick0Buttons;
|
||||
/** C type : field3_union */
|
||||
public field3_union field3;
|
||||
/** Left-most 4 bits are unused */
|
||||
public short stick1Buttons;
|
||||
/** C type : field4_union */
|
||||
public field4_union field4;
|
||||
/** Left-most 4 bits are unused */
|
||||
public short stick2Buttons;
|
||||
/** C type : field5_union */
|
||||
public field5_union field5;
|
||||
/** Left-most 4 bits are unused */
|
||||
public short stick3Buttons;
|
||||
/** Analog inputs are 10 bit right-justified */
|
||||
public short analog1;
|
||||
public short analog2;
|
||||
public short analog3;
|
||||
public short analog4;
|
||||
public long cRIOChecksum;
|
||||
public int FPGAChecksum0;
|
||||
public int FPGAChecksum1;
|
||||
public int FPGAChecksum2;
|
||||
public int FPGAChecksum3;
|
||||
/** C type : char[8] */
|
||||
public byte[] versionData = new byte[8];
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:31</i> */
|
||||
public static class field1_union extends Union<field1_union, field1_union.ByValue, field1_union.ByReference > {
|
||||
public byte control;
|
||||
public field1_union() {
|
||||
super();
|
||||
}
|
||||
public field1_union(byte control) {
|
||||
super();
|
||||
this.control = control;
|
||||
setType(Byte.TYPE);
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field1_union newInstance() { return new field1_union(); }
|
||||
public static field1_union[] newArray(int arrayLength) {
|
||||
return Union.newArray(field1_union.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field1_union implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field1_union implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:63</i> */
|
||||
public static class field2_union extends Union<field2_union, field2_union.ByValue, field2_union.ByReference > {
|
||||
/** C type : int8_t[6] */
|
||||
public byte[] stick0Axes = new byte[6];
|
||||
/** C type : field1_struct */
|
||||
public field1_struct field1;
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:65</i> */
|
||||
public static class field1_struct extends Structure<field1_struct, field1_struct.ByValue, field1_struct.ByReference > {
|
||||
public byte stick0Axis1;
|
||||
public byte stick0Axis2;
|
||||
public byte stick0Axis3;
|
||||
public byte stick0Axis4;
|
||||
public byte stick0Axis5;
|
||||
public byte stick0Axis6;
|
||||
public field1_struct() {
|
||||
super();
|
||||
}
|
||||
protected List<? > getFieldOrder() {
|
||||
return Arrays.asList("stick0Axis1", "stick0Axis2", "stick0Axis3", "stick0Axis4", "stick0Axis5", "stick0Axis6");
|
||||
}
|
||||
public field1_struct(byte stick0Axis1, byte stick0Axis2, byte stick0Axis3, byte stick0Axis4, byte stick0Axis5, byte stick0Axis6) {
|
||||
super();
|
||||
this.stick0Axis1 = stick0Axis1;
|
||||
this.stick0Axis2 = stick0Axis2;
|
||||
this.stick0Axis3 = stick0Axis3;
|
||||
this.stick0Axis4 = stick0Axis4;
|
||||
this.stick0Axis5 = stick0Axis5;
|
||||
this.stick0Axis6 = stick0Axis6;
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field1_struct newInstance() { return new field1_struct(); }
|
||||
public static field1_struct[] newArray(int arrayLength) {
|
||||
return Structure.newArray(field1_struct.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field1_struct implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field1_struct implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
public field2_union() {
|
||||
super();
|
||||
}
|
||||
/** @param field1 C type : field1_struct */
|
||||
public field2_union(field1_struct field1) {
|
||||
super();
|
||||
this.field1 = field1;
|
||||
setType(field1_struct.class);
|
||||
}
|
||||
/** @param stick0Axes C type : int8_t[6] */
|
||||
public field2_union(byte stick0Axes[]) {
|
||||
super();
|
||||
if ((stick0Axes.length != this.stick0Axes.length))
|
||||
throw new IllegalArgumentException("Wrong array size !");
|
||||
this.stick0Axes = stick0Axes;
|
||||
setType(byte[].class);
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field2_union newInstance() { return new field2_union(); }
|
||||
public static field2_union[] newArray(int arrayLength) {
|
||||
return Union.newArray(field2_union.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field2_union implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field2_union implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:76</i> */
|
||||
public static class field3_union extends Union<field3_union, field3_union.ByValue, field3_union.ByReference > {
|
||||
/** C type : int8_t[6] */
|
||||
public byte[] stick1Axes = new byte[6];
|
||||
/** C type : field1_struct */
|
||||
public field1_struct field1;
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:78</i> */
|
||||
public static class field1_struct extends Structure<field1_struct, field1_struct.ByValue, field1_struct.ByReference > {
|
||||
public byte stick1Axis1;
|
||||
public byte stick1Axis2;
|
||||
public byte stick1Axis3;
|
||||
public byte stick1Axis4;
|
||||
public byte stick1Axis5;
|
||||
public byte stick1Axis6;
|
||||
public field1_struct() {
|
||||
super();
|
||||
}
|
||||
protected List<? > getFieldOrder() {
|
||||
return Arrays.asList("stick1Axis1", "stick1Axis2", "stick1Axis3", "stick1Axis4", "stick1Axis5", "stick1Axis6");
|
||||
}
|
||||
public field1_struct(byte stick1Axis1, byte stick1Axis2, byte stick1Axis3, byte stick1Axis4, byte stick1Axis5, byte stick1Axis6) {
|
||||
super();
|
||||
this.stick1Axis1 = stick1Axis1;
|
||||
this.stick1Axis2 = stick1Axis2;
|
||||
this.stick1Axis3 = stick1Axis3;
|
||||
this.stick1Axis4 = stick1Axis4;
|
||||
this.stick1Axis5 = stick1Axis5;
|
||||
this.stick1Axis6 = stick1Axis6;
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field1_struct newInstance() { return new field1_struct(); }
|
||||
public static field1_struct[] newArray(int arrayLength) {
|
||||
return Structure.newArray(field1_struct.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field1_struct implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field1_struct implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
public field3_union() {
|
||||
super();
|
||||
}
|
||||
/** @param field1 C type : field1_struct */
|
||||
public field3_union(field1_struct field1) {
|
||||
super();
|
||||
this.field1 = field1;
|
||||
setType(field1_struct.class);
|
||||
}
|
||||
/** @param stick1Axes C type : int8_t[6] */
|
||||
public field3_union(byte stick1Axes[]) {
|
||||
super();
|
||||
if ((stick1Axes.length != this.stick1Axes.length))
|
||||
throw new IllegalArgumentException("Wrong array size !");
|
||||
this.stick1Axes = stick1Axes;
|
||||
setType(byte[].class);
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field3_union newInstance() { return new field3_union(); }
|
||||
public static field3_union[] newArray(int arrayLength) {
|
||||
return Union.newArray(field3_union.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field3_union implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field3_union implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:89</i> */
|
||||
public static class field4_union extends Union<field4_union, field4_union.ByValue, field4_union.ByReference > {
|
||||
/** C type : int8_t[6] */
|
||||
public byte[] stick2Axes = new byte[6];
|
||||
/** C type : field1_struct */
|
||||
public field1_struct field1;
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:91</i> */
|
||||
public static class field1_struct extends Structure<field1_struct, field1_struct.ByValue, field1_struct.ByReference > {
|
||||
public byte stick2Axis1;
|
||||
public byte stick2Axis2;
|
||||
public byte stick2Axis3;
|
||||
public byte stick2Axis4;
|
||||
public byte stick2Axis5;
|
||||
public byte stick2Axis6;
|
||||
public field1_struct() {
|
||||
super();
|
||||
}
|
||||
protected List<? > getFieldOrder() {
|
||||
return Arrays.asList("stick2Axis1", "stick2Axis2", "stick2Axis3", "stick2Axis4", "stick2Axis5", "stick2Axis6");
|
||||
}
|
||||
public field1_struct(byte stick2Axis1, byte stick2Axis2, byte stick2Axis3, byte stick2Axis4, byte stick2Axis5, byte stick2Axis6) {
|
||||
super();
|
||||
this.stick2Axis1 = stick2Axis1;
|
||||
this.stick2Axis2 = stick2Axis2;
|
||||
this.stick2Axis3 = stick2Axis3;
|
||||
this.stick2Axis4 = stick2Axis4;
|
||||
this.stick2Axis5 = stick2Axis5;
|
||||
this.stick2Axis6 = stick2Axis6;
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field1_struct newInstance() { return new field1_struct(); }
|
||||
public static field1_struct[] newArray(int arrayLength) {
|
||||
return Structure.newArray(field1_struct.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field1_struct implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field1_struct implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
public field4_union() {
|
||||
super();
|
||||
}
|
||||
/** @param field1 C type : field1_struct */
|
||||
public field4_union(field1_struct field1) {
|
||||
super();
|
||||
this.field1 = field1;
|
||||
setType(field1_struct.class);
|
||||
}
|
||||
/** @param stick2Axes C type : int8_t[6] */
|
||||
public field4_union(byte stick2Axes[]) {
|
||||
super();
|
||||
if ((stick2Axes.length != this.stick2Axes.length))
|
||||
throw new IllegalArgumentException("Wrong array size !");
|
||||
this.stick2Axes = stick2Axes;
|
||||
setType(byte[].class);
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field4_union newInstance() { return new field4_union(); }
|
||||
public static field4_union[] newArray(int arrayLength) {
|
||||
return Union.newArray(field4_union.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field4_union implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field4_union implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:102</i> */
|
||||
public static class field5_union extends Union<field5_union, field5_union.ByValue, field5_union.ByReference > {
|
||||
/** C type : int8_t[6] */
|
||||
public byte[] stick3Axes = new byte[6];
|
||||
/** C type : field1_struct */
|
||||
public field1_struct field1;
|
||||
/** <i>native declaration : /home/alex/Projects/WPILib-Development/WPILibC/WPILib/src/main/include/NetworkCommunication/FRCComm.h:104</i> */
|
||||
public static class field1_struct extends Structure<field1_struct, field1_struct.ByValue, field1_struct.ByReference > {
|
||||
public byte stick3Axis1;
|
||||
public byte stick3Axis2;
|
||||
public byte stick3Axis3;
|
||||
public byte stick3Axis4;
|
||||
public byte stick3Axis5;
|
||||
public byte stick3Axis6;
|
||||
public field1_struct() {
|
||||
super();
|
||||
}
|
||||
protected List<? > getFieldOrder() {
|
||||
return Arrays.asList("stick3Axis1", "stick3Axis2", "stick3Axis3", "stick3Axis4", "stick3Axis5", "stick3Axis6");
|
||||
}
|
||||
public field1_struct(byte stick3Axis1, byte stick3Axis2, byte stick3Axis3, byte stick3Axis4, byte stick3Axis5, byte stick3Axis6) {
|
||||
super();
|
||||
this.stick3Axis1 = stick3Axis1;
|
||||
this.stick3Axis2 = stick3Axis2;
|
||||
this.stick3Axis3 = stick3Axis3;
|
||||
this.stick3Axis4 = stick3Axis4;
|
||||
this.stick3Axis5 = stick3Axis5;
|
||||
this.stick3Axis6 = stick3Axis6;
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field1_struct newInstance() { return new field1_struct(); }
|
||||
public static field1_struct[] newArray(int arrayLength) {
|
||||
return Structure.newArray(field1_struct.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field1_struct implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field1_struct implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
public field5_union() {
|
||||
super();
|
||||
}
|
||||
/** @param field1 C type : field1_struct */
|
||||
public field5_union(field1_struct field1) {
|
||||
super();
|
||||
this.field1 = field1;
|
||||
setType(field1_struct.class);
|
||||
}
|
||||
/** @param stick3Axes C type : int8_t[6] */
|
||||
public field5_union(byte stick3Axes[]) {
|
||||
super();
|
||||
if ((stick3Axes.length != this.stick3Axes.length))
|
||||
throw new IllegalArgumentException("Wrong array size !");
|
||||
this.stick3Axes = stick3Axes;
|
||||
setType(byte[].class);
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected field5_union newInstance() { return new field5_union(); }
|
||||
public static field5_union[] newArray(int arrayLength) {
|
||||
return Union.newArray(field5_union.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends field5_union implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends field5_union implements Structure.ByValue {
|
||||
|
||||
};
|
||||
};
|
||||
public FRCCommonControlData() {
|
||||
super();
|
||||
}
|
||||
protected List<? > getFieldOrder() {
|
||||
return Arrays.asList("packetIndex", "field1", "dsDigitalIn", "teamID", "dsID_Alliance", "dsID_Position", "field2", "stick0Buttons", "field3", "stick1Buttons", "field4", "stick2Buttons", "field5", "stick3Buttons", "analog1", "analog2", "analog3", "analog4", "cRIOChecksum", "FPGAChecksum0", "FPGAChecksum1", "FPGAChecksum2", "FPGAChecksum3", "versionData");
|
||||
}
|
||||
protected ByReference newByReference() { return new ByReference(); }
|
||||
protected ByValue newByValue() { return new ByValue(); }
|
||||
protected FRCCommonControlData newInstance() { return new FRCCommonControlData(); }
|
||||
public static FRCCommonControlData[] newArray(int arrayLength) {
|
||||
return Structure.newArray(FRCCommonControlData.class, arrayLength);
|
||||
}
|
||||
public static class ByReference extends FRCCommonControlData implements Structure.ByReference {
|
||||
|
||||
};
|
||||
public static class ByValue extends FRCCommonControlData implements Structure.ByValue {
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package edu.wpi.first.wpilibj.communication;
|
||||
|
||||
public class FRCCommonControlMasks {
|
||||
// XXX: Verify these are right in FRCCommonControlData.field1
|
||||
public static byte CHECK_VERSIONS = 1 << 0;
|
||||
public static byte TEST = 1 << 1;
|
||||
public static byte RESYNC = 1 << 2;
|
||||
public static byte FMS_ATTATCHED = 1 << 3;
|
||||
public static byte AUTONOMOUS = 1 << 4;
|
||||
public static byte ENABLED = 1 << 5;
|
||||
public static byte NOT_ESTOP = 1 << 6;
|
||||
public static byte RESET = (byte) (1 << 7);
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
package edu.wpi.first.wpilibj.communication;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.JNIWrapper;
|
||||
/**
|
||||
* JNA Wrapper for library <b>FRC_NetworkCommunications</b><br>
|
||||
* This file was autogenerated by <a href="http://jnaerator.googlecode.com/">JNAerator</a>,<br>
|
||||
* a tool written by <a href="http://ochafik.com/">Olivier Chafik</a> that <a href="http://code.google.com/p/jnaerator/wiki/CreditsAndLicense">uses a few opensource projects.</a>.<br>
|
||||
* For help, please visit <a href="http://nativelibs4java.googlecode.com/">NativeLibs4Java</a> , <a href="http://rococoa.dev.java.net/">Rococoa</a>, or <a href="http://jna.dev.java.net/">JNA</a>.
|
||||
*/
|
||||
public class FRCNetworkCommunicationsLibrary extends JNIWrapper {
|
||||
//public static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("FRC_NetworkCommunications", true, FRC_NetworkCommunicationsLibrary.class);
|
||||
//public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(FRC_NetworkCommunicationsLibrary.JNA_LIBRARY_NAME, MangledFunctionMapper.DEFAULT_OPTIONS);
|
||||
//static {
|
||||
//System.loadLibrary("JNIWrappers");
|
||||
//Native.register(FRC_NetworkCommunicationsLibrary.class, FRC_NetworkCommunicationsLibrary.JNA_NATIVE_LIB);
|
||||
//}
|
||||
/**
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h</i><br>
|
||||
* enum values
|
||||
*/
|
||||
public static interface tModuleType {
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:9</i> */
|
||||
public static final int kModuleType_Unknown = 0x00;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:10</i> */
|
||||
public static final int kModuleType_Analog = 0x01;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:11</i> */
|
||||
public static final int kModuleType_Digital = 0x02;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:12</i> */
|
||||
public static final int kModuleType_Solenoid = 0x03;
|
||||
};
|
||||
/**
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h</i><br>
|
||||
* enum values
|
||||
*/
|
||||
public static interface tTargetClass {
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:16</i> */
|
||||
public static final int kTargetClass_Unknown = 0x00;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:17</i> */
|
||||
public static final int kTargetClass_FRC1 = 0x10;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:18</i> */
|
||||
public static final int kTargetClass_FRC2 = 0x20;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:19</i> */
|
||||
public static final int kTargetClass_FRC2_Analog = (int)FRCNetworkCommunicationsLibrary.tTargetClass.kTargetClass_FRC2 | (int)FRCNetworkCommunicationsLibrary.tModuleType.kModuleType_Analog;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:20</i> */
|
||||
public static final int kTargetClass_FRC2_Digital = (int)FRCNetworkCommunicationsLibrary.tTargetClass.kTargetClass_FRC2 | (int)FRCNetworkCommunicationsLibrary.tModuleType.kModuleType_Digital;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:21</i> */
|
||||
public static final int kTargetClass_FRC2_Solenoid = (int)FRCNetworkCommunicationsLibrary.tTargetClass.kTargetClass_FRC2 | (int)FRCNetworkCommunicationsLibrary.tModuleType.kModuleType_Solenoid;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:22</i> */
|
||||
public static final int kTargetClass_FamilyMask = 0xF0;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:23</i> */
|
||||
public static final int kTargetClass_ModuleMask = 0x0F;
|
||||
};
|
||||
/**
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h</i><br>
|
||||
* enum values
|
||||
*/
|
||||
public static interface tResourceType {
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:10</i> */
|
||||
public static final int kResourceType_Controller = 0;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:11</i> */
|
||||
public static final int kResourceType_Module = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:12</i> */
|
||||
public static final int kResourceType_Language = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:13</i> */
|
||||
public static final int kResourceType_CANPlugin = 3;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:14</i> */
|
||||
public static final int kResourceType_Accelerometer = 4;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:15</i> */
|
||||
public static final int kResourceType_ADXL345 = 5;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:16</i> */
|
||||
public static final int kResourceType_AnalogChannel = 6;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:17</i> */
|
||||
public static final int kResourceType_AnalogTrigger = 7;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:18</i> */
|
||||
public static final int kResourceType_AnalogTriggerOutput = 8;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:19</i> */
|
||||
public static final int kResourceType_CANJaguar = 9;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:20</i> */
|
||||
public static final int kResourceType_Compressor = 10;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:21</i> */
|
||||
public static final int kResourceType_Counter = 11;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:22</i> */
|
||||
public static final int kResourceType_Dashboard = 12;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:23</i> */
|
||||
public static final int kResourceType_DigitalInput = 13;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:24</i> */
|
||||
public static final int kResourceType_DigitalOutput = 14;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:25</i> */
|
||||
public static final int kResourceType_DriverStationCIO = 15;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:26</i> */
|
||||
public static final int kResourceType_DriverStationEIO = 16;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:27</i> */
|
||||
public static final int kResourceType_DriverStationLCD = 17;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:28</i> */
|
||||
public static final int kResourceType_Encoder = 18;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:29</i> */
|
||||
public static final int kResourceType_GearTooth = 19;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:30</i> */
|
||||
public static final int kResourceType_Gyro = 20;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:31</i> */
|
||||
public static final int kResourceType_I2C = 21;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:32</i> */
|
||||
public static final int kResourceType_Framework = 22;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:33</i> */
|
||||
public static final int kResourceType_Jaguar = 23;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:34</i> */
|
||||
public static final int kResourceType_Joystick = 24;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:35</i> */
|
||||
public static final int kResourceType_Kinect = 25;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:36</i> */
|
||||
public static final int kResourceType_KinectStick = 26;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:37</i> */
|
||||
public static final int kResourceType_PIDController = 27;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:38</i> */
|
||||
public static final int kResourceType_Preferences = 28;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:39</i> */
|
||||
public static final int kResourceType_PWM = 29;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:40</i> */
|
||||
public static final int kResourceType_Relay = 30;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:41</i> */
|
||||
public static final int kResourceType_RobotDrive = 31;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:42</i> */
|
||||
public static final int kResourceType_SerialPort = 32;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:43</i> */
|
||||
public static final int kResourceType_Servo = 33;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:44</i> */
|
||||
public static final int kResourceType_Solenoid = 34;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:45</i> */
|
||||
public static final int kResourceType_SPI = 35;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:46</i> */
|
||||
public static final int kResourceType_Task = 36;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:47</i> */
|
||||
public static final int kResourceType_Ultrasonic = 37;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:48</i> */
|
||||
public static final int kResourceType_Victor = 38;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:49</i> */
|
||||
public static final int kResourceType_Button = 39;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:50</i> */
|
||||
public static final int kResourceType_Command = 40;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:51</i> */
|
||||
public static final int kResourceType_AxisCamera = 41;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:52</i> */
|
||||
public static final int kResourceType_PCVideoServer = 42;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:53</i> */
|
||||
public static final int kResourceType_SmartDashboard = 43;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:54</i> */
|
||||
public static final int kResourceType_Talon = 44;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:55</i> */
|
||||
public static final int kResourceType_HiTechnicColorSensor = 45;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:56</i> */
|
||||
public static final int kResourceType_HiTechnicAccel = 46;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:57</i> */
|
||||
public static final int kResourceType_HiTechnicCompass = 47;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:58</i> */
|
||||
public static final int kResourceType_SRF08 = 48;
|
||||
};
|
||||
/**
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h</i><br>
|
||||
* enum values
|
||||
*/
|
||||
public static interface tInstances {
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:63</i> */
|
||||
public static final int kLanguage_LabVIEW = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:64</i> */
|
||||
public static final int kLanguage_CPlusPlus = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:65</i> */
|
||||
public static final int kLanguage_Java = 3;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:66</i> */
|
||||
public static final int kLanguage_Python = 4;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:68</i> */
|
||||
public static final int kCANPlugin_BlackJagBridge = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:69</i> */
|
||||
public static final int kCANPlugin_2CAN = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:71</i> */
|
||||
public static final int kFramework_Iterative = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:72</i> */
|
||||
public static final int kFramework_Simple = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:74</i> */
|
||||
public static final int kRobotDrive_ArcadeStandard = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:75</i> */
|
||||
public static final int kRobotDrive_ArcadeButtonSpin = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:76</i> */
|
||||
public static final int kRobotDrive_ArcadeRatioCurve = 3;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:77</i> */
|
||||
public static final int kRobotDrive_Tank = 4;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:78</i> */
|
||||
public static final int kRobotDrive_MecanumPolar = 5;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:79</i> */
|
||||
public static final int kRobotDrive_MecanumCartesian = 6;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:81</i> */
|
||||
public static final int kDriverStationCIO_Analog = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:82</i> */
|
||||
public static final int kDriverStationCIO_DigitalIn = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:83</i> */
|
||||
public static final int kDriverStationCIO_DigitalOut = 3;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:85</i> */
|
||||
public static final int kDriverStationEIO_Acceleration = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:86</i> */
|
||||
public static final int kDriverStationEIO_AnalogIn = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:87</i> */
|
||||
public static final int kDriverStationEIO_AnalogOut = 3;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:88</i> */
|
||||
public static final int kDriverStationEIO_Button = 4;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:89</i> */
|
||||
public static final int kDriverStationEIO_LED = 5;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:90</i> */
|
||||
public static final int kDriverStationEIO_DigitalIn = 6;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:91</i> */
|
||||
public static final int kDriverStationEIO_DigitalOut = 7;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:92</i> */
|
||||
public static final int kDriverStationEIO_FixedDigitalOut = 8;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:93</i> */
|
||||
public static final int kDriverStationEIO_PWM = 9;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:94</i> */
|
||||
public static final int kDriverStationEIO_Encoder = 10;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:95</i> */
|
||||
public static final int kDriverStationEIO_TouchSlider = 11;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:97</i> */
|
||||
public static final int kADXL345_SPI = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:98</i> */
|
||||
public static final int kADXL345_I2C = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:100</i> */
|
||||
public static final int kCommand_Scheduler = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:102</i> */
|
||||
public static final int kSmartDashboard_Instance = 1;
|
||||
};
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Input = 17;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Vertices1 = 21;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int SYS_STATUS_DATA_SIZE = 44;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Custom = 25;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Vertices2 = 23;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Header = 19;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Joystick = 24;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int IO_CONFIG_DATA_SIZE = 32;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h</i> */
|
||||
public static final int kMaxModuleNumber = 2;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output = 18;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Extra2 = 22;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int kFRC_NetworkCommunication_DynamicType_Kinect_Extra1 = 20;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int USER_DS_LCD_DATA_SIZE = 128;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h</i> */
|
||||
public static final int kUsageReporting_version = 1;
|
||||
/** <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h</i> */
|
||||
public static final int USER_STATUS_DATA_SIZE = (984 - 32 - 44);
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nAICalibration_getLSBWeight(const uint32_t, const uint32_t, int32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\AICalibration.h:7</i><br>
|
||||
* @deprecated use the safer methods {@link #FRC_NetworkCommunication_nAICalibration_getLSBWeight(int, int, java.nio.IntBuffer)} and {@link #FRC_NetworkCommunication_nAICalibration_getLSBWeight(int, int, com.sun.jna.ptr.IntByReference)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int FRC_NetworkCommunication_nAICalibration_getLSBWeight(int aiSystemIndex, int channel, Integer status);
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nAICalibration_getLSBWeight(const uint32_t, const uint32_t, int32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\AICalibration.h:7</i>
|
||||
*/
|
||||
public static native int FRCNetworkCommunicationAICalibrationGetLSBWeight(int aiSystemIndex, int channel, Integer status);
|
||||
/**
|
||||
* Original signature : <code>int32_t FRC_NetworkCommunication_nAICalibration_getOffset(const uint32_t, const uint32_t, int32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\AICalibration.h:8</i><br>
|
||||
* @deprecated use the safer methods {@link #FRC_NetworkCommunication_nAICalibration_getOffset(int, int, java.nio.IntBuffer)} and {@link #FRC_NetworkCommunication_nAICalibration_getOffset(int, int, com.sun.jna.ptr.IntByReference)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int FRC_NetworkCommunication_nAICalibration_getOffset(int aiSystemIndex, int channel, Integer status);
|
||||
/**
|
||||
* Original signature : <code>int32_t FRC_NetworkCommunication_nAICalibration_getOffset(const uint32_t, const uint32_t, int32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\AICalibration.h:8</i>
|
||||
*/
|
||||
public static native int FRCNetworkCommunicationAICalibrationGetOffset(int aiSystemIndex, int channel, Integer status);
|
||||
/**
|
||||
* Original signature : <code>bool getModulePresence(tModuleType, uint8_t)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:14</i>
|
||||
*/
|
||||
public static native byte getModulePresence(int moduleType, byte moduleNumber);
|
||||
/**
|
||||
* Original signature : <code>tTargetClass getTargetClass()</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:25</i>
|
||||
*/
|
||||
public static native int getTargetClass();
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nLoadOut_getModulePresence(uint32_t, uint8_t)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:32</i>
|
||||
*/
|
||||
public static native int FRCNetworkCommunicationLoadOutGetModulePresence(int moduleType, byte moduleNumber);
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nLoadOut_getTargetClass()</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\LoadOut.h:33</i>
|
||||
*/
|
||||
public static native int FRCNetworkCommunicationLoadOutGetTargetClass();
|
||||
/**
|
||||
* Original signature : <code>STATUS moduleNameFindBySymbolName(const char*, char*)</code><br>
|
||||
* @param symbol symbol name to look for<br>
|
||||
* @param module where to return module name<br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\symModuleLink.h:6</i><br>
|
||||
* @deprecated use the safer methods {@link #moduleNameFindBySymbolName(java.lang.String, java.nio.ByteBuffer)} and {@link #moduleNameFindBySymbolName(com.sun.jna.Pointer, com.sun.jna.Pointer)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native FRC_NetworkCommunicationsLibrary.STATUS moduleNameFindBySymbolName(Pointer symbol, Pointer module);
|
||||
/**
|
||||
* Original signature : <code>STATUS moduleNameFindBySymbolName(const char*, char*)</code><br>
|
||||
* @param symbol symbol name to look for<br>
|
||||
* @param module where to return module name<br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\symModuleLink.h:6</i>
|
||||
*/
|
||||
//public static native FRC_NetworkCommunicationsLibrary.STATUS moduleNameFindBySymbolName(String symbol, ByteBuffer module);
|
||||
/**
|
||||
* Report the usage of a resource of interest.
|
||||
<br>
|
||||
*
|
||||
<br>
|
||||
* @param resource one of the values in the tResourceType above (max value 51).
|
||||
<br>
|
||||
* @param instanceNumber an index that identifies the resource instance.
|
||||
<br>
|
||||
* @param context an optional additional context number for some cases (such as module number). Set to 0 to omit.
|
||||
<br>
|
||||
* @param feature a string to be included describing features in use on a specific resource. Setting the same resource more than once allows you to change the feature string.<br>
|
||||
* Original signature : <code>uint32_t report(tResourceType, uint8_t, uint8_t, const char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:113</i><br>
|
||||
* @deprecated use the safer methods {@link #report(int, byte, byte, java.lang.String)} and {@link #report(int, byte, byte, com.sun.jna.Pointer)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int report(int resource, byte instanceNumber, byte context, Pointer feature);
|
||||
/**
|
||||
* Report the usage of a resource of interest.
|
||||
<br>
|
||||
*
|
||||
<br>
|
||||
* @param resource one of the values in the tResourceType above (max value 51).
|
||||
<br>
|
||||
* @param instanceNumber an index that identifies the resource instance.
|
||||
<br>
|
||||
* @param context an optional additional context number for some cases (such as module number). Set to 0 to omit.
|
||||
<br>
|
||||
* @param feature a string to be included describing features in use on a specific resource. Setting the same resource more than once allows you to change the feature string.<br>
|
||||
* Original signature : <code>uint32_t report(tResourceType, uint8_t, uint8_t, const char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:113</i>
|
||||
*/
|
||||
public static native int report(int resource, byte instanceNumber, byte context, String feature);
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nUsageReporting_report(uint8_t, uint8_t, uint8_t, const char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:120</i><br>
|
||||
* @deprecated use the safer methods {@link #FRC_NetworkCommunication_nUsageReporting_report(byte, byte, byte, java.lang.String)} and {@link #FRC_NetworkCommunication_nUsageReporting_report(byte, byte, byte, com.sun.jna.Pointer)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int FRC_NetworkCommunication_nUsageReporting_report(byte resource, byte instanceNumber, byte context, Pointer feature);
|
||||
/**
|
||||
* Original signature : <code>uint32_t FRC_NetworkCommunication_nUsageReporting_report(uint8_t, uint8_t, uint8_t, const char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\UsageReporting.h:120</i>
|
||||
*/
|
||||
public static native int FRCNetworkCommunicationUsageReportingReport(byte resource, byte instanceNumber, byte context, String feature);
|
||||
/**
|
||||
* Original signature : <code>void getFPGAHardwareVersion(uint16_t*, uint32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:124</i><br>
|
||||
* @deprecated use the safer methods {@link #getFPGAHardwareVersion(java.nio.ShortBuffer, java.nio.IntBuffer)} and {@link #getFPGAHardwareVersion(com.sun.jna.ptr.ShortByReference, com.sun.jna.ptr.IntByReference)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native void getFPGAHardwareVersion(ShortByReference fpgaVersion, IntByReference fpgaRevision);
|
||||
/**
|
||||
* Original signature : <code>void getFPGAHardwareVersion(uint16_t*, uint32_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:124</i>
|
||||
*/
|
||||
public static native void getFPGAHardwareVersion(ShortBuffer fpgaVersion, IntBuffer fpgaRevision);
|
||||
/**
|
||||
* Original signature : <code>int getCommonControlData(FRCCommonControlData*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:126</i>
|
||||
*/
|
||||
public static native int getCommonControlData(FRCCommonControlData data);
|
||||
/**
|
||||
* Original signature : <code>int getRecentCommonControlData(FRCCommonControlData*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:127</i>
|
||||
*/
|
||||
public static native int getRecentCommonControlData(FRCCommonControlData commonData, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int getRecentStatusData(uint8_t*, uint8_t*, uint8_t*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:128</i><br>
|
||||
* @deprecated use the safer methods {@link #getRecentStatusData(java.nio.ByteBuffer, java.nio.ByteBuffer, java.nio.ByteBuffer, int)} and {@link #getRecentStatusData(com.sun.jna.Pointer, com.sun.jna.Pointer, com.sun.jna.Pointer, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int getRecentStatusData(Pointer batteryInt, Pointer batteryDec, Pointer dsDigitalOut, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int getRecentStatusData(uint8_t*, uint8_t*, uint8_t*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:128</i>
|
||||
*/
|
||||
public static native int getRecentStatusData(ByteBuffer batteryInt, ByteBuffer batteryDec, ByteBuffer dsDigitalOut, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int getDynamicControlData(uint8_t, char*, int32_t, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:129</i><br>
|
||||
* @deprecated use the safer methods {@link #getDynamicControlData(byte, java.nio.ByteBuffer, int, int)} and {@link #getDynamicControlData(byte, com.sun.jna.Pointer, int, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int getDynamicControlData(byte type, Pointer dynamicData, int maxLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int getDynamicControlData(uint8_t, char*, int32_t, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:129</i>
|
||||
*/
|
||||
public static native int getDynamicControlData(byte type, ByteBuffer dynamicData, int maxLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setStatusData(float, uint8_t, uint8_t, const char*, int, const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:130</i><br>
|
||||
* @deprecated use the safer methods {@link #setStatusData(float, byte, byte, java.lang.String, int, java.lang.String, int, int)} and {@link #setStatusData(float, byte, byte, com.sun.jna.Pointer, int, com.sun.jna.Pointer, int, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int setStatusData(float battery, byte dsDigitalOut, byte updateNumber, Pointer userDataHigh, int userDataHighLength, Pointer userDataLow, int userDataLowLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setStatusData(float, uint8_t, uint8_t, const char*, int, const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:130</i>
|
||||
*/
|
||||
public static native int setStatusData(float battery, byte dsDigitalOut, byte updateNumber, String userDataHigh, int userDataHighLength, String userDataLow, int userDataLowLength);
|
||||
/**
|
||||
* Original signature : <code>int setStatusDataFloatAsInt(int, uint8_t, uint8_t, const char*, int, const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:133</i><br>
|
||||
* @deprecated use the safer methods {@link #setStatusDataFloatAsInt(int, byte, byte, java.lang.String, int, java.lang.String, int, int)} and {@link #setStatusDataFloatAsInt(int, byte, byte, com.sun.jna.Pointer, int, com.sun.jna.Pointer, int, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int setStatusDataFloatAsInt(int battery, byte dsDigitalOut, byte updateNumber, Pointer userDataHigh, int userDataHighLength, Pointer userDataLow, int userDataLowLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setStatusDataFloatAsInt(int, uint8_t, uint8_t, const char*, int, const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:133</i>
|
||||
*/
|
||||
public static native int setStatusDataFloatAsInt(int battery, byte dsDigitalOut, byte updateNumber, String userDataHigh, int userDataHighLength, String userDataLow, int userDataLowLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setErrorData(const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:136</i><br>
|
||||
* @deprecated use the safer methods {@link #setErrorData(java.lang.String, int, int)} and {@link #setErrorData(com.sun.jna.Pointer, int, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int setErrorData(Pointer errors, int errorsLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setErrorData(const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:136</i>
|
||||
*/
|
||||
public static native int setErrorData(String errors, int errorsLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setUserDsLcdData(const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:137</i><br>
|
||||
* @deprecated use the safer methods {@link #setUserDsLcdData(java.lang.String, int, int)} and {@link #setUserDsLcdData(com.sun.jna.Pointer, int, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int setUserDsLcdData(Pointer userDsLcdData, int userDsLcdDataLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int setUserDsLcdData(const char*, int, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:137</i>
|
||||
*/
|
||||
public static native int setUserDsLcdData(String userDsLcdData, int userDsLcdDataLength, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int overrideIOConfig(const char*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:138</i><br>
|
||||
* @deprecated use the safer methods {@link #overrideIOConfig(java.lang.String, int)} and {@link #overrideIOConfig(com.sun.jna.Pointer, int)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native int overrideIOConfig(String ioConfig, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>int overrideIOConfig(const char*, int)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:138</i>
|
||||
*/
|
||||
public static native int overrideIOConfig(String ioConfig, int wait_ms);
|
||||
/**
|
||||
* Original signature : <code>void setNewDataSem(pthread_mutex_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:147</i>
|
||||
*/
|
||||
public static native void setNewDataSem(ByteBuffer mutexId);
|
||||
/**
|
||||
* Original signature : <code>void setResyncSem(pthread_mutex_t*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:148</i>
|
||||
*/
|
||||
//public static native void setResyncSem(FRC_NetworkCommunicationsLibrary.pthread_mutex_t pthread_mutex_tPtr1);
|
||||
/**
|
||||
* Original signature : <code>void signalResyncActionDone()</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:150</i>
|
||||
*/
|
||||
public static native void signalResyncActionDone();
|
||||
/**
|
||||
* this uint32_t is really a LVRefNum<br>
|
||||
* Original signature : <code>void setNewDataOccurRef(uint32_t)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:154</i>
|
||||
*/
|
||||
public static native void setNewDataOccurRef(int refnum);
|
||||
/**
|
||||
* Original signature : <code>void setResyncOccurRef(uint32_t)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:156</i>
|
||||
*/
|
||||
public static native void setResyncOccurRef(int refnum);
|
||||
/**
|
||||
* Original signature : <code>void FRC_NetworkCommunication_getVersionString(char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:159</i><br>
|
||||
* @deprecated use the safer methods {@link #FRC_NetworkCommunication_getVersionString(java.nio.ByteBuffer)} and {@link #FRC_NetworkCommunication_getVersionString(com.sun.jna.Pointer)} instead
|
||||
*/
|
||||
//@Deprecated
|
||||
//public static native void FRC_NetworkCommunication_getVersionString(Pointer version);
|
||||
/**
|
||||
* Original signature : <code>void FRC_NetworkCommunication_getVersionString(char*)</code><br>
|
||||
* <i>native declaration : src\main\include\NetworkCommunication\FRCComm.h:159</i>
|
||||
*/
|
||||
public static native void FRCNetworkCommunicationGetVersionString(ByteBuffer version);
|
||||
public static native void FRCNetworkCommunicationObserveUserProgramStarting();
|
||||
public static native void FRCNetworkCommunicationObserveUserProgramDisabled();
|
||||
public static native void FRCNetworkCommunicationObserveUserProgramAutonomous();
|
||||
public static native void FRCNetworkCommunicationObserveUserProgramTeleop();
|
||||
public static native void FRCNetworkCommunicationObserveUserProgramTest();
|
||||
public static native void FRCNetworkCommunicationReserve();
|
||||
|
||||
/*
|
||||
public static class pthread_mutex_t extends PointerType {
|
||||
public pthread_mutex_t(Pointer address) {
|
||||
super(address);
|
||||
}
|
||||
public pthread_mutex_t() {
|
||||
super();
|
||||
}
|
||||
};
|
||||
public static class STATUS extends PointerType {
|
||||
public STATUS(Pointer address) {
|
||||
super(address);
|
||||
}
|
||||
public STATUS() {
|
||||
super();
|
||||
}
|
||||
};*/
|
||||
|
||||
//
|
||||
// JNI Testing
|
||||
//
|
||||
public static native void JNIValueParameterTest(boolean booleanValue, byte byteValue, char charValue, short shortValue, int intValue, long longValue, float floatValue, double doubleValue );
|
||||
public static native boolean JNIValueReturnBooleanTest(boolean booleanValue);
|
||||
public static native byte JNIValueReturnByteTest(byte byteValue);
|
||||
public static native char JNIValueReturnCharTest(char charValue);
|
||||
public static native short JNIValueReturnShortTest(short shortValue);
|
||||
public static native int JNIValueReturnIntTest(int intValue);
|
||||
public static native long JNIValueReturnLongTest(long longValue);
|
||||
@@ -0,0 +1,12 @@
|
||||
package edu.wpi.first.wpilibj.communication;
|
||||
|
||||
public class NIRioStatus {
|
||||
// TODO: Should this file be auto-generated?
|
||||
public static final int kRioStatusOffset = -63000;
|
||||
|
||||
public static final int kRioStatusSuccess = 0;
|
||||
public static final int kRIOStatusBufferInvalidSize = kRioStatusOffset - 80;
|
||||
public static final int kRIOStatusOperationTimedOut = -52007;
|
||||
public static final int kRIOStatusFeatureNotSupported = kRioStatusOffset - 193;
|
||||
public static final int kRIOStatusResourceNotInitialized = -52010;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package edu.wpi.first.wpilibj.communication;
|
||||
|
||||
public class UsageReporting {
|
||||
|
||||
public static void report(int resource, int instanceNumber, int i) {
|
||||
report(resource, instanceNumber, i, "");
|
||||
}
|
||||
|
||||
public static void report(int resource, int instanceNumber) {
|
||||
report(resource, instanceNumber, 0, "");
|
||||
}
|
||||
|
||||
public static void report(int resource, int instanceNumber, int i,
|
||||
String string) {
|
||||
FRC_NetworkCommunicationsLibrary.FRC_NetworkCommunication_nUsageReporting_report((byte)resource, (byte) instanceNumber, (byte) i, string);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user