add some return values to some shit so it shuts down elegantly on crash

This commit is contained in:
2026-01-15 00:19:53 +01:00
parent 6297317f93
commit 7929a687e8
11 changed files with 105 additions and 64 deletions

View File

@@ -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() {

View File

@@ -16,12 +16,59 @@
#include <utils.hpp>
#include <vector>
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<std::jthread> threads;
std::function<void(std::stop_token)> 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<std::jthread> threads;
std::function<void(std::stop_token)> 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...");
}
}

View File

@@ -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<uint8_t>(target->module), target->hwmon);
return 0;
}
void update(cpuSensors* c) {

View File

@@ -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 */

View File

@@ -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) {