we're getttng C to work
C deez nuts
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
#ifndef LCDDISPLAY_HPP
|
||||
#define LCDDISPLAY_HPP
|
||||
|
||||
#define LCD_LINES 4
|
||||
#define LCD_COLS 40
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class LCDDisplay {
|
||||
private:
|
||||
int lcd = -1;
|
||||
uint32_t baud = 0;
|
||||
std::string dev;
|
||||
std::array<char, LCD_LINES * LCD_COLS + 8> writebuf{}; // 4x40 chars + 2x4 setcursor commands
|
||||
static constexpr bool dualDisp = (LCD_LINES * LCD_COLS > 80); // is it dual display device or not, evauluated from the size at compile time
|
||||
|
||||
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<uint8_t, 8> 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<char>(c % 8); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef APP_HPP
|
||||
#define APP_HPP
|
||||
|
||||
#include <atomic>
|
||||
#include <cpu.hpp>
|
||||
#include <gpu.hpp>
|
||||
#include <mutex>
|
||||
#include <semaphore>
|
||||
#include <stop_token>
|
||||
#include <sys.hpp>
|
||||
#include <thread>
|
||||
|
||||
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
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef CPU_HPP
|
||||
#define CPU_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
@@ -1,85 +0,0 @@
|
||||
#ifndef GPU_HPP
|
||||
#define GPU_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/* 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
#ifndef HASS_HPP
|
||||
#define HASS_HPP
|
||||
|
||||
#ifdef ENABLE_HOME_ASSISTANT
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
35
include/lcd.h
Normal file
35
include/lcd.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef LCDDISPLAY_HPP
|
||||
#define LCDDISPLAY_HPP
|
||||
|
||||
#define LCD_LINES 4
|
||||
#define LCD_COLS 40
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
41
include/log.h
Normal file
41
include/log.h
Normal file
@@ -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 <stdarg.h>
|
||||
|
||||
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 */
|
||||
@@ -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 <chrono>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <source_location>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef LOG_FILE_LOCATION
|
||||
#include <zlib.h>
|
||||
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 <typename... Args>
|
||||
void log(const LOG level, const std::source_location& loc, std::format_string<Args...> 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>(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<std::chrono::milliseconds>(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>(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
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef SYS_HPP
|
||||
#define SYS_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
@@ -1,80 +0,0 @@
|
||||
#ifndef UTILS_HPP
|
||||
#define UTILS_HPP
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <log.hpp>
|
||||
#include <string>
|
||||
|
||||
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<char, 20> buf;
|
||||
auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), static_cast<double>(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 <size_t N>
|
||||
inline ssize_t readFile(const std::string& path, std::array<char, N>& 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 <uint32_t Divider = 1, typename T, size_t N>
|
||||
inline void fastReadNum(const std::string& path, std::array<char, N>& 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<T>)
|
||||
result = temp / static_cast<T>(Divider);
|
||||
else
|
||||
result = static_cast<T>(temp / Divider);
|
||||
}
|
||||
|
||||
inline bool fileExists(const std::string_view& path) {
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user