Update LiveWindow to provide continuous telemetry. (#771)

LiveWindow.updateValues() is now called from IterativeRobotBase on every
loop iteration.  Telemetry for all WPILib classes is enabled by default;
it can be disabled for specific classes using LiveWindow.disableTelemetry(),
or all telemetry can be disabled using LiveWindow.disableAllTelemetry().

This necessitated changing the hook methodology into other classes to
be more property-based rather than each class providing multiple functions.
This had the benefit of reducing boilerplate and increasing consistency.

- Remove NamedSendable, add name to Sendable.

- Provide SendableBase abstract class.

- Deprecate LiveWindow addSensor/addActuator interfaces.

- Add LiveWindow support to drive classes.

- Add addChild() helper functions to Subsystem.

- Fix inheritance hierarchy.  Now only sensors inherit from SensorBase.
  Other devices inherit from some combination of SendableBase, ErrorBase, or
  nothing.
This commit is contained in:
Peter Johnson
2017-12-04 23:28:33 -08:00
committed by GitHub
parent 3befc7015b
commit f9bece2ffb
213 changed files with 3704 additions and 3758 deletions

View File

@@ -10,20 +10,18 @@ package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* ADXL345 I2C Accelerometer.
*/
@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindowSendable {
public class ADXL345_I2C extends SensorBase implements Accelerometer, Sendable {
private static final byte kAddress = 0x1D;
private static final byte kPowerCtlRegister = 0x2D;
@@ -93,9 +91,14 @@ public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindow
setRange(range);
HAL.report(tResourceType.kResourceType_ADXL345, tInstances.kADXL345_I2C);
LiveWindow.addSensor("ADXL345_I2C", port.value, this);
setName("ADXL345_I2C", port.value);
}
@Override
public void free() {
super.free();
m_i2c.free();
}
@Override
public void setRange(Range range) {
@@ -171,49 +174,16 @@ public class ADXL345_I2C extends SensorBase implements Accelerometer, LiveWindow
}
@Override
public String getSmartDashboardType() {
return "3AxisAccelerometer";
}
@SuppressWarnings("MemberName")
private NetworkTableEntry m_xEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_yEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_zEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_xEntry = subtable.getEntry("X");
m_yEntry = subtable.getEntry("Y");
m_zEntry = subtable.getEntry("Z");
updateTable();
} else {
m_xEntry = null;
m_yEntry = null;
m_zEntry = null;
}
}
@Override
public void updateTable() {
if (m_xEntry != null) {
m_xEntry.setDouble(getX());
}
if (m_yEntry != null) {
m_yEntry.setDouble(getY());
}
if (m_zEntry != null) {
m_zEntry.setDouble(getZ());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
builder.setUpdateTable(() -> {
AllAxes data = getAccelerations();
entryX.setDouble(data.XAxis);
entryY.setDouble(data.YAxis);
entryZ.setDouble(data.ZAxis);
});
}
}

View File

@@ -10,20 +10,18 @@ package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* ADXL345 SPI Accelerometer.
*/
@SuppressWarnings({"TypeName", "PMD.UnusedPrivateField"})
public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindowSendable {
public class ADXL345_SPI extends SensorBase implements Accelerometer, Sendable {
private static final int kPowerCtlRegister = 0x2D;
private static final int kDataFormatRegister = 0x31;
private static final int kDataRegister = 0x32;
@@ -78,10 +76,12 @@ public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindow
public ADXL345_SPI(SPI.Port port, Range range) {
m_spi = new SPI(port);
init(range);
LiveWindow.addSensor("ADXL345_SPI", port.value, this);
setName("ADXL345_SPI", port.value);
}
@Override
public void free() {
super.free();
m_spi.free();
}
@@ -189,49 +189,16 @@ public class ADXL345_SPI extends SensorBase implements Accelerometer, LiveWindow
}
@Override
public String getSmartDashboardType() {
return "3AxisAccelerometer";
}
@SuppressWarnings("MemberName")
private NetworkTableEntry m_xEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_yEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_zEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_xEntry = subtable.getEntry("X");
m_yEntry = subtable.getEntry("Y");
m_zEntry = subtable.getEntry("Z");
updateTable();
} else {
m_xEntry = null;
m_yEntry = null;
m_zEntry = null;
}
}
@Override
public void updateTable() {
if (m_xEntry != null) {
m_xEntry.setDouble(getX());
}
if (m_yEntry != null) {
m_yEntry.setDouble(getY());
}
if (m_zEntry != null) {
m_zEntry.setDouble(getZ());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
builder.setUpdateTable(() -> {
AllAxes data = getAccelerations();
entryX.setDouble(data.XAxis);
entryY.setDouble(data.YAxis);
entryZ.setDouble(data.ZAxis);
});
}
}

View File

