mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-20 00:51:41 +00:00
Update log viewer, add uncalibrated modal (#108)
Adds a prettier log viewer, with the ability to filter logs. Also warns user and prevents switching into 3d mode if the resolution is uncalibrated.
This commit is contained in:
@@ -57,17 +57,17 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
public static void saveUploadedSettingsZip(File uploadPath) {
|
||||
logger.info(uploadPath.getAbsolutePath());
|
||||
var folderPath = Path.of(System.getProperty("java.io.tmpdir"), "photonvision").toFile();
|
||||
folderPath.mkdirs();
|
||||
ZipUtil.unpack(uploadPath, folderPath);
|
||||
FileUtils.deleteDirectory(getRootFolder());
|
||||
try {
|
||||
org.apache.commons.io.FileUtils.copyDirectory(folderPath, getRootFolder().toFile());
|
||||
logger.info("Copied settings successfully!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
logger.error("Exception copying uploaded settings!", e);
|
||||
return;
|
||||
}
|
||||
System.exit(666);
|
||||
}
|
||||
|
||||
public PhotonConfiguration getConfig() {
|
||||
@@ -159,8 +159,6 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
public void saveToDisk() {
|
||||
logger.info("Saving settings...");
|
||||
|
||||
// Delete old configs
|
||||
FileUtils.deleteDirectory(camerasFolder.toPath());
|
||||
|
||||
@@ -214,6 +212,7 @@ public class ConfigManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("Settings saved!");
|
||||
}
|
||||
|
||||
private HashMap<String, CameraConfiguration> loadCameraConfigs() {
|
||||
@@ -341,7 +340,7 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
public void requestSave() {
|
||||
logger.debug("Requesting save...");
|
||||
logger.trace("Requesting save...");
|
||||
saveRequestTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,11 @@
|
||||
package org.photonvision.common.logging;
|
||||
|
||||
public enum LogLevel {
|
||||
OFF(0, Logger.ANSI_BLACK),
|
||||
ERROR(1, Logger.ANSI_RED),
|
||||
WARN(2, Logger.ANSI_YELLOW),
|
||||
INFO(3, Logger.ANSI_GREEN),
|
||||
DEBUG(4, Logger.ANSI_WHITE),
|
||||
TRACE(5, Logger.ANSI_CYAN);
|
||||
ERROR(0, Logger.ANSI_RED),
|
||||
WARN(1, Logger.ANSI_YELLOW),
|
||||
INFO(2, Logger.ANSI_GREEN),
|
||||
DEBUG(3, Logger.ANSI_WHITE),
|
||||
TRACE(4, Logger.ANSI_CYAN);
|
||||
|
||||
public final String colorCode;
|
||||
public final int code;
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
import org.photonvision.common.dataflow.DataChangeService;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
@@ -47,6 +48,11 @@ public class Logger {
|
||||
private static final SimpleDateFormat simpleDateFormat =
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private static final List<Pair<String, LogLevel>> uiBacklog = new ArrayList<>();
|
||||
private static boolean connected = false;
|
||||
|
||||
private static UILogAppender uiLogAppender = new UILogAppender();
|
||||
|
||||
private final String className;
|
||||
private final LogGroup group;
|
||||
|
||||
@@ -97,7 +103,7 @@ public class Logger {
|
||||
|
||||
static {
|
||||
currentAppenders.add(new ConsoleLogAppender());
|
||||
currentAppenders.add(new UILogAppender());
|
||||
currentAppenders.add(uiLogAppender);
|
||||
addFileAppender(ConfigManager.getInstance().getLogPath());
|
||||
}
|
||||
|
||||
@@ -126,6 +132,15 @@ public class Logger {
|
||||
var formattedMessage = format(message, level, group, clazz, shouldColor);
|
||||
a.log(formattedMessage, level);
|
||||
}
|
||||
if (!connected) uiBacklog.add(Pair.of(format(message, level, group, clazz, false), level));
|
||||
}
|
||||
|
||||
public static void sendConnectedBacklog() {
|
||||
for (var message : uiBacklog) {
|
||||
uiLogAppender.log(message.getLeft(), message.getRight());
|
||||
}
|
||||
connected = true;
|
||||
uiBacklog.clear();
|
||||
}
|
||||
|
||||
public boolean shouldLog(LogLevel logLevel) {
|
||||
@@ -244,6 +259,7 @@ public class Logger {
|
||||
|
||||
private static class FileLogAppender implements LogAppender {
|
||||
private OutputStream out;
|
||||
private boolean wantsFlush;
|
||||
|
||||
public FileLogAppender(Path logFilePath) {
|
||||
try {
|
||||
@@ -253,7 +269,10 @@ public class Logger {
|
||||
"FileLogAppender",
|
||||
() -> {
|
||||
try {
|
||||
out.flush();
|
||||
if (wantsFlush) {
|
||||
out.flush();
|
||||
wantsFlush = false;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
},
|
||||
@@ -269,6 +288,7 @@ public class Logger {
|
||||
message += "\n";
|
||||
try {
|
||||
out.write(message.getBytes());
|
||||
wantsFlush = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.photonvision.common.configuration.ConfigManager;
|
||||
import org.photonvision.common.configuration.NetworkConfig;
|
||||
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
|
||||
import org.photonvision.common.hardware.HardwareManager;
|
||||
import org.photonvision.common.hardware.Platform;
|
||||
import org.photonvision.common.logging.LogGroup;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
import org.photonvision.common.networking.NetworkManager;
|
||||
@@ -56,9 +57,17 @@ public class RequestHandler {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ConfigManager.saveUploadedSettingsZip(tempZipPath);
|
||||
// restartDevice();
|
||||
ctx.status(200);
|
||||
logger.info("Settings uploaded, going down for restart.");
|
||||
|
||||
if (!Platform.isRaspberryPi()) {
|
||||
logger.info("(On non-PI platforms, the program may not restart manually...)");
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
} else {
|
||||
logger.error("Couldn't read uploaded settings ZIP! Ignoring.");
|
||||
ctx.status(500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public class Server {
|
||||
ws ->
|
||||
ws.onBinaryMessage(
|
||||
ctx ->
|
||||
logger.debug(
|
||||
logger.trace(
|
||||
() -> {
|
||||
var insa = ctx.session.getRemote().getInetSocketAddress();
|
||||
var host = insa.getAddress().toString() + ":" + insa.getPort();
|
||||
|
||||
@@ -105,14 +105,15 @@ public class SocketHandler {
|
||||
var entryValue = entry.getValue();
|
||||
var socketMessageType = SocketMessageType.fromEntryKey(entryKey);
|
||||
|
||||
logger.debug(
|
||||
"Got WS message: ["
|
||||
+ socketMessageType
|
||||
+ "] ==> ["
|
||||
+ entryKey
|
||||
+ "], ["
|
||||
+ entryValue
|
||||
+ "]");
|
||||
logger.trace(
|
||||
() ->
|
||||
"Got WS message: ["
|
||||
+ socketMessageType
|
||||
+ "] ==> ["
|
||||
+ entryKey
|
||||
+ "], ["
|
||||
+ entryValue
|
||||
+ "]");
|
||||
|
||||
if (socketMessageType == null) {
|
||||
logger.warn("Got unknown socket message type: " + entryKey);
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.photonvision.common.dataflow.DataChangeSubscriber;
|
||||
import org.photonvision.common.dataflow.events.DataChangeEvent;
|
||||
import org.photonvision.common.dataflow.events.IncomingWebSocketEvent;
|
||||
import org.photonvision.common.dataflow.events.OutgoingUIEvent;
|
||||
import org.photonvision.common.logging.Logger;
|
||||
|
||||
public class UIInboundSubscriber extends DataChangeSubscriber {
|
||||
|
||||
@@ -46,6 +47,7 @@ public class UIInboundSubscriber extends DataChangeSubscriber {
|
||||
var message =
|
||||
new OutgoingUIEvent<>("fullsettings", settings, incomingWSEvent.originContext);
|
||||
DataChangeService.getInstance().publishEvent(message);
|
||||
Logger.sendConnectedBacklog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,21 @@ public class SolvePNPPipe
|
||||
|
||||
private final MatOfPoint2f imagePoints = new MatOfPoint2f();
|
||||
|
||||
private boolean hasWarned = false;
|
||||
|
||||
@Override
|
||||
protected List<TrackedTarget> process(List<TrackedTarget> targetList) {
|
||||
if (params.cameraCoefficients == null
|
||||
|| params.cameraCoefficients.getCameraIntrinsicsMat() == null
|
||||
|| params.cameraCoefficients.getCameraExtrinsicsMat() == null) {
|
||||
if (!hasWarned) {
|
||||
logger.warn(
|
||||
"Cannot perform solvePNP an uncalibrated camera! Please calibrate this resolution...");
|
||||
hasWarned = true;
|
||||
}
|
||||
return targetList;
|
||||
}
|
||||
|
||||
for (var target : targetList) {
|
||||
calculateTargetPose(target);
|
||||
}
|
||||
@@ -55,6 +68,7 @@ public class SolvePNPPipe
|
||||
var corners = target.getTargetCorners();
|
||||
if (corners == null
|
||||
|| corners.isEmpty()
|
||||
|| params.cameraCoefficients == null
|
||||
|| params.cameraCoefficients.getCameraIntrinsicsMat() == null
|
||||
|| params.cameraCoefficients.getCameraExtrinsicsMat() == null) {
|
||||
return;
|
||||
|
||||
@@ -40,6 +40,7 @@ public class VisionSourceManager {
|
||||
|
||||
final List<UsbCameraInfo> knownUsbCameras = new CopyOnWriteArrayList<>();
|
||||
final List<CameraConfiguration> unmatchedLoadedConfigs = new CopyOnWriteArrayList<>();
|
||||
private boolean hasWarned;
|
||||
|
||||
private static class SingletonHolder {
|
||||
private static final VisionSourceManager INSTANCE = new VisionSourceManager();
|
||||
@@ -132,12 +133,14 @@ public class VisionSourceManager {
|
||||
// Match camera configs to physical cameras
|
||||
var matchedCameras = matchUSBCameras(notYetLoadedCams, unmatchedLoadedConfigs);
|
||||
unmatchedLoadedConfigs.removeAll(matchedCameras);
|
||||
if (!unmatchedLoadedConfigs.isEmpty())
|
||||
if (!unmatchedLoadedConfigs.isEmpty() && !hasWarned) {
|
||||
logger.warn(
|
||||
() ->
|
||||
"After matching, "
|
||||
+ unmatchedLoadedConfigs.size()
|
||||
+ " configs remained unmatched. Is your camera disconnected?");
|
||||
hasWarned = true;
|
||||
}
|
||||
|
||||
// We add the matched cameras to the known camera list
|
||||
for (var cam : notYetLoadedCams) {
|
||||
|
||||
Reference in New Issue
Block a user