[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:
Thad House
2021-09-16 18:50:27 -07:00
committed by GitHub
parent 906bfc8464
commit 60ede67abd
43 changed files with 1016 additions and 317 deletions

View File

@@ -13,8 +13,7 @@ import org.junit.jupiter.api.Test;
public class DoubleSolenoidTest {
@Test
void testValidInitialization() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3);
DoubleSolenoid solenoid = new DoubleSolenoid(pcm, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
solenoid.set(DoubleSolenoid.Value.kReverse);
assertEquals(DoubleSolenoid.Value.kReverse, solenoid.get());
@@ -28,36 +27,41 @@ public class DoubleSolenoidTest {
@Test
void testThrowForwardPortAlreadyInitialized() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(5);
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(pcm, 2)) {
assertThrows(AllocationException.class, () -> new DoubleSolenoid(pcm, 2, 3));
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(5, PneumaticsModuleType.CTREPCM, 2)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(5, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@Test
void testThrowReversePortAlreadyInitialized() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(6);
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(pcm, 3)) {
assertThrows(AllocationException.class, () -> new DoubleSolenoid(pcm, 2, 3));
try (
// Single solenoid that is reused for forward port
Solenoid solenoid = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@Test
void testThrowBothPortsAlreadyInitialized() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(6);
// Single solenoid that is reused for forward port
Solenoid solenoid0 = new Solenoid(pcm, 2);
Solenoid solenoid1 = new Solenoid(pcm, 3)) {
assertThrows(AllocationException.class, () -> new DoubleSolenoid(pcm, 2, 3));
try (
// Single solenoid that is reused for forward port
Solenoid solenoid0 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 2);
Solenoid solenoid1 = new Solenoid(6, PneumaticsModuleType.CTREPCM, 3)) {
assertThrows(
AllocationException.class,
() -> new DoubleSolenoid(6, PneumaticsModuleType.CTREPCM, 2, 3));
}
}
@Test
void testToggle() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(4);
DoubleSolenoid solenoid = new DoubleSolenoid(pcm, 2, 3)) {
try (DoubleSolenoid solenoid = new DoubleSolenoid(4, PneumaticsModuleType.CTREPCM, 2, 3)) {
// Bootstrap it into reverse
solenoid.set(DoubleSolenoid.Value.kReverse);
@@ -76,15 +80,15 @@ public class DoubleSolenoidTest {
@Test
void testInvalidForwardPort() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(0)) {
assertThrows(IllegalArgumentException.class, () -> new DoubleSolenoid(pcm, 100, 1));
}
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 100, 1));
}
@Test
void testInvalidReversePort() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(0)) {
assertThrows(IllegalArgumentException.class, () -> new DoubleSolenoid(pcm, 0, 100));
}
assertThrows(
IllegalArgumentException.class,
() -> new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 0, 100));
}
}

View File

@@ -15,8 +15,7 @@ import org.junit.jupiter.api.Test;
public class SolenoidTest {
@Test
void testValidInitialization() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3);
Solenoid solenoid = new Solenoid(pcm, 2)) {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
assertEquals(2, solenoid.getChannel());
solenoid.set(true);
@@ -29,31 +28,29 @@ public class SolenoidTest {
@Test
void testDoubleInitialization() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3);
Solenoid solenoid = new Solenoid(pcm, 2)) {
assertThrows(AllocationException.class, () -> new Solenoid(pcm, 2));
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
assertThrows(
AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
}
}
@Test
void testDoubleInitializationFromDoubleSolenoid() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3);
DoubleSolenoid solenoid = new DoubleSolenoid(pcm, 2, 3)) {
assertThrows(AllocationException.class, () -> new Solenoid(pcm, 2));
try (DoubleSolenoid solenoid = new DoubleSolenoid(3, PneumaticsModuleType.CTREPCM, 2, 3)) {
assertThrows(
AllocationException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 2));
}
}
@Test
void testInvalidChannel() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3)) {
assertThrows(IllegalArgumentException.class, () -> new Solenoid(pcm, 100));
}
assertThrows(
IllegalArgumentException.class, () -> new Solenoid(3, PneumaticsModuleType.CTREPCM, 100));
}
@Test
void testToggle() {
try (PneumaticsControlModule pcm = new PneumaticsControlModule(3);
Solenoid solenoid = new Solenoid(pcm, 2)) {
try (Solenoid solenoid = new Solenoid(3, PneumaticsModuleType.CTREPCM, 2)) {
solenoid.set(true);
assertTrue(solenoid.get());

View File

@@ -12,6 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.wpilibj.DoubleSolenoid;
import edu.wpi.first.wpilibj.PneumaticsControlModule;
import edu.wpi.first.wpilibj.PneumaticsModuleType;
import edu.wpi.first.wpilibj.simulation.testutils.BooleanCallback;
import edu.wpi.first.wpilibj.simulation.testutils.DoubleCallback;
import org.junit.jupiter.api.Test;
@@ -32,6 +33,7 @@ class CTREPCMSimTest {
PneumaticsControlModule pcm = new PneumaticsControlModule(0)) {
assertTrue(sim.getInitialized());
}
assertFalse(sim.getInitialized());
}
@Test
@@ -39,8 +41,8 @@ class CTREPCMSimTest {
HAL.initialize(500, 0);
try (PneumaticsControlModule pcm = new PneumaticsControlModule(0);
DoubleSolenoid doubleSolenoid = new DoubleSolenoid(pcm, 3, 4)) {
CTREPCMSim sim = new CTREPCMSim(pcm);
DoubleSolenoid doubleSolenoid = new DoubleSolenoid(0, PneumaticsModuleType.CTREPCM, 3, 4)) {
CTREPCMSim sim = new CTREPCMSim(0);
sim.resetData();
BooleanCallback callback3 = new BooleanCallback();
@@ -75,11 +77,14 @@ class CTREPCMSimTest {
// Off
callback3.reset();
callback4.reset();
doubleSolenoid.set(DoubleSolenoid.Value.kForward);
assertFalse(callback3.wasTriggered());
assertNull(callback3.getSetValue());
doubleSolenoid.set(DoubleSolenoid.Value.kOff);
assertTrue(callback3.wasTriggered());
assertFalse(callback3.getSetValue());
assertFalse(callback4.wasTriggered());
assertNull(callback4.getSetValue());
assertFalse(sim.getSolenoidOutput(3));
assertFalse(sim.getSolenoidOutput(4));
assertEquals(0x0, pcm.getSolenoids());
}
}
}