Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
BasedOnStyle: LLVM
ColumnLimit: 100
BinPackArguments: false
BinPackParameters: false
AllowAllArgumentsOnNextLine: false
AlignAfterOpenBracket: BlockIndent
UseTab: ForIndentation
IndentWidth: 4
TabWidth: 4
ContinuationIndentWidth: 4
AllowShortFunctionsOnASingleLine: None
11 changes: 11 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8

[*.{c,cc,cpp,h,hpp,ino}]
indent_style = tab
indent_size = tab
tab_width = 4
19 changes: 19 additions & 0 deletions .vscode/bin/clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

set -euo pipefail

if command -v clang-format >/dev/null 2>&1; then
exec clang-format "$@"
fi

_home_dir="${HOME:-}"
if [ -n "$_home_dir" ]; then
_candidate="$(ls -1d "$_home_dir"/.vscode/extensions/ms-vscode.cpptools-*-linux-x64/LLVM/bin/clang-format 2>/dev/null | tail -n 1 || true)"
if [ -n "$_candidate" ] && [ -x "$_candidate" ]; then
exec "$_candidate" "$@"
fi
fi

echo "clang-format executable not found." >&2
echo "Install clang-format system-wide or install/update ms-vscode.cpptools." >&2
exit 127
9 changes: 9 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"recommendations": [
"pioarduino.pioarduino-ide",
"xaver.clang-format"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}
30 changes: 30 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"files.associations": {
"*.ino": "cpp"
},
"editor.defaultFormatter": "xaver.clang-format",
"C_Cpp.formatting": "Disabled",
"clang-format.style": "file",
"clang-format.executable": "${workspaceRoot}/.vscode/bin/clang-format",
"[cpp]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"editor.formatOnSave": true
},
"[c]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"editor.formatOnSave": true
},
"[arduino]": {
"editor.defaultFormatter": "xaver.clang-format",
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"editor.formatOnSave": true
}
}
12 changes: 12 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Format Firmware Sources",
"type": "shell",
"command": "bash ${workspaceFolder}/scripts/format_cpp.sh",
"group": "build",
"problemMatcher": []
}
]
}
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ When your feature shuts down (task exit, OTA handoff, mode switch), call `cpuMon
## Tests
- Build and run `examples/basic_monitor`, `examples/manual_sampling`, and `examples/json_export` via PlatformIO CI or Arduino CLI for a quick smoke test on ESP32 dev boards.

## Formatting Baseline

This repository follows the firmware formatting baseline from `esptoolkit-template`:
- `.clang-format` is the source of truth for C/C++/INO layout.
- `.editorconfig` enforces tabs (`tab_width = 4`), LF endings, and final newline.
- Format all tracked firmware sources with `bash scripts/format_cpp.sh`.

## License
MIT — see [LICENSE.md](LICENSE.md).

Expand Down
98 changes: 56 additions & 42 deletions examples/basic_monitor/basic_monitor.ino
Original file line number Diff line number Diff line change
@@ -1,58 +1,72 @@
#include <Arduino.h>
#include <ESPCpuMonitor.h>
#include <esp_log.h>
#include <cmath>
#include <esp_log.h>

ESPCpuMonitor cpuMonitor;

void setup() {
Serial.begin(115200);
Serial.begin(115200);

CpuMonitorConfig cfg;
cfg.sampleIntervalMs = 1000; // 1s sampling cadence
cfg.calibrationSamples = 5; // treat first 5 periods as 100% idle baseline
cfg.historySize = 20;
cfg.enableTemperature = true; // toggle temperature readings if your board supports it
cfg.smoothingMode = CpuSmoothingMode::Ewma;
cfg.smoothingAlpha = 0.25f; // smaller alpha => smoother trend
cpuMonitor.init(cfg);
CpuMonitorConfig cfg;
cfg.sampleIntervalMs = 1000; // 1s sampling cadence
cfg.calibrationSamples = 5; // treat first 5 periods as 100% idle baseline
cfg.historySize = 20;
cfg.enableTemperature = true; // toggle temperature readings if your board supports it
cfg.smoothingMode = CpuSmoothingMode::Ewma;
cfg.smoothingAlpha = 0.25f; // smaller alpha => smoother trend
cpuMonitor.init(cfg);

cpuMonitor.onSample([](const CpuUsageSample &sample) {
cpuMonitor.onSample([](const CpuUsageSample &sample) {
#if portNUM_PROCESSORS > 1
ESP_LOGI("CPU", "core0=%.1f%% core1=%.1f%% avg=%.1f%% smoothed=%.1f%% temp=%.1fC (avg %.1fC)",
sample.perCore[0], sample.perCore[1], sample.average,
std::isnan(sample.smoothedAverage) ? -1.0f : sample.smoothedAverage,
std::isnan(sample.temperatureC) ? -1.0f : sample.temperatureC,
std::isnan(sample.temperatureAvgC) ? -1.0f : sample.temperatureAvgC);
ESP_LOGI(
"CPU",
"core0=%.1f%% core1=%.1f%% avg=%.1f%% smoothed=%.1f%% temp=%.1fC (avg %.1fC)",
sample.perCore[0],
sample.perCore[1],
sample.average,
std::isnan(sample.smoothedAverage) ? -1.0f : sample.smoothedAverage,
std::isnan(sample.temperatureC) ? -1.0f : sample.temperatureC,
std::isnan(sample.temperatureAvgC) ? -1.0f : sample.temperatureAvgC
);
#else
ESP_LOGI("CPU", "core0=%.1f%% avg=%.1f%% smoothed=%.1f%% temp=%.1fC (avg %.1fC)",
sample.perCore[0], sample.average,
std::isnan(sample.smoothedAverage) ? -1.0f : sample.smoothedAverage,
std::isnan(sample.temperatureC) ? -1.0f : sample.temperatureC,
std::isnan(sample.temperatureAvgC) ? -1.0f : sample.temperatureAvgC);
ESP_LOGI(
"CPU",
"core0=%.1f%% avg=%.1f%% smoothed=%.1f%% temp=%.1fC (avg %.1fC)",
sample.perCore[0],
sample.average,
std::isnan(sample.smoothedAverage) ? -1.0f : sample.smoothedAverage,
std::isnan(sample.temperatureC) ? -1.0f : sample.temperatureC,
std::isnan(sample.temperatureAvgC) ? -1.0f : sample.temperatureAvgC
);
#endif
});
});
}

void loop() {
// Optional: pull the latest average every few seconds for a quick check
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 3000) {
lastPrint = millis();
float avg = cpuMonitor.getLastAverage();
float smoothed = cpuMonitor.getLastSmoothedAverage();
if (avg >= 0.0f) {
float temp = 0.0f;
float tempAvg = 0.0f;
if (cpuMonitor.getLastTemperature(temp, tempAvg)) {
Serial.printf("[loop] CPU avg: %.1f%% smoothed: %.1f%% temp: %.1fC (avg %.1fC)\n",
avg, smoothed, temp, tempAvg);
} else {
Serial.printf("[loop] CPU avg: %.1f%% smoothed: %.1f%% temp: n/a\n", avg, smoothed);
}
} else {
Serial.println("[loop] calibrating...");
}
}
delay(250);
// Optional: pull the latest average every few seconds for a quick check
static uint32_t lastPrint = 0;
if (millis() - lastPrint > 3000) {
lastPrint = millis();
float avg = cpuMonitor.getLastAverage();
float smoothed = cpuMonitor.getLastSmoothedAverage();
if (avg >= 0.0f) {
float temp = 0.0f;
float tempAvg = 0.0f;
if (cpuMonitor.getLastTemperature(temp, tempAvg)) {
Serial.printf(
"[loop] CPU avg: %.1f%% smoothed: %.1f%% temp: %.1fC (avg %.1fC)\n",
avg,
smoothed,
temp,
tempAvg
);
} else {
Serial.printf("[loop] CPU avg: %.1f%% smoothed: %.1f%% temp: n/a\n", avg, smoothed);
}
} else {
Serial.println("[loop] calibrating...");
}
}
delay(250);
}
71 changes: 37 additions & 34 deletions examples/json_export/json_export.ino
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,44 @@ ESPCpuMonitor cpuMonitor;
static const uint32_t HISTORY_LOG_PERIOD_MS = 5000;

void setup() {
Serial.begin(115200);

CpuMonitorConfig cfg;
cfg.sampleIntervalMs = 1000; // 1s cadence for telemetry
cfg.historySize = 12; // keep a handful of points for charts/debug
cfg.enableTemperature = true;
cfg.smoothingMode = CpuSmoothingMode::Ewma;
cfg.smoothingAlpha = 0.2f;
cpuMonitor.init(cfg);

cpuMonitor.onSample([](const CpuUsageSample &sample) {
StaticJsonDocument<256> doc;
cpuMonitor.toJson(sample, doc);
doc["avgRounded"] = static_cast<int>(roundf(sample.average)); // handy for dashboards

serializeJson(doc, Serial);
Serial.println(); // newline-delimited JSON (NDJSON) stream
});
Serial.begin(115200);

CpuMonitorConfig cfg;
cfg.sampleIntervalMs = 1000; // 1s cadence for telemetry
cfg.historySize = 12; // keep a handful of points for charts/debug
cfg.enableTemperature = true;
cfg.smoothingMode = CpuSmoothingMode::Ewma;
cfg.smoothingAlpha = 0.2f;
cpuMonitor.init(cfg);

cpuMonitor.onSample([](const CpuUsageSample &sample) {
StaticJsonDocument<256> doc;
cpuMonitor.toJson(sample, doc);
doc["avgRounded"] = static_cast<int>(roundf(sample.average)); // handy for dashboards

serializeJson(doc, Serial);
Serial.println(); // newline-delimited JSON (NDJSON) stream
});
}

void loop() {
static uint32_t lastHistoryMs = 0;

if (cpuMonitor.isReady() && millis() - lastHistoryMs >= HISTORY_LOG_PERIOD_MS) {
lastHistoryMs = millis();
const auto hist = cpuMonitor.history();
if (!hist.empty()) {
const auto &latest = hist.back();
Serial.printf("[json_export] history_depth=%u last_avg=%.1f%% last_smoothed=%.1f%% last_temp=%.1fC\n",
static_cast<unsigned>(hist.size()),
latest.average,
std::isnan(latest.smoothedAverage) ? -1.0f : latest.smoothedAverage,
std::isnan(latest.temperatureC) ? -1.0f : latest.temperatureC);
}
}

delay(50);
static uint32_t lastHistoryMs = 0;

if (cpuMonitor.isReady() && millis() - lastHistoryMs >= HISTORY_LOG_PERIOD_MS) {
lastHistoryMs = millis();
const auto hist = cpuMonitor.history();
if (!hist.empty()) {
const auto &latest = hist.back();
Serial.printf(
"[json_export] history_depth=%u last_avg=%.1f%% last_smoothed=%.1f%% "
"last_temp=%.1fC\n",
static_cast<unsigned>(hist.size()),
latest.average,
std::isnan(latest.smoothedAverage) ? -1.0f : latest.smoothedAverage,
std::isnan(latest.temperatureC) ? -1.0f : latest.temperatureC
);
}
}

delay(50);
}
Loading