Files
project-vesper/vesper/src/OTAManager/OTAManager.hpp

172 lines
7.1 KiB
C++

/*
* ═══════════════════════════════════════════════════════════════════════════════════
* 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 <Arduino.h>
#include <HTTPClient.h>
#include <Update.h>
#include <WiFi.h>
#include <SD.h>
#include <mbedtls/md.h>
#include <ArduinoJson.h>
#include <functional>
#include <time.h>
#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<void(size_t current, size_t total)>;
using StatusCallback = std::function<void(Status status, ErrorCode error)>;
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;
};