From 7929a687e83a9419fe6b5e0ed3b9544941fb689b Mon Sep 17 00:00:00 2001 From: Drath Date: Thu, 15 Jan 2026 00:19:53 +0100 Subject: [PATCH] add some return values to some shit so it shuts down elegantly on crash --- include/LCDDisplay.hpp | 4 +- include/app.hpp | 6 ++- include/cpu.hpp | 2 +- include/gpu.hpp | 2 +- include/sys.hpp | 2 +- main.cpp | 3 +- src/LCDDisplay.cpp | 25 ++++++---- src/app.cpp | 105 ++++++++++++++++++++++++----------------- src/cpu.cpp | 5 +- src/gpu.cpp | 10 +++- src/sys.cpp | 5 +- 11 files changed, 105 insertions(+), 64 deletions(-) diff --git a/include/LCDDisplay.hpp b/include/LCDDisplay.hpp index 558334c..f478f50 100644 --- a/include/LCDDisplay.hpp +++ b/include/LCDDisplay.hpp @@ -11,11 +11,12 @@ class LCDDisplay { private: int _lcd = -1; + uint32_t _baud = 0; std::string _dev; std::array writebuf{}; // 4x40 chars + 2x4 setcursor commands static constexpr bool dualDisp = (LCD_LINES * LCD_COLS > 80); // is it dual display device or not, evauluated from the size at compile time - void open(bool reopen = false); + int open(bool reopen = false); void write(const uint8_t* cmdbuf, uint8_t len); void close(); @@ -27,6 +28,7 @@ class LCDDisplay { explicit LCDDisplay(const std::string& dev, uint32_t baud = 0010002); // from termios-baud.h, B115200 ~LCDDisplay(); + int Init(); void clear(); void setContrast(uint8_t contrast); void setBacklight(bool enabled); diff --git a/include/app.hpp b/include/app.hpp index 0912c3c..31da5a0 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -34,7 +34,7 @@ class Application { explicit Application(Config config); ~Application(); - void Run(); + int Run(); private: struct Sensors { @@ -55,6 +55,8 @@ class Application { sigset_t sigset; }; + pid_t m_mainPid{}; + int m_ret = 0; Config m_config{}; // m_ is prefix for member variable Control m_control{}; Sensors m_sensors{}; @@ -62,6 +64,8 @@ class Application { void hassThread(const std::stop_token& st); void sensorsThread(const std::stop_token& st); void displayThread(const std::stop_token& st); + + void Crash(int ret); }; #endif \ No newline at end of file diff --git a/include/cpu.hpp b/include/cpu.hpp index 1e7fd32..f834d72 100644 --- a/include/cpu.hpp +++ b/include/cpu.hpp @@ -25,7 +25,7 @@ struct cpuSensors { std::string hwmon; }; -void detectHwmon(cpuSensors* target, const std::string& pci); +int detect(cpuSensors* target, const std::string& pci); void update(cpuSensors* c); } // namespace cpu diff --git a/include/gpu.hpp b/include/gpu.hpp index a5a3543..98300ea 100644 --- a/include/gpu.hpp +++ b/include/gpu.hpp @@ -40,7 +40,7 @@ struct gpuSensors { std::string hwmon; }; -void detectHwmon(gpuSensors* target, const std::string& pci); +int detect(gpuSensors* target, const std::string& pci); void update(gpuSensors* g); } // namespace gpu diff --git a/include/sys.hpp b/include/sys.hpp index 525d712..d0d2e63 100644 --- a/include/sys.hpp +++ b/include/sys.hpp @@ -41,7 +41,7 @@ void getTimeDate(TimeDate* td); void getDisk(Disk* disk); void getRam(Memory* mem); void getNetwork(Network* net, const std::string& device); -void detectHwmon(sysSensors* s, const std::string& platform); +int detect(sysSensors* s, const std::string& platform); void updateSensors(sysSensors* s); } // namespace sys diff --git a/main.cpp b/main.cpp index 87f4564..3b06a8d 100644 --- a/main.cpp +++ b/main.cpp @@ -16,6 +16,5 @@ int main() { config.hass.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI0MzUxMTZiY2VjNTg0MTI3OGI4YmU0NTY4ZGQ5MzIyYiIsImlhdCI6MTc1NzQzMDI0MCwiZXhwIjoyMDcyNzkwMjQwfQ.6wKTlxEA0FLWfv-qW35vewUSvTxdVrZWqFwHT5Khu6E"; Application App(config); - App.Run(); - return 0; + return App.Run(); } diff --git a/src/LCDDisplay.cpp b/src/LCDDisplay.cpp index e4b0a8a..da48c7d 100644 --- a/src/LCDDisplay.cpp +++ b/src/LCDDisplay.cpp @@ -13,11 +13,22 @@ /* lcd size hardcoded to 4x40 idgaf */ LCDDisplay::LCDDisplay(const std::string& dev, const uint32_t baud) { _dev = dev; - this->open(); // calls this (LCDDisplay) open() function, LCDDisplay::open() + _baud = baud; +} + +LCDDisplay::~LCDDisplay() { + this->close(); +} + +int LCDDisplay::Init() { + if (const int ret = this->open(); ret < 0) { + this->close(); + return -1; + } struct termios term{}; // Setup the serial port 8 data bits, no parity, 1 stopbit, no flow control - term.c_cflag = baud | CS8 | CSTOPB | CLOCAL | CREAD; + term.c_cflag = _baud | CS8 | CSTOPB | CLOCAL | CREAD; term.c_iflag = 0; term.c_oflag = 0; term.c_lflag = 0; @@ -33,20 +44,18 @@ LCDDisplay::LCDDisplay(const std::string& dev, const uint32_t baud) { // clear display and set cursor home this->clear(); + return 0; } -LCDDisplay::~LCDDisplay() { - this->close(); -} - -void LCDDisplay::open(const bool reopen) { +int LCDDisplay::open(const bool reopen) { applog(LOG::INF, "Opening serial port at \"{}\"", _dev); if (_lcd < 0 || reopen) _lcd = ::open(_dev.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); // ::open calls the global open() instead of LCDDisplay::open() if (_lcd < 0) { applog(LOG::ERR, "Error opening serial port \"{}\"", _dev); // err - exit(_lcd); + return -1; } + return 0; } void LCDDisplay::close() { diff --git a/src/app.cpp b/src/app.cpp index a51f561..fb18002 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -16,12 +16,59 @@ #include #include +Application::Application(Config config) { + m_config = std::move(config); + // set up signals + sigemptyset(&m_control.sigset); + sigaddset(&m_control.sigset, SIGINT); + sigaddset(&m_control.sigset, SIGTERM); + applog(LOG::START, "Application initialized"); +} + +Application::~Application() { + auto level = LOG::START; + if (m_ret < 0) level = LOG::WRN; + applog(level, "Application destroyed"); +} + +int Application::Run() { + int sig; + m_mainPid = getpid(); + pthread_sigmask(SIG_BLOCK, &m_control.sigset, nullptr); + + { + std::vector threads; + + std::function funcs[] = { + [this](const std::stop_token& st) { displayThread(st); }, + [this](const std::stop_token& st) { sensorsThread(st); }, + [this](const std::stop_token& st) { hassThread(st); }, + }; + + // start threads in order + for (auto& f : funcs) { + threads.emplace_back(f); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); // start threads with delay so displayThread can quit the app if theres no lcd + } + + // waits for signal, the threads are stopped when we go out of scope + sigwait(&m_control.sigset, &sig); + applog(LOG::WRN, "got stop signal, shutting down..."); + } + return m_ret; +} + +void Application::Crash(const int ret) { + m_ret = ret; + kill(m_mainPid, SIGINT); +} + void Application::hassThread(const std::stop_token& st) { applog(LOG::START, "Thread started"); HomeAssistant::Config config; config.address = m_config.hass.url; - config.entity = m_config.hass.entity; - config.token = m_config.hass.token; + config.entity = m_config.hass.entity; + config.token = m_config.hass.token; HomeAssistant pc_power(config); pc_power.connect(); @@ -37,10 +84,15 @@ void Application::hassThread(const std::stop_token& st) { void Application::sensorsThread(const std::stop_token& st) { applog(LOG::START, "Thread started, poll interval {} ms", m_config.lcd.refresh_interval_ms); - cpu::detectHwmon(&m_sensors.cpu, m_config.cpu_pciaddr); - gpu::detectHwmon(&m_sensors.gpu, m_config.gpu_pciaddr); - sys::detectHwmon(&m_sensors.sys, m_config.sys_sensor); + int ret = cpu::detect(&m_sensors.cpu, m_config.cpu_pciaddr); + ret += gpu::detect(&m_sensors.gpu, m_config.gpu_pciaddr); + ret += sys::detect(&m_sensors.sys, m_config.sys_sensor); m_sensors.home.mountpoint = m_config.home_dir; + if (ret < 0) { + applog(LOG::ERR, "Failed to detect some sensors"); + this->Crash(ret); + return; + } while (!st.stop_requested()) { auto start = std::chrono::steady_clock::now(); @@ -69,6 +121,11 @@ void Application::displayThread(const std::stop_token& st) { applog(LOG::START, "Thread started"); // init internal variables of LCDDisplay class LCDDisplay lcd(m_config.lcd.port); + if (const int ret = lcd.Init(); ret < 0) { + applog(LOG::ERR, "Failed to initialize LCDDisplay"); + this->Crash(ret); + return; + } // basic lcd setup lcd.setContrast(m_config.lcd.contrast); @@ -137,42 +194,4 @@ void Application::displayThread(const std::stop_token& st) { // goodbye msg lcd.writeBuf(2, 0, utils::center("Goodbye", 40)); lcd.flushBuf(); -} - -Application::Application(Config config) { - m_config = std::move(config); - // set up signals - sigemptyset(&m_control.sigset); - sigaddset(&m_control.sigset, SIGINT); - sigaddset(&m_control.sigset, SIGTERM); -} - -Application::~Application() { - applog(LOG::START, "Application quit"); -} - -void Application::Run() { - applog(LOG::START, "starting"); - int sig; - pthread_sigmask(SIG_BLOCK, &m_control.sigset, nullptr); - - { - std::vector threads; - - std::function funcs[] = { - [this](const std::stop_token& st) { displayThread(st); }, - [this](const std::stop_token& st) { sensorsThread(st); }, - [this](const std::stop_token& st) { hassThread(st); }, - }; - - // start threads in order - for (auto& f : funcs) { - threads.emplace_back(f); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); // start threads with delay so displayThread can quit the app if theres no lcd - } - - // waits for signal, the threads are stopped when we go out of scope - sigwait(&m_control.sigset, &sig); - applog(LOG::WRN, "got stop signal, shutting down..."); - } } \ No newline at end of file diff --git a/src/cpu.cpp b/src/cpu.cpp index a466127..606f758 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -9,19 +9,20 @@ namespace cpu { -void detectHwmon(cpuSensors* target, const std::string& pci) { +int detect(cpuSensors* target, const std::string& pci) { const std::string path = "/sys/bus/pci/devices/" + pci + "/hwmon"; try { target->hwmon = utils::getFirstDir(path); } catch (...) { applog(LOG::ERR, "NO CPU HWMON KERNEL MODULE DETECTED"); - return; + return -1; } target->module = utils::fileExists(target->hwmon + "/in1_input") ? zenpower : k10temp; // idk if this is reliable, we're trying to avoid just reading the name target->num_cores = std::thread::hardware_concurrency(); applog(LOG::INF, "Detected {} cores, module enum #{} in path \"{}\"", target->num_cores, static_cast(target->module), target->hwmon); + return 0; } void update(cpuSensors* c) { diff --git a/src/gpu.cpp b/src/gpu.cpp index 700e82d..d04e4db 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -14,14 +14,20 @@ const std::string rel_metrics_path = "/../../gpu_metrics"; // gpu_metrics path constexpr uint16_t max_metrics_length = 512; // length of the metrics buffer /* takes pointer to a target gpu::sensors struct and updates its hwmon path and detects gpu_metrics */ -void detectHwmon(gpuSensors* target, const std::string& pci) { - target->hwmon = utils::getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon"); +int detect(gpuSensors* target, const std::string& pci) { + try { + target->hwmon = utils::getFirstDir("/sys/bus/pci/devices/" + pci + "/hwmon"); + } catch (...) { + applog(LOG::ERR, "Couldn't find GPU hwmon"); + return -1; + } applog(LOG::INF, "Detected path \"{}\"", target->hwmon); if (utils::fileExists(target->hwmon + rel_metrics_path)) { applog(LOG::INF, "found gpu_metrics"); target->hasGpuMetrics = true; } + return 0; } /* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */ diff --git a/src/sys.cpp b/src/sys.cpp index ba4ae54..8fe883d 100644 --- a/src/sys.cpp +++ b/src/sys.cpp @@ -65,14 +65,15 @@ void sys::getNetwork(Network* net, const std::string& device) { prev = current; } -void sys::detectHwmon(sysSensors* s, const std::string& platform) { +int sys::detect(sysSensors* s, const std::string& platform) { // we dont really need getFirstDir since its a static folder, but its useful for try/catch try { s->hwmon = utils::getFirstDir("/sys/devices/platform/" + platform + "/hwmon"); } catch (...) { applog(LOG::ERR, "Can't open sys hwmon. Module loaded? Kernel params added?"); - return; + return -1; } + return 0; } void sys::updateSensors(sysSensors* s) {