diff --git a/stats-sender/stats_sender.py b/stats-sender/stats_sender.py index 7312fa5..fa7a4b3 100644 --- a/stats-sender/stats_sender.py +++ b/stats-sender/stats_sender.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + import os import struct import sys @@ -8,6 +11,9 @@ import psutil import sensors import serial +should_stop = False +debug = False + structure = [ {'pack': 'I', 'mode': 'magic', 'value': 0xAAAAAAAA}, @@ -78,15 +84,15 @@ def cpu_freq(): def cpu_perc(): - return int(sum(psutil.cpu_percent(percpu=True))) + return int(sum(psutil.cpu_percent(percpu=True)) / psutil.cpu_count()) def cpu_perc_max(): - return 100 * psutil.cpu_count() + return 100 def cpu_perc_kernel(): - return int(cpu_perc() * psutil.cpu_times_percent().system / 100) + return int(psutil.cpu_times_percent().system / 100 * cpu_perc_max()) def cpu_load_avg(): @@ -100,7 +106,7 @@ def ram_perc(): def ram_perc_buffers(): m = psutil.virtual_memory() - return int(m.slab / m.total * 100) + return int(m.inactive / m.total * 100) def ram_used(): @@ -119,7 +125,11 @@ def loop(serial: serial.Serial, hwmon: dict): if item['mode'] == 'magic': struct_data.append(item['value']) elif item['mode'] == 'hwmon': - struct_data.append(int(hwmon[item['driver']][item['feature']].get_value())) + # noinspection PyBroadException + try: + struct_data.append(int(hwmon[item['driver']][item['feature']].get_value())) + except Exception: + struct_data.append(0) else: struct_data.append(globals()[item['mode']]()) @@ -130,21 +140,25 @@ def loop(serial: serial.Serial, hwmon: dict): checkxor ^= byte dto += struct.pack('3}]: ', dto.hex(' '), "\\n") - time.sleep(1) + if debug: + print(f'send[{len(dto) + 1:>3}]: ', dto.hex(' '), "\\n") + + time.sleep(2) def read_serial(s: serial.Serial): - while True: + while not should_stop: line = s.readline(1024) if line.endswith(b'\n'): line = line[:-1] if len(line) > 0: - print(f"recv[{len(line):>3}]: ", line.decode(errors='replace'),) + print(f"recv[{len(line):>3}]: ", line.decode(errors='replace'), ) def main(): + global should_stop + if len(sys.argv) < 2: print(f"Usage: {sys.argv[0]} [tty]") exit(1) @@ -160,10 +174,14 @@ def main(): s = serial.Serial(port=sys.argv[1], baudrate=115200, timeout=0.5) - t = threading.Thread(target=read_serial, args=(s,)) - t.start() + if debug: + t = threading.Thread(target=read_serial, args=(s,)) + t.start() - loop(s, hwmon) + try: + loop(s, hwmon) + finally: + should_stop = True if __name__ == '__main__': diff --git a/stats-viewer/stats-viewer.ino b/stats-viewer/stats-viewer.ino index 8da9165..31833da 100644 --- a/stats-viewer/stats-viewer.ino +++ b/stats-viewer/stats-viewer.ino @@ -2,6 +2,7 @@ #include #include "stats_font1x1.h" #include "stats_font2x2.h" +#include "stats_font4x4.h" #include "glyphs.h" #include "stats_dto.h" @@ -9,19 +10,21 @@ #include #endif -#define DEBUG +//#define DEBUG #ifdef DEBUG #define D #else #define D for(;0;) #endif -#define SCROLL_SPEED 2 +#define SCROLL_SPEED 3 #define NO_DATA_TIMEOUT 5 * 1000 // I²C pins SCL, SDA -#define DISP1_PINS 22, 21 -#define DISP2_PINS 33, 32 +#define DISP1_PINS 27, 26 +#define DISP2_PINS 25, 33 + +#define LID_PIN 18 #define USE_ESP32_I2C_HAL @@ -58,6 +61,7 @@ u8g2_uint_t f1x1h = 8; u8g2_uint_t f2x2h = 16; +u8g2_uint_t f4x4h = 32; char tempLine0Format[] = GLYPH_AMD "%2d" GLYPH_DEGC " " GLYPH_VR_MOS "%2d" GLYPH_DEGC " " @@ -66,7 +70,7 @@ char tempLine0Format[] = GLYPH_AMD "%2d" GLYPH_DEGC " " GLYPH_MOBO "%2d" GLYPH_DEGC " " GLYPH_SSD "%2d" GLYPH_DEGC " "; -char tempLine1Format[] = GLYPH_AMD " %s" GLYPH_HZ " " +char tempLine1Format[] = GLYPH_AMD " %s" GLYPH_HZ " " GLYPH_LOAD " %2d.%02d %4d%%"; @@ -79,7 +83,7 @@ char fansLine0Format[] = GLYPH_AIO "%4d" GLYPH_RPM " " char fansLine1Format[] = GLYPH_RAM " %2d%% %s %4dM" GLYPH_HZ; -char waiting_string[] = "Waiting for data from the computer... "; +char waiting_string[] = " Waiting for data from the computer... "; u8g2_uint_t waiting_width; u8g2_uint_t waiting_offset = 0; @@ -111,7 +115,9 @@ stats_t stats; byte bytes_read = 0; bool stats_ever_received = false; -unsigned long last_received = 0; +unsigned long data_expiration = 0; + +bool lid = 0; bool receiveStats() { @@ -138,6 +144,7 @@ bool receiveStats() { D Serial.println(F(" bytes from serial")); if (bytes_read >= sizeof(stats_t)) { + #ifdef DEBUG char printbuf[100]; sprintf(printbuf, "Received %d bytes, wanted %d == sizeof(stats_t)", bytes_read, sizeof(stats_t)); @@ -151,22 +158,28 @@ bool receiveStats() { Serial.println(F("Check magic start")); #endif + if (stats.magic_start != MAGIC_START) goto invalidate; + D Serial.println(F("Check magic end")); D Serial.println(stats.magic_end, HEX); + if (stats.magic_end != MAGIC_END) goto invalidate; uint8_t checkxor = 0; for (byte *b = (byte *) &stats; b < &(stats.checkxor); b++) { checkxor ^= *b; } - D Serial.println(F("Checking check xor")); - D Serial.print(F("Computed: ")); - D Serial.print(checkxor, HEX); - D Serial.print(F(" at offset ")); - D Serial.println((uint32_t) ((uint32_t) &(stats.checkxor) - ((uint32_t) &stats))); - D Serial.print(F("Got: ")); - D Serial.println(stats.checkxor, HEX); + +#ifdef DEBUG + Serial.println(F("Checking check xor")); + Serial.print(F("Computed: ")); + Serial.print(checkxor, HEX); + Serial.print(F(" at offset ")); + Serial.println((uint32_t) ((uint32_t) &(stats.checkxor) - ((uint32_t) &stats))); + Serial.print(F("Got: ")); + Serial.println(stats.checkxor, HEX); +#endif if (stats.checkxor != checkxor) goto invalidate; @@ -189,9 +202,14 @@ void drawWaitingForData(U8G2 *u8g2, u8g2_uint_t *offset) { u8g2->clearBuffer(); u8g2_uint_t x = *offset; - u8g2->setFont(u8g2_font_helvR18_tf); do { - u8g2->drawStr(x, 26, waiting_string); + u8g2->setCursor(x, 32); + u8g2->setFont(stats_font4x4); + u8g2->print(GLYPH_UNPLUGGED); + + u8g2->setCursor(x + 32, 26); + u8g2->setFont(u8g2_font_helvR18_tf); + u8g2->print(waiting_string); x += waiting_width; } while( x < u8g2->getDisplayWidth() ); @@ -209,7 +227,7 @@ void drawWaitingForDataAllDisplays() { } void format_freq(char *dest, uint16_t value) { - if (value >= 1000) { + if (value < 1000) { sprintf(dest, "%4dM", value); } else { sprintf(dest, "%1d.%03dG", value / 1000, value % 1000); @@ -218,10 +236,11 @@ void format_freq(char *dest, uint16_t value) { void format_bar( char *buffer, uint8_t total_tiles, uint16_t full_perc, uint16_t gray_perc, uint16_t perc_max) { - + memset(buffer, 0, total_tiles + 1); - int32_t gray_tiles = (((int32_t) gray_perc) * 1024) / ((int32_t) perc_max) * total_tiles / 1024; - int32_t full_tiles = (((int32_t) full_perc) * 1024) / ((int32_t) perc_max) * total_tiles / 1024; + int32_t gray_tiles = (int32_t) ((double) (gray_perc+1) / (double) perc_max * total_tiles); + int32_t full_tiles = (int32_t) ((double) (full_perc+1) / (double) perc_max * total_tiles); + int32_t empty_tiles = total_tiles - 2 - gray_tiles - max(full_tiles - 1, 0); // Pick left butt tile if (full_tiles == 1 && gray_tiles == 0) @@ -239,26 +258,26 @@ void format_bar( for (char i = 0; i < full_tiles - 2; i++) strcat(buffer, GLYPH_MID_FULL); - if (full_tiles < total_tiles && gray_tiles == 0) + if (full_tiles > 1 && full_tiles < total_tiles && gray_tiles == 0) strcat(buffer, GLYPH_MID_FULL_END); - else if (gray_tiles > 0) + else if (full_tiles > 0 && gray_tiles > 0) strcat(buffer, GLYPH_MID_FULL); // Draw gray tiles - for (char i = 0; i < full_tiles - 1 - (full_tiles > 0 ? 0 : 1); i++) + for (char i = 0; i < gray_tiles - 1 - (full_tiles > 0 ? 0 : 1); i++) strcat(buffer, GLYPH_MID_GRAY); - if (gray_tiles < total_tiles) + if (gray_tiles > 0 && (full_tiles + gray_tiles) < total_tiles) strcat(buffer, GLYPH_MID_GRAY_END); // Draw empty tiles - for (char i = 0; i < total_tiles - 1 - gray_tiles - full_tiles; i++) + for (char i = 0; i < empty_tiles; i++) strcat(buffer, GLYPH_MID_EMPTY); // Pick right butt tile if (full_tiles == total_tiles) strcat(buffer, GLYPH_BUTT_RIGHT_FULL); - else if (gray_tiles == total_tiles) + else if ((full_tiles + gray_tiles) == total_tiles) strcat(buffer, GLYPH_BUTT_RIGHT_GRAY); else strcat(buffer, GLYPH_BUTT_RIGHT_EMPTY); @@ -292,10 +311,12 @@ void drawStatsPage( } while( x < u8g2->getDisplayWidth() ); // Minibanner - u8g2->setDrawColor(0); - u8g2->drawBox(0, 0, mb_w, mb_h); - u8g2->setDrawColor(1); - u8g2->drawStr(0, f2x2h, minibanner); + if (data_expiration > millis()) { + u8g2->setDrawColor(0); + u8g2->drawBox(0, 0, mb_w, mb_h); + u8g2->setDrawColor(1); + u8g2->drawStr(0, f2x2h, minibanner); + } // Line 1 u8g2->setFont(stats_font1x1); @@ -304,6 +325,15 @@ void drawStatsPage( // Line 2 u8g2->drawStr(0, f2x2h + 2*f1x1h, lines->line2); + // No data maxibanner + if (data_expiration <= millis()) { + u8g2->setFont(stats_font4x4); + u8g2->setDrawColor(0); + u8g2->drawBox(0, 0, 36, 32); + u8g2->setDrawColor(1); + u8g2->drawStr(0, f4x4h, GLYPH_UNPLUGGED); + } + yield(); u8g2->sendBuffer(); @@ -315,7 +345,7 @@ void drawStatsPage( void sprintfStrings() { - uint8_t total_8x8_tiles = u8g2_d1.getDisplayWidth() / 8 - 3; + uint8_t total_8x8_tiles = u8g2_d1.getDisplayWidth() / 8; char tmp_buf[20] = {0}; // Temps page @@ -370,7 +400,16 @@ void displaysTask(void *pvParameters) { Serial.print("Handling displays on core "); Serial.println(xPortGetCoreID()); - while (true) { + while (true) { + bool newLid = digitalRead(LID_PIN); + if (newLid != lid) { + lid = newLid; + u8g2_d1.setPowerSave(!lid); + u8g2_d2.setPowerSave(!lid); + Serial.print(F("LID ")); + Serial.println(lid ? F("OPEN") : F("CLOSED")); + } + if (!stats_ever_received) { drawWaitingForDataAllDisplays(); yield(); @@ -390,15 +429,15 @@ void displaysTask(void *pvParameters) { } void receiverTask(void *pvParameters) { - Serial.print("Handling incoming data on core "); - Serial.println(xPortGetCoreID()); + D Serial.print("Handling incoming data on core "); + D Serial.println(xPortGetCoreID()); while (true) { yield(); if (receiveStats()) { sprintfStrings(); - last_received = millis(); + data_expiration = millis() + NO_DATA_TIMEOUT; stats_ever_received = true; } @@ -413,6 +452,13 @@ void setup() { Serial.begin(115200); Serial.setTimeout(0); + + // Report initial lid state + pinMode(LID_PIN, INPUT_PULLUP); + lid = digitalRead(LID_PIN); + Serial.print(F("LID ")); + Serial.println(lid ? F("OPEN") : F("CLOSED")); + stringsMutex = xSemaphoreCreateMutex(); #ifdef USE_ESP32_I2C_HAL @@ -427,6 +473,10 @@ void setup() { u8g2_d1.setFont(u8g2_font_helvR18_tf); waiting_width = u8g2_d1.getStrWidth(waiting_string); + + u8g2_d1.setFont(stats_font4x4); + waiting_width += u8g2_d1.getStrWidth(GLYPH_UNPLUGGED); + waiting_offset = 0; u8g2_d2.begin(); @@ -446,4 +496,4 @@ void setup() { void loop() { // Avoid task watchdog firing vTaskDelete(NULL); -} \ No newline at end of file +}