2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2018-12-07 23:57:37 -08:00
|
|
|
|
2020-06-26 11:10:34 -07:00
|
|
|
package edu.wpi;
|
|
|
|
|
|
2018-12-07 23:57:37 -08:00
|
|
|
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.first.cameraserver.CameraServer;
|
2021-04-10 11:42:41 -07:00
|
|
|
import edu.wpi.first.cscore.VideoSource;
|
2018-12-07 23:57:37 -08:00
|
|
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
2020-12-29 22:45:16 -08:00
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
2018-12-07 23:57:37 -08:00
|
|
|
|
|
|
|
|
/*
|
2020-12-29 22:45:16 -08:00
|
|
|
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>
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
*/
|
2018-12-07 23:57:37 -08:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-09 12:20:08 -08:00
|
|
|
private static int team;
|
|
|
|
|
private static boolean server;
|
|
|
|
|
private static List<CameraConfig> cameras = new ArrayList<>();
|
2018-12-07 23:57:37 -08:00
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
private Main() {}
|
2018-12-07 23:57:37 -08:00
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Report parse error. */
|
2018-12-07 23:57:37 -08:00
|
|
|
public static void parseError(String str) {
|
|
|
|
|
System.err.println("config error in '" + configFile + "': " + str);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Read single camera configuration. */
|
2018-12-07 23:57:37 -08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Read configuration file. */
|
2018-12-07 23:57:37 -08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Start running the camera. */
|
2018-12-07 23:57:37 -08:00
|
|
|
public static void startCamera(CameraConfig config) {
|
|
|
|
|
System.out.println("Starting camera '" + config.name + "' on " + config.path);
|
2021-06-15 23:06:03 -07:00
|
|
|
VideoSource camera = CameraServer.startAutomaticCapture(config.name, config.path);
|
2018-12-07 23:57:37 -08:00
|
|
|
|
|
|
|
|
Gson gson = new GsonBuilder().create();
|
|
|
|
|
|
|
|
|
|
camera.setConfigJson(gson.toJson(config.config));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Main. */
|
2018-12-07 23:57:37 -08:00
|
|
|
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);
|
2022-10-08 10:01:31 -07:00
|
|
|
ntinst.setServerTeam(team);
|
|
|
|
|
ntinst.startClient4();
|
2018-12-07 23:57:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start cameras
|
|
|
|
|
for (CameraConfig camera : cameras) {
|
|
|
|
|
startCamera(camera);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// loop forever
|
2020-12-29 22:45:16 -08:00
|
|
|
for (; ; ) {
|
2018-12-07 23:57:37 -08:00
|
|
|
try {
|
|
|
|
|
Thread.sleep(10000);
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|