Refactor layout of activities
This commit is contained in:
parent
e2dab0d811
commit
804db098d1
@ -6,7 +6,7 @@
|
||||
#include "config.h"
|
||||
|
||||
namespace {
|
||||
constexpr int menuItemCount = 2;
|
||||
constexpr int menuItemCount = 3;
|
||||
}
|
||||
|
||||
void HomeActivity::taskTrampoline(void* param) {
|
||||
@ -51,6 +51,8 @@ void HomeActivity::loop() {
|
||||
if (selectorIndex == 0) {
|
||||
onReaderOpen();
|
||||
} else if (selectorIndex == 1) {
|
||||
onFileTransferOpen();
|
||||
} else if (selectorIndex == 2) {
|
||||
onSettingsOpen();
|
||||
}
|
||||
} else if (prevPressed) {
|
||||
@ -84,7 +86,8 @@ void HomeActivity::render() const {
|
||||
// Draw selection
|
||||
renderer.fillRect(0, 60 + selectorIndex * 30 + 2, pageWidth - 1, 30);
|
||||
renderer.drawText(UI_FONT_ID, 20, 60, "Read", selectorIndex != 0);
|
||||
renderer.drawText(UI_FONT_ID, 20, 90, "Settings", selectorIndex != 1);
|
||||
renderer.drawText(UI_FONT_ID, 20, 90, "File transfer", selectorIndex != 1);
|
||||
renderer.drawText(UI_FONT_ID, 20, 120, "Settings", selectorIndex != 2);
|
||||
|
||||
renderer.drawRect(25, pageHeight - 40, 106, 40);
|
||||
renderer.drawText(UI_FONT_ID, 25 + (105 - renderer.getTextWidth(UI_FONT_ID, "Back")) / 2, pageHeight - 35, "Back");
|
||||
|
||||
@ -14,6 +14,7 @@ class HomeActivity final : public Activity {
|
||||
bool updateRequired = false;
|
||||
const std::function<void()> onReaderOpen;
|
||||
const std::function<void()> onSettingsOpen;
|
||||
const std::function<void()> onFileTransferOpen;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
@ -21,8 +22,8 @@ class HomeActivity final : public Activity {
|
||||
|
||||
public:
|
||||
explicit HomeActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onReaderOpen,
|
||||
const std::function<void()>& onSettingsOpen)
|
||||
: Activity(renderer, inputManager), onReaderOpen(onReaderOpen), onSettingsOpen(onSettingsOpen) {}
|
||||
const std::function<void()>& onSettingsOpen, const std::function<void()>& onFileTransferOpen)
|
||||
: Activity(renderer, inputManager), onReaderOpen(onReaderOpen), onSettingsOpen(onSettingsOpen), onFileTransferOpen(onFileTransferOpen) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
234
src/activities/network/CrossPointWebServerActivity.cpp
Normal file
234
src/activities/network/CrossPointWebServerActivity.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
#include "CrossPointWebServerActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include "CrossPointWebServer.h"
|
||||
#include "config.h"
|
||||
|
||||
void CrossPointWebServerActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<CrossPointWebServerActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::onEnter() {
|
||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onEnter ==========\n", millis());
|
||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
|
||||
// Reset state
|
||||
state = WebServerActivityState::WIFI_SELECTION;
|
||||
connectedIP.clear();
|
||||
connectedSSID.clear();
|
||||
lastHandleClientTime = 0;
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&CrossPointWebServerActivity::taskTrampoline, "WebServerActivityTask",
|
||||
2048, // Stack size
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
&displayTaskHandle // Task handle
|
||||
);
|
||||
|
||||
// Turn on WiFi immediately
|
||||
Serial.printf("[%lu] [WEBACT] Turning on WiFi...\n", millis());
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Launch WiFi selection subactivity
|
||||
Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis());
|
||||
wifiSelection.reset(new WifiSelectionActivity(renderer, inputManager, [this](bool connected) {
|
||||
onWifiSelectionComplete(connected);
|
||||
}));
|
||||
wifiSelection->onEnter();
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::onExit() {
|
||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onExit START ==========\n", millis());
|
||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
state = WebServerActivityState::SHUTTING_DOWN;
|
||||
|
||||
// Stop the web server first (before disconnecting WiFi)
|
||||
stopWebServer();
|
||||
|
||||
// Exit WiFi selection subactivity if still active
|
||||
if (wifiSelection) {
|
||||
Serial.printf("[%lu] [WEBACT] Exiting WifiSelectionActivity...\n", millis());
|
||||
wifiSelection->onExit();
|
||||
wifiSelection.reset();
|
||||
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity exited\n", millis());
|
||||
}
|
||||
|
||||
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
||||
Serial.printf("[%lu] [WEBACT] Waiting 500ms for network stack to flush pending packets...\n", millis());
|
||||
delay(500);
|
||||
|
||||
// Disconnect WiFi gracefully
|
||||
Serial.printf("[%lu] [WEBACT] Disconnecting WiFi (graceful)...\n", millis());
|
||||
WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame
|
||||
delay(100); // Allow disconnect frame to be sent
|
||||
|
||||
Serial.printf("[%lu] [WEBACT] Setting WiFi mode OFF...\n", millis());
|
||||
WiFi.mode(WIFI_OFF);
|
||||
delay(100); // Allow WiFi hardware to fully power down
|
||||
|
||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap after WiFi disconnect: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
// Acquire mutex before deleting task
|
||||
Serial.printf("[%lu] [WEBACT] Acquiring rendering mutex before task deletion...\n", millis());
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
|
||||
// Delete the display task
|
||||
Serial.printf("[%lu] [WEBACT] Deleting display task...\n", millis());
|
||||
if (displayTaskHandle) {
|
||||
vTaskDelete(displayTaskHandle);
|
||||
displayTaskHandle = nullptr;
|
||||
Serial.printf("[%lu] [WEBACT] Display task deleted\n", millis());
|
||||
}
|
||||
|
||||
// Delete the mutex
|
||||
Serial.printf("[%lu] [WEBACT] Deleting mutex...\n", millis());
|
||||
vSemaphoreDelete(renderingMutex);
|
||||
renderingMutex = nullptr;
|
||||
Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis());
|
||||
|
||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
Serial.printf("[%lu] [WEBACT] ========== CrossPointWebServerActivity onExit COMPLETE ==========\n", millis());
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::onWifiSelectionComplete(bool connected) {
|
||||
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected);
|
||||
|
||||
if (connected) {
|
||||
// Get connection info before exiting subactivity
|
||||
connectedIP = wifiSelection->getConnectedIP();
|
||||
connectedSSID = WiFi.SSID().c_str();
|
||||
|
||||
// Exit the wifi selection subactivity
|
||||
wifiSelection->onExit();
|
||||
wifiSelection.reset();
|
||||
|
||||
// Start the web server
|
||||
startWebServer();
|
||||
} else {
|
||||
// User cancelled - go back
|
||||
onGoBack();
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::startWebServer() {
|
||||
Serial.printf("[%lu] [WEBACT] Starting web server...\n", millis());
|
||||
|
||||
crossPointWebServer.begin();
|
||||
|
||||
if (crossPointWebServer.isRunning()) {
|
||||
state = WebServerActivityState::SERVER_RUNNING;
|
||||
Serial.printf("[%lu] [WEBACT] Web server started successfully\n", millis());
|
||||
|
||||
// Force an immediate render since we're transitioning from a subactivity
|
||||
// that had its own rendering task. We need to make sure our display is shown.
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
render();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
Serial.printf("[%lu] [WEBACT] Rendered File Transfer screen\n", millis());
|
||||
} else {
|
||||
Serial.printf("[%lu] [WEBACT] ERROR: Failed to start web server!\n", millis());
|
||||
// Go back on error
|
||||
onGoBack();
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::stopWebServer() {
|
||||
if (crossPointWebServer.isRunning()) {
|
||||
Serial.printf("[%lu] [WEBACT] Stopping web server...\n", millis());
|
||||
crossPointWebServer.stop();
|
||||
Serial.printf("[%lu] [WEBACT] Web server stopped\n", millis());
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::loop() {
|
||||
// Handle different states
|
||||
switch (state) {
|
||||
case WebServerActivityState::WIFI_SELECTION:
|
||||
// Forward loop to WiFi selection subactivity
|
||||
if (wifiSelection) {
|
||||
wifiSelection->loop();
|
||||
}
|
||||
break;
|
||||
|
||||
case WebServerActivityState::SERVER_RUNNING:
|
||||
// Handle web server requests
|
||||
if (crossPointWebServer.isRunning()) {
|
||||
unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime;
|
||||
|
||||
// Log if there's a significant gap between handleClient calls (>100ms)
|
||||
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
||||
Serial.printf("[%lu] [WEBACT] WARNING: %lu ms gap since last handleClient\n", millis(),
|
||||
timeSinceLastHandleClient);
|
||||
}
|
||||
|
||||
crossPointWebServer.handleClient();
|
||||
lastHandleClientTime = millis();
|
||||
}
|
||||
|
||||
// Handle exit on Back button
|
||||
if (inputManager.wasPressed(InputManager::BTN_BACK)) {
|
||||
onGoBack();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WebServerActivityState::SHUTTING_DOWN:
|
||||
// Do nothing - waiting for cleanup
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) {
|
||||
updateRequired = false;
|
||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||
render();
|
||||
xSemaphoreGive(renderingMutex);
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::render() const {
|
||||
// Only render our own UI when server is running
|
||||
// WiFi selection handles its own rendering
|
||||
if (state == WebServerActivityState::SERVER_RUNNING) {
|
||||
renderer.clearScreen();
|
||||
renderServerRunning();
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void CrossPointWebServerActivity::renderServerRunning() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
const auto top = (pageHeight - height * 5) / 2;
|
||||
|
||||
renderer.drawCenteredText(READER_FONT_ID, top - 30, "File Transfer", true, BOLD);
|
||||
|
||||
std::string ssidInfo = "Network: " + connectedSSID;
|
||||
if (ssidInfo.length() > 28) {
|
||||
ssidInfo = ssidInfo.substr(0, 25) + "...";
|
||||
}
|
||||
renderer.drawCenteredText(UI_FONT_ID, top + 10, ssidInfo.c_str(), true, REGULAR);
|
||||
|
||||
std::string ipInfo = "IP Address: " + connectedIP;
|
||||
renderer.drawCenteredText(UI_FONT_ID, top + 40, ipInfo.c_str(), true, REGULAR);
|
||||
|
||||
// Show web server URL prominently
|
||||
std::string webInfo = "http://" + connectedIP + "/";
|
||||
renderer.drawCenteredText(UI_FONT_ID, top + 70, webInfo.c_str(), true, BOLD);
|
||||
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, top + 110, "Open this URL in your browser", true, REGULAR);
|
||||
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press BACK to exit", true, REGULAR);
|
||||
}
|
||||
61
src/activities/network/CrossPointWebServerActivity.h
Normal file
61
src/activities/network/CrossPointWebServerActivity.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "../Activity.h"
|
||||
#include "WifiSelectionActivity.h"
|
||||
|
||||
// Web server activity states
|
||||
enum class WebServerActivityState {
|
||||
WIFI_SELECTION, // WiFi selection subactivity is active
|
||||
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:
|
||||
* - Immediately turns on WiFi and launches WifiSelectionActivity on enter
|
||||
* - When WifiSelectionActivity completes successfully, starts the CrossPointWebServer
|
||||
* - Handles client requests in its loop() function
|
||||
* - Cleans up the server and shuts down WiFi on exit
|
||||
*/
|
||||
class CrossPointWebServerActivity final : public Activity {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
bool updateRequired = false;
|
||||
WebServerActivityState state = WebServerActivityState::WIFI_SELECTION;
|
||||
const std::function<void()> onGoBack;
|
||||
|
||||
// WiFi selection subactivity
|
||||
std::unique_ptr<WifiSelectionActivity> wifiSelection;
|
||||
|
||||
// Server status
|
||||
std::string connectedIP;
|
||||
std::string connectedSSID;
|
||||
|
||||
// Performance monitoring
|
||||
unsigned long lastHandleClientTime = 0;
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
void renderServerRunning() const;
|
||||
|
||||
void onWifiSelectionComplete(bool connected);
|
||||
void startWebServer();
|
||||
void stopWebServer();
|
||||
|
||||
public:
|
||||
explicit CrossPointWebServerActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||
const std::function<void()>& onGoBack)
|
||||
: Activity(renderer, inputManager), onGoBack(onGoBack) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
};
|
||||
@ -1,20 +1,19 @@
|
||||
#include "WifiScreen.h"
|
||||
#include "WifiSelectionActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "CrossPointWebServer.h"
|
||||
#include "WifiCredentialStore.h"
|
||||
#include "config.h"
|
||||
|
||||
void WifiScreen::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<WifiScreen*>(param);
|
||||
void WifiSelectionActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<WifiSelectionActivity*>(param);
|
||||
self->displayTaskLoop();
|
||||
}
|
||||
|
||||
void WifiScreen::onEnter() {
|
||||
void WifiSelectionActivity::onEnter() {
|
||||
renderingMutex = xSemaphoreCreateMutex();
|
||||
|
||||
// Load saved WiFi credentials
|
||||
@ -23,7 +22,7 @@ void WifiScreen::onEnter() {
|
||||
// Reset state
|
||||
selectedNetworkIndex = 0;
|
||||
networks.clear();
|
||||
state = WifiScreenState::SCANNING;
|
||||
state = WifiSelectionState::SCANNING;
|
||||
selectedSSID.clear();
|
||||
connectedIP.clear();
|
||||
connectionError.clear();
|
||||
@ -36,7 +35,7 @@ void WifiScreen::onEnter() {
|
||||
// Trigger first update to show scanning message
|
||||
updateRequired = true;
|
||||
|
||||
xTaskCreate(&WifiScreen::taskTrampoline, "WifiScreenTask",
|
||||
xTaskCreate(&WifiSelectionActivity::taskTrampoline, "WifiSelectionTask",
|
||||
4096, // Stack size (larger for WiFi operations)
|
||||
this, // Parameters
|
||||
1, // Priority
|
||||
@ -47,8 +46,8 @@ void WifiScreen::onEnter() {
|
||||
startWifiScan();
|
||||
}
|
||||
|
||||
void WifiScreen::onExit() {
|
||||
Serial.printf("[%lu] [WIFI] ========== onExit START ==========\n", millis());
|
||||
void WifiSelectionActivity::onExit() {
|
||||
Serial.printf("[%lu] [WIFI] ========== WifiSelectionActivity onExit START ==========\n", millis());
|
||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
// Stop any ongoing WiFi scan
|
||||
@ -56,28 +55,8 @@ void WifiScreen::onExit() {
|
||||
WiFi.scanDelete();
|
||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
|
||||
// CRITICAL: Stop the web server FIRST to prevent new packets from being queued
|
||||
Serial.printf("[%lu] [WIFI] Stopping web server...\n", millis());
|
||||
crossPointWebServer.stop();
|
||||
Serial.printf("[%lu] [WIFI] Web server stopped successfully\n", millis());
|
||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap after webserver stop: %d bytes\n", millis());
|
||||
|
||||
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
||||
// The crash occurs because WiFi.disconnect() tears down the interface while
|
||||
// packets are still queued in the LWIP stack (ethernet.c, etharp.c, wlanif.c)
|
||||
Serial.printf("[%lu] [WIFI] Waiting 500ms for network stack to flush pending packets...\n", millis());
|
||||
delay(500);
|
||||
|
||||
// Disconnect WiFi gracefully - use disconnect(false) first to send disconnect frame
|
||||
Serial.printf("[%lu] [WIFI] Disconnecting WiFi (graceful)...\n", millis());
|
||||
WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame
|
||||
delay(100); // Allow disconnect frame to be sent
|
||||
|
||||
Serial.printf("[%lu] [WIFI] Setting WiFi mode OFF...\n", millis());
|
||||
WiFi.mode(WIFI_OFF);
|
||||
delay(100); // Allow WiFi hardware to fully power down
|
||||
|
||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap after WiFi disconnect: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
// Note: We do NOT disconnect WiFi here - the parent activity (CrossPointWebServerActivity)
|
||||
// manages WiFi connection state. We just clean up the scan and task.
|
||||
|
||||
// Acquire mutex before deleting task to ensure task isn't using it
|
||||
// This prevents hangs/crashes if the task holds the mutex when deleted
|
||||
@ -99,11 +78,11 @@ void WifiScreen::onExit() {
|
||||
Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis());
|
||||
|
||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||
Serial.printf("[%lu] [WIFI] ========== onExit COMPLETE ==========\n", millis());
|
||||
Serial.printf("[%lu] [WIFI] ========== WifiSelectionActivity onExit COMPLETE ==========\n", millis());
|
||||
}
|
||||
|
||||
void WifiScreen::startWifiScan() {
|
||||
state = WifiScreenState::SCANNING;
|
||||
void WifiSelectionActivity::startWifiScan() {
|
||||
state = WifiSelectionState::SCANNING;
|
||||
networks.clear();
|
||||
updateRequired = true;
|
||||
|
||||
@ -116,7 +95,7 @@ void WifiScreen::startWifiScan() {
|
||||
WiFi.scanNetworks(true); // true = async scan
|
||||
}
|
||||
|
||||
void WifiScreen::processWifiScanResults() {
|
||||
void WifiSelectionActivity::processWifiScanResults() {
|
||||
int16_t scanResult = WiFi.scanComplete();
|
||||
|
||||
if (scanResult == WIFI_SCAN_RUNNING) {
|
||||
@ -125,7 +104,7 @@ void WifiScreen::processWifiScanResults() {
|
||||
}
|
||||
|
||||
if (scanResult == WIFI_SCAN_FAILED) {
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
@ -167,12 +146,12 @@ void WifiScreen::processWifiScanResults() {
|
||||
[](const WifiNetworkInfo& a, const WifiNetworkInfo& b) { return a.rssi > b.rssi; });
|
||||
|
||||
WiFi.scanDelete();
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
selectedNetworkIndex = 0;
|
||||
updateRequired = true;
|
||||
}
|
||||
|
||||
void WifiScreen::selectNetwork(int index) {
|
||||
void WifiSelectionActivity::selectNetwork(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(networks.size())) {
|
||||
return;
|
||||
}
|
||||
@ -197,7 +176,7 @@ void WifiScreen::selectNetwork(int index) {
|
||||
|
||||
if (selectedRequiresPassword) {
|
||||
// Show password entry
|
||||
state = WifiScreenState::PASSWORD_ENTRY;
|
||||
state = WifiSelectionState::PASSWORD_ENTRY;
|
||||
keyboard.reset(new KeyboardEntryActivity(renderer, inputManager, "Enter WiFi Password",
|
||||
"", // No initial text
|
||||
64, // Max password length
|
||||
@ -210,8 +189,8 @@ void WifiScreen::selectNetwork(int index) {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::attemptConnection() {
|
||||
state = WifiScreenState::CONNECTING;
|
||||
void WifiSelectionActivity::attemptConnection() {
|
||||
state = WifiSelectionState::CONNECTING;
|
||||
connectionStartTime = millis();
|
||||
connectedIP.clear();
|
||||
connectionError.clear();
|
||||
@ -231,8 +210,8 @@ void WifiScreen::attemptConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::checkConnectionStatus() {
|
||||
if (state != WifiScreenState::CONNECTING) {
|
||||
void WifiSelectionActivity::checkConnectionStatus() {
|
||||
if (state != WifiSelectionState::CONNECTING) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -245,18 +224,17 @@ void WifiScreen::checkConnectionStatus() {
|
||||
snprintf(ipStr, sizeof(ipStr), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
||||
connectedIP = ipStr;
|
||||
|
||||
// Start the web server
|
||||
crossPointWebServer.begin();
|
||||
|
||||
// If we used a saved password, go directly to connected screen
|
||||
// If we entered a new password, ask if user wants to save it
|
||||
if (usedSavedPassword || enteredPassword.empty()) {
|
||||
state = WifiScreenState::CONNECTED;
|
||||
} else {
|
||||
state = WifiScreenState::SAVE_PROMPT;
|
||||
// Otherwise, immediately complete so parent can start web server
|
||||
if (!usedSavedPassword && !enteredPassword.empty()) {
|
||||
state = WifiSelectionState::SAVE_PROMPT;
|
||||
savePromptSelection = 0; // Default to "Yes"
|
||||
}
|
||||
updateRequired = true;
|
||||
} else {
|
||||
// Using saved password or open network - complete immediately
|
||||
Serial.printf("[%lu] [WIFI] Connected with saved/open credentials, completing immediately\n", millis());
|
||||
onComplete(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -265,7 +243,7 @@ void WifiScreen::checkConnectionStatus() {
|
||||
if (status == WL_NO_SSID_AVAIL) {
|
||||
connectionError = "Network not found";
|
||||
}
|
||||
state = WifiScreenState::CONNECTION_FAILED;
|
||||
state = WifiSelectionState::CONNECTION_FAILED;
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
@ -274,27 +252,27 @@ void WifiScreen::checkConnectionStatus() {
|
||||
if (millis() - connectionStartTime > CONNECTION_TIMEOUT_MS) {
|
||||
WiFi.disconnect();
|
||||
connectionError = "Connection timeout";
|
||||
state = WifiScreenState::CONNECTION_FAILED;
|
||||
state = WifiSelectionState::CONNECTION_FAILED;
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::loop() {
|
||||
void WifiSelectionActivity::loop() {
|
||||
// Check scan progress
|
||||
if (state == WifiScreenState::SCANNING) {
|
||||
if (state == WifiSelectionState::SCANNING) {
|
||||
processWifiScanResults();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check connection progress
|
||||
if (state == WifiScreenState::CONNECTING) {
|
||||
if (state == WifiSelectionState::CONNECTING) {
|
||||
checkConnectionStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle password entry state
|
||||
if (state == WifiScreenState::PASSWORD_ENTRY && keyboard) {
|
||||
if (state == WifiSelectionState::PASSWORD_ENTRY && keyboard) {
|
||||
keyboard->handleInput();
|
||||
|
||||
if (keyboard->isComplete()) {
|
||||
@ -303,7 +281,7 @@ void WifiScreen::loop() {
|
||||
}
|
||||
|
||||
if (keyboard->isCancelled()) {
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
keyboard.reset();
|
||||
updateRequired = true;
|
||||
return;
|
||||
@ -314,7 +292,7 @@ void WifiScreen::loop() {
|
||||
}
|
||||
|
||||
// Handle save prompt state
|
||||
if (state == WifiScreenState::SAVE_PROMPT) {
|
||||
if (state == WifiSelectionState::SAVE_PROMPT) {
|
||||
if (inputManager.wasPressed(InputManager::BTN_LEFT) || inputManager.wasPressed(InputManager::BTN_UP)) {
|
||||
if (savePromptSelection > 0) {
|
||||
savePromptSelection--;
|
||||
@ -330,19 +308,17 @@ void WifiScreen::loop() {
|
||||
// User chose "Yes" - save the password
|
||||
WIFI_STORE.addCredential(selectedSSID, enteredPassword);
|
||||
}
|
||||
// Move to connected screen
|
||||
state = WifiScreenState::CONNECTED;
|
||||
updateRequired = true;
|
||||
// Complete - parent will start web server
|
||||
onComplete(true);
|
||||
} else if (inputManager.wasPressed(InputManager::BTN_BACK)) {
|
||||
// Skip saving, go to connected screen
|
||||
state = WifiScreenState::CONNECTED;
|
||||
updateRequired = true;
|
||||
// Skip saving, complete anyway
|
||||
onComplete(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle forget prompt state (connection failed with saved credentials)
|
||||
if (state == WifiScreenState::FORGET_PROMPT) {
|
||||
if (state == WifiSelectionState::FORGET_PROMPT) {
|
||||
if (inputManager.wasPressed(InputManager::BTN_LEFT) || inputManager.wasPressed(InputManager::BTN_UP)) {
|
||||
if (forgetPromptSelection > 0) {
|
||||
forgetPromptSelection--;
|
||||
@ -366,35 +342,33 @@ void WifiScreen::loop() {
|
||||
}
|
||||
}
|
||||
// Go back to network list
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
updateRequired = true;
|
||||
} else if (inputManager.wasPressed(InputManager::BTN_BACK)) {
|
||||
// Skip forgetting, go back to network list
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
updateRequired = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle connected state
|
||||
if (state == WifiScreenState::CONNECTED) {
|
||||
if (inputManager.wasPressed(InputManager::BTN_BACK) || inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||
// Exit screen on success
|
||||
onGoBack();
|
||||
// Handle connected state (should not normally be reached - connection completes immediately)
|
||||
if (state == WifiSelectionState::CONNECTED) {
|
||||
// Safety fallback - immediately complete
|
||||
onComplete(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle connection failed state
|
||||
if (state == WifiScreenState::CONNECTION_FAILED) {
|
||||
if (state == WifiSelectionState::CONNECTION_FAILED) {
|
||||
if (inputManager.wasPressed(InputManager::BTN_BACK) || inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||
// If we used saved credentials, offer to forget the network
|
||||
if (usedSavedPassword) {
|
||||
state = WifiScreenState::FORGET_PROMPT;
|
||||
state = WifiSelectionState::FORGET_PROMPT;
|
||||
forgetPromptSelection = 0; // Default to "Yes"
|
||||
} else {
|
||||
// Go back to network list on failure
|
||||
state = WifiScreenState::NETWORK_LIST;
|
||||
state = WifiSelectionState::NETWORK_LIST;
|
||||
}
|
||||
updateRequired = true;
|
||||
return;
|
||||
@ -402,10 +376,10 @@ void WifiScreen::loop() {
|
||||
}
|
||||
|
||||
// Handle network list state
|
||||
if (state == WifiScreenState::NETWORK_LIST) {
|
||||
// Check for Back button to exit
|
||||
if (state == WifiSelectionState::NETWORK_LIST) {
|
||||
// Check for Back button to exit (cancel)
|
||||
if (inputManager.wasPressed(InputManager::BTN_BACK)) {
|
||||
onGoBack();
|
||||
onComplete(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -434,7 +408,7 @@ void WifiScreen::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string WifiScreen::getSignalStrengthIndicator(int32_t rssi) const {
|
||||
std::string WifiSelectionActivity::getSignalStrengthIndicator(int32_t rssi) const {
|
||||
// Convert RSSI to signal bars representation
|
||||
if (rssi >= -50) {
|
||||
return "||||"; // Excellent
|
||||
@ -448,7 +422,7 @@ std::string WifiScreen::getSignalStrengthIndicator(int32_t rssi) const {
|
||||
return " "; // Very weak
|
||||
}
|
||||
|
||||
void WifiScreen::displayTaskLoop() {
|
||||
void WifiSelectionActivity::displayTaskLoop() {
|
||||
while (true) {
|
||||
if (updateRequired) {
|
||||
updateRequired = false;
|
||||
@ -460,32 +434,32 @@ void WifiScreen::displayTaskLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::render() const {
|
||||
void WifiSelectionActivity::render() const {
|
||||
renderer.clearScreen();
|
||||
|
||||
switch (state) {
|
||||
case WifiScreenState::SCANNING:
|
||||
case WifiSelectionState::SCANNING:
|
||||
renderConnecting(); // Reuse connecting screen with different message
|
||||
break;
|
||||
case WifiScreenState::NETWORK_LIST:
|
||||
case WifiSelectionState::NETWORK_LIST:
|
||||
renderNetworkList();
|
||||
break;
|
||||
case WifiScreenState::PASSWORD_ENTRY:
|
||||
case WifiSelectionState::PASSWORD_ENTRY:
|
||||
renderPasswordEntry();
|
||||
break;
|
||||
case WifiScreenState::CONNECTING:
|
||||
case WifiSelectionState::CONNECTING:
|
||||
renderConnecting();
|
||||
break;
|
||||
case WifiScreenState::CONNECTED:
|
||||
case WifiSelectionState::CONNECTED:
|
||||
renderConnected();
|
||||
break;
|
||||
case WifiScreenState::SAVE_PROMPT:
|
||||
case WifiSelectionState::SAVE_PROMPT:
|
||||
renderSavePrompt();
|
||||
break;
|
||||
case WifiScreenState::CONNECTION_FAILED:
|
||||
case WifiSelectionState::CONNECTION_FAILED:
|
||||
renderConnectionFailed();
|
||||
break;
|
||||
case WifiScreenState::FORGET_PROMPT:
|
||||
case WifiSelectionState::FORGET_PROMPT:
|
||||
renderForgetPrompt();
|
||||
break;
|
||||
}
|
||||
@ -493,7 +467,7 @@ void WifiScreen::render() const {
|
||||
renderer.displayBuffer();
|
||||
}
|
||||
|
||||
void WifiScreen::renderNetworkList() const {
|
||||
void WifiSelectionActivity::renderNetworkList() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
|
||||
@ -569,7 +543,7 @@ void WifiScreen::renderNetworkList() const {
|
||||
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "OK: Connect | * = Encrypted | + = Saved");
|
||||
}
|
||||
|
||||
void WifiScreen::renderPasswordEntry() const {
|
||||
void WifiSelectionActivity::renderPasswordEntry() const {
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
|
||||
// Draw header
|
||||
@ -588,12 +562,12 @@ void WifiScreen::renderPasswordEntry() const {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::renderConnecting() const {
|
||||
void WifiSelectionActivity::renderConnecting() const {
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
const auto top = (pageHeight - height) / 2;
|
||||
|
||||
if (state == WifiScreenState::SCANNING) {
|
||||
if (state == WifiSelectionState::SCANNING) {
|
||||
renderer.drawCenteredText(UI_FONT_ID, top, "Scanning...", true, REGULAR);
|
||||
} else {
|
||||
renderer.drawCenteredText(READER_FONT_ID, top - 30, "Connecting...", true, BOLD);
|
||||
@ -606,7 +580,7 @@ void WifiScreen::renderConnecting() const {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiScreen::renderConnected() const {
|
||||
void WifiSelectionActivity::renderConnected() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
@ -623,14 +597,10 @@ void WifiScreen::renderConnected() const {
|
||||
std::string ipInfo = "IP Address: " + connectedIP;
|
||||
renderer.drawCenteredText(UI_FONT_ID, top + 40, ipInfo.c_str(), true, REGULAR);
|
||||
|
||||
// Show web server info
|
||||
std::string webInfo = "Web: http://" + connectedIP + "/";
|
||||
renderer.drawCenteredText(UI_FONT_ID, top + 70, webInfo.c_str(), true, REGULAR);
|
||||
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to exit", true, REGULAR);
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue", true, REGULAR);
|
||||
}
|
||||
|
||||
void WifiScreen::renderSavePrompt() const {
|
||||
void WifiSelectionActivity::renderSavePrompt() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
@ -670,7 +640,7 @@ void WifiScreen::renderSavePrompt() const {
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm", true, REGULAR);
|
||||
}
|
||||
|
||||
void WifiScreen::renderConnectionFailed() const {
|
||||
void WifiSelectionActivity::renderConnectionFailed() const {
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
const auto top = (pageHeight - height * 2) / 2;
|
||||
@ -680,7 +650,7 @@ void WifiScreen::renderConnectionFailed() const {
|
||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue", true, REGULAR);
|
||||
}
|
||||
|
||||
void WifiScreen::renderForgetPrompt() const {
|
||||
void WifiSelectionActivity::renderForgetPrompt() const {
|
||||
const auto pageWidth = GfxRenderer::getScreenWidth();
|
||||
const auto pageHeight = GfxRenderer::getScreenHeight();
|
||||
const auto height = renderer.getLineHeight(UI_FONT_ID);
|
||||
@ -20,26 +20,37 @@ struct WifiNetworkInfo {
|
||||
bool hasSavedPassword; // Whether we have saved credentials for this network
|
||||
};
|
||||
|
||||
// WiFi screen states
|
||||
enum class WifiScreenState {
|
||||
// WiFi selection states
|
||||
enum class WifiSelectionState {
|
||||
SCANNING, // Scanning for networks
|
||||
NETWORK_LIST, // Displaying available networks
|
||||
PASSWORD_ENTRY, // Entering password for selected network
|
||||
CONNECTING, // Attempting to connect
|
||||
CONNECTED, // Successfully connected, showing IP
|
||||
CONNECTED, // Successfully connected
|
||||
SAVE_PROMPT, // Asking user if they want to save the password
|
||||
CONNECTION_FAILED, // Connection failed
|
||||
FORGET_PROMPT // Asking user if they want to forget the network
|
||||
};
|
||||
|
||||
class WifiScreen final : public Activity {
|
||||
/**
|
||||
* WifiSelectionActivity is responsible for scanning WiFi APs and connecting to them.
|
||||
* It will:
|
||||
* - Enter scanning mode on entry
|
||||
* - List available WiFi networks
|
||||
* - Allow selection and launch KeyboardEntryActivity for password if needed
|
||||
* - Save the password if requested
|
||||
* - Call onComplete callback when connected or cancelled
|
||||
*
|
||||
* The onComplete callback receives true if connected successfully, false if cancelled.
|
||||
*/
|
||||
class WifiSelectionActivity final : public Activity {
|
||||
TaskHandle_t displayTaskHandle = nullptr;
|
||||
SemaphoreHandle_t renderingMutex = nullptr;
|
||||
bool updateRequired = false;
|
||||
WifiScreenState state = WifiScreenState::SCANNING;
|
||||
WifiSelectionState state = WifiSelectionState::SCANNING;
|
||||
int selectedNetworkIndex = 0;
|
||||
std::vector<WifiNetworkInfo> networks;
|
||||
const std::function<void()> onGoBack;
|
||||
const std::function<void(bool connected)> onComplete;
|
||||
|
||||
// Selected network for connection
|
||||
std::string selectedSSID;
|
||||
@ -85,9 +96,13 @@ class WifiScreen final : public Activity {
|
||||
std::string getSignalStrengthIndicator(int32_t rssi) const;
|
||||
|
||||
public:
|
||||
explicit WifiScreen(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoBack)
|
||||
: Activity(renderer, inputManager), onGoBack(onGoBack) {}
|
||||
explicit WifiSelectionActivity(GfxRenderer& renderer, InputManager& inputManager,
|
||||
const std::function<void(bool connected)>& onComplete)
|
||||
: Activity(renderer, inputManager), onComplete(onComplete) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
// Get the IP address after successful connection
|
||||
const std::string& getConnectedIP() const { return connectedIP; }
|
||||
};
|
||||
@ -9,8 +9,7 @@
|
||||
|
||||
const SettingInfo SettingsActivity::settingsList[settingsCount] = {
|
||||
{"White Sleep Screen", SettingType::TOGGLE, &CrossPointSettings::whiteSleepScreen},
|
||||
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing},
|
||||
{"WiFi", SettingType::ACTION, nullptr}};
|
||||
{"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing}};
|
||||
|
||||
void SettingsActivity::taskTrampoline(void* param) {
|
||||
auto* self = static_cast<SettingsActivity*>(param);
|
||||
@ -48,7 +47,7 @@ void SettingsActivity::onExit() {
|
||||
void SettingsActivity::loop() {
|
||||
// Handle actions with early return
|
||||
if (inputManager.wasPressed(InputManager::BTN_CONFIRM)) {
|
||||
activateCurrentSetting();
|
||||
toggleCurrentSetting();
|
||||
updateRequired = true;
|
||||
return;
|
||||
}
|
||||
@ -73,26 +72,6 @@ void SettingsActivity::loop() {
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsActivity::activateCurrentSetting() {
|
||||
// Validate index
|
||||
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& setting = settingsList[selectedSettingIndex];
|
||||
|
||||
if (setting.type == SettingType::TOGGLE) {
|
||||
toggleCurrentSetting();
|
||||
// Trigger a redraw of the entire screen
|
||||
updateRequired = true;
|
||||
} else if (setting.type == SettingType::ACTION) {
|
||||
// Handle action settings
|
||||
if (std::string(setting.name) == "WiFi") {
|
||||
onGoWifi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsActivity::toggleCurrentSetting() {
|
||||
// Validate index
|
||||
if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) {
|
||||
@ -135,8 +114,6 @@ void SettingsActivity::render() const {
|
||||
// Draw header
|
||||
renderer.drawCenteredText(READER_FONT_ID, 10, "Settings", true, BOLD);
|
||||
|
||||
// We always have at least one setting
|
||||
|
||||
// Draw all settings
|
||||
for (int i = 0; i < settingsCount; i++) {
|
||||
const int settingY = 60 + i * 30; // 30 pixels between settings
|
||||
@ -153,13 +130,11 @@ void SettingsActivity::render() const {
|
||||
if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) {
|
||||
bool value = SETTINGS.*(settingsList[i].valuePtr);
|
||||
renderer.drawText(UI_FONT_ID, pageWidth - 80, settingY, value ? "ON" : "OFF");
|
||||
} else if (settingsList[i].type == SettingType::ACTION) {
|
||||
renderer.drawText(UI_FONT_ID, pageWidth - 80, settingY, ">");
|
||||
}
|
||||
}
|
||||
|
||||
// Draw help text
|
||||
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "Press OK to select, BACK to save & exit");
|
||||
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 30, "Press OK to toggle, BACK to save & exit");
|
||||
|
||||
// Always use standard refresh for settings screen
|
||||
renderer.displayBuffer();
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
class CrossPointSettings;
|
||||
|
||||
enum class SettingType { TOGGLE, ACTION };
|
||||
enum class SettingType { TOGGLE };
|
||||
|
||||
// Structure to hold setting information
|
||||
struct SettingInfo {
|
||||
@ -27,22 +27,19 @@ class SettingsActivity final : public Activity {
|
||||
bool updateRequired = false;
|
||||
int selectedSettingIndex = 0; // Currently selected setting
|
||||
const std::function<void()> onGoHome;
|
||||
const std::function<void()> onGoWifi;
|
||||
|
||||
// Static settings list
|
||||
static constexpr int settingsCount = 3; // Number of settings
|
||||
static constexpr int settingsCount = 2; // Number of settings
|
||||
static const SettingInfo settingsList[settingsCount];
|
||||
|
||||
static void taskTrampoline(void* param);
|
||||
[[noreturn]] void displayTaskLoop();
|
||||
void render() const;
|
||||
void toggleCurrentSetting();
|
||||
void activateCurrentSetting();
|
||||
|
||||
public:
|
||||
explicit SettingsActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoHome,
|
||||
const std::function<void()>& onGoWifi)
|
||||
: Activity(renderer, inputManager), onGoHome(onGoHome), onGoWifi(onGoWifi) {}
|
||||
explicit SettingsActivity(GfxRenderer& renderer, InputManager& inputManager, const std::function<void()>& onGoHome)
|
||||
: Activity(renderer, inputManager), onGoHome(onGoHome) {}
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
void loop() override;
|
||||
|
||||
28
src/main.cpp
28
src/main.cpp
@ -21,7 +21,7 @@
|
||||
#include "activities/boot_sleep/BootActivity.h"
|
||||
#include "activities/boot_sleep/SleepActivity.h"
|
||||
#include "activities/home/HomeActivity.h"
|
||||
#include "activities/network/WifiScreen.h"
|
||||
#include "activities/network/CrossPointWebServerActivity.h"
|
||||
#include "activities/reader/ReaderActivity.h"
|
||||
#include "activities/settings/SettingsActivity.h"
|
||||
#include "activities/util/FullScreenMessageActivity.h"
|
||||
@ -143,21 +143,19 @@ void onGoToReader(const std::string& initialEpubPath) {
|
||||
}
|
||||
void onGoToReaderHome() { onGoToReader(std::string()); }
|
||||
|
||||
void onGoToSettings();
|
||||
|
||||
void onGoToWifi() {
|
||||
void onGoToFileTransfer() {
|
||||
exitActivity();
|
||||
enterNewActivity(new WifiScreen(renderer, inputManager, onGoToSettings));
|
||||
enterNewActivity(new CrossPointWebServerActivity(renderer, inputManager, onGoHome));
|
||||
}
|
||||
|
||||
void onGoToSettings() {
|
||||
exitActivity();
|
||||
enterNewActivity(new SettingsActivity(renderer, inputManager, onGoHome, onGoToWifi));
|
||||
enterNewActivity(new SettingsActivity(renderer, inputManager, onGoHome));
|
||||
}
|
||||
|
||||
void onGoHome() {
|
||||
exitActivity();
|
||||
enterNewActivity(new HomeActivity(renderer, inputManager, onGoToReaderHome, onGoToSettings));
|
||||
enterNewActivity(new HomeActivity(renderer, inputManager, onGoToReaderHome, onGoToSettings, onGoToFileTransfer));
|
||||
}
|
||||
|
||||
void setup() {
|
||||
@ -204,10 +202,8 @@ void setup() {
|
||||
void loop() {
|
||||
static unsigned long lastLoopTime = 0;
|
||||
static unsigned long maxLoopDuration = 0;
|
||||
static unsigned long lastHandleClientTime = 0;
|
||||
|
||||
unsigned long loopStartTime = millis();
|
||||
unsigned long timeSinceLastLoop = loopStartTime - lastLoopTime;
|
||||
|
||||
// Reduce delay when webserver is running to allow faster handleClient() calls
|
||||
// This is critical for upload performance and preventing TCP timeouts
|
||||
@ -251,20 +247,6 @@ void loop() {
|
||||
}
|
||||
unsigned long activityDuration = millis() - activityStartTime;
|
||||
|
||||
// Handle web server requests if running
|
||||
if (crossPointWebServer.isRunning()) {
|
||||
unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime;
|
||||
|
||||
// Log if there's a significant gap between handleClient calls (>100ms)
|
||||
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
||||
Serial.printf("[%lu] [LOOP] WARNING: %lu ms gap since last handleClient (activity took %lu ms)\n", millis(),
|
||||
timeSinceLastHandleClient, activityDuration);
|
||||
}
|
||||
|
||||
crossPointWebServer.handleClient();
|
||||
lastHandleClientTime = millis();
|
||||
}
|
||||
|
||||
unsigned long loopDuration = millis() - loopStartTime;
|
||||
if (loopDuration > maxLoopDuration) {
|
||||
maxLoopDuration = loopDuration;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user