Use the tool plugin to include photon-targeting into photon-core (#2137)

## Description

This allows photon-targeting to be loaded using the same mechanism as
the rest of the WPILib libraries, fixing issues with libraries not being
able to find and load their dependent libraries.

## Meta

Merge checklist:
- [x] Pull Request title is [short, imperative
summary](https://cbea.ms/git-commit/) of proposed changes
- [x] The description documents the _what_ and _why_
- [x] If this PR changes behavior or adds a feature, user documentation
is updated
- [ ] If this PR touches photon-serde, all messages have been
regenerated and hashes have not changed unexpectedly
- [ ] If this PR touches configuration, this is backwards compatible
with settings back to v2025.3.2
- [ ] If this PR touches pipeline settings or anything related to data
exchange, the frontend typing is updated
- [ ] If this PR addresses a bug, a regression test for it is added
This commit is contained in:
Gold856
2025-10-20 10:45:54 -04:00
committed by GitHub
parent b531fe6b81
commit 4f549ba579
21 changed files with 100 additions and 280 deletions

View File

@@ -8,24 +8,26 @@ apply from: "${rootDir}/shared/common.gradle"
wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get()
def nativeConfigName = 'wpilibNatives'
def nativeConfig = configurations.create(nativeConfigName)
configurations {
wpilibNatives
}
def nativeTasks = wpilibTools.createExtractionTasks {
configurationName = nativeConfigName
}
nativeTasks.addToSourceSetResources(sourceSets.main)
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpimath")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpinet")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpiutil")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("ntcore")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("cscore")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("apriltag")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("hal")
nativeConfig.dependencies.add wpilibTools.deps.wpilibOpenCv("frc" + openCVYear, wpi.versions.opencvVersion.get())
dependencies {
wpilibNatives project(path: ':photon-targeting', configuration: 'wpilibNatives')
wpilibNatives wpilibTools.deps.wpilib("wpimath")
wpilibNatives wpilibTools.deps.wpilib("wpinet")
wpilibNatives wpilibTools.deps.wpilib("wpiutil")
wpilibNatives wpilibTools.deps.wpilib("ntcore")
wpilibNatives wpilibTools.deps.wpilib("cscore")
wpilibNatives wpilibTools.deps.wpilib("apriltag")
wpilibNatives wpilibTools.deps.wpilib("hal")
wpilibNatives wpilibTools.deps.wpilibOpenCv("frc" + openCVYear, wpi.versions.opencvVersion.get())
// Zip
implementation 'org.zeroturnaround:zt-zip:1.14'

View File

@@ -25,7 +25,6 @@ import org.photonvision.common.configuration.NetworkConfig;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TimedTaskManager;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.TimeSyncClient;
import org.photonvision.jni.TimeSyncServer;
@@ -43,10 +42,6 @@ public class TimeSyncManager {
IntegerPublisher m_lastPongTimePub;
public TimeSyncManager(NetworkTable kRootTable) {
if (!PhotonTargetingJniLoader.isWorking) {
logger.error("PhotonTargetingJNI was not loaded! Cannot do time-sync");
}
this.ntInstance = kRootTable.getInstance();
// Need this subtable to be unique per coprocessor. TODO: consider using MAC address or
@@ -65,18 +60,10 @@ public class TimeSyncManager {
// Since we're spinning off tasks in a new thread, be careful and start it seperately
public void start() {
if (!PhotonTargetingJniLoader.isWorking) {
logger.error("PhotonTargetingJNI was not loaded! Cannot start");
}
TimedTaskManager.getInstance().addTask("TimeSyncManager::tick", this::tick, 1000);
}
public synchronized long getOffset() {
if (!PhotonTargetingJniLoader.isWorking) {
return 0;
}
// if we're a client, return the offset to server time
if (m_client != null) return m_client.getOffset();
// if we're a server, our time (nt::Now) is the same as network time
@@ -88,10 +75,6 @@ public class TimeSyncManager {
}
synchronized void setConfig(NetworkConfig config) {
if (!PhotonTargetingJniLoader.isWorking) {
return;
}
if (m_client == null && m_server == null) {
throw new RuntimeException("Neither client nor server are null?");
}

View File

@@ -26,14 +26,14 @@ import java.io.IOException;
import java.nio.file.Path;
import org.opencv.core.Mat;
import org.opencv.highgui.HighGui;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.vision.calibration.CameraCalibrationCoefficients;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TrackedTarget;
public class TestUtils {
public static boolean loadLibraries() {
return WpilibLoader.loadLibraries();
return LibraryLoader.loadWpiLibraries() && LibraryLoader.loadTargeting();
}
@SuppressWarnings("unused")

View File

@@ -20,7 +20,6 @@ package org.photonvision.hardware;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import org.photonvision.common.hardware.GPIO.CustomGPIO;
import org.photonvision.common.hardware.GPIO.GPIOBase;
@@ -28,17 +27,11 @@ import org.photonvision.common.hardware.GPIO.pi.PigpioPin;
import org.photonvision.common.hardware.Platform;
import org.photonvision.common.hardware.metrics.MetricsManager;
import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.PhotonTargetingJniLoader;
public class HardwareTest {
@Test
public void testHardware() {
try {
TestUtils.loadLibraries();
PhotonTargetingJniLoader.load();
} catch (UnsatisfiedLinkError | IOException e) {
e.printStackTrace();
}
TestUtils.loadLibraries();
MetricsManager mm = new MetricsManager();
if (!Platform.isRaspberryPi()) return;

View File

@@ -41,24 +41,20 @@ import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.vision.frame.provider.FileFrameProvider;
public class FileSaveFrameConsumerTest {
NetworkTableInstance inst = null;
@BeforeAll
public static void init() throws UnsatisfiedLinkError, IOException {
if (!WpilibLoader.loadLibraries()) {
public static void init() throws IOException {
if (!LibraryLoader.loadWpiLibraries()) {
fail();
}
try {
if (!PhotonTargetingJniLoader.load()) fail();
} catch (UnsatisfiedLinkError | IOException e) {
e.printStackTrace();
fail(e);
if (!LibraryLoader.loadTargeting()) {
fail();
}
}

View File

@@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import edu.wpi.first.cscore.VideoMode;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -32,7 +31,7 @@ import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.dataflow.CVPipelineResultConsumer;
import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.vision.camera.PVCameraInfo;
import org.photonvision.vision.camera.QuirkyCamera;
import org.photonvision.vision.camera.USBCameras.USBCameraSource;
@@ -48,12 +47,7 @@ public class VisionModuleManagerTest {
System.out.print(classpathStr);
TestUtils.loadLibraries();
try {
if (!PhotonTargetingJniLoader.load()) fail();
} catch (UnsatisfiedLinkError | IOException e) {
e.printStackTrace();
fail(e);
}
if (!LibraryLoader.loadTargeting()) fail();
}
private static class TestSource extends VisionSource {

View File

@@ -17,7 +17,6 @@
package org.photonvision.vision.processes;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -33,7 +32,6 @@ import org.photonvision.common.configuration.CameraConfiguration;
import org.photonvision.common.configuration.ConfigManager;
import org.photonvision.common.util.TestUtils;
import org.photonvision.common.util.file.JacksonUtils;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.vision.camera.PVCameraInfo;
public class VisionSourceManagerTest {
@@ -59,9 +57,7 @@ public class VisionSourceManagerTest {
@BeforeAll
public static void loadLibraries() {
TestUtils.loadLibraries();
assertDoesNotThrow(PhotonTargetingJniLoader::load);
assertTrue(PhotonTargetingJniLoader.isWorking);
assertTrue(TestUtils.loadLibraries());
// Broadcast all still calls into configmanager (ew) so set that up here
ConfigManager.getInstance().load();

View File

@@ -363,6 +363,9 @@ def nativeTasks = wpilibTools.createExtractionTasks {
nativeTasks.addToSourceSetResources(sourceSets.test)
dependencies {
wpilibNatives project(":photon-targeting")
}
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpimath")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpinet")
nativeConfig.dependencies.add wpilibTools.deps.wpilib("wpiutil")

View File

@@ -24,8 +24,8 @@
package org.photonvision.timesync;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.TimeSyncServer;
/** Helper to hold a single TimeSyncServer instance with some default config */
@@ -35,12 +35,11 @@ public class TimeSyncSingleton {
public static boolean load() {
if (INSTANCE == null) {
try {
if (!PhotonTargetingJniLoader.load()) {
return false;
}
} catch (UnsatisfiedLinkError | IOException e) {
RuntimeLoader.loadLibrary("photontargetingJNI");
} catch (IOException e) {
// Don't want to return early. We want to create the TimeSyncServer so the program crashes
// because we need it in order to function.
e.printStackTrace();
return false;
}
INSTANCE = new TimeSyncServer(5810);

View File

@@ -35,6 +35,7 @@ import edu.wpi.first.hal.HAL;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.networktables.NetworkTablesJNI;
import edu.wpi.first.util.RuntimeLoader;
import edu.wpi.first.wpilibj.DataLogManager;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.simulation.SimHooks;
@@ -55,9 +56,8 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.photonvision.common.dataflow.structures.Packet;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.jni.TimeSyncClient;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.simulation.PhotonCameraSim;
import org.photonvision.targeting.PhotonPipelineMetadata;
import org.photonvision.targeting.PhotonPipelineResult;
@@ -68,8 +68,9 @@ class PhotonCameraTest {
NetworkTableInstance inst = null;
@BeforeAll
public static void load_wpilib() {
WpilibLoader.loadLibraries();
public static void load() throws IOException {
LibraryLoader.loadWpiLibraries();
RuntimeLoader.loadLibrary("photontargetingJNI");
}
@BeforeEach
@@ -111,9 +112,6 @@ class PhotonCameraTest {
@Test
@Order(3)
public void testTimeSyncServerWithPhotonCamera() throws InterruptedException, IOException {
load_wpilib();
PhotonTargetingJniLoader.load();
inst.stopClient();
inst.startServer();

View File

@@ -48,6 +48,7 @@ import edu.wpi.first.math.geometry.Transform3d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.geometry.Translation3d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -59,8 +60,7 @@ import org.junit.jupiter.api.Test;
import org.photonvision.PhotonPoseEstimator.ConstrainedSolvepnpParams;
import org.photonvision.PhotonPoseEstimator.PoseStrategy;
import org.photonvision.estimation.TargetModel;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.simulation.PhotonCameraSim;
import org.photonvision.simulation.SimCameraProperties;
import org.photonvision.simulation.VisionTargetSim;
@@ -76,13 +76,11 @@ class PhotonPoseEstimatorTest {
@AutoClose final PhotonCameraInjector cameraOne = new PhotonCameraInjector();
@BeforeAll
public static void init() throws UnsatisfiedLinkError, IOException {
if (!WpilibLoader.loadLibraries()) {
fail();
}
if (!PhotonTargetingJniLoader.load()) {
public static void init() throws IOException {
if (!LibraryLoader.loadWpiLibraries()) {
fail();
}
RuntimeLoader.loadLibrary("photontargetingJNI");
HAL.initialize(1000, 0);

View File

@@ -28,7 +28,6 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.photonvision.UnitTestUtils.waitForSequenceNumber;
import edu.wpi.first.apriltag.AprilTag;
@@ -44,6 +43,7 @@ import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.geometry.Translation3d;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.util.RuntimeLoader;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import java.io.IOException;
import java.util.ArrayList;
@@ -59,8 +59,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.photonvision.estimation.TargetModel;
import org.photonvision.estimation.VisionEstimation;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.simulation.PhotonCameraSim;
import org.photonvision.simulation.VisionSystemSim;
import org.photonvision.simulation.VisionTargetSim;
@@ -72,15 +71,9 @@ class VisionSystemSimTest {
NetworkTableInstance inst;
@BeforeAll
public static void setUp() {
assertTrue(WpilibLoader.loadLibraries());
try {
assertTrue(PhotonTargetingJniLoader.load());
} catch (UnsatisfiedLinkError | IOException e) {
e.printStackTrace();
fail(e);
}
public static void setUp() throws IOException {
assertTrue(LibraryLoader.loadWpiLibraries());
RuntimeLoader.loadLibrary("photontargetingJNI");
OpenCvLoader.forceStaticLoad();
}

View File

@@ -38,7 +38,7 @@ import org.photonvision.common.logging.Logger;
import org.photonvision.common.logging.PvCSCoreLogger;
import org.photonvision.common.networking.NetworkManager;
import org.photonvision.common.util.TestUtils;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.jni.RknnDetectorJNI;
import org.photonvision.jni.RubikDetectorJNI;
import org.photonvision.mrcal.MrCalJNILoader;
@@ -205,7 +205,7 @@ public class Main {
logger.info("WPI JNI libraries loaded.");
try {
boolean success = PhotonTargetingJniLoader.load();
boolean success = LibraryLoader.loadTargeting();
if (!success) {
logger.error("Failed to load native libraries! Giving up :(");

View File

@@ -23,20 +23,6 @@ nativeUtils {
sourceSets.main.java.srcDir "${projectDir}/src/generated/main/java"
// Folder whose contents will be included in the final jar
def outputsFolder = file("$buildDir/extra_resources")
// Sync task: like the copy task, but all files that exist in the destination directory will be deleted before copying files
task syncOutputsFolder(type: Sync) {
into outputsFolder
}
// And package our outputs folder into the final jar
jar {
from outputsFolder
dependsOn syncOutputsFolder
}
model {
components {
"${nativeName}"(NativeLibrarySpec) {
@@ -115,21 +101,6 @@ model {
platName = "osxuniversal";
realWpilibName = "osxuniversal";
}
if (binary.targetPlatform.name == platName) {
// only include release binaries (hard coded for now)
def isDebug = binary.buildType.name.contains('debug')
if (!isDebug) {
syncOutputsFolder {
// Just shove the shared library into the root of the jar output by photon-targeting:jar
from(binary.sharedLibraryFile) {
into "nativelibraries/${realWpilibName}/"
}
// And (not sure if this is a hack) make the jar task depend on the build task
dependsOn binary.identifier.projectScopedName
}
}
}
}
}
}
@@ -202,27 +173,6 @@ model {
apply from: "${rootDir}/shared/javacpp/publish.gradle"
// quickly hack our raw jar into publishing
def rawjavaJar = tasks.register("rawjavaJar", Jar) {
dependsOn classes
includeEmptyDirs = false
from sourceSets.main.output
archiveClassifier = 'raw'
}
publishing {
publications {
rawjava(MavenPublication) {
artifact (rawjavaJar) {
classifier = null
}
artifactId = "${nativeName}-rawjava"
groupId = artifactGroupId
version = pubVersion
}
}
}
// Add photon serde headers to our published sources
cppHeadersZip {
from('src/generated/main/native/include') {
@@ -230,12 +180,6 @@ cppHeadersZip {
}
}
// make sure native libraries can be loaded in tests
test {
classpath += files(outputsFolder)
dependsOn syncOutputsFolder
}
// setup wpilib bundled native libs
wpilibTools.deps.wpilibVersion = wpi.versions.wpilibVersion.get()

View File

@@ -29,11 +29,12 @@ import edu.wpi.first.util.WPIUtilJNI;
import java.io.IOException;
import org.opencv.core.Core;
public class WpilibLoader {
private static boolean has_loaded = false;
public class LibraryLoader {
private static boolean hasWpiLoaded = false;
private static boolean hasTargetingLoaded = false;
public static boolean loadLibraries() {
if (has_loaded) return true;
public static boolean loadWpiLibraries() {
if (hasWpiLoaded) return true;
NetworkTablesJNI.Helper.setExtractOnStaticLoad(false);
WPIUtilJNI.Helper.setExtractOnStaticLoad(false);
@@ -45,10 +46,10 @@ public class WpilibLoader {
AprilTagJNI.Helper.setExtractOnStaticLoad(false);
try {
// Need to load wpiutil first before checking if the MSVC runtime is valid
CombinedRuntimeLoader.loadLibraries(WpilibLoader.class, "wpiutiljni");
CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, "wpiutiljni");
WPIUtilJNI.checkMsvcRuntime();
CombinedRuntimeLoader.loadLibraries(
WpilibLoader.class,
LibraryLoader.class,
"wpimathjni",
"ntcorejni",
"wpinetjni",
@@ -56,13 +57,25 @@ public class WpilibLoader {
"cscorejni",
"apriltagjni");
CombinedRuntimeLoader.loadLibraries(WpilibLoader.class, Core.NATIVE_LIBRARY_NAME);
has_loaded = true;
CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, Core.NATIVE_LIBRARY_NAME);
hasWpiLoaded = true;
} catch (IOException e) {
e.printStackTrace();
has_loaded = false;
hasWpiLoaded = false;
}
return has_loaded;
return hasWpiLoaded;
}
public static boolean loadTargeting() {
if (hasTargetingLoaded) return true;
try {
CombinedRuntimeLoader.loadLibraries(LibraryLoader.class, "photontargetingJNI");
hasTargetingLoaded = true;
} catch (IOException e) {
e.printStackTrace();
hasTargetingLoaded = false;
}
return hasTargetingLoaded;
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.photonvision.jni;
import edu.wpi.first.util.RuntimeLoader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import org.photonvision.common.hardware.Platform;
public class PhotonTargetingJniLoader {
public static boolean isWorking = false;
public static boolean load() throws IOException, UnsatisfiedLinkError {
if (isWorking) return true;
isWorking = load_();
return isWorking;
}
public static boolean load_() throws IOException, UnsatisfiedLinkError {
// We always extract the shared object (we could hash each so, but that's a lot
// of work)
String arch_name = Platform.getNativeLibraryFolderName();
var clazz = PhotonTargetingJniLoader.class;
for (var libraryName : List.of("photontargeting", "photontargetingJNI")) {
try {
RuntimeLoader.loadLibrary(libraryName);
continue;
} catch (Exception e) {
System.out.println("Direct library load failed; falling back to extraction");
}
var nativeLibName = System.mapLibraryName(libraryName);
var path = "/nativelibraries/" + arch_name + "/" + nativeLibName;
var in = clazz.getResourceAsStream(path);
if (in == null) {
System.err.println("Could not get resource at path " + path);
return false;
}
// It's important that we don't mangle the names of these files on Windows at
// least
var tempfolder = Files.createTempDirectory("nativeextract");
File temp = new File(tempfolder.toAbsolutePath().toString(), nativeLibName);
System.out.println(temp.getAbsolutePath().toString());
FileOutputStream fos = new FileOutputStream(temp);
int read = -1;
byte[] buffer = new byte[1024];
while ((read = in.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
fos.close();
in.close();
try {
System.load(temp.getAbsolutePath());
} catch (Throwable t) {
System.err.println("Unable to System.load " + temp.getName() + " : " + t.getMessage());
t.printStackTrace();
return false;
}
System.out.println("Successfully loaded shared object " + temp.getName());
}
return true;
}
}

View File

@@ -21,24 +21,22 @@ import static org.junit.jupiter.api.Assertions.fail;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.math.MatBuilder;
import edu.wpi.first.math.Nat;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import java.util.Arrays;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.photonvision.jni.ConstrainedSolvepnpJni;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
public class ConstrainedSolvepnpTest {
@BeforeAll
public static void load_wpilib() throws UnsatisfiedLinkError, IOException {
if (!WpilibLoader.loadLibraries()) {
fail();
}
if (!PhotonTargetingJniLoader.load()) {
public static void load() throws IOException {
if (!LibraryLoader.loadWpiLibraries()) {
fail();
}
RuntimeLoader.loadLibrary("photontargetingJNI");
HAL.initialize(1000, 0);
}

View File

@@ -28,23 +28,21 @@ import edu.wpi.first.cscore.UsbCamera;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.util.PixelFormat;
import edu.wpi.first.util.RawFrame;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.opencv.core.Mat;
import org.photonvision.jni.CscoreExtras;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.WpilibLoader;
import org.photonvision.jni.LibraryLoader;
public class CscoreExtrasTest {
@BeforeAll
public static void load_wpilib() throws UnsatisfiedLinkError, IOException {
if (!WpilibLoader.loadLibraries()) {
fail();
}
if (!PhotonTargetingJniLoader.load()) {
public static void load() throws IOException {
if (!LibraryLoader.loadWpiLibraries()) {
fail();
}
RuntimeLoader.loadLibrary("photontargetingJNI");
HAL.initialize(1000, 0);
}

View File

@@ -21,24 +21,22 @@ import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.photonvision.common.hardware.Platform;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.jni.QueuedFileLogger;
import org.photonvision.jni.WpilibLoader;
public class FileLoggerTest {
@BeforeAll
public static void load_wpilib() throws UnsatisfiedLinkError, IOException {
if (!WpilibLoader.loadLibraries()) {
fail();
}
if (!PhotonTargetingJniLoader.load()) {
public static void load() throws IOException {
if (!LibraryLoader.loadWpiLibraries()) {
fail();
}
RuntimeLoader.loadLibrary("photontargetingJNI");
HAL.initialize(1000, 0);
}

View File

@@ -17,25 +17,21 @@
package net;
import static org.junit.jupiter.api.Assertions.fail;
import edu.wpi.first.hal.HAL;
import edu.wpi.first.util.RuntimeLoader;
import java.io.IOException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.photonvision.jni.PhotonTargetingJniLoader;
import org.photonvision.jni.LibraryLoader;
import org.photonvision.jni.TimeSyncClient;
import org.photonvision.jni.TimeSyncServer;
import org.photonvision.jni.WpilibLoader;
public class TimeSyncTest {
@BeforeAll
public static void load_wpilib() throws UnsatisfiedLinkError, IOException {
WpilibLoader.loadLibraries();
if (!PhotonTargetingJniLoader.load()) {
fail();
}
public static void load() throws IOException {
LibraryLoader.loadWpiLibraries();
RuntimeLoader.loadLibrary("photontargetingJNI");
HAL.initialize(1000, 0);
}

View File

@@ -127,8 +127,14 @@ ext.createComponentZipTasks = { components, names, base, type, project, func ->
project.build.dependsOn task
project.artifacts {
task
// If the zip artifact matches the platform we're building for (either host or whatever the ArchOverride is), and it's a shared library built in release mode, add it to the list of artifacts the project exposes for use
if (key.contains(wpilibTools.getPlatformMapper().getWpilibClassifier()) && !key.contains("debug") && !key.contains("static")) {
// For more information, see https://docs.gradle.org/current/userguide/variant_model.html and the outgoingVariants task
project.artifacts.add("wpilibNatives", task)
} else {
project.artifacts {
task
}
}
addTaskToCopyAllOutputs(task)
}