make it a class
This commit is contained in:
@@ -1,14 +1,36 @@
|
||||
#ifndef APP_HPP
|
||||
#define APP_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <cpu.hpp>
|
||||
#include <gpu.hpp>
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <stop_token>
|
||||
#include <sys.hpp>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
class Application {
|
||||
|
||||
public:
|
||||
struct Config {
|
||||
uint16_t lcd_interval_ms = 500;
|
||||
uint8_t lcd_contrast = 215;
|
||||
|
||||
std::string lcd_port;
|
||||
std::string cpu_pciaddr = "0000:00:18.3";
|
||||
std::string gpu_pciaddr = "0000:0b:00.0";
|
||||
std::string sys_sensor = "nct6775.656";
|
||||
std::string sys_ifname = "enp4s0f0";
|
||||
std::string home_dir = "/home/drath";
|
||||
};
|
||||
|
||||
explicit Application(const Config& config);
|
||||
~Application();
|
||||
void Run();
|
||||
|
||||
private:
|
||||
struct Sensors {
|
||||
sys::TimeDate td;
|
||||
double avg[3] = {0.0f};
|
||||
@@ -22,29 +44,21 @@ class Application {
|
||||
std::mutex mtx; // making sure the struct isnt accessed by multiple threads at once
|
||||
};
|
||||
|
||||
struct Semaphores {
|
||||
inline static std::binary_semaphore display{0};
|
||||
inline static std::binary_semaphore main{0};
|
||||
struct Control {
|
||||
std::binary_semaphore display{0};
|
||||
std::binary_semaphore main{0};
|
||||
std::atomic_bool quit{false};
|
||||
std::stop_source stop;
|
||||
};
|
||||
|
||||
std::string lcd_port;
|
||||
uint16_t lcd_interval_ms = 500;
|
||||
uint8_t lcd_contrast = 215;
|
||||
|
||||
std::string cpu_pciaddr = "0000:00:18.3";
|
||||
std::string gpu_pciaddr = "0000:0b:00.0";
|
||||
std::string sys_sensor = "nct6775.656";
|
||||
std::string sys_ifname = "enp4s0f0";
|
||||
std::string home_dir = "/home/drath";
|
||||
Config m_config; // m_ is member variable
|
||||
Control m_control;
|
||||
|
||||
static Application* s_instance;
|
||||
static void signalHandler(int);
|
||||
static void hassThread(const std::stop_token& st, Sensors& s);
|
||||
static void sensorsThread(const std::stop_token& st, Sensors& s);
|
||||
static void displayThread(const std::stop_token& st, Sensors& s);
|
||||
|
||||
public:
|
||||
explicit Application(const std::string& display_port);
|
||||
void Run();
|
||||
void sensorsThread(const std::stop_token& st, Sensors& s);
|
||||
void displayThread(const std::stop_token& st, Sensors& s);
|
||||
};
|
||||
|
||||
#endif
|
||||
15
main.cpp
15
main.cpp
@@ -1,7 +1,18 @@
|
||||
#include <app.hpp>
|
||||
// put app in a class w a constructor for all the basic params
|
||||
|
||||
int main() {
|
||||
Application app("/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00"); // tis a symlink, can also be just /dev/ttyACM0)
|
||||
Application::Config config;
|
||||
|
||||
config.lcd_port = "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00";
|
||||
config.lcd_interval_ms = 500;
|
||||
config.lcd_contrast = 215;
|
||||
config.cpu_pciaddr = "0000:00:18.3";
|
||||
config.gpu_pciaddr = "0000:0b:00.0";
|
||||
config.sys_sensor = "nct6775.656";
|
||||
config.sys_ifname = "enp4s0f0";
|
||||
config.home_dir = "/home/drath";
|
||||
|
||||
Application app(config); // tis a symlink, can also be just /dev/ttyACM0)
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
61
src/app.cpp
61
src/app.cpp
@@ -15,13 +15,12 @@
|
||||
#include <utils.hpp>
|
||||
#include <vector>
|
||||
|
||||
// std::binary_semaphore Application::Semaphores::main{0};
|
||||
// std::binary_semaphore Application::Semaphores::display{0};
|
||||
Application* Application::s_instance = nullptr;
|
||||
|
||||
void Application::signalHandler(int) {
|
||||
applog(LOG::WRN, "got SIGINT/SIGTERM, exiting...");
|
||||
this->Semaphores::main.release();
|
||||
this->Semaphores::display.release();
|
||||
if (s_instance)
|
||||
s_instance->m_control.quit.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Application::hassThread(const std::stop_token& st, Sensors& s) {
|
||||
@@ -40,11 +39,11 @@ void Application::hassThread(const std::stop_token& st, Sensors& s) {
|
||||
}
|
||||
|
||||
void Application::sensorsThread(const std::stop_token& st, Sensors& s) {
|
||||
applog(LOG::START, "Thread started, poll interval {} ms", lcd_interval_ms);
|
||||
cpu::detectHwmon(&s.cpu, cpu_pciaddr);
|
||||
gpu::detectHwmon(&s.gpu, gpu_pciaddr);
|
||||
sys::detectHwmon(&s.sys, sys_sensor);
|
||||
s.home.mountpoint = home_dir;
|
||||
applog(LOG::START, "Thread started, poll interval {} ms", m_config.lcd_interval_ms);
|
||||
cpu::detectHwmon(&s.cpu, m_config.cpu_pciaddr);
|
||||
gpu::detectHwmon(&s.gpu, m_config.gpu_pciaddr);
|
||||
sys::detectHwmon(&s.sys, m_config.sys_sensor);
|
||||
s.home.mountpoint = m_config.home_dir;
|
||||
|
||||
while (!st.stop_requested()) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
@@ -55,25 +54,27 @@ void Application::sensorsThread(const std::stop_token& st, Sensors& s) {
|
||||
getloadavg(s.avg, 3);
|
||||
sys::getRam(&s.ram);
|
||||
sys::getDisk(&s.home);
|
||||
sys::getNetwork(&s.net, sys_ifname);
|
||||
sys::getNetwork(&s.net, m_config.sys_ifname);
|
||||
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());
|
||||
this->Semaphores::display.release(); // unlocks display loop
|
||||
std::this_thread::sleep_until(start + std::chrono::milliseconds(lcd_interval_ms));
|
||||
m_control.display.release(); // unlocks display loop
|
||||
std::this_thread::sleep_until(start + std::chrono::milliseconds(m_config.lcd_interval_ms));
|
||||
}
|
||||
applog(LOG::INF, "Stopped thread");
|
||||
}
|
||||
|
||||
void Application::displayThread(const std::stop_token& st, Sensors& s) {
|
||||
std::stop_callback cb(st, [&] { m_control.display.release(); });
|
||||
applog(LOG::START, "Thread started");
|
||||
// init internal variables of LCDDisplay class
|
||||
LCDDisplay lcd(lcd_port);
|
||||
LCDDisplay lcd(m_config.lcd_port);
|
||||
|
||||
// basic lcd setup
|
||||
lcd.setContrast(lcd_contrast);
|
||||
lcd.setContrast(m_config.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
|
||||
@@ -88,7 +89,8 @@ void Application::displayThread(const std::stop_token& st, Sensors& s) {
|
||||
|
||||
// actual main display loop
|
||||
while (!st.stop_requested()) {
|
||||
this->Semaphores::display.acquire(); // holds the loop until sensor data is ready
|
||||
m_control.display.try_acquire_for(std::chrono::milliseconds(static_cast<int>(m_config.lcd_interval_ms * 1.25))); // holds the loop until sensor data is ready, max 1.25x of the loop time
|
||||
if (st.stop_requested()) break; // needed, otherwise it wont quit correctly
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s.mtx);
|
||||
|
||||
@@ -137,26 +139,37 @@ void Application::displayThread(const std::stop_token& st, Sensors& s) {
|
||||
lcd.flushBuf();
|
||||
}
|
||||
|
||||
Application::Application(const std::string& display_port) {
|
||||
this->lcd_port = display_port;
|
||||
Application::Application(const Config& config) : m_config(config) {
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
applog(LOG::START, "Application stopped");
|
||||
}
|
||||
|
||||
void Application::Run() {
|
||||
applog(LOG::START, "Application started");
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
s_instance = this;
|
||||
std::signal(SIGINT, &Application::signalHandler);
|
||||
std::signal(SIGTERM, &Application::signalHandler);
|
||||
|
||||
{
|
||||
Sensors sensors;
|
||||
std::vector<std::jthread> threads;
|
||||
|
||||
for (std::function<void(std::stop_token st, Sensors & s)> funcs[] = {displayThread, sensorsThread, hassThread};
|
||||
auto& f : funcs)
|
||||
{
|
||||
std::function<void(std::stop_token, Sensors&)> funcs[] = {
|
||||
[this](const std::stop_token& st, Sensors& s) { displayThread(st, s); },
|
||||
[this](const std::stop_token& st, Sensors& s) { sensorsThread(st, s); },
|
||||
[this](const std::stop_token& st, Sensors& s) { hassThread(st, s); },
|
||||
};
|
||||
|
||||
// start threads in order
|
||||
for (auto& f : funcs) {
|
||||
threads.emplace_back(f, std::ref(sensors)); // 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
|
||||
}
|
||||
|
||||
this->Semaphores::main.acquire();
|
||||
// hold until signal recieved
|
||||
while (!m_control.quit.load(std::memory_order_relaxed))
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // ugly
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user