001/* 002 * Copyright (C) Photon Vision. 003 * 004 * This program is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package org.photonvision.vision.processes; 019 020import java.util.*; 021import java.util.stream.Collectors; 022import org.photonvision.common.dataflow.websocket.UICameraConfiguration; 023import org.photonvision.common.logging.LogGroup; 024import org.photonvision.common.logging.Logger; 025 026/** VisionModuleManager has many VisionModules, and provides camera configuration data to them. */ 027public class VisionModuleManager { 028 private final Logger logger = new Logger(VisionModuleManager.class, LogGroup.VisionModule); 029 030 private final List<VisionModule> visionModules = new ArrayList<>(); 031 032 VisionModuleManager() {} 033 034 public List<VisionModule> getModules() { 035 return visionModules; 036 } 037 038 public VisionModule getModule(String uniqueName) { 039 for (var module : visionModules) { 040 if (module.getStateAsCameraConfig().uniqueName.equals(uniqueName)) return module; 041 } 042 return null; 043 } 044 045 public synchronized VisionModule addSource(VisionSource visionSource) { 046 visionSource.cameraConfiguration.streamIndex = newCameraIndex(); 047 048 var pipelineManager = new PipelineManager(visionSource.getCameraConfiguration()); 049 var module = new VisionModule(pipelineManager, visionSource); 050 visionModules.add(module); 051 052 return module; 053 } 054 055 public synchronized void removeModule(VisionModule module) { 056 visionModules.remove(module); 057 module.stop(); 058 module.saveAndBroadcastAll(); 059 } 060 061 private synchronized int newCameraIndex() { 062 // We won't necessarily have already added all the cameras we need to at this point 063 // But by operating on the list, we have a fairly good idea of which we need to change, 064 // but it's not guaranteed that we change the correct one 065 // The best we can do is try to avoid a case where the stream index runs away to infinity 066 // since we can only stream 5 cameras at once 067 068 // Big list, which should contain every vision source (currently loaded plus the new ones being 069 // added) 070 List<Integer> bigList = 071 this.getModules().stream() 072 .map(it -> it.getCameraConfiguration().streamIndex) 073 .collect(Collectors.toList()); 074 075 int idx = 0; 076 while (bigList.contains(idx)) { 077 idx++; 078 } 079 080 if (idx >= 5) { 081 logger.warn("VisionModuleManager has reached the maximum number of cameras (5)."); 082 } 083 084 return idx; 085 } 086 087 public static class UiVmmState { 088 public final List<UICameraConfiguration> visionModules; 089 090 UiVmmState(List<UICameraConfiguration> _v) { 091 this.visionModules = _v; 092 } 093 } 094 095 public synchronized UiVmmState getState() { 096 return new UiVmmState( 097 this.visionModules.stream() 098 .map(VisionModule::toUICameraConfig) 099 .map( 100 it -> { 101 it.calibrations = null; 102 return it; 103 }) 104 .collect(Collectors.toList())); 105 } 106}