mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-03 03:01:40 +00:00
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:
@@ -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'
|
||||
|
||||
|
||||
@@ -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?");
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 :(");
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user