@@ -10,13 +10,11 @@ package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* ADXL362 SPI Accelerometer.
@@ -24,7 +22,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* <p>This class allows access to an Analog Devices ADXL362 3-axis accelerometer.
*/
@SuppressWarnings("PMD.UnusedPrivateField")
public class ADXL362 extends SensorBase implements Accelerometer, LiveWindowSendable {
public class ADXL362 extends SensorBase implements Accelerometer, Sendable {
private static final byte kRegWrite = 0x0A;
private static final byte kRegRead = 0x0B;
@@ -82,6 +80,7 @@ public class ADXL362 extends SensorBase implements Accelerometer, LiveWindowSend
*/
public ADXL362(SPI.Port port, Range range) {
m_spi = new SPI(port);
m_spi.setClockRate(3000000);
m_spi.setMSBFirst();
m_spi.setSampleDataOnFalling();
@@ -109,17 +108,25 @@ public class ADXL362 extends SensorBase implements Accelerometer, LiveWindowSend
m_spi.write(transferBuffer, 3);
HAL.report(tResourceType.kResourceType_ADXL362, port.value);
LiveWindow.addSensor("ADXL362", port.value, this);
setName("ADXL362", port.value);
}
@Override
public void free() {
m_spi.free();
super.free();
if (m_spi != null) {
m_spi.free();
m_spi = null;
}
}
@Override
public void setRange(Range range) {
final byte value;
if (m_spi == null) {
return;
}
final byte value;
switch (range) {
case k2G:
value = kFilterCtl_Range2G;
@@ -205,49 +212,16 @@ public class ADXL362 extends SensorBase implements Accelerometer, LiveWindowSend
}
@Override
public String getSmartDashboardType() {
return "3AxisAccelerometer";
}
@SuppressWarnings("MemberName")
private NetworkTableEntry m_xEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_yEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_zEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_xEntry = subtable.getEntry("X");
m_yEntry = subtable.getEntry("Y");
m_zEntry = subtable.getEntry("Z");
updateTable();
} else {
m_xEntry = null;
m_yEntry = null;
m_zEntry = null;
}
}
@Override
public void updateTable() {
if (m_xEntry != null) {
m_xEntry.setDouble(getX());
}
if (m_yEntry != null) {
m_yEntry.setDouble(getY());
}
if (m_zEntry != null) {
m_zEntry.setDouble(getZ());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
NetworkTableEntry entryX = builder.getEntry("X");
NetworkTableEntry entryY = builder.getEntry("Y");
NetworkTableEntry entryZ = builder.getEntry("Z");
builder.setUpdateTable(() -> {
AllAxes data = getAccelerations();
entryX.setDouble(data.XAxis);
entryY.setDouble(data.YAxis);
entryZ.setDouble(data.ZAxis);
});
}
}

View File

@@ -13,8 +13,6 @@ import java.nio.ByteOrder;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
/**
* Use a rate gyro to return the robots heading relative to a starting position. The Gyro class
@@ -26,7 +24,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* <p>This class is for the digital ADXRS450 gyro sensor that connects via SPI.
*/
@SuppressWarnings({"TypeName", "AbbreviationAsWordInName", "PMD.UnusedPrivateField"})
public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, LiveWindowSendable {
public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, Sendable {
private static final double kSamplePeriod = 0.001;
private static final double kCalibrationSampleTime = 5.0;
private static final double kDegreePerSecondPerLSB = 0.0125;
@@ -57,6 +55,7 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, LiveWind
*/
public ADXRS450_Gyro(SPI.Port port) {
m_spi = new SPI(port);
m_spi.setClockRate(3000000);
m_spi.setMSBFirst();
m_spi.setSampleDataOnRising();
@@ -78,7 +77,7 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, LiveWind
calibrate();
HAL.report(tResourceType.kResourceType_ADXRS450, port.value);
LiveWindow.addSensor("ADXRS450_Gyro", port.value, this);
setName("ADXRS450_Gyro", port.value);
}
@Override
@@ -137,6 +136,7 @@ public class ADXRS450_Gyro extends GyroBase implements Gyro, PIDSource, LiveWind
*/
@Override
public void free() {
super.free();
if (m_spi != null) {
m_spi.free();
m_spi = null;

View File

@@ -7,12 +7,9 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import static java.util.Objects.requireNonNull;
@@ -21,7 +18,7 @@ import static java.util.Objects.requireNonNull;
* 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 AnalogAccelerometer extends SensorBase implements PIDSource, LiveWindowSendable {
public class AnalogAccelerometer extends SensorBase implements PIDSource, Sendable {
private AnalogInput m_analogChannel;
private double m_voltsPerG = 1.0;
@@ -35,7 +32,7 @@ public class AnalogAccelerometer extends SensorBase implements PIDSource, LiveWi
private void initAccelerometer() {
HAL.report(tResourceType.kResourceType_Accelerometer,
m_analogChannel.getChannel());
LiveWindow.addSensor("Accelerometer", m_analogChannel.getChannel(), this);
setName("Accelerometer", m_analogChannel.getChannel());
}
/**
@@ -46,9 +43,9 @@ public class AnalogAccelerometer extends SensorBase implements PIDSource, LiveWi
* @param channel The channel number for the analog input the accelerometer is connected to
*/
public AnalogAccelerometer(final int channel) {
m_analogChannel = new AnalogInput(channel);
this(new AnalogInput(channel));
m_allocatedChannel = true;
initAccelerometer();
addChild(m_analogChannel);
}
/**
@@ -72,6 +69,7 @@ public class AnalogAccelerometer extends SensorBase implements PIDSource, LiveWi
*/
@Override
public void free() {
super.free();
if (m_analogChannel != null && m_allocatedChannel) {
m_analogChannel.free();
}
@@ -86,6 +84,9 @@ public class AnalogAccelerometer extends SensorBase implements PIDSource, LiveWi
* @return The current acceleration of the sensor in Gs.
*/
public double getAcceleration() {
if (m_analogChannel == null) {
return 0.0;
}
return (m_analogChannel.getAverageVoltage() - m_zeroGVoltage) / m_voltsPerG;
}
@@ -134,43 +135,8 @@ public class AnalogAccelerometer extends SensorBase implements PIDSource, LiveWi
}
@Override
public String getSmartDashboardType() {
return "Accelerometer";
}
/*
* Live Window code, only does anything if live window is activated.
*/
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getAcceleration());
}
}
/**
* Analog Channels don't have to do anything special when entering the LiveWindow. {@inheritDoc}
*/
@Override
public void startLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the LiveWindow. {@inheritDoc}
*/
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Accelerometer");
builder.addDoubleProperty("Value", this::getAcceleration, null);
}
}

View File

@@ -11,8 +11,6 @@ import edu.wpi.first.wpilibj.hal.AnalogGyroJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import static java.util.Objects.requireNonNull;
@@ -25,7 +23,7 @@ import static java.util.Objects.requireNonNull;
*
* <p>This class is for gyro sensors that connect to an analog input.
*/
public class AnalogGyro extends GyroBase implements Gyro, PIDSource, LiveWindowSendable {
public class AnalogGyro extends GyroBase implements Gyro, PIDSource, Sendable {
private static final double kDefaultVoltsPerDegreePerSecond = 0.007;
protected AnalogInput m_analog;
@@ -44,7 +42,7 @@ public class AnalogGyro extends GyroBase implements Gyro, PIDSource, LiveWindowS
AnalogGyroJNI.setupAnalogGyro(m_gyroHandle);
HAL.report(tResourceType.kResourceType_Gyro, m_analog.getChannel());
LiveWindow.addSensor("AnalogGyro", m_analog.getChannel(), this);
setName("AnalogGyro", m_analog.getChannel());
}
@Override
@@ -61,6 +59,7 @@ public class AnalogGyro extends GyroBase implements Gyro, PIDSource, LiveWindowS
public AnalogGyro(int channel) {
this(new AnalogInput(channel));
m_channelAllocated = true;
addChild(m_analog);
}
/**
@@ -90,6 +89,7 @@ public class AnalogGyro extends GyroBase implements Gyro, PIDSource, LiveWindowS
public AnalogGyro(int channel, int center, double offset) {
this(new AnalogInput(channel), center, offset);
m_channelAllocated = true;
addChild(m_analog);
}
/**
@@ -121,6 +121,7 @@ public class AnalogGyro extends GyroBase implements Gyro, PIDSource, LiveWindowS
*/
@Override
public void free() {
super.free();
if (m_analog != null && m_channelAllocated) {
m_analog.free();
}

View File

@@ -7,13 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.AnalogJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.util.AllocationException;
/**
@@ -28,7 +25,7 @@ import edu.wpi.first.wpilibj.util.AllocationException;
* 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 AnalogInput extends SensorBase implements PIDSource, LiveWindowSendable {
public class AnalogInput extends SensorBase implements PIDSource, Sendable {
private static final int kAccumulatorSlot = 1;
int m_port; // explicit no modifier, private and package accessible.
@@ -49,14 +46,16 @@ public class AnalogInput extends SensorBase implements PIDSource, LiveWindowSend
final int portHandle = AnalogJNI.getPort((byte) channel);
m_port = AnalogJNI.initializeAnalogInputPort(portHandle);
LiveWindow.addSensor("AnalogInput", channel, this);
HAL.report(tResourceType.kResourceType_AnalogChannel, channel);
setName("AnalogInput", channel);
}
/**
* Channel destructor.
*/
@Override
public void free() {
super.free();
AnalogJNI.freeAnalogInputPort(m_port);
m_port = 0;
m_channel = 0;
@@ -347,44 +346,9 @@ public class AnalogInput extends SensorBase implements PIDSource, LiveWindowSend
return getAverageVoltage();
}
/**
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Analog Input";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getAverageVoltage());
}
}
/**
* Analog Channels don't have to do anything special when entering the LiveWindow. {@inheritDoc}
*/
@Override
public void startLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the LiveWindow. {@inheritDoc}
*/
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Analog Input");
builder.addDoubleProperty("Value", this::getAverageVoltage, null);
}
}

View File

@@ -7,18 +7,15 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.AnalogJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Analog output class.
*/
public class AnalogOutput extends SensorBase implements LiveWindowSendable {
public class AnalogOutput extends SendableBase implements Sendable {
private int m_port;
private int m_channel;
@@ -28,20 +25,22 @@ public class AnalogOutput extends SensorBase implements LiveWindowSendable {
* @param channel The channel number to represent.
*/
public AnalogOutput(final int channel) {
checkAnalogOutputChannel(channel);
SensorBase.checkAnalogOutputChannel(channel);
m_channel = channel;
final int portHandle = AnalogJNI.getPort((byte) channel);
m_port = AnalogJNI.initializeAnalogOutputPort(portHandle);
LiveWindow.addSensor("AnalogOutput", channel, this);
HAL.report(tResourceType.kResourceType_AnalogOutput, channel);
setName("AnalogOutput", channel);
}
/**
* Channel destructor.
*/
@Override
public void free() {
super.free();
AnalogJNI.freeAnalogOutputPort(m_port);
m_port = 0;
m_channel = 0;
@@ -62,44 +61,9 @@ public class AnalogOutput extends SensorBase implements LiveWindowSendable {
return AnalogJNI.getAnalogOutput(m_port);
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Analog Output";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getVoltage());
}
}
/**
* Analog Channels don't have to do anything special when entering the LiveWindow. {@inheritDoc}
*/
@Override
public void startLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the LiveWindow. {@inheritDoc}
*/
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Analog Output");
builder.addDoubleProperty("Value", this::getVoltage, this::setVoltage);
}
}

View File

@@ -7,17 +7,15 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.interfaces.Potentiometer;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class for reading analog potentiometers. Analog potentiometers read in an analog voltage that
* corresponds to a position. The position is in whichever units you choose, by way of the scaling
* and offset constants passed to the constructor.
*/
public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
public class AnalogPotentiometer extends SensorBase implements Potentiometer, Sendable {
private AnalogInput m_analogInput;
private boolean m_initAnalogInput;
private double m_fullRange;
@@ -40,6 +38,7 @@ public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
public AnalogPotentiometer(final int channel, double fullRange, double offset) {
this(new AnalogInput(channel), fullRange, offset);
m_initAnalogInput = true;
addChild(m_analogInput);
}
/**
@@ -56,6 +55,7 @@ public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
* @param offset The offset to add to the scaled value for controlling the zero value
*/
public AnalogPotentiometer(final AnalogInput input, double fullRange, double offset) {
setName("AnalogPotentiometer", input.getChannel());
m_analogInput = input;
m_initAnalogInput = false;
@@ -118,6 +118,9 @@ public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
*/
@Override
public double get() {
if (m_analogInput == null) {
return m_offset;
}
return (m_analogInput.getVoltage() / ControllerPower.getVoltage5V()) * m_fullRange + m_offset;
}
@@ -144,56 +147,23 @@ public class AnalogPotentiometer implements Potentiometer, LiveWindowSendable {
return get();
}
/**
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Analog Input";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(get());
public void initSendable(SendableBuilder builder) {
if (m_analogInput != null) {
m_analogInput.initSendable(builder);
}
}
/**
* Frees this resource.
*/
@Override
public void free() {
super.free();
if (m_initAnalogInput) {
m_analogInput.free();
m_analogInput = null;
m_initAnalogInput = false;
}
}
/**
* Analog Channels don't have to do anything special when entering the LiveWindow. {@inheritDoc}
*/
@Override
public void startLiveWindowMode() {
}
/**
* Analog Channels don't have to do anything special when exiting the LiveWindow. {@inheritDoc}
*/
@Override
public void stopLiveWindowMode() {
}
}

View File

@@ -14,12 +14,13 @@ import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
import edu.wpi.first.wpilibj.hal.AnalogJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.util.BoundaryException;
/**
* Class for creating and configuring Analog Triggers.
*/
public class AnalogTrigger {
public class AnalogTrigger extends SensorBase implements Sendable {
/**
* Exceptions dealing with improper operation of the Analog trigger.
@@ -53,6 +54,7 @@ public class AnalogTrigger {
public AnalogTrigger(final int channel) {
this(new AnalogInput(channel));
m_ownsAnalog = true;
addChild(m_analogInput);
}
/**
@@ -71,12 +73,15 @@ public class AnalogTrigger {
m_index = index.asIntBuffer().get(0);
HAL.report(tResourceType.kResourceType_AnalogTrigger, channel.getChannel());
setName("AnalogTrigger", channel.getChannel());
}
/**
* Release the resources used by this object.
*/
@Override
public void free() {
super.free();
AnalogJNI.cleanAnalogTrigger(m_port);
m_port = 0;
if (m_ownsAnalog && m_analogInput != null) {
@@ -173,4 +178,11 @@ public class AnalogTrigger {
public AnalogTriggerOutput createOutput(AnalogTriggerType type) {
return new AnalogTriggerOutput(this, type);
}
@Override
public void initSendable(SendableBuilder builder) {
if (m_ownsAnalog) {
m_analogInput.initSendable(builder);
}
}
}

View File

@@ -10,6 +10,7 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.AnalogJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import static java.util.Objects.requireNonNull;
@@ -77,15 +78,6 @@ public class AnalogTriggerOutput extends DigitalSource {
trigger.getIndex(), outputType.value);
}
/**
* Frees the resources for this output.
*/
public void free() {
if (m_interrupt != 0) {
cancelInterrupts();
}
}
/**
* Get the state of the analog trigger output.
*
@@ -130,4 +122,8 @@ public class AnalogTriggerOutput extends DigitalSource {
this.value = value;
}
}
@Override
public void initSendable(SendableBuilder builder) {
}
}

View File

@@ -7,21 +7,18 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.AccelerometerJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.interfaces.Accelerometer;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Built-in accelerometer.
*
* <p>This class allows access to the roboRIO's internal accelerometer.
*/
public class BuiltInAccelerometer implements Accelerometer, LiveWindowSendable {
public class BuiltInAccelerometer extends SensorBase implements Accelerometer, Sendable {
/**
* Constructor.
*
@@ -30,7 +27,7 @@ public class BuiltInAccelerometer implements Accelerometer, LiveWindowSendable {
public BuiltInAccelerometer(Range range) {
setRange(range);
HAL.report(tResourceType.kResourceType_Accelerometer, 0, 0, "Built-in accelerometer");
LiveWindow.addSensor("BuiltInAccel", 0, this);
setName("BuiltInAccel", 0);
}
/**
@@ -94,49 +91,10 @@ public class BuiltInAccelerometer implements Accelerometer, LiveWindowSendable {
}
@Override
public String getSmartDashboardType() {
return "3AxisAccelerometer";
}
@SuppressWarnings("MemberName")
private NetworkTableEntry m_xEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_yEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_zEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_xEntry = subtable.getEntry("X");
m_yEntry = subtable.getEntry("Y");
m_zEntry = subtable.getEntry("Z");
updateTable();
} else {
m_xEntry = null;
m_yEntry = null;
m_zEntry = null;
}
}
@Override
public void updateTable() {
if (m_xEntry != null) {
m_xEntry.setDouble(getX());
}
if (m_yEntry != null) {
m_yEntry.setDouble(getY());
}
if (m_zEntry != null) {
m_zEntry.setDouble(getZ());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("3AxisAccelerometer");
builder.addDoubleProperty("X", this::getX, null);
builder.addDoubleProperty("Y", this::getY, null);
builder.addDoubleProperty("Z", this::getZ, null);
}
}

View File

@@ -7,13 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.CompressorJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class for operating a compressor connected to a PCM (Pneumatic Control Module). The PCM will
@@ -26,7 +23,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* the safety provided by using the pressure switch and closed loop control. You can only turn off
* closed loop control, thereby stopping the compressor from operating.
*/
public class Compressor extends SensorBase implements LiveWindowSendable {
public class Compressor extends SendableBase implements Sendable {
private int m_compressorHandle;
private byte m_module;
@@ -42,6 +39,7 @@ public class Compressor extends SensorBase implements LiveWindowSendable {
m_compressorHandle = CompressorJNI.initializeCompressor((byte) module);
HAL.report(tResourceType.kResourceType_Compressor, module);
setName("Compressor", module);
}
/**
@@ -51,7 +49,7 @@ public class Compressor extends SensorBase implements LiveWindowSendable {
* specifying the CAN ID.}
*/
public Compressor() {
this(getDefaultSolenoidModule());
this(SensorBase.getDefaultSolenoidModule());
}
/**
@@ -193,54 +191,15 @@ public class Compressor extends SensorBase implements LiveWindowSendable {
}
@Override
public void startLiveWindowMode() {
if (m_enabledEntry != null) {
m_enabledListener = m_enabledEntry.addListener((event) -> {
if (event.value.getBoolean()) {
start();
} else {
stop();
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
}
@Override
public void stopLiveWindowMode() {
if (m_enabledEntry != null) {
m_enabledEntry.removeListener(m_enabledListener);
m_enabledListener = 0;
}
}
@Override
public String getSmartDashboardType() {
return "Compressor";
}
private NetworkTableEntry m_enabledEntry;
private NetworkTableEntry m_pressureSwitchEntry;
private int m_enabledListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_enabledEntry = subtable.getEntry("Enabled");
m_pressureSwitchEntry = subtable.getEntry("Pressure Switch");
updateTable();
} else {
m_enabledEntry = null;
m_pressureSwitchEntry = null;
}
}
@Override
public void updateTable() {
if (m_enabledEntry != null) {
m_enabledEntry.setBoolean(enabled());
}
if (m_pressureSwitchEntry != null) {
m_pressureSwitchEntry.setBoolean(getPressureSwitchValue());
}
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Compressor");
builder.addBooleanProperty("Enabled", this::enabled, (value) -> {
if (value) {
start();
} else {
stop();
}
});
builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
}
}

View File

@@ -10,13 +10,11 @@ package edu.wpi.first.wpilibj;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
import edu.wpi.first.wpilibj.hal.CounterJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import static java.util.Objects.requireNonNull;
@@ -30,7 +28,7 @@ import static java.util.Objects.requireNonNull;
* <p>All counters will immediately start counting - reset() them if you need them to be zeroed
* before use.
*/
public class Counter extends SensorBase implements CounterBase, LiveWindowSendable, PIDSource {
public class Counter extends SensorBase implements CounterBase, Sendable, PIDSource {
/**
* Mode determines how and what the counter counts.
@@ -88,6 +86,7 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
setMaxPeriod(.5);
HAL.report(tResourceType.kResourceType_Counter, m_index, mode.value);
setName("Counter", m_index);
}
/**
@@ -183,6 +182,7 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
@Override
public void free() {
super.free();
setUpdateWhenEmpty(true);
clearUpSource();
@@ -213,6 +213,7 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
public void setUpSource(int channel) {
setUpSource(new DigitalInput(channel));
m_allocatedUpSource = true;
addChild(m_upSource);
}
/**
@@ -279,6 +280,7 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
public void setDownSource(int channel) {
setDownSource(new DigitalInput(channel));
m_allocatedDownSource = true;
addChild(m_downSource);
}
/**
@@ -553,34 +555,8 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
}
@Override
public String getSmartDashboardType() {
return "Counter";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(get());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Counter");
builder.addDoubleProperty("Value", this::get, null);
}
}

View File

@@ -12,6 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
import edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.hal.HAL;
/**
@@ -35,6 +36,7 @@ public class DigitalGlitchFilter extends SensorBase {
m_filterAllocated[index] = true;
HAL.report(tResourceType.kResourceType_DigitalFilter,
m_channelIndex, 0);
setName("DigitalGlitchFilter", index);
}
}
}
@@ -43,6 +45,7 @@ public class DigitalGlitchFilter extends SensorBase {
* Free the resources used by this object.
*/
public void free() {
super.free();
if (m_channelIndex >= 0) {
synchronized (m_mutex) {
m_filterAllocated[m_channelIndex] = false;
@@ -170,6 +173,10 @@ public class DigitalGlitchFilter extends SensorBase {
/ (long) (kSystemClockTicksPerMicrosecond / 4);
}
@SuppressWarnings("PMD.UnusedFormalParameter")
public void initSendable(SendableBuilder builder) {
}
private int m_channelIndex = -1;
private static final Lock m_mutex = new ReentrantLock(true);
private static final boolean[] m_filterAllocated = new boolean[3];

View File

@@ -7,13 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.DIOJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class to read a digital input. This class will read digital inputs and return the current value
@@ -21,7 +18,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* 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 LiveWindowSendable {
public class DigitalInput extends DigitalSource implements Sendable {
private int m_channel = 0;
private int m_handle = 0;
@@ -36,14 +33,15 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
m_handle = DIOJNI.initializeDIOPort(DIOJNI.getPort((byte) channel), true);
LiveWindow.addSensor("DigitalInput", channel, this);
HAL.report(tResourceType.kResourceType_DigitalInput, channel);
setName("DigitalInput", channel);
}
/**
* Frees the resources for this output.
*/
public void free() {
super.free();
if (m_interrupt != 0) {
cancelInterrupts();
}
@@ -102,37 +100,8 @@ public class DigitalInput extends DigitalSource implements LiveWindowSendable {
}
@Override
public String getSmartDashboardType() {
return "Digital Input";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setBoolean(get());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Digital Input");
builder.addBooleanProperty("Value", this::get, null);
}
}

View File

@@ -7,19 +7,16 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.DIOJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class to write digital outputs. This class will write digital outputs. Other devices that are
* implemented elsewhere will automatically allocate digital inputs and outputs as required.
*/
public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
public class DigitalOutput extends SendableBase implements Sendable {
private static final int invalidPwmGenerator = 0;
private int m_pwmGenerator = invalidPwmGenerator;
@@ -35,12 +32,13 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
* the MXP
*/
public DigitalOutput(int channel) {
checkDigitalChannel(channel);
SensorBase.checkDigitalChannel(channel);
m_channel = channel;
m_handle = DIOJNI.initializeDIOPort(DIOJNI.getPort((byte) channel), false);
HAL.report(tResourceType.kResourceType_DigitalOutput, channel);
setName("DigitalOutput", channel);
}
/**
@@ -48,6 +46,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
*/
@Override
public void free() {
super.free();
// disable the pwm only if we have allocated it
if (m_pwmGenerator != invalidPwmGenerator) {
disablePWM();
@@ -79,7 +78,6 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
*
* @return The GPIO channel number.
*/
@Override
public int getChannel() {
return m_channel;
}
@@ -146,7 +144,7 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
return;
}
// Disable the output by routing to a dead bit.
DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, kDigitalChannels);
DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, SensorBase.kDigitalChannels);
DIOJNI.freeDigitalPWM(m_pwmGenerator);
m_pwmGenerator = invalidPwmGenerator;
}
@@ -167,76 +165,9 @@ public class DigitalOutput extends DigitalSource implements LiveWindowSendable {
DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle);
}
/**
* Get the analog trigger type.
*
* @return false
*/
@Override
public int getAnalogTriggerTypeForRouting() {
return 0;
}
/**
* Is this an analog trigger.
*
* @return true if this is an analog trigger
*/
@Override
public boolean isAnalogTrigger() {
return false;
}
/**
* Get the HAL Port Handle.
*
* @return The HAL Handle to the specified source.
*/
@Override
public int getPortHandleForRouting() {
return m_handle;
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Digital Output";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
// TODO: Put current value.
}
@Override
public void startLiveWindowMode() {
m_valueListener = m_valueEntry.addListener((event) -> set(event.value.getBoolean()),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Digital Output");
builder.addBooleanProperty("Value", this::get, this::set);
}
}

View File

@@ -7,14 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.hal.SolenoidJNI;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* DoubleSolenoid class for running 2 channels of high voltage Digital Output on the PCM.
@@ -22,7 +18,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* <p>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 {
public class DoubleSolenoid extends SolenoidBase implements Sendable {
/**
* Possible values for a DoubleSolenoid.
@@ -45,7 +41,7 @@ public class DoubleSolenoid extends SolenoidBase implements LiveWindowSendable {
* @param reverseChannel The reverse channel number on the PCM (0..7).
*/
public DoubleSolenoid(final int forwardChannel, final int reverseChannel) {
this(getDefaultSolenoidModule(), forwardChannel, reverseChannel);
this(SensorBase.getDefaultSolenoidModule(), forwardChannel, reverseChannel);
}
/**
@@ -59,9 +55,9 @@ public class DoubleSolenoid extends SolenoidBase implements LiveWindowSendable {
final int reverseChannel) {
super(moduleNumber);
checkSolenoidModule(m_moduleNumber);
checkSolenoidChannel(forwardChannel);
checkSolenoidChannel(reverseChannel);
SensorBase.checkSolenoidModule(m_moduleNumber);
SensorBase.checkSolenoidChannel(forwardChannel);
SensorBase.checkSolenoidChannel(reverseChannel);
int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) forwardChannel);
m_forwardHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
@@ -84,13 +80,15 @@ public class DoubleSolenoid extends SolenoidBase implements LiveWindowSendable {
m_moduleNumber);
HAL.report(tResourceType.kResourceType_Solenoid, reverseChannel,
m_moduleNumber);
LiveWindow.addActuator("DoubleSolenoid", m_moduleNumber, forwardChannel, this);
setName("DoubleSolenoid", m_moduleNumber, forwardChannel);
}
/**
* Destructor.
*/
@Override
public synchronized void free() {
super.free();
SolenoidJNI.freeSolenoidPort(m_forwardHandle);
SolenoidJNI.freeSolenoidPort(m_reverseHandle);
super.free();
@@ -169,52 +167,18 @@ public class DoubleSolenoid extends SolenoidBase implements LiveWindowSendable {
return (blackList & m_reverseMask) != 0;
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Double Solenoid";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setString(get().name().substring(1));
}
}
@Override
public void startLiveWindowMode() {
set(Value.kOff); // Stop for safety
m_valueListener = m_valueEntry.addListener((event) -> {
String value = event.value.getString();
if ("Reverse".equals(value)) {
set(Value.kReverse);
} else if ("Forward".equals(value)) {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Double Solenoid");
builder.setSafeState(() -> set(Value.kOff));
builder.addStringProperty("Value", () -> get().name().substring(1), (value) -> {
if ("Forward".equals(value)) {
set(Value.kForward);
} else if ("Reverse".equals(value)) {
set(Value.kReverse);
} else {
set(Value.kOff);
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
set(Value.kOff); // Stop for safety
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
});
}
}

View File

@@ -7,13 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.EncoderJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.util.AllocationException;
import static java.util.Objects.requireNonNull;
@@ -31,7 +28,7 @@ import static java.util.Objects.requireNonNull;
* <p>All encoders will immediately start counting - reset() them if you need them to be zeroed
* before use.
*/
public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveWindowSendable {
public class Encoder extends SensorBase implements CounterBase, PIDSource, Sendable {
public enum IndexingType {
kResetWhileHigh(0), kResetWhileLow(1), kResetOnFallingEdge(2), kResetOnRisingEdge(3);
@@ -81,8 +78,9 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
m_pidSource = PIDSourceType.kDisplacement;
HAL.report(tResourceType.kResourceType_Encoder, getFPGAIndex(), type.value);
LiveWindow.addSensor("Encoder", m_aSource.getChannel(), this);
int fpgaIndex = getFPGAIndex();
HAL.report(tResourceType.kResourceType_Encoder, fpgaIndex, type.value);
setName("Encoder", fpgaIndex);
}
/**
@@ -96,12 +94,7 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
* if necessary so forward represents positive values.
*/
public Encoder(final int channelA, final int channelB, boolean reverseDirection) {
m_allocatedA = true;
m_allocatedB = true;
m_allocatedI = false;
m_aSource = new DigitalInput(channelA);
m_bSource = new DigitalInput(channelB);
initEncoder(reverseDirection, EncodingType.k4X);
this(channelA, channelB, reverseDirection, EncodingType.k4X);
}
/**
@@ -141,6 +134,8 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
m_allocatedI = false;
m_aSource = new DigitalInput(channelA);
m_bSource = new DigitalInput(channelB);
addChild(m_aSource);
addChild(m_bSource);
initEncoder(reverseDirection, encodingType);
}
@@ -158,13 +153,10 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
*/
public Encoder(final int channelA, final int channelB, final int indexChannel,
boolean reverseDirection) {
m_allocatedA = true;
m_allocatedB = true;
this(channelA, channelB, reverseDirection);
m_allocatedI = true;
m_aSource = new DigitalInput(channelA);
m_bSource = new DigitalInput(channelB);
m_indexSource = new DigitalInput(indexChannel);
initEncoder(reverseDirection, EncodingType.k4X);
addChild(m_indexSource);
setIndexSource(m_indexSource);
}
@@ -195,15 +187,7 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
* if necessary so forward represents positive values.
*/
public Encoder(DigitalSource sourceA, DigitalSource sourceB, boolean reverseDirection) {
requireNonNull(sourceA, "Digital Source A was null");
requireNonNull(sourceB, "Digital Source B was null");
m_allocatedA = false;
m_allocatedB = false;
m_allocatedI = false;
m_aSource = sourceA;
m_bSource = sourceB;
initEncoder(reverseDirection, EncodingType.k4X);
this(sourceA, sourceB, reverseDirection, EncodingType.k4X);
}
/**
@@ -267,16 +251,9 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
*/
public Encoder(DigitalSource sourceA, DigitalSource sourceB, DigitalSource indexSource,
boolean reverseDirection) {
requireNonNull(sourceA, "Digital Source A was null");
requireNonNull(sourceB, "Digital Source B was null");
m_allocatedA = false;
m_allocatedB = false;
this(sourceA, sourceB, reverseDirection);
m_allocatedI = false;
m_aSource = sourceA;
m_bSource = sourceB;
m_indexSource = indexSource;
initEncoder(reverseDirection, EncodingType.k4X);
setIndexSource(indexSource);
}
@@ -317,7 +294,9 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
/**
* Free the resources used by this object.
*/
@Override
public void free() {
super.free();
if (m_aSource != null && m_allocatedA) {
m_aSource.free();
m_allocatedA = false;
@@ -456,6 +435,15 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
EncoderJNI.setEncoderDistancePerPulse(m_encoder, distancePerPulse);
}
/**
* Get the distance per pulse for this encoder.
*
* @return The scale factor that will be used to convert pulses to useful units.
*/
public double getDistancePerPulse() {
return EncoderJNI.getEncoderDistancePerPulse(m_encoder);
}
/**
* 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.
@@ -567,52 +555,16 @@ public class Encoder extends SensorBase implements CounterBase, PIDSource, LiveW
source.getAnalogTriggerTypeForRouting(), type.value);
}
/**
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
@Override
public void initSendable(SendableBuilder builder) {
if (EncoderJNI.getEncoderEncodingType(m_encoder) == EncodingType.k4X.value) {
return "Quadrature Encoder";
}
return "Encoder";
}
private NetworkTableEntry m_speedEntry;
private NetworkTableEntry m_distanceEntry;
private NetworkTableEntry m_distancePerTickEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_speedEntry = subtable.getEntry("Speed");
m_distanceEntry = subtable.getEntry("Distance");
m_distancePerTickEntry = subtable.getEntry("Distance per Tick");
updateTable();
builder.setSmartDashboardType("Quadrature Encoder");
} else {
m_speedEntry = null;
m_distanceEntry = null;
m_distancePerTickEntry = null;
builder.setSmartDashboardType("Encoder");
}
}
@Override
public void updateTable() {
if (m_speedEntry != null) {
m_speedEntry.setDouble(getRate());
}
if (m_distanceEntry != null) {
m_distanceEntry.setDouble(getDistance());
}
if (m_distancePerTickEntry != null) {
m_distancePerTickEntry.setDouble(EncoderJNI.getEncoderDistancePerPulse(m_encoder));
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
builder.addDoubleProperty("Speed", this::getRate, null);
builder.addDoubleProperty("Distance", this::getDistance, null);
builder.addDoubleProperty("Distance per Tick", this::getDistancePerPulse, null);
}
}

View File

@@ -9,7 +9,7 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Alias for counter class. Implement the gear tooth sensor supplied by FIRST. Currently there is no
@@ -56,7 +56,7 @@ public class GearTooth extends Counter {
} else {
HAL.report(tResourceType.kResourceType_GearTooth, channel, 0);
}
LiveWindow.addSensor("GearTooth", channel, this);
setName("GearTooth", channel);
}
/**
@@ -70,6 +70,12 @@ public class GearTooth extends Counter {
public GearTooth(DigitalSource source, boolean directionSensitive) {
super(source);
enableDirectionSensing(directionSensitive);
if (directionSensitive) {
HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel(), 0, "D");
} else {
HAL.report(tResourceType.kResourceType_GearTooth, source.getChannel(), 0);
}
setName("GearTooth", source.getChannel());
}
/**
@@ -84,10 +90,9 @@ public class GearTooth extends Counter {
this(source, false);
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Gear Tooth";
@Override
public void initSendable(SendableBuilder builder) {
super.initSendable(builder);
builder.setSmartDashboardType("Gear Tooth");
}
}

View File

@@ -7,15 +7,13 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* GyroBase is the common base class for Gyro implementations such as AnalogGyro.
*/
public abstract class GyroBase extends SensorBase implements Gyro, PIDSource, LiveWindowSendable {
public abstract class GyroBase extends SensorBase implements Gyro, PIDSource, Sendable {
private PIDSourceType m_pidSource = PIDSourceType.kDisplacement;
/**
@@ -52,38 +50,9 @@ public abstract class GyroBase extends SensorBase implements Gyro, PIDSource, Li
}
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Gyro";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getAngle());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Gyro");
builder.addDoubleProperty("Value", this::getAngle, null);
}
}

View File

@@ -22,7 +22,7 @@ import static java.util.Objects.requireNonNull;
* <p>This class is intended to be used by sensor (and other I2C device) drivers. It probably should
* not be used directly.
*/
public class I2C extends SensorBase {
public class I2C {
public enum Port {
kOnboard(0), kMXP(1);
@@ -56,6 +56,7 @@ public class I2C extends SensorBase {
* Destructor.
*/
public void free() {
I2CJNI.i2CClose(m_port);
}
/**

View File

@@ -45,6 +45,17 @@ public abstract class InterruptableSensorBase extends SensorBase {
m_interrupt = 0;
}
/**
* Frees the resources for this output.
*/
@Override
public void free() {
super.free();
if (m_interrupt != 0) {
cancelInterrupts();
}
}
/**
* If this is an analog trigger.
*

View File

@@ -222,5 +222,6 @@ public abstract class IterativeRobotBase extends RobotBase {
testPeriodic();
}
robotPeriodic();
LiveWindow.updateValues();
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* Texas Instruments / Vex Robotics Jaguar Speed Controller as a PWM device.
@@ -39,6 +38,6 @@ public class Jaguar extends PWMSpeedController {
setZeroLatch();
HAL.report(tResourceType.kResourceType_Jaguar, getChannel());
LiveWindow.addActuator("Jaguar", getChannel(), this);
setName("Jaguar", getChannel());
}
}

View File

@@ -1,23 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2017 FIRST. 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 interface for sendable objects that gives the sendable a default name in the Smart
* Dashboard.
*/
public interface NamedSendable extends Sendable {
/**
* The name of the subtable.
*
* @return the name of the subtable of SmartDashboard that the Sendable object will use.
*/
String getName();
}

View File

@@ -7,18 +7,14 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Nidec Brushless Motor.
*/
public class NidecBrushless implements SpeedController, MotorSafety, LiveWindowSendable {
public class NidecBrushless extends SendableBase implements SpeedController, MotorSafety, Sendable {
private final MotorSafetyHelper m_safetyHelper;
private boolean m_isInverted = false;
private DigitalOutput m_dio;
@@ -41,14 +37,26 @@ public class NidecBrushless implements SpeedController, MotorSafety, LiveWindowS
// the dio controls the output (in PWM mode)
m_dio = new DigitalOutput(dioChannel);
addChild(m_dio);
m_dio.setPWMRate(15625);
m_dio.enablePWM(0.5);
// the pwm enables the controller
m_pwm = new PWM(pwmChannel);
addChild(m_pwm);
LiveWindow.addActuator("Nidec Brushless", pwmChannel, this);
HAL.report(tResourceType.kResourceType_NidecBrushless, pwmChannel);
setName("Nidec Brushless", pwmChannel);
}
/**
* Free the resources used by this object.
*/
@Override
public void free() {
super.free();
m_dio.free();
m_pwm.free();
}
/**
@@ -188,45 +196,10 @@ public class NidecBrushless implements SpeedController, MotorSafety, LiveWindowS
return m_pwm.getChannel();
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Nidec Brushless";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(get());
}
}
@Override
public void startLiveWindowMode() {
set(0); // Stop for safety
m_valueListener = m_valueEntry.addListener((event) -> set(event.value.getDouble()),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
set(0); // Stop for safety
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Nidec Brushless");
builder.setSafeState(this::stopMotor);
builder.addDoubleProperty("Value", this::get, this::set);
}
}

View File

@@ -10,11 +10,8 @@ package edu.wpi.first.wpilibj;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.filters.LinearDigitalFilter;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.util.BoundaryException;
import static java.util.Objects.requireNonNull;
@@ -29,7 +26,7 @@ import static java.util.Objects.requireNonNull;
* and derivative calculations. Therefore, the sample rate affects the controller's behavior for a
* given set of PID constants.
*/
public class PIDController implements PIDInterface, LiveWindowSendable, Controller {
public class PIDController extends SendableBase implements PIDInterface, Sendable, Controller {
public static final double kDefaultPeriod = .05;
private static int instances = 0;
@@ -153,6 +150,7 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
@SuppressWarnings("ParameterName")
public PIDController(double Kp, double Ki, double Kd, double Kf, PIDSource source,
PIDOutput output, double period) {
super(false);
requireNonNull(source, "Null PIDSource was given");
requireNonNull(output, "Null PIDOutput was given");
@@ -180,6 +178,7 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
instances++;
HLUsageReporting.reportPIDController(instances);
m_tolerance = new NullTolerance();
setName("PIDController", instances);
}
/**
@@ -232,7 +231,9 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
/**
* Free the PID object.
*/
@Override
public void free() {
super.free();
m_controlLoop.cancel();
m_thisMutex.lock();
try {
@@ -242,7 +243,6 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_thisMutex.unlock();
}
removeListeners();
}
/**
@@ -395,16 +395,6 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_thisMutex.unlock();
}
if (m_pEntry != null) {
m_pEntry.setDouble(p);
}
if (m_iEntry != null) {
m_iEntry.setDouble(i);
}
if (m_dEntry != null) {
m_dEntry.setDouble(d);
}
}
/**
@@ -427,18 +417,65 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_thisMutex.unlock();
}
}
if (m_pEntry != null) {
m_pEntry.setDouble(p);
/**
* Set the Proportional coefficient of the PID controller gain.
*
* @param p Proportional coefficient
*/
@SuppressWarnings("ParameterName")
public void setP(double p) {
m_thisMutex.lock();
try {
m_P = p;
} finally {
m_thisMutex.unlock();
}
if (m_iEntry != null) {
m_iEntry.setDouble(i);
}
/**
* Set the Integral coefficient of the PID controller gain.
*
* @param i Integral coefficient
*/
@SuppressWarnings("ParameterName")
public void setI(double i) {
m_thisMutex.lock();
try {
m_I = i;
} finally {
m_thisMutex.unlock();
}
if (m_dEntry != null) {
m_dEntry.setDouble(d);
}
/**
* Set the Differential coefficient of the PID controller gain.
*
* @param d differential coefficient
*/
@SuppressWarnings("ParameterName")
public void setD(double d) {
m_thisMutex.lock();
try {
m_D = d;
} finally {
m_thisMutex.unlock();
}
if (m_fEntry != null) {
m_fEntry.setDouble(f);
}
/**
* Set the Feed forward coefficient of the PID controller gain.
*
* @param f feed forward coefficient
*/
@SuppressWarnings("ParameterName")
public void setF(double f) {
m_thisMutex.lock();
try {
m_F = f;
} finally {
m_thisMutex.unlock();
}
}
@@ -601,10 +638,6 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_thisMutex.unlock();
}
if (m_setpointEntry != null) {
m_setpointEntry.setDouble(m_setpoint);
}
}
/**
@@ -776,10 +809,6 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_thisMutex.unlock();
}
if (m_enabledEntry != null) {
m_enabledEntry.setBoolean(true);
}
}
/**
@@ -801,9 +830,16 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
} finally {
m_pidWriteMutex.unlock();
}
}
if (m_enabledEntry != null) {
m_enabledEntry.setBoolean(false);
/**
* Set the enabled state of the PIDController.
*/
public void setEnabled(boolean enable) {
if (enable) {
enable();
} else {
disable();
}
}
@@ -824,7 +860,7 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
* Reset the previous error,, the integral term, and disable the controller.
*/
@Override
public synchronized void reset() {
public void reset() {
disable();
m_thisMutex.lock();
@@ -838,130 +874,15 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
}
@Override
public String getSmartDashboardType() {
return "PIDController";
}
@SuppressWarnings("MemberName")
private NetworkTableEntry m_pEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_iEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_dEntry;
@SuppressWarnings("MemberName")
private NetworkTableEntry m_fEntry;
private NetworkTableEntry m_setpointEntry;
private NetworkTableEntry m_enabledEntry;
@SuppressWarnings("MemberName")
private int m_pListener;
@SuppressWarnings("MemberName")
private int m_iListener;
@SuppressWarnings("MemberName")
private int m_dListener;
@SuppressWarnings("MemberName")
private int m_fListener;
private int m_setpointListener;
private int m_enabledListener;
private void removeListeners() {
if (m_pEntry != null) {
m_pEntry.removeListener(m_pListener);
}
if (m_iEntry != null) {
m_iEntry.removeListener(m_iListener);
}
if (m_dEntry != null) {
m_dEntry.removeListener(m_dListener);
}
if (m_fEntry != null) {
m_fEntry.removeListener(m_fListener);
}
if (m_setpointEntry != null) {
m_setpointEntry.removeListener(m_setpointListener);
}
if (m_enabledEntry != null) {
m_enabledEntry.removeListener(m_enabledListener);
}
}
@Override
public void initTable(NetworkTable table) {
removeListeners();
if (table != null) {
m_pEntry = table.getEntry("p");
m_pEntry.setDouble(getP());
m_iEntry = table.getEntry("i");
m_iEntry.setDouble(getI());
m_dEntry = table.getEntry("d");
m_dEntry.setDouble(getD());
m_fEntry = table.getEntry("f");
m_fEntry.setDouble(getF());
m_setpointEntry = table.getEntry("setpoint");
m_setpointEntry.setDouble(getSetpoint());
m_enabledEntry = table.getEntry("enabled");
m_enabledEntry.setBoolean(isEnabled());
m_pListener = m_pEntry.addListener((entry) -> {
m_thisMutex.lock();
try {
m_P = entry.value.getDouble();
} finally {
m_thisMutex.unlock();
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
m_iListener = m_iEntry.addListener((entry) -> {
m_thisMutex.lock();
try {
m_I = entry.value.getDouble();
} finally {
m_thisMutex.unlock();
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
m_dListener = m_dEntry.addListener((entry) -> {
m_thisMutex.lock();
try {
m_D = entry.value.getDouble();
} finally {
m_thisMutex.unlock();
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
m_fListener = m_fEntry.addListener((entry) -> {
m_thisMutex.lock();
try {
m_F = entry.value.getDouble();
} finally {
m_thisMutex.unlock();
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
m_setpointListener = m_setpointEntry.addListener((entry) -> {
double val = entry.value.getDouble();
if (getSetpoint() != val) {
setSetpoint(val);
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
m_enabledListener = m_enabledEntry.addListener((entry) -> {
boolean val = entry.value.getBoolean();
if (isEnabled() != val) {
if (val) {
enable();
} else {
disable();
}
}
}, EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
} else {
m_pEntry = null;
m_iEntry = null;
m_dEntry = null;
m_fEntry = null;
m_setpointEntry = null;
m_enabledEntry = null;
}
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("PIDController");
builder.setSafeState(this::reset);
builder.addDoubleProperty("p", this::getP, this::setP);
builder.addDoubleProperty("i", this::getI, this::setI);
builder.addDoubleProperty("d", this::getD, this::setD);
builder.addDoubleProperty("f", this::getF, this::setF);
builder.addDoubleProperty("setpoint", this::getSetpoint, this::setSetpoint);
builder.addBooleanProperty("enabled", this::isEnabled, this::setEnabled);
}
/**
@@ -986,21 +907,6 @@ public class PIDController implements PIDInterface, LiveWindowSendable, Controll
return error;
}
@Override
public void updateTable() {
}
@Override
public void startLiveWindowMode() {
disable();
}
@Override
public void stopLiveWindowMode() {
}
private static double clamp(double value, double low, double high) {
return Math.max(low, Math.min(value, high));
}

View File

@@ -7,14 +7,11 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.DIOJNI;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.hal.PWMJNI;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class implements the PWM generation in the FPGA.
@@ -28,7 +25,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* center value - 999 to 2 = linear scaling from "center" to "full reverse" - 1 = minimum pulse
* width (currently .5ms) - 0 = disabled (i.e. PWM output is held low)
*/
public class PWM extends SensorBase implements LiveWindowSendable {
public class PWM extends SendableBase implements Sendable {
/**
* Represents the amount to multiply the minimum servo-pulse pwm period by.
*/
@@ -56,7 +53,7 @@ public class PWM extends SensorBase implements LiveWindowSendable {
* @param channel The PWM channel number. 0-9 are on-board, 10-19 are on the MXP port
*/
public PWM(final int channel) {
checkPWMChannel(channel);
SensorBase.checkPWMChannel(channel);
m_channel = channel;
m_handle = PWMJNI.initializePWMPort(DIOJNI.getPort((byte) channel));
@@ -66,6 +63,7 @@ public class PWM extends SensorBase implements LiveWindowSendable {
PWMJNI.setPWMEliminateDeadband(m_handle, false);
HAL.report(tResourceType.kResourceType_PWM, channel);
setName("PWM", channel);
}
/**
@@ -73,7 +71,9 @@ public class PWM extends SensorBase implements LiveWindowSendable {
*
* <p>Free the resource associated with the PWM channel and set the value to 0.
*/
@Override
public void free() {
super.free();
if (m_handle == 0) {
return;
}
@@ -242,45 +242,10 @@ public class PWM extends SensorBase implements LiveWindowSendable {
PWMJNI.latchPWMZero(m_handle);
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Speed Controller";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getSpeed());
}
}
@Override
public void startLiveWindowMode() {
setSpeed(0); // Stop for safety
m_valueListener = m_valueEntry.addListener((event) -> setSpeed(event.value.getDouble()),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
setSpeed(0); // Stop for safety
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Speed Controller");
builder.setSafeState(this::setDisabled);
builder.addDoubleProperty("Value", this::getSpeed, this::setSpeed);
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* Cross the Road Electronics (CTRE) Talon SRX Speed Controller with PWM control.
@@ -41,7 +40,7 @@ public class PWMTalonSRX extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("PWMTalonSRX", getChannel(), this);
HAL.report(tResourceType.kResourceType_PWMTalonSRX, getChannel());
setName("PWMTalonSRX", getChannel());
}
}

View File

@@ -7,16 +7,14 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.PDPJNI;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Class for getting voltage, current, temperature, power and energy from the Power Distribution
* Panel over CAN.
*/
public class PowerDistributionPanel extends SensorBase implements LiveWindowSendable {
public class PowerDistributionPanel extends SensorBase implements Sendable {
private final int m_module;
@@ -29,6 +27,7 @@ public class PowerDistributionPanel extends SensorBase implements LiveWindowSend
m_module = module;
checkPDPModule(module);
PDPJNI.initializePDP(module);
setName("PowerDistributionPanel", module);
}
/**
@@ -111,61 +110,13 @@ public class PowerDistributionPanel extends SensorBase implements LiveWindowSend
}
@Override
public String getSmartDashboardType() {
return "PowerDistributionPanel";
}
/*
* Live Window code, only does anything if live window is activated.
*/
private NetworkTableEntry[] m_chanEntry;
private NetworkTableEntry m_voltageEntry;
private NetworkTableEntry m_totalCurrentEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_chanEntry = new NetworkTableEntry[16];
for (int i = 0; i < m_chanEntry.length; i++) {
m_chanEntry[i] = subtable.getEntry("Chan" + i);
}
m_voltageEntry = subtable.getEntry("Voltage");
m_totalCurrentEntry = subtable.getEntry("TotalCurrent");
updateTable();
} else {
m_chanEntry = null;
m_voltageEntry = null;
m_totalCurrentEntry = null;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("PowerDistributionPanel");
for (int i = 0; i < kPDPChannels; ++i) {
final int chan = i;
builder.addDoubleProperty("Chan" + i, () -> getCurrent(chan), null);
}
builder.addDoubleProperty("Voltage", this::getVoltage, null);
builder.addDoubleProperty("TotalCurrent", this::getTotalCurrent, null);
}
@Override
public void updateTable() {
if (m_chanEntry != null) {
for (int i = 0; i < m_chanEntry.length; i++) {
m_chanEntry[i].setDouble(getCurrent(i));
}
}
if (m_voltageEntry != null) {
m_voltageEntry.setDouble(getVoltage());
}
if (m_totalCurrentEntry != null) {
m_totalCurrentEntry.setDouble(getTotalCurrent());
}
}
/**
* PDP doesn't have to do anything special when entering the LiveWindow. {@inheritDoc}
*/
@Override
public void startLiveWindowMode() {
}
/**
* PDP doesn't have to do anything special when exiting the LiveWindow. {@inheritDoc}
*/
@Override
public void stopLiveWindowMode() {
}
}

View File

@@ -7,14 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.hal.RelayJNI;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import java.util.Arrays;
import java.util.Optional;
@@ -30,7 +26,7 @@ import static java.util.Objects.requireNonNull;
* 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 MotorSafety, LiveWindowSendable {
public class Relay extends SendableBase implements MotorSafety, Sendable {
private MotorSafetyHelper m_safetyHelper;
/**
@@ -120,7 +116,7 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable
m_safetyHelper = new MotorSafetyHelper(this);
m_safetyHelper.setSafetyEnabled(false);
LiveWindow.addActuator("Relay", m_channel, this);
setName("Relay", m_channel);
}
/**
@@ -147,6 +143,11 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable
@Override
public void free() {
super.free();
freeRelay();
}
private void freeRelay() {
try {
RelayJNI.setRelay(m_forwardHandle, false);
} catch (RuntimeException ex) {
@@ -324,49 +325,16 @@ public class Relay extends SensorBase implements MotorSafety, LiveWindowSendable
return;
}
free();
freeRelay();
m_direction = direction;
initRelay();
}
/*
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Relay";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setString(get().getPrettyValue());
}
}
@Override
public void startLiveWindowMode() {
m_valueListener = m_valueEntry.addListener(
(event) -> set(Value.getValueOf(event.value.getString()).orElse(Value.kOff)),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Relay");
builder.setSafeState(() -> set(Value.kOff));
builder.addStringProperty("Value", () -> get().getPrettyValue(),
(value) -> set(Value.getValueOf(value).orElse(Value.kOff)));
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* Mindsensors SD540 Speed Controller.
@@ -35,8 +34,8 @@ public class SD540 extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("SD540", getChannel(), this);
HAL.report(tResourceType.kResourceType_MindsensorsSD540, getChannel());
setName("SD540", getChannel());
}
/**

View File

@@ -16,7 +16,7 @@ import edu.wpi.first.wpilibj.hal.SPIJNI;
/**
* Represents a SPI bus port.
*/
public class SPI extends SensorBase {
public class SPI {
public enum Port {
kOnboardCS0(0), kOnboardCS1(1), kOnboardCS2(2), kOnboardCS3(3), kMXP(4);

View File

@@ -7,7 +7,7 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
@@ -15,17 +15,48 @@ import edu.wpi.first.networktables.NetworkTable;
*/
public interface Sendable {
/**
* Initializes a table for this {@link Sendable} object.
* Gets the name of this {@link Sendable} object.
*
* @param subtable The table to put the values in.
* @return Name
*/
void initTable(NetworkTable subtable);
String getName();
/**
* The string representation of the named data type that will be used by the smart dashboard for
* this {@link Sendable}.
* Sets the name of this {@link Sendable} object.
*
* @return The type of this {@link Sendable}.
* @param name name
*/
String getSmartDashboardType();
void setName(String name);
/**
* Sets both the subsystem name and device name of this {@link Sendable} object.
*
* @param subsystem subsystem name
* @param name device name
*/
default void setName(String subsystem, String name) {
setSubsystem(subsystem);
setName(name);
}
/**
* Gets the subsystem name of this {@link Sendable} object.
*
* @return Subsystem name
*/
String getSubsystem();
/**
* Sets the subsystem name of this {@link Sendable} object.
*
* @param subsystem subsystem name
*/
void setSubsystem(String subsystem);
/**
* Initializes this {@link Sendable} object.
*
* @param builder sendable builder
*/
void initSendable(SendableBuilder builder);
}

View File

@@ -0,0 +1,94 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. 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.livewindow.LiveWindow;
/**
* Base class for all sensors. Stores most recent status information as well as containing utility
* functions for checking channels and error processing.
*/
public abstract class SendableBase implements Sendable {
private String m_name = "";
private String m_subsystem = "Ungrouped";
/**
* Creates an instance of the sensor base.
*/
public SendableBase() {
this(true);
}
/**
* Creates an instance of the sensor base.
*
* @param addLiveWindow if true, add this Sendable to LiveWindow
*/
public SendableBase(boolean addLiveWindow) {
if (addLiveWindow) {
LiveWindow.add(this);
}
}
/**
* Free the resources used by this object.
*/
public void free() {
LiveWindow.remove(this);
}
@Override
public final synchronized String getName() {
return m_name;
}
@Override
public final synchronized void setName(String name) {
m_name = name;
}
/**
* Sets the name of the sensor with a channel number.
*
* @param moduleType A string that defines the module name in the label for the value
* @param channel The channel number the device is plugged into
*/
protected final void setName(String moduleType, int channel) {
setName(moduleType + "[" + channel + "]");
}
/**
* Sets the name of the sensor with a module and channel number.
*
* @param moduleType A string that defines the module name in the label for the value
* @param moduleNumber The number of the particular module type
* @param channel The channel number the device is plugged into (usually PWM)
*/
protected final void setName(String moduleType, int moduleNumber, int channel) {
setName(moduleType + "[" + moduleNumber + "," + channel + "]");
}
@Override
public final synchronized String getSubsystem() {
return m_subsystem;
}
@Override
public final synchronized void setSubsystem(String subsystem) {
m_subsystem = subsystem;
}
/**
* Add a child component.
*
* @param child child component
*/
protected final void addChild(Object child) {
LiveWindow.addChild(this, child);
}
}

View File

@@ -20,7 +20,7 @@ import edu.wpi.first.wpilibj.hal.SolenoidJNI;
* Base class for all sensors. Stores most recent status information as well as containing utility
* functions for checking channels and error processing.
*/
public abstract class SensorBase {
public abstract class SensorBase extends SendableBase {
/**
* Ticks per microsecond.
*/
@@ -65,12 +65,6 @@ public abstract class SensorBase {
private static int m_defaultSolenoidModule = 0;
/**
* Creates an instance of the sensor base and gets an FPGA handle.
*/
public SensorBase() {
}
/**
* Set the default location for the Solenoid module.
*
@@ -86,7 +80,7 @@ public abstract class SensorBase {
*
* @param moduleNumber The solenoid module module number to check.
*/
protected static void checkSolenoidModule(final int moduleNumber) {
public static void checkSolenoidModule(final int moduleNumber) {
if (!SolenoidJNI.checkSolenoidModule(moduleNumber)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested solenoid module is out of range. Minimum: 0, Maximum: ")
@@ -103,7 +97,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkDigitalChannel(final int channel) {
public static void checkDigitalChannel(final int channel) {
if (!DIOJNI.checkDIOChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested DIO channel is out of range. Minimum: 0, Maximum: ")
@@ -120,7 +114,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkRelayChannel(final int channel) {
public static void checkRelayChannel(final int channel) {
if (!RelayJNI.checkRelayChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested relay channel is out of range. Minimum: 0, Maximum: ")
@@ -137,7 +131,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkPWMChannel(final int channel) {
public static void checkPWMChannel(final int channel) {
if (!PWMJNI.checkPWMChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested PWM channel is out of range. Minimum: 0, Maximum: ")
@@ -154,7 +148,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkAnalogInputChannel(final int channel) {
public static void checkAnalogInputChannel(final int channel) {
if (!AnalogJNI.checkAnalogInputChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested analog input channel is out of range. Minimum: 0, Maximum: ")
@@ -171,7 +165,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkAnalogOutputChannel(final int channel) {
public static void checkAnalogOutputChannel(final int channel) {
if (!AnalogJNI.checkAnalogOutputChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested analog output channel is out of range. Minimum: 0, Maximum: ")
@@ -187,7 +181,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkSolenoidChannel(final int channel) {
public static void checkSolenoidChannel(final int channel) {
if (!SolenoidJNI.checkSolenoidChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested solenoid channel is out of range. Minimum: 0, Maximum: ")
@@ -204,7 +198,7 @@ public abstract class SensorBase {
*
* @param channel The channel number to check.
*/
protected static void checkPDPChannel(final int channel) {
public static void checkPDPChannel(final int channel) {
if (!PDPJNI.checkPDPChannel(channel)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested PDP channel is out of range. Minimum: 0, Maximum: ")
@@ -220,7 +214,7 @@ public abstract class SensorBase {
*
* @param module The module number to check.
*/
protected static void checkPDPModule(final int module) {
public static void checkPDPModule(final int module) {
if (!PDPJNI.checkPDPModule(module)) {
StringBuilder buf = new StringBuilder();
buf.append("Requested PDP module is out of range. Minimum: 0, Maximum: ")
@@ -239,10 +233,4 @@ public abstract class SensorBase {
public static int getDefaultSolenoidModule() {
return SensorBase.m_defaultSolenoidModule;
}
/**
* Free the resources used by this object.
*/
public void free() {
}
}

View File

@@ -7,12 +7,9 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Standard hobby style servo.
@@ -42,8 +39,8 @@ public class Servo extends PWM {
setBounds(kDefaultMaxServoPWM, 0, 0, 0, kDefaultMinServoPWM);
setPeriodMultiplier(PeriodMultiplier.k4X);
LiveWindow.addActuator("Servo", getChannel(), this);
HAL.report(tResourceType.kResourceType_Servo, getChannel());
setName("Servo", getChannel());
}
@@ -108,44 +105,9 @@ public class Servo extends PWM {
return kMaxServoAngle - kMinServoAngle;
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Servo";
}
private NetworkTable m_table;
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
m_table = subtable;
if (m_table != null) {
m_valueEntry = m_table.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(get());
}
}
@Override
public void startLiveWindowMode() {
m_valueListener = m_valueEntry.addListener((event) -> set(event.value.getDouble()),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Servo");
builder.addDoubleProperty("Value", this::get, this::set);
}
}

View File

@@ -7,14 +7,10 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.hal.SolenoidJNI;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Solenoid class for running high voltage Digital Output on the PCM.
@@ -22,7 +18,7 @@ import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
* <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any
* device within the current spec of the PCM.
*/
public class Solenoid extends SolenoidBase implements LiveWindowSendable {
public class Solenoid extends SolenoidBase implements Sendable {
private final int m_channel; // The channel to control.
private int m_solenoidHandle;
@@ -33,7 +29,7 @@ public class Solenoid extends SolenoidBase implements LiveWindowSendable {
* @param channel The channel on the PCM to control (0..7).
*/
public Solenoid(final int channel) {
this(getDefaultSolenoidModule(), channel);
this(SensorBase.getDefaultSolenoidModule(), channel);
}
/**
@@ -46,26 +42,24 @@ public class Solenoid extends SolenoidBase implements LiveWindowSendable {
super(moduleNumber);
m_channel = channel;
checkSolenoidModule(m_moduleNumber);
checkSolenoidChannel(m_channel);
SensorBase.checkSolenoidModule(m_moduleNumber);
SensorBase.checkSolenoidChannel(m_channel);
int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
m_solenoidHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
LiveWindow.addActuator("Solenoid", m_moduleNumber, m_channel, this);
HAL.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber);
setName("Solenoid", m_moduleNumber, m_channel);
}
/**
* Destructor.
*/
@Override
public synchronized void free() {
super.free();
SolenoidJNI.freeSolenoidPort(m_solenoidHandle);
m_solenoidHandle = 0;
if (m_valueEntry != null) {
m_valueEntry.removeListener(m_valueListener);
}
super.free();
}
/**
@@ -122,44 +116,10 @@ public class Solenoid extends SolenoidBase implements LiveWindowSendable {
SolenoidJNI.fireOneShot(m_solenoidHandle);
}
/*
* Live Window code, only does anything if live window is activated.
*/
public String getSmartDashboardType() {
return "Solenoid";
}
private NetworkTableEntry m_valueEntry;
private int m_valueListener;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setBoolean(get());
}
}
@Override
public void startLiveWindowMode() {
set(false); // Stop for safety
m_valueListener = m_valueEntry.addListener((event) -> set(event.value.getBoolean()),
EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
@Override
public void stopLiveWindowMode() {
set(false); // Stop for safety
m_valueEntry.removeListener(m_valueListener);
m_valueListener = 0;
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Solenoid");
builder.setSafeState(() -> set(false));
builder.addBooleanProperty("Value", this::get, this::set);
}
}

View File

@@ -13,7 +13,7 @@ import edu.wpi.first.wpilibj.hal.SolenoidJNI;
* SolenoidBase class is the common base class for the {@link Solenoid} and {@link DoubleSolenoid}
* classes.
*/
public abstract class SolenoidBase extends SensorBase {
public abstract class SolenoidBase extends SendableBase {
protected final int m_moduleNumber; // The number of the solenoid module being used.

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* REV Robotics SPARK Speed Controller.
@@ -35,8 +34,8 @@ public class Spark extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("Spark", getChannel(), this);
HAL.report(tResourceType.kResourceType_RevSPARK, getChannel());
setName("Spark", getChannel());
}
/**

View File

@@ -7,13 +7,16 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* Allows multiple {@link SpeedController} objects to be linked together.
*/
public class SpeedControllerGroup implements SpeedController {
public class SpeedControllerGroup extends SendableBase implements SpeedController {
private boolean m_isInverted = false;
private final SpeedController[] m_speedControllers;
private static int instances = 0;
/**
* Create a new SpeedControllerGroup with the provided SpeedControllers.
@@ -24,9 +27,13 @@ public class SpeedControllerGroup implements SpeedController {
SpeedController... speedControllers) {
m_speedControllers = new SpeedController[speedControllers.length + 1];
m_speedControllers[0] = speedController;
addChild(speedController);
for (int i = 0; i < speedControllers.length; i++) {
m_speedControllers[i + 1] = speedControllers[i];
addChild(speedControllers[i]);
}
instances++;
setName("SpeedControllerGroup", instances);
}
@Override
@@ -74,4 +81,11 @@ public class SpeedControllerGroup implements SpeedController {
speedController.pidWrite(output);
}
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Speed Controller");
builder.setSafeState(this::stopMotor);
builder.addDoubleProperty("Value", this::get, this::set);
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* Cross the Road Electronics (CTRE) Talon and Talon SR Speed Controller.
@@ -40,7 +39,7 @@ public class Talon extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("Talon", getChannel(), this);
HAL.report(tResourceType.kResourceType_Talon, getChannel());
setName("Talon", getChannel());
}
}

View File

@@ -7,12 +7,9 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import static java.util.Objects.requireNonNull;
@@ -25,7 +22,7 @@ import static java.util.Objects.requireNonNull;
* 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, LiveWindowSendable {
public class Ultrasonic extends SensorBase implements PIDSource, Sendable {
/**
* The units to return when PIDGet is called.
@@ -107,6 +104,7 @@ public class Ultrasonic extends SensorBase implements PIDSource, LiveWindowSenda
m_firstSensor = this;
m_counter = new Counter(m_echoChannel); // set up counter for this
addChild(m_counter);
// sensor
m_counter.setMaxPeriod(1.0);
m_counter.setSemiPeriodMode(true);
@@ -116,7 +114,7 @@ public class Ultrasonic extends SensorBase implements PIDSource, LiveWindowSenda
m_instances++;
HAL.report(tResourceType.kResourceType_Ultrasonic, m_instances);
LiveWindow.addSensor("Ultrasonic", m_echoChannel.getChannel(), this);
setName("Ultrasonic", m_echoChannel.getChannel());
}
/**
@@ -133,6 +131,8 @@ public class Ultrasonic extends SensorBase implements PIDSource, LiveWindowSenda
public Ultrasonic(final int pingChannel, final int echoChannel, Unit units) {
m_pingChannel = new DigitalOutput(pingChannel);
m_echoChannel = new DigitalInput(echoChannel);
addChild(m_pingChannel);
addChild(m_echoChannel);
m_allocatedChannels = true;
m_units = units;
initialize();
@@ -194,6 +194,7 @@ public class Ultrasonic extends SensorBase implements PIDSource, LiveWindowSenda
*/
@Override
public synchronized void free() {
super.free();
final boolean wasAutomaticMode = m_automaticEnabled;
setAutomaticMode(false);
if (m_allocatedChannels) {
@@ -391,38 +392,9 @@ public class Ultrasonic extends SensorBase implements PIDSource, LiveWindowSenda
m_enabled = enable;
}
/**
* Live Window code, only does anything if live window is activated.
*/
@Override
public String getSmartDashboardType() {
return "Ultrasonic";
}
private NetworkTableEntry m_valueEntry;
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_valueEntry = subtable.getEntry("Value");
updateTable();
} else {
m_valueEntry = null;
}
}
@Override
public void updateTable() {
if (m_valueEntry != null) {
m_valueEntry.setDouble(getRangeInches());
}
}
@Override
public void startLiveWindowMode() {
}
@Override
public void stopLiveWindowMode() {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Ultrasonic");
builder.addDoubleProperty("Value", this::getRangeInches, null);
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* VEX Robotics Victor 888 Speed Controller The Vex Robotics Victor 884 Speed Controller can also
@@ -42,7 +41,7 @@ public class Victor extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("Victor", getChannel(), this);
HAL.report(tResourceType.kResourceType_Victor, getChannel());
setName("Victor", getChannel());
}
}

View File

@@ -9,7 +9,6 @@ package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
/**
* VEX Robotics Victor SP Speed Controller.
@@ -40,7 +39,7 @@ public class VictorSP extends PWMSpeedController {
setSpeed(0.0);
setZeroLatch();
LiveWindow.addActuator("VictorSP", getChannel(), this);
HAL.report(tResourceType.kResourceType_VictorSP, getChannel());
setName("VictorSP", getChannel());
}
}

View File

@@ -7,11 +7,10 @@
package edu.wpi.first.wpilibj.buttons;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* This class provides an easy way to link commands to inputs.
@@ -24,7 +23,9 @@ import edu.wpi.first.wpilibj.command.Scheduler;
* certain sensor input). For this, they only have to write the {@link Trigger#get()} method to get
* the full functionality of the Trigger class.
*/
public abstract class Trigger implements Sendable {
public abstract class Trigger extends SendableBase {
private volatile boolean m_sendablePressed = false;
/**
* Returns whether or not the trigger is active.
@@ -42,8 +43,7 @@ public abstract class Trigger implements Sendable {
*/
@SuppressWarnings("PMD.UselessParentheses")
private boolean grab() {
return get() || (m_pressedEntry != null && m_pressedEntry.getBoolean(false));
return get() || m_sendablePressed;
}
/**
@@ -186,24 +186,14 @@ public abstract class Trigger implements Sendable {
}
}
/**
* These methods continue to return the "Button" SmartDashboard type until we decided to create a
* Trigger widget type for the dashboard.
*/
@Override
public String getSmartDashboardType() {
return "Button";
}
private NetworkTableEntry m_pressedEntry;
@Override
public void initTable(NetworkTable table) {
if (table != null) {
m_pressedEntry = table.getEntry("pressed");
m_pressedEntry.setBoolean(get());
} else {
m_pressedEntry = null;
}
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Button");
builder.setSafeState(() -> {
m_sendablePressed = false;
});
builder.addBooleanProperty("pressed", this::grab, (value) -> {
m_sendablePressed = value;
});
}
}

View File

@@ -9,12 +9,11 @@ package edu.wpi.first.wpilibj.command;
import java.util.Enumeration;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.NamedSendable;
import edu.wpi.first.wpilibj.RobotState;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* The Command class is at the very core of the entire command framework. Every command can be
@@ -41,12 +40,7 @@ import edu.wpi.first.wpilibj.Timer;
* @see CommandGroup
* @see IllegalUseOfCommandException
*/
public abstract class Command implements NamedSendable {
/**
* The name of this command.
*/
private String m_name;
public abstract class Command extends SendableBase implements Sendable {
/**
* The time since this command was initialized.
*/
@@ -101,8 +95,9 @@ public abstract class Command implements NamedSendable {
* 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);
super(false);
String name = getClass().getName();
setName(name.substring(name.lastIndexOf('.') + 1));
}
/**
@@ -112,10 +107,11 @@ public abstract class Command implements NamedSendable {
* @throws IllegalArgumentException if name is null
*/
public Command(String name) {
super(false);
if (name == null) {
throw new IllegalArgumentException("Name must not be null.");
}
m_name = name;
setName(name);
}
/**
@@ -150,16 +146,6 @@ public abstract class Command implements NamedSendable {
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.
*
@@ -222,9 +208,6 @@ public abstract class Command implements NamedSendable {
m_initialized = false;
m_canceled = false;
m_running = false;
if (m_runningEntry != null) {
m_runningEntry.setBoolean(false);
}
}
/**
@@ -387,9 +370,15 @@ public abstract class Command implements NamedSendable {
}
lockChanges();
m_parent = parent;
if (m_isParentedEntry != null) {
m_isParentedEntry.setBoolean(true);
}
}
/**
* Returns whether the command has a parent.
*
* @param True if the command has a parent.
*/
synchronized boolean isParented() {
return m_parent != null;
}
/**
@@ -429,9 +418,6 @@ public abstract class Command implements NamedSendable {
synchronized void startRunning() {
m_running = true;
m_startTime = -1;
if (m_runningEntry != null) {
m_runningEntry.setBoolean(true);
}
}
/**
@@ -550,36 +536,21 @@ public abstract class Command implements NamedSendable {
return getName();
}
public String getSmartDashboardType() {
return "Command";
}
private NetworkTableEntry m_runningEntry;
private NetworkTableEntry m_isParentedEntry;
private int m_runningListener;
@Override
public void initTable(NetworkTable table) {
if (m_runningEntry != null) {
m_runningEntry.removeListener(m_runningListener);
}
if (table != null) {
m_runningEntry = table.getEntry("running");
m_isParentedEntry = table.getEntry(".isParented");
table.getEntry(".name").setString(getName());
m_runningEntry.setBoolean(isRunning());
m_isParentedEntry.setBoolean(m_parent != null);
m_runningListener = m_runningEntry.addListener((event) -> {
if (event.value.getBoolean()) {
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Command");
builder.addStringProperty(".name", this::getName, null);
builder.addBooleanProperty("running", this::isRunning, (value) -> {
if (value) {
if (!isRunning()) {
start();
} else {
}
} else {
if (isRunning()) {
cancel();
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
} else {
m_runningEntry = null;
m_isParentedEntry = null;
}
}
});
builder.addBooleanProperty(".isParented", this::isParented, null);
}
}

View File

@@ -7,12 +7,12 @@
package edu.wpi.first.wpilibj.command;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.wpilibj.PIDController;
import edu.wpi.first.wpilibj.PIDOutput;
import edu.wpi.first.wpilibj.PIDSource;
import edu.wpi.first.wpilibj.PIDSourceType;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* This class defines a {@link Command} which interacts heavily with a PID loop.
@@ -209,12 +209,10 @@ public abstract class PIDCommand extends Command implements Sendable {
*/
protected abstract void usePIDOutput(double output);
public String getSmartDashboardType() {
return "PIDCommand";
}
public void initTable(NetworkTable table) {
m_controller.initTable(table);
super.initTable(table);
@Override
public void initSendable(SendableBuilder builder) {
m_controller.initSendable(builder);
super.initSendable(builder);
builder.setSmartDashboardType("PIDCommand");
}
}

View File

@@ -7,7 +7,6 @@
package edu.wpi.first.wpilibj.command;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.wpilibj.PIDController;
import edu.wpi.first.wpilibj.PIDOutput;
import edu.wpi.first.wpilibj.PIDSource;
@@ -62,6 +61,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
public PIDSubsystem(String name, double p, double i, double d) {
super(name);
m_controller = new PIDController(p, i, d, m_source, m_output);
addChild("PIDController", m_controller);
}
/**
@@ -77,6 +77,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
public PIDSubsystem(String name, double p, double i, double d, double f) {
super(name);
m_controller = new PIDController(p, i, d, f, m_source, m_output);
addChild("PIDController", m_controller);
}
/**
@@ -93,6 +94,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
public PIDSubsystem(String name, double p, double i, double d, double f, double period) {
super(name);
m_controller = new PIDController(p, i, d, f, m_source, m_output, period);
addChild("PIDController", m_controller);
}
/**
@@ -106,6 +108,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
@SuppressWarnings("ParameterName")
public PIDSubsystem(double p, double i, double d) {
m_controller = new PIDController(p, i, d, m_source, m_output);
addChild("PIDController", m_controller);
}
/**
@@ -122,6 +125,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
@SuppressWarnings("ParameterName")
public PIDSubsystem(double p, double i, double d, double period, double f) {
m_controller = new PIDController(p, i, d, f, m_source, m_output, period);
addChild("PIDController", m_controller);
}
/**
@@ -137,6 +141,7 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
@SuppressWarnings("ParameterName")
public PIDSubsystem(double p, double i, double d, double period) {
m_controller = new PIDController(p, i, d, m_source, m_output, period);
addChild("PIDController", m_controller);
}
/**
@@ -277,15 +282,4 @@ public abstract class PIDSubsystem extends Subsystem implements Sendable {
public void disable() {
m_controller.disable();
}
@Override
public String getSmartDashboardType() {
return "PIDSubsystem";
}
@Override
public void initTable(NetworkTable table) {
m_controller.initTable(table);
super.initTable(table);
}
}

View File

@@ -11,11 +11,12 @@ import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.HLUsageReporting;
import edu.wpi.first.wpilibj.NamedSendable;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* The {@link Scheduler} is a singleton which holds the top-level running commands. It is in charge
@@ -29,7 +30,7 @@ import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
*
* @see Command
*/
public class Scheduler implements NamedSendable {
public class Scheduler extends SendableBase implements Sendable {
/**
* The Singleton Instance.
@@ -91,6 +92,7 @@ public class Scheduler implements NamedSendable {
*/
private Scheduler() {
HLUsageReporting.reportScheduler();
setName("Scheduler");
}
/**
@@ -237,8 +239,6 @@ public class Scheduler implements NamedSendable {
}
lock.confirmCommand();
}
updateTable();
}
/**
@@ -307,67 +307,44 @@ public class Scheduler implements NamedSendable {
}
@Override
public String getName() {
return "Scheduler";
}
public String getType() {
return "Scheduler";
}
@Override
public void initTable(NetworkTable subtable) {
if (subtable != null) {
m_namesEntry = subtable.getEntry("Names");
m_idsEntry = subtable.getEntry("Ids");
m_cancelEntry = subtable.getEntry("Cancel");
m_namesEntry.setStringArray(new String[0]);
m_idsEntry.setDoubleArray(new double[0]);
m_cancelEntry.setDoubleArray(new double[0]);
} else {
m_namesEntry = null;
m_idsEntry = null;
m_cancelEntry = null;
}
}
private void updateTable() {
if (m_namesEntry != null && m_idsEntry != null && m_cancelEntry != null) {
// Get the commands to cancel
double[] toCancel = m_cancelEntry.getDoubleArray(new double[0]);
if (toCancel.length > 0) {
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
for (double d : toCancel) {
if (e.getData().hashCode() == d) {
e.getData().cancel();
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Scheduler");
m_namesEntry = builder.getEntry("Names");
m_idsEntry = builder.getEntry("Ids");
m_cancelEntry = builder.getEntry("Cancel");
builder.setUpdateTable(() -> {
if (m_namesEntry != null && m_idsEntry != null && m_cancelEntry != null) {
// Get the commands to cancel
double[] toCancel = m_cancelEntry.getDoubleArray(new double[0]);
if (toCancel.length > 0) {
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
for (double d : toCancel) {
if (e.getData().hashCode() == d) {
e.getData().cancel();
}
}
}
m_cancelEntry.setDoubleArray(new double[0]);
}
m_cancelEntry.setDoubleArray(new double[0]);
}
if (m_runningCommandsChanged) {
// Set the the running commands
int number = 0;
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
number++;
if (m_runningCommandsChanged) {
// Set the the running commands
int number = 0;
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
number++;
}
String[] commands = new String[number];
double[] ids = new double[number];
number = 0;
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
commands[number] = e.getData().getName();
ids[number] = e.getData().hashCode();
number++;
}
m_namesEntry.setStringArray(commands);
m_idsEntry.setDoubleArray(ids);
}
String[] commands = new String[number];
double[] ids = new double[number];
number = 0;
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
commands[number] = e.getData().getName();
ids[number] = e.getData().hashCode();
number++;
}
m_namesEntry.setStringArray(commands);
m_idsEntry.setDoubleArray(ids);
}
}
}
@Override
public String getSmartDashboardType() {
return "Scheduler";
});
}
}

View File

@@ -9,9 +9,10 @@ package edu.wpi.first.wpilibj.command;
import java.util.Enumeration;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.NamedSendable;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* This class defines a major component of the robot.
@@ -27,7 +28,7 @@ import edu.wpi.first.wpilibj.NamedSendable;
*
* @see Command
*/
public abstract class Subsystem implements NamedSendable {
public abstract class Subsystem extends SendableBase implements Sendable {
/**
* Whether or not getDefaultCommand() was called.
@@ -43,10 +44,6 @@ public abstract class Subsystem implements NamedSendable {
* The default command.
*/
private Command m_defaultCommand;
/**
* The name.
*/
private String m_name;
/**
* Creates a subsystem with the given name.
@@ -54,7 +51,7 @@ public abstract class Subsystem implements NamedSendable {
* @param name the name of the subsystem
*/
public Subsystem(String name) {
m_name = name;
setName(name, name);
Scheduler.getInstance().registerSubsystem(this);
}
@@ -62,7 +59,9 @@ public abstract class Subsystem implements NamedSendable {
* Creates a subsystem. This will set the name to the name of the class.
*/
public Subsystem() {
m_name = getClass().getName().substring(getClass().getName().lastIndexOf('.') + 1);
String name = getClass().getName();
name = name.substring(name.lastIndexOf('.') + 1);
setName(name, name);
Scheduler.getInstance().registerSubsystem(this);
m_currentCommandChanged = true;
}
@@ -110,14 +109,6 @@ public abstract class Subsystem implements NamedSendable {
}
m_defaultCommand = command;
}
if (m_hasDefaultEntry != null && m_defaultEntry != null) {
if (m_defaultCommand != null) {
m_hasDefaultEntry.setBoolean(true);
m_defaultEntry.setString(m_defaultCommand.getName());
} else {
m_hasDefaultEntry.setBoolean(false);
}
}
}
/**
@@ -125,7 +116,7 @@ public abstract class Subsystem implements NamedSendable {
*
* @return the default command
*/
protected Command getDefaultCommand() {
public Command getDefaultCommand() {
if (!m_initializedDefaultCommand) {
m_initializedDefaultCommand = true;
initDefaultCommand();
@@ -133,6 +124,20 @@ public abstract class Subsystem implements NamedSendable {
return m_defaultCommand;
}
/**
* Returns the default command name, or empty string is there is none.
*
* @return the default command name
*/
public String getDefaultCommandName() {
Command defaultCommand = getDefaultCommand();
if (defaultCommand != null) {
return defaultCommand.getName();
} else {
return "";
}
}
/**
* Sets the current command.
*
@@ -150,14 +155,6 @@ public abstract class Subsystem implements NamedSendable {
*/
void confirmCommand() {
if (m_currentCommandChanged) {
if (m_hasCommandEntry != null && m_commandEntry != null) {
if (m_currentCommand != null) {
m_hasCommandEntry.setBoolean(true);
m_commandEntry.setString(m_currentCommand.getName());
} else {
m_hasCommandEntry.setBoolean(false);
}
}
m_currentCommandChanged = false;
}
}
@@ -171,51 +168,54 @@ public abstract class Subsystem implements NamedSendable {
return m_currentCommand;
}
@Override
public String toString() {
return getName();
/**
* Returns the current command name, or empty string if no current command.
*
* @return the current command name
*/
public String getCurrentCommandName() {
Command currentCommand = getCurrentCommand();
if (currentCommand != null) {
return currentCommand.getName();
} else {
return "";
}
}
/**
* Returns the name of this subsystem, which is by default the class name.
* Associate a {@link Sendable} with this Subsystem.
* Also update the child's name.
*
* @return the name of this subsystem
* @param name name to give child
* @param child sendable
*/
@Override
public String getName() {
return m_name;
public void addChild(String name, Sendable child) {
child.setName(getSubsystem(), name);
LiveWindow.add(child);
}
/**
* Associate a {@link Sendable} with this Subsystem.
*
* @param child sendable
*/
public void addChild(Sendable child) {
child.setSubsystem(getSubsystem());
LiveWindow.add(child);
}
@Override
public String getSmartDashboardType() {
return "Subsystem";
public String toString() {
return getSubsystem();
}
private NetworkTableEntry m_hasDefaultEntry;
private NetworkTableEntry m_defaultEntry;
private NetworkTableEntry m_hasCommandEntry;
private NetworkTableEntry m_commandEntry;
@Override
public void initTable(NetworkTable table) {
if (table != null) {
m_hasDefaultEntry = table.getEntry("hasDefault");
m_defaultEntry = table.getEntry("default");
m_hasCommandEntry = table.getEntry("hasCommand");
m_commandEntry = table.getEntry("command");
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Subsystem");
if (m_defaultCommand != null) {
m_hasDefaultEntry.setBoolean(true);
m_defaultEntry.setString(m_defaultCommand.getName());
} else {
m_hasDefaultEntry.setBoolean(false);
}
if (m_currentCommand != null) {
m_hasCommandEntry.setBoolean(true);
m_commandEntry.setString(m_currentCommand.getName());
} else {
m_hasCommandEntry.setBoolean(false);
}
}
builder.addBooleanProperty("hasDefault", () -> m_defaultCommand != null, null);
builder.addStringProperty("default", this::getDefaultCommandName, null);
builder.addBooleanProperty("hasCommand", () -> m_currentCommand != null, null);
builder.addStringProperty("command", this::getCurrentCommandName, null);
}
}

View File

@@ -11,6 +11,7 @@ import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* A class for driving differential drive/skid-steer drive platforms such as the Kit of Parts drive
@@ -93,6 +94,8 @@ public class DifferentialDrive extends RobotDriveBase {
public static final double kDefaultQuickStopThreshold = 0.2;
public static final double kDefaultQuickStopAlpha = 0.1;
private static int instances = 0;
private SpeedController m_leftMotor;
private SpeedController m_rightMotor;
@@ -110,6 +113,10 @@ public class DifferentialDrive extends RobotDriveBase {
public DifferentialDrive(SpeedController leftMotor, SpeedController rightMotor) {
m_leftMotor = leftMotor;
m_rightMotor = rightMotor;
addChild(m_leftMotor);
addChild(m_rightMotor);
instances++;
setName("DifferentialDrive", instances);
}
/**
@@ -349,4 +356,11 @@ public class DifferentialDrive extends RobotDriveBase {
public String getDescription() {
return "DifferentialDrive";
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("DifferentialDrive");
builder.addDoubleProperty("Left Motor Speed", m_leftMotor::get, m_leftMotor::set);
builder.addDoubleProperty("Right Motor Speed", m_rightMotor::get, m_rightMotor::set);
}
}

View File

@@ -8,6 +8,7 @@
package edu.wpi.first.wpilibj.drive;
import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
// import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
// import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
// import edu.wpi.first.wpilibj.hal.HAL;
@@ -41,6 +42,8 @@ public class KilloughDrive extends RobotDriveBase {
public static final double kDefaultRightMotorAngle = 120.0;
public static final double kDefaultBackMotorAngle = 270.0;
private static int instances = 0;
private SpeedController m_leftMotor;
private SpeedController m_rightMotor;
private SpeedController m_backMotor;
@@ -93,6 +96,11 @@ public class KilloughDrive extends RobotDriveBase {
Math.sin(rightMotorAngle * (Math.PI / 180.0)));
m_backVec = new Vector2d(Math.cos(backMotorAngle * (Math.PI / 180.0)),
Math.sin(backMotorAngle * (Math.PI / 180.0)));
addChild(m_leftMotor);
addChild(m_rightMotor);
addChild(m_backMotor);
instances++;
setName("KilloughDrive", instances);
}
/**
@@ -192,4 +200,12 @@ public class KilloughDrive extends RobotDriveBase {
public String getDescription() {
return "KilloughDrive";
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("KilloughDrive");
builder.addDoubleProperty("Left Motor Speed", m_leftMotor::get, m_leftMotor::set);
builder.addDoubleProperty("Right Motor Speed", m_rightMotor::get, m_rightMotor::set);
builder.addDoubleProperty("Back Motor Speed", m_backMotor::get, m_backMotor::set);
}
}

View File

@@ -11,6 +11,7 @@ import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
* A class for driving Mecanum drive platforms.
@@ -56,6 +57,8 @@ import edu.wpi.first.wpilibj.hal.HAL;
* deadband of 0 is used.
*/
public class MecanumDrive extends RobotDriveBase {
private static int instances = 0;
private SpeedController m_frontLeftMotor;
private SpeedController m_rearLeftMotor;
private SpeedController m_frontRightMotor;
@@ -74,6 +77,12 @@ public class MecanumDrive extends RobotDriveBase {
m_rearLeftMotor = rearLeftMotor;
m_frontRightMotor = frontRightMotor;
m_rearRightMotor = rearRightMotor;
addChild(m_frontLeftMotor);
addChild(m_rearLeftMotor);
addChild(m_frontRightMotor);
addChild(m_rearRightMotor);
instances++;
setName("MecanumDrive", instances);
}
/**
@@ -174,4 +183,17 @@ public class MecanumDrive extends RobotDriveBase {
public String getDescription() {
return "MecanumDrive";
}
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("MecanumDrive");
builder.addDoubleProperty("Front Left Motor Speed", m_frontLeftMotor::get,
m_frontLeftMotor::set);
builder.addDoubleProperty("Front Right Motor Speed", m_frontRightMotor::get,
m_frontRightMotor::set);
builder.addDoubleProperty("Rear Left Motor Speed", m_rearLeftMotor::get,
m_rearLeftMotor::set);
builder.addDoubleProperty("Rear Right Motor Speed", m_rearRightMotor::get,
m_rearRightMotor::set);
}
}

View File

@@ -9,11 +9,12 @@ package edu.wpi.first.wpilibj.drive;
import edu.wpi.first.wpilibj.MotorSafety;
import edu.wpi.first.wpilibj.MotorSafetyHelper;
import edu.wpi.first.wpilibj.SendableBase;
/**
* Common base class for drive platforms.
*/
public abstract class RobotDriveBase implements MotorSafety {
public abstract class RobotDriveBase extends SendableBase implements MotorSafety {
public static final double kDefaultDeadband = 0.02;
public static final double kDefaultMaxOutput = 1.0;
@@ -38,6 +39,7 @@ public abstract class RobotDriveBase implements MotorSafety {
public RobotDriveBase() {
m_safetyHelper.setSafetyEnabled(true);
setName("RobotDriveBase");
}
/**

View File

@@ -7,14 +7,15 @@
package edu.wpi.first.wpilibj.livewindow;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.HashMap;
import java.util.Map;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.command.Scheduler;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilderImpl;
import edu.wpi.first.wpilibj.Sendable;
/**
@@ -23,42 +24,30 @@ import edu.wpi.first.wpilibj.command.Scheduler;
*/
public class LiveWindow {
private static Vector<LiveWindowSendable> sensors = new Vector<>();
// private static Vector actuators = new Vector();
private static Hashtable<LiveWindowSendable, LiveWindowComponent> components = new Hashtable<>();
private static NetworkTable livewindowTable;
private static NetworkTable statusTable;
private static NetworkTableEntry enabledEntry;
private static boolean liveWindowEnabled = false;
private static boolean firstTime = true;
/**
* Initialize all the LiveWindow elements the first time we enter LiveWindow mode. By holding off
* creating the NetworkTable entries, it allows them to be redefined before the first time in
* LiveWindow mode. This allows default sensor and actuator values to be created that are replaced
* with the custom names from users calling addActuator and addSensor.
*/
private static void initializeLiveWindowComponents() {
System.out.println("Initializing the components first time");
livewindowTable = NetworkTableInstance.getDefault().getTable("LiveWindow");
statusTable = livewindowTable.getSubTable(".status");
enabledEntry = statusTable.getEntry("LW Enabled");
for (Enumeration e = components.keys(); e.hasMoreElements(); ) {
LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
LiveWindowComponent liveWindowComponent = components.get(component);
String subsystem = liveWindowComponent.getSubsystem();
String name = liveWindowComponent.getName();
System.out.println("Initializing table for '" + subsystem + "' '" + name + "'");
livewindowTable.getSubTable(subsystem).getEntry(".type").setString("LW Subsystem");
NetworkTable table = livewindowTable.getSubTable(subsystem).getSubTable(name);
table.getEntry(".type").setString(component.getSmartDashboardType());
table.getEntry(".name").setString(name);
table.getEntry(".subsystem").setString(subsystem);
component.initTable(table);
if (liveWindowComponent.isSensor()) {
sensors.addElement(component);
}
private static class Component {
Component(Sendable sendable, Sendable parent) {
m_sendable = sendable;
m_parent = parent;
}
final Sendable m_sendable;
Sendable m_parent;
final SendableBuilderImpl m_builder = new SendableBuilderImpl();
boolean m_firstTime = true;
boolean m_telemetryEnabled = true;
}
private static final Map<Object, Component> components = new HashMap<>();
private static final NetworkTable liveWindowTable =
NetworkTableInstance.getDefault().getTable("LiveWindow");
private static final NetworkTable statusTable = liveWindowTable.getSubTable(".status");
private static final NetworkTableEntry enabledEntry = statusTable.getEntry("LW Enabled");
private static boolean startLiveWindow = false;
private static boolean liveWindowEnabled = false;
private static boolean telemetryEnabled = true;
public static synchronized boolean isEnabled() {
return liveWindowEnabled;
}
/**
@@ -69,28 +58,21 @@ public class LiveWindow {
* themselves when they get rescheduled. This prevents arms from starting to move around, etc.
* after a period of adjusting them in LiveWindow mode.
*/
public static void setEnabled(boolean enabled) {
public static synchronized void setEnabled(boolean enabled) {
if (liveWindowEnabled != enabled) {
Scheduler scheduler = Scheduler.getInstance();
if (enabled) {
System.out.println("Starting live window mode.");
if (firstTime) {
initializeLiveWindowComponents();
firstTime = false;
}
Scheduler.getInstance().disable();
Scheduler.getInstance().removeAll();
for (Enumeration e = components.keys(); e.hasMoreElements(); ) {
LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
component.startLiveWindowMode();
}
scheduler.disable();
scheduler.removeAll();
} else {
System.out.println("stopping live window mode.");
for (Enumeration e = components.keys(); e.hasMoreElements(); ) {
LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
component.stopLiveWindowMode();
for (Component component : components.values()) {
component.m_builder.stopLiveWindowMode();
}
Scheduler.getInstance().enable();
scheduler.enable();
}
startLiveWindow = enabled;
liveWindowEnabled = enabled;
enabledEntry.setBoolean(enabled);
}
@@ -98,7 +80,9 @@ public class LiveWindow {
/**
* The run method is called repeatedly to keep the values refreshed on the screen in test mode.
* @deprecated No longer required
*/
@Deprecated
public static void run() {
updateValues();
}
@@ -109,9 +93,12 @@ public class LiveWindow {
* @param subsystem The subsystem this component is part of.
* @param name The name of this component.
* @param component A LiveWindowSendable component that represents a sensor.
* @deprecated Use {@link Sendable#setName(String, String)} instead.
*/
public static void addSensor(String subsystem, String name, LiveWindowSendable component) {
components.put(component, new LiveWindowComponent(subsystem, name, true));
@Deprecated
public static synchronized void addSensor(String subsystem, String name, Sendable component) {
add(component);
component.setName(subsystem, name);
}
/**
@@ -121,13 +108,12 @@ public class LiveWindow {
* @param moduleType A string indicating the type of the module used in the naming (above)
* @param channel The channel number the device is connected to
* @param component A reference to the object being added
* @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int)} instead.
*/
public static void addSensor(String moduleType, int channel, LiveWindowSendable component) {
addSensor("Ungrouped", moduleType + "[" + channel + "]", component);
if (sensors.contains(component)) {
sensors.removeElement(component);
}
sensors.addElement(component);
@Deprecated
public static void addSensor(String moduleType, int channel, Sendable component) {
add(component);
component.setName("Ungrouped", moduleType + "[" + channel + "]");
}
/**
@@ -136,9 +122,12 @@ public class LiveWindow {
* @param subsystem The subsystem this component is part of.
* @param name The name of this component.
* @param component A LiveWindowSendable component that represents a actuator.
* @deprecated Use {@link Sendable#setName(String, String)} instead.
*/
public static void addActuator(String subsystem, String name, LiveWindowSendable component) {
components.put(component, new LiveWindowComponent(subsystem, name, false));
@Deprecated
public static synchronized void addActuator(String subsystem, String name, Sendable component) {
add(component);
component.setName(subsystem, name);
}
/**
@@ -148,9 +137,12 @@ public class LiveWindow {
* @param moduleType A string that defines the module name in the label for the value
* @param channel The channel number the device is plugged into (usually PWM)
* @param component The reference to the object being added
* @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int)} instead.
*/
public static void addActuator(String moduleType, int channel, LiveWindowSendable component) {
addActuator("Ungrouped", moduleType + "[" + channel + "]", component);
@Deprecated
public static void addActuator(String moduleType, int channel, Sendable component) {
add(component);
component.setName("Ungrouped", moduleType + "[" + channel + "]");
}
/**
@@ -161,22 +153,137 @@ public class LiveWindow {
* @param moduleNumber The number of the particular module type
* @param channel The channel number the device is plugged into (usually PWM)
* @param component The reference to the object being added
* @deprecated Use {@link edu.wpi.first.wpilibj.SensorBase#setName(String, int, int)} instead.
*/
@Deprecated
public static void addActuator(String moduleType, int moduleNumber, int channel,
LiveWindowSendable component) {
addActuator("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]", component);
Sendable component) {
add(component);
component.setName("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]");
}
/**
* Puts all sensor values on the live window.
* Add a component to the LiveWindow.
*
* @param sendable component to add
*/
private static void updateValues() {
// TODO: gross - needs to be sped up
for (int i = 0; i < sensors.size(); i++) {
LiveWindowSendable lws = sensors.elementAt(i);
lws.updateTable();
public static synchronized void add(Sendable sendable) {
components.putIfAbsent(sendable, new Component(sendable, null));
}
/**
* Add a child component to a component.
*
* @param parent parent component
* @param child child component
*/
public static synchronized void addChild(Sendable parent, Object child) {
Component component = components.get(child);
if (component == null) {
component = new Component(null, parent);
components.put(child, component);
} else {
component.m_parent = parent;
}
// TODO: Add actuators?
// TODO: Add better rate limiting.
component.m_telemetryEnabled = false;
}
/**
* Remove a component from the LiveWindow.
*
* @param sendable component to remove
*/
public static synchronized void remove(Sendable sendable) {
Component component = components.remove(sendable);
if (component != null && isEnabled()) {
component.m_builder.stopLiveWindowMode();
}
}
/**
* Enable telemetry for a single component.
*
* @param sendable component
*/
public static synchronized void enableTelemetry(Sendable sendable) {
// Re-enable global setting in case disableAllTelemetry() was called.
telemetryEnabled = true;
Component component = components.get(sendable);
if (component != null) {
component.m_telemetryEnabled = true;
}
}
/**
* Disable telemetry for a single component.
*
* @param sendable component
*/
public static synchronized void disableTelemetry(Sendable sendable) {
Component component = components.get(sendable);
if (component != null) {
component.m_telemetryEnabled = false;
}
}
/**
* Disable ALL telemetry.
*/
public static synchronized void disableAllTelemetry() {
telemetryEnabled = false;
for (Component component : components.values()) {
component.m_telemetryEnabled = false;
}
}
/**
* Tell all the sensors to update (send) their values.
*
* <p>Actuators are handled through callbacks on their value changing from the
* SmartDashboard widgets.
*/
public static synchronized void updateValues() {
// Only do this if either LiveWindow mode or telemetry is enabled.
if (!liveWindowEnabled && !telemetryEnabled) {
return;
}
for (Component component : components.values()) {
if (component.m_sendable != null && component.m_parent == null
&& (liveWindowEnabled || component.m_telemetryEnabled)) {
if (component.m_firstTime) {
// By holding off creating the NetworkTable entries, it allows the
// components to be redefined. This allows default sensor and actuator
// values to be created that are replaced with the custom names from
// users calling setName.
String name = component.m_sendable.getName();
if (name.isEmpty()) {
continue;
}
String subsystem = component.m_sendable.getSubsystem();
NetworkTable ssTable = liveWindowTable.getSubTable(subsystem);
NetworkTable table;
// Treat name==subsystem as top level of subsystem
if (name.equals(subsystem)) {
table = ssTable;
} else {
table = ssTable.getSubTable(name);
}
table.getEntry(".name").setString(name);
component.m_builder.setTable(table);
component.m_sendable.initSendable(component.m_builder);
ssTable.getEntry(".type").setString("LW Subsystem");
component.m_firstTime = false;
}
if (startLiveWindow) {
component.m_builder.startLiveWindowMode();
}
component.m_builder.updateTable();
}
}
startLiveWindow = false;
}
}

View File

@@ -1,41 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2017 FIRST. 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.livewindow;
/**
* A LiveWindow component is a device (sensor or actuator) that should be added to the
* SmartDashboard in test mode. The components are cached until the first time the robot enters Test
* mode. This allows the components to be inserted, then renamed.
*/
/*
* This class is intentionally package private.
*/
class LiveWindowComponent {
String m_subsystem;
String m_name;
boolean m_isSensor;
LiveWindowComponent(String subsystem, String name, boolean isSensor) {
m_subsystem = subsystem;
m_name = name;
m_isSensor = isSensor;
}
public String getName() {
return m_name;
}
public String getSubsystem() {
return m_subsystem;
}
public boolean isSensor() {
return m_isSensor;
}
}

View File

@@ -1,31 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2017 FIRST. 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.livewindow;
import edu.wpi.first.wpilibj.Sendable;
/**
* Live Window Sendable is a special type of object sendable to the live window.
*/
public interface LiveWindowSendable extends Sendable {
/**
* Update the table for this sendable object with the latest values.
*/
void updateTable();
/**
* Start having this sendable object automatically respond to value changes reflect the value on
* the table.
*/
void startLiveWindowMode();
/**
* Stop having this sendable object automatically respond to value changes.
*/
void stopLiveWindowMode();
}

View File

@@ -0,0 +1,143 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. 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.smartdashboard;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableValue;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
public interface SendableBuilder {
/**
* Set the string representation of the named data type that will be used
* by the smart dashboard for this sendable.
*
* @param type data type
*/
void setSmartDashboardType(String type);
/**
* Set the function that should be called to set the Sendable into a safe
* state. This is called when entering and exiting Live Window mode.
*
* @param func function
*/
void setSafeState(Runnable func);
/**
* Set the function that should be called to update the network table
* for things other than properties. Note this function is not passed
* the network table object; instead it should use the entry handles
* returned by getEntry().
*
* @param func function
*/
void setUpdateTable(Runnable func);
/**
* Add a property without getters or setters. This can be used to get
* entry handles for the function called by setUpdateTable().
*
* @param key property name
* @return Network table entry
*/
NetworkTableEntry getEntry(String key);
/**
* Represents an operation that accepts a single boolean-valued argument and
* returns no result. This is the primitive type specialization of Consumer
* for boolean. Unlike most other functional interfaces, BooleanConsumer is
* expected to operate via side-effects.
*
* <p>This is a functional interface whose functional method is accept(boolean).
*/
@FunctionalInterface
interface BooleanConsumer {
/**
* Performs the operation on the given value.
* @param value the value
*/
void accept(boolean value);
}
/**
* Add a boolean property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter);
/**
* Add a double property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter);
/**
* Add a string property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter);
/**
* Add a boolean array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addBooleanArrayProperty(String key, Supplier<boolean[]> getter, Consumer<boolean[]> setter);
/**
* Add a double array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addDoubleArrayProperty(String key, Supplier<double[]> getter, Consumer<double[]> setter);
/**
* Add a string array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addStringArrayProperty(String key, Supplier<String[]> getter, Consumer<String[]> setter);
/**
* Add a raw property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addRawProperty(String key, Supplier<byte[]> getter, Consumer<byte[]> setter);
/**
* Add a NetworkTableValue property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
void addValueProperty(String key, Supplier<NetworkTableValue> getter,
Consumer<NetworkTableValue> setter);
}

View File

@@ -0,0 +1,346 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017 FIRST. 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.smartdashboard;
import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableValue;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.DoubleSupplier;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.ArrayList;
import java.util.List;
public class SendableBuilderImpl implements SendableBuilder {
private static class Property {
Property(NetworkTable table, String key) {
m_entry = table.getEntry(key);
}
@Override
@SuppressWarnings("NoFinalizer")
public synchronized void finalize() {
stopListener();
}
void startListener() {
if (m_entry.isValid() && m_listener == 0 && m_createListener != null) {
m_listener = m_createListener.apply(m_entry);
}
}
void stopListener() {
if (m_entry.isValid() && m_listener != 0) {
m_entry.removeListener(m_listener);
m_listener = 0;
}
}
final NetworkTableEntry m_entry;
int m_listener = 0;
Consumer<NetworkTableEntry> m_update;
Function<NetworkTableEntry, Integer> m_createListener;
}
private final List<Property> m_properties = new ArrayList<>();
private Runnable m_safeState;
private Runnable m_updateTable;
private NetworkTable m_table;
/**
* Set the network table. Must be called prior to any Add* functions being
* called.
* @param table Network table
*/
public void setTable(NetworkTable table) {
m_table = table;
}
/**
* Get the network table.
* @return The network table
*/
public NetworkTable getTable() {
return m_table;
}
/**
* Update the network table values by calling the getters for all properties.
*/
public void updateTable() {
for (Property property : m_properties) {
if (property.m_update != null) {
property.m_update.accept(property.m_entry);
}
}
if (m_updateTable != null) {
m_updateTable.run();
}
}
/**
* Start LiveWindow mode by hooking the setters for all properties.
*/
public void startLiveWindowMode() {
if (m_safeState != null) {
m_safeState.run();
}
for (Property property : m_properties) {
property.startListener();
}
}
/**
* Stop LiveWindow mode by unhooking the setters for all properties.
*/
public void stopLiveWindowMode() {
if (m_safeState != null) {
m_safeState.run();
}
for (Property property : m_properties) {
property.stopListener();
}
}
/**
* Set the string representation of the named data type that will be used
* by the smart dashboard for this sendable.
*
* @param type data type
*/
@Override
public void setSmartDashboardType(String type) {
m_table.getEntry(".type").setString(type);
}
/**
* Set the function that should be called to set the Sendable into a safe
* state. This is called when entering and exiting Live Window mode.
*
* @param func function
*/
@Override
public void setSafeState(Runnable func) {
m_safeState = func;
}
/**
* Set the function that should be called to update the network table
* for things other than properties. Note this function is not passed
* the network table object; instead it should use the entry handles
* returned by getEntry().
*
* @param func function
*/
@Override
public void setUpdateTable(Runnable func) {
m_updateTable = func;
}
/**
* Add a property without getters or setters. This can be used to get
* entry handles for the function called by setUpdateTable().
*
* @param key property name
* @return Network table entry
*/
@Override
public NetworkTableEntry getEntry(String key) {
return m_table.getEntry(key);
}
/**
* Add a boolean property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addBooleanProperty(String key, BooleanSupplier getter, BooleanConsumer setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setBoolean(getter.getAsBoolean());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isBoolean()) {
setter.accept(event.value.getBoolean());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a double property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addDoubleProperty(String key, DoubleSupplier getter, DoubleConsumer setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setDouble(getter.getAsDouble());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isDouble()) {
setter.accept(event.value.getDouble());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a string property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addStringProperty(String key, Supplier<String> getter, Consumer<String> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setString(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isString()) {
setter.accept(event.value.getString());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a boolean array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addBooleanArrayProperty(String key, Supplier<boolean[]> getter,
Consumer<boolean[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setBooleanArray(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isBooleanArray()) {
setter.accept(event.value.getBooleanArray());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a double array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addDoubleArrayProperty(String key, Supplier<double[]> getter,
Consumer<double[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setDoubleArray(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isDoubleArray()) {
setter.accept(event.value.getDoubleArray());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a string array property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addStringArrayProperty(String key, Supplier<String[]> getter,
Consumer<String[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setStringArray(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isStringArray()) {
setter.accept(event.value.getStringArray());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a raw property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addRawProperty(String key, Supplier<byte[]> getter, Consumer<byte[]> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setRaw(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
if (event.value.isRaw()) {
setter.accept(event.value.getRaw());
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
/**
* Add a NetworkTableValue property.
*
* @param key property name
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
@Override
public void addValueProperty(String key, Supplier<NetworkTableValue> getter,
Consumer<NetworkTableValue> setter) {
Property property = new Property(m_table, key);
if (getter != null) {
property.m_update = (entry) -> entry.setValue(getter.get());
}
if (setter != null) {
property.m_createListener = (entry) -> entry.addListener((event) -> {
setter.accept(event.value);
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kNew | EntryListenerFlags.kUpdate);
}
m_properties.add(property);
}
}

View File

@@ -9,9 +9,9 @@ package edu.wpi.first.wpilibj.smartdashboard;
import java.util.LinkedHashMap;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.command.Command;
import static java.util.Objects.requireNonNull;
@@ -28,7 +28,7 @@ import static java.util.Objects.requireNonNull;
*
* @param <V> The type of the values to be stored
*/
public class SendableChooser<V> implements Sendable {
public class SendableChooser<V> extends SendableBase implements Sendable {
/**
* The key for the default value.
@@ -46,7 +46,7 @@ public class SendableChooser<V> implements Sendable {
* A map linking strings to the objects the represent.
*/
private final LinkedHashMap<String, V> m_map = new LinkedHashMap<>();
private String m_defaultChoice = null;
private String m_defaultChoice = "";
/**
* Instantiates a {@link SendableChooser}.
@@ -63,10 +63,6 @@ public class SendableChooser<V> implements Sendable {
*/
public void addObject(String name, V object) {
m_map.put(name, object);
if (m_tableOptions != null) {
m_tableOptions.setStringArray(m_map.keySet().toArray(new String[0]));
}
}
/**
@@ -81,9 +77,6 @@ public class SendableChooser<V> implements Sendable {
requireNonNull(name, "Provided name was null");
m_defaultChoice = name;
if (m_tableDefault != null) {
m_tableDefault.setString(m_defaultChoice);
}
addObject(name, object);
}
@@ -94,29 +87,24 @@ public class SendableChooser<V> implements Sendable {
* @return the option selected
*/
public V getSelected() {
String selected = m_tableSelected.getString(null);
return m_map.getOrDefault(selected, m_map.get(m_defaultChoice));
}
@Override
public String getSmartDashboardType() {
return "String Chooser";
}
private NetworkTableEntry m_tableDefault;
private NetworkTableEntry m_tableSelected;
private NetworkTableEntry m_tableOptions;
@Override
public void initTable(NetworkTable table) {
if (table != null) {
m_tableDefault = table.getEntry(DEFAULT);
m_tableSelected = table.getEntry(SELECTED);
m_tableOptions = table.getEntry(OPTIONS);
m_tableOptions.setStringArray(m_map.keySet().toArray(new String[0]));
if (m_defaultChoice != null) {
m_tableDefault.setString(m_defaultChoice);
}
String selected = m_defaultChoice;
if (m_tableSelected != null) {
selected = m_tableSelected.getString(m_defaultChoice);
}
return m_map.get(selected);
}
private NetworkTableEntry m_tableSelected;
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("String Chooser");
builder.addStringProperty(DEFAULT, () -> {
return m_defaultChoice;
}, null);
builder.addStringArrayProperty(OPTIONS, () -> {
return m_map.keySet().toArray(new String[0]);
}, null);
m_tableSelected = builder.getEntry(SELECTED);
}
}

View File

@@ -8,14 +8,14 @@
package edu.wpi.first.wpilibj.smartdashboard;
import java.nio.ByteBuffer;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.HLUsageReporting;
import edu.wpi.first.wpilibj.NamedSendable;
import edu.wpi.first.wpilibj.Sendable;
/**
@@ -31,11 +31,17 @@ public class SmartDashboard {
*/
private static final NetworkTable table =
NetworkTableInstance.getDefault().getTable("SmartDashboard");
private static class Data {
Sendable m_sendable;
final SendableBuilderImpl m_builder = new SendableBuilderImpl();
}
/**
* A table linking tables in the SmartDashboard to the {@link Sendable} objects they
* came from.
*/
private static final Hashtable<NetworkTable, Sendable> tablesToData = new Hashtable<>();
private static final Map<String, Data> tablesToData = new HashMap<>();
static {
HLUsageReporting.reportSmartDashboard();
@@ -49,25 +55,29 @@ public class SmartDashboard {
* @param data the value
* @throws IllegalArgumentException If key is null
*/
public static void putData(String key, Sendable data) {
NetworkTable dataTable = table.getSubTable(key);
dataTable.getEntry(".type").setString(data.getSmartDashboardType());
data.initTable(dataTable);
tablesToData.put(dataTable, data);
public static synchronized void putData(String key, Sendable data) {
Data sddata = tablesToData.get(key);
if (sddata == null) {
sddata = new Data();
tablesToData.put(key, sddata);
}
if (sddata.m_sendable == null || sddata.m_sendable != data) {
sddata.m_sendable = data;
sddata.m_builder.setTable(table.getSubTable(key));
data.initSendable(sddata.m_builder);
}
sddata.m_builder.updateTable();
}
// TODO should we reimplement NamedSendable?
/**
* Maps the specified key (where the key is the name of the {@link NamedSendable}
* SmartDashboardNamedData to the specified value in this table. The value can be retrieved by
* to the specified value in this table. The value can be retrieved by
* calling the get method with a key that is equal to the original key.
*
* @param value the value
* @throws IllegalArgumentException If key is null
*/
public static void putData(NamedSendable value) {
public static void putData(Sendable value) {
putData(value.getName(), value);
}
@@ -78,13 +88,12 @@ public class SmartDashboard {
* @return the value
* @throws IllegalArgumentException if the key is null
*/
public static Sendable getData(String key) {
NetworkTable subtable = table.getSubTable(key);
Sendable data = tablesToData.get(subtable);
public static synchronized Sendable getData(String key) {
Data data = tablesToData.get(key);
if (data == null) {
throw new IllegalArgumentException("SmartDashboard data does not exist: " + key);
} else {
return data;
return data.m_sendable;
}
}