diff --git a/cereal/custom.capnp b/cereal/custom.capnp index 46206913e..5650f580a 100644 --- a/cereal/custom.capnp +++ b/cereal/custom.capnp @@ -16,6 +16,8 @@ struct FrogPilotCarState @0xaedffd8f31e7b55d { } struct FrogPilotDeviceState @0xf35cc4560bbf6ec2 { + freeSpace @0 :Int16; + usedSpace @1 :Int16; } struct FrogPilotNavigation @0xda96579883444c35 { diff --git a/common/params.cc b/common/params.cc index 84d837a9c..15d941353 100644 --- a/common/params.cc +++ b/common/params.cc @@ -279,6 +279,11 @@ std::unordered_map keys = { {"RelaxedFollow", PERSISTENT}, {"RelaxedJerk", PERSISTENT}, {"RoadEdgesWidth", PERSISTENT}, + {"ShowCPU", PERSISTENT}, + {"ShowGPU", PERSISTENT}, + {"ShowMemoryUsage", PERSISTENT}, + {"ShowStorageLeft", PERSISTENT}, + {"ShowStorageUsed", PERSISTENT}, {"StandardFollow", PERSISTENT}, {"StandardJerk", PERSISTENT}, {"StockTune", PERSISTENT}, diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index da1d09e7c..926f0ce6b 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -18,7 +18,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import DT_TRML 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.selfdrive.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring @@ -248,6 +248,9 @@ def thermald_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) msg.deviceState.freeSpacePercent = get_available_percent(default=100.0) diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 22f234570..334f9ba70 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -40,6 +40,13 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed( pm = std::make_unique>({"userFlag"}); // FrogPilot variables + isCPU = params.getBool("ShowCPU"); + isGPU = params.getBool("ShowGPU"); + + isMemoryUsage = params.getBool("ShowMemoryUsage"); + isStorageLeft = params.getBool("ShowStorageLeft"); + isStorageUsed = params.getBool("ShowStorageUsed"); + themeConfiguration = { {0, {"stock", {QColor(255, 255, 255)}}}, {1, {"frog_theme", {QColor(23, 134, 68)}}}, @@ -64,7 +71,37 @@ Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed( } void Sidebar::mousePressEvent(QMouseEvent *event) { - if (onroad && home_btn.contains(event->pos())) { + // Declare the click boxes + QRect cpuRect = {30, 496, 240, 126}; + QRect memoryRect = {30, 654, 240, 126}; + + static int showChip = 0; + static int showMemory = 0; + + // Swap between the respective metrics upon tap + if (cpuRect.contains(event->pos())) { + showChip = (showChip + 1) % 3; + + isCPU = (showChip == 1); + isGPU = (showChip == 2); + + params.putBoolNonBlocking("ShowCPU", isCPU); + params.putBoolNonBlocking("ShowGPU", isGPU); + + update(); + } else if (memoryRect.contains(event->pos())) { + showMemory = (showMemory + 1) % 4; + + isMemoryUsage = (showMemory == 1); + isStorageLeft = (showMemory == 2); + isStorageUsed = (showMemory == 3); + + params.putBoolNonBlocking("ShowMemoryUsage", isMemoryUsage); + params.putBoolNonBlocking("ShowStorageLeft", isStorageLeft); + params.putBoolNonBlocking("ShowStorageUsed", isStorageUsed); + + update(); + } else if (onroad && home_btn.contains(event->pos())) { flag_pressed = true; update(); } else if (settings_btn.contains(event->pos())) { @@ -111,6 +148,54 @@ void Sidebar::updateState(const UIState &s) { auto frogpilotDeviceState = sm["frogpilotDeviceState"].getFrogpilotDeviceState(); + // FrogPilot metrics + if (isCPU || isGPU) { + auto cpu_loads = deviceState.getCpuUsagePercent(); + int cpu_usage = std::accumulate(cpu_loads.begin(), cpu_loads.end(), 0) / cpu_loads.size(); + 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) { @@ -170,6 +255,18 @@ void Sidebar::paintEvent(QPaintEvent *event) { // 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 22656af64..9989dbc32 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -19,6 +19,9 @@ class Sidebar : public QFrame { 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); @@ -66,6 +69,14 @@ private: Params params; UIScene &scene; + ItemStatus cpu_status, memory_status, storage_status; + + bool isCPU; + bool isGPU; + bool isMemoryUsage; + bool isStorageLeft; + bool isStorageUsed; + std::unordered_map>> themeConfiguration; std::unordered_map flag_imgs; std::unordered_map home_imgs; 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