diff --git a/README.md b/README.md index e9a1f7b..0b855d4 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ Vaguely inspired by suckless software philosophy, as in: Same as plugins. Just write in more features scrub, learn some C, damn ## TODOs (real) -- 1st line is done -- do the fast file read func, we'll need a lot of that +- still missing gpu and hass +- and the lil gpu usage bar, should just work +- idk some formatting? we had a lot of that on c++ ver +- halts to wait for sensors p long on boot, ig its a minor detail but still ## TODOs - Extra screens support perhaps? just halt sensors monitoring thread and print another struct on display if needed, have a semaphore or sth diff --git a/include/sys.h b/include/sys.h index 04242fe..1bcc911 100644 --- a/include/sys.h +++ b/include/sys.h @@ -25,6 +25,11 @@ struct network_t { char device[32]; }; +struct syssensors_t { + uint16_t fan_speed[2]; // left and right cpu fans + int16_t t_sensor; // ntc temp sensor + char hwmon[128]; +}; void sys_get_time(struct time_date_t *td); @@ -36,4 +41,7 @@ void sys_get_disk(struct disk_t* disk); void sys_get_network(struct network_t* network); +void sys_detect(struct syssensors_t* s, const char* platform); +void sys_update_sensors(struct syssensors_t* s); + #endif //LINUXSMARTIE_SYS_H \ No newline at end of file diff --git a/include/utils.h b/include/utils.h index c9d4a80..f6387b0 100644 --- a/include/utils.h +++ b/include/utils.h @@ -1,11 +1,22 @@ #ifndef UTILS_H #define UTILS_H +#include + +uint64_t timespec_diff_us(const struct timespec *a, const struct timespec *b); +void timespec_add_ms(struct timespec *ts, uint16_t ms); +char *pretty_bytes(uint64_t bytes, int8_t start_suffix, char *buf, size_t bufsz); + void fast_read_num_u64(const char* dir, const char* file, char* buf, uint64_t* result, uint16_t divider); +void fast_read_num_u16(const char* dir, const char* file, char* buf, uint16_t* result, uint16_t divider); void fast_read_num_i16(const char* dir, const char* file, char* buf, int16_t* result, uint16_t divider); bool file_exists(const char *path); int get_hwmon_dir(char *path); +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define P_BYTES(kb, start) pretty_bytes((kb), (start), (char[16]){0}, 16) + #endif diff --git a/src/cpu.c b/src/cpu.c index 67e56bf..2e9f381 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -14,7 +14,7 @@ void cpu_detect(struct cpu_sensors_t *t, const char *pci_dev) { snprintf(t->hwmon, sizeof(t->hwmon), "/sys/bus/pci/devices/%s/hwmon", pci_dev); const int ret = get_hwmon_dir(t->hwmon); if (ret != 0) { - memset(t->hwmon, '\0', sizeof(t->hwmon)); + t->hwmon[0] = '\0'; applog(LOG_WRN, "Detected %d cores, module enum #%d. Can't get hwmon path, skipping", t->num_cores, t->module); return; } @@ -41,7 +41,7 @@ void cpu_update(struct cpu_sensors_t *c) { clock_gettime(CLOCK_MONOTONIC, &curr.ts); fast_read_num_u64("/sys/class/powercap/intel-rapl:0", "energy_uj", buf, &curr.energy, 1); - c->ptotal = (float)(curr.energy - prev.energy) / (float)((curr.ts.tv_nsec - prev.ts.tv_nsec) / 1000); + c->ptotal = (float)(curr.energy - prev.energy) / (float)timespec_diff_us(&curr.ts, &prev.ts); prev = curr; // lots of reads but still faster than reading /proc/cpuinfo @@ -58,6 +58,11 @@ void cpu_update(struct cpu_sensors_t *c) { if (c->module == unknown) return; + if (c->module == k10temp) { + fast_read_num_i16(c->hwmon, "/temp1_input", buf, &c->tctl, 1000); + fast_read_num_i16(c->hwmon, "/temp3_input", buf, &c->tccd1, 1000); + } + // commented out unused values so its faster if (c->module == zenpower) { fast_read_num_i16(c->hwmon, "/temp1_input", buf, &c->tdie, 1000); @@ -66,10 +71,4 @@ void cpu_update(struct cpu_sensors_t *c) { // utils::fastReadNum<1000>(c->hwmon + "/in1_input", buf, c->vcore); // utils::fastReadNum<1000>(c->hwmon + "/in2_input", buf, c->vsoc); } - - if (c->module == k10temp) { - fast_read_num_i16(c->hwmon, "/temp1_input", buf, &c->tctl, 1000); - fast_read_num_i16(c->hwmon, "/temp3_input", buf, &c->tccd1, 1000); - } - } \ No newline at end of file diff --git a/src/main.c b/src/main.c index ad2f961..c3affdf 100644 --- a/src/main.c +++ b/src/main.c @@ -16,15 +16,6 @@ static constexpr uint16_t refresh_interval_ms = 500; -/* move to utils */ -static void timespec_add_ms(struct timespec *ts, const uint16_t ms) { - ts->tv_nsec += ms * 1000000L; - if (ts->tv_nsec >= 1000000000L) { - ts->tv_sec++; - ts->tv_nsec -= 1000000000L; - } -} - struct control_t { pthread_mutex_t sensors_mtx; pthread_cond_t sensors_ready; @@ -36,8 +27,8 @@ struct sensors_t { double loadavg[3]; struct memory_t ram; struct disk_t home; - // sys::Network net; - // sys::sysSensors sys; + struct network_t net; + struct syssensors_t sys; struct cpu_sensors_t cpu; // gpu::gpuSensors gpu; double hass_state; @@ -52,7 +43,9 @@ static void *sensors_thread(void *arg) { // set up paths for the sensors strcpy(sensors->home.mountpoint, "/home/drath"); + strcpy(sensors->net.device, "enp7s0"); cpu_detect(&sensors->cpu, "0000:00:18.3"); + sys_detect(&sensors->sys, "nct6775.656"); while (control.g_running) { // NOLINT pthread_mutex_lock(&control.sensors_mtx); @@ -61,11 +54,13 @@ static void *sensors_thread(void *arg) { sys_get_time(&sensors->td); sys_get_ram(&sensors->ram); sys_get_disk(&sensors->home); + sys_get_network(&sensors->net); + sys_update_sensors(&sensors->sys); cpu_update(&sensors->cpu); - pthread_cond_signal(&control.sensors_ready); pthread_mutex_unlock(&control.sensors_mtx); + pthread_cond_signal(&control.sensors_ready); timespec_add_ms(&next, refresh_interval_ms); clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, nullptr); @@ -108,9 +103,22 @@ static void *display_thread(void *arg) { pthread_mutex_lock(&control.sensors_mtx); // lock sensor struct pthread_cond_timedwait(&control.sensors_ready, &control.sensors_mtx, &ts); // wait until data ready + const uint16_t avg_fan_speed = (sensors->sys.fan_speed[0] + sensors->sys.fan_speed[1]) / 2; + lcd_writef(&lcd, 0, 0, "%s %s", sensors->td.date, sensors->td.time); lcd_writef(&lcd, 26, 0, "%.2f %.2f %.2f", sensors->loadavg[0], sensors->loadavg[1], sensors->loadavg[2]); + lcd_writef(&lcd, 0, 1, "%d/%d%c", sensors->cpu.tctl, sensors->cpu.tccd1, 0); + lcd_writef(&lcd, 7, 1, "%s", P_BYTES(sensors->ram.used, 0)); + lcd_writef(&lcd, 20, 1, "%d%c", sensors->sys.t_sensor, 0); + + lcd_writef(&lcd, 0, 2, "%.0fW", sensors->cpu.ptotal); + lcd_writef(&lcd, 5, 2, "%dR", avg_fan_speed); + lcd_writef(&lcd, 12, 2, "%c%s %c%s", 3, P_BYTES(sensors->net.upload, 1), 4, P_BYTES(sensors->net.download, 1)); + + lcd_writef(&lcd, 0, 3, "%dMHz", sensors->cpu.avg_freq); + lcd_writef(&lcd, 14, 3, "%c%s", 2, P_BYTES(sensors->home.usage.free, 1)); + pthread_mutex_unlock(&control.sensors_mtx); // unlock sensor struct lcd_flush_buf(&lcd); diff --git a/src/sys.c b/src/sys.c index 95ff63c..03e2171 100644 --- a/src/sys.c +++ b/src/sys.c @@ -1,13 +1,14 @@ -#include "sys.h" - -#include "utils.h" - #include #include #include #include #include +#include "sys.h" +#include "log.h" +#include "utils.h" + + void sys_get_time(struct time_date_t *td) { 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"}; @@ -61,10 +62,29 @@ void sys_get_network(struct network_t* network) { clock_gettime(CLOCK_MONOTONIC, ¤t.ts); fast_read_num_u64(path, "rx_bytes", buf, ¤t.rx, 1); - fast_read_num_u64(path, "tx_bytes", buf, ¤t.rx, 1); - const double ts_diff = (current.ts.tv_sec - prev.ts.tv_sec) + (current.ts.tv_nsec - prev.ts.tv_nsec) / 1000000000.0; - network->download = (current.rx - prev.rx) / ts_diff; - network->upload = (current.tx - prev.tx) / ts_diff; + fast_read_num_u64(path, "tx_bytes", buf, ¤t.tx, 1); + const double diff_s = (double)timespec_diff_us(¤t.ts, &prev.ts) / 1000000.0; + network->download = (uint32_t)((double)(current.rx - prev.rx) / diff_s); + network->upload = (uint32_t)((double)(current.tx - prev.tx) / diff_s); prev = current; +} -} \ No newline at end of file +void sys_detect(struct syssensors_t* s, const char* platform) { + snprintf(s->hwmon, sizeof(s->hwmon), "/sys/devices/platform/%s/hwmon", platform); + const int ret = get_hwmon_dir(s->hwmon); + if (ret != 0) { + s->hwmon[0] = '\0'; + applog(LOG_WRN, "Can't open system hwmon. Kernel params added? Module loaded? See README"); + return; + } + applog(LOG_INF, "Detected system sensors in %s", s->hwmon); +} + +void sys_update_sensors(struct syssensors_t* s) { + if (!s->hwmon[0]) + return; + static char buf[8]; + fast_read_num_u16(s->hwmon, "/fan2_input", buf, &s->fan_speed[0], 1); + fast_read_num_u16(s->hwmon, "/fan7_input", buf, &s->fan_speed[1], 1); + fast_read_num_i16(s->hwmon, "/temp5_input", buf, &s->t_sensor, 1000); +} diff --git a/src/utils.c b/src/utils.c index 0b124a6..1937f04 100644 --- a/src/utils.c +++ b/src/utils.c @@ -4,12 +4,42 @@ #include #include #include +#include +#include #include "log.h" #include "utils.h" #define MKPATH(path, dir, file) do {char *nt = stpcpy(path, dir); *nt++ = '/'; stpcpy(nt, file); } while (0) +inline void timespec_add_ms(struct timespec *ts, const uint16_t ms) { + ts->tv_nsec += ms * 1000000L; + if (ts->tv_nsec >= 1000000000L) { + ts->tv_sec++; + ts->tv_nsec -= 1000000000L; + } +} + +inline uint64_t timespec_diff_us(const struct timespec *a, const struct timespec *b) { + const int64_t sec = a->tv_sec - b->tv_sec; + const int64_t nsec = a->tv_nsec - b->tv_nsec; + return sec * 1000000LL + nsec / 1000LL; +} + +char *pretty_bytes(const uint64_t bytes, int8_t start_suffix, char *buf, const size_t bufsz) { + constexpr char suffix_list[] = {'K', 'M', 'G', 'T', 'P', 'E', 'Z'}; + start_suffix *= -1; + double bytes_d = (double)bytes; + while (bytes_d > 1024.0) { + bytes_d /= 1024.0; + start_suffix++; + } + const uint8_t decimals = (bytes_d < 10) ? 2 : (bytes_d < 100) ? 1 : 0; + snprintf(buf, bufsz, "%.*f%c", decimals, bytes_d, suffix_list[MAX(0, start_suffix)]); + return buf; +} + + inline bool file_exists(const char* path) { return access(path, F_OK) == 0; } @@ -17,10 +47,10 @@ inline bool file_exists(const char* path) { /* path has to have at least 8 free chars at the end for glob */ int get_hwmon_dir(char* path) { glob_t g; - strncat(path, "/hwmon*", 8); + strncat(path, "/hwmon*", 10); if (glob(path, 0, nullptr, &g) == 0) { - strncpy(path, g.gl_pathv[0], 256); + strncpy(path, g.gl_pathv[0], 128); // bug prone, careful globfree(&g); return 0; } @@ -47,6 +77,13 @@ inline void fast_read_num_u64(const char* dir, const char* file, char* buf, uint *result = strtoull(buf, nullptr, 10) / divider; } +inline void fast_read_num_u16(const char* dir, const char* file, char* buf, uint16_t* result, const uint16_t divider) { + char path[256]; + MKPATH(path, dir, file); + read_file(path, buf, 32); + *result = strtol(buf, nullptr, 10) / divider; +} + inline void fast_read_num_i16(const char* dir, const char* file, char* buf, int16_t* result, const uint16_t divider) { char path[256]; MKPATH(path, dir, file);