From c35fca94eafb0d9951c6415347efb26ac4ce0290 Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Sat, 11 May 2024 14:29:53 -0700 Subject: [PATCH] Visuals - Developer UI - Sidebar Display various custom metrics on the sidebar for the CPU, GPU, RAM, IP, and storage used/left. --- selfdrive/ui/qt/sidebar.cc | 129 ++++++++++++++++++++++++++++++++--- selfdrive/ui/qt/sidebar.h | 14 ++++ selfdrive/ui/ui.cc | 7 ++ selfdrive/ui/ui.h | 7 ++ system/hardware/hardwared.py | 5 +- system/loggerd/config.py | 11 +++ 6 files changed, 163 insertions(+), 10 deletions(-) diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index dcea96176..9fde190b0 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -97,11 +97,46 @@ void Sidebar::mousePressEvent(QMouseEvent *event) { QPoint pos = event->pos(); + QRect cpuRect = {30, 496, 240, 126}; + QRect memoryRect = {30, 654, 240, 126}; QRect tempRect = {30, 338, 240, 126}; + static int showChip = 0; + static int showMemory = 0; static int showTemp = 0; - if (tempRect.contains(pos)) { + if (cpuRect.contains(pos) && sidebarMetrics) { + showChip = (showChip + 1) % 3; + + isCPU = (showChip == 1); + isGPU = (showChip == 2); + + scene.is_CPU = isCPU; + scene.is_GPU = isGPU; + + params.putBoolNonBlocking("ShowCPU", isCPU); + params.putBoolNonBlocking("ShowGPU", isGPU); + + update(); + return; + } else if (memoryRect.contains(pos) && sidebarMetrics) { + showMemory = (showMemory + 1) % 4; + + isMemoryUsage = (showMemory == 1); + isStorageLeft = (showMemory == 2); + isStorageUsed = (showMemory == 3); + + scene.is_memory = isMemoryUsage; + scene.is_storage_left = isStorageLeft; + scene.is_storage_used = isStorageUsed; + + params.putBoolNonBlocking("ShowMemoryUsage", isMemoryUsage); + params.putBoolNonBlocking("ShowStorageLeft", isStorageLeft); + params.putBoolNonBlocking("ShowStorageUsed", isStorageUsed); + + update(); + return; + } else if (tempRect.contains(pos) && sidebarMetrics) { showTemp = (showTemp + 1) % 3; scene.fahrenheit = showTemp == 2; @@ -169,11 +204,65 @@ void Sidebar::updateState(const UIState &s) { auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState(); + isCPU = scene.is_CPU; + isGPU = scene.is_GPU; + isIP = scene.is_IP; + isMemoryUsage = scene.is_memory; isNumericalTemp = scene.numerical_temp; + isStorageLeft = scene.is_storage_left; + isStorageUsed = scene.is_storage_used; + sidebarMetrics = scene.sidebar_metrics; int maxTempC = deviceState.getMaxTempC(); QString max_temp = scene.fahrenheit ? QString::number(maxTempC * 9 / 5 + 32) + "°F" : QString::number(maxTempC) + "°C"; + if (isCPU || isGPU) { + auto cpu_loads = deviceState.getCpuUsagePercent(); + int cpu_usage = cpu_loads.size() != 0 ? std::accumulate(cpu_loads.begin(), cpu_loads.end(), 0) / cpu_loads.size() : 0; + int gpu_usage = deviceState.getGpuUsagePercent(); + + QString cpu = QString::number(cpu_usage) + "%"; + QString gpu = QString::number(gpu_usage) + "%"; + + QString metric = isGPU ? gpu : cpu; + int usage = isGPU ? gpu_usage : cpu_usage; + + ItemStatus cpuStatus = {{isGPU ? tr("GPU") : tr("CPU"), metric}, currentColors[0]}; + if (usage >= 85) { + cpuStatus = {{isGPU ? tr("GPU") : tr("CPU"), metric}, danger_color}; + } else if (usage >= 70) { + cpuStatus = {{isGPU ? tr("GPU") : tr("CPU"), metric}, warning_color}; + } + setProperty("cpuStatus", QVariant::fromValue(cpuStatus)); + } + + if (isMemoryUsage || isStorageLeft || isStorageUsed) { + int memory_usage = deviceState.getMemoryUsagePercent(); + int storage_left = frogpilotDeviceState.getFreeSpace(); + int storage_used = frogpilotDeviceState.getUsedSpace(); + + QString memory = QString::number(memory_usage) + "%"; + QString storage = QString::number(isStorageLeft ? storage_left : storage_used) + tr(" GB"); + + if (isMemoryUsage) { + ItemStatus memoryStatus = {{tr("MEMORY"), memory}, currentColors[0]}; + if (memory_usage >= 85) { + memoryStatus = {{tr("MEMORY"), memory}, danger_color}; + } else if (memory_usage >= 70) { + memoryStatus = {{tr("MEMORY"), memory}, warning_color}; + } + setProperty("memoryStatus", QVariant::fromValue(memoryStatus)); + } else { + ItemStatus storageStatus = {{isStorageLeft ? tr("LEFT") : tr("USED"), storage}, currentColors[0]}; + if (25 > storage_left && storage_left >= 10) { + storageStatus = {{isStorageLeft ? tr("LEFT") : tr("USED"), storage}, warning_color}; + } else if (10 > storage_left) { + storageStatus = {{isStorageLeft ? tr("LEFT") : tr("USED"), storage}, danger_color}; + } + setProperty("storageStatus", QVariant::fromValue(storageStatus)); + } + } + ItemStatus connectStatus; auto last_ping = deviceState.getLastAthenaPingTime(); if (last_ping == 0) { @@ -220,19 +309,41 @@ void Sidebar::paintEvent(QPaintEvent *event) { // network int x = 58; const QColor gray(0x54, 0x54, 0x54); - for (int i = 0; i < 5; ++i) { - p.setBrush(i < net_strength ? Qt::white : gray); - p.drawEllipse(x, 196, 27, 27); - x += 37; + p.setFont(InterFont(35)); + + if (isIP) { + p.setPen(QColor(0xff, 0xff, 0xff)); + p.save(); + p.setFont(InterFont(30)); + QRect ipBox = QRect(50, 196, 225, 27); + p.drawText(ipBox, Qt::AlignLeft | Qt::AlignVCenter, uiState()->wifi->getIp4Address()); + p.restore(); + } else { + for (int i = 0; i < 5; ++i) { + p.setBrush(i < net_strength ? Qt::white : gray); + p.drawEllipse(x, 196, 27, 27); + x += 37; + } + p.setPen(QColor(0xff, 0xff, 0xff)); } - p.setFont(InterFont(35)); - p.setPen(QColor(0xff, 0xff, 0xff)); const QRect r = QRect(50, 247, 100, 50); p.drawText(r, Qt::AlignCenter, net_type); // metrics drawMetric(p, temp_status.first, temp_status.second, 338); - drawMetric(p, panda_status.first, panda_status.second, 496); - drawMetric(p, connect_status.first, connect_status.second, 654); + + if (isCPU || isGPU) { + drawMetric(p, cpu_status.first, cpu_status.second, 496); + } else { + drawMetric(p, panda_status.first, panda_status.second, 496); + } + + if (isMemoryUsage) { + drawMetric(p, memory_status.first, memory_status.second, 654); + } else if (isStorageLeft || isStorageUsed) { + drawMetric(p, storage_status.first, storage_status.second, 654); + } else { + drawMetric(p, connect_status.first, connect_status.second, 654); + } } diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index a63c3ac8a..e2263f799 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -18,6 +18,11 @@ class Sidebar : public QFrame { Q_PROPERTY(QString netType MEMBER net_type NOTIFY valueChanged); Q_PROPERTY(int netStrength MEMBER net_strength NOTIFY valueChanged); + // FrogPilot properties + Q_PROPERTY(ItemStatus cpuStatus MEMBER cpu_status NOTIFY valueChanged) + Q_PROPERTY(ItemStatus memoryStatus MEMBER memory_status NOTIFY valueChanged) + Q_PROPERTY(ItemStatus storageStatus MEMBER storage_status NOTIFY valueChanged) + public: explicit Sidebar(QWidget* parent = 0); @@ -63,7 +68,16 @@ private: // FrogPilot variables Params params; + ItemStatus cpu_status, memory_status, storage_status; + + bool isCPU; + bool isGPU; + bool isIP; + bool isMemoryUsage; bool isNumericalTemp; + bool isStorageLeft; + bool isStorageUsed; + bool sidebarMetrics; std::unordered_map>> themeConfiguration; std::unordered_map flag_imgs; diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 6235c8080..536399a56 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -364,6 +364,13 @@ void ui_update_frogpilot_params(UIState *s, Params ¶ms) { scene.show_jerk = show_longitudinal && params.getBool("JerkInfo"); scene.numerical_temp = developer_ui && params.getBool("NumericalTemp"); scene.fahrenheit = scene.numerical_temp && params.getBool("Fahrenheit"); + scene.sidebar_metrics = developer_ui && params.getBool("SidebarMetrics"); + scene.is_CPU = scene.sidebar_metrics && params.getBool("ShowCPU"); + scene.is_GPU = scene.sidebar_metrics && params.getBool("ShowGPU"); + scene.is_IP = scene.sidebar_metrics && params.getBool("ShowIP"); + scene.is_memory = scene.sidebar_metrics && params.getBool("ShowMemoryUsage"); + scene.is_storage_left = scene.sidebar_metrics && params.getBool("ShowStorageLeft"); + scene.is_storage_used = scene.sidebar_metrics && params.getBool("ShowStorageUsed"); scene.disable_smoothing_mtsc = params.getBool("MTSCEnabled") && params.getBool("DisableMTSCSmoothing"); scene.disable_smoothing_vtsc = params.getBool("VisionTurnControl") && params.getBool("DisableVTSCSmoothing"); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 9c4983e51..0b6fd96fd 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -142,6 +142,12 @@ typedef struct UIScene { bool has_auto_tune; bool has_lead; bool holiday_themes; + bool is_CPU; + bool is_GPU; + bool is_IP; + bool is_memory; + bool is_storage_left; + bool is_storage_used; bool lead_info; bool live_valid; bool map_open; @@ -171,6 +177,7 @@ typedef struct UIScene { bool show_stopping_point; bool show_stopping_point_metrics; bool show_tuning; + bool sidebar_metrics; bool speed_limit_changed; bool speed_limit_controller; bool speed_limit_overridden; diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index 7f6ca90cd..f6e5abd3d 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -18,7 +18,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import DT_HW from openpilot.selfdrive.controls.lib.alertmanager import set_offroad_alert from openpilot.system.hardware import HARDWARE, TICI, AGNOS -from openpilot.system.loggerd.config import get_available_percent +from openpilot.system.loggerd.config import get_available_bytes, get_available_percent, get_used_bytes from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.system.hardware.power_monitoring import PowerMonitoring @@ -419,6 +419,9 @@ def hardware_thread(end_event, hw_queue) -> None: fpmsg = messaging.new_message('frogpilotDeviceState') + fpmsg.frogpilotDeviceState.freeSpace = round(get_available_bytes(default=32.0 * (2 ** 30)) / (2 ** 30)) + fpmsg.frogpilotDeviceState.usedSpace = round(get_used_bytes(default=0.0 * (2 ** 30)) / (2 ** 30)) + pm.send("frogpilotDeviceState", fpmsg) # Log to statsd diff --git a/system/loggerd/config.py b/system/loggerd/config.py index 5c2c89b73..03abe216c 100644 --- a/system/loggerd/config.py +++ b/system/loggerd/config.py @@ -27,3 +27,14 @@ def get_available_bytes(default=None): available_bytes = default return available_bytes + +def get_used_bytes(default=None): + try: + statvfs = os.statvfs(Paths.log_root()) + total_bytes = statvfs.f_blocks * statvfs.f_frsize + available_bytes = get_available_bytes(default) + used_bytes = total_bytes - available_bytes + except OSError: + used_bytes = default + + return used_bytes