/* * ═══════════════════════════════════════════════════════════════════════════════════ * OTAMANAGER.HPP - Over-The-Air Update Management System * ═══════════════════════════════════════════════════════════════════════════════════ * * 🔄 THE UPDATE ORCHESTRATOR OF VESPER 🔄 * * This class manages over-the-air firmware updates with safe, reliable * update mechanisms, version checking, and comprehensive error handling. * * 📋 VERSION: 2.1 (Enhanced with scheduled checks and full validation) * 📅 DATE: 2025 * 👨‍💻 AUTHOR: Advanced Bell Systems * ═══════════════════════════════════════════════════════════════════════════════════ */ #pragma once #include #include #include #include #include #include #include #include #include #include "../FileManager/FileManager.hpp" #include "../Telemetry/Telemetry.hpp" #include "../TimeKeeper/TimeKeeper.hpp" class ConfigManager; // Forward declaration class Player; // Forward declaration for idle check class Timekeeper; // Forward declaration for freeze mode class Telemetry; // Forward declaration for freeze mode class OTAManager { public: enum class Status { IDLE, CHECKING_VERSION, DOWNLOADING, INSTALLING, SUCCESS, FAILED }; enum class ErrorCode { NONE, HTTP_ERROR, VERSION_CHECK_FAILED, DOWNLOAD_FAILED, INSUFFICIENT_SPACE, WRITE_FAILED, VERIFICATION_FAILED, CHECKSUM_MISMATCH, METADATA_PARSE_FAILED, SIZE_MISMATCH, VERSION_TOO_LOW, CHANNEL_MISMATCH, PLAYER_ACTIVE }; // Callback types using ProgressCallback = std::function; using StatusCallback = std::function; explicit OTAManager(ConfigManager& configManager); ~OTAManager(); void begin(); void setFileManager(FileManager* fm); void setPlayer(Player* player); // Set player reference for idle check void setTimeKeeper(Timekeeper* tk); // Set timekeeper reference for freeze mode void setTelemetry(Telemetry* telemetry); // Set telemetry reference for freeze mode void checkForUpdates(); void checkForUpdates(const String& channel); // Check specific channel void checkForEmergencyUpdates(); // NEW: Scheduled emergency-only check void update(); void update(const String& channel); // Update from specific channel void checkFirmwareUpdateFromSD(); // Check SD for firmware update bool performManualUpdate(); // Manual update triggered by app bool performManualUpdate(const String& channel); // Manual update from specific channel bool performCustomUpdate(const String& firmwareUrl, const String& checksum = "", size_t fileSize = 0); // Custom firmware update // Hardware identification String getHardwareVariant() const; void setHardwareVariant(const String& variant); // Deprecated: Use ConfigManager instead // Status and info Status getStatus() const { return _status; } ErrorCode getLastError() const { return _lastError; } uint16_t getCurrentVersion() const; uint16_t getAvailableVersion() const { return _availableVersion; } bool isUpdateAvailable() const { return _updateAvailable; } // Callbacks void setProgressCallback(ProgressCallback callback) { _progressCallback = callback; } void setStatusCallback(StatusCallback callback) { _statusCallback = callback; } // ═══════════════════════════════════════════════════════════════════════════════ // HEALTH CHECK METHOD // ═══════════════════════════════════════════════════════════════════════════════ /** @brief Check if OTAManager is in healthy state */ bool isHealthy() const; private: ConfigManager& _configManager; FileManager* _fileManager; Player* _player; // Player reference for idle check Timekeeper* _timeKeeper; // TimeKeeper reference for freeze mode Telemetry* _telemetry; // Telemetry reference for freeze mode Status _status; ErrorCode _lastError; uint16_t _availableVersion; uint16_t _minVersion; // NEW: Minimum required version size_t _expectedFileSize; // NEW: Expected firmware file size bool _updateAvailable; String _availableChecksum; String _updateChannel; bool _isMandatory; bool _isEmergency; ProgressCallback _progressCallback; StatusCallback _statusCallback; // NEW: Scheduled check timer TimerHandle_t _scheduledCheckTimer; static void scheduledCheckCallback(TimerHandle_t xTimer); // Initial boot check timer (non-blocking delayed check) TimerHandle_t _initialCheckTimer; static void initialCheckCallback(TimerHandle_t xTimer); void performInitialCheck(); // Async initial check after boot // Worker task for OTA operations (prevents stack overflow in timer callbacks) TaskHandle_t _otaWorkerTask; SemaphoreHandle_t _otaWorkSignal; static void otaWorkerTaskFunction(void* parameter); void otaWorkerLoop(); enum class OTAWorkType { NONE, INITIAL_CHECK, SCHEDULED_CHECK }; OTAWorkType _pendingWork; void setStatus(Status status, ErrorCode error = ErrorCode::NONE); void notifyProgress(size_t current, size_t total); bool checkVersion(); bool checkVersion(const String& channel); bool checkChannelsMetadata(); bool downloadAndInstall(); bool downloadAndInstall(const String& channel); bool downloadDirectToFlash(const String& url, size_t expectedSize); // NEW: Direct to flash (bypasses SD) bool downloadToSD(const String& url, const String& expectedChecksum, size_t expectedSize); // OLD: Via SD card bool verifyChecksum(const String& filePath, const String& expectedChecksum); String calculateSHA256(const String& filePath); bool installFromSD(const String& filePath); String buildChannelUrl(const String& channel) const; String buildMetadataUrl(const String& channel) const; String buildFirmwareUrl(const String& channel) const; // NEW: Helper methods bool isPlayerActive() const; bool checkAvailableSpace(size_t requiredBytes) const; };