Плата принимает по USB-CDC строки "T=67.0;L=34" от агента на ПК и рисует крупную цифру, загрузку и график за последнюю минуту на экране 72x40. Пины дисплея (SDA=5, SCL=6) определены сканером, а не по шелкографии: подписи GPIO8/GPIO9 на плате - это дефолтные Wire-пины чипа. Агент читает сенсоры через LibreHardwareMonitorLib. С версии 0.9.5 она требует отдельно установленный драйвер PawnIO: без него загрузка CPU читается, а температуры пусты даже под администратором. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
61 lines
1.4 KiB
C++
61 lines
1.4 KiB
C++
#include "link.h"
|
|
|
|
#include <Arduino.h>
|
|
|
|
static const size_t BUF_SIZE = 64;
|
|
static char buf[BUF_SIZE];
|
|
static size_t len = 0;
|
|
|
|
void linkBegin() {
|
|
Serial.begin(115200);
|
|
len = 0;
|
|
}
|
|
|
|
static bool parseLine(char *line, CpuStats &out) {
|
|
bool haveTemp = false;
|
|
bool haveLoad = false;
|
|
CpuStats parsed = {0.0f, 0};
|
|
|
|
char *save = nullptr;
|
|
for (char *tok = strtok_r(line, ";", &save); tok; tok = strtok_r(nullptr, ";", &save)) {
|
|
char *eq = strchr(tok, '=');
|
|
if (!eq) continue;
|
|
*eq = '\0';
|
|
const char *key = tok;
|
|
const char *val = eq + 1;
|
|
|
|
if (strcmp(key, "T") == 0) {
|
|
parsed.tempC = atof(val);
|
|
haveTemp = true;
|
|
} else if (strcmp(key, "L") == 0) {
|
|
parsed.loadPct = atoi(val);
|
|
haveLoad = true;
|
|
}
|
|
// прочие ключи игнорируются намеренно: протокол расширяемый
|
|
}
|
|
|
|
if (!haveTemp || !haveLoad) return false;
|
|
out = parsed;
|
|
return true;
|
|
}
|
|
|
|
bool linkPoll(CpuStats &out) {
|
|
bool got = false;
|
|
while (Serial.available()) {
|
|
const char c = (char)Serial.read();
|
|
if (c == '\r') continue;
|
|
if (c == '\n') {
|
|
buf[len] = '\0';
|
|
if (len > 0 && parseLine(buf, out)) got = true;
|
|
len = 0;
|
|
continue;
|
|
}
|
|
if (len < BUF_SIZE - 1) {
|
|
buf[len++] = c;
|
|
} else {
|
|
len = 0; // строка длиннее буфера — мусор, начинаем заново
|
|
}
|
|
}
|
|
return got;
|
|
}
|