diff --git a/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java b/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java index 87c61e8279c..2c6837d49c9 100644 --- a/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java +++ b/apriltag/src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java @@ -18,8 +18,8 @@ public class AprilTagJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. @@ -55,6 +55,19 @@ private Helper() {} } } + /** + * Force load the library. + * + * @throws IOException if library load failed + */ + public static synchronized void forceLoad() throws IOException { + if (libraryLoaded) { + return; + } + RuntimeLoader.loadLibrary("apriltagjni"); + libraryLoaded = true; + } + /** * Constructs an AprilTag detector engine. * diff --git a/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagJniTestExtension.java b/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagJniTestExtension.java new file mode 100644 index 00000000000..e5345103b2c --- /dev/null +++ b/apriltag/src/test/java/edu/wpi/first/apriltag/AprilTagJniTestExtension.java @@ -0,0 +1,40 @@ +// 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.apriltag; + +import edu.wpi.first.apriltag.jni.AprilTagJNI; +import edu.wpi.first.util.WPIUtilJNI; +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class AprilTagJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(AprilTagJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "April Tag Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + AprilTagJNI.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/apriltag/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/apriltag/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..149d61ac0e7 --- /dev/null +++ b/apriltag/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.apriltag.AprilTagJniTestExtension diff --git a/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java b/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java index b0ac27aef53..ec2b79ee1eb 100644 --- a/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java +++ b/cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java @@ -16,8 +16,8 @@ public class CameraServerJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java b/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java index d6df2eec926..f16866ded12 100644 --- a/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java +++ b/cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java @@ -16,7 +16,7 @@ public final class OpenCvLoader { /** Sets whether JNI should be loaded in the static block. */ public static final class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/cscore/src/test/java/edu/wpi/first/cscore/CameraServerJniTestExtension.java b/cscore/src/test/java/edu/wpi/first/cscore/CameraServerJniTestExtension.java new file mode 100644 index 00000000000..fba8ba7a5ab --- /dev/null +++ b/cscore/src/test/java/edu/wpi/first/cscore/CameraServerJniTestExtension.java @@ -0,0 +1,41 @@ +// 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.cscore; + +import edu.wpi.first.util.WPIUtilJNI; + +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class CameraServerJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(CameraServerJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "CsCore Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + CameraServerJNI.forceLoad(); + OpenCvLoader.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/cscore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/cscore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..3e39d456fc1 --- /dev/null +++ b/cscore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.cscore.CameraServerJniTestExtension diff --git a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java index 5cc2e126558..44f14bf36ba 100644 --- a/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java +++ b/hal/src/main/java/edu/wpi/first/hal/JNIWrapper.java @@ -13,8 +13,8 @@ public class JNIWrapper { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/hal/src/test/java/edu/wpi/first/hal/HalJniTestExtension.java b/hal/src/test/java/edu/wpi/first/hal/HalJniTestExtension.java new file mode 100644 index 00000000000..05aa5a51096 --- /dev/null +++ b/hal/src/test/java/edu/wpi/first/hal/HalJniTestExtension.java @@ -0,0 +1,39 @@ +// 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.hal; + +import edu.wpi.first.util.WPIUtilJNI; +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class HalJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(HalJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "HAL Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + JNIWrapper.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/hal/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/hal/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..8c64204de27 --- /dev/null +++ b/hal/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.hal.HalJniTestExtension diff --git a/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja b/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja index 17d15c17540..2bc02ddee89 100644 --- a/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja +++ b/ntcore/src/generate/main/java/NetworkTablesJNI.java.jinja @@ -19,8 +19,8 @@ public final class NetworkTablesJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java b/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java index 4741f7642a7..20bc953fab1 100644 --- a/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java +++ b/ntcore/src/generated/main/java/edu/wpi/first/networktables/NetworkTablesJNI.java @@ -19,8 +19,8 @@ public final class NetworkTablesJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/ntcore/src/test/java/edu/wpi/first/networktables/NetworkTablesJniTestExtension.java b/ntcore/src/test/java/edu/wpi/first/networktables/NetworkTablesJniTestExtension.java new file mode 100644 index 00000000000..7941b28ba54 --- /dev/null +++ b/ntcore/src/test/java/edu/wpi/first/networktables/NetworkTablesJniTestExtension.java @@ -0,0 +1,40 @@ +// 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.networktables; + +import edu.wpi.first.util.WPIUtilJNI; + +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class NetworkTablesJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(NetworkTablesJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "Ntcore Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + NetworkTablesJNI.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/ntcore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/ntcore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..178c9c4f7eb --- /dev/null +++ b/ntcore/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.networktables.NetworkTablesJniTestExtension diff --git a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/MockHardwareExtension.java b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/MockHardwareExtension.java index 2de1a075833..dfb3b353259 100644 --- a/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/MockHardwareExtension.java +++ b/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/MockHardwareExtension.java @@ -4,8 +4,9 @@ package edu.wpi.first.wpilibj2; -import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.simulation.DriverStationSim; + import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; @@ -29,7 +30,8 @@ public void beforeAll(ExtensionContext context) { } private void initializeHardware() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + DriverStationSim.setDsAttached(true); DriverStationSim.setAutonomous(false); DriverStationSim.setEnabled(true); diff --git a/wpilibj/CMakeLists.txt b/wpilibj/CMakeLists.txt index 440f7585592..518fd3fd137 100644 --- a/wpilibj/CMakeLists.txt +++ b/wpilibj/CMakeLists.txt @@ -38,8 +38,10 @@ if(WITH_JAVA) ${OPENCV_JAR_FILE} cscore_jar cameraserver_jar + apriltag_jar wpimath_jar wpiunits_jar + wpinet_jar wpiutil_jar OUTPUT_NAME wpilibj OUTPUT_DIR ${WPILIB_BINARY_DIR}/${java_lib_dest} diff --git a/wpilibj/build.gradle b/wpilibj/build.gradle index d397f934801..a767773a55a 100644 --- a/wpilibj/build.gradle +++ b/wpilibj/build.gradle @@ -70,6 +70,7 @@ dependencies { implementation project(':ntcore') implementation project(':cscore') implementation project(':cameraserver') + implementation project(':apriltag') testImplementation 'org.mockito:mockito-core:4.1.0' devImplementation sourceSets.main.output } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java index 2de7cf1ce86..c20d82a4acd 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/RobotBase.java @@ -4,17 +4,24 @@ package edu.wpi.first.wpilibj; +import edu.wpi.first.apriltag.jni.AprilTagJNI; import edu.wpi.first.cameraserver.CameraServerShared; import edu.wpi.first.cameraserver.CameraServerSharedStore; +import edu.wpi.first.cscore.CameraServerJNI; +import edu.wpi.first.cscore.OpenCvLoader; import edu.wpi.first.hal.FRCNetComm.tInstances; import edu.wpi.first.hal.FRCNetComm.tResourceType; import edu.wpi.first.hal.HAL; import edu.wpi.first.hal.HALUtil; +import edu.wpi.first.hal.JNIWrapper; import edu.wpi.first.math.MathShared; import edu.wpi.first.math.MathSharedStore; import edu.wpi.first.math.MathUsageId; +import edu.wpi.first.math.jni.WPIMathJNI; +import edu.wpi.first.net.WPINetJNI; import edu.wpi.first.networktables.MultiSubscriber; import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.NetworkTablesJNI; import edu.wpi.first.util.WPIUtilJNI; import edu.wpi.first.wpilibj.livewindow.LiveWindow; import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; @@ -390,6 +397,50 @@ public static void suppressExitWarning(boolean value) { m_runMutex.unlock(); } + /** + * Loads base native libraries needed by WPILib in all robot projects. + * + * @throws IOException If any library was not found + */ + public static void loadBaseNativeLibraries() throws IOException { + WPIUtilJNI.forceLoad(); + WPINetJNI.forceLoad(); + WPIMathJNI.forceLoad(); + JNIWrapper.forceLoad(); + NetworkTablesJNI.forceLoad(); + } + + /** + * Sets the static load behavior for all of the vision libraries + * + * @param loadOnStaticInitialization true to load on static initialization, false to disable (default) + */ + public static void setVisionNativeLibrariesStaticLoadBehavior(boolean loadOnStaticInitialization) { + CameraServerJNI.Helper.setExtractOnStaticLoad(true); + OpenCvLoader.Helper.setExtractOnStaticLoad(true); + AprilTagJNI.Helper.setExtractOnStaticLoad(true); + } + + /** + * Configure all native libraries to match how a robot program works. + * + *

