Files
MeshCore/test/fixtures/official_web_console/firmware.cpp
T
mikecarper c38ba5f8d0 Make ESP32 OTA startup handle WiFi and WebConfig automatically
Report the upload address and required network, honor AP switches on an existing uploader, and keep delayed WebConfig cleanup from disabling OTA WiFi. Preserve actionable startup errors and account for OTA in wireless state controls.

Exercise the production OTA lifecycle and stock website console, including power-saving idle sessions, in host regression tests.
2026-10-05 10:31:43 -07:00

104 lines
3.9 KiB
C++

// Inserted after the ESP32Board peripheral harness. Peripheral queues/time are
// simulated. @-marked methods below are copied verbatim from production.
#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <deque>
#include <sstream>
#include <string>
struct Stream {
std::deque<uint8_t> input;
std::string output;
int available() { return input.size(); }
int read() { int c = input.front(); input.pop_front(); return c; }
void print(char c) { output += c; }
void print(const char* text) { output += text; }
void println(const char* text) { output += text; output += "\r\n"; }
void printf(const char* format, ...) {
char buffer[256]; va_list args; va_start(args, format);
int n = vsnprintf(buffer, sizeof(buffer), format, args); va_end(args);
assert(n >= 0 && size_t(n) < sizeof(buffer)); output.append(buffer, n);
}
} console;
namespace mesh {
void serviceUsbLoggingPort() {}
void serviceUsbTerminalPort() {}
bool takeUsbTerminalSessionReset() { return false; }
bool tryCompleteUsbTerminalSessionReset() { return true; }
bool canAcceptUsbConsoleCommand() { return true; }
Stream& usbConsolePort() { return console; }
void noteUsbLoggingStatsCommand(const char*) {}
bool isUsbLoggingWatchdogArmed() { return false; }
namespace wireless {
struct Control { bool pending() { return false; } };
Control& control() { static Control value; return value; }
}
}
struct Prefs { uint8_t powersaving_enabled = 0; } prefs;
struct Sensors { void setPowerSavingEnabled(bool) {} } sensors;
struct MyMesh {
Prefs* _prefs = &prefs;
Sensors* _sensors = &sensors;
unsigned saves = 0;
void savePrefs() { ++saves; }
void set(const char* config, char* reply) { @SETTER@ }
void get(const char* config, char* reply) { @GETTER@ }
void handleUsbCommand(const char* command, char* reply) {
if (!strncmp(command, "set ", 4)) set(command + 4, reply);
else if (!strncmp(command, "get ", 4)) get(command + 4, reply);
else strcpy(reply, "Unknown");
}
void cancelPendingSerialOutput() {}
bool hasPendingSerialOutput() { return false; }
Prefs* getNodePrefs() { return _prefs; }
unsigned getPowerSaveSleepSeconds(unsigned limit) { return limit; }
bool millisHasNowPassed(unsigned deadline) { return millis() > deadline; }
} the_mesh;
static ESP32Board board;
static constexpr unsigned POWERSAVING_FIRSTSLEEP_SECS = 120;
static constexpr size_t LOCAL_SERIAL_COMMAND_MAX = 159;
static char command[LOCAL_SERIAL_COMMAND_MAX + 2] = {};
static bool command_overflow = false;
@COMMAND_PUMP@
static void power_loop() { @POWER_LOOP@ }
static void emit() {
if (!console.output.empty()) {
std::cout << "DATA ";
for (uint8_t c : console.output) printf("%02x", c);
std::cout << '\n'; console.output.clear();
}
std::cout << "STATE " << unsigned(prefs.powersaving_enabled) << ' '
<< sleep_calls << ' ' << millis() << '\n';
std::cout << "DONE\n" << std::flush;
}
int main() {
attachHost(true); // The Web Serial port is open, with no DTR/keepalive.
Serial.terminal_open = false;
mesh::logging_enabled = false;
std::string line;
while (std::getline(std::cin, line)) {
if (line.rfind("WRITE ", 0) == 0) {
// A USB peripheral suspended in light sleep cannot deliver new bytes.
if (sleep_calls == 0) {
for (size_t n = 6; n < line.size(); n += 2) {
unsigned byte; assert(n + 1 < line.size());
assert(sscanf(line.c_str() + n, "%2x", &byte) == 1);
console.input.push_back(uint8_t(byte));
}
while (console.available()) serviceCommandInterfaces();
}
} else if (line.rfind("TIME ", 0) == 0) {
mock_millis = std::stoul(line.substr(5)); power_loop();
} else if (line == "CLOSE") {
console.input.clear(); console.output.clear(); command[0] = 0;
} else if (line == "HOST_OFF") {
attachHost(false);
} else { assert(false && "Unknown peripheral operation"); }
emit();
}
}