From 8632cab336b6b4bb99b7e4595d70d4e06bbaf09c Mon Sep 17 00:00:00 2001 From: Drath Date: Sat, 3 May 2025 20:20:15 +0200 Subject: [PATCH] add bar drawing, use pointers more --- Makefile | 6 ++--- README.md | 11 ++++++++ include/LCDDisplay.hpp | 4 +++ include/gpu.hpp | 9 ++++++- main.cpp | 61 +++++++++++++++++++++++++++++++----------- src/LCDDisplay.cpp | 30 ++++++++++++++------- src/gpu.cpp | 19 +++++-------- 7 files changed, 99 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index 646ece1..4917439 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ MAKEFLAGS := --jobs=16 # compiling with C++26 CXXFLAGS := -std=c++2c -Ofast -fdiagnostics-color=always -Iinclude -# CXXFLAGS += -MMD -MP +CXXFLAGS += -MMD -MP SOURCES := main.cpp $(wildcard src/*.cpp) OBJECTS := $(SOURCES:.cpp=.o) -# DEPS := $(OBJECTS:.o=.d) +DEPS := $(OBJECTS:.o=.d) TEST_SRC := test.cpp $(wildcard src/*.cpp) TEST_OBJS := $(TEST_SRC:.cpp=.o) @@ -24,7 +24,7 @@ test: $(TEST_OBJS) %.o: %.cpp g++ $(CXXFLAGS) -c $< -o $@ -# -include $(DEPS) +-include $(DEPS) .PHONY: clean clean: diff --git a/README.md b/README.md index eb83962..8ff2bac 100644 --- a/README.md +++ b/README.md @@ -50,3 +50,14 @@ Text02="$dll(hwinfo,1,1|CPU Die (average),0|a)/$dll(hwinfo,1,1|L3 Cache (CCD1),0 Text03="$dll(hwinfo,1,5|1,0)W$Fill(5)$dll(hwinfo,1,3|2,)R$Fill(14)$Right($dll(tasmopwr,1,tasmota-plug-pc.lan,)W,$6%)$Fill(21)$Right($dll(hwinfo,1,GPU|3|1,)R,$5%)$Fill(27)$Right($dll(hwinfo,1,GPU|5|9,0)/$dll(hwinfo,1,GPU|5|10,0)W,$8%)$Fill(36)$Right($dll(hwinfo,1,GPU|5|7,0)W,$4%)" Text04="$dll(hwinfo,1,Vcore,3)V $Right($dll(hwinfo,1,Average Effective Clock,a)MHz,$7%)$Fill(16)$dll(hwinfo,1,GPU Shader Clock Frequency Limit,)$Fill(21)$Right($dll(hwinfo,1,GPU|6|2,)/$dll(hwinfo,1,GPU|6|4,)MHz,$12%)$Fill(34)$dll(hwinfo,1,GPU|2|1,3)V$CustomChar(1,16,6,9,8,8,9,6,0)" ``` + +### So what's still missing +- Tasmota wall power, doable +- Average CPU freq, doable +- Per-core CPU load, doable but annoying +- FPS counter, maybe possible? +- Active core count, probably impossible but loadAvg is better? +- GPU board power, probably impossible, it was estimated on windows anyway +- CPU cache/iod, likely impossible, zenpower doesnt show it +- GPU clock limit, probably impossible, amdgpu doesnt show it? +- CPU fan, likely impossible, no modules diff --git a/include/LCDDisplay.hpp b/include/LCDDisplay.hpp index a85c886..1d9bf51 100644 --- a/include/LCDDisplay.hpp +++ b/include/LCDDisplay.hpp @@ -12,6 +12,9 @@ class LCDDisplay { LCDDisplay(std::string dev, uint32_t baud); ~LCDDisplay(); + // custom char array + char cc[8] = {'\0', '\1', '\2', '\3', '\4', '\5', '\6', '\7'}; + void clear(); void setContrast(uint8_t contrast); void setBacklight(bool enabled); @@ -19,4 +22,5 @@ class LCDDisplay { void writeLines(std::array lines); void writeSStream(std::stringstream& ss); void setCustomChar(uint8_t index, std::array cchar); + char bar(uint8_t char_id, double value); }; diff --git a/include/gpu.hpp b/include/gpu.hpp index 049c157..6dad241 100644 --- a/include/gpu.hpp +++ b/include/gpu.hpp @@ -22,4 +22,11 @@ struct gpu_t { uint8_t umc_usage; }; -gpu_t getGpu(std::string hw); \ No newline at end of file +struct GpuMetricsHeader_t { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; +}; + +gpu_t getGpu(GpuMetricsHeader_t header, std::string hw); +GpuMetricsHeader_t getGpuMetricsRev(std::string path); \ No newline at end of file diff --git a/main.cpp b/main.cpp index 329c3c3..2cc9232 100644 --- a/main.cpp +++ b/main.cpp @@ -115,24 +115,40 @@ mem_usage_t getDisk(std::string mount) { auto getCpuTemp(std::string hw) { struct { + double tdie; double tctl; double tccd1; + double pcore = 0.0; + double psoc = 0.0; + double ptotal = 0.0; + double vcore = 0.0; + double vsoc = 0.0; } cpu; - cpu.tctl = (double)(std::stoul(readFile(hw + "/temp1_input")) / 1000.0); - cpu.tccd1 = (double)(std::stoul(readFile(hw + "/temp3_input")) / 1000.0); + if (readFile(hw + "/name") == "zenpower") { + cpu.tdie = (double)(std::stoul(readFile(hw + "/temp1_input")) / 1000.0); + cpu.tctl = (double)(std::stoul(readFile(hw + "/temp2_input")) / 1000.0); + cpu.tccd1 = (double)(std::stoul(readFile(hw + "/temp3_input")) / 1000.0); + cpu.pcore = (double)(std::stoul(readFile(hw + "/power1_input")) / 1000000.0); + cpu.psoc = (double)(std::stoul(readFile(hw + "/power2_input")) / 1000000.0); + cpu.ptotal = cpu.pcore + cpu.psoc; + cpu.vcore = (double)(std::stoul(readFile(hw + "/in1_input")) / 1000.0); + cpu.vsoc = (double)(std::stoul(readFile(hw + "/in2_input")) / 1000.0); + } else { + cpu.tctl = (double)(std::stoul(readFile(hw + "/temp1_input")) / 1000.0); + cpu.tccd1 = (double)(std::stoul(readFile(hw + "/temp3_input")) / 1000.0); + } return cpu; } -void collectAndDraw(LCDDisplay *lcd) { -} - int main(int argc, char *argv[]) { bool daemon_mode = (argc > 1 && std::string(argv[1]) == "-d"); - /* init lcd, set contrast and backlight */ + /* init lcd and chars, set contrast and backlight */ LCDDisplay lcd(LCD_PORT, 0010002); + lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius + /* only set in daemon mode, so we dont burn through eeprom writes if running with watch -n 1 when testing */ if (daemon_mode) { lcd.setContrast(LCD_CONTRAST); lcd.setBacklight(true); @@ -141,7 +157,21 @@ int main(int argc, char *argv[]) { /* initial vars */ std::array lines; auto cpu_hwmon = findHwmonPath("k10temp"); - auto gpu_hwmon = "/sys/class/drm/card1/device"; + if (cpu_hwmon.size() == 0) { + std::cout << "[Hwmon] k10temp not found, trying zenpower" << std::endl; + cpu_hwmon = findHwmonPath("zenpower"); + } + + std::string gpu_hwmon; + GpuMetricsHeader_t gpu_mtr_rev; + for(uint8_t i = 0; i < 10; i++) { + gpu_hwmon = "/sys/class/drm/card" + std::to_string(i) + "/device"; + gpu_mtr_rev = getGpuMetricsRev(gpu_hwmon + "/gpu_metrics"); + if(gpu_mtr_rev.structure_size > 0) + break; + } + + /* loop setup */ std::cout << "[Chrono] Running in daemon mode, " << LCD_INTERVAL_MS << "ms interval" << std::endl; @@ -154,24 +184,25 @@ int main(int argc, char *argv[]) { auto ram = getRam(); auto anime = getDisk("/mnt/anime"); auto home = getDisk("/var/home/drath"); - auto gpu = getGpu(gpu_hwmon); + auto gpu = getGpu(gpu_mtr_rev, gpu_hwmon); auto cpu = getCpuTemp(cpu_hwmon); - lines[0] = td[1] + " " + td[0] + pad(getAvgs(), 20); + lines[0] = td[1] + " " + td[0] + lcd.bar(1, gpu.core_usage / 100.0) + pad(getAvgs(), 17); - lines[1] = pad(pNum(cpu.tctl) + "/" + pNum(cpu.tccd1) + "C", 8, true); + lines[1] = pad(pNum(cpu.tctl) + "/" + pNum(cpu.tccd1) + lcd.cc[0], 8, true); lines[1] += pad(pBytes(ram.used, true) + "B", 7, true); lines[1] += fill(7); lines[1] += pad(pBytes(gpu.vram_used) + "B", 7); - lines[1] += pad(std::to_string(gpu.edge_temp) + "/" + std::to_string(gpu.hotspot_temp) + "/" + std::to_string(gpu.mem_temp) + "C", 11); + lines[1] += pad(std::to_string(gpu.edge_temp) + "/" + std::to_string(gpu.hotspot_temp) + "/" + std::to_string(gpu.mem_temp) + lcd.cc[0], 11); - lines[2] = pad("home: " + pBytes(home.free), 11, true); - lines[2] += fill(15); + lines[2] = pad(pNum(cpu.ptotal, 1) + "W", 8, true); + lines[2] += pad("home: " + pBytes(home.free), 12); + lines[2] += fill(6); lines[2] += pad(pNum(gpu.fan_speed) + "R", 5); lines[2] += pad(std::to_string(gpu.power_avg) + "/" + std::to_string(gpu.power_cap) + "W", 9); - lines[3] = pad("anime: " + pBytes(anime.free), 13, true); - lines[3] += fill(8); + lines[3] = pad(pNum(cpu.vcore, 3) + "V", 6, true); + lines[3] += fill(15); lines[3] += pad(pNum(gpu.core_clock) + "/" + pNum(gpu.mem_clock) + "MHz ", 13); lines[3] += pad(pNum(gpu.vcore, 3) + "V", 5); diff --git a/src/LCDDisplay.cpp b/src/LCDDisplay.cpp index 991f5e1..00990b6 100644 --- a/src/LCDDisplay.cpp +++ b/src/LCDDisplay.cpp @@ -36,24 +36,24 @@ LCDDisplay::~LCDDisplay() { void LCDDisplay::clear() { uint8_t cmdbuf[] = {254, 88}; - write(_lcd, cmdbuf, 2); + write(_lcd, &cmdbuf, 2); } void LCDDisplay::setContrast(uint8_t contrast) { std::cout << "[LCDDisplay] Set contrast to " << std::to_string(contrast) << std::endl; uint8_t cmdbuf[] = {254, 80, contrast}; - write(_lcd, cmdbuf, 3); + write(_lcd, &cmdbuf, 3); } void LCDDisplay::setBacklight(bool enabled) { std::cout << "[LCDDisplay] Backlight set to " << std::to_string(enabled) << std::endl; uint8_t cmdbuf[] = {254, (uint8_t)(enabled ? 66 : 70), 255}; - write(_lcd, cmdbuf, enabled ? 3 : 2); + write(_lcd, &cmdbuf, enabled ? 3 : 2); } void LCDDisplay::setCursor(uint8_t row, uint8_t col) { uint8_t cmdbuf[] = {254, 71, (uint8_t)(col + 1), (uint8_t)(row + 1)}; - write(_lcd, cmdbuf, 4); + write(_lcd, &cmdbuf, 4); } void LCDDisplay::writeStr(std::string str) { @@ -62,7 +62,7 @@ void LCDDisplay::writeStr(std::string str) { void LCDDisplay::writeLines(std::array lines) { for (auto& line : lines) { - if(line.size() > 40) { + if (line.size() > 40) { std::cerr << "Line " << line << " too long! (" << line.size() << " chars)" << std::endl; continue; } @@ -85,10 +85,22 @@ void LCDDisplay::writeSStream(std::stringstream& ss) { writeStr(s.substr(80, 159)); } + void LCDDisplay::setCustomChar(uint8_t index, std::array cchar) { uint8_t cmdbuf[11]; - cmdbuf[0] = 254; cmdbuf[1] = 78; cmdbuf[2] = index; - for(uint8_t i = 0; i < 8; i++) - cmdbuf[i+3] = cchar[i]; - write(_lcd, cmdbuf, 11); + cmdbuf[0] = 254; + cmdbuf[1] = 78; + cmdbuf[2] = index; + for (uint8_t i = 0; i < 8; i++) + cmdbuf[i + 3] = cchar[i]; + write(_lcd, &cmdbuf, 11); +} + +char LCDDisplay::bar(uint8_t char_id, double value) { + std::array b; + b.fill(0b01110); + for(uint8_t i = 0; i < (1.0 - value) * 8; i++) + b[i] = 0; + setCustomChar(char_id, b); + return cc[char_id]; } \ No newline at end of file diff --git a/src/gpu.cpp b/src/gpu.cpp index e22c37d..14293f0 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -5,12 +5,6 @@ #include #include -struct GpuMetricsHeader_t { - uint16_t structure_size; - uint8_t format_revision; - uint8_t content_revision; -}; - struct GpuMetrics_v1_1_t { uint16_t temperature_edge; uint16_t temperature_hotspot; @@ -95,11 +89,11 @@ GpuMetricsHeader_t getGpuMetricsRev(std::string path) { std::ifstream f(path, std::ios::binary); if (f.good()) { f.read(reinterpret_cast(&header), sizeof(header)); - std::cout << "[GpuMetrics] Read GpuMetrics format v" << std::to_string(header.format_revision) << "_" << std::to_string(header.content_revision); + std::cout << "[GpuMetrics] header at path " + path + " read, GpuMetrics_v" << std::to_string(header.format_revision) << "_" << std::to_string(header.content_revision); std::cout << ", size " << std::to_string(header.structure_size) << std::endl; f.close(); } else { - std::cerr << "[GpuMetrics] Error reading gpu metrics header" << std::endl; + std::cerr << "[GpuMetrics] error reading header at path " + path << std::endl; } return header; @@ -122,15 +116,14 @@ auto getGpuMetrics(GpuMetricsHeader_t h, std::string path) { } // clean abstraction of gpu_metrics + extra metrics from fs -gpu_t getGpu(std::string hw) { +gpu_t getGpu(GpuMetricsHeader_t header, std::string hw) { gpu_t gpu; - auto h = getGpuMetricsRev(hw + "/gpu_metrics"); - auto metrics = getGpuMetrics(h, hw + "/gpu_metrics"); + auto metrics = getGpuMetrics(header, hw + "/gpu_metrics"); // we want as much data as posible from gpu_metrics so we dont read filesystem as much gpu.fan_speed = std::stol(readFile(hw + "/hwmon/hwmon2/fan1_input")); - gpu.core_clock = metrics.average_vclk1_frequency; // why not gfxclock? - gpu.mem_clock = metrics.average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping + gpu.core_clock = metrics.average_vclk1_frequency; // why not gfxclock? + gpu.mem_clock = metrics.average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping gpu.vcore = std::stod(readFile(hw + "/hwmon/hwmon2/in0_input")) / 1000.0; gpu.power_avg = metrics.average_socket_power; gpu.power_cap = std::stol(readFile(hw + "/hwmon/hwmon2/power1_cap", 6));