Squashed 'third_party/allwpilib_2019/' content from commit bd05dfa1c
Change-Id: I2b1c2250cdb9b055133780c33593292098c375b7
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: bd05dfa1c7cca74c4fac451e7b9d6a37e7b53447
diff --git a/cameraserver/multiCameraServer/src/main/java/Main.java b/cameraserver/multiCameraServer/src/main/java/Main.java
new file mode 100644
index 0000000..8bcc54d
--- /dev/null
+++ b/cameraserver/multiCameraServer/src/main/java/Main.java
@@ -0,0 +1,211 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import edu.wpi.cscore.VideoSource;
+import edu.wpi.first.cameraserver.CameraServer;
+import edu.wpi.first.networktables.NetworkTableInstance;
+
+/*
+ JSON format:
+ {
+ "team": <team number>,
+ "ntmode": <"client" or "server", "client" if unspecified>
+ "cameras": [
+ {
+ "name": <camera name>
+ "path": <path, e.g. "/dev/video0">
+ "pixel format": <"MJPEG", "YUYV", etc> // optional
+ "width": <video mode width> // optional
+ "height": <video mode height> // optional
+ "fps": <video mode fps> // optional
+ "brightness": <percentage brightness> // optional
+ "white balance": <"auto", "hold", value> // optional
+ "exposure": <"auto", "hold", value> // optional
+ "properties": [ // optional
+ {
+ "name": <property name>
+ "value": <property value>
+ }
+ ]
+ }
+ ]
+ }
+ */
+
+public final class Main {
+ private static String configFile = "/boot/frc.json";
+
+ @SuppressWarnings("MemberName")
+ public static class CameraConfig {
+ public String name;
+ public String path;
+ public JsonObject config;
+ }
+
+ public static int team;
+ public static boolean server;
+ public static List<CameraConfig> cameras = new ArrayList<>();
+
+ private Main() {
+ }
+
+ /**
+ * Report parse error.
+ */
+ public static void parseError(String str) {
+ System.err.println("config error in '" + configFile + "': " + str);
+ }
+
+ /**
+ * Read single camera configuration.
+ */
+ public static boolean readCameraConfig(JsonObject config) {
+ CameraConfig cam = new CameraConfig();
+
+ // name
+ JsonElement nameElement = config.get("name");
+ if (nameElement == null) {
+ parseError("could not read camera name");
+ return false;
+ }
+ cam.name = nameElement.getAsString();
+
+ // path
+ JsonElement pathElement = config.get("path");
+ if (pathElement == null) {
+ parseError("camera '" + cam.name + "': could not read path");
+ return false;
+ }
+ cam.path = pathElement.getAsString();
+
+ cam.config = config;
+
+ cameras.add(cam);
+ return true;
+ }
+
+ /**
+ * Read configuration file.
+ */
+ @SuppressWarnings("PMD.CyclomaticComplexity")
+ public static boolean readConfig() {
+ // parse file
+ JsonElement top;
+ try {
+ top = new JsonParser().parse(Files.newBufferedReader(Paths.get(configFile)));
+ } catch (IOException ex) {
+ System.err.println("could not open '" + configFile + "': " + ex);
+ return false;
+ }
+
+ // top level must be an object
+ if (!top.isJsonObject()) {
+ parseError("must be JSON object");
+ return false;
+ }
+ JsonObject obj = top.getAsJsonObject();
+
+ // team number
+ JsonElement teamElement = obj.get("team");
+ if (teamElement == null) {
+ parseError("could not read team number");
+ return false;
+ }
+ team = teamElement.getAsInt();
+
+ // ntmode (optional)
+ if (obj.has("ntmode")) {
+ String str = obj.get("ntmode").getAsString();
+ if ("client".equalsIgnoreCase(str)) {
+ server = false;
+ } else if ("server".equalsIgnoreCase(str)) {
+ server = true;
+ } else {
+ parseError("could not understand ntmode value '" + str + "'");
+ }
+ }
+
+ // cameras
+ JsonElement camerasElement = obj.get("cameras");
+ if (camerasElement == null) {
+ parseError("could not read cameras");
+ return false;
+ }
+ JsonArray cameras = camerasElement.getAsJsonArray();
+ for (JsonElement camera : cameras) {
+ if (!readCameraConfig(camera.getAsJsonObject())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Start running the camera.
+ */
+ public static void startCamera(CameraConfig config) {
+ System.out.println("Starting camera '" + config.name + "' on " + config.path);
+ VideoSource camera = CameraServer.getInstance().startAutomaticCapture(
+ config.name, config.path);
+
+ Gson gson = new GsonBuilder().create();
+
+ camera.setConfigJson(gson.toJson(config.config));
+ }
+
+ /**
+ * Main.
+ */
+ public static void main(String... args) {
+ if (args.length > 0) {
+ configFile = args[0];
+ }
+
+ // read configuration
+ if (!readConfig()) {
+ return;
+ }
+
+ // start NetworkTables
+ NetworkTableInstance ntinst = NetworkTableInstance.getDefault();
+ if (server) {
+ System.out.println("Setting up NetworkTables server");
+ ntinst.startServer();
+ } else {
+ System.out.println("Setting up NetworkTables client for team " + team);
+ ntinst.startClientTeam(team);
+ }
+
+ // start cameras
+ for (CameraConfig camera : cameras) {
+ startCamera(camera);
+ }
+
+ // loop forever
+ for (;;) {
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException ex) {
+ return;
+ }
+ }
+ }
+}