The main loop rests between passes (#40)

It made 50,000 passes a second and kept core 1 100 % busy at rest. Keys
are buffered by the keyboard controller, the consoles and the radio have
their own tasks, and no Service ticks more often than every 50 ms, so
the loop now rests 5 ms after a pass with the screen on and 20 ms with
it off; never during a serial file transfer. Safe Mode's loop too.

Screen off: 50 passes a second and core 1 at 1 %; screen on: 167 and
10 %. The chip settles 4 C cooler (34.3 against 38.3). GNSS, Gemini, an
upload, the Sweep and the radio's interrupt all checked at the new pace.
`tasks` shows the loop's passes; Debug Builds: `loop spin on|off`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-06 03:08:02 +02:00
co-authored by Claude Opus 5.5
parent 9078ab9c39
commit 06a593293d
3 changed files with 62 additions and 2 deletions
+38 -1
View File
@@ -390,10 +390,17 @@ static std::vector<TaskSample> tasksBefore;
static uint32_t tasksTotal = 0, tasksDueMs = 0;
static bool tasksPending = false;
static uint32_t loopPasses = 0; // counted in loop(), for `tasks` (issue #40)
#ifdef RORO_DEBUG
static bool loopSpin = false; // `loop spin on`: no rest between passes, to compare load and radio noise
#endif
static uint32_t tasksPasses = 0;
static void tasksStep() {
if (!tasksPending || static_cast<int32_t>(millis() - tasksDueMs) < 0) return;
tasksPending = false;
system_info::printTasks(console, tasksBefore, tasksTotal);
console.printf("loop: %lu passes in the last second, chip %.1f C\n", (unsigned long)(loopPasses - tasksPasses), temperatureRead());
std::vector<TaskSample>().swap(tasksBefore);
}
@@ -421,6 +428,7 @@ static const char* const kHelp =
#ifdef RORO_DEBUG
"crash abort|wdt crash on purpose (to test crash reports and Safe Mode)\n"
"wifi ip ... try <seconds> | wifi ip keep a trial IP setting: back to the previous one unless kept\n"
"loop spin on|off make the main loop spin without resting, to compare load and radio noise\n"
"lora inject <hex> [rssi] [snr] a packet into the LoRa Scanner as if received (nothing is sent)\n"
"coredump get (Debug Console only) send the raw core dump: use scripts/rdbg.py coredump\n"
"reset (Debug Console only) restart at once, even if the main loop is stuck\n"
@@ -448,9 +456,16 @@ static void runCommand(String line) {
console.printf("update: %s\n", update->onProbation() ? "on probation" : "confirmed");
system_info::printSlots(console, nvs);
}
#ifdef RORO_DEBUG
if (line == "loop spin on" || line == "loop spin off") {
loopSpin = line.endsWith("on");
console.printf("loop: %s\n", loopSpin ? "spinning, no rest" : "resting between passes");
}
#endif
if (line == "tasks") { // sampled now, printed a second later by tasksStep(): the loop must run in between
tasksTotal = system_info::sampleTasks(tasksBefore);
tasksDueMs = millis() + 1000;
tasksPasses = loopPasses;
tasksPending = true;
}
if (line == "net") { // bytes each service has read and written since boot (S1, Q121)
@@ -778,8 +793,30 @@ static void loopSafeMode() {
delay(10);
}
// How long the main loop rests after a pass (issue #40). Spinning, it made 50,000 passes a
// second and kept core 1 100 % busy for nothing: keys are buffered by the keyboard controller,
// the consoles and the radio have their own tasks, and no Service asks for a tick more often than
// every 50 ms. Shorter with the screen on, so a key or a redraw never waits long.
constexpr uint32_t kLoopRestScreenOnMs = 5;
constexpr uint32_t kLoopRestScreenOffMs = 20;
static void loopPass();
void loop() {
if (safeMode) return loopSafeMode();
loopPasses++;
if (safeMode) {
loopSafeMode();
delay(kLoopRestScreenOnMs);
return;
}
loopPass();
#ifdef RORO_DEBUG
if (loopSpin) return;
#endif
if (upload.active()) return; // a serial file transfer: every byte is read promptly
delay(power->screen() == ScreenState::Off ? kLoopRestScreenOffMs : kLoopRestScreenOnMs);
}
static void loopPass() {
#ifdef RORO_TEST_CRASH
// Test builds only (never in a release): crash during Probation to exercise Rollback.
if (millis() > 5000) abort();