From e8dc798e26fce2def9322bfc41d5d5f01a4ebb3f Mon Sep 17 00:00:00 2001 From: Drath Date: Sat, 13 Sep 2025 18:00:56 +0200 Subject: [PATCH] lotsa changes again --- main.cpp | 138 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 58 deletions(-) diff --git a/main.cpp b/main.cpp index ac505a4..68915bb 100644 --- a/main.cpp +++ b/main.cpp @@ -4,9 +4,10 @@ #include #include #include -#include +#include +#include #include -#include +#include #include #include #include @@ -19,11 +20,12 @@ #include #define LCD_PORT "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00" // tis a symlink, can also be just /dev/ttyACM0 -#define LCD_INTERVAL_MS 1000 +#define LCD_INTERVAL_MS 500 #define LCD_CONTRAST 215 -std::chrono::milliseconds interval(LCD_INTERVAL_MS); -std::stop_source sigint; +/* these need to be global since we're talking to them from sighandler */ +std::binary_semaphore sDisp{0}; // halts display func until we have sensor data +std::binary_semaphore sMain{0}; // halts the main thread until SIGINT struct sensors_t { std::array td; @@ -32,97 +34,117 @@ struct sensors_t { mem_usage_t home; gpu_t gpu; cpu_t cpu; - float hass_state = 0; + float hass_state = 0.0f; + std::mutex mtx; // making sure the struct isnt accessed by multiple threads at once }; void sighandler(int s) { - std::println("[Signal] got SIGINT, exiting..."); - sigint.request_stop(); + std::println("[Signal] got SIGINT/SIGTERM, exiting..."); + sDisp.release(); + sMain.release(); } -void hass_thread(sensors_t *s, std::stop_token st) { +void hass_thread(std::stop_token st, std::shared_ptr s) { std::println("[Thread] Starting hass_thread, pid {}", gettid()); - hass_connect(); + HomeAssistant pc_power("home.drath.win", "sensor.gniazdko_komputer_moc"); + + pc_power.connect(); while (!st.stop_requested()) { - hass_poll(); - s->hass_state = hass_get(); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + pc_power.service(); + { + // locks mutex for the lifetime of the scope, unlocks when it goes out of scope + std::lock_guard lock(s->mtx); + s->hass_state = pc_power.state; + } + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - hass_disconnect(); } -void sensors_thread(sensors_t *s, std::stop_token st) { - std::println("[Thread] Starting sensors_thread, pid {}", gettid()); - /* find hwmon paths from pci addresses */ +void sensors_thread(std::stop_token st, std::shared_ptr s) { + std::println("[Thread] Starting sensors_thread, pid {}, poll interval {} ms", gettid(), LCD_INTERVAL_MS); cpu_hwmon_t cpu_hwmon = detectCpuHwmon("0000:00:18.3"); std::string gpu_hwmon = detectGpuHwmon("0000:08:00.0"); while (!st.stop_requested()) { auto start = std::chrono::steady_clock::now(); - s->td = getTimeDate(); - s->loadavg = getAvgs(); - s->ram = getRam(); - s->home = getDisk("/home/drath"); - s->cpu = getCpu(cpu_hwmon); - s->gpu = getGpu(gpu_hwmon); + { + std::lock_guard lock(s->mtx); // will unlock when it goes out of scope, this is why this whole thing is in braces + s->td = getTimeDate(); + s->loadavg = getAvgs(); + s->ram = getRam(); + s->home = getDisk("/home/drath"); + s->cpu = getCpu(cpu_hwmon); + s->gpu = getGpu(gpu_hwmon); + } - // std::print("[Sensors] took {} microseconds \r", std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count()); - // std::cout << std::flush; - std::this_thread::sleep_until(start + interval); + // std::println("[Sensors] took {} microseconds", std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count()); + sDisp.release(); // unlocks display loop + std::this_thread::sleep_until(start + std::chrono::milliseconds(LCD_INTERVAL_MS)); } } -void display_thread(sensors_t *s, std::stop_token st) { +void display_thread(std::stop_token st, std::shared_ptr s) { std::println("[Thread] Starting display_thread, pid {}", gettid()); LCDDisplay lcd(LCD_PORT); - lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius - std::println("[Chrono] Running in daemon mode, {} ms interval", LCD_INTERVAL_MS); lcd.setContrast(LCD_CONTRAST); lcd.setBacklight(true); - lcd.clear(); + lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius while (!st.stop_requested()) { - auto start = std::chrono::steady_clock::now(); - std::array lines; + sDisp.acquire(); // holds the loop until sensor data is ready + { + std::lock_guard lock(s->mtx); - auto gpu_temps = (s->gpu.hotspot_temp) ? "/" + std::to_string(s->gpu.hotspot_temp) : ""; - gpu_temps += (s->gpu.mem_temp) ? "/" + std::to_string(s->gpu.mem_temp) : ""; + auto gpu_temps = (s->gpu.hotspot_temp) ? "/" + std::to_string(s->gpu.hotspot_temp) : ""; + gpu_temps += (s->gpu.mem_temp) ? "/" + std::to_string(s->gpu.mem_temp) : ""; - lcd.writeBuf(0, 0, pad(s->td[1], 11, true) + " " + s->td[0] + lcd.bar(1, s->gpu.core_usage / 100.0) + pad(s->loadavg, 17)); + lcd.writeBuf(0, 0, pad(s->td[1], 11, true) + " " + s->td[0] + lcd.bar(1, s->gpu.core_usage / 100.0) + pad(s->loadavg, 17)); - lcd.writeBuf(1, 0, pad(std::to_string(s->cpu.tctl) + "/" + std::to_string(s->cpu.tccd1) + lcd.cc[0], 8, true)); - lcd.writeBuf(1, 8, pad(pBytes(s->ram.used, true) + "B", 7, true)); - lcd.writeBuf(1, 16, pad(pNum(s->hass_state) + "W", 4)); - lcd.writeBuf(1, 22, pad(pBytes(s->gpu.vram_used) + "B", 7)); - lcd.writeBuf(1, 29, pad(std::to_string(s->gpu.edge_temp) + gpu_temps + lcd.cc[0], 11)); + lcd.writeBuf(1, 0, pad(std::to_string(s->cpu.tctl) + "/" + std::to_string(s->cpu.tccd1) + lcd.cc[0], 8, true)); + lcd.writeBuf(1, 8, pad(pBytes(s->ram.used, true) + "B", 7, true)); + lcd.writeBuf(1, 16, pad(pNum(s->hass_state) + "W", 4)); + lcd.writeBuf(1, 22, pad(pBytes(s->gpu.vram_used) + "B", 7)); + lcd.writeBuf(1, 29, pad(std::to_string(s->gpu.edge_temp) + gpu_temps + lcd.cc[0], 11)); - lcd.writeBuf(2, 0, pad(pNum(s->cpu.ptotal, 1) + "W", 8, true)); - lcd.writeBuf(2, 14, "home:" + pad(pBytes(s->home.free), 5)); + lcd.writeBuf(2, 0, pad(pNum(s->cpu.ptotal, 1) + "W", 8, true)); + lcd.writeBuf(2, 8, "home:" + pad(pBytes(s->home.free), 5)); - lcd.writeBuf(2, 25, pad(std::to_string(s->gpu.fan_speed), 4) + "R"); - // std::println("{}", s->gpu.fan_speed); - lcd.writeBuf(2, 31, pad(std::to_string(s->gpu.power_avg) + "/" + std::to_string(s->gpu.power_cap) + "W", 9)); + lcd.writeBuf(2, 20, pad(std::to_string(s->gpu.fan_pwm) + "%", 4)); + lcd.writeBuf(2, 25, pad(std::to_string(s->gpu.fan_speed), 4) + "R"); + lcd.writeBuf(2, 31, pad(std::to_string(s->gpu.power_avg) + "/" + std::to_string(s->gpu.power_cap) + "W", 9)); - lcd.writeBuf(3, 0, pad(pNum(s->cpu.vcore, 3) + "V", 7, true)); - lcd.writeBuf(3, 7, std::to_string(s->cpu.avg_freq) + "MHz"); - lcd.writeBuf(3, 21, pad(std::to_string(s->gpu.core_clock) + "/" + std::to_string(s->gpu.mem_clock) + "MHz ", 13)); - lcd.writeBuf(3, 34, pad(pNum(s->gpu.vcore, 3) + "Vabscd", 5)); + lcd.writeBuf(3, 0, pad(pNum(s->cpu.vcore, 3) + "V", 7, true)); + lcd.writeBuf(3, 7, std::to_string(s->cpu.avg_freq) + "MHz"); + lcd.writeBuf(3, 21, pad(std::to_string(s->gpu.core_clock) + "/" + std::to_string(s->gpu.mem_clock) + "MHz ", 13)); + lcd.writeBuf(3, 34, pad(pNum(s->gpu.vcore, 3) + "V", 5)); + } - lcd.flushBuffer(); - - std::this_thread::sleep_until(start + interval); + lcd.flushBuf(); } + + lcd.clearBuf(); + lcd.writeBuf(1, 10, "linuxSmartie closed"); + // lcd.flushBuf(); } -int main(int argc, char *argv[]) { - signal(SIGINT, sighandler); +int main(int argc, char* argv[]) { + std::signal(SIGINT, sighandler); + std::signal(SIGTERM, sighandler); + std::println("[Thread] Main thread, pid {}", gettid()); - sensors_t sensors; + std::shared_ptr pSensors = std::make_shared(); - std::jthread producer(sensors_thread, &sensors, sigint.get_token()); - std::jthread hass(hass_thread, &sensors, sigint.get_token()); + std::jthread disp(display_thread, pSensors); + std::jthread hass(hass_thread, pSensors); + std::jthread sens(sensors_thread, pSensors); - display_thread(&sensors, sigint.get_token()); + // halt main thread until we trigger sighandler + sMain.acquire(); + + // main thread resumed, tell workers to stop + hass.request_stop(); + sens.request_stop(); + disp.request_stop(); return 0; }