diff --git a/photon-client/src/components/settings/MetricsCard.vue b/photon-client/src/components/settings/MetricsCard.vue index 9bc5956adf..585f8ce33c 100644 --- a/photon-client/src/components/settings/MetricsCard.vue +++ b/photon-client/src/components/settings/MetricsCard.vue @@ -39,48 +39,69 @@ const generalMetrics = computed(() => { return stats; }); +// @ts-expect-error This uses Intl.DurationFormat which is newly implemented and not available in TS. +const durationFormatter = new Intl.DurationFormat("en", { style: "narrow" }); const platformMetrics = computed(() => { + const metrics = useSettingsStore().metrics; const stats = [ { header: "CPU Temp", - value: useSettingsStore().metrics.cpuTemp === undefined ? "Unknown" : `${useSettingsStore().metrics.cpuTemp}°C` + value: metrics.cpuTemp === undefined || metrics.cpuTemp == -1 ? "Unknown" : `${metrics.cpuTemp}°C` }, { header: "CPU Usage", - value: useSettingsStore().metrics.cpuUtil === undefined ? "Unknown" : `${useSettingsStore().metrics.cpuUtil}%` + value: metrics.cpuUtil === undefined ? "Unknown" : `${metrics.cpuUtil}%` }, { header: "CPU Memory Usage", value: - useSettingsStore().metrics.ramUtil === undefined || useSettingsStore().metrics.cpuMem === undefined - ? "Unknown" - : `${useSettingsStore().metrics.ramUtil || "Unknown"}MB of ${useSettingsStore().metrics.cpuMem}MB` + metrics.ramUtil && metrics.ramMem && metrics.ramUtil >= 0 && metrics.ramMem >= 0 + ? `${metrics.ramUtil}MB of ${metrics.ramMem}MB` + : "Unknown" }, { - header: "GPU Memory Usage", - value: - useSettingsStore().metrics.gpuMemUtil === undefined || useSettingsStore().metrics.gpuMem === undefined - ? "Unknown" - : `${useSettingsStore().metrics.gpuMemUtil}MB of ${useSettingsStore().metrics.gpuMem}MB` - }, - { - header: "CPU Throttling", - value: useSettingsStore().metrics.cpuThr || "Unknown" - }, - { - header: "CPU Uptime", - value: useSettingsStore().metrics.cpuUptime || "Unknown" + header: "Uptime", + value: (() => { + const seconds = metrics.uptime; + if (seconds === undefined) return "Unknown"; + + const days = Math.floor(seconds / 86400); + const hours = Math.floor((seconds % 86400) / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = Math.floor(seconds % 60); + + return durationFormatter.format({ + days: days, + hours: hours, + minutes: minutes, + seconds: secs + }); + })() }, { header: "Disk Usage", - value: useSettingsStore().metrics.diskUtilPct || "Unknown" + value: metrics.diskUtilPct === undefined ? "Unknown" : `${metrics.diskUtilPct}%` } ]; - if (useSettingsStore().metrics.npuUsage) { + if (metrics.npuUsage && metrics.npuUsage.length > 0) { stats.push({ header: "NPU Usage", - value: useSettingsStore().metrics.npuUsage || "Unknown" + value: metrics.npuUsage?.map((usage, index) => `Core${index} ${usage}%`).join(", ") || "Unknown" + }); + } + + if (metrics.gpuMem && metrics.gpuMemUtil && metrics.gpuMem > 0 && metrics.gpuMemUtil > 0) { + stats.push({ + header: "GPU Memory Usage", + value: `${metrics.gpuMemUtil}MB of ${metrics.gpuMem}MB` + }); + } + + if (metrics.cpuThr) { + stats.push({ + header: "CPU Throttling", + value: metrics.cpuThr.toString() }); } diff --git a/photon-client/src/stores/settings/GeneralSettingsStore.ts b/photon-client/src/stores/settings/GeneralSettingsStore.ts index e5f3458236..28b0f7ad03 100644 --- a/photon-client/src/stores/settings/GeneralSettingsStore.ts +++ b/photon-client/src/stores/settings/GeneralSettingsStore.ts @@ -56,15 +56,15 @@ export const useSettingsStore = defineStore("settings", { metrics: { cpuTemp: undefined, cpuUtil: undefined, - cpuMem: undefined, - gpuMem: undefined, + cpuThr: undefined, + ramMem: undefined, ramUtil: undefined, + gpuMem: undefined, gpuMemUtil: undefined, - cpuThr: undefined, - cpuUptime: undefined, diskUtilPct: undefined, npuUsage: undefined, - ipAddress: undefined + ipAddress: undefined, + uptime: undefined }, currentFieldLayout: { field: { @@ -90,15 +90,15 @@ export const useSettingsStore = defineStore("settings", { this.metrics = { cpuTemp: data.cpuTemp || undefined, cpuUtil: data.cpuUtil || undefined, - cpuMem: data.cpuMem || undefined, - gpuMem: data.gpuMem || undefined, + cpuThr: data.cpuThr || undefined, + ramMem: data.ramMem || undefined, ramUtil: data.ramUtil || undefined, + gpuMem: data.gpuMem || undefined, gpuMemUtil: data.gpuMemUtil || undefined, - cpuThr: data.cpuThr || undefined, - cpuUptime: data.cpuUptime || undefined, diskUtilPct: data.diskUtilPct || undefined, npuUsage: data.npuUsage || undefined, - ipAddress: data.ipAddress || undefined + ipAddress: data.ipAddress || undefined, + uptime: data.uptime || undefined }; }, updateGeneralSettingsFromWebsocket(data: WebsocketSettingsUpdate) { diff --git a/photon-client/src/types/SettingTypes.ts b/photon-client/src/types/SettingTypes.ts index 6f9dfe3522..98030bbdda 100644 --- a/photon-client/src/types/SettingTypes.ts +++ b/photon-client/src/types/SettingTypes.ts @@ -25,17 +25,17 @@ export interface ObjectDetectionModelProperties { } export interface MetricData { - cpuTemp?: string; - cpuUtil?: string; - cpuMem?: string; - gpuMem?: string; - ramUtil?: string; - gpuMemUtil?: string; + cpuTemp?: number; + cpuUtil?: number; cpuThr?: string; - cpuUptime?: string; - diskUtilPct?: string; - npuUsage?: string; + ramMem?: number; + ramUtil?: number; + gpuMem?: number; + gpuMemUtil?: number; + diskUtilPct?: number; + npuUsage?: number[]; ipAddress?: string; + uptime?: number; } export enum NetworkConnectionType { diff --git a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java index 5b112ddf16..2a44f6738b 100644 --- a/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java +++ b/photon-core/src/main/java/org/photonvision/common/dataflow/networktables/NetworkTablesManager.java @@ -55,10 +55,12 @@ public class NetworkTablesManager { private final NetworkTableInstance ntInstance = NetworkTableInstance.getDefault(); private final String kRootTableName = "/photonvision"; - private final String kCoprocTableName = "coprocessors"; + public final String kCoprocTableName = "coprocessors"; private final String kFieldLayoutName = "apriltag_field_layout"; public final NetworkTable kRootTable = ntInstance.getTable(kRootTableName); + // This is used to subscribe to all coprocessor tables, so we can detect conflicts + @SuppressWarnings("unused") private final MultiSubscriber sub = new MultiSubscriber(ntInstance, new String[] {kRootTableName + "/" + kCoprocTableName + "/"}); diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java index e1a2170314..8e8035169c 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java @@ -76,6 +76,9 @@ private HardwareManager(HardwareConfig hardwareConfig, HardwareSettings hardware this.metricsManager = new MetricsManager(); this.metricsManager.setConfig(hardwareConfig); + TimedTaskManager.getInstance() + .addTask("Metrics Publisher", this.metricsManager::publishMetrics, 5000); + ledModeRequest = NetworkTablesManager.getInstance() .kRootTable @@ -222,10 +225,6 @@ private void statusLEDUpdate() { blinkCounter++; } - public HardwareConfig getConfig() { - return hardwareConfig; - } - public void publishMetrics() { metricsManager.publishMetrics(); } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/DeviceMetrics.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/DeviceMetrics.java new file mode 100644 index 0000000000..4c31a20fd9 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/DeviceMetrics.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.photonvision.common.hardware.metrics; + +import org.photonvision.common.hardware.metrics.proto.DeviceMetricsProto; + +public record DeviceMetrics( + double cpuTemp, + double cpuUtil, + String cpuThr, + double ramMem, + double ramUtil, + double gpuMem, + double gpuMemUtil, + double diskUtilPct, + double[] npuUsage, + String ipAddress, + double uptime) { + public static final DeviceMetricsProto proto = new DeviceMetricsProto(); +} diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java index 053f14a70c..9a41f4c441 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/MetricsManager.java @@ -17,13 +17,15 @@ package org.photonvision.common.hardware.metrics; +import edu.wpi.first.cscore.CameraServerJNI; +import edu.wpi.first.networktables.ProtobufPublisher; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.HashMap; import org.photonvision.common.configuration.ConfigManager; import org.photonvision.common.configuration.HardwareConfig; import org.photonvision.common.dataflow.DataChangeService; import org.photonvision.common.dataflow.events.OutgoingUIEvent; +import org.photonvision.common.dataflow.networktables.NetworkTablesManager; import org.photonvision.common.hardware.Platform; import org.photonvision.common.hardware.metrics.cmds.CmdBase; import org.photonvision.common.hardware.metrics.cmds.FileCmds; @@ -41,6 +43,13 @@ public class MetricsManager { CmdBase cmds; + ProtobufPublisher metricPublisher = + NetworkTablesManager.getInstance() + .kRootTable + .getSubTable("/" + NetworkTablesManager.getInstance().kCoprocTableName + "/metrics") + .getProtobufTopic(CameraServerJNI.getHostname(), DeviceMetrics.proto) + .publish(); + private final ShellExec runCommand = new ShellExec(true, true); public void setConfig(HardwareConfig config) { @@ -70,60 +79,148 @@ public String safeExecute(String str) { } } - private String cpuMemSave = null; - - public String getMemory() { - if (cmds.cpuMemoryCommand.isEmpty()) return ""; - if (cpuMemSave == null) { - // save the value and only run it once - cpuMemSave = execute(cmds.cpuMemoryCommand); + /** + * Get the CPU temperature in Celsius. + * + * @return The CPU temperature in Celsius, or -1.0 if the command fails or parsing fails. + */ + public double getCpuTemp() { + try { + return Double.parseDouble(safeExecute(cmds.cpuTemperatureCommand)); + } catch (NumberFormatException e) { + return -1.0; } - return cpuMemSave; } - public String getTemp() { - return safeExecute(cmds.cpuTemperatureCommand); + /** + * Get the CPU utilization as a percentage. + * + * @return The CPU utilization as a percentage, or -1.0 if the command fails or parsing fails. + */ + public double getCpuUtilization() { + try { + return Double.parseDouble(safeExecute(cmds.cpuUtilizationCommand)); + } catch (NumberFormatException e) { + return -1.0; + } } - public String getUtilization() { - return safeExecute(cmds.cpuUtilizationCommand); + /** + * Get the reason for CPU throttling, if applicable. + * + * @return A string describing the CPU throttle reason, or an empty string if the command fails. + */ + public String getThrottleReason() { + return safeExecute(cmds.cpuThrottleReasonCmd); } - public String getUptime() { - return safeExecute(cmds.cpuUptimeCommand); - } + private double ramMemSave = -2.0; - public String getThrottleReason() { - return safeExecute(cmds.cpuThrottleReasonCmd); + /** + * Get the total RAM memory in MB. This only runs once, as it won't change over time. + * + * @return The total RAM memory in MB, or -1.0 if the command fails or parsing fails. + */ + public double getRamMem() { + if (ramMemSave == -2.0) { + try { + ramMemSave = Double.parseDouble(safeExecute(cmds.ramMemCommand)); + } catch (NumberFormatException e) { + ramMemSave = -1.0; + } + } + return ramMemSave; } - public String getNpuUsage() { - return safeExecute(cmds.npuUsageCommand); + /** + * Get the RAM utilization in MBs. + * + * @return The RAM utilization in MBs, or -1.0 if the command fails or parsing fails. + */ + public double getRamUtil() { + try { + return Double.parseDouble(safeExecute(cmds.ramUtilCommand)); + } catch (NumberFormatException e) { + return -1.0; + } } - private String gpuMemSave = null; + private double gpuMemSave = -2.0; - public String getGPUMemorySplit() { - if (gpuMemSave == null) { - // only needs to run once - gpuMemSave = safeExecute(cmds.gpuMemoryCommand); + /** + * Get the total GPU memory in MB. This only runs once, as it won't change over time. + * + * @return The total GPU memory in MB, or -1.0 if the command fails or parsing fails. + */ + public double getGpuMem() { + if (gpuMemSave == -2.0) { + try { + gpuMemSave = Double.parseDouble(safeExecute(cmds.gpuMemCommand)); + } catch (NumberFormatException e) { + gpuMemSave = -1.0; + } } return gpuMemSave; } - public String getMallocedMemory() { - return safeExecute(cmds.gpuMemUsageCommand); + /** + * Get the GPU memory utilization as MBs. + * + * @return The GPU memory utilization in MBs, or -1.0 if the command fails or parsing fails. + */ + public double getGpuMemUtil() { + try { + return Double.parseDouble(safeExecute(cmds.gpuMemUtilCommand)); + } catch (NumberFormatException e) { + return -1.0; + } } - public String getUsedDiskPct() { - return safeExecute(cmds.diskUsageCommand); + /** + * Get the percentage of disk space used. + * + * @return The percentage of disk space used, or -1.0 if the command fails or parsing fails. + */ + public double getUsedDiskPct() { + try { + return Double.parseDouble(safeExecute(cmds.diskUsageCommand)); + } catch (NumberFormatException e) { + return -1.0; + } } - // TODO: Output in MBs for consistency - public String getUsedRam() { - return safeExecute(cmds.ramUsageCommand); + // This is here so we don't spam logs if it fails + boolean npuParseWarning = false; + + /** + * Get the NPU usage as an array of doubles. + * + * @return An array of doubles representing NPU usage, or null if parsing fails. + */ + public double[] getNpuUsage() { + String[] usages = safeExecute(cmds.npuUsageCommand).split(","); + double[] usageDoubles = new double[usages.length]; + for (int i = 0; i < usages.length; i++) { + try { + usageDoubles[i] = Double.parseDouble(usages[i]); + npuParseWarning = false; // Reset warning if parsing succeeds + } catch (NumberFormatException e) { + if (!npuParseWarning) { + logger.error("Failed to parse NPU usage value: " + usages[i], e); + npuParseWarning = true; + } + usageDoubles = new double[0]; // Default to empty array if parsing fails + break; + } + } + return usageDoubles; } + /** + * Get the IP address of the device. + * + * @return The IP address as a string, or an empty string if the command fails. + */ public String getIpAddress() { String dev = ConfigManager.getInstance().getConfig().getNetworkConfig().networkManagerIface; logger.debug("Requesting IP addresses for \"" + dev + "\""); @@ -132,21 +229,36 @@ public String getIpAddress() { return addr; } + /** + * Get the uptime of the device in seconds. + * + * @return The uptime in seconds, or -1.0 if the command fails or parsing fails. + */ + public double getUptime() { + try { + return Double.parseDouble(safeExecute(cmds.uptimeCommand)); + } catch (NumberFormatException e) { + return -1.0; + } + } + public void publishMetrics() { logger.debug("Publishing Metrics..."); - final var metrics = new HashMap(); - - metrics.put("cpuTemp", this.getTemp()); - metrics.put("cpuUtil", this.getUtilization()); - metrics.put("cpuMem", this.getMemory()); - metrics.put("cpuThr", this.getThrottleReason()); - metrics.put("cpuUptime", this.getUptime()); - metrics.put("gpuMem", this.getGPUMemorySplit()); - metrics.put("ramUtil", this.getUsedRam()); - metrics.put("gpuMemUtil", this.getMallocedMemory()); - metrics.put("diskUtilPct", this.getUsedDiskPct()); - metrics.put("npuUsage", this.getNpuUsage()); - metrics.put("ipAddress", this.getIpAddress()); + var metrics = + new DeviceMetrics( + this.getCpuTemp(), + this.getCpuUtilization(), + this.getThrottleReason(), + this.getRamMem(), + this.getRamUtil(), + this.getGpuMem(), + this.getGpuMemUtil(), + this.getUsedDiskPct(), + this.getNpuUsage(), + this.getIpAddress(), + this.getUptime()); + + metricPublisher.set(metrics); DataChangeService.getInstance().publishEvent(OutgoingUIEvent.wrappedOf("metrics", metrics)); } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/CmdBase.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/CmdBase.java index 1580b5d665..78ec89edc1 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/CmdBase.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/CmdBase.java @@ -21,20 +21,21 @@ public class CmdBase { // CPU - public String cpuMemoryCommand = ""; public String cpuTemperatureCommand = ""; public String cpuUtilizationCommand = ""; public String cpuThrottleReasonCmd = ""; - public String cpuUptimeCommand = ""; + // RAM + public String ramMemCommand = ""; + public String ramUtilCommand = ""; // GPU - public String gpuMemoryCommand = ""; - public String gpuMemUsageCommand = ""; + public String gpuMemCommand = ""; + public String gpuMemUtilCommand = ""; // NPU public String npuUsageCommand = ""; - // RAM - public String ramUsageCommand = ""; // Disk public String diskUsageCommand = ""; + // Uptime + public String uptimeCommand = ""; public void initCmds(HardwareConfig config) { // default - do nothing diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java index bda20e0afc..6c988feeb9 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/FileCmds.java @@ -22,17 +22,18 @@ public class FileCmds extends CmdBase { @Override public void initCmds(HardwareConfig config) { - cpuMemoryCommand = config.cpuMemoryCommand(); cpuTemperatureCommand = config.cpuTempCommand(); cpuUtilizationCommand = config.cpuUtilCommand(); cpuThrottleReasonCmd = config.cpuThrottleReasonCmd(); - cpuUptimeCommand = config.cpuUptimeCommand(); - gpuMemoryCommand = config.gpuMemoryCommand(); - gpuMemUsageCommand = config.gpuMemUsageCommand(); + ramMemCommand = config.cpuMemoryCommand(); + ramUtilCommand = config.ramUtilCommand(); + + gpuMemCommand = config.gpuMemoryCommand(); + gpuMemUtilCommand = config.gpuMemUsageCommand(); diskUsageCommand = config.diskUsageCommand(); - ramUsageCommand = config.ramUtilCommand(); + uptimeCommand = config.cpuUptimeCommand(); } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/LinuxCmds.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/LinuxCmds.java index 56ad1b736c..6db4dbce97 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/LinuxCmds.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/LinuxCmds.java @@ -21,20 +21,20 @@ public class LinuxCmds extends CmdBase { public void initCmds(HardwareConfig config) { - // CPU - cpuMemoryCommand = "free -m | awk 'FNR == 2 {print $2}'"; - // TODO: boards have lots of thermal devices. Hard to pick the CPU + // CPU cpuUtilizationCommand = "top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}'"; - cpuUptimeCommand = "uptime -p | cut -c 4-"; + // Uptime + uptimeCommand = "cat /proc/uptime | cut -d ' ' -f1"; // RAM - ramUsageCommand = "free -m | awk 'FNR == 2 {print $3}'"; + ramMemCommand = "free -m | awk 'FNR == 2 {print $2}'"; + ramUtilCommand = "free -m | awk 'FNR == 2 {print $3}'"; // Disk - diskUsageCommand = "df ./ --output=pcent | tail -n +2"; + diskUsageCommand = "df ./ --output=pcent | tail -n +2 | tr -d '%'"; } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/PiCmds.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/PiCmds.java index 88ed23f22c..57680726e9 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/PiCmds.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/PiCmds.java @@ -34,7 +34,7 @@ public void initCmds(HardwareConfig config) { + " else echo \"None\"; fi"; // GPU - gpuMemoryCommand = "vcgencmd get_mem gpu | grep -Eo '[0-9]+'"; - gpuMemUsageCommand = "vcgencmd get_mem malloc | grep -Eo '[0-9]+'"; + gpuMemCommand = "vcgencmd get_mem gpu | grep -Eo '[0-9]+'"; + gpuMemUtilCommand = "vcgencmd get_mem malloc | grep -Eo '[0-9]+'"; } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/RK3588Cmds.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/RK3588Cmds.java index a215570bb2..b8be38ac6a 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/RK3588Cmds.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/cmds/RK3588Cmds.java @@ -45,6 +45,7 @@ public void initCmds(HardwareConfig config) { cpuTemperatureCommand = "cat /sys/class/thermal/thermal_zone1/temp | awk '{printf \"%.1f\", $1/1000}'"; - npuUsageCommand = "cat /sys/kernel/debug/rknpu/load | sed 's/NPU load://; s/^ *//; s/ *$//'"; + npuUsageCommand = + "cat /sys/kernel/debug/rknpu/load | grep -o '[0-9]\\+%' | sed 's/%//g' | paste -sd ','"; } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/metrics/proto/DeviceMetricsProto.java b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/proto/DeviceMetricsProto.java new file mode 100644 index 0000000000..4033e2dd43 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/common/hardware/metrics/proto/DeviceMetricsProto.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.photonvision.common.hardware.metrics.proto; + +import edu.wpi.first.util.protobuf.Protobuf; +import org.photonvision.common.hardware.metrics.DeviceMetrics; +import org.photonvision.proto.Photon.ProtobufDeviceMetrics; +import us.hebi.quickbuf.Descriptors.Descriptor; + +public class DeviceMetricsProto implements Protobuf { + @Override + public Class getTypeClass() { + return DeviceMetrics.class; + } + + @Override + public Descriptor getDescriptor() { + return ProtobufDeviceMetrics.getDescriptor(); + } + + @Override + public ProtobufDeviceMetrics createMessage() { + return ProtobufDeviceMetrics.newInstance(); + } + + @Override + public DeviceMetrics unpack(ProtobufDeviceMetrics msg) { + return new DeviceMetrics( + msg.getCpuTemp(), + msg.getCpuUtil(), + msg.getCpuThr(), + msg.getRamMem(), + msg.getRamUtil(), + msg.getGpuMem(), + msg.getGpuMemUtil(), + msg.getDiskUtilPct(), + msg.getNpuUsage().toArray(), + msg.getIpAddress(), + msg.getUptime()); + } + + @Override + public void pack(ProtobufDeviceMetrics msg, DeviceMetrics value) { + msg.setCpuTemp(value.cpuTemp()); + msg.setCpuUtil(value.cpuUtil()); + msg.setRamMem(value.ramMem()); + msg.setCpuThr(value.cpuThr()); + msg.setUptime(value.uptime()); + msg.setGpuMem(value.gpuMem()); + msg.setRamUtil(value.ramUtil()); + msg.setGpuMemUtil(value.gpuMemUtil()); + msg.setDiskUtilPct(value.diskUtilPct()); + msg.addAllNpuUsage(value.npuUsage()); + msg.setIpAddress(value.ipAddress()); + } +} diff --git a/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java b/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java index 9d371d25f8..f5fa86cbe5 100644 --- a/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java +++ b/photon-core/src/test/java/org/photonvision/hardware/HardwareTest.java @@ -20,16 +20,25 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.IOException; import org.junit.jupiter.api.Test; import org.photonvision.common.hardware.GPIO.CustomGPIO; import org.photonvision.common.hardware.GPIO.GPIOBase; import org.photonvision.common.hardware.GPIO.pi.PigpioPin; import org.photonvision.common.hardware.Platform; import org.photonvision.common.hardware.metrics.MetricsManager; +import org.photonvision.common.util.TestUtils; +import org.photonvision.jni.PhotonTargetingJniLoader; public class HardwareTest { @Test public void testHardware() { + try { + TestUtils.loadLibraries(); + PhotonTargetingJniLoader.load(); + } catch (UnsatisfiedLinkError | IOException e) { + e.printStackTrace(); + } MetricsManager mm = new MetricsManager(); if (!Platform.isRaspberryPi()) return; @@ -37,15 +46,15 @@ public void testHardware() { System.out.println("Testing on platform: " + Platform.getPlatformName()); System.out.println("Printing CPU Info:"); - System.out.println("Memory: " + mm.getMemory() + "MB"); - System.out.println("Temperature: " + mm.getTemp() + "C"); - System.out.println("Utilization: : " + mm.getUtilization() + "%"); + System.out.println("Memory: " + mm.getRamMem() + "MB"); + System.out.println("Temperature: " + mm.getCpuTemp() + "C"); + System.out.println("Utilization: : " + mm.getCpuUtilization() + "%"); System.out.println("Printing GPU Info:"); - System.out.println("Memory: " + mm.getGPUMemorySplit() + "MB"); + System.out.println("Memory: " + mm.getGpuMem() + "MB"); System.out.println("Printing RAM Info: "); - System.out.println("Used RAM: : " + mm.getUsedRam() + "MB"); + System.out.println("Used RAM: : " + mm.getRamUtil() + "MB"); } @Test diff --git a/photon-targeting/src/main/proto/photon.proto b/photon-targeting/src/main/proto/photon.proto index 6650785bd6..0ff3991f9d 100644 --- a/photon-targeting/src/main/proto/photon.proto +++ b/photon-targeting/src/main/proto/photon.proto @@ -68,3 +68,17 @@ message ProtobufPhotonPipelineResult { int64 nt_publish_timestamp_micros = 6; int64 time_since_last_pong_micros = 7; } + +message ProtobufDeviceMetrics { + double cpu_temp = 1; + double cpu_util = 2; + string cpu_thr = 3; + double ram_mem = 4; + double ram_util = 5; + double gpu_mem = 6; + double gpu_mem_util = 7; + double disk_util_pct = 8; + repeated double npu_usage = 9; + string ip_address = 10; + double uptime = 11; +}