#include #include #include #include #include #include #include #include #include #include #include #include #include "include/LCDDisplay.hpp" #include "include/gpu.hpp" #include "include/utils.hpp" #define LCD_PORT "/dev/ttyACM0" #define LCD_INTERVAL_MS 1000 #define LCD_CONTRAST 215 #define FILL_CHAR ' ' struct mem_usage_t { uint64_t free; uint64_t used; uint64_t total; }; /* DISPLAY FUNCS */ std::string pBytes(double i, bool isKbytes = false) { std::stringstream ss; std::array suffix = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; for (auto &s : suffix) { if (s == 'K' && isKbytes) continue; i /= 1024.0; if (i < 1024) { uint8_t p = 2; if (i > 10) p = 1; if (i > 100) p = 0; ss << std::fixed << std::setprecision(p) << i << s; return ss.str(); } } return "++++"; } // converts number to string with given decimal places std::string pNum(auto num, uint8_t decs = 0) { std::stringstream ss; ss << std::fixed << std::setprecision(decs) << num; return ss.str(); } // pads given string to size std::string pad(std::string s, uint8_t w, bool ljust = false) { if (w > s.size()) s.insert(ljust ? s.end() : s.begin(), w - s.size(), FILL_CHAR); return s; } // fills n spaces std::string fill(uint8_t n) { return std::string(n, FILL_CHAR); } /* getters */ std::string getAvgs() { std::stringstream ss; double avgs[3]; getloadavg(avgs, 3); for (uint8_t i = 0; i < 3; i++) { ss << std::fixed << std::setprecision(avgs[i] > 10 ? 1 : 2); ss << " " << avgs[i]; } return ss.str(); } std::array getTimeDate() { std::array months = {"sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paz", "lis", "gru"}; std::array wdays = {"nie", "pon", "wto", "sro", "czw", "pia", "sob"}; auto now = std::time(nullptr); auto tm = *std::localtime(&now); std::stringstream time, date; time << std::setfill('0'); time << std::setw(2) << tm.tm_hour << ":"; time << std::setw(2) << tm.tm_min << ":"; time << std::setw(2) << tm.tm_sec; date << wdays[tm.tm_wday] << ", " << tm.tm_mday << " " << months[tm.tm_mon]; return {time.str(), date.str()}; } mem_usage_t getRam() { mem_usage_t mem; std::ifstream proc_meminfo("/proc/meminfo"); if (proc_meminfo.good()) { std::string content((std::istreambuf_iterator(proc_meminfo)), std::istreambuf_iterator()); mem.free = get_val("MemAvailable:", content); mem.total = get_val("MemTotal:", content); mem.used = mem.total - mem.free; } proc_meminfo.close(); return mem; } mem_usage_t getDisk(std::string mount) { mem_usage_t disk; struct statvfs diskData; statvfs(mount.c_str(), &diskData); disk.free = diskData.f_bfree * diskData.f_frsize; disk.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize; disk.total = diskData.f_blocks * diskData.f_frsize; return disk; } 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; 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; } int main(int argc, char *argv[]) { bool daemon_mode = (argc > 1 && std::string(argv[1]) == "-d"); /* 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); } /* initial vars */ std::array lines; auto cpu_hwmon = findHwmonPath("k10temp"); 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; std::chrono::milliseconds interval(LCD_INTERVAL_MS); auto start = std::chrono::steady_clock::now(); /* main loop */ while (true) { auto td = getTimeDate(); auto ram = getRam(); auto anime = getDisk("/mnt/anime"); auto home = getDisk("/var/home/drath"); auto gpu = getGpu(gpu_mtr_rev, gpu_hwmon); auto cpu = getCpuTemp(cpu_hwmon); 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) + 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) + lcd.cc[0], 11); 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(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); lcd.writeLines(lines); if (daemon_mode) { std::this_thread::sleep_until(start + interval); start += interval; } else { break; } } return 0; }