diff --git a/docs/source/docs/contributing/building-photon.md b/docs/source/docs/contributing/building-photon.md index 3ae9e19893..ec2c92cbe3 100644 --- a/docs/source/docs/contributing/building-photon.md +++ b/docs/source/docs/contributing/building-photon.md @@ -290,5 +290,5 @@ Then, run the examples: Using the [GitHub CLI](https://cli.github.com/), we can download artifacts from pipelines by run ID and name: ``` -~/photonvision$ gh run download 11759699679 -n jar-Linux +~/photonvision$ gh run download 11759699679 -n jar-Linux ``` diff --git a/photon-client/src/components/app/photon-sidebar.vue b/photon-client/src/components/app/photon-sidebar.vue index ac8636d521..16a784b4da 100644 --- a/photon-client/src/components/app/photon-sidebar.vue +++ b/photon-client/src/components/app/photon-sidebar.vue @@ -40,7 +40,7 @@ const mdAndUp = computed(() => getCurrentInstance()?.proxy.$vuetify.bre mdi-camera - Cameras + Camera @@ -51,6 +51,14 @@ const mdAndUp = computed(() => getCurrentInstance()?.proxy.$vuetify.bre Settings + + + mdi-notebook + + + Camera Configs + + mdi-bookshelf diff --git a/photon-client/src/router/index.ts b/photon-client/src/router/index.ts index 9e3e78f259..ed3645c936 100644 --- a/photon-client/src/router/index.ts +++ b/photon-client/src/router/index.ts @@ -6,6 +6,7 @@ import CameraSettingsView from "@/views/CameraSettingsView.vue"; import GeneralSettingsView from "@/views/GeneralSettingsView.vue"; import DocsView from "@/views/DocsView.vue"; import NotFoundView from "@/views/NotFoundView.vue"; +import CameraMatchingView from "@/views/CameraMatchingView.vue"; Vue.use(VueRouter); @@ -33,6 +34,11 @@ const router = new VueRouter({ name: "Settings", component: GeneralSettingsView }, + { + path: "/cameraConfigs", + name: "Camera Configs", + component: CameraMatchingView + }, { path: "/docs", name: "Docs", diff --git a/photon-client/src/stores/settings/CameraSettingsStore.ts b/photon-client/src/stores/settings/CameraSettingsStore.ts index 5ab00eac71..97b4575d67 100644 --- a/photon-client/src/stores/settings/CameraSettingsStore.ts +++ b/photon-client/src/stores/settings/CameraSettingsStore.ts @@ -88,6 +88,8 @@ export const useCameraSettingsStore = defineStore("cameraSettings", { actions: { updateCameraSettingsFromWebsocket(data: WebsocketCameraSettingsUpdate[]) { const configuredCameras = data.map((d) => ({ + cameraPath: d.cameraPath, + nickname: d.nickname, uniqueName: d.uniqueName, fov: { diff --git a/photon-client/src/stores/settings/GeneralSettingsStore.ts b/photon-client/src/stores/settings/GeneralSettingsStore.ts index f5940789fa..66e41e3c0e 100644 --- a/photon-client/src/stores/settings/GeneralSettingsStore.ts +++ b/photon-client/src/stores/settings/GeneralSettingsStore.ts @@ -4,7 +4,8 @@ import type { GeneralSettings, LightingSettings, MetricData, - NetworkSettings + NetworkSettings, + VisionSourceManagerState } from "@/types/SettingTypes"; import { NetworkConnectionType } from "@/types/SettingTypes"; import { useStateStore } from "@/stores/StateStore"; @@ -17,7 +18,7 @@ interface GeneralSettingsStore { network: NetworkSettings; lighting: LightingSettings; metrics: MetricData; - currentFieldLayout: AprilTagFieldLayout; + visionSourceManagerState: VisionSourceManagerState; } export const useSettingsStore = defineStore("settings", { @@ -71,6 +72,20 @@ export const useSettingsStore = defineStore("settings", { width: 8.2296 }, tags: [] + }, + visionSourceManagerState: { + knownCameras: [ + { + cameraType: "USBCamera", + dev: 1, + name: "foobar", + otherPaths: ["asdf", "bfdsa"], + path: "/some/path", + vendorId: 1, + productId: 2 + } + ], + unmatchedLoadedConfigs: [] } }), getters: { @@ -112,6 +127,8 @@ export const useSettingsStore = defineStore("settings", { this.lighting = data.lighting; this.network = data.networkSettings; this.currentFieldLayout = data.atfl; + + this.visionSourceManagerState = data.visionSourceManagerState; }, updateGeneralSettings(payload: Required) { return axios.post("/settings/general", payload); diff --git a/photon-client/src/types/PhotonTrackingTypes.ts b/photon-client/src/types/PhotonTrackingTypes.ts index 596a7ab664..405576ad74 100644 --- a/photon-client/src/types/PhotonTrackingTypes.ts +++ b/photon-client/src/types/PhotonTrackingTypes.ts @@ -67,6 +67,7 @@ export interface MultitagResult { } export interface PipelineResult { + sequenceID: number; fps: number; latency: number; targets: PhotonTarget[]; diff --git a/photon-client/src/types/SettingTypes.ts b/photon-client/src/types/SettingTypes.ts index 9cad1d65b5..f3cff6ff2b 100644 --- a/photon-client/src/types/SettingTypes.ts +++ b/photon-client/src/types/SettingTypes.ts @@ -56,6 +56,24 @@ export type ConfigurableNetworkSettings = Omit< "canManage" | "networkInterfaceNames" | "networkingDisabled" >; +export interface UiCameraConfiguration {} +export interface CameraConfiguration {} + +export interface PvCameraInfo { + cameraType: string; // CameraType -- todo + dev: number; + path: string; + name: string; + otherPaths: string[]; + vendorId: number; + productId: number; +} + +export interface VisionSourceManagerState { + knownCameras: PvCameraInfo[]; + unmatchedLoadedConfigs: CameraConfiguration[]; +} + export interface LightingSettings { supported: boolean; brightness: number; @@ -173,6 +191,8 @@ export interface QuirkyCamera { } export interface CameraSettings { + cameraPath: string; + nickname: string; uniqueName: string; diff --git a/photon-client/src/types/WebsocketDataTypes.ts b/photon-client/src/types/WebsocketDataTypes.ts index 2e9b6dad51..5ae44749e6 100644 --- a/photon-client/src/types/WebsocketDataTypes.ts +++ b/photon-client/src/types/WebsocketDataTypes.ts @@ -5,7 +5,8 @@ import type { LogLevel, MetricData, NetworkSettings, - QuirkyCamera + QuirkyCamera, + VisionSourceManagerState } from "@/types/SettingTypes"; import type { ActivePipelineSettings } from "@/types/PipelineTypes"; import type { AprilTagFieldLayout, PipelineResult } from "@/types/PhotonTrackingTypes"; @@ -21,6 +22,7 @@ export interface WebsocketSettingsUpdate { lighting: Required; networkSettings: NetworkSettings; atfl: AprilTagFieldLayout; + visionSourceManagerState: VisionSourceManagerState; } export interface WebsocketNumberPair { @@ -44,7 +46,10 @@ export type WebsocketVideoFormat = Record< } >; +// Companion to UICameraConfiguration in Java export interface WebsocketCameraSettingsUpdate { + cameraPath: string; + calibrations: CameraCalibrationResult[]; currentPipelineIndex: number; currentPipelineSettings: ActivePipelineSettings; diff --git a/photon-client/src/views/CameraMatchingView.vue b/photon-client/src/views/CameraMatchingView.vue new file mode 100644 index 0000000000..e1a801be33 --- /dev/null +++ b/photon-client/src/views/CameraMatchingView.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/CameraConfiguration.java b/photon-core/src/main/java/org/photonvision/common/configuration/CameraConfiguration.java index 211f3cb8d2..90bfc6341a 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/CameraConfiguration.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/CameraConfiguration.java @@ -197,6 +197,18 @@ public String toShortString() { + usbVID; } + /** + * cscore will auto-reconnect to the camera path we give it. v4l does not guarantee that if i swap + * cameras around, the same /dev/videoN ID will be assigned to that camera. So instead default to + * pinning to a particular USB port, or by "path" (appears to be a global identifier on Windows). + * + *

This represents our best guess at an immutable path to detect a camera at. + */ + @JsonIgnore + public String getUsbPathOrDefault() { + return getUSBPath().orElse(path); + } + @Override public String toString() { return "CameraConfiguration [baseName=" diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/PhotonConfiguration.java b/photon-core/src/main/java/org/photonvision/common/configuration/PhotonConfiguration.java index 74d67ec73e..02cb108573 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/PhotonConfiguration.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/PhotonConfiguration.java @@ -35,6 +35,7 @@ import org.photonvision.vision.processes.VisionModule; import org.photonvision.vision.processes.VisionModuleManager; import org.photonvision.vision.processes.VisionSource; +import org.photonvision.vision.processes.VisionSourceManager; public class PhotonConfiguration { private final HardwareConfig hardwareConfig; @@ -161,6 +162,8 @@ public Map toHashMap() { // AprilTagFieldLayout settingsSubmap.put("atfl", this.atfl); + settingsSubmap.put("visionSourceManagerState", VisionSourceManager.getInstance().getState()); + map.put( "cameraSettings", VisionModuleManager.getInstance().getModules().stream() @@ -178,21 +181,23 @@ public static class UILightingConfig { } public static class UICameraConfiguration { - @SuppressWarnings("unused") - public double fov; + // Path to the camera device. On Linux, this is a special file in /dev/v4l/by-id or /dev/videoN. + // This is the path we hand to CSCore to do auto-reconnect on + public String cameraPath; + public List calibrations; + public int currentPipelineIndex; + public HashMap currentPipelineSettings; + public double fov; + public int inputStreamPort; + public boolean isFovConfigurable = true; + public boolean isCSICamera; public String nickname; public String uniqueName; - public HashMap currentPipelineSettings; - public int currentPipelineIndex; + public int outputStreamPort; public List pipelineNicknames; public HashMap> videoFormatList; - public int outputStreamPort; - public int inputStreamPort; - public List calibrations; - public boolean isFovConfigurable = true; public QuirkyCamera cameraQuirks; - public boolean isCSICamera; public double minExposureRaw; public double maxExposureRaw; public double minWhiteBalanceTemp; diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIDataPublisher.java b/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIDataPublisher.java index a376ed7d2d..17bdf8fd86 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIDataPublisher.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/websocket/UIDataPublisher.java @@ -46,6 +46,7 @@ public void accept(CVPipelineResult result) { if (lastUIResultUpdateTime + 1000.0 / 10.0 > now) return; var dataMap = new HashMap(); + dataMap.put("sequenceID", result.sequenceID); dataMap.put("fps", result.fps); dataMap.put("latency", result.getLatencyMillis()); var uiTargets = new ArrayList>(result.targets.size()); diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/CameraInfo.java b/photon-core/src/main/java/org/photonvision/vision/camera/PvCameraInfo.java similarity index 95% rename from photon-core/src/main/java/org/photonvision/vision/camera/CameraInfo.java rename to photon-core/src/main/java/org/photonvision/vision/camera/PvCameraInfo.java index 750679f776..03011b4aa7 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/CameraInfo.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/PvCameraInfo.java @@ -22,16 +22,16 @@ import java.util.Optional; import org.photonvision.common.hardware.Platform; -public class CameraInfo extends UsbCameraInfo { +public class PvCameraInfo extends UsbCameraInfo { public final CameraType cameraType; - public CameraInfo( + public PvCameraInfo( int dev, String path, String name, String[] otherPaths, int vendorId, int productId) { super(dev, path, name, otherPaths, vendorId, productId); cameraType = CameraType.UsbCamera; } - public CameraInfo( + public PvCameraInfo( int dev, String path, String name, @@ -43,7 +43,7 @@ public CameraInfo( this.cameraType = cameraType; } - public CameraInfo(UsbCameraInfo info) { + public PvCameraInfo(UsbCameraInfo info) { super(info.dev, info.path, info.name, info.otherPaths, info.vendorId, info.productId); cameraType = CameraType.UsbCamera; } @@ -85,7 +85,7 @@ public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; - CameraInfo other = (CameraInfo) obj; + PvCameraInfo other = (PvCameraInfo) obj; // Windows device number is not significant. See // https://github.com/wpilibsuite/allwpilib/blob/4b94a64b06057c723d6fcafeb1a45f55a70d179a/cscore/src/main/native/windows/UsbCameraImpl.cpp#L1128 diff --git a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java index a2699f0316..0daeead4a8 100644 --- a/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java +++ b/photon-core/src/main/java/org/photonvision/vision/camera/USBCameras/USBCameraSource.java @@ -45,11 +45,8 @@ public USBCameraSource(CameraConfiguration config) { super(config); logger = new Logger(USBCameraSource.class, config.nickname, LogGroup.Camera); - // cscore will auto-reconnect to the camera path we give it. v4l does not guarantee that if i - // swap cameras around, the same /dev/videoN ID will be assigned to that camera. So instead - // default to pinning to a particular USB port, or by "path" (appears to be a global identifier) - // on Windows. - camera = new UsbCamera(config.nickname, config.getUSBPath().orElse(config.path)); + + camera = new UsbCamera(config.nickname, config.getUsbPathOrDefault()); cvSink = CameraServer.getVideo(this.camera); // set vid/pid if not done already for future matching diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java index 5aeda5ed78..e7e4b0f7f5 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java @@ -519,6 +519,7 @@ public void setCameraNickname(String newName) { public PhotonConfiguration.UICameraConfiguration toUICameraConfig() { var ret = new PhotonConfiguration.UICameraConfiguration(); + ret.cameraPath = visionSource.getCameraConfiguration().getUsbPathOrDefault(); ret.fov = visionSource.getSettables().getFOV(); ret.isCSICamera = visionSource.getCameraConfiguration().cameraType == CameraType.ZeroCopyPicam; ret.nickname = visionSource.getSettables().getConfiguration().nickname; diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java index d75e62cb7e..b40aa66127 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModuleManager.java @@ -19,6 +19,7 @@ import java.util.*; import java.util.stream.Collectors; +import org.photonvision.common.configuration.PhotonConfiguration.UICameraConfiguration; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; @@ -105,4 +106,24 @@ private void assignCameraIndex(List config) { } } } + + public static class UiVmmState { + public final List visionModules; + + UiVmmState(List _v) { + this.visionModules = _v; + } + } + + public UiVmmState getState() { + return new UiVmmState( + this.visionModules.stream() + .map(VisionModule::toUICameraConfig) + .map( + it -> { + it.calibrations = null; + return it; + }) + .collect(Collectors.toList())); + } } 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 f71bd9d926..22d6481694 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 @@ -36,10 +36,10 @@ import org.photonvision.common.util.TimedTaskManager; import org.photonvision.raspi.LibCameraJNI; import org.photonvision.raspi.LibCameraJNILoader; -import org.photonvision.vision.camera.CameraInfo; import org.photonvision.vision.camera.CameraQuirk; import org.photonvision.vision.camera.CameraType; import org.photonvision.vision.camera.LibcameraGpuSource; +import org.photonvision.vision.camera.PvCameraInfo; import org.photonvision.vision.camera.TestSource; import org.photonvision.vision.camera.USBCameras.USBCameraSource; @@ -47,7 +47,7 @@ public class VisionSourceManager { private static final Logger logger = new Logger(VisionSourceManager.class, LogGroup.Camera); private static final List deviceBlacklist = List.of("bcm2835-isp"); - final List knownCameras = new CopyOnWriteArrayList<>(); + final List knownCameras = new CopyOnWriteArrayList<>(); final List unmatchedLoadedConfigs = new CopyOnWriteArrayList<>(); private boolean hasWarned; @@ -87,10 +87,10 @@ public void registerLoadedConfigs(Collection configs) { * * @return a list containing usbcamerainfo. */ - protected List getConnectedUSBCameras() { - List cameraInfos = + protected List getConnectedUSBCameras() { + List cameraInfos = List.of(UsbCamera.enumerateUsbCameras()).stream() - .map(c -> new CameraInfo(c)) + .map(c -> new PvCameraInfo(c)) .collect(Collectors.toList()); return cameraInfos; } @@ -100,13 +100,13 @@ protected List getConnectedUSBCameras() { * * @return a list containing csicamerainfo. */ - protected List getConnectedCSICameras() { - List cameraInfos = new ArrayList(); + protected List getConnectedCSICameras() { + List cameraInfos = new ArrayList(); if (LibCameraJNILoader.isSupported()) for (String path : LibCameraJNI.getCameraNames()) { String name = LibCameraJNI.getSensorModel(path).getFriendlyName(); cameraInfos.add( - new CameraInfo(-1, path, name, new String[] {}, -1, -1, CameraType.ZeroCopyPicam)); + new PvCameraInfo(-1, path, name, new String[] {}, -1, -1, CameraType.ZeroCopyPicam)); } return cameraInfos; } @@ -129,7 +129,7 @@ protected List tryMatchCamImpl() { return tryMatchCamImpl(null); } - protected List tryMatchCamImpl(ArrayList cameraInfos) { + protected List tryMatchCamImpl(ArrayList cameraInfos) { return tryMatchCamImpl(cameraInfos, Platform.getCurrentPlatform()); } @@ -138,9 +138,9 @@ protected List tryMatchCamImpl(ArrayList cameraInfos) * @return New VisionSources. */ protected List tryMatchCamImpl( - ArrayList cameraInfos, Platform platform) { + ArrayList cameraInfos, Platform platform) { boolean createSources = true; - List connectedCameras; + List connectedCameras; if (cameraInfos == null) { // Detect USB cameras using CSCore connectedCameras = new ArrayList<>(filterAllowedDevices(getConnectedUSBCameras(), platform)); @@ -226,12 +226,12 @@ protected List tryMatchCamImpl( * @param savedConfig The saved camera configuration to match against * @param checkUSBPath If we should compare the USB port/bus IDs * @param checkVidPid If we should compare USB VID and PID - * @param checkBaseName If we should compare {@link CameraInfo#getBaseName} + * @param checkBaseName If we should compare {@link PvCameraInfo#getBaseName} * @param checkPath If we should check {@link CameraInfo::path} (eg /dev/videoN on Linux, or * ?/usb#vid_05c8&pid_03df&mi_00#7&fa76035&0&0000#{e5323777-f976-4f5b-9b55-b94699c46e44}\global * on Windows) */ - private final Predicate getCameraMatcher( + private final Predicate getCameraMatcher( final CameraConfiguration savedConfig, boolean checkUSBPath, boolean checkVidPid, @@ -243,7 +243,7 @@ private final Predicate getCameraMatcher( + savedConfig.toShortString()); } - return (CameraInfo physicalCamera) -> { + return (PvCameraInfo physicalCamera) -> { var matches = true; if (checkUSBPath) { @@ -277,7 +277,7 @@ private final Predicate getCameraMatcher( * @return the matched configurations. */ public List matchCameras( - List detectedCamInfos, List loadedCamConfigs) { + List detectedCamInfos, List loadedCamConfigs) { return matchCameras( detectedCamInfos, loadedCamConfigs, @@ -294,7 +294,7 @@ public List matchCameras( * @return the matched configurations. */ public List matchCameras( - List detectedCamInfos, + List detectedCamInfos, List loadedCamConfigs, boolean matchCamerasOnlyByPath) { var detectedCameraList = new ArrayList<>(detectedCamInfos); @@ -371,7 +371,7 @@ public List matchCameras( logger.warn( "Not creating 'new' Photon CameraConfigurations for [" + detectedCamInfos.stream() - .map(CameraInfo::toString) + .map(PvCameraInfo::toString) .collect(Collectors.joining(";")) + "], disabled by user"); } @@ -396,7 +396,7 @@ public List matchCameras( * @return All matched or created new configs */ private List matchCamerasByStrategy( - List detectedCamInfos, + List detectedCamInfos, List unloadedConfigs, CameraMatchingOptions matchingOptions) { List ret = new ArrayList(); @@ -417,7 +417,7 @@ private List matchCamerasByStrategy( config.baseName, config.uniqueName, config.toShortString())); // Get matcher and filter against it, picking out the first match - Predicate matches = + Predicate matches = getCameraMatcher( config, matchingOptions.checkUSBPath, @@ -449,7 +449,7 @@ private List matchCamerasByStrategy( * (unique in the set of (loaded configs, unloaded configs, loaded vision modules) at least) */ private List createConfigsForCameras( - List detectedCameraList, + List detectedCameraList, List unloadedCamConfigs, List loadedConfigs) { List ret = new ArrayList(); @@ -458,7 +458,7 @@ private List createConfigsForCameras( + detectedCameraList.stream() .map(n -> String.valueOf(n)) .collect(Collectors.joining("-", "{", "}"))); - for (CameraInfo info : detectedCameraList) { + for (PvCameraInfo info : detectedCameraList) { // create new camera config for all new cameras String baseName = info.getBaseName(); String uniqueName = info.getHumanReadableName(); @@ -486,7 +486,7 @@ private List createConfigsForCameras( return ret; } - private CameraConfiguration mergeInfoIntoConfig(CameraConfiguration cfg, CameraInfo info) { + private CameraConfiguration mergeInfoIntoConfig(CameraConfiguration cfg, PvCameraInfo info) { if (!cfg.path.equals(info.path)) { logger.debug("Updating path config from " + cfg.path + " to " + info.path); cfg.path = info.path; @@ -528,8 +528,9 @@ public void setIgnoredCamerasRegex(String ignoredCamerasRegex) { * @param allDevices * @return list of devices with blacklisted or ignore devices removed. */ - private List filterAllowedDevices(List allDevices, Platform platform) { - List filteredDevices = new ArrayList<>(); + private List filterAllowedDevices( + List allDevices, Platform platform) { + List filteredDevices = new ArrayList<>(); for (var device : allDevices) { if (deviceBlacklist.contains(device.name)) { logger.trace( @@ -604,4 +605,31 @@ private boolean containsName(final String uniqueName) { return VisionModuleManager.getInstance().getModules().stream() .anyMatch(camera -> camera.visionSource.cameraConfiguration.uniqueName.equals(uniqueName)); } + + // TODO: merge with our other UiCameraConfiration + public static class UiCameraConfig { + String uniqueName; + + UiCameraConfig(CameraConfiguration c) { + this.uniqueName = c.uniqueName; + } + } + + public static class UiVsmState { + public List knownCameras; + public List unmatchedLoadedConfigs; + + public UiVsmState( + List knownCameras, List _unmatchedLoadedConfigs) { + this.knownCameras = knownCameras; + this.unmatchedLoadedConfigs = new ArrayList<>(); + for (var config : _unmatchedLoadedConfigs) { + this.unmatchedLoadedConfigs.add(new UiCameraConfig(config)); + } + } + } + + public UiVsmState getState() { + return new UiVsmState(this.knownCameras, this.unmatchedLoadedConfigs); + } } 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 17cd2ed068..fe65b01fc7 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 @@ -28,8 +28,8 @@ import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.LogLevel; import org.photonvision.common.logging.Logger; -import org.photonvision.vision.camera.CameraInfo; import org.photonvision.vision.camera.CameraType; +import org.photonvision.vision.camera.PvCameraInfo; public class VisionSourceManagerTest { @Test @@ -37,7 +37,7 @@ public void visionSourceTest() { Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG); var inst = new VisionSourceManager(); - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); ConfigManager.getInstance().clearConfig(); ConfigManager.getInstance().load(); @@ -62,8 +62,8 @@ public void visionSourceTest() { config4.usbVID = 5; config4.usbPID = 6; - CameraInfo info1 = - new CameraInfo(0, "dev/video0", "testVideo", new String[] {"/usb/path/0"}, 1, 2); + PvCameraInfo info1 = + new PvCameraInfo(0, "dev/video0", "testVideo", new String[] {"/usb/path/0"}, 1, 2); cameraInfos.add(info1); @@ -74,8 +74,8 @@ public void visionSourceTest() { assertTrue(inst.knownCameras.contains(info1)); assertEquals(2, inst.unmatchedLoadedConfigs.size()); - CameraInfo info2 = - new CameraInfo(0, "dev/video1", "secondTestVideo", new String[] {"/usb/path/1"}, 2, 3); + PvCameraInfo info2 = + new PvCameraInfo(0, "dev/video1", "secondTestVideo", new String[] {"/usb/path/1"}, 2, 3); cameraInfos.add(info2); @@ -88,11 +88,11 @@ public void visionSourceTest() { assertTrue(inst.knownCameras.contains(info2)); assertEquals(2, inst.unmatchedLoadedConfigs.size()); - CameraInfo info3 = - new CameraInfo(0, "dev/video2", "thirdTestVideo", new String[] {"by-id/123"}, 3, 4); + PvCameraInfo info3 = + new PvCameraInfo(0, "dev/video2", "thirdTestVideo", new String[] {"by-id/123"}, 3, 4); - CameraInfo info4 = - new CameraInfo(0, "dev/video3", "fourthTestVideo", new String[] {"by-id/321"}, 5, 6); + PvCameraInfo info4 = + new PvCameraInfo(0, "dev/video3", "fourthTestVideo", new String[] {"by-id/321"}, 5, 6); cameraInfos.add(info4); @@ -133,8 +133,8 @@ public void visionSourceTest() { assertEquals(cam3.nickname, config3.nickname); assertEquals(cam4.nickname, config4.nickname); - CameraInfo info5 = - new CameraInfo( + PvCameraInfo info5 = + new PvCameraInfo( 2, "/dev/video2", "Left Camera", @@ -149,8 +149,8 @@ public void visionSourceTest() { assertTrue(inst.knownCameras.contains(info5)); - CameraInfo info6 = - new CameraInfo( + PvCameraInfo info6 = + new PvCameraInfo( 3, "dev/video3", "Right Camera", @@ -168,8 +168,8 @@ public void visionSourceTest() { // RPI 5 CSI Tests // CSI CAMERAS SHOULD NOT BE LOADED LIKE THIS THEY SHOULD GO THROUGH LIBCAM. - CameraInfo info7 = - new CameraInfo( + PvCameraInfo info7 = + new PvCameraInfo( 4, "dev/video4", "CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -181,8 +181,8 @@ public void visionSourceTest() { assertTrue(!inst.knownCameras.contains(info7)); // This camera should not be recognized/used. - CameraInfo info8 = - new CameraInfo( + PvCameraInfo info8 = + new PvCameraInfo( 5, "dev/video8", "CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -194,8 +194,8 @@ public void visionSourceTest() { assertTrue(!inst.knownCameras.contains(info8)); // This camera should not be recognized/used. - CameraInfo info9 = - new CameraInfo( + PvCameraInfo info9 = + new PvCameraInfo( 6, "dev/video9", "CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -210,8 +210,8 @@ public void visionSourceTest() { assertEquals(0, inst.unmatchedLoadedConfigs.size()); // RPI LIBCAMERA CSI CAMERA TESTS - CameraInfo info10 = - new CameraInfo( + PvCameraInfo info10 = + new PvCameraInfo( -1, "/base/soc/i2c0mux/i2c@0/ov9281@60", "OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -226,8 +226,8 @@ public void visionSourceTest() { assertEquals(7, inst.knownCameras.size()); assertEquals(0, inst.unmatchedLoadedConfigs.size()); - CameraInfo info11 = - new CameraInfo( + PvCameraInfo info11 = + new PvCameraInfo( -1, "/base/soc/i2c0mux/i2c@1/ov9281@60", "OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -242,8 +242,8 @@ public void visionSourceTest() { assertEquals(8, inst.knownCameras.size()); assertEquals(0, inst.unmatchedLoadedConfigs.size()); - CameraInfo info12 = - new CameraInfo( + PvCameraInfo info12 = + new PvCameraInfo( -1, " /base/axi/pcie@120000/rp1/i2c@80000/ov5647@36", "Camera Module v1", @@ -258,8 +258,8 @@ public void visionSourceTest() { assertEquals(9, inst.knownCameras.size()); assertEquals(0, inst.unmatchedLoadedConfigs.size()); - CameraInfo info13 = - new CameraInfo( + PvCameraInfo info13 = + new PvCameraInfo( -1, "/base/axi/pcie@120000/rp1/i2c@88000/imx708@1a", "Camera Module v3", @@ -319,14 +319,14 @@ public void testDisableInhibitPathChangeIdenticalCams() { // Camera attached to new port, but strict matching disabled { - CameraInfo info1 = - new CameraInfo( + PvCameraInfo info1 = + new PvCameraInfo( 0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446); - CameraInfo info2 = - new CameraInfo( + PvCameraInfo info2 = + new PvCameraInfo( 0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446); - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); cameraInfos.add(info1); cameraInfos.add(info2); List ret1 = inst.tryMatchCamImpl(cameraInfos); @@ -386,14 +386,14 @@ public void testInhibitPathChangeIdenticalCams() { { // Give our cameras new "paths" to fake the windows logic out. this should not // affect strict matching - CameraInfo info1 = - new CameraInfo( + PvCameraInfo info1 = + new PvCameraInfo( 0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446); - CameraInfo info2 = - new CameraInfo( + PvCameraInfo info2 = + new PvCameraInfo( 0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446); - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); cameraInfos.add(info1); cameraInfos.add(info2); List ret1 = inst.tryMatchCamImpl(cameraInfos); @@ -414,14 +414,14 @@ public void testInhibitPathChangeIdenticalCams() { // Now move our camera back { - CameraInfo info1 = - new CameraInfo( + PvCameraInfo info1 = + new PvCameraInfo( 0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446); - CameraInfo info2 = - new CameraInfo( + PvCameraInfo info2 = + new PvCameraInfo( 0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_OLD_PATH, 3141, 25446); - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); cameraInfos.add(info1); cameraInfos.add(info2); List ret1 = inst.tryMatchCamImpl(cameraInfos); @@ -440,15 +440,15 @@ public void testCSICameraMatching() { Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG); // List of known cameras - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); var inst = new VisionSourceManager(); ConfigManager.getInstance().clearConfig(); ConfigManager.getInstance().load(); ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false; - CameraInfo info1 = - new CameraInfo( + PvCameraInfo info1 = + new PvCameraInfo( -1, "/base/soc/i2c0mux/i2c@0/ov9281@60", "OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -457,8 +457,8 @@ public void testCSICameraMatching() { -1, CameraType.ZeroCopyPicam); - CameraInfo info2 = - new CameraInfo( + PvCameraInfo info2 = + new PvCameraInfo( -1, "/base/soc/i2c0mux/i2c@1/ov9281@60", "OV9281", // Typically rp1-cfe for unit test changed to CSICAM-DEV @@ -507,7 +507,7 @@ public void testNoOtherPaths() { Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG); // List of known cameras - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); var inst = new VisionSourceManager(); ConfigManager.getInstance().clearConfig(); @@ -517,8 +517,9 @@ public void testNoOtherPaths() { // Match empty camera infos inst.tryMatchCamImpl(cameraInfos); - CameraInfo info1 = - new CameraInfo(0, "/dev/video0", "Arducam OV2311 USB Camera", new String[] {}, 3141, 25446); + PvCameraInfo info1 = + new PvCameraInfo( + 0, "/dev/video0", "Arducam OV2311 USB Camera", new String[] {}, 3141, 25446); cameraInfos.add(info1); @@ -544,7 +545,7 @@ public void testIdenticalCameras() { Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG); // List of known cameras - var cameraInfos = new ArrayList(); + var cameraInfos = new ArrayList(); var inst = new VisionSourceManager(); ConfigManager.getInstance().clearConfig(); @@ -554,8 +555,8 @@ public void testIdenticalCameras() { // Match empty camera infos inst.tryMatchCamImpl(cameraInfos); - CameraInfo info1 = - new CameraInfo( + PvCameraInfo info1 = + new PvCameraInfo( 0, "/dev/video0", "Arducam OV2311 USB Camera", @@ -568,8 +569,8 @@ public void testIdenticalCameras() { }, 3141, 25446); - CameraInfo info2 = - new CameraInfo( + PvCameraInfo info2 = + new PvCameraInfo( 0, "/dev/video2", "Arducam OV2311 USB Camera", @@ -611,9 +612,9 @@ public void testIdenticalCameras() { } // duplicate cameras, same info, new ref - var duplicateCameraInfos = new ArrayList(); - CameraInfo info1_dup = - new CameraInfo( + var duplicateCameraInfos = new ArrayList(); + PvCameraInfo info1_dup = + new PvCameraInfo( 0, "/dev/video0", "Arducam OV2311 USB Camera", @@ -626,8 +627,8 @@ public void testIdenticalCameras() { }, 3141, 25446); - CameraInfo info2_dup = - new CameraInfo( + PvCameraInfo info2_dup = + new PvCameraInfo( 0, "/dev/video2", "Arducam OV2311 USB Camera", @@ -650,9 +651,9 @@ public void testIdenticalCameras() { // duplicate cameras this simulates unplugging one and plugging the other in where v4l assigns // the same by-id path to the other camera - var duplicateCameraInfos1 = new ArrayList(); - CameraInfo info3_dup = - new CameraInfo( + var duplicateCameraInfos1 = new ArrayList(); + PvCameraInfo info3_dup = + new PvCameraInfo( 0, "/dev/video0", "Arducam OV2311 USB Camera", @@ -662,8 +663,8 @@ public void testIdenticalCameras() { }, 3141, 25446); - CameraInfo info4_dup = - new CameraInfo( + PvCameraInfo info4_dup = + new PvCameraInfo( 0, "/dev/video2", "Arducam OV2311 USB Camera",