WiFi/LWIP/netif teardown scatters long-lived allocations across the heap, leaving ~50KB of contiguous space unrecoverable without a reboot. Reboot the SoC on exit from any wifi-using activity to guarantee a clean heap. An RTC_NOINIT flag survives the reboot and tells setup() to skip the boot splash and route the user back where they came from: - File transfer / Calibre / OPDS / Font download -> home - KOReader sync -> currently-open EPUB Activities check WiFi.getMode() before rebooting, so backing out of the network mode menu without joining doesn't trigger a cycle. KOSync also esp_wifi_stop()s after the sync result so the radio is off while the user reads it; full teardown happens at the reboot. ## Additional Context The silent reboot skips the booting splash screen - it visibly looks like a screen refresh. This does cause a disconnection/reconnection blip for developers actively pulling logs over serial, but `pio device monitor` and the like successfully reconnect and feed in the early boot serial. as an example: ``` [256676] [DBG] [ACT] Exiting activity: KOReaderSync [256706] [DBG] [MAIN] Silent restart (target=reader) ESP-ROM:esp32c3-api1-20210207 Build:Feb 7 2021 rst:0xc (RTC_SW_CPU_RST),boot:0xf (SPI_FAST_FLASH_BOOT) Saved PC:0x403872bc SPIWP:0xee mode:DIO, clock div:1 load:0x3fcd72a0,len:0x990 load:0x403cbf10,len:0xac8 load:0x403ce710,len:0x4d28 entry 0x403cbf10 [22] [INF] [MAIN] Hardware detect: X4 [29] [SD] SD card detected [43] [DBG] [CPS] Settings loaded from file [58] [DBG] [KRS] Loaded KOReader credentials for user: jeremydk [69] [DBG] [OPS] Loaded 1 OPDS servers from file [69] [DBG] [UI] Using Lyra theme [70] [DBG] [MAIN] Starting CrossPoint version 1.2.0-dev-detached-bde75787 ... [203] [DBG] [ACT] Entering activity: Reader [211] [DBG] [EBP] Loading ePub: /Halting State - Charles Stross.epub [221] [DBG] [BMC] Loaded cache data: 51 spine, 41 TOC entries [246] [DBG] [CSS] Loaded 41 rules from cache [247] [DBG] [EBP] Loaded ePub: /Halting State - Charles Stross.epub ``` --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _PARTIALLY_
73 lines
2.6 KiB
C++
73 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "NetworkModeSelectionActivity.h"
|
|
#include "activities/Activity.h"
|
|
#include "network/CrossPointWebServer.h"
|
|
|
|
// Web server activity states
|
|
enum class WebServerActivityState {
|
|
MODE_SELECTION, // Choosing between Join Network and Create Hotspot
|
|
WIFI_SELECTION, // WiFi selection subactivity is active (for Join Network mode)
|
|
AP_STARTING, // Starting Access Point mode
|
|
SERVER_RUNNING, // Web server is running and handling requests
|
|
SHUTTING_DOWN // Shutting down server and WiFi
|
|
};
|
|
|
|
/**
|
|
* CrossPointWebServerActivity is the entry point for file transfer functionality.
|
|
* It:
|
|
* - First presents a choice between "Join a Network" (STA), "Connect to Calibre", and "Create Hotspot" (AP)
|
|
* - For STA mode: Launches WifiSelectionActivity to connect to an existing network
|
|
* - For AP mode: Creates an Access Point that clients can connect to
|
|
* - Starts the CrossPointWebServer when connected
|
|
* - Handles client requests in its loop() function
|
|
* - Cleans up the server and shuts down WiFi on exit
|
|
*/
|
|
class CrossPointWebServerActivity final : public Activity {
|
|
WebServerActivityState state = WebServerActivityState::MODE_SELECTION;
|
|
|
|
// Network mode
|
|
NetworkMode networkMode = NetworkMode::JOIN_NETWORK;
|
|
bool isApMode = false;
|
|
|
|
// Web server - owned by this activity
|
|
std::unique_ptr<CrossPointWebServer> webServer;
|
|
|
|
// Server status
|
|
std::string connectedIP;
|
|
std::string connectedSSID; // For STA mode: network name, For AP mode: AP name
|
|
|
|
// Performance monitoring
|
|
unsigned long lastHandleClientTime = 0;
|
|
|
|
// Sustained WiFi-loss tracking; abandon only after WIFI_ABANDON_MS.
|
|
int consecutiveDisconnects = 0;
|
|
unsigned long firstDisconnectAt = 0;
|
|
static constexpr unsigned long WIFI_ABANDON_MS = 5UL * 60UL * 1000UL;
|
|
|
|
// Cached signal-strength bracket (0..4) for the WiFi indicator.
|
|
int lastWifiBars = 0;
|
|
|
|
void renderServerRunning() const;
|
|
void renderWifiIndicator(int subHeaderTop) const;
|
|
|
|
void onNetworkModeSelected(NetworkMode mode);
|
|
void onWifiSelectionComplete(bool connected);
|
|
void startAccessPoint();
|
|
void startWebServer();
|
|
|
|
public:
|
|
explicit CrossPointWebServerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput)
|
|
: Activity("CrossPointWebServer", renderer, mappedInput) {}
|
|
void onEnter() override;
|
|
void onExit() override;
|
|
void loop() override;
|
|
void render(RenderLock&&) override;
|
|
bool skipLoopDelay() override { return webServer && webServer->isRunning(); }
|
|
bool preventAutoSleep() override { return webServer && webServer->isRunning(); }
|
|
};
|