feat: Add per-subsystem log tags to all firmware modules
Refactored logging system to require a TAG as first argument on all LOG_* macros, enabling per-subsystem log filtering and cleaner output. Each subsystem now defines its own TAG (e.g. "BellEngine", "Player"). Also overhauled Logging.hpp/cpp with improved level control and output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#include "OTAManager.hpp"
|
||||
|
||||
#define TAG "OTAManager"
|
||||
#include "../ConfigManager/ConfigManager.hpp"
|
||||
#include "../Logging/Logging.hpp"
|
||||
#include "../Player/Player.hpp"
|
||||
@@ -56,13 +58,13 @@ OTAManager::~OTAManager() {
|
||||
}
|
||||
|
||||
void OTAManager::begin() {
|
||||
LOG_INFO("OTA Manager initialized");
|
||||
LOG_INFO(TAG, "OTA Manager initialized");
|
||||
setStatus(Status::IDLE);
|
||||
|
||||
// Create semaphore for worker task signaling
|
||||
_otaWorkSignal = xSemaphoreCreateBinary();
|
||||
if (_otaWorkSignal == NULL) {
|
||||
LOG_ERROR("Failed to create OTA work semaphore!");
|
||||
LOG_ERROR(TAG, "Failed to create OTA work semaphore!");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,13 +80,13 @@ void OTAManager::begin() {
|
||||
);
|
||||
|
||||
if (taskCreated != pdPASS) {
|
||||
LOG_ERROR("Failed to create OTA worker task!");
|
||||
LOG_ERROR(TAG, "Failed to create OTA worker task!");
|
||||
vSemaphoreDelete(_otaWorkSignal);
|
||||
_otaWorkSignal = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("OTA worker task created with 8KB stack on Core 0");
|
||||
LOG_INFO(TAG, "OTA worker task created with 8KB stack on Core 0");
|
||||
|
||||
// Create timer for scheduled checks (checks every minute if it's 3:00 AM)
|
||||
_scheduledCheckTimer = xTimerCreate(
|
||||
@@ -97,9 +99,9 @@ void OTAManager::begin() {
|
||||
|
||||
if (_scheduledCheckTimer != NULL) {
|
||||
xTimerStart(_scheduledCheckTimer, 0);
|
||||
LOG_INFO("OTA scheduled check timer started (will check at 3:00 AM)");
|
||||
LOG_INFO(TAG, "OTA scheduled check timer started (will check at 3:00 AM)");
|
||||
} else {
|
||||
LOG_ERROR("Failed to create OTA scheduled check timer!");
|
||||
LOG_ERROR(TAG, "Failed to create OTA scheduled check timer!");
|
||||
}
|
||||
|
||||
// 🔥 NEW: Create one-shot timer for initial boot check (5 seconds after boot)
|
||||
@@ -114,9 +116,9 @@ void OTAManager::begin() {
|
||||
|
||||
if (_initialCheckTimer != NULL) {
|
||||
xTimerStart(_initialCheckTimer, 0);
|
||||
LOG_INFO("OTA initial check scheduled for 5 seconds after boot (non-blocking)");
|
||||
LOG_INFO(TAG, "OTA initial check scheduled for 5 seconds after boot (non-blocking)");
|
||||
} else {
|
||||
LOG_ERROR("Failed to create OTA initial check timer!");
|
||||
LOG_ERROR(TAG, "Failed to create OTA initial check timer!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +174,7 @@ void OTAManager::scheduledCheckCallback(TimerHandle_t xTimer) {
|
||||
ota->_pendingWork = OTAWorkType::SCHEDULED_CHECK;
|
||||
xSemaphoreGive(ota->_otaWorkSignal);
|
||||
} else if (ota->isPlayerActive()) {
|
||||
LOG_WARNING("⚠️ Player is active - skipping scheduled update check");
|
||||
LOG_WARNING(TAG, "⚠️ Player is active - skipping scheduled update check");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,21 +182,21 @@ void OTAManager::scheduledCheckCallback(TimerHandle_t xTimer) {
|
||||
// ✅ NEW: Check for emergency updates only (called by scheduled timer)
|
||||
void OTAManager::checkForEmergencyUpdates() {
|
||||
if (_status != Status::IDLE) {
|
||||
LOG_WARNING("OTA check already in progress");
|
||||
LOG_WARNING(TAG, "OTA check already in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Checking for EMERGENCY updates only...");
|
||||
LOG_INFO(TAG, "Checking for EMERGENCY updates only...");
|
||||
checkForUpdates("stable"); // Check stable channel
|
||||
|
||||
// Only proceed if emergency flag is set
|
||||
if (_updateAvailable && _isEmergency) {
|
||||
LOG_INFO("🚨 EMERGENCY update detected during scheduled check - updating immediately");
|
||||
LOG_INFO(TAG, "🚨 EMERGENCY update detected during scheduled check - updating immediately");
|
||||
update("stable");
|
||||
} else if (_updateAvailable && _isMandatory) {
|
||||
LOG_INFO("⚠️ Mandatory update available, but will wait for next boot");
|
||||
LOG_INFO(TAG, "⚠️ Mandatory update available, but will wait for next boot");
|
||||
} else {
|
||||
LOG_INFO("✅ No emergency updates available");
|
||||
LOG_INFO(TAG, "✅ No emergency updates available");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,39 +207,39 @@ void OTAManager::checkForUpdates() {
|
||||
|
||||
void OTAManager::checkForUpdates(const String& channel) {
|
||||
if (_status != Status::IDLE) {
|
||||
LOG_WARNING("OTA check already in progress");
|
||||
LOG_WARNING(TAG, "OTA check already in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
// 🔥 CRITICAL: Check network connectivity before attempting HTTP requests
|
||||
if (WiFi.status() != WL_CONNECTED && !ETH.linkUp()) {
|
||||
LOG_WARNING("OTA check skipped - no network connectivity");
|
||||
if (WiFi.status() != WL_CONNECTED) { // ETHERNET DISABLED - WiFi only
|
||||
LOG_WARNING(TAG, "OTA check skipped - no network connectivity");
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(Status::CHECKING_VERSION);
|
||||
LOG_INFO("Checking for firmware updates in %s channel for %s...",
|
||||
LOG_INFO(TAG, "Checking for firmware updates in %s channel for %s...",
|
||||
channel.c_str(), _configManager.getHardwareVariant().c_str());
|
||||
|
||||
if (checkVersion(channel)) {
|
||||
uint16_t currentVersion = getCurrentVersion();
|
||||
LOG_INFO("Current version: %u, Available version: %u (Channel: %s)",
|
||||
LOG_INFO(TAG, "Current version: %u, Available version: %u (Channel: %s)",
|
||||
currentVersion, _availableVersion, channel.c_str());
|
||||
|
||||
if (_availableVersion > currentVersion) {
|
||||
_updateAvailable = true;
|
||||
LOG_INFO("New version available! Mandatory: %s, Emergency: %s",
|
||||
LOG_INFO(TAG, "New version available! Mandatory: %s, Emergency: %s",
|
||||
_isMandatory ? "YES" : "NO", _isEmergency ? "YES" : "NO");
|
||||
setStatus(Status::IDLE);
|
||||
|
||||
// Auto-update for emergency or mandatory updates during boot check
|
||||
if (channel == "stable" && (_isEmergency || _isMandatory)) {
|
||||
LOG_INFO("Emergency/Mandatory update detected - starting automatic update");
|
||||
LOG_INFO(TAG, "Emergency/Mandatory update detected - starting automatic update");
|
||||
update(channel);
|
||||
}
|
||||
} else {
|
||||
_updateAvailable = false;
|
||||
LOG_INFO("No new version available");
|
||||
LOG_INFO(TAG, "No new version available");
|
||||
setStatus(Status::IDLE);
|
||||
}
|
||||
} else {
|
||||
@@ -252,21 +254,21 @@ void OTAManager::update() {
|
||||
|
||||
void OTAManager::update(const String& channel) {
|
||||
if (_status != Status::IDLE) {
|
||||
LOG_WARNING("OTA update already in progress");
|
||||
LOG_WARNING(TAG, "OTA update already in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_updateAvailable) {
|
||||
LOG_WARNING("No update available for channel: %s", channel.c_str());
|
||||
LOG_WARNING(TAG, "No update available for channel: %s", channel.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Starting OTA update from %s channel...", channel.c_str());
|
||||
LOG_INFO(TAG, "Starting OTA update from %s channel...", channel.c_str());
|
||||
setStatus(Status::DOWNLOADING);
|
||||
|
||||
if (downloadAndInstall(channel)) {
|
||||
setStatus(Status::SUCCESS);
|
||||
LOG_INFO("Update successfully finished. Rebooting...");
|
||||
LOG_INFO(TAG, "Update successfully finished. Rebooting...");
|
||||
delay(1000);
|
||||
ESP.restart();
|
||||
} else {
|
||||
@@ -304,7 +306,7 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
String baseUrl = servers[serverIndex];
|
||||
String metadataUrl = baseUrl + "/ota/" + _configManager.getHardwareVariant() + "/" + channel + "/metadata.json";
|
||||
|
||||
LOG_INFO("OTA: Trying server %d/%d: %s", serverIndex + 1, servers.size(), baseUrl.c_str());
|
||||
LOG_INFO(TAG, "OTA: Trying server %d/%d: %s", serverIndex + 1, servers.size(), baseUrl.c_str());
|
||||
|
||||
HTTPClient http;
|
||||
http.setTimeout(updateConfig.timeout);
|
||||
@@ -316,7 +318,7 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
// Retry logic for current server
|
||||
while (retryCount < updateConfig.retries && httpCode != HTTP_CODE_OK) {
|
||||
if (retryCount > 0) {
|
||||
LOG_INFO("OTA: Retry %d/%d for %s", retryCount + 1, updateConfig.retries, baseUrl.c_str());
|
||||
LOG_INFO(TAG, "OTA: Retry %d/%d for %s", retryCount + 1, updateConfig.retries, baseUrl.c_str());
|
||||
delay(1000 * retryCount); // Exponential backoff
|
||||
}
|
||||
|
||||
@@ -333,7 +335,7 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
DeserializationError error = deserializeJson(doc, jsonStr);
|
||||
|
||||
if (error) {
|
||||
LOG_ERROR("OTA: Failed to parse metadata JSON from %s: %s",
|
||||
LOG_ERROR(TAG, "OTA: Failed to parse metadata JSON from %s: %s",
|
||||
baseUrl.c_str(), error.c_str());
|
||||
continue; // Try next server
|
||||
}
|
||||
@@ -349,7 +351,7 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
|
||||
// ✅ NEW: Validate channel matches requested
|
||||
if (_updateChannel != channel) {
|
||||
LOG_ERROR("OTA: Channel mismatch! Requested: %s, Got: %s",
|
||||
LOG_ERROR(TAG, "OTA: Channel mismatch! Requested: %s, Got: %s",
|
||||
channel.c_str(), _updateChannel.c_str());
|
||||
_lastError = ErrorCode::CHANNEL_MISMATCH;
|
||||
continue; // Try next server
|
||||
@@ -359,7 +361,7 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
String hwVariant = doc["hardwareVariant"].as<String>();
|
||||
String ourHardwareVariant = _configManager.getHardwareVariant();
|
||||
if (!hwVariant.isEmpty() && hwVariant != ourHardwareVariant) {
|
||||
LOG_ERROR("OTA: Hardware variant mismatch! Expected: %s, Got: %s",
|
||||
LOG_ERROR(TAG, "OTA: Hardware variant mismatch! Expected: %s, Got: %s",
|
||||
ourHardwareVariant.c_str(), hwVariant.c_str());
|
||||
continue; // Try next server
|
||||
}
|
||||
@@ -367,36 +369,36 @@ bool OTAManager::checkVersion(const String& channel) {
|
||||
// ✅ NEW: Check minVersion compatibility
|
||||
uint16_t currentVersion = getCurrentVersion();
|
||||
if (_minVersion > 0 && currentVersion < _minVersion) {
|
||||
LOG_ERROR("OTA: Current version %u is below minimum required %u",
|
||||
LOG_ERROR(TAG, "OTA: Current version %u is below minimum required %u",
|
||||
currentVersion, _minVersion);
|
||||
LOG_ERROR("OTA: Intermediate update required first - cannot proceed");
|
||||
LOG_ERROR(TAG, "OTA: Intermediate update required first - cannot proceed");
|
||||
_lastError = ErrorCode::VERSION_TOO_LOW;
|
||||
continue; // Try next server
|
||||
}
|
||||
|
||||
if (_availableVersion == 0) {
|
||||
LOG_ERROR("OTA: Invalid version in metadata from %s", baseUrl.c_str());
|
||||
LOG_ERROR(TAG, "OTA: Invalid version in metadata from %s", baseUrl.c_str());
|
||||
continue; // Try next server
|
||||
}
|
||||
|
||||
if (_availableChecksum.length() != 64) { // SHA256 is 64 hex characters
|
||||
LOG_ERROR("OTA: Invalid checksum in metadata from %s", baseUrl.c_str());
|
||||
LOG_ERROR(TAG, "OTA: Invalid checksum in metadata from %s", baseUrl.c_str());
|
||||
continue; // Try next server
|
||||
}
|
||||
|
||||
LOG_INFO("OTA: Successfully got metadata from %s", baseUrl.c_str());
|
||||
LOG_INFO("OTA: Expected file size: %u bytes, Min version: %u",
|
||||
LOG_INFO(TAG, "OTA: Successfully got metadata from %s", baseUrl.c_str());
|
||||
LOG_INFO(TAG, "OTA: Expected file size: %u bytes, Min version: %u",
|
||||
_expectedFileSize, _minVersion);
|
||||
return true; // Success!
|
||||
} else {
|
||||
LOG_ERROR("OTA: Server %s failed after %d retries. HTTP error: %d",
|
||||
LOG_ERROR(TAG, "OTA: Server %s failed after %d retries. HTTP error: %d",
|
||||
baseUrl.c_str(), updateConfig.retries, httpCode);
|
||||
http.end();
|
||||
}
|
||||
}
|
||||
|
||||
// All servers failed
|
||||
LOG_ERROR("OTA: All %d servers failed to provide metadata", servers.size());
|
||||
LOG_ERROR(TAG, "OTA: All %d servers failed to provide metadata", servers.size());
|
||||
_lastError = ErrorCode::HTTP_ERROR;
|
||||
return false;
|
||||
}
|
||||
@@ -409,26 +411,26 @@ bool OTAManager::downloadAndInstall(const String& channel) {
|
||||
String baseUrl = servers[serverIndex];
|
||||
String firmwareUrl = baseUrl + "/ota/" + _configManager.getHardwareVariant() + "/" + channel + "/firmware.bin";
|
||||
|
||||
LOG_INFO("OTA: Trying firmware download from server %d/%d: %s",
|
||||
LOG_INFO(TAG, "OTA: Trying firmware download from server %d/%d: %s",
|
||||
serverIndex + 1, servers.size(), baseUrl.c_str());
|
||||
|
||||
// 🔥 Download directly to flash (bypassing problematic SD card writes)
|
||||
if (downloadDirectToFlash(firmwareUrl, _expectedFileSize)) {
|
||||
LOG_INFO("✅ OTA update successful!");
|
||||
LOG_INFO(TAG, "✅ OTA update successful!");
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARNING("OTA: Firmware download failed from %s, trying next server", baseUrl.c_str());
|
||||
LOG_WARNING(TAG, "OTA: Firmware download failed from %s, trying next server", baseUrl.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// All servers failed
|
||||
LOG_ERROR("OTA: All %d servers failed to provide firmware", servers.size());
|
||||
LOG_ERROR(TAG, "OTA: All %d servers failed to provide firmware", servers.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 🔥 NEW: Download directly to flash memory, bypassing SD card
|
||||
bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
LOG_INFO("OTA: Starting direct-to-flash download (bypassing SD card)");
|
||||
LOG_INFO(TAG, "OTA: Starting direct-to-flash download (bypassing SD card)");
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url.c_str());
|
||||
@@ -437,7 +439,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode != HTTP_CODE_OK) {
|
||||
LOG_ERROR("Download HTTP error code: %d", httpCode);
|
||||
LOG_ERROR(TAG, "Download HTTP error code: %d", httpCode);
|
||||
setStatus(Status::FAILED, ErrorCode::HTTP_ERROR);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -445,11 +447,11 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
|
||||
int contentLength = http.getSize();
|
||||
|
||||
LOG_INFO("OTA: HTTP Response Code: %d", httpCode);
|
||||
LOG_INFO("OTA: Content-Length: %d bytes", contentLength);
|
||||
LOG_INFO(TAG, "OTA: HTTP Response Code: %d", httpCode);
|
||||
LOG_INFO(TAG, "OTA: Content-Length: %d bytes", contentLength);
|
||||
|
||||
if (contentLength <= 0) {
|
||||
LOG_ERROR("Invalid content length");
|
||||
LOG_ERROR(TAG, "Invalid content length");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -457,7 +459,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
|
||||
// Validate file size
|
||||
if (expectedSize > 0 && (size_t)contentLength != expectedSize) {
|
||||
LOG_ERROR("OTA: File size mismatch! Expected: %u, Got: %d", expectedSize, contentLength);
|
||||
LOG_ERROR(TAG, "OTA: File size mismatch! Expected: %u, Got: %d", expectedSize, contentLength);
|
||||
setStatus(Status::FAILED, ErrorCode::SIZE_MISMATCH);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -466,7 +468,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// ENTER OTA FREEZE MODE - Pause all non-critical systems
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
LOG_INFO("OTA: Entering freeze mode - pausing TimeKeeper and Telemetry");
|
||||
LOG_INFO(TAG, "OTA: Entering freeze mode - pausing TimeKeeper and Telemetry");
|
||||
|
||||
if (_timeKeeper) {
|
||||
_timeKeeper->pauseClockUpdates();
|
||||
@@ -478,7 +480,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
|
||||
// Begin OTA update to flash with MD5 validation enabled
|
||||
if (!Update.begin(contentLength)) {
|
||||
LOG_ERROR("Not enough space to begin OTA update");
|
||||
LOG_ERROR(TAG, "Not enough space to begin OTA update");
|
||||
setStatus(Status::FAILED, ErrorCode::INSUFFICIENT_SPACE);
|
||||
http.end();
|
||||
|
||||
@@ -489,8 +491,8 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("OTA: Update partition ready, starting stream write...");
|
||||
LOG_INFO("OTA: Checksum validation will be performed by ESP32 bootloader");
|
||||
LOG_INFO(TAG, "OTA: Update partition ready, starting stream write...");
|
||||
LOG_INFO(TAG, "OTA: Checksum validation will be performed by ESP32 bootloader");
|
||||
setStatus(Status::INSTALLING);
|
||||
|
||||
// Stream directly to flash with periodic watchdog feeding
|
||||
@@ -511,7 +513,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
size_t bytesWritten = Update.write(buffer, bytesRead);
|
||||
|
||||
if (bytesWritten != bytesRead) {
|
||||
LOG_ERROR("OTA: Flash write failed at offset %u (%u/%u bytes written)",
|
||||
LOG_ERROR(TAG, "OTA: Flash write failed at offset %u (%u/%u bytes written)",
|
||||
written, bytesWritten, bytesRead);
|
||||
http.end();
|
||||
|
||||
@@ -528,7 +530,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
// Log progress every 20%
|
||||
size_t currentPercent = (written * 100) / contentLength;
|
||||
if (currentPercent >= lastLoggedPercent + 20) {
|
||||
LOG_INFO("OTA: Flash write progress: %u%% (%u/%u bytes)",
|
||||
LOG_INFO(TAG, "OTA: Flash write progress: %u%% (%u/%u bytes)",
|
||||
currentPercent, written, contentLength);
|
||||
lastLoggedPercent = currentPercent;
|
||||
}
|
||||
@@ -550,7 +552,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// EXIT OTA FREEZE MODE - Resume all paused systems
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
LOG_INFO("OTA: Exiting freeze mode - resuming TimeKeeper and Telemetry");
|
||||
LOG_INFO(TAG, "OTA: Exiting freeze mode - resuming TimeKeeper and Telemetry");
|
||||
|
||||
if (_timeKeeper) {
|
||||
_timeKeeper->resumeClockUpdates();
|
||||
@@ -561,18 +563,18 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
}
|
||||
|
||||
if (written == (size_t)contentLength) {
|
||||
LOG_INFO("OTA: Successfully written %u bytes to flash", written);
|
||||
LOG_INFO(TAG, "OTA: Successfully written %u bytes to flash", written);
|
||||
} else {
|
||||
LOG_ERROR("OTA: Written only %u/%d bytes", written, contentLength);
|
||||
LOG_ERROR(TAG, "OTA: Written only %u/%d bytes", written, contentLength);
|
||||
setStatus(Status::FAILED, ErrorCode::WRITE_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Update.end(true)) { // true = set new boot partition
|
||||
LOG_INFO("OTA: Update complete!");
|
||||
LOG_INFO(TAG, "OTA: Update complete!");
|
||||
if (Update.isFinished()) {
|
||||
setStatus(Status::SUCCESS);
|
||||
LOG_INFO("OTA: Firmware update successful. Rebooting...");
|
||||
LOG_INFO(TAG, "OTA: Firmware update successful. Rebooting...");
|
||||
|
||||
// Update version in config
|
||||
_configManager.setFwVersion(String(_availableVersion));
|
||||
@@ -582,12 +584,12 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
ESP.restart();
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERROR("OTA: Update not finished");
|
||||
LOG_ERROR(TAG, "OTA: Update not finished");
|
||||
setStatus(Status::FAILED, ErrorCode::VERIFICATION_FAILED);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("OTA: Update error: %s", Update.errorString());
|
||||
LOG_ERROR(TAG, "OTA: Update error: %s", Update.errorString());
|
||||
setStatus(Status::FAILED, ErrorCode::VERIFICATION_FAILED);
|
||||
return false;
|
||||
}
|
||||
@@ -595,7 +597,7 @@ bool OTAManager::downloadDirectToFlash(const String& url, size_t expectedSize) {
|
||||
|
||||
bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum, size_t expectedSize) {
|
||||
if (!_fileManager) {
|
||||
LOG_ERROR("FileManager not set!");
|
||||
LOG_ERROR(TAG, "FileManager not set!");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
@@ -615,7 +617,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode != HTTP_CODE_OK) {
|
||||
LOG_ERROR("Download HTTP error code: %d", httpCode);
|
||||
LOG_ERROR(TAG, "Download HTTP error code: %d", httpCode);
|
||||
setStatus(Status::FAILED, ErrorCode::HTTP_ERROR);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -624,10 +626,10 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
int contentLength = http.getSize();
|
||||
|
||||
// Log HTTP response headers for debugging
|
||||
LOG_INFO("OTA: HTTP Response Code: %d", httpCode);
|
||||
LOG_INFO("OTA: Content-Length header: %d bytes", contentLength);
|
||||
LOG_INFO(TAG, "OTA: HTTP Response Code: %d", httpCode);
|
||||
LOG_INFO(TAG, "OTA: Content-Length header: %d bytes", contentLength);
|
||||
if (contentLength <= 0) {
|
||||
LOG_ERROR("Invalid content length");
|
||||
LOG_ERROR(TAG, "Invalid content length");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -635,7 +637,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
|
||||
// ✅ NEW: Validate file size against metadata
|
||||
if (expectedSize > 0 && (size_t)contentLength != expectedSize) {
|
||||
LOG_ERROR("OTA: File size mismatch! Expected: %u, Got: %d", expectedSize, contentLength);
|
||||
LOG_ERROR(TAG, "OTA: File size mismatch! Expected: %u, Got: %d", expectedSize, contentLength);
|
||||
setStatus(Status::FAILED, ErrorCode::SIZE_MISMATCH);
|
||||
http.end();
|
||||
return false;
|
||||
@@ -643,18 +645,18 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
|
||||
// ✅ NEW: Check available SD card space
|
||||
if (!checkAvailableSpace(contentLength)) {
|
||||
LOG_ERROR("OTA: Insufficient SD card space for update");
|
||||
LOG_ERROR(TAG, "OTA: Insufficient SD card space for update");
|
||||
setStatus(Status::FAILED, ErrorCode::INSUFFICIENT_SPACE);
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("OTA: Starting download of %d bytes...", contentLength);
|
||||
LOG_INFO(TAG, "OTA: Starting download of %d bytes...", contentLength);
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// ENTER OTA FREEZE MODE - Pause all non-critical systems to prevent SD contention
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
LOG_INFO("OTA: Entering freeze mode - pausing TimeKeeper and Telemetry");
|
||||
LOG_INFO(TAG, "OTA: Entering freeze mode - pausing TimeKeeper and Telemetry");
|
||||
|
||||
if (_timeKeeper) {
|
||||
_timeKeeper->pauseClockUpdates();
|
||||
@@ -665,9 +667,9 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
}
|
||||
|
||||
// 🔒 ACQUIRE SD CARD MUTEX - Prevents concurrent SD access
|
||||
LOG_INFO("OTA: Acquiring SD card mutex for safe file operations");
|
||||
LOG_INFO(TAG, "OTA: Acquiring SD card mutex for safe file operations");
|
||||
if (!SDCardMutex::getInstance().lock(10000)) { // 10 second timeout
|
||||
LOG_ERROR("OTA: Failed to acquire SD card mutex!");
|
||||
LOG_ERROR(TAG, "OTA: Failed to acquire SD card mutex!");
|
||||
if (_timeKeeper) _timeKeeper->resumeClockUpdates();
|
||||
if (_telemetry) _telemetry->resume();
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
@@ -677,9 +679,9 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
|
||||
// Delete file if it exists, before opening
|
||||
if (SD.exists(tempPath.c_str())) {
|
||||
LOG_INFO("OTA: Removing existing staged update file");
|
||||
LOG_INFO(TAG, "OTA: Removing existing staged update file");
|
||||
if (!SD.remove(tempPath.c_str())) {
|
||||
LOG_ERROR("OTA: Failed to remove existing file!");
|
||||
LOG_ERROR(TAG, "OTA: Failed to remove existing file!");
|
||||
}
|
||||
delay(200); // Give SD card time to complete deletion
|
||||
}
|
||||
@@ -687,7 +689,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
// Open file for writing
|
||||
File file = SD.open(tempPath.c_str(), FILE_WRITE);
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to create temporary update file");
|
||||
LOG_ERROR(TAG, "Failed to create temporary update file");
|
||||
|
||||
// Release mutex and resume systems before returning
|
||||
SDCardMutex::getInstance().unlock();
|
||||
@@ -699,7 +701,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("OTA: File opened successfully for writing (mutex locked)");
|
||||
LOG_INFO(TAG, "OTA: File opened successfully for writing (mutex locked)");
|
||||
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
uint8_t buffer[4096]; // ✅ Increased to 4KB for better performance
|
||||
@@ -721,7 +723,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
|
||||
// Check if write succeeded
|
||||
if (bytesWritten != bytesRead) {
|
||||
LOG_ERROR("SD write failed at offset %u (%u/%u bytes written)", written, bytesWritten, bytesRead);
|
||||
LOG_ERROR(TAG, "SD write failed at offset %u (%u/%u bytes written)", written, bytesWritten, bytesRead);
|
||||
file.close();
|
||||
SDCardMutex::getInstance().unlock();
|
||||
http.end();
|
||||
@@ -741,7 +743,7 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
// Log progress every 20%
|
||||
size_t currentPercent = (written * 100) / contentLength;
|
||||
if (currentPercent >= lastLoggedPercent + 20) {
|
||||
LOG_INFO("OTA: Download progress: %u%% (%u/%u bytes)",
|
||||
LOG_INFO(TAG, "OTA: Download progress: %u%% (%u/%u bytes)",
|
||||
currentPercent, written, contentLength);
|
||||
lastLoggedPercent = currentPercent;
|
||||
}
|
||||
@@ -770,14 +772,14 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
|
||||
// 🔓 RELEASE SD CARD MUTEX - Other tasks can now access SD
|
||||
SDCardMutex::getInstance().unlock();
|
||||
LOG_INFO("OTA: SD card mutex released");
|
||||
LOG_INFO(TAG, "OTA: SD card mutex released");
|
||||
|
||||
http.end();
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// EXIT OTA FREEZE MODE - Resume all paused systems
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
LOG_INFO("OTA: Exiting freeze mode - resuming TimeKeeper and Telemetry");
|
||||
LOG_INFO(TAG, "OTA: Exiting freeze mode - resuming TimeKeeper and Telemetry");
|
||||
|
||||
if (_timeKeeper) {
|
||||
_timeKeeper->resumeClockUpdates();
|
||||
@@ -788,26 +790,26 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
}
|
||||
|
||||
if (written != (size_t)contentLength) {
|
||||
LOG_ERROR("Download incomplete: %u/%d bytes", written, contentLength);
|
||||
LOG_ERROR(TAG, "Download incomplete: %u/%d bytes", written, contentLength);
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Download complete (%u bytes)", written);
|
||||
LOG_INFO(TAG, "Download complete (%u bytes)", written);
|
||||
|
||||
// 🔒 Acquire mutex for file verification operations
|
||||
if (!SDCardMutex::getInstance().lock(5000)) {
|
||||
LOG_ERROR("OTA: Failed to acquire SD mutex for verification");
|
||||
LOG_ERROR(TAG, "OTA: Failed to acquire SD mutex for verification");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 🔍 DEBUG: Check actual file size on SD card
|
||||
size_t actualFileSize = _fileManager->getFileSize(tempPath);
|
||||
LOG_INFO("OTA: File size on SD card: %u bytes (expected: %u)", actualFileSize, written);
|
||||
LOG_INFO(TAG, "OTA: File size on SD card: %u bytes (expected: %u)", actualFileSize, written);
|
||||
|
||||
if (actualFileSize != written) {
|
||||
LOG_ERROR("OTA: FILE SIZE MISMATCH ON SD CARD! Expected %u, got %u", written, actualFileSize);
|
||||
LOG_ERROR(TAG, "OTA: FILE SIZE MISMATCH ON SD CARD! Expected %u, got %u", written, actualFileSize);
|
||||
SDCardMutex::getInstance().unlock();
|
||||
setStatus(Status::FAILED, ErrorCode::WRITE_FAILED);
|
||||
return false;
|
||||
@@ -826,20 +828,20 @@ bool OTAManager::downloadToSD(const String& url, const String& expectedChecksum,
|
||||
sprintf(hex, "%02X ", debugBuffer[i]);
|
||||
hexDump += hex;
|
||||
}
|
||||
LOG_INFO("%s", hexDump.c_str());
|
||||
LOG_INFO(TAG, "%s", hexDump.c_str());
|
||||
}
|
||||
|
||||
SDCardMutex::getInstance().unlock(); // Release before checksum (checksum will acquire its own)
|
||||
|
||||
// Verify checksum (verifyChecksum acquires its own mutex)
|
||||
if (!verifyChecksum(tempPath, expectedChecksum)) {
|
||||
LOG_ERROR("Checksum verification failed after download");
|
||||
LOG_ERROR(TAG, "Checksum verification failed after download");
|
||||
_fileManager->deleteFile(tempPath);
|
||||
setStatus(Status::FAILED, ErrorCode::CHECKSUM_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Download and checksum verification successful");
|
||||
LOG_INFO(TAG, "Download and checksum verification successful");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -847,18 +849,18 @@ bool OTAManager::verifyChecksum(const String& filePath, const String& expectedCh
|
||||
String calculatedChecksum = calculateSHA256(filePath);
|
||||
|
||||
if (calculatedChecksum.isEmpty()) {
|
||||
LOG_ERROR("Failed to calculate checksum");
|
||||
LOG_ERROR(TAG, "Failed to calculate checksum");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool match = calculatedChecksum.equalsIgnoreCase(expectedChecksum);
|
||||
|
||||
if (match) {
|
||||
LOG_INFO("Checksum verification passed");
|
||||
LOG_INFO(TAG, "Checksum verification passed");
|
||||
} else {
|
||||
LOG_ERROR("Checksum mismatch!");
|
||||
LOG_ERROR("Expected: %s", expectedChecksum.c_str());
|
||||
LOG_ERROR("Calculated: %s", calculatedChecksum.c_str());
|
||||
LOG_ERROR(TAG, "Checksum mismatch!");
|
||||
LOG_ERROR(TAG, "Expected: %s", expectedChecksum.c_str());
|
||||
LOG_ERROR(TAG, "Calculated: %s", calculatedChecksum.c_str());
|
||||
}
|
||||
|
||||
return match;
|
||||
@@ -867,13 +869,13 @@ bool OTAManager::verifyChecksum(const String& filePath, const String& expectedCh
|
||||
String OTAManager::calculateSHA256(const String& filePath) {
|
||||
// 🔒 Acquire SD mutex for file reading
|
||||
if (!SDCardMutex::getInstance().lock(5000)) {
|
||||
LOG_ERROR("Failed to acquire SD mutex for checksum calculation");
|
||||
LOG_ERROR(TAG, "Failed to acquire SD mutex for checksum calculation");
|
||||
return "";
|
||||
}
|
||||
|
||||
File file = SD.open(filePath.c_str());
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to open file for checksum calculation: %s", filePath.c_str());
|
||||
LOG_ERROR(TAG, "Failed to open file for checksum calculation: %s", filePath.c_str());
|
||||
SDCardMutex::getInstance().unlock();
|
||||
return "";
|
||||
}
|
||||
@@ -917,7 +919,7 @@ String OTAManager::calculateSHA256(const String& filePath) {
|
||||
bool OTAManager::installFromSD(const String& filePath) {
|
||||
// 🔒 Acquire SD mutex for file size check
|
||||
if (!SDCardMutex::getInstance().lock(5000)) {
|
||||
LOG_ERROR("Failed to acquire SD mutex for installation");
|
||||
LOG_ERROR(TAG, "Failed to acquire SD mutex for installation");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
@@ -927,30 +929,30 @@ bool OTAManager::installFromSD(const String& filePath) {
|
||||
SDCardMutex::getInstance().unlock(); // Release after size check
|
||||
|
||||
if (updateSize == 0) {
|
||||
LOG_ERROR("Empty update file");
|
||||
LOG_ERROR(TAG, "Empty update file");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Installing firmware from SD (%u bytes)...", updateSize);
|
||||
LOG_INFO(TAG, "Installing firmware from SD (%u bytes)...", updateSize);
|
||||
setStatus(Status::INSTALLING);
|
||||
|
||||
if (!Update.begin(updateSize)) {
|
||||
LOG_ERROR("Not enough space to begin update");
|
||||
LOG_ERROR(TAG, "Not enough space to begin update");
|
||||
setStatus(Status::FAILED, ErrorCode::INSUFFICIENT_SPACE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 🔒 Acquire SD mutex for file reading during flash
|
||||
if (!SDCardMutex::getInstance().lock(30000)) { // 30 second timeout for flash operation
|
||||
LOG_ERROR("Failed to acquire SD mutex for firmware flash");
|
||||
LOG_ERROR(TAG, "Failed to acquire SD mutex for firmware flash");
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
File updateBin = SD.open(filePath.c_str());
|
||||
if (!updateBin) {
|
||||
LOG_ERROR("Failed to open update file: %s", filePath.c_str());
|
||||
LOG_ERROR(TAG, "Failed to open update file: %s", filePath.c_str());
|
||||
SDCardMutex::getInstance().unlock();
|
||||
setStatus(Status::FAILED, ErrorCode::DOWNLOAD_FAILED);
|
||||
return false;
|
||||
@@ -963,18 +965,18 @@ bool OTAManager::installFromSD(const String& filePath) {
|
||||
SDCardMutex::getInstance().unlock();
|
||||
|
||||
if (written == updateSize) {
|
||||
LOG_INFO("Update written successfully (%u bytes)", written);
|
||||
LOG_INFO(TAG, "Update written successfully (%u bytes)", written);
|
||||
} else {
|
||||
LOG_ERROR("Written only %u/%u bytes", written, updateSize);
|
||||
LOG_ERROR(TAG, "Written only %u/%u bytes", written, updateSize);
|
||||
setStatus(Status::FAILED, ErrorCode::WRITE_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Update.end(true)) { // true = set new boot partition
|
||||
LOG_INFO("Update finished!");
|
||||
LOG_INFO(TAG, "Update finished!");
|
||||
if (Update.isFinished()) {
|
||||
setStatus(Status::SUCCESS);
|
||||
LOG_INFO("Update complete. Cleaning up and rebooting...");
|
||||
LOG_INFO(TAG, "Update complete. Cleaning up and rebooting...");
|
||||
|
||||
// Clean up the update files
|
||||
_fileManager->deleteFile(filePath);
|
||||
@@ -990,9 +992,9 @@ bool OTAManager::installFromSD(const String& filePath) {
|
||||
nvs_erase_key(nvsHandle, "fail_count");
|
||||
nvs_commit(nvsHandle);
|
||||
nvs_close(nvsHandle);
|
||||
LOG_INFO("✅ OTA: Firmware validation state cleared - new firmware will be validated");
|
||||
LOG_INFO(TAG, "✅ OTA: Firmware validation state cleared - new firmware will be validated");
|
||||
} else {
|
||||
LOG_WARNING("⚠️ OTA: Failed to clear validation state: %s", esp_err_to_name(err));
|
||||
LOG_WARNING(TAG, "⚠️ OTA: Failed to clear validation state: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
@@ -1003,12 +1005,12 @@ bool OTAManager::installFromSD(const String& filePath) {
|
||||
ESP.restart();
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERROR("Update not complete");
|
||||
LOG_ERROR(TAG, "Update not complete");
|
||||
setStatus(Status::FAILED, ErrorCode::VERIFICATION_FAILED);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("Update error: %s", Update.errorString());
|
||||
LOG_ERROR(TAG, "Update error: %s", Update.errorString());
|
||||
setStatus(Status::FAILED, ErrorCode::VERIFICATION_FAILED);
|
||||
return false;
|
||||
}
|
||||
@@ -1016,19 +1018,19 @@ bool OTAManager::installFromSD(const String& filePath) {
|
||||
|
||||
void OTAManager::checkFirmwareUpdateFromSD() {
|
||||
if (!_fileManager) {
|
||||
LOG_ERROR("FileManager not set!");
|
||||
LOG_ERROR(TAG, "FileManager not set!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_fileManager->fileExists("/firmware/update.bin")) {
|
||||
LOG_DEBUG("No update.bin found on SD card");
|
||||
LOG_DEBUG(TAG, "No update.bin found on SD card");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for checksum file
|
||||
String checksumFile = "/firmware/update.sha256";
|
||||
if (!_fileManager->fileExists(checksumFile)) {
|
||||
LOG_WARNING("No checksum file found, proceeding without verification");
|
||||
LOG_WARNING(TAG, "No checksum file found, proceeding without verification");
|
||||
installFromSD("/firmware/update.bin");
|
||||
return;
|
||||
}
|
||||
@@ -1036,7 +1038,7 @@ void OTAManager::checkFirmwareUpdateFromSD() {
|
||||
// Read expected checksum
|
||||
File checksumFileHandle = SD.open(checksumFile.c_str());
|
||||
if (!checksumFileHandle) {
|
||||
LOG_ERROR("Failed to open checksum file");
|
||||
LOG_ERROR(TAG, "Failed to open checksum file");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1046,12 +1048,12 @@ void OTAManager::checkFirmwareUpdateFromSD() {
|
||||
|
||||
// Verify checksum
|
||||
if (!verifyChecksum("/firmware/update.bin", expectedChecksum)) {
|
||||
LOG_ERROR("Checksum verification failed, aborting update");
|
||||
LOG_ERROR(TAG, "Checksum verification failed, aborting update");
|
||||
setStatus(Status::FAILED, ErrorCode::CHECKSUM_MISMATCH);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Checksum verified, proceeding with update");
|
||||
LOG_INFO(TAG, "Checksum verified, proceeding with update");
|
||||
installFromSD("/firmware/update.bin");
|
||||
}
|
||||
|
||||
@@ -1061,7 +1063,7 @@ bool OTAManager::performManualUpdate() {
|
||||
|
||||
bool OTAManager::performManualUpdate(const String& channel) {
|
||||
if (_status != Status::IDLE) {
|
||||
LOG_WARNING("OTA update already in progress");
|
||||
LOG_WARNING(TAG, "OTA update already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1069,11 +1071,11 @@ bool OTAManager::performManualUpdate(const String& channel) {
|
||||
checkForUpdates(channel);
|
||||
|
||||
if (!_updateAvailable) {
|
||||
LOG_WARNING("No update available in %s channel", channel.c_str());
|
||||
LOG_WARNING(TAG, "No update available in %s channel", channel.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Starting manual OTA update from %s channel (direct-to-flash)...", channel.c_str());
|
||||
LOG_INFO(TAG, "Starting manual OTA update from %s channel (direct-to-flash)...", channel.c_str());
|
||||
setStatus(Status::DOWNLOADING);
|
||||
|
||||
String firmwareUrl = buildFirmwareUrl(channel);
|
||||
@@ -1088,27 +1090,27 @@ bool OTAManager::performManualUpdate(const String& channel) {
|
||||
|
||||
bool OTAManager::performCustomUpdate(const String& firmwareUrl, const String& checksum, size_t fileSize, uint16_t version) {
|
||||
if (_status != Status::IDLE) {
|
||||
LOG_WARNING("OTA update already in progress");
|
||||
LOG_WARNING(TAG, "OTA update already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if player is active
|
||||
if (isPlayerActive()) {
|
||||
LOG_ERROR("Cannot perform custom update: Player is active");
|
||||
LOG_ERROR(TAG, "Cannot perform custom update: Player is active");
|
||||
setStatus(Status::FAILED, ErrorCode::PLAYER_ACTIVE);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("🔥 Starting CUSTOM firmware update (direct-to-flash)...");
|
||||
LOG_INFO(" URL: %s", firmwareUrl.c_str());
|
||||
LOG_INFO(" File Size: %u bytes", fileSize);
|
||||
LOG_INFO(TAG, "🔥 Starting CUSTOM firmware update (direct-to-flash)...");
|
||||
LOG_INFO(TAG, " URL: %s", firmwareUrl.c_str());
|
||||
LOG_INFO(TAG, " File Size: %u bytes", fileSize);
|
||||
|
||||
if (!checksum.isEmpty()) {
|
||||
LOG_INFO(" Checksum: %s (NOTE: ESP32 will validate after flash)", checksum.c_str());
|
||||
LOG_INFO(TAG, " Checksum: %s (NOTE: ESP32 will validate after flash)", checksum.c_str());
|
||||
}
|
||||
|
||||
if (version > 0) {
|
||||
LOG_INFO(" Target Version: %u", version);
|
||||
LOG_INFO(TAG, " Target Version: %u", version);
|
||||
}
|
||||
|
||||
setStatus(Status::DOWNLOADING);
|
||||
@@ -1121,14 +1123,14 @@ bool OTAManager::performCustomUpdate(const String& firmwareUrl, const String& ch
|
||||
if (version > 0) {
|
||||
_configManager.setFwVersion(String(version));
|
||||
_configManager.saveDeviceConfig();
|
||||
LOG_INFO("✅ Custom firmware version %u saved to NVS", version);
|
||||
LOG_INFO(TAG, "✅ Custom firmware version %u saved to NVS", version);
|
||||
} else {
|
||||
LOG_WARNING("⚠️ No version provided - NVS version unchanged");
|
||||
LOG_WARNING(TAG, "⚠️ No version provided - NVS version unchanged");
|
||||
}
|
||||
|
||||
LOG_INFO("🚀 Custom firmware installed - device will reboot");
|
||||
LOG_INFO(TAG, "🚀 Custom firmware installed - device will reboot");
|
||||
} else {
|
||||
LOG_ERROR("❌ Custom firmware installation failed");
|
||||
LOG_ERROR(TAG, "❌ Custom firmware installation failed");
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1140,7 +1142,7 @@ String OTAManager::getHardwareVariant() const {
|
||||
}
|
||||
|
||||
void OTAManager::setHardwareVariant(const String& variant) {
|
||||
LOG_WARNING("OTAManager::setHardwareVariant is deprecated. Use ConfigManager::setHardwareVariant instead");
|
||||
LOG_WARNING(TAG, "OTAManager::setHardwareVariant is deprecated. Use ConfigManager::setHardwareVariant instead");
|
||||
}
|
||||
|
||||
// URL builders for multi-channel architecture
|
||||
@@ -1173,7 +1175,7 @@ bool OTAManager::isPlayerActive() const {
|
||||
// ✅ NEW: Check if SD card has enough free space
|
||||
bool OTAManager::checkAvailableSpace(size_t requiredBytes) const {
|
||||
if (!_fileManager) {
|
||||
LOG_WARNING("OTA: FileManager not set, cannot check available space");
|
||||
LOG_WARNING(TAG, "OTA: FileManager not set, cannot check available space");
|
||||
return true; // Assume it's okay if we can't check
|
||||
}
|
||||
|
||||
@@ -1185,18 +1187,18 @@ bool OTAManager::checkAvailableSpace(size_t requiredBytes) const {
|
||||
uint64_t usedBytes = SD.usedBytes();
|
||||
uint64_t freeBytes = totalBytes - usedBytes;
|
||||
|
||||
LOG_INFO("OTA: SD card space - Total: %llu MB, Used: %llu MB, Free: %llu MB",
|
||||
LOG_INFO(TAG, "OTA: SD card space - Total: %llu MB, Used: %llu MB, Free: %llu MB",
|
||||
totalBytes / (1024 * 1024),
|
||||
usedBytes / (1024 * 1024),
|
||||
freeBytes / (1024 * 1024));
|
||||
|
||||
if (freeBytes < requiredWithMargin) {
|
||||
LOG_ERROR("OTA: Insufficient space! Required: %u bytes (+10%% margin), Available: %llu bytes",
|
||||
LOG_ERROR(TAG, "OTA: Insufficient space! Required: %u bytes (+10%% margin), Available: %llu bytes",
|
||||
requiredWithMargin, freeBytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("OTA: Sufficient space available for update");
|
||||
LOG_INFO(TAG, "OTA: Sufficient space available for update");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1207,45 +1209,45 @@ bool OTAManager::checkAvailableSpace(size_t requiredBytes) const {
|
||||
bool OTAManager::isHealthy() const {
|
||||
// Check if FileManager dependency is set
|
||||
if (!_fileManager) {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - FileManager not set");
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - FileManager not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're not in a failed state
|
||||
if (_status == Status::FAILED) {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - In failed state");
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - In failed state");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if ConfigManager has valid configuration
|
||||
String hwVariant = _configManager.getHardwareVariant();
|
||||
if (hwVariant.isEmpty() || hwVariant == "BellSystems") {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - Invalid hardware variant: %s", hwVariant.c_str());
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - Invalid hardware variant: %s", hwVariant.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
String fwVersion = _configManager.getFwVersion();
|
||||
if (fwVersion.isEmpty() || fwVersion == "0") {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - Invalid firmware version: %s", fwVersion.c_str());
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - Invalid firmware version: %s", fwVersion.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if update servers are available
|
||||
std::vector<String> servers = _configManager.getUpdateServers();
|
||||
if (servers.empty()) {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - No update servers configured");
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - No update servers configured");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if FileManager is healthy (can access SD card)
|
||||
if (!_fileManager->isHealthy()) {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - FileManager is unhealthy");
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - FileManager is unhealthy");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if scheduled timer is running
|
||||
if (_scheduledCheckTimer == NULL || xTimerIsTimerActive(_scheduledCheckTimer) == pdFALSE) {
|
||||
LOG_DEBUG("OTAManager: Unhealthy - Scheduled check timer not running");
|
||||
LOG_DEBUG(TAG, "OTAManager: Unhealthy - Scheduled check timer not running");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1259,13 +1261,13 @@ bool OTAManager::isHealthy() const {
|
||||
// Static entry point for worker task
|
||||
void OTAManager::otaWorkerTaskFunction(void* parameter) {
|
||||
OTAManager* ota = static_cast<OTAManager*>(parameter);
|
||||
LOG_INFO("🔧 OTA Worker task started on Core %d with 8KB stack", xPortGetCoreID());
|
||||
LOG_INFO(TAG, "🔧 OTA Worker task started on Core %d with 8KB stack", xPortGetCoreID());
|
||||
|
||||
// Run the worker loop
|
||||
ota->otaWorkerLoop();
|
||||
|
||||
// Should not reach here
|
||||
LOG_ERROR("❌ OTA Worker task ended unexpectedly!");
|
||||
LOG_ERROR(TAG, "❌ OTA Worker task ended unexpectedly!");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
@@ -1277,18 +1279,18 @@ void OTAManager::otaWorkerLoop() {
|
||||
// Check what type of work to perform
|
||||
switch (_pendingWork) {
|
||||
case OTAWorkType::INITIAL_CHECK:
|
||||
LOG_INFO("🚀 Worker: Performing initial OTA check");
|
||||
LOG_INFO(TAG, "🚀 Worker: Performing initial OTA check");
|
||||
performInitialCheck();
|
||||
break;
|
||||
|
||||
case OTAWorkType::SCHEDULED_CHECK:
|
||||
LOG_INFO("🕒 Worker: Performing scheduled emergency check");
|
||||
LOG_INFO(TAG, "🕒 Worker: Performing scheduled emergency check");
|
||||
checkForEmergencyUpdates();
|
||||
break;
|
||||
|
||||
case OTAWorkType::NONE:
|
||||
default:
|
||||
LOG_WARNING("⚠️ Worker: Received signal but no work pending");
|
||||
LOG_WARNING(TAG, "⚠️ Worker: Received signal but no work pending");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user