#ifndef CLASSES_H #define CLASSES_H #include #include #include #include #include #include #include "structures.h" // Класс для работы с SD картой class SDCardManager { public: bool init() { if (!SD.begin(SD_CS_PIN, SPI, SD_SPI_SPEED)) { Serial.println("Ошибка инициализации SD карты"); return false; } return true; } bool saveData(const char* filename, const void* data, size_t size) { File file = SD.open(filename, FILE_WRITE); if (!file) { Serial.println("Ошибка открытия файла для записи"); return false; } size_t written = file.write((const uint8_t*)data, size); file.close(); return written == size; } bool loadData(const char* filename, void* data, size_t size) { File file = SD.open(filename, FILE_READ); if (!file) { Serial.println("Ошибка открытия файла для чтения"); return false; } size_t read = file.read((uint8_t*)data, size); file.close(); return read == size; } }; // Класс для работы с PSRAM class PSRAMManager { private: void* psramData; size_t dataSize; bool initialized; public: PSRAMManager() : psramData(nullptr), dataSize(0), initialized(false) {} bool init() { if (!psramInit()) { Serial.println("Ошибка инициализации PSRAM"); return false; } // Выделяем память для всех данных dataSize = sizeof(ConfigData) + sizeof(LearningData) + sizeof(RXXLearningData); psramData = ps_malloc(dataSize); if (!psramData) { Serial.println("Ошибка выделения памяти в PSRAM"); return false; } initialized = true; Serial.println("PSRAM инициализирован"); return true; } bool saveData(const void* data, size_t size, size_t offset) { if (!initialized) return false; if (offset + size > dataSize) { Serial.println("Ошибка: превышение размера PSRAM"); return false; } memcpy((uint8_t*)psramData + offset, data, size); return true; } bool loadData(void* data, size_t size, size_t offset) { if (!initialized) return false; if (offset + size > dataSize) { Serial.println("Ошибка: превышение размера PSRAM"); return false; } memcpy(data, (uint8_t*)psramData + offset, size); return true; } size_t getFreeMemory() { return ESP.getFreePsram(); } size_t getTotalMemory() { return ESP.getPsramSize(); } }; // Класс для работы с веб-сервером class WebServerManager { private: WebServer server; PSRAMManager psramManager; public: void init() { // Инициализация WiFi WiFi.mode(WIFI_AP_STA); WiFi.softAP(WEB_SSID, WEB_PASSWORD); // Настройка маршрутов server.on("/", HTTP_GET, [this]() { server.send(200, "text/html", htmlPage); }); server.on("/config", HTTP_GET, [this]() { StaticJsonDocument<1024> doc; ConfigData config; if (psramManager.loadData(&config, sizeof(ConfigData), 0)) { doc["injectionTimeMin"] = config.injectionTimeMin; doc["injectionTimeMax"] = config.injectionTimeMax; // ... добавьте остальные поля конфигурации } String response; serializeJson(doc, response); server.send(200, "application/json", response); }); server.on("/config", HTTP_POST, [this]() { StaticJsonDocument<1024> doc; DeserializationError error = deserializeJson(doc, server.arg("plain")); if (error) { server.send(400, "text/plain", "Ошибка разбора JSON"); return; } ConfigData config; // Обновление конфигурации config.injectionTimeMin = doc["injectionTimeMin"]; config.injectionTimeMax = doc["injectionTimeMax"]; // ... обновите остальные поля конфигурации if (psramManager.saveData(&config, sizeof(ConfigData), 0)) { server.send(200, "text/plain", "Конфигурация сохранена"); } else { server.send(500, "text/plain", "Ошибка сохранения конфигурации"); } }); server.begin(); } void handleClient() { server.handleClient(); } }; // Класс для управления двигателем class EngineManager { private: float currentRPM; float currentThrottle; float currentTemp; float currentLambda; public: void updateSensors(float rpm, float throttle, float temp, float lambda) { currentRPM = rpm; currentThrottle = throttle; currentTemp = temp; currentLambda = lambda; } float calculateInjectionTime() { // Базовая логика расчета времени впрыска float baseTime = map(currentRPM, 0, MAX_RPM, configData.injectionTimeMin, configData.injectionTimeMax); // Коррекция по температуре if (configData.tempCorrectionEnabled) { baseTime *= getTempCorrection(currentTemp); } // Коррекция по лямбде if (configData.lambdaCorrectionEnabled) { baseTime *= getLambdaCorrection(currentLambda); } return baseTime; } float calculateAdvance() { // Базовая логика расчета УОЗ float baseAdvance = map(currentRPM, 0, MAX_RPM, configData.minAdvance, configData.maxAdvance); // Коррекция для холостого хода if (isIdle()) { return getIdleAdvance(); } return baseAdvance; } private: bool isIdle() { return currentRPM >= configData.idleRpmMin && currentRPM <= configData.idleRpmMax && currentThrottle < THROTTLE_IDLE_THRESHOLD; } float getTempCorrection(float temp) { // Логика коррекции по температуре return 1.0; // Заглушка } float getLambdaCorrection(float lambda) { // Логика коррекции по лямбде return 1.0; // Заглушка } float getIdleAdvance() { // Логика расчета УОЗ на холостом ходу return map(currentRPM, configData.idleRpmMin, configData.idleRpmMax, configData.idleAdvanceMin, configData.idleAdvanceMax); } }; #endif // CLASSES_H