diff --git a/Main/src/main/java/com/chameleonvision/Main.java b/Main/src/main/java/com/chameleonvision/Main.java index 65d22321a..943d2b676 100644 --- a/Main/src/main/java/com/chameleonvision/Main.java +++ b/Main/src/main/java/com/chameleonvision/Main.java @@ -8,10 +8,10 @@ import edu.wpi.cscore.UsbCamera; import java.util.Map; public class Main { - public static void main(String [] args) { + public static void main(String[] args) { SettingsManager manager = SettingsManager.getInstance(); // NetworkTableInstance.getDefault().startClientTeam(SettingsManager.GeneralSettings.team_number); - for (Map.Entry entry: SettingsManager.UsbCameras.entrySet()){ + for (Map.Entry entry : SettingsManager.UsbCameras.entrySet()) { new Thread(new CameraProcess(entry.getKey())).start(); } Server.main(8888); diff --git a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java index e714a3a41..39b27c28f 100644 --- a/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java +++ b/Main/src/main/java/com/chameleonvision/settings/SettingsManager.java @@ -1,4 +1,5 @@ package com.chameleonvision.settings; + import com.chameleonvision.NoCameraException; import java.io.*; @@ -9,6 +10,7 @@ import com.chameleonvision.vision.Camera; import com.chameleonvision.vision.GeneralSettings; import com.chameleonvision.vision.Pipeline; import com.google.gson.Gson; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -17,102 +19,114 @@ import java.util.Map; import edu.wpi.cscore.*; import org.opencv.videoio.VideoCapture; -public class SettingsManager { +public class SettingsManager { private static SettingsManager instance; + private SettingsManager() { InitiateGeneralSettings(); InitiateCamerasInfo(); InitiateUsbCameras(); InitiateCameras(); InitiateUsbCamerasSettings(); + + if (!Cameras.containsKey(GeneralSettings.curr_camera) && Cameras.size() > 0) { + String camName = Cameras.keySet().stream().findFirst().get(); + GeneralSettings.curr_camera = camName; + GeneralSettings.curr_pipeline = Cameras.get(camName).pipelines.keySet().stream().findFirst().get(); + } } - public static synchronized SettingsManager getInstance(){ - if(instance == null){ + + public static synchronized SettingsManager getInstance() { + if (instance == null) { synchronized (SettingsManager.class) { - if(instance == null){ + if (instance == null) { instance = new SettingsManager(); } } } return instance; } + public static HashMap Cameras = new HashMap(); - public static HashMap UsbCameras = new HashMap(); - public static HashMap USBCamerasInfo = new HashMap(); + public static HashMap UsbCameras = new HashMap(); + public static HashMap USBCamerasInfo = new HashMap(); public static com.chameleonvision.vision.GeneralSettings GeneralSettings; public static HashMap CamerasCurrentPipeline = new HashMap(); - public static HashMap CameraPort = new HashMap(); - private Path SettingsPath = Paths.get(System.getProperty("user.dir"),"Settings"); - private Path CamsPath = Paths.get(SettingsPath.toString(),"Cams"); + public static HashMap CameraPorts = new HashMap();//TODO Implement ports + private Path SettingsPath = Paths.get(System.getProperty("user.dir"), "Settings"); + private Path CamsPath = Paths.get(SettingsPath.toString(), "Cams"); - - private void InitiateGeneralSettings(){ + private void InitiateGeneralSettings() { CheckPath(SettingsPath); try { - GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(),"Settings.json").toString()), com.chameleonvision.vision.GeneralSettings.class); + GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "Settings.json").toString()), com.chameleonvision.vision.GeneralSettings.class); } catch (FileNotFoundException e) { GeneralSettings = new GeneralSettings(); } } - private void InitiateCamerasInfo(){ + private void InitiateCamerasInfo() { List TrueCameras = new ArrayList(); UsbCameraInfo[] UsbDevices = UsbCamera.enumerateUsbCameras(); - for (var i=0; i < UsbDevices.length; i++){ + for (var i = 0; i < UsbDevices.length; i++) { var cap = new VideoCapture(UsbDevices[i].dev); - if (cap.isOpened()){ + if (cap.isOpened()) { TrueCameras.add(i); cap.release(); } } - for (var i: TrueCameras){ + for (var i : TrueCameras) { var DeviceName = UsbDevices[i].name; var suffix = 0; - while (USBCamerasInfo.containsKey(DeviceName)){ + while (USBCamerasInfo.containsKey(DeviceName)) { suffix++; - DeviceName = String.format("%s(%s)",UsbDevices[i].name,suffix); + DeviceName = String.format("%s(%s)", UsbDevices[i].name, suffix); } - USBCamerasInfo.put(DeviceName,UsbDevices[i]); + USBCamerasInfo.put(DeviceName, UsbDevices[i]); } } - private void InitiateUsbCameras(){ - for(Map.Entry entry : USBCamerasInfo.entrySet()){ + + private void InitiateUsbCameras() { + for (Map.Entry entry : USBCamerasInfo.entrySet()) { var device = entry.getValue(); var camera = new UsbCamera(device.name, device.dev); - UsbCameras.put(device.name,camera); + UsbCameras.put(device.name, camera); } } - private void InitiateCameras(){ + + private void InitiateCameras() { CheckPath(CamsPath); - for(Map.Entry entry: USBCamerasInfo.entrySet()){ - var camPath = Paths.get(CamsPath.toString(),String.format("%s.json",entry.getKey())); - if(Files.exists(camPath)){ + for (Map.Entry entry : USBCamerasInfo.entrySet()) { + var camPath = Paths.get(CamsPath.toString(), String.format("%s.json", entry.getKey())); + if (Files.exists(camPath)) { try { - Camera cam = new Gson().fromJson(new FileReader(camPath.toString()),Camera.class); - Cameras.put(entry.getKey(),cam); + Camera cam = new Gson().fromJson(new FileReader(camPath.toString()), Camera.class); + Cameras.put(entry.getKey(), cam); } catch (FileNotFoundException e) { e.printStackTrace(); } - } else{ + } else { CreateNewCam(entry.getKey()); } } } - private void InitiateUsbCamerasSettings(){ - for(Map.Entry entry: UsbCameras.entrySet()){ + + private void InitiateUsbCamerasSettings() { + for (Map.Entry entry : UsbCameras.entrySet()) { var cam = entry.getValue(); var camName = entry.getKey(); var camInfo = Cameras.get(camName); cam.setPixelFormat(VideoMode.PixelFormat.valueOf(camInfo.camVideoMode.pixel_format)); cam.setFPS(camInfo.camVideoMode.fps); - cam.setResolution(camInfo.camVideoMode.width, camInfo.camVideoMode.heigh); + cam.setResolution(camInfo.camVideoMode.width, camInfo.camVideoMode.height); } } - private void CheckPath(Path path){ - if (!Files.exists(path)){ + + private void CheckPath(Path path) { + if (!Files.exists(path)) { try { Files.createDirectories(path); } catch (IOException e) { @@ -120,92 +134,122 @@ public class SettingsManager { } } } + // Creators - private void CreateNewCam(String CameraName){ + private void CreateNewCam(String CameraName) { Camera cam = new Camera(); - var caminfo =USBCamerasInfo.get(CameraName); + var caminfo = USBCamerasInfo.get(CameraName); cam.path = caminfo.path; var videomode = UsbCameras.get(CameraName).enumerateVideoModes()[0]; CamVideoMode CamVideoMode = new CamVideoMode(); CamVideoMode.fps = videomode.fps; - CamVideoMode.heigh = videomode.height; + CamVideoMode.height = videomode.height; CamVideoMode.width = videomode.width; CamVideoMode.pixel_format = videomode.pixelFormat.name(); cam.camVideoMode = CamVideoMode; cam.pipelines = new HashMap(); cam.resolution = 0; cam.FOV = 60.8; - Cameras.put(CameraName,cam); + Cameras.put(CameraName, cam); - CreateNewPipeline(null,CameraName); + CreateNewPipeline(null, CameraName); } - private void CreateNewPipeline(String PipeName, String CamName){ - if (CamName == null){ + + private void CreateNewPipeline(String PipeName, String CamName) { + if (CamName == null) { CamName = GeneralSettings.curr_camera; } var cam = Cameras.get(CamName); - if (PipeName == null){ + if (PipeName == null) { var suffix = 0; PipeName = "pipeline" + suffix; - while (cam.pipelines.containsKey(PipeName)){ - suffix ++; - PipeName = "pipeline"+suffix; + while (cam.pipelines.containsKey(PipeName)) { + suffix++; + PipeName = "pipeline" + suffix; } - } - else if (cam.pipelines.containsKey(PipeName)){ + } else if (cam.pipelines.containsKey(PipeName)) { System.err.println("Pipeline Already Exists"); } - cam.pipelines.put(PipeName,new Pipeline()); + cam.pipelines.put(PipeName, new Pipeline()); } + //Access Methods - public Pipeline GetCurrentPipeline() throws Exception { - if (!GeneralSettings.curr_pipeline.equals("")){ + public Pipeline GetCurrentPipeline() throws NoCameraException { + if (!GeneralSettings.curr_pipeline.equals("")) { return Cameras.get(GeneralSettings.curr_camera).pipelines.get(GeneralSettings.curr_pipeline); } throw new NoCameraException(); } - public Camera GetCurrentCamera() throws Exception { - if (!GeneralSettings.curr_camera.equals("")){ + + public Camera GetCurrentCamera() throws NoCameraException { + if (!GeneralSettings.curr_camera.equals("")) { return Cameras.get(GeneralSettings.curr_camera); } throw new NoCameraException(); } + public List GetResolutionList() throws NoCameraException { - if (!GeneralSettings.curr_camera.equals("")){ + if (!GeneralSettings.curr_camera.equals("")) { List list = new ArrayList(); var cam = UsbCameras.get(GeneralSettings.curr_camera); - for (var res : cam.enumerateVideoModes()){ + for (var res : cam.enumerateVideoModes()) { list.add(String.format("%s X %s at %s fps", res.width, res.height, res.fps)); } return list; } throw new NoCameraException(); } + public void SetCurrentCamera(String CamName) throws Exception { - if (Cameras.containsKey(CamName)){ + if (Cameras.containsKey(CamName)) { GeneralSettings.curr_camera = CamName; GeneralSettings.curr_pipeline = GetCurrentCamera().pipelines.keySet().stream().findFirst().toString(); } } + public void SetCurrentPipeline(String PipelineName) throws Exception { - if (GetCurrentCamera().pipelines.containsKey(PipelineName)){ + if (GetCurrentCamera().pipelines.containsKey(PipelineName)) { GeneralSettings.curr_pipeline = PipelineName; } } + + + public void SetCameraSettings(String cameraName, String field, Object value) { + switch (field) { + case "brightness": + UsbCameras.get(cameraName).setBrightness((int) value); + break; + case "exposure": + UsbCameras.get(cameraName).setExposureManual((int) value); + break; + case "resolution": + VideoMode videoMode = UsbCameras.get(cameraName).enumerateVideoModes()[(int) value]; + Camera cam = Cameras.get(cameraName); + cam.camVideoMode.height = videoMode.height; + cam.camVideoMode.width = videoMode.width; + cam.camVideoMode.fps = videoMode.fps; + //cam.camVideoMode.pixel_format=videoMode.pixelFormat.toString().split(".")[1];//legacy from python + cam.camVideoMode.pixel_format = videoMode.pixelFormat.toString(); + break; + } + + } + //Savers - public void SaveSettings(){ + public void SaveSettings() { SaveCameras(); SaveGeneralSettings(); } - private void SaveCameras(){ - for(Map.Entry entry: Cameras.entrySet()){ + + private void SaveCameras() { + for (Map.Entry entry : Cameras.entrySet()) { try { Gson gson = new Gson(); - FileWriter writer = new FileWriter(Paths.get(CamsPath.toString(),String.format("%s.json",entry.getKey())).toString()); - gson.toJson(entry.getValue(),writer); + FileWriter writer = new FileWriter(Paths.get(CamsPath.toString(), String.format("%s.json", entry.getKey())).toString()); + gson.toJson(entry.getValue(), writer); writer.flush(); writer.close(); } catch (IOException e) { @@ -213,10 +257,11 @@ public class SettingsManager { } } } - private void SaveGeneralSettings(){ + + private void SaveGeneralSettings() { try { Gson gson = new Gson(); - FileWriter writer = new FileWriter(Paths.get(SettingsPath.toString(),"Settings.json").toString()); + FileWriter writer = new FileWriter(Paths.get(SettingsPath.toString(), "Settings.json").toString()); new Gson().toJson(GeneralSettings, writer); writer.flush(); writer.close(); @@ -224,4 +269,6 @@ public class SettingsManager { e.printStackTrace(); } } + + } diff --git a/Main/src/main/java/com/chameleonvision/vision/CamVideoMode.java b/Main/src/main/java/com/chameleonvision/vision/CamVideoMode.java index a288d100e..7ba6f2468 100644 --- a/Main/src/main/java/com/chameleonvision/vision/CamVideoMode.java +++ b/Main/src/main/java/com/chameleonvision/vision/CamVideoMode.java @@ -3,7 +3,7 @@ package com.chameleonvision.vision; public class CamVideoMode { public int fps; public int width; - public int heigh; + public int height; public String pixel_format; } diff --git a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java index e1c907c89..66e5ffabd 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/CameraProcess.java @@ -30,7 +30,7 @@ public class CameraProcess implements Runnable{ int Width = manager.Cameras.get(CameraName).camVideoMode.width; - int Height = manager.Cameras.get(CameraName).camVideoMode.heigh; + int Height = manager.Cameras.get(CameraName).camVideoMode.height; var cv_publish = cs.putVideo(CameraName,Width,Height); //initial math setup for camera double DiagonalView = FastMath.toRadians(manager.Cameras.get(CameraName).FOV); diff --git a/Main/src/main/java/com/chameleonvision/web/Server.java b/Main/src/main/java/com/chameleonvision/web/Server.java index e9accf11f..c899419bf 100644 --- a/Main/src/main/java/com/chameleonvision/web/Server.java +++ b/Main/src/main/java/com/chameleonvision/web/Server.java @@ -1,13 +1,15 @@ package com.chameleonvision.web; +import com.chameleonvision.NoCameraException; import com.chameleonvision.settings.SettingsManager; +import com.chameleonvision.vision.GeneralSettings; import com.chameleonvision.vision.Pipeline; +import com.google.gson.JsonObject; import io.javalin.Javalin; import io.javalin.websocket.WsContext; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import org.json.JSONArray; import org.json.JSONObject; @@ -16,13 +18,15 @@ import org.springframework.beans.BeanUtils; public class Server { private static List users = new ArrayList(); + public static void main(int port) { Javalin app = Javalin.create(); app.config.addStaticFiles("web"); - app.ws("/websocket", ws ->{ + app.ws("/websocket", ws -> { ws.onConnect(ctx -> { users.add(ctx); System.out.println("Socket Connected"); + sendFullSettings(); }); ws.onClose(ctx -> { users.remove(ctx); @@ -30,36 +34,133 @@ public class Server { SettingsManager.getInstance().SaveSettings(); }); ws.onMessage(ctx -> { +// System.out.println(SettingsManager.getInstance().GetCurrentPipeline().); broadcastMessage(ctx, ctx.message()); JSONObject jsonObject = new JSONObject(ctx.message()); - String key =jsonObject.keySet().toArray()[0].toString(); + String key = jsonObject.keySet().toArray()[0].toString(); Object value = jsonObject.get(key); - System.out.println("Key: "+key+" Value: "+value); - Field[] fields = Pipeline.class.getFields(); - for (Field f : fields) - {//TODO: check calibration in output tab for crashes - if(f.getName().equals(key)) - { - if(BeanUtils.isSimpleValueType(value.getClass())) - f.set(SettingsManager.getInstance().GetCurrentPipeline(),value); - else - if(value.getClass()==JSONArray.class){ - f.set(SettingsManager.getInstance().GetCurrentPipeline(),((JSONArray)value).toList()); - } + if (!setField(SettingsManager.getInstance().GetCurrentPipeline(), key, value)) { + //If field not in pipeline + switch (key) { + case "change_general_settings_values": + JSONObject newSettings = (JSONObject) value; + setFields(SettingsManager.getInstance().GeneralSettings, newSettings); + break; + case "curr_camera": + SettingsManager.getInstance().SetCurrentCamera((String) value); + //broadcastMessage((Map) new HashMap(){}.put("port",SettingsManager.CameraPorts.get(SettingsManager.GeneralSettings.curr_camera))); + //broadcastMessage(SettingsManager.getInstance().GetCurrentCamera());//TODO CHECK JSON FOR CAMERA CHANGE + break; + case "curr_pipeline": + System.out.println("change pipeline"); + SettingsManager.getInstance().SetCurrentPipeline((String) value); + SettingsManager.CamerasCurrentPipeline.put(SettingsManager.GeneralSettings.curr_camera, (String) value); +// broadcastMessage(SettingsManager.getInstance().GetCurrentPipeline());//TODO CHECK JSON FOR PIPELINE CHANGE + break; + case "resolution": + System.out.println("change res"); + SettingsManager.getInstance().GetCurrentCamera().resolution = (int) value; + SettingsManager.getInstance().SetCameraSettings(SettingsManager.GeneralSettings.curr_camera, "resolution", value); + SettingsManager.getInstance().SaveSettings(); + break; + case "fov": + System.out.println("change fov"); + SettingsManager.getInstance().GetCurrentCamera().FOV = (double) value; + SettingsManager.getInstance().SaveSettings(); + break; + default: + System.out.println("Unexpected value"); + break; } } }); }); app.start(port); } - private static void broadcastMessage(WsContext sendingUser, String message){ - for (var user : users) - { - if (user != sendingUser){ + + + public static boolean setField(Object obj, String fieldName, Object value) { + boolean successful = false; + try { + Field[] fields = obj.getClass().getFields(); + for (Field f : fields) { + if (f.getName().equals(fieldName)) { + successful = true; + if (BeanUtils.isSimpleValueType(value.getClass())) { + f.set(obj, value); + } else if (value.getClass() == JSONArray.class) { + f.set(obj, ((JSONArray) value).toList()); + } + } + } + } catch (IllegalAccessException e) { + return false; + } + return successful; + } + + public static boolean setFields(Object obj, JSONObject data) { + boolean successful = false; + try { + Field[] fields = obj.getClass().getFields(); + for (Field f : fields) { + if (data.has(f.getName())) { + Object value = data.get(f.getName()); + if (BeanUtils.isSimpleValueType(value.getClass())) { + successful = true; + f.set(obj, value); + } + } + } + } catch (IllegalAccessException e) { + return false; + } + return successful; + } + + private static void broadcastMessage(WsContext sendingUser, String message) { + for (var user : users) { + if (user != sendingUser) { user.send(message); } } } + private static void broadcastMessage(Map map) { + for (var user : users) { + user.send(new JSONObject(map).toString()); + } + + } + + private static void addAllFieldsToMap(Map map, Object obj) { + try { + Field[] fields = obj.getClass().getFields(); + for (Field field : fields) + map.put(field.getName(), field.get(obj)); + } catch (IllegalAccessException e) { + System.err.println("Illegal Access error:" + e.getStackTrace().toString()); + } + } + + private static void sendFullSettings() { + Map fullSettings = new HashMap<>(); + //General settings + addAllFieldsToMap(fullSettings, SettingsManager.GeneralSettings); + fullSettings.put("cameraList", SettingsManager.Cameras.keySet()); + try { + addAllFieldsToMap(fullSettings, SettingsManager.getInstance().GetCurrentPipeline()); + fullSettings.put("pipelineList", SettingsManager.getInstance().GetCurrentCamera().pipelines.keySet()); + fullSettings.put("resolutionList", SettingsManager.getInstance().GetResolutionList()); + fullSettings.put("resolution", SettingsManager.getInstance().GetCurrentCamera().resolution); + fullSettings.put("FOV", SettingsManager.getInstance().GetCurrentCamera().FOV); +// fullSettings.put("port", SettingsManager.CameraPorts.get(SettingsManager.GeneralSettings.curr_camera)); + } catch (NoCameraException e) { + System.err.println("No camera found!"); + //TODO: add message to ui to inform that there are no cameras + } + broadcastMessage(fullSettings); + } + }