add some return values to some shit so it shuts down elegantly on crash
This commit is contained in:
@@ -11,11 +11,12 @@
|
||||
class LCDDisplay {
|
||||
private:
|
||||
int _lcd = -1;
|
||||
uint32_t _baud = 0;
|
||||
std::string _dev;
|
||||
std::array<char, LCD_LINES * LCD_COLS + 8> 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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
3
main.cpp
3
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();
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
105
src/app.cpp
105
src/app.cpp
@@ -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...");
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
10
src/gpu.cpp
10
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 */
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user