mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-24 01:31:46 +00:00
[hal, wpilib] Switch PCM to be a single object that is allowed to be duplicated (#3475)
Having PCM as a singleton is a problem, as multiple things need to use it, and that gets really ugly. This changes PCM's to be a reference counted object, that can be passed around and constructed from multiple places. In Java, this is using a map to hold a data store with a ref count, and allocating new objects any time a duplicate is requested. In C++, this uses a trick constructor to store a PCM instance in the data store itself. This instance can then be passed to base objects using std::shared_ptr's aliasing constructor, which means constructing a solenoid from a PCM is not allocating after the 1st one. This did require removing sendable from PCM. A compressor class was added back in to act as sendable for the PCM. After this change is finished, the only change RobotBuilder and Team Code would require is passing a module type to solenoid constructors. Co-authored-by: sciencewhiz <sciencewhiz@users.noreply.github.com>
This commit is contained in:
154
wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
Normal file
154
wpilibj/src/main/java/edu/wpi/first/wpilibj/Compressor.java
Normal file
@@ -0,0 +1,154 @@
|
||||
// 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.FRCNetComm.tResourceType;
|
||||
import edu.wpi.first.hal.HAL;
|
||||
import edu.wpi.first.hal.util.AllocationException;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
|
||||
/**
|
||||
* Class for operating a compressor connected to a pneumatics module. The module will automatically
|
||||
* run in closed loop mode by default whenever a {@link Solenoid} object is created. For most cases,
|
||||
* a Compressor object does not need to be instantiated or used in a robot program. This class is
|
||||
* only required in cases where the robot program needs a more detailed status of the compressor or
|
||||
* to enable/disable closed loop control.
|
||||
*
|
||||
* <p>Note: you cannot operate the compressor directly from this class as doing so would circumvent
|
||||
* 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 implements Sendable, AutoCloseable {
|
||||
private PneumaticsBase m_module;
|
||||
|
||||
/**
|
||||
* Constructs a compressor for a specified module and type.
|
||||
*
|
||||
* @param module The module ID to use.
|
||||
* @param moduleType The module type to use.
|
||||
*/
|
||||
public Compressor(int module, PneumaticsModuleType moduleType) {
|
||||
m_module = PneumaticsBase.getForType(module, moduleType);
|
||||
boolean allocatedCompressor = false;
|
||||
boolean successfulCompletion = false;
|
||||
|
||||
try {
|
||||
if (!m_module.reserveCompressor()) {
|
||||
throw new AllocationException("Compressor already allocated");
|
||||
}
|
||||
|
||||
allocatedCompressor = true;
|
||||
|
||||
m_module.setClosedLoopControl(true);
|
||||
|
||||
HAL.report(tResourceType.kResourceType_Compressor, module + 1);
|
||||
SendableRegistry.addLW(this, "Compressor", module);
|
||||
successfulCompletion = true;
|
||||
|
||||
} finally {
|
||||
if (!successfulCompletion) {
|
||||
if (allocatedCompressor) {
|
||||
m_module.unreserveCompressor();
|
||||
}
|
||||
m_module.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a compressor for a default module and specified type.
|
||||
*
|
||||
* @param moduleType The module type to use.
|
||||
*/
|
||||
public Compressor(PneumaticsModuleType moduleType) {
|
||||
this(PneumaticsBase.getDefaultForType(moduleType), moduleType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
m_module.unreserveCompressor();
|
||||
m_module.close();
|
||||
m_module = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the compressor running in closed loop control mode.
|
||||
*
|
||||
* <p>Use the method in cases where you would like to manually stop and start the compressor for
|
||||
* applications such as conserving battery or making sure that the compressor motor doesn't start
|
||||
* during critical operations.
|
||||
*/
|
||||
public void start() {
|
||||
setClosedLoopControl(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the compressor from running in closed loop control mode.
|
||||
*
|
||||
* <p>Use the method in cases where you would like to manually stop and start the compressor for
|
||||
* applications such as conserving battery or making sure that the compressor motor doesn't start
|
||||
* during critical operations.
|
||||
*/
|
||||
public void stop() {
|
||||
setClosedLoopControl(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of the compressor.
|
||||
*
|
||||
* @return true if the compressor is on
|
||||
*/
|
||||
public boolean enabled() {
|
||||
return m_module.getCompressor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pressure switch value.
|
||||
*
|
||||
* @return true if the pressure is low
|
||||
*/
|
||||
public boolean getPressureSwitchValue() {
|
||||
return m_module.getPressureSwitch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current being used by the compressor.
|
||||
*
|
||||
* @return current consumed by the compressor in amps
|
||||
*/
|
||||
public double getCompressorCurrent() {
|
||||
return m_module.getCompressorCurrent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PCM in closed loop control mode.
|
||||
*
|
||||
* @param on if true sets the compressor to be in closed loop control mode (default)
|
||||
*/
|
||||
public void setClosedLoopControl(boolean on) {
|
||||
m_module.setClosedLoopControl(on);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current operating mode of the PCM.
|
||||
*
|
||||
* @return true if compressor is operating on closed-loop mode
|
||||
*/
|
||||
public boolean getClosedLoopControl() {
|
||||
return m_module.getClosedLoopControl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Compressor");
|
||||
builder.addBooleanProperty(
|
||||
"Closed Loop Control", this::getClosedLoopControl, this::setClosedLoopControl);
|
||||
builder.addBooleanProperty("Enabled", this::enabled, null);
|
||||
builder.addBooleanProperty("Pressure switch", this::getPressureSwitchValue, null);
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,10 @@ import edu.wpi.first.hal.util.AllocationException;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* DoubleSolenoid class for running 2 channels of high voltage Digital Output on the PCM.
|
||||
* DoubleSolenoid class for running 2 channels of high voltage Digital Output on the pneumatics
|
||||
* module.
|
||||
*
|
||||
* <p>The DoubleSolenoid class is typically used for pneumatics solenoids that have two positions
|
||||
* controlled by two separate channels.
|
||||
@@ -34,22 +34,33 @@ public class DoubleSolenoid implements Sendable, AutoCloseable {
|
||||
private final int m_reverseChannel;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructs a double solenoid for a default module of a specific module type.
|
||||
*
|
||||
* @param moduleType The module type to use.
|
||||
* @param forwardChannel The forward channel on the module to control.
|
||||
* @param reverseChannel The reverse channel on the module to control.
|
||||
*/
|
||||
public DoubleSolenoid(
|
||||
final PneumaticsModuleType moduleType, final int forwardChannel, final int reverseChannel) {
|
||||
this(PneumaticsBase.getDefaultForType(moduleType), moduleType, forwardChannel, reverseChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a double solenoid for a specified module of a specific module type.
|
||||
*
|
||||
* @param module The module of the solenoid module to use.
|
||||
* @param forwardChannel The forward channel on the module to control (0..7).
|
||||
* @param reverseChannel The reverse channel on the module to control (0..7).
|
||||
* @param moduleType The module type to use.
|
||||
* @param forwardChannel The forward channel on the module to control.
|
||||
* @param reverseChannel The reverse channel on the module to control.
|
||||
*/
|
||||
public DoubleSolenoid(PneumaticsBase module, final int forwardChannel, final int reverseChannel) {
|
||||
m_module = Objects.requireNonNull(module, "Module cannot be null");
|
||||
|
||||
if (!module.checkSolenoidChannel(forwardChannel)) {
|
||||
throw new IllegalArgumentException("Channel " + forwardChannel + " out of range");
|
||||
}
|
||||
|
||||
if (!module.checkSolenoidChannel(reverseChannel)) {
|
||||
throw new IllegalArgumentException("Channel " + reverseChannel + " out of range");
|
||||
}
|
||||
public DoubleSolenoid(
|
||||
final int module,
|
||||
final PneumaticsModuleType moduleType,
|
||||
final int forwardChannel,
|
||||
final int reverseChannel) {
|
||||
m_module = PneumaticsBase.getForType(module, moduleType);
|
||||
boolean allocatedSolenoids = false;
|
||||
boolean successfulCompletion = false;
|
||||
|
||||
m_forwardChannel = forwardChannel;
|
||||
m_reverseChannel = reverseChannel;
|
||||
@@ -58,29 +69,49 @@ public class DoubleSolenoid implements Sendable, AutoCloseable {
|
||||
m_reverseMask = 1 << reverseChannel;
|
||||
m_mask = m_forwardMask | m_reverseMask;
|
||||
|
||||
int allocMask = module.checkAndReserveSolenoids(m_mask);
|
||||
if (allocMask != 0) {
|
||||
if (allocMask == m_mask) {
|
||||
throw new AllocationException(
|
||||
"Channels " + forwardChannel + " and " + reverseChannel + " already allocated");
|
||||
} else if (allocMask == m_forwardMask) {
|
||||
throw new AllocationException("Channel " + forwardChannel + " already allocated");
|
||||
} else {
|
||||
throw new AllocationException("Channel " + reverseChannel + " already allocated");
|
||||
try {
|
||||
if (!m_module.checkSolenoidChannel(forwardChannel)) {
|
||||
throw new IllegalArgumentException("Channel " + forwardChannel + " out of range");
|
||||
}
|
||||
|
||||
if (!m_module.checkSolenoidChannel(reverseChannel)) {
|
||||
throw new IllegalArgumentException("Channel " + reverseChannel + " out of range");
|
||||
}
|
||||
|
||||
int allocMask = m_module.checkAndReserveSolenoids(m_mask);
|
||||
if (allocMask != 0) {
|
||||
if (allocMask == m_mask) {
|
||||
throw new AllocationException(
|
||||
"Channels " + forwardChannel + " and " + reverseChannel + " already allocated");
|
||||
} else if (allocMask == m_forwardMask) {
|
||||
throw new AllocationException("Channel " + forwardChannel + " already allocated");
|
||||
} else {
|
||||
throw new AllocationException("Channel " + reverseChannel + " already allocated");
|
||||
}
|
||||
}
|
||||
allocatedSolenoids = true;
|
||||
|
||||
HAL.report(
|
||||
tResourceType.kResourceType_Solenoid, forwardChannel + 1, m_module.getModuleNumber() + 1);
|
||||
HAL.report(
|
||||
tResourceType.kResourceType_Solenoid, reverseChannel + 1, m_module.getModuleNumber() + 1);
|
||||
SendableRegistry.addLW(this, "DoubleSolenoid", m_module.getModuleNumber(), forwardChannel);
|
||||
successfulCompletion = true;
|
||||
} finally {
|
||||
if (!successfulCompletion) {
|
||||
if (allocatedSolenoids) {
|
||||
m_module.unreserveSolenoids(m_mask);
|
||||
}
|
||||
m_module.close();
|
||||
}
|
||||
}
|
||||
|
||||
HAL.report(
|
||||
tResourceType.kResourceType_Solenoid, forwardChannel + 1, module.getModuleNumber() + 1);
|
||||
HAL.report(
|
||||
tResourceType.kResourceType_Solenoid, reverseChannel + 1, module.getModuleNumber() + 1);
|
||||
SendableRegistry.addLW(this, "DoubleSolenoid", module.getModuleNumber(), forwardChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
SendableRegistry.remove(this);
|
||||
m_module.unreserveSolenoids(m_mask);
|
||||
m_module.close();
|
||||
m_module = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,33 @@
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
public interface PneumaticsBase extends AutoCloseable {
|
||||
/**
|
||||
* For internal use to get a module for a specific type.
|
||||
*
|
||||
* @param module module number
|
||||
* @param type module type
|
||||
* @return module
|
||||
*/
|
||||
static PneumaticsControlModule getForType(int module, PneumaticsModuleType type) {
|
||||
if (type == PneumaticsModuleType.CTREPCM) {
|
||||
return new PneumaticsControlModule();
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown module type");
|
||||
}
|
||||
|
||||
/**
|
||||
* For internal use to get the default for a specific type.
|
||||
*
|
||||
* @param type module type
|
||||
* @return module default
|
||||
*/
|
||||
static int getDefaultForType(PneumaticsModuleType type) {
|
||||
if (type == PneumaticsModuleType.CTREPCM) {
|
||||
return SensorUtil.getDefaultCTREPCMModule();
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown module type");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets solenoids on a pneumatics module.
|
||||
*
|
||||
@@ -49,6 +76,16 @@ public interface PneumaticsBase extends AutoCloseable {
|
||||
*/
|
||||
void setOneShotDuration(int index, int durMs);
|
||||
|
||||
boolean getCompressor();
|
||||
|
||||
boolean getPressureSwitch();
|
||||
|
||||
double getCompressorCurrent();
|
||||
|
||||
void setClosedLoopControl(boolean on);
|
||||
|
||||
boolean getClosedLoopControl();
|
||||
|
||||
/**
|
||||
* Check if a solenoid channel is valid.
|
||||
*
|
||||
@@ -71,4 +108,17 @@ public interface PneumaticsBase extends AutoCloseable {
|
||||
* @param mask The solenoid mask to unreserve
|
||||
*/
|
||||
void unreserveSolenoids(int mask);
|
||||
|
||||
boolean reserveCompressor();
|
||||
|
||||
void unreserveCompressor();
|
||||
|
||||
@Override
|
||||
void close();
|
||||
|
||||
Solenoid makeSolenoid(int channel);
|
||||
|
||||
DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel);
|
||||
|
||||
Compressor makeCompressor();
|
||||
}
|
||||
|
||||
@@ -5,16 +5,68 @@
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import edu.wpi.first.hal.CTREPCMJNI;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PneumaticsControlModule implements PneumaticsBase, Sendable {
|
||||
/** Module class for controlling a Cross The Road Electronics Pneumatics Control Module. */
|
||||
public class PneumaticsControlModule 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 = CTREPCMJNI.initialize(module);
|
||||
m_module = module;
|
||||
m_handleMap.put(module, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
CTREPCMJNI.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;
|
||||
private final int m_module;
|
||||
private int m_reservedMask;
|
||||
private final Object m_reserveLock = new Object();
|
||||
|
||||
/** Constructs a PneumaticsControlModule with the default id (0). */
|
||||
public PneumaticsControlModule() {
|
||||
this(SensorUtil.getDefaultCTREPCMModule());
|
||||
}
|
||||
@@ -25,34 +77,36 @@ public class PneumaticsControlModule implements PneumaticsBase, Sendable {
|
||||
* @param module module number to construct
|
||||
*/
|
||||
public PneumaticsControlModule(int module) {
|
||||
m_handle = CTREPCMJNI.initialize(module);
|
||||
m_module = module;
|
||||
|
||||
SendableRegistry.addLW(this, "Compressor", module);
|
||||
m_dataStore = getForModule(module);
|
||||
m_handle = m_dataStore.m_handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
CTREPCMJNI.free(m_handle);
|
||||
SendableRegistry.remove(this);
|
||||
freeModule(m_dataStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCompressor() {
|
||||
return CTREPCMJNI.getCompressor(m_handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClosedLoopControl(boolean enabled) {
|
||||
CTREPCMJNI.setClosedLoopControl(m_handle, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getClosedLoopControl() {
|
||||
return CTREPCMJNI.getClosedLoopControl(m_handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPressureSwitch() {
|
||||
return CTREPCMJNI.getPressureSwitch(m_handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCompressorCurrent() {
|
||||
return CTREPCMJNI.getCompressorCurrent(m_handle);
|
||||
}
|
||||
@@ -93,7 +147,7 @@ public class PneumaticsControlModule implements PneumaticsBase, Sendable {
|
||||
|
||||
@Override
|
||||
public int getModuleNumber() {
|
||||
return m_module;
|
||||
return m_dataStore.m_handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,28 +184,53 @@ public class PneumaticsControlModule implements PneumaticsBase, Sendable {
|
||||
|
||||
@Override
|
||||
public int checkAndReserveSolenoids(int mask) {
|
||||
synchronized (m_reserveLock) {
|
||||
if ((m_reservedMask & mask) != 0) {
|
||||
return m_reservedMask & mask;
|
||||
synchronized (m_dataStore.m_reserveLock) {
|
||||
if ((m_dataStore.m_reservedMask & mask) != 0) {
|
||||
return m_dataStore.m_reservedMask & mask;
|
||||
}
|
||||
m_reservedMask |= mask;
|
||||
m_dataStore.m_reservedMask |= mask;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unreserveSolenoids(int mask) {
|
||||
synchronized (m_reserveLock) {
|
||||
m_reservedMask &= ~mask;
|
||||
synchronized (m_dataStore.m_reserveLock) {
|
||||
m_dataStore.m_reservedMask &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initSendable(SendableBuilder builder) {
|
||||
builder.setSmartDashboardType("Compressor");
|
||||
builder.addBooleanProperty(
|
||||
"Closed Loop Control", this::getClosedLoopControl, this::setClosedLoopControl);
|
||||
builder.addBooleanProperty("Enabled", this::getCompressor, null);
|
||||
builder.addBooleanProperty("Pressure switch", this::getPressureSwitch, null);
|
||||
public Solenoid makeSolenoid(int channel) {
|
||||
return new Solenoid(m_dataStore.m_module, PneumaticsModuleType.CTREPCM, channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DoubleSolenoid makeDoubleSolenoid(int forwardChannel, int reverseChannel) {
|
||||
return new DoubleSolenoid(
|
||||
m_dataStore.m_module, PneumaticsModuleType.CTREPCM, forwardChannel, reverseChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Compressor makeCompressor() {
|
||||
return new Compressor(m_dataStore.m_module, PneumaticsModuleType.CTREPCM);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// 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;
|
||||
|
||||
public enum PneumaticsModuleType {
|
||||
CTREPCM,
|
||||
REVPH;
|
||||
}
|
||||
@@ -10,13 +10,12 @@ import edu.wpi.first.hal.util.AllocationException;
|
||||
import edu.wpi.first.util.sendable.Sendable;
|
||||
import edu.wpi.first.util.sendable.SendableBuilder;
|
||||
import edu.wpi.first.util.sendable.SendableRegistry;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Solenoid class for running high voltage Digital Output on the PCM.
|
||||
* Solenoid class for running high voltage Digital Output on a pneumatics module.
|
||||
*
|
||||
* <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any device
|
||||
* within the current spec of the PCM.
|
||||
* within the current spec of the module.
|
||||
*/
|
||||
public class Solenoid implements Sendable, AutoCloseable {
|
||||
private final int m_mask; // The channel mask
|
||||
@@ -24,33 +23,60 @@ public class Solenoid implements Sendable, AutoCloseable {
|
||||
private PneumaticsBase m_module;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Constructs a solenoid for a default module and specified type.
|
||||
*
|
||||
* @param module The PCM the solenoid is attached to.
|
||||
* @param channel The channel on the PCM to control (0..7).
|
||||
* @param moduleType The module type to use.
|
||||
* @param channel The channel the solenoid is on.
|
||||
*/
|
||||
public Solenoid(PneumaticsBase module, final int channel) {
|
||||
m_module = Objects.requireNonNull(module, "Module cannot be null");
|
||||
public Solenoid(final PneumaticsModuleType moduleType, final int channel) {
|
||||
this(PneumaticsBase.getDefaultForType(moduleType), moduleType, channel);
|
||||
}
|
||||
|
||||
if (!module.checkSolenoidChannel(channel)) {
|
||||
throw new IllegalArgumentException(); // TODO fix me
|
||||
}
|
||||
/**
|
||||
* Constructs a solenoid for a specified module and type.
|
||||
*
|
||||
* @param module The module ID to use.
|
||||
* @param moduleType The module type to use.
|
||||
* @param channel The channel the solenoid is on.
|
||||
*/
|
||||
public Solenoid(final int module, final PneumaticsModuleType moduleType, final int channel) {
|
||||
m_module = PneumaticsBase.getForType(module, moduleType);
|
||||
boolean allocatedSolenoids = false;
|
||||
boolean successfulCompletion = false;
|
||||
|
||||
m_mask = 1 << channel;
|
||||
m_channel = channel;
|
||||
|
||||
if (module.checkAndReserveSolenoids(m_mask) != 0) {
|
||||
throw new AllocationException("Solenoid already allocated");
|
||||
}
|
||||
try {
|
||||
if (!m_module.checkSolenoidChannel(channel)) {
|
||||
throw new IllegalArgumentException("Channel " + channel + " out of range");
|
||||
}
|
||||
|
||||
HAL.report(tResourceType.kResourceType_Solenoid, channel + 1, module.getModuleNumber() + 1);
|
||||
SendableRegistry.addLW(this, "Solenoid", module.getModuleNumber(), channel);
|
||||
if (m_module.checkAndReserveSolenoids(m_mask) != 0) {
|
||||
throw new AllocationException("Solenoid already allocated");
|
||||
}
|
||||
|
||||
allocatedSolenoids = true;
|
||||
|
||||
HAL.report(tResourceType.kResourceType_Solenoid, channel + 1, m_module.getModuleNumber() + 1);
|
||||
SendableRegistry.addLW(this, "Solenoid", m_module.getModuleNumber(), channel);
|
||||
successfulCompletion = true;
|
||||
|
||||
} finally {
|
||||
if (!successfulCompletion) {
|
||||
if (allocatedSolenoids) {
|
||||
m_module.unreserveSolenoids(m_mask);
|
||||
}
|
||||
m_module.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
SendableRegistry.remove(this);
|
||||
m_module.unreserveSolenoids(m_mask);
|
||||
m_module.close();
|
||||
m_module = null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user