[hal, wpilib] Add REV PneumaticsHub (#3600)

This commit is contained in:
Thad House
2021-10-10 20:04:50 -07:00
committed by GitHub
parent 4c61a13057
commit 10f19e6fc3
49 changed files with 8383 additions and 19 deletions

View File

@@ -12,9 +12,11 @@ public interface PneumaticsBase extends AutoCloseable {
* @param type module type
* @return module
*/
static PneumaticsControlModule getForType(int module, PneumaticsModuleType type) {
static PneumaticsBase getForType(int module, PneumaticsModuleType type) {
if (type == PneumaticsModuleType.CTREPCM) {
return new PneumaticsControlModule();
return new PneumaticsControlModule(module);
} else if (type == PneumaticsModuleType.REVPH) {
return new PneumaticsHub(module);
}
throw new IllegalArgumentException("Unknown module type");
}
@@ -28,6 +30,8 @@ public interface PneumaticsBase extends AutoCloseable {
static int getDefaultForType(PneumaticsModuleType type) {
if (type == PneumaticsModuleType.CTREPCM) {
return SensorUtil.getDefaultCTREPCMModule();
} else if (type == PneumaticsModuleType.REVPH) {
return SensorUtil.getDefaultREVPHModule();
}
throw new IllegalArgumentException("Unknown module type");
}

View File

@@ -147,7 +147,7 @@ public class PneumaticsControlModule implements PneumaticsBase {
@Override
public int getModuleNumber() {
return m_dataStore.m_handle;
return m_dataStore.m_module;
}
@Override

View File

@@ -0,0 +1,203 @@
// 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 edu.wpi.first.hal.REVPHJNI;
import java.util.HashMap;
import java.util.Map;
/** Module class for controlling a REV Robotics Pneumatics Hub. */
public class PneumaticsHub implements PneumaticsBase {
private static class DataStore implements AutoCloseable {
public final int m_module;
public final int m_handle;
private int m_refCount;
private int m_reservedMask;
private boolean m_compressorReserved;
private final Object m_reserveLock = new Object();
DataStore(int module) {
m_handle = REVPHJNI.initialize(module);
m_module = module;
m_handleMap.put(module, this);
}
@Override
public void close() {
REVPHJNI.free(m_handle);
m_handleMap.remove(m_module);
}
public void addRef() {
m_refCount++;
}
public void removeRef() {
m_refCount--;
if (m_refCount == 0) {
this.close();
}
}
}
private static final Map<Integer, DataStore> m_handleMap = new HashMap<>();
private static final Object m_handleLock = new Object();
private static DataStore getForModule(int module) {
synchronized (m_handleLock) {
Integer moduleBoxed = module;
DataStore pcm = m_handleMap.get(moduleBoxed);
if (pcm == null) {
pcm = new DataStore(module);
}
pcm.addRef();
return pcm;
}
}
private static void freeModule(DataStore store) {
synchronized (m_handleLock) {
store.removeRef();
}
}
private final DataStore m_dataStore;
private final int m_handle;
/** Constructs a PneumaticsHub with the default id (1). */
public PneumaticsHub() {
this(SensorUtil.getDefaultREVPHModule());
}
/**
* Constructs a PneumaticsHub.
*
* @param module module number to construct
*/
public PneumaticsHub(int module) {
m_dataStore = getForModule(module);
m_handle = m_dataStore.m_handle;
}
@Override
public void close() {
freeModule(m_dataStore);
}
@Override
public boolean getCompressor() {
return REVPHJNI.getCompressor(m_handle);
}
@Override
public void setClosedLoopControl(boolean enabled) {
REVPHJNI.setClosedLoopControl(m_handle, enabled);
}
@Override
public boolean getClosedLoopControl() {
return REVPHJNI.getClosedLoopControl(m_handle);
}
@Override
public boolean getPressureSwitch() {
return REVPHJNI.getPressureSwitch(m_handle);
}
@Override
public double getCompressorCurrent() {
return REVPHJNI.getCompressorCurrent(m_handle);
}
@Override
public void setSolenoids(int mask, int values) {
REVPHJNI.setSolenoids(m_handle, mask, values);
}
@Override
public int getSolenoids() {
return REVPHJNI.getSolenoids(m_handle);
}
@Override
public int getModuleNumber() {
return m_dataStore.m_module;
}
@Override
public void fireOneShot(int index) {
// TODO Combine APIs
// REVPHJNI.fireOneShot(m_handle, index, durMs);
}
@Override
public void setOneShotDuration(int index, int durMs) {
// TODO Combine APIs
// REVPHJNI.setOneShotDuration(m_handle, index, durMs);
}
@Override
public boolean checkSolenoidChannel(int channel) {
return REVPHJNI.checkSolenoidChannel(channel);
}
@Override
public int checkAndReserveSolenoids(int mask) {
synchronized (m_dataStore.m_reserveLock) {
if ((m_dataStore.m_reservedMask & mask) != 0) {
return m_dataStore.m_reservedMask & mask;
}
m_dataStore.m_reservedMask |= mask;
return 0;
}
}
@Override
public void unreserveSolenoids(int mask) {
synchronized (m_dataStore.m_reserveLock) {
m_dataStore.m_reservedMask &= ~mask;
}
}
@Override
public Solenoid makeSolenoid(int channel) {
return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.REVPH, channel);
}
@Override
public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
return new DoubleSolenoid(
m_dataStore.m_module, PneumaticsModuleType.REVPH, forwardChannel, reverseChannel);
}
@Override
public Compressor makeCompressor() {
return new Compressor(m_dataStore.m_module, PneumaticsModuleType.REVPH);
}
@Override
public boolean reserveCompressor() {
synchronized (m_dataStore.m_reserveLock) {
if (m_dataStore.m_compressorReserved) {
return false;
}
m_dataStore.m_compressorReserved = true;
return true;
}
}
@Override
public void unreserveCompressor() {
synchronized (m_dataStore.m_reserveLock) {
m_dataStore.m_compressorReserved = false;
}
}
@Override
public int getSolenoidDisabledList() {
// TODO Get this working
return 0;
}
}

View File

@@ -47,6 +47,10 @@ public final class SensorUtil {
/** Number of PCM Modules. */
public static final int kCTREPCMModules = PortsJNI.getNumCTREPCMModules();
public static final int kREVPHChannels = PortsJNI.getNumREVPHChannels();
public static final int kREVPHModules = PortsJNI.getNumREVPHModules();
/**
* Check that the digital channel number is valid. Verify that the channel number is one of the
* legal channel numbers. Channel numbers are 0-based.
@@ -142,5 +146,15 @@ public final class SensorUtil {
return 0;
}
/**
* Get the number of the default solenoid module.
*
* @return The number of the default solenoid module.
*/
@SuppressWarnings("AbbreviationAsWordInName")
public static int getDefaultREVPHModule() {
return 1;
}
private SensorUtil() {}
}

View File

@@ -0,0 +1,239 @@
// 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.simulation.NotifyCallback;
import edu.wpi.first.hal.simulation.REVPHDataJNI;
import edu.wpi.first.wpilibj.PneumaticsBase;
import edu.wpi.first.wpilibj.SensorUtil;
/** Class to control a simulated PneumaticsHub (PH). */
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHSim {
private final int m_index;
/** Constructs for the default PH. */
public REVPHSim() {
m_index = SensorUtil.getDefaultREVPHModule();
}
/**
* Constructs from a PH module number (CAN ID).
*
* @param module module number
*/
public REVPHSim(int module) {
m_index = module;
}
/**
* Constructs from a Compressor object.
*
* @param module PCM module to simulate
*/
public REVPHSim(PneumaticsBase module) {
m_index = module.getModuleNumber();
}
/**
* Register a callback to be run when the solenoid output on a channel changes.
*
* @param channel the channel to monitor
* @param callback the callback
* @param initialNotify should the callback be run with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerSolenoidOutputCallback(
int channel, NotifyCallback callback, boolean initialNotify) {
int uid =
REVPHDataJNI.registerSolenoidOutputCallback(m_index, channel, callback, initialNotify);
return new CallbackStore(m_index, channel, uid, REVPHDataJNI::cancelSolenoidOutputCallback);
}
/**
* Check the solenoid output on a specific channel.
*
* @param channel the channel to check
* @return the solenoid output
*/
public boolean getSolenoidOutput(int channel) {
return REVPHDataJNI.getSolenoidOutput(m_index, channel);
}
/**
* Change the solenoid output on a specific channel.
*
* @param channel the channel to check
* @param solenoidOutput the new solenoid output
*/
public void setSolenoidOutput(int channel, boolean solenoidOutput) {
REVPHDataJNI.setSolenoidOutput(m_index, channel, solenoidOutput);
}
/**
* Register a callback to be run when the compressor is initialized.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerInitializedCallback(NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerInitializedCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelInitializedCallback);
}
/**
* Check whether the compressor has been initialized.
*
* @return true if initialized
*/
public boolean getInitialized() {
return REVPHDataJNI.getInitialized(m_index);
}
/**
* Define whether the compressor has been initialized.
*
* @param initialized whether the compressor is initialized
*/
public void setInitialized(boolean initialized) {
REVPHDataJNI.setInitialized(m_index, initialized);
}
/**
* Register a callback to be run when the compressor activates.
*
* @param callback the callback
* @param initialNotify whether to run the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerCompressorOnCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerCompressorOnCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorOnCallback);
}
/**
* Check if the compressor is on.
*
* @return true if the compressor is active
*/
public boolean getCompressorOn() {
return REVPHDataJNI.getCompressorOn(m_index);
}
/**
* Set whether the compressor is active.
*
* @param compressorOn the new value
*/
public void setCompressorOn(boolean compressorOn) {
REVPHDataJNI.setCompressorOn(m_index, compressorOn);
}
/**
* Register a callback to be run whenever the closed loop state changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerClosedLoopEnabledCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerClosedLoopEnabledCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelClosedLoopEnabledCallback);
}
/**
* Check whether the closed loop compressor control is active.
*
* @return true if active
*/
public boolean getClosedLoopEnabled() {
return REVPHDataJNI.getClosedLoopEnabled(m_index);
}
/**
* Turn on/off the closed loop control of the compressor.
*
* @param closedLoopEnabled whether the control loop is active
*/
public void setClosedLoopEnabled(boolean closedLoopEnabled) {
REVPHDataJNI.setClosedLoopEnabled(m_index, closedLoopEnabled);
}
/**
* Register a callback to be run whenever the pressure switch value changes.
*
* @param callback the callback
* @param initialNotify whether the callback should be called with the initial value
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerPressureSwitchCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerPressureSwitchCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelPressureSwitchCallback);
}
/**
* Check the value of the pressure switch.
*
* @return the pressure switch value
*/
public boolean getPressureSwitch() {
return REVPHDataJNI.getPressureSwitch(m_index);
}
/**
* Set the value of the pressure switch.
*
* @param pressureSwitch the new value
*/
public void setPressureSwitch(boolean pressureSwitch) {
REVPHDataJNI.setPressureSwitch(m_index, pressureSwitch);
}
/**
* Register a callback to be run whenever the compressor current changes.
*
* @param callback the callback
* @param initialNotify whether to call the callback with the initial state
* @return the {@link CallbackStore} object associated with this callback. Save a reference to
* this object so GC doesn't cancel the callback.
*/
public CallbackStore registerCompressorCurrentCallback(
NotifyCallback callback, boolean initialNotify) {
int uid = REVPHDataJNI.registerCompressorCurrentCallback(m_index, callback, initialNotify);
return new CallbackStore(m_index, uid, REVPHDataJNI::cancelCompressorCurrentCallback);
}
/**
* Read the compressor current.
*
* @return the current of the compressor connected to this module
*/
public double getCompressorCurrent() {
return REVPHDataJNI.getCompressorCurrent(m_index);
}
/**
* Set the compressor current.
*
* @param compressorCurrent the new compressor current
*/
public void setCompressorCurrent(double compressorCurrent) {
REVPHDataJNI.setCompressorCurrent(m_index, compressorCurrent);
}
/** Reset all simulation data for this object. */
public void resetData() {
REVPHDataJNI.resetData(m_index);
}
}