diff --git a/.clang-format b/.clang-format
index 222df9c..5ae9bee 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,4 +1,56 @@
----
-BasedOnStyle: Google
-IndentWidth: 4
-ColumnLimit: 0
\ No newline at end of file
+BasedOnStyle: LLVM
+
+# Indentation (Linux kernel style)
+UseTab: Always
+IndentWidth: 8
+TabWidth: 8
+
+# Keep parameters on one line as much as possible
+BinPackParameters: true
+BinPackArguments: true
+
+# Allow long lines (important!)
+ColumnLimit: 0 # or set to something large like 120
+
+# Prevent breaking after return type / before function name
+AlwaysBreakAfterReturnType: None
+AlwaysBreakAfterDefinitionReturnType: None
+
+# Keep function declarations/definitions on one line if possible
+PenaltyBreakBeforeFirstCallParameter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 1000000
+
+# Braces: K&R style everywhere, INCLUDING functions (your modification)
+BreakBeforeBraces: Attach
+
+# Control specific brace wrapping behavior
+BraceWrapping:
+ AfterFunction: false # <-- key change (same line for functions)
+ AfterControlStatement: false
+ AfterStruct: false
+ AfterEnum: false
+ AfterUnion: false
+ AfterClass: false
+ BeforeElse: false
+
+# Spaces
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+
+# Pointer alignment (kernel prefers this style)
+PointerAlignment: Right
+
+# Keep simple statements compact
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+
+# For-loop style similar to kernel
+AllowShortBlocksOnASingleLine: Never
+
+# Don't align weirdly
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+
+# Include handling (kernel is manual about includes)
+SortIncludes: false
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 81469bd..c93a9d9 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,8 +1,7 @@
-
-
+
@@ -98,8 +97,5 @@
-
-
-
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
index e7b96ca..6438eb1 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -245,7 +245,6 @@
-
@@ -340,6 +339,6 @@
-
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c8791c9..0ca46eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,18 +2,17 @@ cmake_minimum_required(VERSION 3.20)
project(linuxSmartie
VERSION 1.0
- LANGUAGES CXX
+ LANGUAGES C
)
-# Use C++20
-set(CMAKE_CXX_STANDARD 20)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
+# Use C23
+set(CMAKE_C_STANDARD 23)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS ON)
# Collect sources
file(GLOB SOURCES
- src/*.cpp
- main.cpp
+ src/*.c
)
# Define executable
@@ -27,12 +26,14 @@ target_include_directories(linuxSmartie
# Compiler warnings
target_compile_options(linuxSmartie
- PRIVATE
+ PRIVATE
-O2
-Wall
-Wextra
- -Wpedantic
-Werror
+ -Wshadow
+ -Wformat=2 # replaces what -Wpedantic caught for printf
+ -Wformat-security
-fdiagnostics-color=always
)
@@ -47,7 +48,7 @@ else()
endif()
if(ZLIB_FOUND)
- target_link_libraries(linuxSmartie PRIVATE z)
+ target_link_libraries(linuxSmartie PRIVATE ZLIB::ZLIB)
target_compile_definitions(linuxSmartie PRIVATE ENABLE_ZLIB)
else()
message(STATUS "no zlib found, disabling saving logs to gz")
diff --git a/README.md b/README.md
index 43f2c4f..b8e36e1 100644
--- a/README.md
+++ b/README.md
@@ -1,27 +1,22 @@
# linuxSmartie
Alphanumeric LCD controller software for Linux (kind of LCDSmartie for Windows but no GUI, no config file, no plugins, no Windows).
-~~Written with C++26 (`-std=c++2c`), will need at least gcc 14 to compile.~~ Uhm actually written with C++20 now, I was only really using `std::print` from 26. Let us not fall for memes. Will need gcc 10 to compile. GCC actually made C++20 the default since v16.
-
-We can't go lower than C++20, we use too much shit introduced by it (std::format, std::chrono stuff mostly).
+Big ol rewrite in C, like God intended because GOOD LORD C++ IS A MESS.
Hardcoded to work with 4x40 character display because that's what I have and I don't plan on using anything else. Uses Matrix Orbital protocol over serial. Should work with most other display sizes by modifying `src/LCDDisplay.cpp`. Best of luck if you try to make it work with anything else.
Vaguely inspired by suckless software philosophy, as in:
## The config is the source code
-Same as plugins. Just write in more features scrub, learn some C++, damn
+Same as plugins. Just write in more features scrub, learn some C, damn
## TODOs
-- Use `std::string_view` or `const std::string &` when possible, its faster, no copy
- Extra screens support perhaps? just halt sensors monitoring thread and print another struct on display if needed, have a semaphore or sth
- Maybe not even screens, keep the 1st line and change lines 2-4
- Media playback screen (use mpris, get playback info with mpris)
- In the LCDDisplay lib, reimplement all the features I have in picoSmartie + maybe finally add keypad support for both so I can toggle backlight (?) or change screens if I want any
- Screens could be automatic tbh, like if it detects media playing it switches to media screen, if in media screen and GPU power > 80W it switches to main (hwmon) screen
-- Try to be C++, avoid globals, wrap in namespaces, use naming conventions, use classes, avoid pure C way of doing things unless it makes more sense (which it often does tbh, better for reading small files)
- **FUCK C++, HUGE REWRITE FROM SCRATCH IN C LIKE GOD ALWAYS INTENDED** but fuuuuck display thread would be so painful without std::string. And I really would need to start a whole ass project from a clean slate since I made it a point to use a lot of C++ features which now bite me in the ass.
-- Fuck it man, nvm let's leave it. Make it C++17 or 20 or sth so it compiles on yo mama or sth.
## LCD layout
It looks something like this
diff --git a/include/LCDDisplay.hpp b/include/LCDDisplay.hpp
deleted file mode 100644
index 641dc1d..0000000
--- a/include/LCDDisplay.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef LCDDISPLAY_HPP
-#define LCDDISPLAY_HPP
-
-#define LCD_LINES 4
-#define LCD_COLS 40
-
-#include
-#include
-#include
-
-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
-
- int open(bool reopen = false);
- void write(const uint8_t* cmdbuf, uint8_t len);
- void close();
-
- // we avoid using these, use buffer (even if these are faster for small writes, perhaps a rewrite is in order)
- void writeStr(const std::string& str);
- void writeStr(uint8_t row, uint8_t col, const std::string& str);
-
- public:
- 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);
- void setBacklight(uint8_t brightness);
- void setCursor(uint8_t row, uint8_t col);
- void setCustomChar(uint8_t index, std::array cchar);
-
- void writeBuf(uint8_t row, uint8_t col, const std::string& str);
- void clearBuf();
- void flushBuf();
- char bar(uint8_t char_id, double value);
-
- // returns custom char no. c, small enough to define in header
- static constexpr char cc(const uint8_t c) { return static_cast(c % 8); }
-};
-
-#endif
diff --git a/include/app.hpp b/include/app.hpp
deleted file mode 100644
index 31da5a0..0000000
--- a/include/app.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef APP_HPP
-#define APP_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-class Application {
- public:
- struct Config {
- struct Lcd {
- uint16_t refresh_interval_ms;
- uint8_t contrast;
- std::string port;
- };
- struct HomeAssistant {
- std::string url;
- std::string entity;
- std::string token;
- };
- Lcd lcd;
- HomeAssistant hass;
- std::string cpu_pciaddr;
- std::string gpu_pciaddr;
- std::string sys_sensor;
- std::string sys_ifname;
- std::string home_dir;
- };
-
- explicit Application(Config config);
- ~Application();
- int Run();
-
- private:
- struct Sensors {
- sys::TimeDate td;
- double loadavg[3] = {0.0f};
- sys::Memory ram;
- sys::Disk home;
- sys::Network net;
- sys::sysSensors sys;
- cpu::cpuSensors cpu;
- gpu::gpuSensors gpu;
- double hass_state = 0.0f;
- };
-
- struct Control {
- std::binary_semaphore display{0};
- std::mutex sensors; // making sure the sensors struct isnt accessed by multiple threads at once
- 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{};
-
- 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
deleted file mode 100644
index f834d72..0000000
--- a/include/cpu.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef CPU_HPP
-#define CPU_HPP
-
-#include
-#include
-
-namespace cpu {
-
-enum Module : uint8_t { unknown,
- k10temp,
- zenpower };
-
-struct cpuSensors {
- Module module = unknown;
- uint8_t num_cores = 0;
- int16_t tdie = 0;
- int16_t tctl = 0;
- int16_t tccd1 = 0;
- // double pcore = 0.0;
- // double psoc = 0.0;
- float ptotal = 0.0;
- // double vcore = 0.0;
- // double vsoc = 0.0;
- uint32_t avg_freq = 0;
- std::string hwmon;
-};
-
-int detect(cpuSensors* target, const std::string& pci);
-void update(cpuSensors* c);
-
-} // namespace cpu
-
-#endif
diff --git a/include/gpu.hpp b/include/gpu.hpp
deleted file mode 100644
index 98300ea..0000000
--- a/include/gpu.hpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef GPU_HPP
-#define GPU_HPP
-
-#include
-#include
-
-/* clean abstraction for gpu_metrics or metrics in filesystem in sane units */
-
-namespace gpu {
-
-struct gpuSensors {
- uint64_t vram_used = 0;
- // uint64_t vram_total = 0;
-
- float vcore = 0.0f;
-
- uint16_t clock_core = 0;
- uint16_t clock_mem = 0;
-
- // uint8_t fan_pwm = 0;
- uint16_t fan_speed = 0;
-
- uint16_t power_avg = 0;
- uint16_t power_cap = 0;
- // uint16_t power_cap_max = 0;
-
- uint8_t temp_edge = 0;
- uint8_t temp_hotspot = 0;
- uint8_t temp_mem = 0;
- uint8_t temp_vrm_gfx = 0;
- uint8_t temp_vrm_soc = 0;
- uint8_t temp_vrm_mem = 0;
-
- bool hasGpuMetrics = false;
-
- uint8_t usage_core = 0;
- uint8_t usage_media = 0;
- uint8_t usage_umc = 0;
-
- std::string hwmon;
-};
-
-int detect(gpuSensors* target, const std::string& pci);
-void update(gpuSensors* g);
-
-} // namespace gpu
-
-// class ThrottleStatus(IntFlag):
-// # linux/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
-// PPT0 = 1 << 0
-// PPT1 = 1 << 1
-// PPT2 = 1 << 2
-// PPT3 = 1 << 3
-// SPL = 1 << 4
-// FPPT = 1 << 5
-// SPPT = 1 << 6
-// SPPT_APU = 1 << 7
-// TDC_GFX = 1 << 16
-// TDC_SOC = 1 << 17
-// TDC_MEM = 1 << 18
-// TDC_VDD = 1 << 19
-// TDC_CVIP = 1 << 20
-// EDC_CPU = 1 << 21
-// EDC_GFX = 1 << 22
-// APCC = 1 << 23
-// TEMP_GPU = 1 << 32
-// TEMP_CORE = 1 << 33
-// TEMP_MEM = 1 << 34
-// TEMP_EDGE = 1 << 35
-// TEMP_HOTSPOT = 1 << 36
-// TEMP_SOC = 1 << 37
-// TEMP_VR_GFX = 1 << 38
-// TEMP_VR_SOC = 1 << 39
-// TEMP_VR_MEM0 = 1 << 40
-// TEMP_VR_MEM1 = 1 << 41
-// TEMP_LIQUID0 = 1 << 42
-// TEMP_LIQUID1 = 1 << 43
-// VRHOT0 = 1 << 44
-// VRHOT1 = 1 << 45
-// PROCHOT_CPU = 1 << 46
-// PROCHOT_GFX = 1 << 47
-// PPM = 1 << 56
-// FIT = 1 << 57
-
-#endif
\ No newline at end of file
diff --git a/include/gpu_metrics.hpp b/include/gpu_metrics.h
similarity index 96%
rename from include/gpu_metrics.hpp
rename to include/gpu_metrics.h
index 11cd56a..ec6fe20 100644
--- a/include/gpu_metrics.hpp
+++ b/include/gpu_metrics.h
@@ -1,800 +1,797 @@
-#ifndef GPU_METRICS_HPP
-#define GPU_METRICS_HPP
-
-#include
-
-/* STRUCTS COPIED WHOLESALE FROM LINUX SOURCE CODE, formatted and wrapped around a namespace
-https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/kgd_pp_interface.h */
-
-#define NUM_HBM_INSTANCES 4
-#define NUM_XGMI_LINKS 8
-#define MAX_GFX_CLKS 8
-#define MAX_CLKS 4
-#define NUM_VCN 4
-#define NUM_JPEG_ENG 32
-#define NUM_JPEG_ENG_V1 40
-#define MAX_XCC 8
-#define NUM_XCP 8
-
-namespace metrics {
-
-struct metrics_table_header {
- uint16_t structure_size;
- uint8_t format_revision;
- uint8_t content_revision;
-};
-
-/*
- * gpu_metrics_v1_0 is not recommended as it's not naturally aligned.
- * Use gpu_metrics_v1_1 or later instead.
- */
-struct gpu_metrics_v1_0 {
- struct metrics_table_header common_header;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Temperature */
- uint16_t temperature_edge;
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrgfx;
- uint16_t temperature_vrsoc;
- uint16_t temperature_vrmem;
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Power/Energy */
- uint16_t average_socket_power;
- uint32_t energy_accumulator;
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_vclk0_frequency;
- uint16_t average_dclk0_frequency;
- uint16_t average_vclk1_frequency;
- uint16_t average_dclk1_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_vclk0;
- uint16_t current_dclk0;
- uint16_t current_vclk1;
- uint16_t current_dclk1;
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t current_fan_speed;
-
- /* Link width/speed */
- uint8_t pcie_link_width;
- uint8_t pcie_link_speed; // in 0.1 GT/s
-};
-
-struct gpu_metrics_v1_1 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_edge;
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrgfx;
- uint16_t temperature_vrsoc;
- uint16_t temperature_vrmem;
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Power/Energy */
- uint16_t average_socket_power;
- uint64_t energy_accumulator;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_vclk0_frequency;
- uint16_t average_dclk0_frequency;
- uint16_t average_vclk1_frequency;
- uint16_t average_dclk1_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_vclk0;
- uint16_t current_dclk0;
- uint16_t current_vclk1;
- uint16_t current_dclk1;
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t current_fan_speed;
-
- /* Link width/speed */
- uint16_t pcie_link_width;
- uint16_t pcie_link_speed; // in 0.1 GT/s
-
- uint16_t padding;
-
- uint32_t gfx_activity_acc;
- uint32_t mem_activity_acc;
-
- uint16_t temperature_hbm[NUM_HBM_INSTANCES];
-};
-
-struct gpu_metrics_v1_2 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_edge;
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrgfx;
- uint16_t temperature_vrsoc;
- uint16_t temperature_vrmem;
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Power/Energy */
- uint16_t average_socket_power;
- uint64_t energy_accumulator;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_vclk0_frequency;
- uint16_t average_dclk0_frequency;
- uint16_t average_vclk1_frequency;
- uint16_t average_dclk1_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_vclk0;
- uint16_t current_dclk0;
- uint16_t current_vclk1;
- uint16_t current_dclk1;
-
- /* Throttle status (ASIC dependent) */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t current_fan_speed;
-
- /* Link width/speed */
- uint16_t pcie_link_width;
- uint16_t pcie_link_speed; // in 0.1 GT/s
-
- uint16_t padding;
-
- uint32_t gfx_activity_acc;
- uint32_t mem_activity_acc;
-
- uint16_t temperature_hbm[NUM_HBM_INSTANCES];
-
- /* PMFW attached timestamp (10ns resolution) */
- uint64_t firmware_timestamp;
-};
-
-struct gpu_metrics_v1_3 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_edge;
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrgfx;
- uint16_t temperature_vrsoc;
- uint16_t temperature_vrmem;
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Power/Energy */
- uint16_t average_socket_power;
- uint64_t energy_accumulator;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_vclk0_frequency;
- uint16_t average_dclk0_frequency;
- uint16_t average_vclk1_frequency;
- uint16_t average_dclk1_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_vclk0;
- uint16_t current_dclk0;
- uint16_t current_vclk1;
- uint16_t current_dclk1;
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t current_fan_speed;
-
- /* Link width/speed */
- uint16_t pcie_link_width;
- uint16_t pcie_link_speed; // in 0.1 GT/s
-
- uint16_t padding;
-
- uint32_t gfx_activity_acc;
- uint32_t mem_activity_acc;
-
- uint16_t temperature_hbm[NUM_HBM_INSTANCES];
-
- /* PMFW attached timestamp (10ns resolution) */
- uint64_t firmware_timestamp;
-
- /* Voltage (mV) */
- uint16_t voltage_soc;
- uint16_t voltage_gfx;
- uint16_t voltage_mem;
-
- uint16_t padding1;
-
- /* Throttle status (ASIC independent) */
- uint64_t indep_throttle_status;
-};
-
-struct gpu_metrics_v1_4 {
- struct metrics_table_header common_header;
-
- /* Temperature (Celsius) */
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrsoc;
-
- /* Power (Watts) */
- uint16_t curr_socket_power;
-
- /* Utilization (%) */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t vcn_activity[NUM_VCN];
-
- /* Energy (15.259uJ (2^-16) units) */
- uint64_t energy_accumulator;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Clock Lock Status. Each bit corresponds to clock instance */
- uint32_t gfxclk_lock_status;
-
- /* Link width (number of lanes) and speed (in 0.1 GT/s) */
- uint16_t pcie_link_width;
- uint16_t pcie_link_speed;
-
- /* XGMI bus width and bitrate (in Gbps) */
- uint16_t xgmi_link_width;
- uint16_t xgmi_link_speed;
-
- /* Utilization Accumulated (%) */
- uint32_t gfx_activity_acc;
- uint32_t mem_activity_acc;
-
- /*PCIE accumulated bandwidth (GB/sec) */
- uint64_t pcie_bandwidth_acc;
-
- /*PCIE instantaneous bandwidth (GB/sec) */
- uint64_t pcie_bandwidth_inst;
-
- /* PCIE L0 to recovery state transition accumulated count */
- uint64_t pcie_l0_to_recov_count_acc;
-
- /* PCIE replay accumulated count */
- uint64_t pcie_replay_count_acc;
-
- /* PCIE replay rollover accumulated count */
- uint64_t pcie_replay_rover_count_acc;
-
- /* XGMI accumulated data transfer size(KiloBytes) */
- uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS];
- uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS];
-
- /* PMFW attached timestamp (10ns resolution) */
- uint64_t firmware_timestamp;
-
- /* Current clocks (Mhz) */
- uint16_t current_gfxclk[MAX_GFX_CLKS];
- uint16_t current_socclk[MAX_CLKS];
- uint16_t current_vclk0[MAX_CLKS];
- uint16_t current_dclk0[MAX_CLKS];
- uint16_t current_uclk;
-
- uint16_t padding;
-};
-
-struct gpu_metrics_v1_5 {
- struct metrics_table_header common_header;
-
- /* Temperature (Celsius) */
- uint16_t temperature_hotspot;
- uint16_t temperature_mem;
- uint16_t temperature_vrsoc;
-
- /* Power (Watts) */
- uint16_t curr_socket_power;
-
- /* Utilization (%) */
- uint16_t average_gfx_activity;
- uint16_t average_umc_activity; // memory controller
- uint16_t vcn_activity[NUM_VCN];
- uint16_t jpeg_activity[NUM_JPEG_ENG];
-
- /* Energy (15.259uJ (2^-16) units) */
- uint64_t energy_accumulator;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Clock Lock Status. Each bit corresponds to clock instance */
- uint32_t gfxclk_lock_status;
-
- /* Link width (number of lanes) and speed (in 0.1 GT/s) */
- uint16_t pcie_link_width;
- uint16_t pcie_link_speed;
-
- /* XGMI bus width and bitrate (in Gbps) */
- uint16_t xgmi_link_width;
- uint16_t xgmi_link_speed;
-
- /* Utilization Accumulated (%) */
- uint32_t gfx_activity_acc;
- uint32_t mem_activity_acc;
-
- /*PCIE accumulated bandwidth (GB/sec) */
- uint64_t pcie_bandwidth_acc;
-
- /*PCIE instantaneous bandwidth (GB/sec) */
- uint64_t pcie_bandwidth_inst;
-
- /* PCIE L0 to recovery state transition accumulated count */
- uint64_t pcie_l0_to_recov_count_acc;
-
- /* PCIE replay accumulated count */
- uint64_t pcie_replay_count_acc;
-
- /* PCIE replay rollover accumulated count */
- uint64_t pcie_replay_rover_count_acc;
-
- /* PCIE NAK sent accumulated count */
- uint32_t pcie_nak_sent_count_acc;
-
- /* PCIE NAK received accumulated count */
- uint32_t pcie_nak_rcvd_count_acc;
-
- /* XGMI accumulated data transfer size(KiloBytes) */
- uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS];
- uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS];
-
- /* PMFW attached timestamp (10ns resolution) */
- uint64_t firmware_timestamp;
-
- /* Current clocks (Mhz) */
- uint16_t current_gfxclk[MAX_GFX_CLKS];
- uint16_t current_socclk[MAX_CLKS];
- uint16_t current_vclk0[MAX_CLKS];
- uint16_t current_dclk0[MAX_CLKS];
- uint16_t current_uclk;
-
- uint16_t padding;
-};
-
-/*
- * gpu_metrics_v2_0 is not recommended as it's not naturally aligned.
- * Use gpu_metrics_v2_1 or later instead.
- */
-struct gpu_metrics_v2_0 {
- struct metrics_table_header common_header;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Temperature */
- uint16_t temperature_gfx; // gfx temperature on APUs
- uint16_t temperature_soc; // soc temperature on APUs
- uint16_t temperature_core[8]; // CPU core temperature on APUs
- uint16_t temperature_l3[2];
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Power/Energy */
- uint16_t average_socket_power; // dGPU + APU power on A + A platform
- uint16_t average_cpu_power;
- uint16_t average_soc_power;
- uint16_t average_gfx_power;
- uint16_t average_core_power[8]; // CPU core power on APUs
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_dclk_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_fclk;
- uint16_t current_vclk;
- uint16_t current_dclk;
- uint16_t current_coreclk[8]; // CPU core clocks
- uint16_t current_l3clk[2];
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t fan_pwm;
-
- uint16_t padding;
-};
-
-struct gpu_metrics_v2_1 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_gfx; // gfx temperature on APUs
- uint16_t temperature_soc; // soc temperature on APUs
- uint16_t temperature_core[8]; // CPU core temperature on APUs
- uint16_t temperature_l3[2];
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Power/Energy */
- uint16_t average_socket_power; // dGPU + APU power on A + A platform
- uint16_t average_cpu_power;
- uint16_t average_soc_power;
- uint16_t average_gfx_power;
- uint16_t average_core_power[8]; // CPU core power on APUs
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_dclk_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_fclk;
- uint16_t current_vclk;
- uint16_t current_dclk;
- uint16_t current_coreclk[8]; // CPU core clocks
- uint16_t current_l3clk[2];
-
- /* Throttle status */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t fan_pwm;
-
- uint16_t padding[3];
-};
-
-struct gpu_metrics_v2_2 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_gfx; // gfx temperature on APUs
- uint16_t temperature_soc; // soc temperature on APUs
- uint16_t temperature_core[8]; // CPU core temperature on APUs
- uint16_t temperature_l3[2];
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Power/Energy */
- uint16_t average_socket_power; // dGPU + APU power on A + A platform
- uint16_t average_cpu_power;
- uint16_t average_soc_power;
- uint16_t average_gfx_power;
- uint16_t average_core_power[8]; // CPU core power on APUs
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_dclk_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_fclk;
- uint16_t current_vclk;
- uint16_t current_dclk;
- uint16_t current_coreclk[8]; // CPU core clocks
- uint16_t current_l3clk[2];
-
- /* Throttle status (ASIC dependent) */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t fan_pwm;
-
- uint16_t padding[3];
-
- /* Throttle status (ASIC independent) */
- uint64_t indep_throttle_status;
-};
-
-struct gpu_metrics_v2_3 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- uint16_t temperature_gfx; // gfx temperature on APUs
- uint16_t temperature_soc; // soc temperature on APUs
- uint16_t temperature_core[8]; // CPU core temperature on APUs
- uint16_t temperature_l3[2];
-
- /* Utilization */
- uint16_t average_gfx_activity;
- uint16_t average_mm_activity; // UVD or VCN
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Power/Energy */
- uint16_t average_socket_power; // dGPU + APU power on A + A platform
- uint16_t average_cpu_power;
- uint16_t average_soc_power;
- uint16_t average_gfx_power;
- uint16_t average_core_power[8]; // CPU core power on APUs
-
- /* Average clocks */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_dclk_frequency;
-
- /* Current clocks */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_fclk;
- uint16_t current_vclk;
- uint16_t current_dclk;
- uint16_t current_coreclk[8]; // CPU core clocks
- uint16_t current_l3clk[2];
-
- /* Throttle status (ASIC dependent) */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t fan_pwm;
-
- uint16_t padding[3];
-
- /* Throttle status (ASIC independent) */
- uint64_t indep_throttle_status;
-
- /* Average Temperature */
- uint16_t average_temperature_gfx; // average gfx temperature on APUs
- uint16_t average_temperature_soc; // average soc temperature on APUs
- uint16_t average_temperature_core[8]; // average CPU core temperature on APUs
- uint16_t average_temperature_l3[2];
-};
-
-struct gpu_metrics_v2_4 {
- struct metrics_table_header common_header;
-
- /* Temperature (unit: centi-Celsius) */
- uint16_t temperature_gfx;
- uint16_t temperature_soc;
- uint16_t temperature_core[8];
- uint16_t temperature_l3[2];
-
- /* Utilization (unit: centi) */
- uint16_t average_gfx_activity;
- uint16_t average_mm_activity;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Power/Energy (unit: mW) */
- uint16_t average_socket_power;
- uint16_t average_cpu_power;
- uint16_t average_soc_power;
- uint16_t average_gfx_power;
- uint16_t average_core_power[8];
-
- /* Average clocks (unit: MHz) */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_dclk_frequency;
-
- /* Current clocks (unit: MHz) */
- uint16_t current_gfxclk;
- uint16_t current_socclk;
- uint16_t current_uclk;
- uint16_t current_fclk;
- uint16_t current_vclk;
- uint16_t current_dclk;
- uint16_t current_coreclk[8];
- uint16_t current_l3clk[2];
-
- /* Throttle status (ASIC dependent) */
- uint32_t throttle_status;
-
- /* Fans */
- uint16_t fan_pwm;
-
- uint16_t padding[3];
-
- /* Throttle status (ASIC independent) */
- uint64_t indep_throttle_status;
-
- /* Average Temperature (unit: centi-Celsius) */
- uint16_t average_temperature_gfx;
- uint16_t average_temperature_soc;
- uint16_t average_temperature_core[8];
- uint16_t average_temperature_l3[2];
-
- /* Power/Voltage (unit: mV) */
- uint16_t average_cpu_voltage;
- uint16_t average_soc_voltage;
- uint16_t average_gfx_voltage;
-
- /* Power/Current (unit: mA) */
- uint16_t average_cpu_current;
- uint16_t average_soc_current;
- uint16_t average_gfx_current;
-};
-
-struct gpu_metrics_v3_0 {
- struct metrics_table_header common_header;
-
- /* Temperature */
- /* gfx temperature on APUs */
- uint16_t temperature_gfx;
- /* soc temperature on APUs */
- uint16_t temperature_soc;
- /* CPU core temperature on APUs */
- uint16_t temperature_core[16];
- /* skin temperature on APUs */
- uint16_t temperature_skin;
-
- /* Utilization */
- /* time filtered GFX busy % [0-100] */
- uint16_t average_gfx_activity;
- /* time filtered VCN busy % [0-100] */
- uint16_t average_vcn_activity;
- /* time filtered IPU per-column busy % [0-100] */
- uint16_t average_ipu_activity[8];
- /* time filtered per-core C0 residency % [0-100]*/
- uint16_t average_core_c0_activity[16];
- /* time filtered DRAM read bandwidth [MB/sec] */
- uint16_t average_dram_reads;
- /* time filtered DRAM write bandwidth [MB/sec] */
- uint16_t average_dram_writes;
- /* time filtered IPU read bandwidth [MB/sec] */
- uint16_t average_ipu_reads;
- /* time filtered IPU write bandwidth [MB/sec] */
- uint16_t average_ipu_writes;
-
- /* Driver attached timestamp (in ns) */
- uint64_t system_clock_counter;
-
- /* Power/Energy */
- /* time filtered power used for PPT/STAPM [APU+dGPU] [mW] */
- uint32_t average_socket_power;
- /* time filtered IPU power [mW] */
- uint16_t average_ipu_power;
- /* time filtered APU power [mW] */
- uint32_t average_apu_power;
- /* time filtered GFX power [mW] */
- uint32_t average_gfx_power;
- /* time filtered dGPU power [mW] */
- uint32_t average_dgpu_power;
- /* time filtered sum of core power across all cores in the socket [mW] */
- uint32_t average_all_core_power;
- /* calculated core power [mW] */
- uint16_t average_core_power[16];
- /* time filtered total system power [mW] */
- uint16_t average_sys_power;
- /* maximum IRM defined STAPM power limit [mW] */
- uint16_t stapm_power_limit;
- /* time filtered STAPM power limit [mW] */
- uint16_t current_stapm_power_limit;
-
- /* time filtered clocks [MHz] */
- uint16_t average_gfxclk_frequency;
- uint16_t average_socclk_frequency;
- uint16_t average_vpeclk_frequency;
- uint16_t average_ipuclk_frequency;
- uint16_t average_fclk_frequency;
- uint16_t average_vclk_frequency;
- uint16_t average_uclk_frequency;
- uint16_t average_mpipu_frequency;
-
- /* Current clocks */
- /* target core frequency [MHz] */
- uint16_t current_coreclk[16];
- /* CCLK frequency limit enforced on classic cores [MHz] */
- uint16_t current_core_maxfreq;
- /* GFXCLK frequency limit enforced on GFX [MHz] */
- uint16_t current_gfx_maxfreq;
-
- /* Throttle Residency (ASIC dependent) */
- uint32_t throttle_residency_prochot;
- uint32_t throttle_residency_spl;
- uint32_t throttle_residency_fppt;
- uint32_t throttle_residency_sppt;
- uint32_t throttle_residency_thm_core;
- uint32_t throttle_residency_thm_gfx;
- uint32_t throttle_residency_thm_soc;
-
- /* Metrics table alpha filter time constant [us] */
- uint32_t time_filter_alphavalue;
-};
-} // namespace metrics
-
-#endif
+#ifndef GPU_METRICS_H
+#define GPU_METRICS_H
+
+#include
+
+/* STRUCTS COPIED WHOLESALE FROM LINUX SOURCE CODE, formatted and wrapped around a namespace
+https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/include/kgd_pp_interface.h */
+
+#define NUM_HBM_INSTANCES 4
+#define NUM_XGMI_LINKS 8
+#define MAX_GFX_CLKS 8
+#define MAX_CLKS 4
+#define NUM_VCN 4
+#define NUM_JPEG_ENG 32
+#define NUM_JPEG_ENG_V1 40
+#define MAX_XCC 8
+#define NUM_XCP 8
+
+struct metrics_table_header {
+ uint16_t structure_size;
+ uint8_t format_revision;
+ uint8_t content_revision;
+};
+
+/*
+ * gpu_metrics_v1_0 is not recommended as it's not naturally aligned.
+ * Use gpu_metrics_v1_1 or later instead.
+ */
+struct gpu_metrics_v1_0 {
+ struct metrics_table_header common_header;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Temperature */
+ uint16_t temperature_edge;
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrgfx;
+ uint16_t temperature_vrsoc;
+ uint16_t temperature_vrmem;
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Power/Energy */
+ uint16_t average_socket_power;
+ uint32_t energy_accumulator;
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_vclk0_frequency;
+ uint16_t average_dclk0_frequency;
+ uint16_t average_vclk1_frequency;
+ uint16_t average_dclk1_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_vclk0;
+ uint16_t current_dclk0;
+ uint16_t current_vclk1;
+ uint16_t current_dclk1;
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t current_fan_speed;
+
+ /* Link width/speed */
+ uint8_t pcie_link_width;
+ uint8_t pcie_link_speed; // in 0.1 GT/s
+};
+
+struct gpu_metrics_v1_1 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_edge;
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrgfx;
+ uint16_t temperature_vrsoc;
+ uint16_t temperature_vrmem;
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Power/Energy */
+ uint16_t average_socket_power;
+ uint64_t energy_accumulator;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_vclk0_frequency;
+ uint16_t average_dclk0_frequency;
+ uint16_t average_vclk1_frequency;
+ uint16_t average_dclk1_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_vclk0;
+ uint16_t current_dclk0;
+ uint16_t current_vclk1;
+ uint16_t current_dclk1;
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t current_fan_speed;
+
+ /* Link width/speed */
+ uint16_t pcie_link_width;
+ uint16_t pcie_link_speed; // in 0.1 GT/s
+
+ uint16_t padding;
+
+ uint32_t gfx_activity_acc;
+ uint32_t mem_activity_acc;
+
+ uint16_t temperature_hbm[NUM_HBM_INSTANCES];
+};
+
+struct gpu_metrics_v1_2 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_edge;
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrgfx;
+ uint16_t temperature_vrsoc;
+ uint16_t temperature_vrmem;
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Power/Energy */
+ uint16_t average_socket_power;
+ uint64_t energy_accumulator;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_vclk0_frequency;
+ uint16_t average_dclk0_frequency;
+ uint16_t average_vclk1_frequency;
+ uint16_t average_dclk1_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_vclk0;
+ uint16_t current_dclk0;
+ uint16_t current_vclk1;
+ uint16_t current_dclk1;
+
+ /* Throttle status (ASIC dependent) */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t current_fan_speed;
+
+ /* Link width/speed */
+ uint16_t pcie_link_width;
+ uint16_t pcie_link_speed; // in 0.1 GT/s
+
+ uint16_t padding;
+
+ uint32_t gfx_activity_acc;
+ uint32_t mem_activity_acc;
+
+ uint16_t temperature_hbm[NUM_HBM_INSTANCES];
+
+ /* PMFW attached timestamp (10ns resolution) */
+ uint64_t firmware_timestamp;
+};
+
+struct gpu_metrics_v1_3 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_edge;
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrgfx;
+ uint16_t temperature_vrsoc;
+ uint16_t temperature_vrmem;
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Power/Energy */
+ uint16_t average_socket_power;
+ uint64_t energy_accumulator;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_vclk0_frequency;
+ uint16_t average_dclk0_frequency;
+ uint16_t average_vclk1_frequency;
+ uint16_t average_dclk1_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_vclk0;
+ uint16_t current_dclk0;
+ uint16_t current_vclk1;
+ uint16_t current_dclk1;
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t current_fan_speed;
+
+ /* Link width/speed */
+ uint16_t pcie_link_width;
+ uint16_t pcie_link_speed; // in 0.1 GT/s
+
+ uint16_t padding;
+
+ uint32_t gfx_activity_acc;
+ uint32_t mem_activity_acc;
+
+ uint16_t temperature_hbm[NUM_HBM_INSTANCES];
+
+ /* PMFW attached timestamp (10ns resolution) */
+ uint64_t firmware_timestamp;
+
+ /* Voltage (mV) */
+ uint16_t voltage_soc;
+ uint16_t voltage_gfx;
+ uint16_t voltage_mem;
+
+ uint16_t padding1;
+
+ /* Throttle status (ASIC independent) */
+ uint64_t indep_throttle_status;
+};
+
+struct gpu_metrics_v1_4 {
+ struct metrics_table_header common_header;
+
+ /* Temperature (Celsius) */
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrsoc;
+
+ /* Power (Watts) */
+ uint16_t curr_socket_power;
+
+ /* Utilization (%) */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t vcn_activity[NUM_VCN];
+
+ /* Energy (15.259uJ (2^-16) units) */
+ uint64_t energy_accumulator;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Clock Lock Status. Each bit corresponds to clock instance */
+ uint32_t gfxclk_lock_status;
+
+ /* Link width (number of lanes) and speed (in 0.1 GT/s) */
+ uint16_t pcie_link_width;
+ uint16_t pcie_link_speed;
+
+ /* XGMI bus width and bitrate (in Gbps) */
+ uint16_t xgmi_link_width;
+ uint16_t xgmi_link_speed;
+
+ /* Utilization Accumulated (%) */
+ uint32_t gfx_activity_acc;
+ uint32_t mem_activity_acc;
+
+ /*PCIE accumulated bandwidth (GB/sec) */
+ uint64_t pcie_bandwidth_acc;
+
+ /*PCIE instantaneous bandwidth (GB/sec) */
+ uint64_t pcie_bandwidth_inst;
+
+ /* PCIE L0 to recovery state transition accumulated count */
+ uint64_t pcie_l0_to_recov_count_acc;
+
+ /* PCIE replay accumulated count */
+ uint64_t pcie_replay_count_acc;
+
+ /* PCIE replay rollover accumulated count */
+ uint64_t pcie_replay_rover_count_acc;
+
+ /* XGMI accumulated data transfer size(KiloBytes) */
+ uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS];
+ uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS];
+
+ /* PMFW attached timestamp (10ns resolution) */
+ uint64_t firmware_timestamp;
+
+ /* Current clocks (Mhz) */
+ uint16_t current_gfxclk[MAX_GFX_CLKS];
+ uint16_t current_socclk[MAX_CLKS];
+ uint16_t current_vclk0[MAX_CLKS];
+ uint16_t current_dclk0[MAX_CLKS];
+ uint16_t current_uclk;
+
+ uint16_t padding;
+};
+
+struct gpu_metrics_v1_5 {
+ struct metrics_table_header common_header;
+
+ /* Temperature (Celsius) */
+ uint16_t temperature_hotspot;
+ uint16_t temperature_mem;
+ uint16_t temperature_vrsoc;
+
+ /* Power (Watts) */
+ uint16_t curr_socket_power;
+
+ /* Utilization (%) */
+ uint16_t average_gfx_activity;
+ uint16_t average_umc_activity; // memory controller
+ uint16_t vcn_activity[NUM_VCN];
+ uint16_t jpeg_activity[NUM_JPEG_ENG];
+
+ /* Energy (15.259uJ (2^-16) units) */
+ uint64_t energy_accumulator;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Clock Lock Status. Each bit corresponds to clock instance */
+ uint32_t gfxclk_lock_status;
+
+ /* Link width (number of lanes) and speed (in 0.1 GT/s) */
+ uint16_t pcie_link_width;
+ uint16_t pcie_link_speed;
+
+ /* XGMI bus width and bitrate (in Gbps) */
+ uint16_t xgmi_link_width;
+ uint16_t xgmi_link_speed;
+
+ /* Utilization Accumulated (%) */
+ uint32_t gfx_activity_acc;
+ uint32_t mem_activity_acc;
+
+ /*PCIE accumulated bandwidth (GB/sec) */
+ uint64_t pcie_bandwidth_acc;
+
+ /*PCIE instantaneous bandwidth (GB/sec) */
+ uint64_t pcie_bandwidth_inst;
+
+ /* PCIE L0 to recovery state transition accumulated count */
+ uint64_t pcie_l0_to_recov_count_acc;
+
+ /* PCIE replay accumulated count */
+ uint64_t pcie_replay_count_acc;
+
+ /* PCIE replay rollover accumulated count */
+ uint64_t pcie_replay_rover_count_acc;
+
+ /* PCIE NAK sent accumulated count */
+ uint32_t pcie_nak_sent_count_acc;
+
+ /* PCIE NAK received accumulated count */
+ uint32_t pcie_nak_rcvd_count_acc;
+
+ /* XGMI accumulated data transfer size(KiloBytes) */
+ uint64_t xgmi_read_data_acc[NUM_XGMI_LINKS];
+ uint64_t xgmi_write_data_acc[NUM_XGMI_LINKS];
+
+ /* PMFW attached timestamp (10ns resolution) */
+ uint64_t firmware_timestamp;
+
+ /* Current clocks (Mhz) */
+ uint16_t current_gfxclk[MAX_GFX_CLKS];
+ uint16_t current_socclk[MAX_CLKS];
+ uint16_t current_vclk0[MAX_CLKS];
+ uint16_t current_dclk0[MAX_CLKS];
+ uint16_t current_uclk;
+
+ uint16_t padding;
+};
+
+/*
+ * gpu_metrics_v2_0 is not recommended as it's not naturally aligned.
+ * Use gpu_metrics_v2_1 or later instead.
+ */
+struct gpu_metrics_v2_0 {
+ struct metrics_table_header common_header;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Temperature */
+ uint16_t temperature_gfx; // gfx temperature on APUs
+ uint16_t temperature_soc; // soc temperature on APUs
+ uint16_t temperature_core[8]; // CPU core temperature on APUs
+ uint16_t temperature_l3[2];
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Power/Energy */
+ uint16_t average_socket_power; // dGPU + APU power on A + A platform
+ uint16_t average_cpu_power;
+ uint16_t average_soc_power;
+ uint16_t average_gfx_power;
+ uint16_t average_core_power[8]; // CPU core power on APUs
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_dclk_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_fclk;
+ uint16_t current_vclk;
+ uint16_t current_dclk;
+ uint16_t current_coreclk[8]; // CPU core clocks
+ uint16_t current_l3clk[2];
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t fan_pwm;
+
+ uint16_t padding;
+};
+
+struct gpu_metrics_v2_1 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_gfx; // gfx temperature on APUs
+ uint16_t temperature_soc; // soc temperature on APUs
+ uint16_t temperature_core[8]; // CPU core temperature on APUs
+ uint16_t temperature_l3[2];
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Power/Energy */
+ uint16_t average_socket_power; // dGPU + APU power on A + A platform
+ uint16_t average_cpu_power;
+ uint16_t average_soc_power;
+ uint16_t average_gfx_power;
+ uint16_t average_core_power[8]; // CPU core power on APUs
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_dclk_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_fclk;
+ uint16_t current_vclk;
+ uint16_t current_dclk;
+ uint16_t current_coreclk[8]; // CPU core clocks
+ uint16_t current_l3clk[2];
+
+ /* Throttle status */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t fan_pwm;
+
+ uint16_t padding[3];
+};
+
+struct gpu_metrics_v2_2 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_gfx; // gfx temperature on APUs
+ uint16_t temperature_soc; // soc temperature on APUs
+ uint16_t temperature_core[8]; // CPU core temperature on APUs
+ uint16_t temperature_l3[2];
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Power/Energy */
+ uint16_t average_socket_power; // dGPU + APU power on A + A platform
+ uint16_t average_cpu_power;
+ uint16_t average_soc_power;
+ uint16_t average_gfx_power;
+ uint16_t average_core_power[8]; // CPU core power on APUs
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_dclk_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_fclk;
+ uint16_t current_vclk;
+ uint16_t current_dclk;
+ uint16_t current_coreclk[8]; // CPU core clocks
+ uint16_t current_l3clk[2];
+
+ /* Throttle status (ASIC dependent) */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t fan_pwm;
+
+ uint16_t padding[3];
+
+ /* Throttle status (ASIC independent) */
+ uint64_t indep_throttle_status;
+};
+
+struct gpu_metrics_v2_3 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ uint16_t temperature_gfx; // gfx temperature on APUs
+ uint16_t temperature_soc; // soc temperature on APUs
+ uint16_t temperature_core[8]; // CPU core temperature on APUs
+ uint16_t temperature_l3[2];
+
+ /* Utilization */
+ uint16_t average_gfx_activity;
+ uint16_t average_mm_activity; // UVD or VCN
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Power/Energy */
+ uint16_t average_socket_power; // dGPU + APU power on A + A platform
+ uint16_t average_cpu_power;
+ uint16_t average_soc_power;
+ uint16_t average_gfx_power;
+ uint16_t average_core_power[8]; // CPU core power on APUs
+
+ /* Average clocks */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_dclk_frequency;
+
+ /* Current clocks */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_fclk;
+ uint16_t current_vclk;
+ uint16_t current_dclk;
+ uint16_t current_coreclk[8]; // CPU core clocks
+ uint16_t current_l3clk[2];
+
+ /* Throttle status (ASIC dependent) */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t fan_pwm;
+
+ uint16_t padding[3];
+
+ /* Throttle status (ASIC independent) */
+ uint64_t indep_throttle_status;
+
+ /* Average Temperature */
+ uint16_t average_temperature_gfx; // average gfx temperature on APUs
+ uint16_t average_temperature_soc; // average soc temperature on APUs
+ uint16_t average_temperature_core[8]; // average CPU core temperature on APUs
+ uint16_t average_temperature_l3[2];
+};
+
+struct gpu_metrics_v2_4 {
+ struct metrics_table_header common_header;
+
+ /* Temperature (unit: centi-Celsius) */
+ uint16_t temperature_gfx;
+ uint16_t temperature_soc;
+ uint16_t temperature_core[8];
+ uint16_t temperature_l3[2];
+
+ /* Utilization (unit: centi) */
+ uint16_t average_gfx_activity;
+ uint16_t average_mm_activity;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Power/Energy (unit: mW) */
+ uint16_t average_socket_power;
+ uint16_t average_cpu_power;
+ uint16_t average_soc_power;
+ uint16_t average_gfx_power;
+ uint16_t average_core_power[8];
+
+ /* Average clocks (unit: MHz) */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_dclk_frequency;
+
+ /* Current clocks (unit: MHz) */
+ uint16_t current_gfxclk;
+ uint16_t current_socclk;
+ uint16_t current_uclk;
+ uint16_t current_fclk;
+ uint16_t current_vclk;
+ uint16_t current_dclk;
+ uint16_t current_coreclk[8];
+ uint16_t current_l3clk[2];
+
+ /* Throttle status (ASIC dependent) */
+ uint32_t throttle_status;
+
+ /* Fans */
+ uint16_t fan_pwm;
+
+ uint16_t padding[3];
+
+ /* Throttle status (ASIC independent) */
+ uint64_t indep_throttle_status;
+
+ /* Average Temperature (unit: centi-Celsius) */
+ uint16_t average_temperature_gfx;
+ uint16_t average_temperature_soc;
+ uint16_t average_temperature_core[8];
+ uint16_t average_temperature_l3[2];
+
+ /* Power/Voltage (unit: mV) */
+ uint16_t average_cpu_voltage;
+ uint16_t average_soc_voltage;
+ uint16_t average_gfx_voltage;
+
+ /* Power/Current (unit: mA) */
+ uint16_t average_cpu_current;
+ uint16_t average_soc_current;
+ uint16_t average_gfx_current;
+};
+
+struct gpu_metrics_v3_0 {
+ struct metrics_table_header common_header;
+
+ /* Temperature */
+ /* gfx temperature on APUs */
+ uint16_t temperature_gfx;
+ /* soc temperature on APUs */
+ uint16_t temperature_soc;
+ /* CPU core temperature on APUs */
+ uint16_t temperature_core[16];
+ /* skin temperature on APUs */
+ uint16_t temperature_skin;
+
+ /* Utilization */
+ /* time filtered GFX busy % [0-100] */
+ uint16_t average_gfx_activity;
+ /* time filtered VCN busy % [0-100] */
+ uint16_t average_vcn_activity;
+ /* time filtered IPU per-column busy % [0-100] */
+ uint16_t average_ipu_activity[8];
+ /* time filtered per-core C0 residency % [0-100]*/
+ uint16_t average_core_c0_activity[16];
+ /* time filtered DRAM read bandwidth [MB/sec] */
+ uint16_t average_dram_reads;
+ /* time filtered DRAM write bandwidth [MB/sec] */
+ uint16_t average_dram_writes;
+ /* time filtered IPU read bandwidth [MB/sec] */
+ uint16_t average_ipu_reads;
+ /* time filtered IPU write bandwidth [MB/sec] */
+ uint16_t average_ipu_writes;
+
+ /* Driver attached timestamp (in ns) */
+ uint64_t system_clock_counter;
+
+ /* Power/Energy */
+ /* time filtered power used for PPT/STAPM [APU+dGPU] [mW] */
+ uint32_t average_socket_power;
+ /* time filtered IPU power [mW] */
+ uint16_t average_ipu_power;
+ /* time filtered APU power [mW] */
+ uint32_t average_apu_power;
+ /* time filtered GFX power [mW] */
+ uint32_t average_gfx_power;
+ /* time filtered dGPU power [mW] */
+ uint32_t average_dgpu_power;
+ /* time filtered sum of core power across all cores in the socket [mW] */
+ uint32_t average_all_core_power;
+ /* calculated core power [mW] */
+ uint16_t average_core_power[16];
+ /* time filtered total system power [mW] */
+ uint16_t average_sys_power;
+ /* maximum IRM defined STAPM power limit [mW] */
+ uint16_t stapm_power_limit;
+ /* time filtered STAPM power limit [mW] */
+ uint16_t current_stapm_power_limit;
+
+ /* time filtered clocks [MHz] */
+ uint16_t average_gfxclk_frequency;
+ uint16_t average_socclk_frequency;
+ uint16_t average_vpeclk_frequency;
+ uint16_t average_ipuclk_frequency;
+ uint16_t average_fclk_frequency;
+ uint16_t average_vclk_frequency;
+ uint16_t average_uclk_frequency;
+ uint16_t average_mpipu_frequency;
+
+ /* Current clocks */
+ /* target core frequency [MHz] */
+ uint16_t current_coreclk[16];
+ /* CCLK frequency limit enforced on classic cores [MHz] */
+ uint16_t current_core_maxfreq;
+ /* GFXCLK frequency limit enforced on GFX [MHz] */
+ uint16_t current_gfx_maxfreq;
+
+ /* Throttle Residency (ASIC dependent) */
+ uint32_t throttle_residency_prochot;
+ uint32_t throttle_residency_spl;
+ uint32_t throttle_residency_fppt;
+ uint32_t throttle_residency_sppt;
+ uint32_t throttle_residency_thm_core;
+ uint32_t throttle_residency_thm_gfx;
+ uint32_t throttle_residency_thm_soc;
+
+ /* Metrics table alpha filter time constant [us] */
+ uint32_t time_filter_alphavalue;
+};
+
+#endif
diff --git a/include/hass.hpp b/include/hass.hpp
deleted file mode 100644
index 01b7685..0000000
--- a/include/hass.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef HASS_HPP
-#define HASS_HPP
-
-#ifdef ENABLE_HOME_ASSISTANT
-#include
-
-#include
-#include
-
-class HomeAssistant {
- public:
- struct Config {
- std::string address;
- std::string entity;
- std::string token;
- };
- explicit HomeAssistant(const Config& config);
- ~HomeAssistant();
-
- float state = 0.0f;
- int connect();
- void disconnect() const;
- void service(int timeout_ms = 0) const;
-
- private:
- uint16_t id = 2;
- std::string tx;
- lws_context* context = nullptr;
- lws* websock = nullptr;
- void event_handler(lws* wsi, lws_callback_reasons reason, char* in);
- static int callback(lws* wsi, lws_callback_reasons reason, void* user, void* in, size_t len);
- Config m_config;
-};
-
-#endif
-
-#endif
\ No newline at end of file
diff --git a/include/lcd.h b/include/lcd.h
new file mode 100644
index 0000000..9a98233
--- /dev/null
+++ b/include/lcd.h
@@ -0,0 +1,35 @@
+#ifndef LCDDISPLAY_HPP
+#define LCDDISPLAY_HPP
+
+#define LCD_LINES 4
+#define LCD_COLS 40
+
+#include
+
+struct lcd_t {
+ int fd;
+ uint32_t baud;
+ char writebuf[LCD_LINES * LCD_COLS + 8];
+ char port[128];
+};
+
+typedef uint8_t lcd_glyph_t[8];
+
+void lcd_close(struct lcd_t* lcd);
+void lcd_clear(struct lcd_t* lcd);
+void lcd_set_contrast(struct lcd_t* lcd, uint8_t contrast);
+void lcd_set_backlight(struct lcd_t* lcd, bool enabled);
+void lcd_set_cursor(struct lcd_t* lcd, uint8_t row, uint8_t col);
+void lcd_set_custom_char(struct lcd_t* lcd, uint8_t index, const lcd_glyph_t* glyph);
+void lcd_write_str(struct lcd_t* lcd, const char* str, uint8_t len);
+void lcd_write_str_pos(struct lcd_t* lcd, const char* str, uint8_t len, uint8_t posX, uint8_t posY);
+void lcd_write_buf(struct lcd_t* lcd, uint8_t row, uint8_t col, const char* str);
+void lcd_clear_buf(struct lcd_t* lcd);
+void lcd_flush_buf(struct lcd_t* lcd);
+char lcd_bar(struct lcd_t* lcd, uint8_t char_id, double value);
+int lcd_init(struct lcd_t* lcd);
+
+inline char cc(const uint8_t c) { return (char)(c % 8); }
+
+
+#endif
\ No newline at end of file
diff --git a/include/log.h b/include/log.h
new file mode 100644
index 0000000..85d2ea2
--- /dev/null
+++ b/include/log.h
@@ -0,0 +1,41 @@
+#ifndef LOG_H
+#define LOG_H
+
+/* ── kill switch ────────────────────────────────────────────────────────── */
+/* comment out to disable all logging */
+#define APPLOG_ENABLED
+
+/* comment out to disable file logging */
+/* #define LOG_FILE_LOCATION "linuxSmartie.log.gz" */
+
+/* ─────────────────────────────────────────────────────────────────────── */
+
+#ifdef APPLOG_ENABLED
+
+#include
+
+typedef enum {
+ LOG_INF,
+ LOG_WRN,
+ LOG_ERR,
+ LOG_DBG,
+ LOG_START,
+} LogLevel;
+
+/* __PRETTY_FUNCTION__ is a GCC/Clang extension that gives the full
+ s ignature: "voi*d foo(int x)" — same thing source_location gave you.
+ Falls back to plain __func__ (C99) if somehow unavailable. */
+#define applog(level, fmt, ...) \
+log_write(level, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__)
+
+/* format attribute gives compile-time printf format checking —
+ better than wha*t std::format gave you at runtime */
+void log_write(LogLevel level, const char *func, const char *fmt, ...)
+__attribute__((format(printf, 3, 4)));
+
+#else /* APPLOG_ENABLED not defined */
+
+#define applog(...) ((void)0)
+
+#endif /* APPLOG_ENABLED */
+#endif /* LOG_H */
diff --git a/include/log.hpp b/include/log.hpp
deleted file mode 100644
index 72e830f..0000000
--- a/include/log.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifndef LOG_HPP
-#define LOG_HPP
-
-// comment out to disable logging in general
-
-#define applog(level, fmt, ...) utils::log(level, std::source_location::current(), fmt, ##__VA_ARGS__)
-
-// comment out to disable logging to file
-// #define LOG_FILE_LOCATION "linuxSmartie.log.gz"
-
-#ifdef applog
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#ifdef LOG_FILE_LOCATION
-#include
-inline std::mutex fmtx; // file logging mutex
-#endif
-
-enum class LOG { INF, WRN, ERR, DBG, START };
-
-namespace utils {
-inline std::mutex cmtx; // console logging mutex
-
-constexpr std::string pFname(std::string_view full) {
- if (const auto pos = full.find(' '); pos != std::string_view::npos)
- full.remove_prefix(pos + 1);
-
- if (const auto pos = full.rfind('('); pos != std::string_view::npos)
- full.remove_suffix(full.size() - pos);
-
- return std::string(full);
-}
-
-template
-void log(const LOG level, const std::source_location& loc, std::format_string str, Args&&... args) {
- constexpr std::string_view reset = "\033[0m";
- constexpr std::string_view pattern = "[{}{}{}] ";
- std::string_view color;
-
- switch (level) {
- case LOG::INF:
- color = "\033[1;32m";
- break; // bold; green
- case LOG::WRN:
- color = "\033[1;33m"; // bold; yellow
- break;
- case LOG::ERR:
- color = "\033[1;31m"; // bold; red
- break;
- case LOG::DBG:
- break;
- case LOG::START:
- color = "\033[1;3;36m"; // bold; blinking; cyan
- break;
- }
-
- /* log to console */
- {
- std::scoped_lock lock(cmtx);
- std::cout << std::format(pattern, color, pFname(loc.function_name()), reset);
- std::cout << std::format(str, std::forward(args)...) << std::endl;
- }
-
-#ifdef LOG_FILE_LOCATION
- /* log to file */
- {
- auto now = std::chrono::system_clock::now();
- auto local = std::chrono::current_zone()->to_local(now);
- std::string msg = std::format("{:%x %H:%M:%S }", floor(local)); // timestamp
- std::format_to(std::back_inserter(msg), pattern, color, pFname(loc.function_name()), reset); // tag
- std::format_to(std::back_inserter(msg), str, std::forward(args)...); // actual log message
-
- std::scoped_lock lock(fmtx);
- gzFile file = gzopen(LOG_FILE_LOCATION, "ab");
- if (file) {
- gzprintf(file, "%s\n", msg.c_str());
- gzclose(file);
- }
- }
-#endif
-}
-} // namespace utils
-
-#else
-
-#define applog(...)
-
-#endif
-
-#endif
diff --git a/include/sys.hpp b/include/sys.hpp
deleted file mode 100644
index d0d2e63..0000000
--- a/include/sys.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef SYS_HPP
-#define SYS_HPP
-
-#include
-#include
-
-namespace sys {
-
-constexpr char months[][4] = {"sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paz", "lis", "gru"};
-constexpr char wdays[][4] = {"Nie", "Pon", "Wto", "Sro", "Czw", "Pia", "Sob"};
-
-struct sysSensors {
- std::string hwmon;
- uint16_t fan_speed[2] = {0}; // left and right cpu fans
- int16_t t_sensor = 0; // ntc temp sensor
- std::byte _pad[2];
-};
-
-struct Memory {
- uint64_t free = 0;
- uint64_t used = 0;
- uint64_t total = 0;
-};
-
-struct Disk {
- std::string mountpoint;
- Memory usage;
-};
-
-struct TimeDate {
- std::string time;
- std::string date;
-};
-
-struct Network {
- uint32_t download = 0;
- uint32_t upload = 0;
-};
-
-void getTimeDate(TimeDate* td);
-void getDisk(Disk* disk);
-void getRam(Memory* mem);
-void getNetwork(Network* net, const std::string& device);
-int detect(sysSensors* s, const std::string& platform);
-void updateSensors(sysSensors* s);
-
-} // namespace sys
-
-#endif
diff --git a/include/utils.hpp b/include/utils.hpp
deleted file mode 100644
index 2ae9ff9..0000000
--- a/include/utils.hpp
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef UTILS_HPP
-#define UTILS_HPP
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace utils {
-
-constexpr char fill_char = ' ';
-enum just : uint8_t { right, left };
-
-std::string pad(std::string s, uint8_t len, just j = right);
-std::string center(std::string str, uint8_t len);
-std::string getFirstDir(const std::string_view& path);
-
-inline std::string pNum(const auto num, const uint8_t decs = 0) {
- static std::array buf;
- auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), static_cast(num), std::chars_format::fixed, decs);
- return {buf.data(), ptr};
-}
-
-/* converts large number in (k)bytes to human-readable numer with suffix and sane decimal */
-std::string pBytes(const auto bytes, const bool isKbytes = false) {
- double bytes_d = bytes;
- for (constexpr std::array suffix_list = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; const auto& suffix : suffix_list) {
- if (suffix == 'K' && isKbytes) continue; // skip first loop if already in Kbytes
- bytes_d /= 1024.0;
- if (bytes_d < 1024) {
- if (bytes_d > 100) return pNum(bytes_d) + suffix;
- if (bytes_d > 10) return pNum(bytes_d, 1) + suffix;
- return pNum(bytes_d, 2) + suffix;
- }
- }
- return "++++";
-}
-
-/* reads file into a std::array buffer */
-template
-inline ssize_t readFile(const std::string& path, std::array& buffer) {
- const int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- applog(LOG::ERR, "Error reading {}", path);
- return 0;
- }
- const ssize_t len = read(fd, buffer.data(), buffer.size());
- if (len >= 0) buffer[len] = '\0';
- close(fd);
- return len;
-}
-
-/* reads a number fast and divides it if needed */
-template
-inline void fastReadNum(const std::string& path, std::array& buf, T& result) {
- readFile(path, buf);
- if constexpr (Divider == 1) {
- std::from_chars(buf.data(), buf.data() + N, result);
- return;
- }
- uint64_t temp{};
- std::from_chars(buf.data(), buf.data() + N, temp);
- if constexpr (std::is_floating_point_v)
- result = temp / static_cast(Divider);
- else
- result = static_cast(temp / Divider);
-}
-
-inline bool fileExists(const std::string_view& path) {
- return std::filesystem::exists(path);
-}
-
-} // namespace utils
-
-#endif
diff --git a/main.cpp b/main.cpp
deleted file mode 100644
index 3b06a8d..0000000
--- a/main.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include
-
-int main() {
- Application::Config config;
-
- config.lcd.port = "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00"; // tis a symlink, can also be just /dev/ttyACM0)
- config.lcd.refresh_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";
- config.hass.url = "home.drath.win";
- config.hass.entity = "sensor.gniazdko_komputer_moc";
- config.hass.token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI0MzUxMTZiY2VjNTg0MTI3OGI4YmU0NTY4ZGQ5MzIyYiIsImlhdCI6MTc1NzQzMDI0MCwiZXhwIjoyMDcyNzkwMjQwfQ.6wKTlxEA0FLWfv-qW35vewUSvTxdVrZWqFwHT5Khu6E";
-
- Application App(config);
- return App.Run();
-}
diff --git a/src/LCDDisplay.cpp b/src/LCDDisplay.cpp
deleted file mode 100644
index e47494d..0000000
--- a/src/LCDDisplay.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "LCDDisplay.hpp"
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-/* lcd size hardcoded to 4x40 idgaf */
-LCDDisplay::LCDDisplay(const std::string& dev, const uint32_t baud) {
- this->dev = dev;
- this->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_iflag = 0;
- term.c_oflag = 0;
- term.c_lflag = 0;
- tcflush(lcd, TCIFLUSH);
- tcsetattr(lcd, TCSANOW, &term);
-
- // init linebuf to spaces
- this->clearBuf();
-
- // disable underline and block cursor
- constexpr uint8_t cmdbuf[] = {254, 75, 254, 84};
- ::write(lcd, &cmdbuf, sizeof(cmdbuf));
-
- // clear display and set cursor home
- this->clear();
- return 0;
-}
-
-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
- return -1;
- }
- return 0;
-}
-
-void LCDDisplay::close() {
- if (lcd >= 0) {
- ::close(lcd);
- applog(LOG::INF, "LCD port closed");
- }
- lcd = -1;
-}
-
-void LCDDisplay::write(const uint8_t* cmdbuf, const uint8_t len) {
- if (::write(lcd, cmdbuf, len) != len) {
- applog(LOG::ERR, "failed to execute ::write, lost access to port?");
- this->open(true);
- }
-}
-
-void LCDDisplay::clear() {
- constexpr uint8_t cmdbuf[] = {254, 88};
- this->write(cmdbuf, sizeof(cmdbuf));
-}
-
-void LCDDisplay::setContrast(const uint8_t contrast) {
- applog(LOG::INF, "Set contrast to {}", contrast);
- const uint8_t cmdbuf[] = {254, 80, contrast};
- this->write(cmdbuf, sizeof(cmdbuf));
-}
-
-void LCDDisplay::setBacklight(const bool enabled) {
- applog(LOG::INF, "Set backlight to {}", enabled);
- const uint8_t cmdbuf[] = {254, static_cast(enabled ? 66 : 70), 255};
- this->write(cmdbuf, enabled ? 3 : 2);
-}
-
-/* still doesnt work? */
-void LCDDisplay::setBacklight(const uint8_t brightness) {
- applog(LOG::INF, "Set backlight brightness to {}", brightness);
- const uint8_t cmdbuf[] = {254, static_cast(brightness ? 66 : 70), 255, brightness}; // 3rd char is timer, 4th is brightness
- this->write(cmdbuf, brightness ? 4 : 2);
-}
-
-void LCDDisplay::setCursor(const uint8_t row, const uint8_t col) {
- const uint8_t cmdbuf[] = {254, 71, static_cast(col + 1), static_cast(row + 1)};
- this->write(cmdbuf, sizeof(cmdbuf));
-}
-
-/* reconsider so im not writing every time. prepend custom chars to the write buffer? */
-void LCDDisplay::setCustomChar(const uint8_t index, const std::array cchar) {
- uint8_t cmdbuf[] = {254, 78, index, 0, 0, 0, 0, 0, 0, 0, 0};
- std::memcpy(&cmdbuf[3], &cchar, sizeof(cchar));
- this->write(cmdbuf, sizeof(cmdbuf));
-}
-
-/* immediately writes string to the lcd at current cursor pos */
-void LCDDisplay::writeStr(const std::string& str) {
- this->write(reinterpret_cast(str.c_str()), str.size());
-}
-
-/* immediately writes string to the lcd at given cursor pos */
-void LCDDisplay::writeStr(const uint8_t row, const uint8_t col, const std::string& str) {
- this->setCursor(row, col);
- this->write(reinterpret_cast(str.c_str()), str.size());
-}
-
-/* writes string to write buffer at calculated pos */
-void LCDDisplay::writeBuf(const uint8_t row, const uint8_t col, const std::string& str) {
- const size_t len = std::min(str.size(), writebuf.size() - col);
- uint8_t pos = 4 + col + (LCD_COLS * (row % 2)); // skip 4 bytes to leave room for set cursor command
- if (row >= 2) pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1
- std::memcpy(&writebuf[pos], str.c_str(), len);
-}
-
-/* initializes the write buffer to spaces */
-void LCDDisplay::clearBuf() {
- std::memset(writebuf.data(), ' ', writebuf.size());
-}
-
-/* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */
-void LCDDisplay::flushBuf() {
- constexpr uint8_t setDisp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1
- std::memcpy(&writebuf[0], setDisp, 4);
- std::memcpy(&writebuf[2 * LCD_COLS + 4], setDisp, 4);
- writebuf[2 * LCD_COLS + 7] = 3; // overwrite set cursor c1 l1 to c1 l3
- this->write(reinterpret_cast(writebuf.data()), writebuf.size());
-}
-
-// i have a whole flushbuf func to avoid too many writes, but im writing on every bar, need to rethink this.
-// we could have a separate pre-char buffer and put all the setCustomChar commands to that?
-char LCDDisplay::bar(const uint8_t char_id, const double value) {
- std::array b{};
- b.fill(0b01110);
- for (uint8_t i = 0; i < (1.0 - value) * 8; i++)
- b[i] = 0;
- this->setCustomChar(char_id, b);
- return cc(char_id);
-}
diff --git a/src/app.cpp b/src/app.cpp
deleted file mode 100644
index 29db7f7..0000000
--- a/src/app.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#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) { //NOLINT
- applog(LOG::START, "Thread started");
-#ifdef ENABLE_HOME_ASSISTANT
- static double power;
- HomeAssistant::Config config;
- config.address = m_config.hass.url;
- config.entity = m_config.hass.entity;
- config.token = m_config.hass.token;
- HomeAssistant pc_power(config);
-
- pc_power.connect();
- while (!st.stop_requested()) {
- pc_power.service();
- if (power != pc_power.state) {
- power = pc_power.state;
- {
- std::lock_guard lock(m_control.sensors);
- m_sensors.hass_state = power;
- }
- }
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
-#else
- (void)st;
- applog(LOG::WRN, "feature disabled at compile time, probably no libwebsockets on host. exiting thread");
- {
- std::lock_guard lock(m_control.sensors);
- m_sensors.hass_state = -1.0;
- }
-#endif
-}
-
-void Application::sensorsThread(const std::stop_token& st) {
- applog(LOG::START, "Thread started, poll interval {} ms", m_config.lcd.refresh_interval_ms);
- 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");
-
- while (!st.stop_requested()) {
- auto start = std::chrono::steady_clock::now();
- {
- std::lock_guard lock(m_control.sensors);
-
- sys::getTimeDate(&m_sensors.td);
- getloadavg(m_sensors.loadavg, 3);
- sys::getRam(&m_sensors.ram);
- sys::getDisk(&m_sensors.home);
- sys::getNetwork(&m_sensors.net, m_config.sys_ifname);
- sys::updateSensors(&m_sensors.sys);
- cpu::update(&m_sensors.cpu);
- gpu::update(&m_sensors.gpu);
- }
-
- // log(LOG::DBG, "took {} microseconds", std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count());
- m_control.display.release(); // unlocks display loop
- std::this_thread::sleep_until(start + std::chrono::milliseconds(m_config.lcd.refresh_interval_ms));
- }
- applog(LOG::INF, "Thread stopped");
-}
-
-void Application::displayThread(const std::stop_token& st) {
- std::stop_callback cb(st, [&] { m_control.display.release(); });
- 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);
- 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()) {
- m_control.display.try_acquire_for(std::chrono::milliseconds(static_cast(m_config.lcd.refresh_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 lock(m_control.sensors);
-
- // prepare some tricky sensors
- std::string gpu_temps = std::to_string(m_sensors.gpu.temp_edge);
- if (m_sensors.gpu.temp_hotspot) {
- const auto delta = m_sensors.gpu.temp_hotspot - m_sensors.gpu.temp_edge;
- gpu_temps.append("/" + std::to_string(m_sensors.gpu.temp_hotspot));
- gpu_temps.insert(0, LCDDisplay::cc(1) + std::to_string(delta) + LCDDisplay::cc(0) + " ");
- }
-
- uint16_t cpu_fan = 0;
- for (const auto& fan : m_sensors.sys.fan_speed)
- cpu_fan += fan;
- cpu_fan /= 2;
-
- // write to display buffer
- lcd.writeBuf(0, 0, utils::pad(m_sensors.td.date, 11, utils::just::left) + " " + m_sensors.td.time + lcd.bar(7, m_sensors.gpu.usage_core / 100.0));
- lcd.writeBuf(0, 26, utils::pNum(m_sensors.loadavg[0], m_sensors.loadavg[0] > 10 ? 1 : 2));
- lcd.writeBuf(0, 31, utils::pNum(m_sensors.loadavg[1], m_sensors.loadavg[1] > 10 ? 1 : 2));
- lcd.writeBuf(0, 36, utils::pNum(m_sensors.loadavg[2], m_sensors.loadavg[2] > 10 ? 1 : 2));
-
- lcd.writeBuf(1, 0, utils::pad(std::to_string(m_sensors.cpu.tctl) + "/" + std::to_string(m_sensors.cpu.tccd1) + LCDDisplay::cc(0), 8, utils::just::left));
- lcd.writeBuf(1, 7, utils::pad(utils::pBytes(m_sensors.ram.used, true), 6, utils::just::left));
- if (m_sensors.hass_state >= 0)
- lcd.writeBuf(1, 13, utils::pad(utils::pNum(m_sensors.hass_state) + "W", 4));
- lcd.writeBuf(1, 19, std::to_string(m_sensors.sys.t_sensor) + LCDDisplay::cc(0)); // t_sensor temp
- lcd.writeBuf(1, 32 - gpu_temps.size(), utils::pad(utils::pBytes(m_sensors.gpu.vram_used), 6));
- lcd.writeBuf(1, 39 - gpu_temps.size(), gpu_temps + LCDDisplay::cc(0));
-
- lcd.writeBuf(2, 0, utils::pad(std::to_string(static_cast(m_sensors.cpu.ptotal)) + "W", 8, utils::just::left));
- lcd.writeBuf(2, m_sensors.cpu.ptotal < 100 ? 4 : 5, std::to_string(cpu_fan) + "R"); // avg fan speed
- lcd.writeBuf(2, 12, LCDDisplay::cc(3) + utils::pBytes(m_sensors.net.upload));
- lcd.writeBuf(2, 19, LCDDisplay::cc(4) + utils::pBytes(m_sensors.net.download));
- lcd.writeBuf(2, 26, utils::pad(std::to_string(m_sensors.gpu.fan_speed) + "R", 5));
- lcd.writeBuf(2, 31, utils::pad(std::to_string(m_sensors.gpu.power_avg) + "/" + std::to_string(m_sensors.gpu.power_cap) + "W", 9));
-
- lcd.writeBuf(3, 0, std::to_string(m_sensors.cpu.avg_freq) + "MHz");
- lcd.writeBuf(3, 14, utils::pad(LCDDisplay::cc(2) + utils::pBytes(m_sensors.home.usage.free), 6));
- lcd.writeBuf(3, 21, utils::pad(std::to_string(m_sensors.gpu.clock_core) + "/" + std::to_string(m_sensors.gpu.clock_mem) + "MHz ", 13));
- lcd.writeBuf(3, 34, utils::pad(utils::pNum(m_sensors.gpu.vcore, 3) + "V", 5));
- }
-
- lcd.flushBuf();
- lcd.clearBuf();
- }
-
- // goodbye msg
- lcd.writeBuf(2, 0, utils::center("Goodbye", 40));
- lcd.flushBuf();
-}
diff --git a/src/cpu.cpp b/src/cpu.cpp
deleted file mode 100644
index 4aa265e..0000000
--- a/src/cpu.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace cpu {
-
-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 -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) {
- static std::array buf;
- struct EnergyTs {
- uint64_t energy = 0;
- std::chrono::time_point ts;
- };
-
- static EnergyTs prev;
- EnergyTs curr;
-
- // read power from intel-rapl? works on amd too, btop uses this trick, seems accurate
- // it tracks with "socket power" in hwinfo on windows, its actually the same thing i had in lcdsmartie
- curr.ts = std::chrono::steady_clock::now();
- utils::fastReadNum("/sys/class/powercap/intel-rapl:0/energy_uj", buf, curr.energy);
- c->ptotal = static_cast(curr.energy - prev.energy) / static_cast(std::chrono::duration_cast(curr.ts - prev.ts).count());
- prev = curr;
-
- // lots of reads but still faster than reading /proc/cpuinfo
- c->avg_freq = 0;
- for (uint8_t i = 0; i < c->num_cores; i++) {
- uint32_t t = 0;
- utils::fastReadNum<1000>("/sys/devices/system/cpu/cpu" + std::to_string(i) + "/cpufreq/cpuinfo_avg_freq", buf, t);
- c->avg_freq += t;
- }
- c->avg_freq /= (c->num_cores > 1) ? c->num_cores : 1;
-
- if (c->hwmon.empty())
- return;
-
- // commented out unused values so its faster
- if (c->module == zenpower) {
- utils::fastReadNum<1000>(c->hwmon + "/temp1_input", buf, c->tdie);
- utils::fastReadNum<1000>(c->hwmon + "/temp2_input", buf, c->tctl);
- utils::fastReadNum<1000>(c->hwmon + "/temp3_input", buf, c->tccd1);
- // utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore);
- // utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc);
- }
-
- if (c->module == k10temp) {
- utils::fastReadNum<1000>(c->hwmon + "/temp1_input", buf, c->tctl);
- utils::fastReadNum<1000>(c->hwmon + "/temp3_input", buf, c->tccd1);
- }
-}
-
-} // namespace cpu
diff --git a/src/gpu.cpp b/src/gpu.cpp
deleted file mode 100644
index 2c85f33..0000000
--- a/src/gpu.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-
-/* maybe have a read pp_table function */
-/* would be neat to wrap it in a class but eh namespace is good enough */
-
-namespace gpu {
-
-const std::string rel_metrics_path = "/../../gpu_metrics"; // gpu_metrics path relative to hwmon 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 */
-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)) {
- std::array raw_metrics{};
- if (!utils::readFile(target->hwmon + rel_metrics_path, raw_metrics))
- return -1;
- const auto header = reinterpret_cast(raw_metrics.data());
-
- applog(LOG::INF, "Found gpu_metrics_v{}_{}", header->format_revision, header->content_revision);
- target->hasGpuMetrics = true;
- }
- return 0;
-}
-
-/* some metrics are missing in gpu_metrics, we always fill them from fs, unused metrics are commented out */
-void fillMissingMetrics(gpuSensors* g) {
- static std::array buf;
- utils::fastReadNum<1000>(g->hwmon + "/in0_input", buf, g->vcore);
- // g->fan_pwm = std::stoi(readFile(g->hwmon + "/pwm1", 4)) * 100 / 256;
- utils::fastReadNum(g->hwmon + "/fan1_input", buf, g->fan_speed);
- utils::fastReadNum<1000000>(g->hwmon + "/power1_cap", buf, g->power_cap);
- // utils::fastReadNum(g->hwmon + "/power1_cap_max", g->power_cap_max) / 1000000;
- utils::fastReadNum(g->hwmon + "/../../mem_info_vram_used", buf, g->vram_used);
- // utils::fastReadNum(g->hwmon + "/../../mem_info_vram_total", g->vram_total);
-}
-
-/* get sensors for pre-vega cards (rx480/580) */
-void updateFromFs(gpuSensors* g) {
- static std::array buf;
- utils::fastReadNum<1000000>(g->hwmon + "/freq1_input", buf, g->clock_core);
- utils::fastReadNum<1000000>(g->hwmon + "/freq2_input", buf, g->clock_mem);
- utils::fastReadNum<1000000>(g->hwmon + "/power1_input", buf, g->power_avg);
- utils::fastReadNum<1000>(g->hwmon + "/temp1_input", buf, g->temp_edge);
- utils::fastReadNum(g->hwmon + "/../../gpu_busy_percent", buf, g->usage_core);
-}
-
-/* get sensors for vega and newer (rx5700xt, rx7800xt [*]) */
-void updateFromMetrics(gpuSensors* g) {
- std::array raw_metrics{};
- if (!utils::readFile(g->hwmon + rel_metrics_path, raw_metrics)) return;
-
- switch (const auto header = reinterpret_cast(raw_metrics.data()); header->format_revision * 10 + header->content_revision) {
- /* rx5700xt, rx7800xt */
- case 13: {
- const auto metrics = reinterpret_cast(raw_metrics.data());
- g->usage_core = metrics->average_gfx_activity;
- g->usage_umc = metrics->average_umc_activity;
- g->usage_media = metrics->average_mm_activity;
-
- g->temp_edge = metrics->temperature_edge;
- g->temp_hotspot = metrics->temperature_hotspot;
- g->temp_mem = metrics->temperature_mem;
-
- g->temp_vrm_gfx = metrics->temperature_vrgfx;
- g->temp_vrm_soc = metrics->temperature_vrsoc;
- g->temp_vrm_mem = metrics->temperature_vrmem;
- g->power_avg = metrics->average_socket_power;
- g->fan_speed = metrics->current_fan_speed;
-
- // hacks for rx7800xt
- // g->clock_core = metrics->average_vclk1_frequency; // why not gfxclock?
- // g->clock_mem = metrics->average_gfxclk_frequency; // why gfxclock? min mem clock seems to be 96mhz, this is probably including time sleeping
-
- // hacks for rx5700xt
- g->clock_core = metrics->average_gfxclk_frequency;
- g->clock_mem = metrics->average_uclk_frequency * 2; // mem controller clock, actual mem is 2x that
- break;
- }
-
- /* ryzen 5 5600g */
- case 22: {
- const auto metrics = reinterpret_cast(raw_metrics.data());
- g->temp_edge = metrics->temperature_gfx / 100;
- break;
- }
-
- /* werid hardware i probably dont like, maybe fallback to reading from fs? */
- default: {
- applog(LOG::WRN, "Unsupported gpu_metrics_v{}_{}", header->format_revision, header->content_revision);
- break;
- }
- }
-}
-
-/* reads values from system and updates the target gpu::sensors struct */
-void update(gpuSensors* g) {
- const bool hwmon_valid = !g->hwmon.empty();
- if (hwmon_valid)
- fillMissingMetrics(g);
-
- if (g->hasGpuMetrics)
- updateFromMetrics(g);
- else
- if (hwmon_valid)
- updateFromFs(g);
-
- if (g->fan_speed > 9999) g->fan_speed = 9999; // sanity check fan speed
-}
-
-} // namespace gpu
diff --git a/src/hass.cpp b/src/hass.cpp
deleted file mode 100644
index e8f20ef..0000000
--- a/src/hass.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-#ifdef ENABLE_HOME_ASSISTANT
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-HomeAssistant::HomeAssistant(const Config& config) {
- m_config = config;
-}
-
-HomeAssistant::~HomeAssistant() {
- disconnect();
-}
-
-void HomeAssistant::event_handler(lws* wsi, const lws_callback_reasons reason, char* in) {
- switch (reason) {
- case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
- applog(LOG::ERR, "websocket conn error: {}", in ? in : "(null)");
- return;
- }
-
- case LWS_CALLBACK_CLIENT_RECEIVE: {
- nlohmann::json json = nlohmann::json::parse(in);
- const std::string ha_type = json["type"].get();
-
- if (ha_type == "auth_required") {
- json.clear();
- json["type"] = "auth";
- json["access_token"] = m_config.token;
- tx = json.dump();
- break;
- }
-
- if (ha_type == "auth_ok") {
- applog(LOG::INF, "subscribing to entity \"{}\"", m_config.entity);
- json.clear();
- json["id"] = id++;
- json["type"] = "subscribe_entities";
- json["entity_ids"][0] = m_config.entity.c_str();
- tx = json.dump();
- break;
- }
-
- if (ha_type == "result") {
- if (json["success"].get() != true)
- applog(LOG::ERR, "api said success was \"false\" on message id {}", id - 1);
- break;
- }
-
- if (ha_type == "event") {
- json = json["event"];
- if (json.contains("a"))
- state = std::stof(json["a"][m_config.entity]["s"].get());
- if (json.contains("c"))
- state = std::stof(json["c"][m_config.entity]["+"]["s"].get());
- break;
- }
-
- applog(LOG::WRN, "unhandled event: {}", static_cast(in));
- break;
- }
-
- case LWS_CALLBACK_CLIENT_ESTABLISHED: {
- applog(LOG::INF, "Websocket connected");
- break;
- }
-
- case LWS_CALLBACK_CLIENT_CLOSED: {
- applog(LOG::INF, "Websocket closed");
- return;
- }
-
- case LWS_CALLBACK_CLIENT_WRITEABLE: {
- /* skip whole callback if there's no tx to send */
- if (!tx.empty()) {
- const size_t msgLen = LWS_PRE + tx.size();
- auto* buf = static_cast(malloc(msgLen));
- if (buf) {
- memcpy(&buf[LWS_PRE], tx.c_str(), tx.size());
- lws_write(wsi, &buf[LWS_PRE], tx.size(), LWS_WRITE_TEXT);
- tx = "";
- free(buf);
- }
- }
- break;
- }
-
- default:
- break;
- }
-}
-
-int HomeAssistant::callback(lws* wsi, const lws_callback_reasons reason, void* user, void* in, size_t) {
- auto* self = static_cast(user);
- self->event_handler(wsi, reason, static_cast(in));
- return 0;
-}
-
-int HomeAssistant::connect() {
- lws_client_connect_info i{};
- lws_context_creation_info info{};
-
- lws_set_log_level(LLL_ERR | LLL_WARN, lwsl_emit_syslog);
-
- std::memset(&i, 0, sizeof(i));
- std::memset(&info, 0, sizeof info);
-
- static constexpr lws_protocols protocols[] = {
- {"lws-minimal-client", callback, sizeof(void*), 0, 0, nullptr, 0},
- LWS_PROTOCOL_LIST_TERM};
-
- static constexpr lws_extension extensions[] = {
- {"permessage-deflate",
- lws_extension_callback_pm_deflate,
- "permessage-deflate"
- "; client_no_context_takeover"
- "; client_max_window_bits"},
- {nullptr, nullptr, nullptr}};
-
- info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
- info.port = CONTEXT_PORT_NO_LISTEN;
- info.protocols = protocols;
- info.fd_limit_per_thread = 1 + 1 + 1;
- info.extensions = extensions;
-
- context = lws_create_context(&info);
- if (!context) {
- applog(LOG::ERR, "error creating context");
- return -1;
- }
-
- i.context = context;
- i.port = 443;
- i.address = m_config.address.c_str();
- i.path = "/api/websocket";
- i.host = i.address;
- i.origin = i.address;
- i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_PRIORITIZE_READS;
- i.protocol = nullptr;
- i.userdata = this;
- i.local_protocol_name = "lws-minimal-client";
-
- websock = lws_client_connect_via_info(&i);
- if (!websock) {
- applog(LOG::ERR, "error creating lws client");
- return -1;
- }
- return 0;
-}
-
-void HomeAssistant::service(const int timeout_ms) const {
- lws_callback_on_writable(websock);
- lws_service(context, timeout_ms);
-}
-
-void HomeAssistant::disconnect() const {
- lws_context_destroy(context);
-}
-
-#endif
diff --git a/src/lcd.c b/src/lcd.c
new file mode 100644
index 0000000..6b30285
--- /dev/null
+++ b/src/lcd.c
@@ -0,0 +1,133 @@
+#include
+#include
+#include
+#include
+#include "log.h"
+#include "lcd.h"
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+int lcd_open(struct lcd_t* lcd, const bool reopen) {
+ applog(LOG_INF, "Opening serial port at %s", lcd->port);
+ if (lcd->fd <= 0 || reopen)
+ lcd->fd = open(lcd->port, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if (lcd->fd <= 0) {
+ applog(LOG_ERR, "Error opening serial port %s", lcd->port); // err
+ return -1;
+ }
+ return 0;
+}
+
+void lcd_close(struct lcd_t* lcd) {
+ if (lcd->fd >= 0) {
+ close(lcd->fd);
+ applog(LOG_INF, "LCD port closed");
+ }
+ lcd->fd = -1;
+}
+
+void lcd_write(struct lcd_t* lcd, const uint8_t* cmdbuf, const uint8_t len) {
+ if (!write(lcd->fd, cmdbuf, len)) {
+ applog(LOG_ERR, "failed to execute write(), lost access to port?");
+ lcd_open(lcd, true);
+ }
+}
+
+void lcd_clear(struct lcd_t* lcd) {
+ constexpr uint8_t cmdbuf[] = {254, 88};
+ lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
+}
+
+void lcd_set_contrast(struct lcd_t* lcd, const uint8_t contrast) {
+ applog(LOG_INF, "Set contrast to %d", contrast);
+ const uint8_t cmdbuf[] = {254, 80, contrast};
+ lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
+}
+
+void lcd_set_backlight(struct lcd_t* lcd, const bool enabled) {
+ applog(LOG_INF, "Set backlight to %s", enabled ? "true" : "false");
+ const uint8_t cmdbuf[] = {254, (enabled ? 66 : 70), 255};
+ lcd_write(lcd, cmdbuf, enabled ? 3 : 2);
+}
+
+void lcd_set_cursor(struct lcd_t* lcd, const uint8_t row, const uint8_t col) {
+ const uint8_t cmdbuf[] = {254, 71, (col + 1), (row + 1)};
+ lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
+}
+
+/* reconsider so im not writing every time. prepend custom chars to the write buffer? */
+void lcd_set_custom_char(struct lcd_t* lcd, const uint8_t index, const lcd_glyph_t* glyph) {
+ uint8_t cmdbuf[] = {254, 78, index, 0, 0, 0, 0, 0, 0, 0, 0};
+ memcpy(&cmdbuf[3], &glyph, sizeof(glyph));
+ lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
+}
+
+/* immediately writes string to the lcd at current cursor pos */
+void lcd_write_str(struct lcd_t* lcd, const char* str, const uint8_t len) {
+ lcd_write(lcd, (const uint8_t*)str, len);
+}
+
+void lcd_write_str_pos(struct lcd_t* lcd, const char* str, const uint8_t len, const uint8_t posX, const uint8_t posY) {
+ lcd_set_cursor(lcd, posX, posY);
+ lcd_write(lcd, (const uint8_t*)str, len);
+}
+
+/* writes string to write buffer at calculated pos, we trust it to be null terminated */
+void lcd_write_buf(struct lcd_t* lcd, const uint8_t row, const uint8_t col, const char* str) {
+ size_t len = 0;
+ while (str[len] != '\0')
+ len++;
+
+ len = MIN(len, sizeof(lcd->writebuf) - col);
+ uint8_t pos = 4 + col + (LCD_COLS * (row % 2)); // skip 4 bytes to leave room for set cursor command
+ if (row >= 2) pos += 2 * LCD_COLS + 4; // if we're writing to disp2, skip another 4 bytes for set cursor command and 2*40 bytes of disp 1
+ memcpy(&lcd->writebuf[pos], str, len);
+}
+
+
+void lcd_clear_buf(struct lcd_t* lcd) {
+ memset(lcd->writebuf, ' ', sizeof(lcd->writebuf));
+}
+
+/* flushes writebuffer to lcd, hyperoptmized, flushes buffer and commands in a single write operation */
+void lcd_flush_buf(struct lcd_t* lcd) {
+ constexpr uint8_t set_disp[] = {254, 71, 1, 1}; // set cursor to char 1, line 1
+ memcpy(&lcd->writebuf[0], set_disp, 4);
+ memcpy(&lcd->writebuf[2 * LCD_COLS + 4], set_disp, 4);
+ lcd->writebuf[2 * LCD_COLS + 7] = 3; // overwrite set cursor c1 l1 to c1 l3
+ lcd_write(lcd, (const uint8_t*)lcd->writebuf, sizeof(lcd->writebuf));
+}
+
+// i have a whole flushbuf func to avoid too many writes, but im writing on every bar, need to rethink this.
+// we could have a separate pre-char buffer and put all the setCustomChar commands to that?
+char lcd_bar(struct lcd_t* lcd, const uint8_t char_id, const double value) {
+ uint8_t b[8];
+ memset(b, 0b01110, sizeof(b));
+ for (uint8_t i = 0; i < (1.0 - value) * 8; i++)
+ b[i] = 0;
+ lcd_set_custom_char(lcd, char_id, &b);
+ return cc(char_id);
+}
+
+int lcd_init(struct lcd_t* lcd) {
+ const int ret = lcd_open(lcd, false);
+ if (ret < 0) {
+ lcd_close(lcd);
+ return -1;
+ }
+
+ applog(LOG_INF, "ret %d, fd %d", ret, lcd->fd);
+
+ struct termios term = {};
+ term.c_cflag = lcd->baud | CS8 | CLOCAL | CREAD;
+
+ tcflush(lcd->fd, TCIFLUSH);
+ tcsetattr(lcd->fd, TCSANOW, &term);
+
+ lcd_clear_buf(lcd);
+ constexpr uint8_t cmdbuf[] = {254, 75, 254, 84};
+ lcd_write(lcd, cmdbuf, sizeof(cmdbuf));
+
+ lcd_clear(lcd);
+ return 0;
+}
\ No newline at end of file
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..5f9b11d
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,95 @@
+#include "log.h"
+
+#ifdef APPLOG_ENABLED
+
+#include
+#include
+#include
+#include
+#include
+
+#ifdef LOG_FILE_LOCATION
+#include
+static pthread_mutex_t fmtx = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+static pthread_mutex_t cmtx = PTHREAD_MUTEX_INITIALIZER;
+
+/* Replicates pFname: strips return type and parameters from __PRETTY_FUNCTION__
+ * "void myFunc(int x)" → "myFunc"
+ * "int other_func(void)" → "other_func"
+ */
+static void fmt_funcname(const char *pretty, char *out, size_t outsz) {
+ const char *start = pretty;
+
+ const char *space = strchr(pretty, ' ');
+ if (space) start = space + 1;
+
+ const char *paren = strrchr(start, '(');
+ size_t len = paren ? (size_t)(paren - start) : strlen(start);
+ if (len >= outsz) len = outsz - 1;
+
+ memcpy(out, start, len);
+ out[len] = '\0';
+}
+
+void log_write(const LogLevel level, const char *func, const char *fmt, ...) {
+ static const char *reset = "\033[0m";
+ const char *color;
+
+ switch (level) {
+ case LOG_INF: color = "\033[1;32m"; break; /* bold green */
+ case LOG_WRN: color = "\033[1;33m"; break; /* bold yellow */
+ case LOG_ERR: color = "\033[1;31m"; break; /* bold red */
+ case LOG_DBG: color = ""; break;
+ case LOG_START: color = "\033[1;3;36m"; break; /* bold italic cyan */
+ default: color = ""; break;
+ }
+
+ char funcname[128];
+ fmt_funcname(func, funcname, sizeof(funcname));
+
+ /* ── console ─────────────────────────────────────────────────────── */
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ pthread_mutex_lock(&cmtx);
+ fprintf(stderr, "[%s%s%s] ", color, funcname, reset);
+ vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ pthread_mutex_unlock(&cmtx);
+ va_end(ap);
+ }
+
+ #ifdef LOG_FILE_LOCATION
+ /* ── file ────────────────────────────────────────────────────────── */
+ {
+ char timebuf[32];
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ struct tm tm_info;
+ localtime_r(&ts.tv_sec, &tm_info);
+ strftime(timebuf, sizeof(timebuf), "%x %H:%M:%S", &tm_info);
+
+ char msgbuf[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ int offset = snprintf(msgbuf, sizeof(msgbuf),
+ "%s.%03ld [%s%s%s] ",
+ timebuf, ts.tv_nsec / 1000000L,
+ color, funcname, reset);
+ vsnprintf(msgbuf + offset, sizeof(msgbuf) - offset, fmt, ap);
+ va_end(ap);
+
+ pthread_mutex_lock(&fmtx);
+ gzFile file = gzopen(LOG_FILE_LOCATION, "ab");
+ if (file) {
+ gzprintf(file, "%s\n", msgbuf);
+ gzclose(file);
+ }
+ pthread_mutex_unlock(&fmtx);
+ }
+ #endif /* LOG_FILE_LOCATION */
+}
+
+#endif /* APPLOG_ENABLED */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..0a38131
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,115 @@
+#include
+#include
+#include
+#include "log.h"
+#include
+#include
+#include
+#include "lcd.h"
+
+atomic_bool g_running; // if using c11, you need atomic_store() and atomic_load();
+
+struct control_t {
+ pthread_mutex_t sensors_mtx = PTHREAD_MUTEX_INITIALIZER;
+ pthread_cond_t sensors_ready = PTHREAD_COND_INITIALIZER,
+
+} control;
+
+struct sensors_t {
+ // sys::TimeDate td;
+ double loadavg[3];
+ // sys::Memory ram;
+ // sys::Disk home;
+ // sys::Network net;
+ // sys::sysSensors sys;
+ // cpu::cpuSensors cpu;
+ // gpu::gpuSensors gpu;
+ double hass_state;
+};
+
+static void *display_thread(void *arg) {
+ applog(LOG_START, "display thread started");
+ struct sensors_t* sensors = arg;
+ sensors->hass_state = 1;
+
+ struct lcd_t lcd = {
+ .port = "/dev/serial/by-id/usb-Raspberry_Pi_Pico_E6616407E37AA12F-if00",
+ .baud = 0010002, // from termios-baud.h, B115200
+ };
+
+ lcd_init(&lcd);
+
+ // basic lcd setup
+ lcd_set_contrast(&lcd, 215);
+ lcd_set_backlight(&lcd, true);
+ lcd_set_custom_char(&lcd, 0, &(lcd_glyph_t){16, 6, 9, 8, 8, 9, 6, 0}); // celcius
+ lcd_set_custom_char(&lcd, 1, &(lcd_glyph_t){0, 0, 4, 10, 10, 17, 31, 0}); // delta
+ lcd_set_custom_char(&lcd, 2, &(lcd_glyph_t){0, 0, 8, 21, 21, 2, 0, 0}); // home (tilde)
+ lcd_set_custom_char(&lcd, 3, &(lcd_glyph_t){4, 14, 21, 4, 4, 4, 0}); // up arrow
+ lcd_set_custom_char(&lcd, 4, &(lcd_glyph_t){4, 4, 4, 21, 14, 4, 0}); // down arrow
+
+ lcd_write_buf(&lcd, 2, 0, "Waiting for sensors..."); // need to center this still
+ lcd_flush_buf(&lcd);
+ lcd_clear_buf(&lcd);
+
+ while (g_running) { // NOLINT its updated globally bud
+ ;
+ }
+
+ lcd_close(&lcd);
+ applog(LOG_WRN, "display thread stopped");
+ return nullptr;
+}
+
+static void *sensors_thread(void *arg) {
+ applog(LOG_START, "sensors thread started");
+ struct sensors_t* sensors = arg;
+ (void)sensors;
+ applog(LOG_WRN, "sensors thread stopped");
+ return nullptr;
+}
+
+int main(void) {
+ g_running = true;
+ applog(LOG_START, "linuxSmartie started");
+
+ /* signal setup */
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigaddset(&sigset, SIGTERM);
+ sigaddset(&sigset, SIGQUIT);
+ pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
+ struct signalfd_siginfo info;
+ const int sfd = signalfd(-1, &sigset, SFD_CLOEXEC);
+
+ struct sensors_t *sensors = malloc(sizeof(struct sensors_t));
+
+ if (sensors == nullptr) {
+ applog(LOG_ERR, "cant allocate mem for the sensor struct");
+ free(sensors);
+ return -1;
+ }
+ applog(LOG_INF, "sensor struct allocated, size is %lu bytes", sizeof(struct sensors_t));
+
+ applog(LOG_INF, "sensors is %.1f", sensors->hass_state);
+
+ pthread_t display_pthread;
+ pthread_t sensors_pthread;
+ pthread_create(&display_pthread, nullptr, display_thread, sensors);
+ pthread_create(&sensors_pthread, nullptr, sensors_thread, sensors);
+
+ read(sfd, &info, sizeof(info)); // halts on this until SIGTERM
+ g_running = false;
+ close(sfd);
+ applog(LOG_WRN, "got stop signal, shutting down...");
+
+ pthread_join(display_pthread, nullptr);
+ pthread_join(sensors_pthread, nullptr);
+
+ applog(LOG_INF, "sensors is %.1f", sensors->hass_state);
+
+ free(sensors);
+ applog(LOG_INF, "freed memory");
+ return 0;
+}
\ No newline at end of file
diff --git a/src/sys.cpp b/src/sys.cpp
deleted file mode 100644
index c9024a9..0000000
--- a/src/sys.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-int getVal(const std::string_view target, std::string_view content) {
- int result = -1;
- if (const std::size_t start = content.find(target); start != std::string::npos) {
- content.remove_prefix(start + target.length());
- const std::size_t end = content.find(" kB");
- while (std::isspace(content.front()))
- content.remove_prefix(1);
- std::from_chars(content.data(), content.data() + end, result);
- }
- return result;
-}
-
-void sys::getTimeDate(TimeDate* td) {
- const auto now = std::chrono::system_clock::now();
- const auto local = std::chrono::current_zone()->to_local(now);
- const std::chrono::year_month_day ymd{floor(local)};
- const std::chrono::weekday wd{floor(local)};
- td->time = std::format("{:%H:%M:%S}", floor(local));
- td->date = std::format("{}, {} {}", wdays[wd.c_encoding()], ymd.day(), months[static_cast(ymd.month()) - 1]);
-}
-
-void sys::getRam(Memory* mem) {
- static std::array buf; // file is longer but we only need first 128 chars
- utils::readFile("/proc/meminfo", buf);
- mem->free = getVal("MemAvailable:", buf.data());
- mem->total = getVal("MemTotal:", buf.data()); // shouldn't really update this on each loop
- mem->used = mem->total - mem->free;
-}
-
-void sys::getDisk(Disk* disk) {
- struct statvfs diskData{};
- statvfs(disk->mountpoint.c_str(), &diskData);
- disk->usage.free = diskData.f_bfree * diskData.f_frsize;
- disk->usage.used = (diskData.f_blocks - diskData.f_bfree) * diskData.f_frsize;
- disk->usage.total = diskData.f_blocks * diskData.f_frsize;
-}
-
-void sys::getNetwork(Network* net, const std::string& device) {
- struct Network {
- std::chrono::time_point ts;
- uint64_t rx = 0;
- uint64_t tx = 0;
- };
-
- static std::array buf;
- static Network prev;
- Network current;
-
- current.ts = std::chrono::steady_clock::now();
- utils::fastReadNum("/sys/class/net/" + device + "/statistics/rx_bytes", buf, current.rx);
- utils::fastReadNum("/sys/class/net/" + device + "/statistics/tx_bytes", buf, current.tx);
- const double ts_diff = static_cast(std::chrono::duration_cast(current.ts - prev.ts).count()) / 1000000.0f;
- net->download = static_cast(static_cast(current.rx - prev.rx) / ts_diff);
- net->upload = static_cast(static_cast(current.tx - prev.tx) / ts_diff);
- prev = current;
-}
-
-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/devices/platform/{}/hwmon\". Kernel params added? Module loaded?", platform);
- return -1;
- }
- applog(LOG::INF, "Found system sensors");
- return 0;
-}
-
-void sys::updateSensors(sysSensors* s) {
- if (s->hwmon.empty())
- return;
- static std::array buf;
- utils::fastReadNum(s->hwmon + "/fan2_input", buf, s->fan_speed[0]);
- utils::fastReadNum(s->hwmon + "/fan7_input", buf, s->fan_speed[1]);
- utils::fastReadNum<1000>(s->hwmon + "/temp5_input", buf, s->t_sensor);
-}
diff --git a/src/utils.cpp b/src/utils.cpp
deleted file mode 100644
index c3eede0..0000000
--- a/src/utils.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include
-
-#include
-#include
-#include
-#include
-
-namespace utils {
-
-/* pads given string to length */
-std::string pad(std::string s, const uint8_t len, const just j) {
- if (len > s.size())
- s.insert(j == left ? s.end() : s.begin(), len - s.size(), fill_char);
- return s;
-}
-
-/* returns the string centered within given length */
-std::string center(std::string str, const uint8_t len) {
- const uint8_t padding = len - str.size();
- str.insert(str.begin(), padding / 2, fill_char);
- str.insert(str.end(), padding / 2, fill_char);
- return str;
-}
-
-/* finds first dir in path and returns it. don't refactor, you don't understand it, its fast enough, and you only use it on init */
-std::string getFirstDir(const std::string_view& path) {
- for (const auto& entry : std::filesystem::directory_iterator(path))
- return entry.path();
- return "";
-}
-
-} // namespace utils
\ No newline at end of file