mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[hal, wpilib] Add initial systemcore counter implementation (#7723)
This commit is contained in:
@@ -1,535 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.hal.CounterJNI;
|
||||
import edu.wpi.first.hal.FRCNetComm.tResourceType;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import edu.wpi.first.wpilibj.AnalogTriggerOutput.AnalogTriggerType;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Class for counting the number of ticks on a digital input channel.
|
||||
*
|
||||
* <p>This is a general purpose class for counting repetitive events. It can return the number of
|
||||
* counts, the period of the most recent cycle, and detect when the signal being counted has stopped
|
||||
* by supplying a maximum cycle time.
|
||||
*
|
||||
* <p>All counters will immediately start counting - reset() them if you need them to be zeroed
|
||||
* before use.
|
||||
*/
|
||||
public class Counter implements CounterBase, Sendable, AutoCloseable {
|
||||
/** Mode determines how and what the counter counts. */
|
||||
public enum Mode {
|
||||
/** mode: two pulse. */
|
||||
kTwoPulse(0),
|
||||
/** mode: semi period. */
|
||||
kSemiperiod(1),
|
||||
/** mode: pulse length. */
|
||||
kPulseLength(2),
|
||||
/** mode: external direction. */
|
||||
kExternalDirection(3);
|
||||
|
||||
/** Mode value. */
|
||||
public final int value;
|
||||
|
||||
Mode(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/** What makes the counter count up. */
|
||||
protected DigitalSource m_upSource;
|
||||
|
||||
/** What makes the counter count down. */
|
||||
protected DigitalSource m_downSource;
|
||||
|
||||
private boolean m_allocatedUpSource;
|
||||
private boolean m_allocatedDownSource;
|
||||
|
||||
/** The FPGA counter object. */
|
||||
int m_counter;
|
||||
|
||||
/** The index of this counter. */
|
||||
private int m_index;
|
||||
|
||||
/** Distance of travel for each tick. */
|
||||
private double m_distancePerPulse = 1;
|
||||
|
||||
/**
|
||||
* Create an instance of a counter with the given mode.
|
||||
*
|
||||
* @param mode The counter mode.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Counter(final Mode mode) {
|
||||
ByteBuffer index = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
index.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_counter = CounterJNI.initializeCounter(mode.value, index.asIntBuffer());
|
||||
m_index = index.asIntBuffer().get(0);
|
||||
|
||||
m_allocatedUpSource = false;
|
||||
m_allocatedDownSource = false;
|
||||
m_upSource = null;
|
||||
m_downSource = null;
|
||||
|
||||
setMaxPeriod(0.5);
|
||||
|
||||
HAL.report(tResourceType.kResourceType_Counter, m_index + 1, mode.value + 1);
|
||||
SendableRegistry.add(this, "Counter", m_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a counter where no sources are selected. Then they all must be selected
|
||||
* by calling functions to specify the up source and the down source independently.
|
||||
*
|
||||
* <p>The counter will start counting immediately.
|
||||
*/
|
||||
public Counter() {
|
||||
this(Mode.kTwoPulse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a counter from a Digital Input. This is used if an existing digital input
|
||||
* is to be shared by multiple other objects such as encoders or if the Digital Source is not a
|
||||
* DIO channel (such as an Analog Trigger)
|
||||
*
|
||||
* <p>The counter will start counting immediately.
|
||||
*
|
||||
* @param source the digital source to count
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Counter(DigitalSource source) {
|
||||
this();
|
||||
|
||||
requireNonNullParam(source, "source", "Counter");
|
||||
setUpSource(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an up-Counter instance given a channel.
|
||||
*
|
||||
* <p>The counter will start counting immediately.
|
||||
*
|
||||
* @param channel the DIO channel to use as the up source. 0-9 are on-board, 10-25 are on the MXP
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Counter(int channel) {
|
||||
this();
|
||||
setUpSource(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an instance of a simple up-Counter given an
|
||||
* analog trigger. Use the trigger state output from the analog trigger.
|
||||
*
|
||||
* <p>The counter will start counting immediately.
|
||||
*
|
||||
* @param encodingType which edges to count
|
||||
* @param upSource first source to count
|
||||
* @param downSource second source for direction
|
||||
* @param inverted true to invert the count
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Counter(
|
||||
EncodingType encodingType,
|
||||
DigitalSource upSource,
|
||||
DigitalSource downSource,
|
||||
boolean inverted) {
|
||||
this(Mode.kExternalDirection);
|
||||
|
||||
requireNonNullParam(encodingType, "encodingType", "Counter");
|
||||
requireNonNullParam(upSource, "upSource", "Counter");
|
||||
requireNonNullParam(downSource, "downSource", "Counter");
|
||||
|
||||
if (encodingType != EncodingType.k1X && encodingType != EncodingType.k2X) {
|
||||
throw new IllegalArgumentException("Counters only support 1X and 2X quadrature decoding!");
|
||||
}
|
||||
|
||||
setUpSource(upSource);
|
||||
setDownSource(downSource);
|
||||
|
||||
if (encodingType == EncodingType.k1X) {
|
||||
setUpSourceEdge(true, false);
|
||||
CounterJNI.setCounterAverageSize(m_counter, 1);
|
||||
} else {
|
||||
setUpSourceEdge(true, true);
|
||||
CounterJNI.setCounterAverageSize(m_counter, 2);
|
||||
}
|
||||
|
||||
setDownSourceEdge(inverted, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of a Counter object. Create an instance of a simple up-Counter given an
|
||||
* analog trigger. Use the trigger state output from the analog trigger.
|
||||
*
|
||||
* <p>The counter will start counting immediately.
|
||||
*
|
||||
* @param trigger the analog trigger to count
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Counter(AnalogTrigger trigger) {
|
||||
this();
|
||||
|
||||
requireNonNullParam(trigger, "trigger", "Counter");
|
||||
|
||||
setUpSource(trigger.createOutput(AnalogTriggerType.kState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
|
||||
setUpdateWhenEmpty(true);
|
||||
|
||||
clearUpSource();
|
||||
clearDownSource();
|
||||
|
||||
CounterJNI.freeCounter(m_counter);
|
||||
|
||||
m_upSource = null;
|
||||
m_downSource = null;
|
||||
m_counter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The counter's FPGA index.
|
||||
*
|
||||
* @return the Counter's FPGA index
|
||||
*/
|
||||
public int getFPGAIndex() {
|
||||
return m_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the up source for the counter as a digital input channel.
|
||||
*
|
||||
* @param channel the DIO channel to count 0-9 are on-board, 10-25 are on the MXP
|
||||
*/
|
||||
public final void setUpSource(int channel) {
|
||||
setUpSource(new DigitalInput(channel));
|
||||
m_allocatedUpSource = true;
|
||||
SendableRegistry.addChild(this, m_upSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count up. Set the up counting DigitalSource.
|
||||
*
|
||||
* @param source the digital source to count
|
||||
*/
|
||||
public void setUpSource(DigitalSource source) {
|
||||
if (m_upSource != null && m_allocatedUpSource) {
|
||||
m_upSource.close();
|
||||
m_allocatedUpSource = false;
|
||||
}
|
||||
m_upSource = source;
|
||||
CounterJNI.setCounterUpSource(
|
||||
m_counter, source.getPortHandleForRouting(), source.getAnalogTriggerTypeForRouting());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the up counting source to be an analog trigger.
|
||||
*
|
||||
* @param analogTrigger The analog trigger object that is used for the Up Source
|
||||
* @param triggerType The analog trigger output that will trigger the counter.
|
||||
*/
|
||||
public void setUpSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
|
||||
requireNonNullParam(analogTrigger, "analogTrigger", "setUpSource");
|
||||
requireNonNullParam(triggerType, "triggerType", "setUpSource");
|
||||
|
||||
setUpSource(analogTrigger.createOutput(triggerType));
|
||||
m_allocatedUpSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on an up counting source. Set the up source to either detect rising
|
||||
* edges or falling edges.
|
||||
*
|
||||
* @param risingEdge true to count rising edge
|
||||
* @param fallingEdge true to count falling edge
|
||||
*/
|
||||
public void setUpSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_upSource == null) {
|
||||
throw new IllegalStateException("Up Source must be set before setting the edge!");
|
||||
}
|
||||
CounterJNI.setCounterUpSourceEdge(m_counter, risingEdge, fallingEdge);
|
||||
}
|
||||
|
||||
/** Disable the up counting source to the counter. */
|
||||
public void clearUpSource() {
|
||||
if (m_upSource != null && m_allocatedUpSource) {
|
||||
m_upSource.close();
|
||||
m_allocatedUpSource = false;
|
||||
}
|
||||
m_upSource = null;
|
||||
|
||||
CounterJNI.clearCounterUpSource(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the down counting source to be a digital input channel.
|
||||
*
|
||||
* @param channel the DIO channel to count 0-9 are on-board, 10-25 are on the MXP
|
||||
*/
|
||||
public void setDownSource(int channel) {
|
||||
setDownSource(new DigitalInput(channel));
|
||||
m_allocatedDownSource = true;
|
||||
SendableRegistry.addChild(this, m_downSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source object that causes the counter to count down. Set the down counting
|
||||
* DigitalSource.
|
||||
*
|
||||
* @param source the digital source to count
|
||||
*/
|
||||
public void setDownSource(DigitalSource source) {
|
||||
requireNonNullParam(source, "source", "setDownSource");
|
||||
|
||||
if (m_downSource != null && m_allocatedDownSource) {
|
||||
m_downSource.close();
|
||||
m_allocatedDownSource = false;
|
||||
}
|
||||
CounterJNI.setCounterDownSource(
|
||||
m_counter, source.getPortHandleForRouting(), source.getAnalogTriggerTypeForRouting());
|
||||
m_downSource = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the down counting source to be an analog trigger.
|
||||
*
|
||||
* @param analogTrigger The analog trigger object that is used for the Down Source
|
||||
* @param triggerType The analog trigger output that will trigger the counter.
|
||||
*/
|
||||
public void setDownSource(AnalogTrigger analogTrigger, AnalogTriggerType triggerType) {
|
||||
requireNonNullParam(analogTrigger, "analogTrigger", "setDownSource");
|
||||
requireNonNullParam(triggerType, "analogTrigger", "setDownSource");
|
||||
|
||||
setDownSource(analogTrigger.createOutput(triggerType));
|
||||
m_allocatedDownSource = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the edge sensitivity on a down counting source. Set the down source to either detect rising
|
||||
* edges or falling edges.
|
||||
*
|
||||
* @param risingEdge true to count the rising edge
|
||||
* @param fallingEdge true to count the falling edge
|
||||
*/
|
||||
public void setDownSourceEdge(boolean risingEdge, boolean fallingEdge) {
|
||||
if (m_downSource == null) {
|
||||
throw new IllegalStateException("Down Source must be set before setting the edge!");
|
||||
}
|
||||
|
||||
CounterJNI.setCounterDownSourceEdge(m_counter, risingEdge, fallingEdge);
|
||||
}
|
||||
|
||||
/** Disable the down counting source to the counter. */
|
||||
public void clearDownSource() {
|
||||
if (m_downSource != null && m_allocatedDownSource) {
|
||||
m_downSource.close();
|
||||
m_allocatedDownSource = false;
|
||||
}
|
||||
m_downSource = null;
|
||||
|
||||
CounterJNI.clearCounterDownSource(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set standard up / down counting mode on this counter. Up and down counts are sourced
|
||||
* independently from two inputs.
|
||||
*/
|
||||
public void setUpDownCounterMode() {
|
||||
CounterJNI.setCounterUpDownMode(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set external direction mode on this counter. Counts are sourced on the Up counter input. The
|
||||
* Down counter input represents the direction to count.
|
||||
*/
|
||||
public void setExternalDirectionMode() {
|
||||
CounterJNI.setCounterExternalDirectionMode(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Semi-period mode on this counter. Counts up on both rising and falling edges.
|
||||
*
|
||||
* @param highSemiPeriod true to count up on both rising and falling
|
||||
*/
|
||||
public void setSemiPeriodMode(boolean highSemiPeriod) {
|
||||
CounterJNI.setCounterSemiPeriodMode(m_counter, highSemiPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the counter to count in up or down based on the length of the input pulse. This mode
|
||||
* is most useful for direction sensitive gear tooth sensors.
|
||||
*
|
||||
* @param threshold The pulse length beyond which the counter counts the opposite direction. Units
|
||||
* are seconds.
|
||||
*/
|
||||
public void setPulseLengthMode(double threshold) {
|
||||
CounterJNI.setCounterPulseLengthMode(m_counter, threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current counter value. Read the value at this instant. It may still be running, so it
|
||||
* reflects the current value. Next time it is read, it might have a different value.
|
||||
*/
|
||||
@Override
|
||||
public int get() {
|
||||
return CounterJNI.getCounter(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current scaled counter value. Read the value at this instant, scaled by the distance
|
||||
* per pulse (defaults to 1).
|
||||
*
|
||||
* @return The distance since the last reset
|
||||
*/
|
||||
public double getDistance() {
|
||||
return get() * m_distancePerPulse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the Counter to zero. Set the counter value to zero. This doesn't affect the running state
|
||||
* of the counter, just sets the current value to zero.
|
||||
*/
|
||||
@Override
|
||||
public void reset() {
|
||||
CounterJNI.resetCounter(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum period where the device is still considered "moving". Sets the maximum period
|
||||
* where the device is considered moving. This value is used to determine the "stopped" state of
|
||||
* the counter using the GetStopped method.
|
||||
*
|
||||
* @param maxPeriod The maximum period where the counted device is considered moving in seconds.
|
||||
*/
|
||||
@Override
|
||||
public final void setMaxPeriod(double maxPeriod) {
|
||||
CounterJNI.setCounterMaxPeriod(m_counter, maxPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select whether you want to continue updating the event timer output when there are no samples
|
||||
* captured. The output of the event timer has a buffer of periods that are averaged and posted to
|
||||
* a register on the FPGA. When the timer detects that the event source has stopped (based on the
|
||||
* MaxPeriod) the buffer of samples to be averaged is emptied. If you enable the update when
|
||||
* empty, you will be notified of the stopped source and the event time will report 0 samples. If
|
||||
* you disable update when empty, the most recent average will remain on the output until a new
|
||||
* sample is acquired. You will never see 0 samples output (except when there have been no events
|
||||
* since an FPGA reset) and you will likely not see the stopped bit become true (since it is
|
||||
* updated at the end of an average and there are no samples to average).
|
||||
*
|
||||
* @param enabled true to continue updating
|
||||
*/
|
||||
public void setUpdateWhenEmpty(boolean enabled) {
|
||||
CounterJNI.setCounterUpdateWhenEmpty(m_counter, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the clock is stopped. Determine if the clocked input is stopped based on the
|
||||
* MaxPeriod value set using the SetMaxPeriod method. If the clock exceeds the MaxPeriod, then the
|
||||
* device (and counter) are assumed to be stopped and the method will return true.
|
||||
*
|
||||
* @return true if the most recent counter period exceeds the MaxPeriod value set by SetMaxPeriod.
|
||||
*/
|
||||
@Override
|
||||
public boolean getStopped() {
|
||||
return CounterJNI.getCounterStopped(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* The last direction the counter value changed.
|
||||
*
|
||||
* @return The last direction the counter value changed.
|
||||
*/
|
||||
@Override
|
||||
public boolean getDirection() {
|
||||
return CounterJNI.getCounterDirection(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Counter to return reversed sensing on the direction. This allows counters to change the
|
||||
* direction they are counting in the case of 1X and 2X quadrature encoding only. Any other
|
||||
* counter mode isn't supported.
|
||||
*
|
||||
* @param reverseDirection true if the value counted should be negated.
|
||||
*/
|
||||
public void setReverseDirection(boolean reverseDirection) {
|
||||
CounterJNI.setCounterReverseDirection(m_counter, reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Period of the most recent count. Returns the time interval of the most recent count.
|
||||
* This can be used for velocity calculations to determine shaft speed.
|
||||
*
|
||||
* @return The period of the last two pulses in units of seconds.
|
||||
*/
|
||||
@Override
|
||||
public double getPeriod() {
|
||||
return CounterJNI.getCounterPeriod(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current rate of the Counter. Read the current rate of the counter accounting for the
|
||||
* distance per pulse value. The default value for distance per pulse (1) yields units of pulses
|
||||
* per second.
|
||||
*
|
||||
* @return The rate in units/sec
|
||||
*/
|
||||
public double getRate() {
|
||||
return m_distancePerPulse / getPeriod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Samples to Average which specifies the number of samples of the timer to average when
|
||||
* calculating the period. Perform averaging to account for mechanical imperfections or as
|
||||
* oversampling to increase resolution.
|
||||
*
|
||||
* @param samplesToAverage The number of samples to average from 1 to 127.
|
||||
*/
|
||||
public void setSamplesToAverage(int samplesToAverage) {
|
||||
CounterJNI.setCounterSamplesToAverage(m_counter, samplesToAverage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Samples to Average which specifies the number of samples of the timer to average when
|
||||
* calculating the period. Perform averaging to account for mechanical imperfections or as
|
||||
* oversampling to increase resolution.
|
||||
*
|
||||
* @return SamplesToAverage The number of samples being averaged (from 1 to 127)
|
||||
*/
|
||||
public int getSamplesToAverage() {
|
||||
return CounterJNI.getCounterSamplesToAverage(m_counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the distance per pulse for this counter. This sets the multiplier used to determine the
|
||||
* distance driven based on the count value from the encoder. Set this value based on the Pulses
|
||||
* per Revolution and factor in any gearing reductions. This distance can be in any units you
|
||||
* like, linear or angular.
|
||||
*
|
||||
* @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
|
||||
*/
|
||||
public void setDistancePerPulse(double distancePerPulse) {
|
||||
m_distancePerPulse = distancePerPulse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Counter");
|
||||
builder.addDoubleProperty("Value", this::get, null);
|
||||
}
|
||||
}
|
||||
@@ -1,328 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.hal.FRCNetComm.tResourceType;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.hal.SimBoolean;
|
||||
import edu.wpi.first.hal.SimDevice;
|
||||
import edu.wpi.first.hal.SimDevice.Direction;
|
||||
import edu.wpi.first.hal.SimDouble;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Ultrasonic rangefinder class. The Ultrasonic rangefinder measures absolute distance based on the
|
||||
* round-trip time of a ping generated by the controller. These sensors use two transducers, a
|
||||
* speaker and a microphone both tuned to the ultrasonic range. A common ultrasonic sensor, the
|
||||
* Daventech SRF04 requires a short pulse to be generated on a digital channel. This causes the
|
||||
* chirp to be emitted. A second line becomes high as the ping is transmitted and goes low when the
|
||||
* echo is received. The time that the line is high determines the round trip distance (time of
|
||||
* flight).
|
||||
*/
|
||||
public class Ultrasonic implements Sendable, AutoCloseable {
|
||||
// Time (sec) for the ping trigger pulse.
|
||||
private static final double kPingTime = 10 * 1e-6;
|
||||
private static final double kSpeedOfSoundInchesPerSec = 1130.0 * 12.0;
|
||||
// ultrasonic sensor list
|
||||
private static final List<Ultrasonic> m_sensors = new ArrayList<>();
|
||||
// automatic round robin mode
|
||||
private static volatile boolean m_automaticEnabled;
|
||||
private DigitalInput m_echoChannel;
|
||||
private DigitalOutput m_pingChannel;
|
||||
private final boolean m_allocatedChannels;
|
||||
private boolean m_enabled;
|
||||
private Counter m_counter;
|
||||
// task doing the round-robin automatic sensing
|
||||
private static Thread m_task;
|
||||
private static int m_instances;
|
||||
|
||||
@SuppressWarnings("PMD.SingularField")
|
||||
private SimDevice m_simDevice;
|
||||
|
||||
private SimBoolean m_simRangeValid;
|
||||
private SimDouble m_simRange;
|
||||
|
||||
/**
|
||||
* Background task that goes through the list of ultrasonic sensors and pings each one in turn.
|
||||
* The counter is configured to read the timing of the returned echo pulse.
|
||||
*
|
||||
* <p><b>DANGER WILL ROBINSON, DANGER WILL ROBINSON:</b> This code runs as a task and assumes that
|
||||
* none of the ultrasonic sensors will change while it's running. If one does, then this will
|
||||
* certainly break. Make sure to disable automatic mode before changing anything with the
|
||||
* sensors!!
|
||||
*/
|
||||
private static final class UltrasonicChecker extends Thread {
|
||||
@Override
|
||||
public synchronized void run() {
|
||||
while (m_automaticEnabled) {
|
||||
for (Ultrasonic sensor : m_sensors) {
|
||||
if (!m_automaticEnabled) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sensor.isEnabled()) {
|
||||
sensor.m_pingChannel.pulse(kPingTime); // do the ping
|
||||
}
|
||||
|
||||
Timer.delay(0.1); // wait for ping to return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Ultrasonic Sensor. This is the common code that initializes the ultrasonic
|
||||
* sensor given that there are two digital I/O channels allocated. If the system was running in
|
||||
* automatic mode (round-robin) when the new sensor is added, it is stopped, the sensor is added,
|
||||
* then automatic mode is restored.
|
||||
*/
|
||||
private synchronized void initialize() {
|
||||
m_simDevice = SimDevice.create("Ultrasonic", m_echoChannel.getChannel());
|
||||
if (m_simDevice != null) {
|
||||
m_simRangeValid = m_simDevice.createBoolean("Range Valid", Direction.kInput, true);
|
||||
m_simRange = m_simDevice.createDouble("Range (in)", Direction.kInput, 0.0);
|
||||
m_pingChannel.setSimDevice(m_simDevice);
|
||||
m_echoChannel.setSimDevice(m_simDevice);
|
||||
}
|
||||
final boolean originalMode = m_automaticEnabled;
|
||||
setAutomaticMode(false); // kill task when adding a new sensor
|
||||
m_sensors.add(this);
|
||||
|
||||
m_counter = new Counter(m_echoChannel); // set up counter for this
|
||||
SendableRegistry.addChild(this, m_counter);
|
||||
// sensor
|
||||
m_counter.setMaxPeriod(1.0);
|
||||
m_counter.setSemiPeriodMode(true);
|
||||
m_counter.reset();
|
||||
m_enabled = true; // make it available for round-robin scheduling
|
||||
setAutomaticMode(originalMode);
|
||||
|
||||
m_instances++;
|
||||
HAL.report(tResourceType.kResourceType_Ultrasonic, m_instances);
|
||||
SendableRegistry.add(this, "Ultrasonic", m_echoChannel.getChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the echo channel.
|
||||
*
|
||||
* @return The echo channel.
|
||||
*/
|
||||
public int getEchoChannel() {
|
||||
return m_echoChannel.getChannel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Ultrasonic Sensor. This is designed to support the Daventech SRF04
|
||||
* and Vex ultrasonic sensors.
|
||||
*
|
||||
* @param pingChannel The digital output channel that sends the pulse to initiate the sensor
|
||||
* sending the ping.
|
||||
* @param echoChannel The digital input channel that receives the echo. The length of time that
|
||||
* the echo is high represents the round trip time of the ping, and the distance.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Ultrasonic(final int pingChannel, final int echoChannel) {
|
||||
m_pingChannel = new DigitalOutput(pingChannel);
|
||||
m_echoChannel = new DigitalInput(echoChannel);
|
||||
SendableRegistry.addChild(this, m_pingChannel);
|
||||
SendableRegistry.addChild(this, m_echoChannel);
|
||||
m_allocatedChannels = true;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of an Ultrasonic Sensor from a DigitalInput for the echo channel and a
|
||||
* DigitalOutput for the ping channel.
|
||||
*
|
||||
* @param pingChannel The digital output object that starts the sensor doing a ping. Requires a
|
||||
* 10uS pulse to start.
|
||||
* @param echoChannel The digital input object that times the return pulse to determine the range.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Ultrasonic(DigitalOutput pingChannel, DigitalInput echoChannel) {
|
||||
requireNonNullParam(pingChannel, "pingChannel", "Ultrasonic");
|
||||
requireNonNullParam(echoChannel, "echoChannel", "Ultrasonic");
|
||||
|
||||
m_allocatedChannels = false;
|
||||
m_pingChannel = pingChannel;
|
||||
m_echoChannel = echoChannel;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for the ultrasonic sensor. Delete the instance of the ultrasonic sensor by freeing
|
||||
* the allocated digital channels. If the system was in automatic mode (round-robin), then it is
|
||||
* stopped, then started again after this sensor is removed (provided this wasn't the last
|
||||
* sensor).
|
||||
*/
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
SendableRegistry.remove(this);
|
||||
final boolean wasAutomaticMode = m_automaticEnabled;
|
||||
setAutomaticMode(false);
|
||||
if (m_allocatedChannels) {
|
||||
if (m_pingChannel != null) {
|
||||
m_pingChannel.close();
|
||||
}
|
||||
if (m_echoChannel != null) {
|
||||
m_echoChannel.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_counter != null) {
|
||||
m_counter.close();
|
||||
m_counter = null;
|
||||
}
|
||||
|
||||
m_pingChannel = null;
|
||||
m_echoChannel = null;
|
||||
synchronized (m_sensors) {
|
||||
m_sensors.remove(this);
|
||||
}
|
||||
if (!m_sensors.isEmpty() && wasAutomaticMode) {
|
||||
setAutomaticMode(true);
|
||||
}
|
||||
|
||||
if (m_simDevice != null) {
|
||||
m_simDevice.close();
|
||||
m_simDevice = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn Automatic mode on/off for all sensors.
|
||||
*
|
||||
* <p>When in Automatic mode, all sensors will fire in round-robin, waiting a set time between
|
||||
* each sensor.
|
||||
*
|
||||
* @param enabling Set to true if round-robin scheduling should start for all the ultrasonic
|
||||
* sensors. This scheduling method assures that the sensors are non-interfering because no two
|
||||
* sensors fire at the same time. If another scheduling algorithm is preferred, it can be
|
||||
* implemented by pinging the sensors manually and waiting for the results to come back.
|
||||
*/
|
||||
public static synchronized void setAutomaticMode(boolean enabling) {
|
||||
if (enabling == m_automaticEnabled) {
|
||||
return; // ignore the case of no change
|
||||
}
|
||||
m_automaticEnabled = enabling;
|
||||
|
||||
if (enabling) {
|
||||
/* Clear all the counters so no data is valid. No synchronization is
|
||||
* needed because the background task is stopped.
|
||||
*/
|
||||
for (Ultrasonic u : m_sensors) {
|
||||
u.m_counter.reset();
|
||||
}
|
||||
|
||||
// Start round robin task
|
||||
m_task = new UltrasonicChecker();
|
||||
m_task.start();
|
||||
} else {
|
||||
if (m_task != null) {
|
||||
// Wait for background task to stop running
|
||||
try {
|
||||
m_task.join();
|
||||
m_task = null;
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear all the counters (data now invalid) since automatic mode is
|
||||
* disabled. No synchronization is needed because the background task is
|
||||
* stopped.
|
||||
*/
|
||||
for (Ultrasonic u : m_sensors) {
|
||||
u.m_counter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single ping to ultrasonic sensor. Send out a single ping to the ultrasonic sensor. This only
|
||||
* works if automatic (round-robin) mode is disabled. A single ping is sent out, and the counter
|
||||
* should count the semi-period when it comes in. The counter is reset to make the current value
|
||||
* invalid.
|
||||
*/
|
||||
public void ping() {
|
||||
setAutomaticMode(false); // turn off automatic round-robin if pinging
|
||||
// single sensor
|
||||
m_counter.reset(); // reset the counter to zero (invalid data now)
|
||||
// do the ping to start getting a single range
|
||||
m_pingChannel.pulse(kPingTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is a valid range measurement. The ranges are accumulated in a counter that will
|
||||
* increment on each edge of the echo (return) signal. If the count is not at least 2, then the
|
||||
* range has not yet been measured, and is invalid.
|
||||
*
|
||||
* @return true if the range is valid
|
||||
*/
|
||||
public boolean isRangeValid() {
|
||||
if (m_simRangeValid != null) {
|
||||
return m_simRangeValid.get();
|
||||
}
|
||||
return m_counter.get() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range in inches from the ultrasonic sensor. If there is no valid value yet, i.e. at
|
||||
* least one measurement hasn't completed, then return 0.
|
||||
*
|
||||
* @return double Range in inches of the target returned from the ultrasonic sensor.
|
||||
*/
|
||||
public double getRangeInches() {
|
||||
if (isRangeValid()) {
|
||||
if (m_simRange != null) {
|
||||
return m_simRange.get();
|
||||
}
|
||||
return m_counter.getPeriod() * kSpeedOfSoundInchesPerSec / 2.0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the range in millimeters from the ultrasonic sensor. If there is no valid value yet, i.e.
|
||||
* at least one measurement hasn't completed, then return 0.
|
||||
*
|
||||
* @return double Range in millimeters of the target returned by the ultrasonic sensor.
|
||||
*/
|
||||
public double getRangeMM() {
|
||||
return getRangeInches() * 25.4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the ultrasonic enabled.
|
||||
*
|
||||
* @return true if the ultrasonic is enabled
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the ultrasonic is enabled.
|
||||
*
|
||||
* @param enable set to true to enable the ultrasonic
|
||||
*/
|
||||
public void setEnabled(boolean enable) {
|
||||
m_enabled = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Ultrasonic");
|
||||
builder.addDoubleProperty("Value", this::getRangeInches, null);
|
||||
}
|
||||
}
|
||||
@@ -6,25 +6,16 @@ package edu.wpi.first.wpilibj.counter;
|
||||
|
||||
/** Edge configuration. */
|
||||
public enum EdgeConfiguration {
|
||||
/** No edge configuration (neither rising nor falling). */
|
||||
kNone(false, false),
|
||||
/** Rising edge configuration. */
|
||||
kRisingEdge(true, false),
|
||||
kRisingEdge(true),
|
||||
/** Falling edge configuration. */
|
||||
kFallingEdge(false, true),
|
||||
/** Both rising and falling edge configuration. */
|
||||
kBoth(true, true);
|
||||
kFallingEdge(false);
|
||||
|
||||
/** True if triggering on rising edge. */
|
||||
@SuppressWarnings("MemberName")
|
||||
public final boolean rising;
|
||||
|
||||
/** True if triggering on falling edge. */
|
||||
@SuppressWarnings("MemberName")
|
||||
public final boolean falling;
|
||||
|
||||
EdgeConfiguration(boolean rising, boolean falling) {
|
||||
EdgeConfiguration(boolean rising) {
|
||||
this.rising = rising;
|
||||
this.falling = falling;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.wpilibj.counter;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.hal.CounterJNI;
|
||||
import edu.wpi.first.hal.FRCNetComm.tResourceType;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import edu.wpi.first.wpilibj.DigitalSource;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Counter using external direction.
|
||||
*
|
||||
* <p>This counts on an edge from one digital input and the whether it counts up or down based on
|
||||
* the state of a second digital input.
|
||||
*/
|
||||
public class ExternalDirectionCounter implements Sendable, AutoCloseable {
|
||||
private final DigitalSource m_countSource;
|
||||
private final DigitalSource m_directionSource;
|
||||
|
||||
private final int m_handle;
|
||||
|
||||
/**
|
||||
* Constructs a new ExternalDirectionCounter.
|
||||
*
|
||||
* @param countSource The source for counting.
|
||||
* @param directionSource The source for selecting count direction.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public ExternalDirectionCounter(DigitalSource countSource, DigitalSource directionSource) {
|
||||
m_countSource = requireNonNullParam(countSource, "countSource", "ExternalDirectionCounter");
|
||||
m_directionSource =
|
||||
requireNonNullParam(directionSource, "directionSource", "ExternalDirectionCounter");
|
||||
|
||||
ByteBuffer index = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
index.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_handle = CounterJNI.initializeCounter(CounterJNI.EXTERNAL_DIRECTION, index.asIntBuffer());
|
||||
|
||||
CounterJNI.setCounterUpSource(
|
||||
m_handle,
|
||||
countSource.getPortHandleForRouting(),
|
||||
countSource.getAnalogTriggerTypeForRouting());
|
||||
CounterJNI.setCounterUpSourceEdge(m_handle, true, false);
|
||||
|
||||
CounterJNI.setCounterDownSource(
|
||||
m_handle,
|
||||
directionSource.getPortHandleForRouting(),
|
||||
directionSource.getAnalogTriggerTypeForRouting());
|
||||
CounterJNI.setCounterDownSourceEdge(m_handle, false, true);
|
||||
CounterJNI.resetCounter(m_handle);
|
||||
|
||||
int intIndex = index.getInt();
|
||||
HAL.report(tResourceType.kResourceType_Counter, intIndex + 1);
|
||||
SendableRegistry.add(this, "External Direction Counter", intIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current count.
|
||||
*
|
||||
* @return The current count.
|
||||
*/
|
||||
public int getCount() {
|
||||
return CounterJNI.getCounter(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to reverse the counter direction.
|
||||
*
|
||||
* @param reverseDirection True to reverse counting direction.
|
||||
*/
|
||||
public void setReverseDirection(boolean reverseDirection) {
|
||||
CounterJNI.setCounterReverseDirection(m_handle, reverseDirection);
|
||||
}
|
||||
|
||||
/** Resets the current count. */
|
||||
public void reset() {
|
||||
CounterJNI.resetCounter(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the edge configuration for counting.
|
||||
*
|
||||
* @param configuration The counting edge configuration.
|
||||
*/
|
||||
public void setEdgeConfiguration(EdgeConfiguration configuration) {
|
||||
CounterJNI.setCounterUpSourceEdge(m_handle, configuration.rising, configuration.falling);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
CounterJNI.freeCounter(m_handle);
|
||||
CounterJNI.suppressUnused(m_countSource);
|
||||
CounterJNI.suppressUnused(m_directionSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("External Direction Counter");
|
||||
builder.addDoubleProperty("Count", this::getCount, null);
|
||||
}
|
||||
}
|
||||
@@ -4,17 +4,12 @@
|
||||
|
||||
package edu.wpi.first.wpilibj.counter;
|
||||
|
||||
import static edu.wpi.first.util.ErrorMessages.requireNonNullParam;
|
||||
|
||||
import edu.wpi.first.hal.CounterJNI;
|
||||
import edu.wpi.first.hal.FRCNetComm.tResourceType;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import edu.wpi.first.wpilibj.DigitalSource;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Tachometer.
|
||||
@@ -25,38 +20,27 @@ import java.nio.ByteOrder;
|
||||
* encoders, this class only needs a single digital input.
|
||||
*/
|
||||
public class Tachometer implements Sendable, AutoCloseable {
|
||||
private final DigitalSource m_source;
|
||||
private final int m_handle;
|
||||
private int m_edgesPerRevolution = 1;
|
||||
|
||||
/**
|
||||
* Constructs a new tachometer.
|
||||
*
|
||||
* @param source The DigitalSource (e.g. DigitalInput) of the Tachometer.
|
||||
* @param channel The channel of the Tachometer.
|
||||
* @param configuration The edge configuration
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public Tachometer(DigitalSource source) {
|
||||
m_source = requireNonNullParam(source, "source", "Tachometer");
|
||||
public Tachometer(int channel, EdgeConfiguration configuration) {
|
||||
m_handle = CounterJNI.initializeCounter(channel, configuration.rising);
|
||||
|
||||
ByteBuffer index = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
index.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_handle = CounterJNI.initializeCounter(CounterJNI.TWO_PULSE, index.asIntBuffer());
|
||||
|
||||
CounterJNI.setCounterUpSource(
|
||||
m_handle, source.getPortHandleForRouting(), source.getAnalogTriggerTypeForRouting());
|
||||
CounterJNI.setCounterUpSourceEdge(m_handle, true, false);
|
||||
|
||||
int intIndex = index.getInt();
|
||||
HAL.report(tResourceType.kResourceType_Counter, intIndex + 1);
|
||||
SendableRegistry.add(this, "Tachometer", intIndex);
|
||||
HAL.report(tResourceType.kResourceType_Counter, channel + 1);
|
||||
SendableRegistry.add(this, "Tachometer", channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
CounterJNI.freeCounter(m_handle);
|
||||
CounterJNI.suppressUnused(m_source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,24 +122,6 @@ public class Tachometer implements Sendable, AutoCloseable {
|
||||
return CounterJNI.getCounterStopped(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of samples to average.
|
||||
*
|
||||
* @return Samples to average.
|
||||
*/
|
||||
public int getSamplesToAverage() {
|
||||
return CounterJNI.getCounterSamplesToAverage(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of samples to average.
|
||||
*
|
||||
* @param samplesToAverage Samples to average.
|
||||
*/
|
||||
public void setSamplesToAverage(int samplesToAverage) {
|
||||
CounterJNI.setCounterSamplesToAverage(m_handle, samplesToAverage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum period before the tachometer is considered stopped.
|
||||
*
|
||||
@@ -165,15 +131,6 @@ public class Tachometer implements Sendable, AutoCloseable {
|
||||
CounterJNI.setCounterMaxPeriod(m_handle, maxPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if to update when empty.
|
||||
*
|
||||
* @param updateWhenEmpty Update when empty if true.
|
||||
*/
|
||||
public void setUpdateWhenEmpty(boolean updateWhenEmpty) {
|
||||
CounterJNI.setCounterUpdateWhenEmpty(m_handle, updateWhenEmpty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Tachometer");
|
||||
|
||||
@@ -10,9 +10,6 @@ import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import edu.wpi.first.wpilibj.DigitalSource;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Up Down Counter.
|
||||
@@ -21,57 +18,28 @@ import java.nio.ByteOrder;
|
||||
* digital input and down on an edge from another digital input.
|
||||
*/
|
||||
public class UpDownCounter implements Sendable, AutoCloseable {
|
||||
private final DigitalSource m_upSource;
|
||||
private final DigitalSource m_downSource;
|
||||
|
||||
private final int m_handle;
|
||||
|
||||
/**
|
||||
* Constructs a new UpDown Counter.
|
||||
*
|
||||
* @param upSource The up count source (can be null).
|
||||
* @param downSource The down count source (can be null).
|
||||
* @param channel The up count source (can be null).
|
||||
* @param configuration The edge configuration.
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public UpDownCounter(DigitalSource upSource, DigitalSource downSource) {
|
||||
ByteBuffer index = ByteBuffer.allocateDirect(4);
|
||||
// set the byte order
|
||||
index.order(ByteOrder.LITTLE_ENDIAN);
|
||||
m_handle = CounterJNI.initializeCounter(CounterJNI.TWO_PULSE, index.asIntBuffer());
|
||||
|
||||
if (upSource != null) {
|
||||
m_upSource = upSource;
|
||||
CounterJNI.setCounterUpSource(
|
||||
m_handle, upSource.getPortHandleForRouting(), upSource.getAnalogTriggerTypeForRouting());
|
||||
CounterJNI.setCounterUpSourceEdge(m_handle, true, false);
|
||||
} else {
|
||||
m_upSource = null;
|
||||
}
|
||||
|
||||
if (downSource != null) {
|
||||
m_downSource = downSource;
|
||||
CounterJNI.setCounterDownSource(
|
||||
m_handle,
|
||||
downSource.getPortHandleForRouting(),
|
||||
downSource.getAnalogTriggerTypeForRouting());
|
||||
CounterJNI.setCounterDownSourceEdge(m_handle, true, false);
|
||||
} else {
|
||||
m_downSource = null;
|
||||
}
|
||||
public UpDownCounter(int channel, EdgeConfiguration configuration) {
|
||||
m_handle = CounterJNI.initializeCounter(channel, configuration.rising);
|
||||
|
||||
reset();
|
||||
|
||||
int intIndex = index.getInt();
|
||||
HAL.report(tResourceType.kResourceType_Counter, intIndex + 1);
|
||||
SendableRegistry.add(this, "UpDown Counter", intIndex);
|
||||
HAL.report(tResourceType.kResourceType_Counter, channel);
|
||||
SendableRegistry.add(this, "UpDown Counter", channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
CounterJNI.freeCounter(m_handle);
|
||||
CounterJNI.suppressUnused(m_upSource);
|
||||
CounterJNI.suppressUnused(m_downSource);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,17 +47,8 @@ public class UpDownCounter implements Sendable, AutoCloseable {
|
||||
*
|
||||
* @param configuration The up source configuration.
|
||||
*/
|
||||
public void setUpEdgeConfiguration(EdgeConfiguration configuration) {
|
||||
CounterJNI.setCounterUpSourceEdge(m_handle, configuration.rising, configuration.falling);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration for the down source.
|
||||
*
|
||||
* @param configuration The down source configuration.
|
||||
*/
|
||||
public void setDownEdgeConfiguration(EdgeConfiguration configuration) {
|
||||
CounterJNI.setCounterDownSourceEdge(m_handle, configuration.rising, configuration.falling);
|
||||
public void setEdgeConfiguration(EdgeConfiguration configuration) {
|
||||
CounterJNI.setCounterEdgeConfiguration(m_handle, configuration.rising);
|
||||
}
|
||||
|
||||
/** Resets the current count. */
|
||||
@@ -97,15 +56,6 @@ public class UpDownCounter implements Sendable, AutoCloseable {
|
||||
CounterJNI.resetCounter(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets to reverse the counter direction.
|
||||
*
|
||||
* @param reverseDirection True to reverse counting direction.
|
||||
*/
|
||||
public void setReverseDirection(boolean reverseDirection) {
|
||||
CounterJNI.setCounterReverseDirection(m_handle, reverseDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current count.
|
||||
*
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.wpilibj.simulation;
|
||||
|
||||
import edu.wpi.first.hal.SimBoolean;
|
||||
import edu.wpi.first.hal.SimDouble;
|
||||
import edu.wpi.first.math.util.Units;
|
||||
import edu.wpi.first.wpilibj.Ultrasonic;
|
||||
|
||||
/** Class to control a simulated {@link edu.wpi.first.wpilibj.Ultrasonic}. */
|
||||
public class UltrasonicSim {
|
||||
private final SimBoolean m_simRangeValid;
|
||||
private final SimDouble m_simRange;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ultrasonic The real ultrasonic to simulate
|
||||
*/
|
||||
public UltrasonicSim(Ultrasonic ultrasonic) {
|
||||
// ping parameter is unused
|
||||
this(-1, ultrasonic.getEchoChannel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ping unused.
|
||||
* @param echo the ultrasonic's echo channel.
|
||||
*/
|
||||
public UltrasonicSim(@SuppressWarnings("unused") int ping, int echo) {
|
||||
SimDeviceSim simDevice = new SimDeviceSim("Ultrasonic", echo);
|
||||
m_simRangeValid = simDevice.getBoolean("Range Valid");
|
||||
m_simRange = simDevice.getDouble("Range (in)");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the range measurement is valid.
|
||||
*
|
||||
* @param valid True if valid
|
||||
*/
|
||||
public void setRangeValid(boolean valid) {
|
||||
m_simRangeValid.set(valid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the range measurement.
|
||||
*
|
||||
* @param inches The range in inches.
|
||||
*/
|
||||
public void setRangeInches(double inches) {
|
||||
m_simRange.set(inches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the range measurement.
|
||||
*
|
||||
* @param meters The range in meters.
|
||||
*/
|
||||
public void setRangeMeters(double meters) {
|
||||
m_simRange.set(Units.metersToInches(meters));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user