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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
.venv
build/
build_prev_runner/
.vscode
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 @@ -101,5 +101,12 @@ If any guard rejects (or times out), the flow is:
- `allow=false`: request is blocked immediately and reboot does not proceed.
- `defer=true`: request is deferred immediately, remaining guards are skipped for the current pass, and evaluation restarts from the first guard after `deferTimeoutMs` (minimum 1ms when omitted/0).

## 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).
30 changes: 15 additions & 15 deletions examples/basic_reboot_request/basic_reboot_request.ino
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,29 @@ void setup() {
rebootManager.onEvaluation([](const RebootEvaluation &evaluation) {
if (evaluation.accepted) {
Serial.printf(
"[reboot] accepted id=%lu reason=%s delay=%lu\n",
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason,
static_cast<unsigned long>(evaluation.delayMs)
);
"[reboot] accepted id=%lu reason=%s delay=%lu\n",
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason,
static_cast<unsigned long>(evaluation.delayMs)
);
return;
}

Serial.printf(
"[reboot] rejected id=%lu code=%u blocker=%s detail=%s\n",
static_cast<unsigned long>(evaluation.requestId),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
"[reboot] rejected id=%lu code=%u blocker=%s detail=%s\n",
static_cast<unsigned long>(evaluation.requestId),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
});

RebootSubmitResult result = rebootManager.requestReboot("ExampleReason", 1500);
Serial.printf(
"submit status=%u requestId=%lu\n",
static_cast<unsigned>(result.status),
static_cast<unsigned long>(result.requestId)
);
"submit status=%u requestId=%lu\n",
static_cast<unsigned>(result.status),
static_cast<unsigned long>(result.requestId)
);
}

void loop() {
Expand Down
32 changes: 14 additions & 18 deletions examples/busy_and_retry/busy_and_retry.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ bool finished = false;

void printSubmitResult(const char *label, const RebootSubmitResult &result) {
Serial.printf(
"%s submit status=%u requestId=%lu\n",
label,
static_cast<unsigned>(result.status),
static_cast<unsigned long>(result.requestId)
);
"%s submit status=%u requestId=%lu\n",
label,
static_cast<unsigned>(result.status),
static_cast<unsigned long>(result.requestId)
);
}

void setup() {
Expand All @@ -25,28 +25,24 @@ void setup() {
ESPRebootManagerConfig config;
config.taskName = "reboot-manager";
config.callbackTimeoutMs = 1000;
config.rebootExecutor = []() {
Serial.println("[executor] simulated reboot");
};
config.rebootExecutor = []() { Serial.println("[executor] simulated reboot"); };

if (!rebootManager.init(config)) {
Serial.println("Failed to init ESPRebootManager");
return;
}

rebootManager.onRebootRequest([](const RebootRequestContext &) {
return RebootVote{};
});
rebootManager.onRebootRequest([](const RebootRequestContext &) { return RebootVote{}; });

rebootManager.onEvaluation([](const RebootEvaluation &evaluation) {
Serial.printf(
"[evaluation] accepted=%u code=%u id=%lu reason=%s delayMs=%lu\n",
static_cast<unsigned>(evaluation.accepted),
static_cast<unsigned>(evaluation.code),
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason,
static_cast<unsigned long>(evaluation.delayMs)
);
"[evaluation] accepted=%u code=%u id=%lu reason=%s delayMs=%lu\n",
static_cast<unsigned>(evaluation.accepted),
static_cast<unsigned>(evaluation.code),
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason,
static_cast<unsigned long>(evaluation.delayMs)
);
});

RebootSubmitResult first = rebootManager.requestReboot("firmware-update", 4000);
Expand Down
22 changes: 11 additions & 11 deletions examples/callback_timeout/callback_timeout.ino
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ void setup() {

rebootManager.onEvaluation([](const RebootEvaluation &evaluation) {
Serial.printf(
"[evaluation] accepted=%u code=%u blocker=%s detail=%s\n",
static_cast<unsigned>(evaluation.accepted),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
"[evaluation] accepted=%u code=%u blocker=%s detail=%s\n",
static_cast<unsigned>(evaluation.accepted),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
});

RebootSubmitResult result = rebootManager.requestReboot("simulate-timeout", 0);
Expand All @@ -57,11 +57,11 @@ void loop() {
if (rebootManager.rebootStatus() == RebootRequestStatus::Idle) {
const RebootEvaluation latest = rebootManager.lastEvaluation();
Serial.printf(
"final accepted=%u code=%u detail=%s\n",
static_cast<unsigned>(latest.accepted),
static_cast<unsigned>(latest.code),
latest.detail
);
"final accepted=%u code=%u detail=%s\n",
static_cast<unsigned>(latest.accepted),
static_cast<unsigned>(latest.code),
latest.detail
);
printedFinal = true;
}

Expand Down
27 changes: 13 additions & 14 deletions examples/guard_blocking/guard_blocking.ino
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ void setup() {
ESPRebootManagerConfig config;
config.taskName = "reboot-manager";
config.callbackTimeoutMs = 1000;
config.rebootExecutor = []() {
Serial.println("[executor] simulated reboot");
};
config.rebootExecutor = []() { Serial.println("[executor] simulated reboot"); };

if (!rebootManager.init(config)) {
Serial.println("Failed to init ESPRebootManager");
Expand All @@ -38,20 +36,20 @@ void setup() {
rebootManager.onEvaluation([](const RebootEvaluation &evaluation) {
if (evaluation.accepted) {
Serial.printf(
"[evaluation] accepted id=%lu reason=%s\n",
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason
);
"[evaluation] accepted id=%lu reason=%s\n",
static_cast<unsigned long>(evaluation.requestId),
evaluation.reason
);
return;
}

Serial.printf(
"[evaluation] rejected id=%lu code=%u blocker=%s detail=%s\n",
static_cast<unsigned long>(evaluation.requestId),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
"[evaluation] rejected id=%lu code=%u blocker=%s detail=%s\n",
static_cast<unsigned long>(evaluation.requestId),
static_cast<unsigned>(evaluation.code),
evaluation.blockerName,
evaluation.detail
);
});

RebootSubmitResult first = rebootManager.requestReboot("scheduled-maintenance", 1000);
Expand All @@ -67,7 +65,8 @@ void loop() {
Serial.println("Maintenance window opened. Retrying reboot request...");
}

if (maintenanceWindowOpen && !secondQueued && rebootManager.rebootStatus() == RebootRequestStatus::Idle) {
if (maintenanceWindowOpen && !secondQueued &&
rebootManager.rebootStatus() == RebootRequestStatus::Idle) {
RebootSubmitResult second = rebootManager.requestReboot("scheduled-maintenance", 1000);
secondQueued = (second.status == RebootSubmitStatus::Queued);
Serial.printf("second submit status=%u\n", static_cast<unsigned>(second.status));
Expand Down
24 changes: 24 additions & 0 deletions scripts/format_cpp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash

set -euo pipefail

_repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
_clang_format="${_repo_root}/.vscode/bin/clang-format"

if [ ! -x "${_clang_format}" ]; then
echo "clang-format wrapper not found: ${_clang_format}" >&2
exit 1
fi

mapfile -d '' _format_files < <(
git -C "${_repo_root}" ls-files -z -- '*.c' '*.cc' '*.cpp' '*.h' '*.hpp' '*.ino'
)

if [ "${#_format_files[@]}" -eq 0 ]; then
echo "No tracked C/C++/INO files found to format."
exit 0
fi

"${_clang_format}" -i --style=file "${_format_files[@]}"

echo "Formatted ${#_format_files[@]} files."
Loading