158 lines
4.4 KiB
C
158 lines
4.4 KiB
C
#include <signal.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include "log.h"
|
|
#include <unistd.h>
|
|
#include <stdatomic.h>
|
|
#include <sys/signalfd.h>
|
|
#include "lcd.h"
|
|
#include "sys.h"
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static constexpr uint16_t refresh_interval_ms = 500;
|
|
|
|
atomic_bool g_running; // if using c11, you need atomic_store() and atomic_load();
|
|
|
|
struct control_t {
|
|
pthread_mutex_t sensors_mtx;
|
|
pthread_cond_t sensors_ready;
|
|
} control;
|
|
|
|
struct sensors_t {
|
|
struct time_date_t 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
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
timespec_add_ms(&ts, (uint16_t)(refresh_interval_ms * 1.25));
|
|
|
|
pthread_mutex_lock(&control.sensors_mtx); // lock sensor struct
|
|
pthread_cond_timedwait(&control.sensors_ready, &control.sensors_mtx, &ts); // wait until data ready
|
|
|
|
lcd_clear_buf(&lcd);
|
|
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_flush_buf(&lcd);
|
|
pthread_mutex_unlock(&control.sensors_mtx); // unlock sensor struct
|
|
}
|
|
|
|
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;
|
|
|
|
struct timespec next;
|
|
clock_gettime(CLOCK_REALTIME, &next);
|
|
|
|
while (g_running) { // NOLINT
|
|
timespec_add_ms(&next, refresh_interval_ms);
|
|
pthread_mutex_lock(&control.sensors_mtx);
|
|
|
|
sys_get_load_avg(sensors->loadavg);
|
|
sys_get_time(&sensors->td);
|
|
|
|
pthread_cond_signal(&control.sensors_ready);
|
|
pthread_mutex_unlock(&control.sensors_mtx);
|
|
|
|
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &next, nullptr);
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
/* init control struct */
|
|
pthread_mutex_init(&control.sensors_mtx, nullptr);
|
|
pthread_cond_init(&control.sensors_ready, nullptr);
|
|
|
|
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;
|
|
} |