Removed AnalogModule, DigitalModule, and Module from Java

Change-Id: I42c58237f1e14d0ebae1c7266aecda00d51eeae1
This commit is contained in:
thomasclark
2014-07-22 13:31:36 -04:00
parent 48e8b2136e
commit b5fb35c0c4
18 changed files with 702 additions and 1680 deletions

View File

@@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* 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. */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
@@ -53,7 +53,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* Construct an analog channel.
*
* @param channel
* The channel number to represent.
* The channel number to represent.
*/
public AnalogInput(final int channel) {
m_channel = channel;
@@ -69,7 +69,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
+ " is already allocated");
}
ByteBuffer port_pointer = AnalogJNI.getPortWithModule((byte) 1, (byte) channel);
ByteBuffer port_pointer = AnalogJNI.getPort((byte) channel);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
@@ -91,21 +91,12 @@ public class AnalogInput extends SensorBase implements PIDSource,
}
/**
* Get the analog module.
* Get a sample straight from this channel. The sample is a 12-bit value
* representing the 0V to 10V range of the A/D converter. The units are in
* A/D converter codes. Use GetVoltage() to get the analog value in
* calibrated units.
*
* @return The AnalogModule.
*/
public AnalogModule getModule() {
return AnalogModule.getInstance(1);
}
/**
* 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.
* @return A sample straight from this channel.
*/
public int getValue() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
@@ -122,8 +113,8 @@ public class AnalogInput extends SensorBase implements PIDSource,
* 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.
* AverageBits) samples have been acquired from this channel. Use
* getAverageVoltage() to get the analog value in calibrated units.
*
* @return A sample from the oversample and average engine for this channel.
*/
@@ -137,11 +128,11 @@ public class AnalogInput extends SensorBase implements PIDSource,
}
/**
* 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().
* Get a scaled sample straight from this channel. 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.
* @return A scaled sample straight from this channel.
*/
public double getVoltage() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
@@ -161,7 +152,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* stable, but it will update more slowly.
*
* @return A scaled sample from the output of the oversample and average
* engine for this channel.
* engine for this channel.
*/
public double getAverageVoltage() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
@@ -175,7 +166,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
/**
* 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.
* manufacturing and stored in an eeprom.
*
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
*
@@ -192,8 +183,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
/**
* 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.
* channel that was calibrated in manufacturing and stored in an eeprom.
*
* Volts = ((LSB_Weight * 1e-9) * raw) - (Offset * 1e-9)
*
@@ -223,7 +213,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* automatically in the FPGA.
*
* @param bits
* The number of averaging bits.
* The number of averaging bits.
*/
public void setAverageBits(final int bits) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
@@ -255,7 +245,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* oversampling is done automatically in the FPGA.
*
* @param bits
* The number of oversample bits.
* The number of oversample bits.
*/
public void setOversampleBits(final int bits) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
@@ -306,7 +296,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* This will be added to all values returned to the user.
*
* @param initialValue
* The value that the accumulator should start from when reset.
* The value that the accumulator should start from when reset.
*/
public void setAccumulatorInitialValue(long initialValue) {
m_accumulatorOffset = initialValue;
@@ -396,7 +386,7 @@ public class AnalogInput extends SensorBase implements PIDSource,
* can be used for averaging.
*
* @param result
* AccumulatorResult object to store the results in.
* AccumulatorResult object to store the results in.
*/
public void getAccumulatorOutput(AccumulatorResult result) {
if (result == null) {
@@ -435,16 +425,41 @@ public class AnalogInput extends SensorBase implements PIDSource,
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.
/**
* Set the sample rate.
*
* This is a global setting for all channels.
*
* @param samplesPerSecond The number of samples per second.
*/
public static void setGlobalSampleRate(final double samplesPerSecond) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
AnalogJNI.setAnalogSampleRate((float) samplesPerSecond, status.asIntBuffer());
AnalogJNI.setAnalogSampleRate((float)samplesPerSecond, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Get the current sample rate.
*
* This assumes one entry in the scan list. This is a global setting for
* all channels.
*
* @return Sample rate.
*/
public static double getGlobalSampleRate() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
double value = AnalogJNI.getAnalogSampleRate(status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
/**
* Get the average value for use with PIDController
*

View File

@@ -1,316 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tModuleType;
import edu.wpi.first.wpilibj.hal.AnalogJNI;
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 ByteBuffer[] 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 ByteBuffer[8];
for (int i = 0; i < SensorBase.kAnalogInputChannels; i++) {
ByteBuffer port_pointer = AnalogJNI.getPortWithModule((byte) moduleNumber, (byte) i);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
// XXX: Uncomment when analogchannel has been fixed
// m_ports[i] = HALLibrary.initializeAnalogPort(port_pointer, status);
HALUtil.checkStatus(status.asIntBuffer());
}
}
/**
* 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.
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
AnalogJNI.setAnalogSampleRateWithModule((byte) m_moduleNumber, (float) samplesPerSecond, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
double value = AnalogJNI.getAnalogSampleRateWithModule((byte) m_moduleNumber, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
AnalogJNI.setAnalogAverageBits(m_ports[channel], bits, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogAverageBits(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
AnalogJNI.setAnalogOversampleBits(m_ports[channel], bits, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogOversampleBits(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogValue(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogAverageValue(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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);
ByteBuffer status = ByteBuffer.allocate(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogVoltsToValue(m_ports[channel], (float) voltage, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
double value = AnalogJNI.getAnalogVoltage(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
double value = AnalogJNI.getAnalogAverageVoltage(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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.
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
long value = AnalogJNI.getAnalogLSBWeight(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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.
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = AnalogJNI.getAnalogOffset(m_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
}

View File

@@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2014. All Rights Reserved. */
/* Copyright (c) FIRST 2014. 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. */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
@@ -28,113 +28,113 @@ import edu.wpi.first.wpilibj.util.CheckedAllocationException;
* Analog output class.
*/
public class AnalogOutput extends SensorBase implements LiveWindowSendable {
private static Resource channels = new Resource(kAnalogOutputChannels);
private ByteBuffer m_port;
private int m_channel;
private static Resource channels = new Resource(kAnalogOutputChannels);
private ByteBuffer m_port;
private int m_channel;
/**
* Construct an analog output on a specified MXP channel.
*
* @param channel
* The channel number to represent.
*/
public AnalogOutput(final int channel) {
m_channel = channel;
/**
* Construct an analog output on a specified MXP channel.
*
* @param channel
* The channel number to represent.
*/
public AnalogOutput(final int channel) {
m_channel = channel;
if (AnalogJNI.checkAnalogOutputChannel(channel) == 0) {
throw new AllocationException("Analog output channel " + m_channel
+ " cannot be allocated. Channel is not present.");
}
try {
channels.allocate(channel);
} catch (CheckedAllocationException e) {
throw new AllocationException("Analog output channel " + m_channel
+ " is already allocated");
}
if (AnalogJNI.checkAnalogOutputChannel(channel) == 0) {
throw new AllocationException("Analog output channel " + m_channel
+ " cannot be allocated. Channel is not present.");
}
try {
channels.allocate(channel);
} catch (CheckedAllocationException e) {
throw new AllocationException("Analog output channel " + m_channel
+ " is already allocated");
}
ByteBuffer port_pointer = AnalogJNI.getPortWithModule((byte) 1, (byte) channel);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = AnalogJNI.initializeAnalogOutputPort(port_pointer, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
ByteBuffer port_pointer = AnalogJNI.getPort((byte)channel);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = AnalogJNI.initializeAnalogOutputPort(port_pointer, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
LiveWindow.addSensor("AnalogOutput", channel, this);
UsageReporting.report(tResourceType.kResourceType_AnalogChannel, channel, 1);
}
LiveWindow.addSensor("AnalogOutput", channel, this);
UsageReporting.report(tResourceType.kResourceType_AnalogChannel, channel, 1);
}
/**
* Channel destructor.
*/
public void free() {
channels.free(m_channel);
m_channel = 0;
}
/**
* Channel destructor.
*/
public void free() {
channels.free(m_channel);
m_channel = 0;
}
public void setVoltage(double voltage) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
public void setVoltage(double voltage) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
AnalogJNI.setAnalogOutput(m_port, voltage, status.asIntBuffer());
AnalogJNI.setAnalogOutput(m_port, voltage, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
HALUtil.checkStatus(status.asIntBuffer());
}
public double getVoltage() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
public double getVoltage() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
double voltage = AnalogJNI.getAnalogOutput(m_port, status.asIntBuffer());
double voltage = AnalogJNI.getAnalogOutput(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return voltage;
}
return voltage;
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Analog Output";
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Analog Output";
}
private ITable m_table;
private ITable m_table;
/**
* {@inheritDoc}
*/
public void initTable(ITable subtable) {
m_table = subtable;
updateTable();
}
/**
* {@inheritDoc}
*/
public void initTable(ITable subtable) {
m_table = subtable;
updateTable();
}
/**
* {@inheritDoc}
*/
public void updateTable() {
if (m_table != null) {
m_table.putNumber("Value", getVoltage());
}
}
/**
* {@inheritDoc}
*/
public void updateTable() {
if (m_table != null) {
m_table.putNumber("Value", getVoltage());
}
}
/**
* {@inheritDoc}
*/
public ITable getTable() {
return m_table;
}
/**
* {@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 entering the
* LiveWindow. {@inheritDoc}
*/
public void startLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the
* LiveWindow. {@inheritDoc}
*/
public void stopLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the
* LiveWindow. {@inheritDoc}
*/
public void stopLiveWindowMode() {
}
}

View File

@@ -56,7 +56,7 @@ public class AnalogTrigger implements IInputOutput {
* the port to use for the analog trigger
*/
protected void initTrigger(final int channel) {
ByteBuffer port_pointer = AnalogJNI.getPortWithModule((byte) 1, (byte) channel);
ByteBuffer port_pointer = AnalogJNI.getPort((byte) channel);
IntBuffer status = IntBuffer.allocate(1);
IntBuffer index = IntBuffer.allocate(1);
// XXX: Uncomment when analog has been fixed

View File

@@ -1,542 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ByteBuffer;
//import com.sun.jna.Pointer;
//import com.sun.jna.ptr.IntByReference;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tModuleType;
import edu.wpi.first.wpilibj.hal.DIOJNI;
import edu.wpi.first.wpilibj.hal.PWMJNI;
import edu.wpi.first.wpilibj.hal.RelayJNI;
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 ByteBuffer[] m_digital_ports;
private ByteBuffer[] m_relay_ports;
private ByteBuffer[] 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);
}
/**
* 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 ByteBuffer[SensorBase.kDigitalChannels];
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
ByteBuffer port_pointer = DIOJNI.getPortWithModule(
(byte) moduleNumber, (byte) i);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_digital_ports[i] = DIOJNI.initializeDigitalPort(port_pointer,
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
m_relay_ports = new ByteBuffer[SensorBase.kRelayChannels];
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
ByteBuffer port_pointer = RelayJNI.getPortWithModule(
(byte) moduleNumber, (byte) i);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_relay_ports[i] = RelayJNI.initializeDigitalPort(port_pointer,
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
m_pwm_ports = new ByteBuffer[SensorBase.kPwmChannels];
for (int i = 0; i < SensorBase.kPwmChannels; i++) {
ByteBuffer port_pointer = PWMJNI.getPortWithModule(
(byte) moduleNumber, (byte) i);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_pwm_ports[i] = PWMJNI.initializeDigitalPort(port_pointer,
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWM(m_pwm_ports[channel], (short) value, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = (int) PWMJNI.getPWM(m_pwm_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMPeriodScale(m_pwm_ports[channel], squelchMask,
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
RelayJNI.setRelayForward(m_relay_ports[channel], (byte) (on ? 1
: 0), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
RelayJNI.setRelayReverse(m_relay_ports[channel], (byte) (on ? 1
: 0), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean value = RelayJNI.getRelayForward(m_relay_ports[channel],
status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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;
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
value |= RelayJNI.getRelayForward(m_relay_ports[i], status.asIntBuffer()) << i;
}
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean value = RelayJNI.getRelayReverse(m_relay_ports[channel],
status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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;
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < SensorBase.kRelayChannels; i++) {
value |= RelayJNI.getRelayReverse(m_relay_ports[i], status.asIntBuffer()) << i;
}
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean allocated = DIOJNI.allocateDIO(
m_digital_ports[channel], (byte) (input ? 1 : 0), status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
DIOJNI.freeDIO(m_digital_ports[channel], status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
DIOJNI.setDIO(m_digital_ports[channel], (byte) (value ? 1 : 0),
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean value = DIOJNI.getDIO(m_digital_ports[channel], status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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() {
short value = 0;
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
value |= DIOJNI.getDIO(m_digital_ports[i], status.asIntBuffer()) << i;
}
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean value = DIOJNI.getDIODirection(
m_digital_ports[channel], status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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;
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < SensorBase.kDigitalChannels; i++) {
value |= DIOJNI.getDIODirection(m_digital_ports[i], status.asIntBuffer()) << i;
}
HALUtil.checkStatus(status.asIntBuffer());
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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
DIOJNI.pulse(m_digital_ports[channel], pulseLength, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* @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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
float convertedPulse = (float) (pulseLength / 1.0e9 * (DIOJNI.getLoopTiming(status.asIntBuffer()) * 25));
System.err
.println("You should use the float version of pulse for portability. This is deprecated");
DIOJNI.pulse(m_digital_ports[channel], convertedPulse, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
boolean value = DIOJNI.isPulsing(m_digital_ports[channel],
status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
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;
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
value = DIOJNI.isAnyPulsingWithModule((byte) m_module, status.asIntBuffer()) != 0;
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
/**
* Allocate a DO PWM Generator. Allocate PWM generators so that they are not
* accidently reused.
*/
public ByteBuffer allocateDO_PWM() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer value = PWMJNI.allocatePWMWithModule((byte) m_module, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
/**
* Free the resource associated with a DO PWM generator.
*/
public void freeDO_PWM(ByteBuffer pwmGenerator) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.freePWMWithModule((byte) m_module, pwmGenerator, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMRateWithModule((byte) m_module, rate, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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(ByteBuffer pwmGenerator, int channel) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMOutputChannelWithModule((byte) m_module, pwmGenerator,
channel, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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(ByteBuffer pwmGenerator, double dutyCycle) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMDutyCycleWithModule((byte) m_module, pwmGenerator, dutyCycle, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Get the loop timing of the Digital Module
*
* @return The number of clock ticks per DIO loop
*/
public int getLoopTiming() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
int value = DIOJNI.getLoopTiming(status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
}

View File

@@ -138,25 +138,22 @@ public class DigitalOutput extends DigitalSource implements IInputOutput,
* 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.
* There is only one PWM frequency for all channnels.
*
* @param rate
* The frequency to output all digital output PWM signals on this
* module.
* @param rate The frequency to output all digital output PWM signals.
*/
public void setPWMRate(double rate) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMRateWithModule((byte) 1, rate,
status.asIntBuffer());
PWMJNI.setPWMRate(rate, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* Enable a PWM Output on this line.
*
* Allocate one of the 4 DO PWM generator resources from this module.
* Allocate one of the 4 DO PWM generator resources.
*
* Supply the initial duty-cycle to output so as to avoid a glitch when
* first starting.
@@ -173,12 +170,12 @@ public class DigitalOutput extends DigitalSource implements IInputOutput,
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
m_pwmGenerator = PWMJNI.allocatePWMWithModule((byte) 1, status.asIntBuffer());
m_pwmGenerator = PWMJNI.allocatePWM(status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
PWMJNI.setPWMDutyCycle(m_pwmGenerator, initialDutyCycle,
status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
PWMJNI.setPWMOutputChannelWithModule((byte) 1, m_pwmGenerator, m_channel, status.asIntBuffer());
PWMJNI.setPWMOutputChannel(m_pwmGenerator, m_channel, status.asIntBuffer());
}
/**
@@ -193,7 +190,7 @@ public class DigitalOutput extends DigitalSource implements IInputOutput,
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMOutputChannel(m_pwmGenerator, kDigitalChannels, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
PWMJNI.freePWMWithModule((byte) 1, m_pwmGenerator, status.asIntBuffer());
PWMJNI.freePWM(m_pwmGenerator, status.asIntBuffer());
m_pwmGenerator = null;
}
@@ -210,7 +207,7 @@ public class DigitalOutput extends DigitalSource implements IInputOutput,
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWMDutyCycleWithModule((byte) 1, m_pwmGenerator, dutyCycle, status.asIntBuffer());
PWMJNI.setPWMDutyCycle(m_pwmGenerator, dutyCycle, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}

View File

@@ -44,7 +44,7 @@ public abstract class DigitalSource extends InterruptableSensorBase {
+ " is already allocated");
}
ByteBuffer port_pointer = DIOJNI.getPortWithModule((byte) 1, (byte) channel);
ByteBuffer port_pointer = DIOJNI.getPort((byte) channel);
ByteBuffer status = ByteBuffer.allocateDirect(4);
// set the byte order
status.order(ByteOrder.LITTLE_ENDIAN);

View File

@@ -52,9 +52,9 @@ public class GearTooth extends Counter implements ISensor {
super(channel);
enableDirectionSensing(directionSensitive);
if(directionSensitive) {
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1, "D");
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, 0, "D");
} else {
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, DigitalModule.getDefaultDigitalModule()-1);
UsageReporting.report(tResourceType.kResourceType_GearTooth, channel, 0);
}
LiveWindow.addSensor("GearTooth", channel, this);
}

View File

@@ -57,7 +57,7 @@ public class Gyro extends SensorBase implements PIDSource, ISensor,
m_analog.setOversampleBits(kOversampleBits);
double sampleRate = kSamplesPerSecond
* (1 << (kAverageBits + kOversampleBits));
m_analog.setSampleRate(sampleRate);
AnalogInput.setGlobalSampleRate(sampleRate);
Timer.delay(1.0);
m_analog.initAccumulator();
@@ -160,7 +160,7 @@ public class Gyro extends SensorBase implements PIDSource, ISensor,
* 1e-9
* m_analog.getLSBWeight()
* (1 << m_analog.getAverageBits())
/ (m_analog.getModule().getSampleRate() * m_voltsPerDegreePerSecond);
/ (AnalogInput.getGlobalSampleRate() * m_voltsPerDegreePerSecond);
return scaledValue;
}

View File

@@ -28,11 +28,11 @@ import edu.wpi.first.wpilibj.util.BoundaryException;
public class I2C extends SensorBase {
public enum Port {kOnboard(0), kMXP(1);
private int value;
private Port(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
@@ -44,21 +44,19 @@ public class I2C extends SensorBase {
/**
* 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(Port port, int deviceAddress) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = port;
m_deviceAddress = deviceAddress;
I2CJNI.i2CInitialize((byte)m_port.getValue(), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
UsageReporting.report(tResourceType.kResourceType_I2C, deviceAddress);
}
@@ -93,7 +91,7 @@ public class I2C extends SensorBase {
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(receiveSize);
aborted = I2CJNI
.i2CTransaction((byte) m_port.getValue(), (byte) m_deviceAddress,
.i2CTransaction((byte) m_port.getValue(), (byte) m_deviceAddress,
dataToSendBuffer, (byte) sendSize,
dataReceivedBuffer, (byte) receiveSize) != 0;
/*if (status.get() == HALUtil.PARAMETER_OUT_OF_RANGE) {
@@ -140,13 +138,13 @@ public class I2C extends SensorBase {
byte[] buffer = new byte[2];
buffer[0] = (byte) registerAddress;
buffer[1] = (byte) data;
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(2);
dataToSendBuffer.put(buffer);
return I2CJNI.i2CWrite((byte)m_port.getValue(), (byte) m_deviceAddress, dataToSendBuffer, (byte)buffer.length) < 0;
}
/**
* Execute a write transaction with the device.
*
@@ -156,10 +154,10 @@ public class I2C extends SensorBase {
* @param data
* The data to write to the device.
*/
public synchronized boolean writeBulk(byte[] data) {
public synchronized boolean writeBulk(byte[] data) {
ByteBuffer dataToSendBuffer = ByteBuffer.allocateDirect(data.length);
dataToSendBuffer.put(data);
return I2CJNI.i2CWrite((byte)m_port.getValue(), (byte) m_deviceAddress, dataToSendBuffer, (byte)data.length) < 0;
}
@@ -190,7 +188,7 @@ public class I2C extends SensorBase {
return transaction(registerAddressArray, registerAddressArray.length,
buffer, count);
}
/**
* Execute a read only transaction with the device.
*
@@ -209,9 +207,9 @@ public class I2C extends SensorBase {
if (buffer == null) {
throw new NullPointerException("Null return buffer was given");
}
ByteBuffer dataReceivedBuffer = ByteBuffer.allocateDirect(count);
int retVal = I2CJNI.i2CRead((byte)m_port.getValue(), (byte) m_deviceAddress, dataReceivedBuffer, (byte)count);
dataReceivedBuffer.get(buffer);
return retVal < 0;

View File

@@ -1,93 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008-2012. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.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 * FRCNetworkCommunicationsLibrary.kMaxModuleNumber + (FRCNetworkCommunicationsLibrary.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 > FRCNetworkCommunicationsLibrary.kMaxModuleNumber)
return 0;
return moduleType * FRCNetworkCommunicationsLibrary.kMaxModuleNumber + (moduleNumber - 1);
}
}

View File

@@ -7,14 +7,19 @@
package edu.wpi.first.wpilibj;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
import edu.wpi.first.wpilibj.communication.UsageReporting;
import edu.wpi.first.wpilibj.hal.PWMJNI;
import edu.wpi.first.wpilibj.hal.DIOJNI;
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;
import edu.wpi.first.wpilibj.hal.HALUtil;
/**
* Class implements the PWM generation in the FPGA.
@@ -32,427 +37,457 @@ import edu.wpi.first.wpilibj.util.CheckedAllocationException;
* 0 = disabled (i.e. PWM output is held low)
*/
public class PWM extends SensorBase implements LiveWindowSendable {
private static Resource allocated = new Resource( 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 ByteBuffer m_port;
/**
* 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 a channel.
*
* This method is private and is the common path for all the constructors
* for creating PWM instances. Checks 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 channel) {
checkPWMChannel(channel);
try {
allocated.allocate(channel);
} catch (CheckedAllocationException e) {
throw new AllocationException(
"PWM channel " + channel + " is already allocated");
}
m_channel = channel;
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = DIOJNI.initializeDigitalPort(DIOJNI.getPort((byte) m_channel), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
PWMJNI.setPWM(m_port, (short) 0, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
m_eliminateDeadband = false;
UsageReporting.report(tResourceType.kResourceType_PWM, channel);
}
/**
* Allocate a PWM given a channel.
*
* @param channel The PWM channel.
*/
public PWM(final int channel) {
initPWM(channel);
}
/**
* Free the PWM channel.
*
* Free the resource associated with the PWM channel and set the value to 0.
*/
public void free() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWM(m_port, (short) 0, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
PWMJNI.freeDIO(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
allocated.free(m_channel);
}
/**
* 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
*/
protected void setBounds(double max, double deadbandMax, double center, double deadbandMin, double min) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
double loopTime = DIOJNI.getLoopTiming(status.asIntBuffer())/(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 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) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
PWMJNI.setPWM(m_port, (short) value, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
* 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() {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
int value = PWMJNI.getPWM(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
return value;
}
/**
* Slow down the PWM signal for old devices.
*
* @param mult The period multiplier to apply to this channel
*/
public void setPeriodMultiplier(PeriodMultiplier mult) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
switch (mult.value) {
case PeriodMultiplier.k4X_val:
// Squelch 3 out of 4 outputs
PWMJNI.setPWMPeriodScale(m_port, 3, status.asIntBuffer());
break;
case PeriodMultiplier.k2X_val:
// Squelch 1 out of 2 outputs
PWMJNI.setPWMPeriodScale(m_port, 1, status.asIntBuffer());
break;
case PeriodMultiplier.k1X_val:
// Don't squelch any outputs
PWMJNI.setPWMPeriodScale(m_port, 0, status.asIntBuffer());
break;
default:
//Cannot hit this, limited by PeriodMultiplier enum
}
HALUtil.checkStatus(status.asIntBuffer());
}
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.
/*
* 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.
* 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;
private static Resource allocated = new Resource( kPwmChannels);
/**
* {@inheritDoc}
*/
public void initTable(ITable subtable) {
m_table = subtable;
updateTable();
}
/**
* Represents the amount to multiply the minimum servo-pulse pwm period by.
*/
public static class PeriodMultiplier {
/**
* {@inheritDoc}
*/
public void updateTable() {
if (m_table != null) {
m_table.putNumber("Value", getSpeed());
}
}
/**
* 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);
/**
* {@inheritDoc}
*/
public ITable getTable() {
return m_table;
}
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;
/**
* {@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);
}
/**
* Initialize PWMs given a 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 channel) {
checkPWMChannel(channel);
try {
allocated.allocate(channel);
} catch (CheckedAllocationException e) {
throw new AllocationException(
"PWM channel " + channel + " is already allocated");
}
m_channel = channel;
m_module = DigitalModule.getInstance(1);
m_module.setPWM(m_channel, kPwmDisabled);
m_eliminateDeadband = false;
UsageReporting.report(tResourceType.kResourceType_PWM, channel);
}
/**
* Allocate a PWM given a channel.
*
* @param channel The PWM channel.
*/
public PWM(final int channel) {
initPWM(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_channel);
}
/**
* 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
*/
protected 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 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);
}
/**
* {@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);
}
}

View File

@@ -7,9 +7,15 @@
package edu.wpi.first.wpilibj;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
import edu.wpi.first.wpilibj.communication.UsageReporting;
import edu.wpi.first.wpilibj.hal.DIOJNI;
import edu.wpi.first.wpilibj.hal.RelayJNI;
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.IDeviceController;
@@ -113,8 +119,8 @@ public class Relay extends SensorBase implements IDeviceController,
}
private int m_channel;
private ByteBuffer m_port;
private Direction m_direction;
private DigitalModule m_module;
private static Resource relayChannels = new Resource(kRelayChannels * 2);
/**
@@ -138,9 +144,13 @@ public class Relay extends SensorBase implements IDeviceController,
} catch (CheckedAllocationException e) {
throw new AllocationException("Relay channel " + m_channel + " is already allocated");
}
m_module = DigitalModule.getInstance(1);
m_module.setRelayForward(m_channel, false);
m_module.setRelayReverse(m_channel, false);
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
m_port = DIOJNI.initializeDigitalPort(DIOJNI.getPort((byte) m_channel), status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
LiveWindow.addActuator("Relay", m_channel, this);
}
@@ -173,21 +183,22 @@ public class Relay extends SensorBase implements IDeviceController,
}
public void free() {
m_module.setRelayForward(m_channel, false);
m_module.setRelayReverse(m_channel, false);
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
RelayJNI.setRelayForward(m_port, (byte) 0, status.asIntBuffer());
RelayJNI.setRelayForward(m_port, (byte) 0, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
if (m_direction == Direction.kBoth || m_direction == Direction.kForward) {
relayChannels.free(((m_module.getModuleNumber() - 1)
* kRelayChannels + m_channel) * 2);
m_module.freeDIO(((m_module.getModuleNumber() - 1) * kRelayChannels
+ m_channel) * 2);
relayChannels.free(m_channel);
}
if (m_direction == Direction.kBoth || m_direction == Direction.kReverse) {
relayChannels.free(((m_module.getModuleNumber() - 1)
* kRelayChannels + m_channel) * 2 + 1);
m_module.freeDIO(((m_module.getModuleNumber() - 1) * kRelayChannels
+ m_channel) * 2 + 1);
relayChannels.free(m_channel + 1);
}
DIOJNI.freeDIO(m_port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());
}
/**
@@ -207,25 +218,28 @@ public class Relay extends SensorBase implements IDeviceController,
* The state to set the relay.
*/
public void set(Value value) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
switch (value.value) {
case Value.kOff_val:
if (m_direction == Direction.kBoth
|| m_direction == Direction.kForward) {
m_module.setRelayForward(m_channel, false);
RelayJNI.setRelayForward(m_port, (byte) 0, status.asIntBuffer());
}
if (m_direction == Direction.kBoth
|| m_direction == Direction.kReverse) {
m_module.setRelayReverse(m_channel, false);
RelayJNI.setRelayReverse(m_port, (byte) 0, status.asIntBuffer());
}
break;
case Value.kOn_val:
if (m_direction == Direction.kBoth
|| m_direction == Direction.kForward) {
m_module.setRelayForward(m_channel, true);
RelayJNI.setRelayForward(m_port, (byte) 1, status.asIntBuffer());
}
if (m_direction == Direction.kBoth
|| m_direction == Direction.kReverse) {
m_module.setRelayReverse(m_channel, true);
RelayJNI.setRelayReverse(m_port, (byte) 1, status.asIntBuffer());
}
break;
case Value.kForward_val:
@@ -234,10 +248,10 @@ public class Relay extends SensorBase implements IDeviceController,
"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);
RelayJNI.setRelayForward(m_port, (byte) 1, status.asIntBuffer());
}
if (m_direction == Direction.kBoth) {
m_module.setRelayReverse(m_channel, false);
RelayJNI.setRelayReverse(m_port, (byte) 0, status.asIntBuffer());
}
break;
case Value.kReverse_val:
@@ -245,16 +259,18 @@ public class Relay extends SensorBase implements IDeviceController,
throw new InvalidValueException(
"A relay configured for forward cannot be set to reverse");
if (m_direction == Direction.kBoth) {
m_module.setRelayForward(m_channel, false);
RelayJNI.setRelayForward(m_port, (byte) 0, status.asIntBuffer());
}
if (m_direction == Direction.kBoth
|| m_direction == Direction.kReverse) {
m_module.setRelayReverse(m_channel, true);
RelayJNI.setRelayReverse(m_port, (byte) 1, status.asIntBuffer());
}
break;
default:
// Cannot hit this, limited by Value enum
}
HALUtil.checkStatus(status.asIntBuffer());
}
/**
@@ -268,8 +284,11 @@ public class Relay extends SensorBase implements IDeviceController,
* @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)) {
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
if (RelayJNI.getRelayForward(m_port, status.asIntBuffer()) != 0) {
if (RelayJNI.getRelayReverse(m_port, status.asIntBuffer()) != 0) {
return Value.kOn;
} else {
if (m_direction == Direction.kForward) {
@@ -279,7 +298,7 @@ public class Relay extends SensorBase implements IDeviceController,
}
}
} else {
if (m_module.getRelayReverse(m_channel)) {
if (RelayJNI.getRelayReverse(m_port, status.asIntBuffer()) != 0) {
if (m_direction == Direction.kForward) {
return Value.kOn;
} else {

View File

@@ -14,8 +14,6 @@ import edu.wpi.first.wpilibj.hal.AnalogJNI;
* 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
@@ -30,28 +28,19 @@ public abstract class SensorBase { // TODO: Refactor
*/
public static final int kDigitalChannels = 26;
/**
* Number of digital modules
* XXX: This number is incorrect. We need to find the correct number.
*/
public static final int kDigitalModules = 1;
/**
* Number of analog input channels per module
* Number of analog input channels
*/
public static final int kAnalogInputChannels = 8;
/**
* Number of analog output channels per module
* Number of analog output channels
*/
public static final int kAnalogOutputChannels = 2;
/**
* Number of analog modules
*/
public static final int kAnalogModules = 1;
/**
* Number of solenoid channels per module
*/
public static final int kSolenoidChannels = 8;
/**
* Number of analog modules
* Number of solenoid modules
*/
public static final int kSolenoidModules = 2;
/**
@@ -67,8 +56,6 @@ public abstract class SensorBase { // TODO: Refactor
*/
public static final int kPDPChannels = 16;
private static int m_defaultAnalogModule = 1;
private static int m_defaultDigitalModule = 1;
private static int m_defaultSolenoidModule = 0;
/**
@@ -78,33 +65,7 @@ public abstract class SensorBase { // TODO: Refactor
}
/**
* 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.
* Set the default location for the Solenoid module.
*
* @param moduleNumber The number of the solenoid module to use.
*/
@@ -113,49 +74,6 @@ public abstract class SensorBase { // TODO: Refactor
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(DIOJNI.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(AnalogJNI.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).
@@ -260,25 +178,7 @@ public abstract class SensorBase { // TODO: Refactor
}
/**
* 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.
* Get the number of the default solenoid module.
*
* @return The number of the default analog module.
*/

View File

@@ -22,14 +22,14 @@ import edu.wpi.first.wpilibj.util.AllocationException;
import edu.wpi.first.wpilibj.util.CheckedAllocationException;
/**
* Solenoid class for running high voltage Digital Output (9472 module).
* Solenoid class for running high voltage Digital Output.
*
* The Solenoid class is typically used for pneumatics solenoids, but could be used
* for any device within the current spec of the 9472 module.
* for any device within the current spec of the PCM.
*/
public class Solenoid extends SolenoidBase implements LiveWindowSendable {
private int m_channel; ///< The channel on the module to control.
private int m_channel; ///< The channel to control.
private ByteBuffer m_solenoid_port;
/**
@@ -39,16 +39,9 @@ public class Solenoid extends SolenoidBase implements LiveWindowSendable {
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");
// }
ByteBuffer status = ByteBuffer.allocateDirect(4);
status.order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer port = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
m_solenoid_port = SolenoidJNI.initializeSolenoidPort(port, status.asIntBuffer());
HALUtil.checkStatus(status.asIntBuffer());

View File

@@ -162,8 +162,7 @@ public class Ultrasonic extends SensorBase implements PIDSource, ISensor,
/**
* Create an instance of the Ultrasonic Sensor.
* 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.
* sensors. Default unit is inches.
*
* @param pingChannel
* The digital output channel that sends the pulse to initiate

View File

@@ -23,33 +23,33 @@ public class JNIWrapper
jniLibrary = File.createTempFile("libwpilibJavaJNI", ".so");
// flag for delete on exit
jniLibrary.deleteOnExit();
byte [] buffer = new byte[1024];
int readBytes;
InputStream is = JNIWrapper.class.getResourceAsStream("/linux-arm/libwpilibJavaJNI.so");
OutputStream os = new FileOutputStream(jniLibrary);
try
{
while((readBytes = is.read(buffer)) != -1 )
{
os.write(buffer, 0, readBytes);
}
}
finally
{
os.close();
is.close();
}
libraryLoaded = true;
}
System.load(jniLibrary.getAbsolutePath());
}
catch( Exception ex )
@@ -59,4 +59,5 @@ public class JNIWrapper
}
}
public static native ByteBuffer getPortWithModule(byte module, byte pin);
public static native ByteBuffer getPort(byte pin);
}