diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java b/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java index c12d883ccb..023394ee23 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/PVCameraInfo.java @@ -102,6 +102,8 @@ public String name() { @Override public String uniquePath() { return Arrays.stream(super.otherPaths) + .sorted() // Must sort to ensure a consistent unique path as we can get more than one + // by-path and their order changes at random? .filter(path -> path.contains("/by-path/")) .findFirst() .orElse(path()); diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionSourceManager.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionSourceManager.java index fd0e0d7441..fa3cb2f41e 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionSourceManager.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionSourceManager.java @@ -213,6 +213,7 @@ public synchronized boolean assignUnmatchedCamera(PVCameraInfo cameraInfo) { .equals(cameraInfo.uniquePath()))) { logger.error( "Camera unique-path already in use by active VisionModule! Cannot add " + cameraInfo); + return false; } var source = loadVisionSourceFromCamConfig(new CameraConfiguration(cameraInfo)); diff --git a/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java b/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java index fddeb8e3fb..06cd97b10a 100644 --- a/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java +++ b/photon-core/src/test/java/org/photonvision/vision/processes/VisionSourceManagerTest.java @@ -193,6 +193,47 @@ public void testEnabledDisabled() throws InterruptedException { vsm.teardown(); } + @Test + public void testOtherPathsOrderChange() throws InterruptedException { + // GIVEN a VSM + var vsm = new TestVsm(); + // AND one camera and camera config with flipped otherpaths order + var cam = + PVCameraInfo.fromUsbCameraInfo( + new UsbCameraInfo( + 0, + "/dev/video0", + "Lifecam HD-3000", + new String[] {"/dev/v4l/by-path/usbv2/foobar1", "/dev/v4l/by-path/usb/foobar1"}, + 5940, + 5940)); + + var camOtherPaths = + PVCameraInfo.fromUsbCameraInfo( + new UsbCameraInfo( + 1, + "/dev/video1", + "Lifecam HD-3000", + new String[] {"/dev/v4l/by-path/usb/foobar1", "/dev/v4l/by-path/usbv2/foobar1"}, + 5940, + 5940)); + CameraConfiguration camOtherPathsConf = new CameraConfiguration(camOtherPaths); + camOtherPathsConf.nickname = "TestCamera"; + camOtherPathsConf.deactivated = false; + + vsm.registerLoadedConfigs(List.of(camOtherPathsConf)); + + vsm.assignUnmatchedCamera(cam); + + assertEquals(0, vsm.getVsmState().disabledConfigs.size()); + assertEquals(1, vsm.vmm.getModules().size()); + assertEquals(cam.uniquePath(), camOtherPaths.uniquePath()); + + Thread.sleep(2000); + + vsm.teardown(); + } + @Test public void testDuplicate() throws InterruptedException, IOException { var fileCamera1 =