This will load all the base JNI libraries, set the vision libaries + * to load on static initialization, and initialize the HAL. + * + * @return HAL initialization result, true for success. + */ + public static boolean loadLibrariesAndInitializeHal() { + try { + loadBaseNativeLibraries(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + setVisionNativeLibrariesStaticLoadBehavior(true); + + return HAL.initialize(500, 0); + } + /** * Starting point for the applications. * @@ -397,7 +448,7 @@ public static void suppressExitWarning(boolean value) { * @param robotSupplier Function that returns an instance of the robot subclass. */ public static void startRobot(Supplier robotSupplier) { - if (!HAL.initialize(500, 0)) { + if (!loadLibrariesAndInitializeHal()) { throw new IllegalStateException("Failed to initialize. Terminating"); } diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java index e70f182a3b3..e4c5fd6f00b 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/MockHardwareExtension.java @@ -4,8 +4,8 @@ package edu.wpi.first.wpilibj; -import edu.wpi.first.hal.HAL; import edu.wpi.first.wpilibj.simulation.DriverStationSim; + import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ExtensionContext.Namespace; @@ -29,7 +29,8 @@ public void beforeAll(ExtensionContext context) { } private void initializeHardware() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + DriverStationSim.setDsAttached(true); DriverStationSim.setAutonomous(false); DriverStationSim.setEnabled(true); diff --git a/wpilibjExamples/networktables.json.bck b/wpilibjExamples/networktables.json.bck new file mode 100644 index 00000000000..9f2529c0e80 --- /dev/null +++ b/wpilibjExamples/networktables.json.bck @@ -0,0 +1,3 @@ +[ + +] diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/armsimulation/ArmSimulationTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/armsimulation/ArmSimulationTest.java index eeb5e74ea3a..7c1b80c7156 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/armsimulation/ArmSimulationTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/armsimulation/ArmSimulationTest.java @@ -7,9 +7,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import edu.wpi.first.hal.HAL; import edu.wpi.first.math.util.Units; import edu.wpi.first.wpilibj.Preferences; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.simulation.EncoderSim; import edu.wpi.first.wpilibj.simulation.JoystickSim; @@ -33,7 +33,8 @@ class ArmSimulationTest { @BeforeEach void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_robot = new Robot(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/digitalcommunication/DigitalCommunicationTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/digitalcommunication/DigitalCommunicationTest.java index 9f11dc9e3ce..dd54b7deadf 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/digitalcommunication/DigitalCommunicationTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/digitalcommunication/DigitalCommunicationTest.java @@ -9,7 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import edu.wpi.first.hal.AllianceStationID; -import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.simulation.DIOSim; import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.simulation.SimHooks; @@ -31,7 +31,8 @@ class DigitalCommunicationTest { @BeforeEach void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_robot = new Robot(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/elevatorsimulation/ElevatorSimulationTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/elevatorsimulation/ElevatorSimulationTest.java index 7faeec68f33..fd531378e7a 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/elevatorsimulation/ElevatorSimulationTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/elevatorsimulation/ElevatorSimulationTest.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.simulation.EncoderSim; import edu.wpi.first.wpilibj.simulation.JoystickSim; @@ -30,7 +30,8 @@ class ElevatorSimulationTest { @BeforeEach void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_robot = new Robot(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/i2ccommunication/I2CCommunicationTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/i2ccommunication/I2CCommunicationTest.java index 278f97f9d87..b166cc880b9 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/i2ccommunication/I2CCommunicationTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/i2ccommunication/I2CCommunicationTest.java @@ -9,8 +9,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import edu.wpi.first.hal.AllianceStationID; -import edu.wpi.first.hal.HAL; import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.simulation.CallbackStore; import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.simulation.I2CSim; @@ -34,7 +34,8 @@ class I2CCommunicationTest { @BeforeEach void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_future = new CompletableFuture<>(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/potentiometerpid/PotentiometerPIDTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/potentiometerpid/PotentiometerPIDTest.java index 8a3d92b8e66..ebf7256a450 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/potentiometerpid/PotentiometerPIDTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/potentiometerpid/PotentiometerPIDTest.java @@ -11,6 +11,7 @@ import edu.wpi.first.hal.HAL.SimPeriodicBeforeCallback; import edu.wpi.first.math.system.plant.DCMotor; import edu.wpi.first.math.util.Units; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.RobotController; import edu.wpi.first.wpilibj.simulation.AnalogInputSim; import edu.wpi.first.wpilibj.simulation.DriverStationSim; @@ -41,7 +42,8 @@ class PotentiometerPIDTest { @BeforeEach void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_robot = new Robot(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/ultrasonicpid/UltrasonicPIDTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/ultrasonicpid/UltrasonicPIDTest.java index f0a27b8f9c0..2d2ff28fc99 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/ultrasonicpid/UltrasonicPIDTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/ultrasonicpid/UltrasonicPIDTest.java @@ -11,6 +11,7 @@ import edu.wpi.first.hal.HAL.SimPeriodicBeforeCallback; import edu.wpi.first.math.system.plant.DCMotor; import edu.wpi.first.math.system.plant.LinearSystemId; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.RobotController; import edu.wpi.first.wpilibj.simulation.DifferentialDrivetrainSim; import edu.wpi.first.wpilibj.simulation.DifferentialDrivetrainSim.KitbotGearing; @@ -50,7 +51,8 @@ class UltrasonicPIDTest { // We're not using @BeforeEach so m_startToObject gets initialized properly private void startThread() { - HAL.initialize(500, 0); + RobotBase.loadLibrariesAndInitializeHal(); + SimHooks.pauseTiming(); DriverStationSim.resetData(); m_robot = new Robot(); diff --git a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/unittest/subsystems/IntakeTest.java b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/unittest/subsystems/IntakeTest.java index 33be835ef81..44a9c1d39b6 100644 --- a/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/unittest/subsystems/IntakeTest.java +++ b/wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/unittest/subsystems/IntakeTest.java @@ -6,9 +6,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import edu.wpi.first.hal.HAL; import edu.wpi.first.wpilibj.DoubleSolenoid; import edu.wpi.first.wpilibj.PneumaticsModuleType; +import edu.wpi.first.wpilibj.RobotBase; import edu.wpi.first.wpilibj.examples.unittest.Constants.IntakeConstants; import edu.wpi.first.wpilibj.simulation.DoubleSolenoidSim; import edu.wpi.first.wpilibj.simulation.PWMSim; @@ -24,7 +24,7 @@ class IntakeTest { @BeforeEach // this method will run before each test void setup() { - assert HAL.initialize(500, 0); // initialize the HAL, crash if failed + assert RobotBase.loadLibrariesAndInitializeHal(); // initialize the HAL, crash if failed m_intake = new Intake(); // create our intake m_simMotor = new PWMSim(IntakeConstants.kMotorPort); // create our simulation PWM motor controller diff --git a/wpimath/src/main/java/edu/wpi/first/math/jni/WPIMathJNI.java b/wpimath/src/main/java/edu/wpi/first/math/jni/WPIMathJNI.java index 8b16e7a1895..b73afb49bae 100644 --- a/wpimath/src/main/java/edu/wpi/first/math/jni/WPIMathJNI.java +++ b/wpimath/src/main/java/edu/wpi/first/math/jni/WPIMathJNI.java @@ -13,8 +13,8 @@ public class WPIMathJNI { private static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/wpimath/src/test/java/edu/wpi/first/math/MathJniTestExtension.java b/wpimath/src/test/java/edu/wpi/first/math/MathJniTestExtension.java new file mode 100644 index 00000000000..1164bf79e75 --- /dev/null +++ b/wpimath/src/test/java/edu/wpi/first/math/MathJniTestExtension.java @@ -0,0 +1,41 @@ +// 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.math; + +import edu.wpi.first.math.jni.WPIMathJNI; +import edu.wpi.first.util.WPIUtilJNI; + +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class MathJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(MathJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "Ntcore Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + WPIMathJNI.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/wpimath/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/wpimath/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..2501701d073 --- /dev/null +++ b/wpimath/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.math.MathJniTestExtension diff --git a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java index 084f0220f54..bb11cef55ec 100644 --- a/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java +++ b/wpinet/src/main/java/edu/wpi/first/net/WPINetJNI.java @@ -13,8 +13,8 @@ public class WPINetJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/wpinet/src/test/java/edu/wpi/first/net/WPINetJNITest.java b/wpinet/src/test/java/edu/wpi/first/net/WPINetJNITest.java index dfa6d4d952d..98fa45ba795 100644 --- a/wpinet/src/test/java/edu/wpi/first/net/WPINetJNITest.java +++ b/wpinet/src/test/java/edu/wpi/first/net/WPINetJNITest.java @@ -4,12 +4,13 @@ package edu.wpi.first.net; -import java.io.IOException; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + import org.junit.jupiter.api.Test; public class WPINetJNITest { @Test - void jniLinkTest() throws IOException { - WPINetJNI.forceLoad(); + void jniLinkTest() { + assertDoesNotThrow(WPINetJNI::forceLoad); } } diff --git a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java index 58e69c34bc2..5127e6da9a5 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java @@ -13,8 +13,8 @@ public class WPIUtilJNI { static boolean libraryLoaded = false; /** Sets whether JNI should be loaded in the static block. */ - public static class Helper { - private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true); + public static final class Helper { + private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(false); /** * Returns true if the JNI should be loaded in the static block. diff --git a/wpiutil/src/test/java/edu/wpi/first/util/WPIUtilJniTestExtension.java b/wpiutil/src/test/java/edu/wpi/first/util/WPIUtilJniTestExtension.java new file mode 100644 index 00000000000..a3e95c1d4fe --- /dev/null +++ b/wpiutil/src/test/java/edu/wpi/first/util/WPIUtilJniTestExtension.java @@ -0,0 +1,37 @@ +// 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.util; + +import java.io.IOException; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; + +public final class WPIUtilJniTestExtension implements BeforeAllCallback { + private static ExtensionContext getRoot(ExtensionContext context) { + return context.getParent().map(WPIUtilJniTestExtension::getRoot).orElse(context); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + getRoot(context) + .getStore(Namespace.GLOBAL) + .getOrComputeIfAbsent( + "WPIUtil Initialized", + key -> { + initializeNatives(); + return true; + }, + Boolean.class); + } + + private void initializeNatives() { + try { + WPIUtilJNI.forceLoad(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/wpiutil/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/wpiutil/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension new file mode 100644 index 00000000000..53f1deb9372 --- /dev/null +++ b/wpiutil/src/test/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -0,0 +1 @@ +edu.wpi.first.util.WPIUtilJniTestExtension