move out everything out of main into a separate file
This commit is contained in:
183
main.cpp
183
main.cpp
@@ -1,186 +1,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <stop_token>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
// local includes
|
||||
#include <LCDDisplay.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <gpu.hpp>
|
||||
#include <hass.hpp>
|
||||
#include <log.hpp>
|
||||
#include <sys.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#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 500
|
||||
#define LCD_CONTRAST 215
|
||||
|
||||
/* these need to be global since we're talking to them from sighandler */
|
||||
|
||||
namespace sem {
|
||||
std::binary_semaphore display{0};
|
||||
std::binary_semaphore main{0};
|
||||
} // namespace sem
|
||||
|
||||
struct Sensors {
|
||||
sys::TimeDate td;
|
||||
double avg[3] = {0.0f};
|
||||
sys::Memory ram;
|
||||
sys::Disk home;
|
||||
sys::Network net;
|
||||
sys::sysSensors sys;
|
||||
cpu::cpuSensors cpu;
|
||||
gpu::gpuSensors gpu;
|
||||
float hass_state = 0.0f;
|
||||
std::mutex mtx; // making sure the struct isnt accessed by multiple threads at once
|
||||
};
|
||||
|
||||
void signalHandler(int) {
|
||||
applog(LOG::WRN, "got SIGINT/SIGTERM, exiting...");
|
||||
sem::main.release();
|
||||
sem::display.release();
|
||||
}
|
||||
|
||||
void hassThread(std::stop_token st, Sensors* s) {
|
||||
applog(LOG::START, "Thread started");
|
||||
HomeAssistant pc_power("home.drath.win", "sensor.gniazdko_komputer_moc");
|
||||
|
||||
pc_power.connect();
|
||||
while (!st.stop_requested()) {
|
||||
pc_power.service();
|
||||
{
|
||||
// locks mutex for the lifetime of the scope, unlocks when it goes out of scope
|
||||
// mutex can only be locked in one place, so when its locked here, other threads need to wait until its unlocked before they can lock it again
|
||||
std::lock_guard<std::mutex> lock(s->mtx);
|
||||
s->hass_state = pc_power.state;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
void sensorsThread(std::stop_token st, Sensors* s) {
|
||||
applog(LOG::START, "Thread started, poll interval {} ms", LCD_INTERVAL_MS);
|
||||
cpu::detectHwmon(&s->cpu, "0000:00:18.3");
|
||||
gpu::detectHwmon(&s->gpu, "0000:0b:00.0");
|
||||
sys::detectHwmon(&s->sys, "nct6775.656");
|
||||
s->home.mountpoint = "/home/drath";
|
||||
|
||||
while (!st.stop_requested()) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s->mtx);
|
||||
|
||||
sys::getTimeDate(&s->td);
|
||||
getloadavg(s->avg, 3);
|
||||
sys::getRam(&s->ram);
|
||||
sys::getDisk(&s->home);
|
||||
sys::getNetwork(&s->net, "enp4s0f0");
|
||||
sys::updateSensors(&s->sys);
|
||||
cpu::update(&s->cpu);
|
||||
gpu::update(&s->gpu);
|
||||
}
|
||||
|
||||
// log(LOG::DBG, "took {} microseconds", std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count());
|
||||
sem::display.release(); // unlocks display loop
|
||||
std::this_thread::sleep_until(start + std::chrono::milliseconds(LCD_INTERVAL_MS));
|
||||
}
|
||||
}
|
||||
|
||||
void displayThread(std::stop_token st, Sensors* s) {
|
||||
applog(LOG::START, "Thread started");
|
||||
// init internal variables of LCDDisplay class
|
||||
LCDDisplay lcd(LCD_PORT);
|
||||
|
||||
// basic lcd setup
|
||||
lcd.setContrast(LCD_CONTRAST);
|
||||
lcd.setBacklight(true);
|
||||
lcd.setCustomChar(0, {16, 6, 9, 8, 8, 9, 6, 0}); // celcius
|
||||
lcd.setCustomChar(1, {0, 0, 4, 10, 10, 17, 31, 0}); // delta
|
||||
lcd.setCustomChar(2, {0, 0, 8, 21, 21, 2, 0, 0}); // home (tilde)
|
||||
lcd.setCustomChar(3, {4, 14, 21, 4, 4, 4, 0}); // up arrow
|
||||
lcd.setCustomChar(4, {4, 4, 4, 21, 14, 4, 0}); // down arrow
|
||||
|
||||
// welcome msg
|
||||
lcd.writeBuf(2, 0, utils::center("Waiting for sensors...", 40));
|
||||
lcd.flushBuf();
|
||||
lcd.clearBuf();
|
||||
|
||||
// actual main display loop
|
||||
while (!st.stop_requested()) {
|
||||
sem::display.acquire(); // holds the loop until sensor data is ready
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s->mtx);
|
||||
|
||||
// prepare some tricky sensors
|
||||
std::string gpu_temps = std::to_string(s->gpu.temp_edge);
|
||||
if (s->gpu.temp_hotspot)
|
||||
gpu_temps = utils::pad(lcd.cc(1) + std::to_string(s->gpu.temp_hotspot - s->gpu.temp_edge) + lcd.cc(0), 4) + " " + utils::pad(gpu_temps + "/" + std::to_string(s->gpu.temp_hotspot), 5);
|
||||
|
||||
uint16_t cpu_fan = 0;
|
||||
for (auto& fan : s->sys.fan_speed)
|
||||
cpu_fan += fan;
|
||||
cpu_fan /= 2;
|
||||
|
||||
// write to display buffer
|
||||
lcd.writeBuf(0, 0, utils::pad(s->td.date, 11, utils::just::left) + " " + s->td.time + lcd.bar(7, s->gpu.usage_core / 100.0));
|
||||
lcd.writeBuf(0, 26, utils::pNum(s->avg[0], s->avg[0] > 10 ? 1 : 2));
|
||||
lcd.writeBuf(0, 31, utils::pNum(s->avg[1], s->avg[1] > 10 ? 1 : 2));
|
||||
lcd.writeBuf(0, 36, utils::pNum(s->avg[2], s->avg[2] > 10 ? 1 : 2));
|
||||
|
||||
lcd.writeBuf(1, 0, utils::pad(std::to_string(s->cpu.tctl) + "/" + std::to_string(s->cpu.tccd1) + lcd.cc(0), 8, utils::just::left));
|
||||
lcd.writeBuf(1, 7, utils::pad(utils::pBytes(s->ram.used, true), 6, utils::just::left));
|
||||
lcd.writeBuf(1, 13, utils::pad(utils::pNum(s->hass_state) + "W", 4));
|
||||
lcd.writeBuf(1, 19, std::to_string(s->sys.t_sensor) + lcd.cc(0)); // t_sensor temp
|
||||
lcd.writeBuf(1, 32 - gpu_temps.size(), utils::pad(utils::pBytes(s->gpu.vram_used), 6));
|
||||
lcd.writeBuf(1, 39 - gpu_temps.size(), gpu_temps + lcd.cc(0));
|
||||
|
||||
lcd.writeBuf(2, 0, utils::pad(std::to_string((int)s->cpu.ptotal) + "W", 8, utils::just::left));
|
||||
lcd.writeBuf(2, s->cpu.ptotal < 100 ? 4 : 5, std::to_string(cpu_fan) + "R"); // avg fan speed
|
||||
lcd.writeBuf(2, 12, lcd.cc(3) + utils::pBytes(s->net.upload));
|
||||
lcd.writeBuf(2, 19, lcd.cc(4) + utils::pBytes(s->net.download));
|
||||
lcd.writeBuf(2, 26, utils::pad(std::to_string(s->gpu.fan_speed) + "R", 5));
|
||||
lcd.writeBuf(2, 31, utils::pad(std::to_string(s->gpu.power_avg) + "/" + std::to_string(s->gpu.power_cap) + "W", 9));
|
||||
|
||||
lcd.writeBuf(3, 0, utils::pad(utils::pNum(s->cpu.vcore, 2) + "V", 7, utils::just::left));
|
||||
lcd.writeBuf(3, 6, std::to_string(s->cpu.avg_freq) + "MHz");
|
||||
lcd.writeBuf(3, 14, utils::pad(lcd.cc(2) + utils::pBytes(s->home.usage.free), 6));
|
||||
lcd.writeBuf(3, 21, utils::pad(std::to_string(s->gpu.clock_core) + "/" + std::to_string(s->gpu.clock_mem) + "MHz ", 13));
|
||||
lcd.writeBuf(3, 34, utils::pad(utils::pNum(s->gpu.vcore, 3) + "V", 5));
|
||||
}
|
||||
|
||||
lcd.flushBuf();
|
||||
lcd.clearBuf();
|
||||
}
|
||||
|
||||
// goodbye msg
|
||||
lcd.writeBuf(2, 0, utils::center("linuxSmartie closed", 40));
|
||||
lcd.flushBuf();
|
||||
}
|
||||
#include <app.hpp>
|
||||
|
||||
int main() {
|
||||
applog(LOG::START, "Application started", __FILE__); // to make logs clearer
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
|
||||
{
|
||||
std::unique_ptr<Sensors> pSensors = std::make_unique<Sensors>();
|
||||
std::vector<std::jthread> threads;
|
||||
std::function<void(std::stop_token st, Sensors * s)> funcs[] = {displayThread, sensorsThread, hassThread};
|
||||
|
||||
for (auto& f : funcs) {
|
||||
threads.emplace_back(f, pSensors.get()); // params: function, stop_token (implied), pointer to sensor struct
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // start threads with delay so displayThread can quit the app if theres no lcd
|
||||
}
|
||||
|
||||
sem::main.acquire();
|
||||
}
|
||||
|
||||
app::start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user