new code
This commit is contained in:
429
Memory.h
Normal file
429
Memory.h
Normal file
@@ -0,0 +1,429 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "Config.h"
|
||||
|
||||
// -------------------- کتابخانه EEPROM داخلی برای STM32 --------------------
|
||||
#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32F4xx)
|
||||
#include <EEPROM.h>
|
||||
#endif
|
||||
|
||||
// -------------------- متغیرهای خارجی --------------------
|
||||
extern SPIClass flashSPI;
|
||||
extern DeviceConfig config;
|
||||
|
||||
// -------------------- تنظیمات EEPROM داخلی --------------------
|
||||
#define EEPROM_CONFIG_START 0 // آدرس شروع در EEPROM
|
||||
#define EEPROM_SIGNATURE_ADDR 0 // آدرس سیگنچور در EEPROM
|
||||
#define EEPROM_CONFIG_SIZE sizeof(DeviceConfig)
|
||||
|
||||
// -------------------- توابع حافظه SPI Flash --------------------
|
||||
inline void flashInit() {
|
||||
pinMode(FLASH_CS, OUTPUT);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
flashSPI.begin();
|
||||
flashSPI.setClockDivider(SPI_CLOCK_DIV4);
|
||||
delay(100);
|
||||
}
|
||||
|
||||
inline bool flashIsBusy() {
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x05);
|
||||
uint8_t status = flashSPI.transfer(0);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
return (status & 0x01);
|
||||
}
|
||||
|
||||
inline void flashWaitForReady() {
|
||||
unsigned long start = millis();
|
||||
while (flashIsBusy()) {
|
||||
if (millis() - start > 1000) {
|
||||
Serial1.println("⚠️ Flash wait timeout");
|
||||
break;
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool flashReadBytes(uint32_t addr, uint8_t *data, uint32_t len) {
|
||||
if (len == 0) return false;
|
||||
|
||||
flashWaitForReady();
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x03); // Read command
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
data[i] = flashSPI.transfer(0);
|
||||
}
|
||||
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool flashWriteBytes(uint32_t addr, uint8_t *data, uint32_t len) {
|
||||
if (len == 0) return false;
|
||||
|
||||
// Write Enable
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x06);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
delay(1);
|
||||
|
||||
// Page Program
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x02);
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
flashSPI.transfer(data[i]);
|
||||
}
|
||||
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
flashWaitForReady();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void flashSectorErase(uint32_t addr) {
|
||||
// Write Enable
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x06);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
delay(1);
|
||||
|
||||
// Sector Erase
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x20);
|
||||
flashSPI.transfer((addr >> 16) & 0xFF);
|
||||
flashSPI.transfer((addr >> 8) & 0xFF);
|
||||
flashSPI.transfer(addr & 0xFF);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
|
||||
flashWaitForReady();
|
||||
}
|
||||
|
||||
inline bool testFlashCommunication() {
|
||||
Serial1.print("Testing flash communication... ");
|
||||
|
||||
// دستور خواندن JEDEC ID
|
||||
digitalWrite(FLASH_CS, LOW);
|
||||
flashSPI.transfer(0x9F);
|
||||
uint8_t manuf = flashSPI.transfer(0);
|
||||
uint8_t type = flashSPI.transfer(0);
|
||||
uint8_t capacity = flashSPI.transfer(0);
|
||||
digitalWrite(FLASH_CS, HIGH);
|
||||
|
||||
if (manuf == 0xFF || manuf == 0x00) {
|
||||
Serial1.println("❌ FAILED (No response)");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.print("✅ OK (Manuf: 0x");
|
||||
Serial1.print(manuf, HEX);
|
||||
Serial1.print(", Type: 0x");
|
||||
Serial1.print(type, HEX);
|
||||
Serial1.print(", Capacity: 0x");
|
||||
Serial1.print(capacity, HEX);
|
||||
Serial1.println(")");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- توابع EEPROM داخلی STM32 --------------------
|
||||
inline bool eepromIsAvailable() {
|
||||
#if defined(STM32F1xx) || defined(STM32F3xx) || defined(STM32F4xx)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool eepromWriteConfig(const DeviceConfig &cfg) {
|
||||
if (!eepromIsAvailable()) {
|
||||
Serial1.println("❌ EEPROM not available on this board");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.print("Writing config to EEPROM (");
|
||||
Serial1.print(sizeof(cfg));
|
||||
Serial1.println(" bytes)...");
|
||||
|
||||
uint8_t *data = (uint8_t*)&cfg;
|
||||
|
||||
// نوشتن در EEPROM
|
||||
for (uint16_t i = 0; i < sizeof(cfg); i++) {
|
||||
EEPROM.write(EEPROM_CONFIG_START + i, data[i]);
|
||||
}
|
||||
|
||||
// ذخیره تغییرات
|
||||
#if defined(EEPROM_commit)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
|
||||
Serial1.println("✅ Config written to EEPROM");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool eepromReadConfig(DeviceConfig &cfg) {
|
||||
if (!eepromIsAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *data = (uint8_t*)&cfg;
|
||||
|
||||
// خواندن از EEPROM
|
||||
for (uint16_t i = 0; i < sizeof(cfg); i++) {
|
||||
data[i] = EEPROM.read(EEPROM_CONFIG_START + i);
|
||||
}
|
||||
|
||||
// بررسی سیگنچور
|
||||
if (strcmp(cfg.signature, "CFG") != 0) {
|
||||
Serial1.println("❌ Invalid signature in EEPROM");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial1.println("✅ Config read from EEPROM");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool eepromClearConfig() {
|
||||
if (!eepromIsAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// پاک کردن با نوشتن 0xFF
|
||||
for (uint16_t i = 0; i < EEPROM_CONFIG_SIZE; i++) {
|
||||
EEPROM.write(EEPROM_CONFIG_START + i, 0xFF);
|
||||
}
|
||||
|
||||
#if defined(EEPROM_commit)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
|
||||
Serial1.println("✅ EEPROM cleared");
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------- توابع مدیریت کانفیگ هوشمند --------------------
|
||||
inline void saveConfig() {
|
||||
Serial1.println("\n💾 SAVING CONFIGURATION");
|
||||
|
||||
config.valid = true;
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
memcpy(buffer, &config, sizeof(DeviceConfig));
|
||||
|
||||
bool flashSuccess = false;
|
||||
bool eepromSuccess = false;
|
||||
|
||||
// 1. ذخیره در حافظه SPI Flash (اصلی)
|
||||
Serial1.println("1. Saving to SPI Flash...");
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
if (flashWriteBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig))) {
|
||||
// تأیید
|
||||
uint8_t verifyBuffer[sizeof(DeviceConfig)];
|
||||
if (flashReadBytes(CONFIG_ADDRESS, verifyBuffer, sizeof(DeviceConfig))) {
|
||||
if (memcmp(buffer, verifyBuffer, sizeof(DeviceConfig)) == 0) {
|
||||
flashSuccess = true;
|
||||
Serial1.println(" ✅ SPI Flash: Saved and verified");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!flashSuccess) {
|
||||
Serial1.println(" ❌ SPI Flash: Failed or not available");
|
||||
}
|
||||
|
||||
// 2. ذخیره در EEPROM داخلی (پشتیبان)
|
||||
Serial1.println("2. Saving to internal EEPROM...");
|
||||
eepromSuccess = eepromWriteConfig(config);
|
||||
|
||||
if (eepromSuccess) {
|
||||
Serial1.println(" ✅ EEPROM: Backup saved");
|
||||
} else {
|
||||
Serial1.println(" ⚠️ EEPROM: Backup not available");
|
||||
}
|
||||
|
||||
// خلاصه
|
||||
Serial1.println("\n📊 SAVE SUMMARY:");
|
||||
Serial1.print(" SPI Flash: ");
|
||||
Serial1.println(flashSuccess ? "✅" : "❌");
|
||||
Serial1.print(" Internal EEPROM: ");
|
||||
Serial1.println(eepromSuccess ? "✅" : "⚠️");
|
||||
|
||||
if (flashSuccess || eepromSuccess) {
|
||||
Serial1.println("✅ Configuration saved successfully");
|
||||
} else {
|
||||
Serial1.println("❌ CRITICAL: Could not save config anywhere!");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool loadConfigFromFlash() {
|
||||
Serial1.print("Trying to load from SPI Flash... ");
|
||||
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
|
||||
if (!testFlashCommunication()) {
|
||||
Serial1.println("❌ Flash not responding");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!flashReadBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig))) {
|
||||
Serial1.println("❌ Failed to read from flash");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&config, buffer, sizeof(DeviceConfig));
|
||||
|
||||
if (strcmp(config.signature, "CFG") != 0) {
|
||||
Serial1.println("❌ Invalid signature in flash");
|
||||
return false;
|
||||
}
|
||||
|
||||
config.valid = true;
|
||||
Serial1.println("✅ Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool loadConfigFromEEPROM() {
|
||||
Serial1.print("Trying to load from internal EEPROM... ");
|
||||
|
||||
if (!eepromIsAvailable()) {
|
||||
Serial1.println("❌ EEPROM not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eepromReadConfig(config)) {
|
||||
Serial1.println("❌ Failed to read from EEPROM");
|
||||
return false;
|
||||
}
|
||||
|
||||
config.valid = true;
|
||||
Serial1.println("✅ Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void createDefaultConfig() {
|
||||
Serial1.println("Creating default configuration...");
|
||||
|
||||
strcpy(config.signature, "CFG");
|
||||
strcpy(config.deviceId, "");
|
||||
strcpy(config.serverPhoneNumber, "");
|
||||
strcpy(config.serverUrl, "https://ghback.nabaksoft.ir");
|
||||
config.uploadInterval = 5;
|
||||
config.smsInterval = 10;
|
||||
config.saveInterval = 60;
|
||||
config.simType = SIM_UNKNOWN;
|
||||
config.smsEnabled = false;
|
||||
config.verified = false;
|
||||
config.valid = false;
|
||||
}
|
||||
|
||||
inline void readConfig() {
|
||||
Serial1.println("\n📖 LOADING CONFIGURATION");
|
||||
|
||||
bool configLoaded = false;
|
||||
String source = "";
|
||||
|
||||
// استراتژی: اول SPI Flash، اگر نشد EEPROM داخلی
|
||||
Serial1.println("Strategy: SPI Flash → Internal EEPROM");
|
||||
|
||||
// 1. اول از SPI Flash بخوان
|
||||
if (loadConfigFromFlash()) {
|
||||
configLoaded = true;
|
||||
source = "SPI Flash";
|
||||
|
||||
// همچنین در EEPROM هم بروزرسانی کن (sync)
|
||||
eepromWriteConfig(config);
|
||||
}
|
||||
// 2. اگر SPI Flash کار نکرد، از EEPROM داخلی بخوان
|
||||
else if (loadConfigFromEEPROM()) {
|
||||
configLoaded = true;
|
||||
source = "Internal EEPROM (backup)";
|
||||
|
||||
// سعی کن دوباره در SPI Flash ذخیره کنی (بازیابی)
|
||||
Serial1.println("Attempting to restore to SPI Flash...");
|
||||
uint8_t buffer[sizeof(DeviceConfig)];
|
||||
memcpy(buffer, &config, sizeof(DeviceConfig));
|
||||
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
flashWriteBytes(CONFIG_ADDRESS, buffer, sizeof(DeviceConfig));
|
||||
Serial1.println("✅ Restored to SPI Flash");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. اگر هیچ کدام کار نکرد، کانفیگ پیشفرض بساز
|
||||
if (!configLoaded) {
|
||||
Serial1.println("❌ No valid config found in any memory");
|
||||
source = "Default";
|
||||
|
||||
createDefaultConfig();
|
||||
saveConfig(); // ذخیره کانفیگ جدید
|
||||
configLoaded = true;
|
||||
}
|
||||
|
||||
// نمایش نتیجه
|
||||
Serial1.println("\n📊 LOAD RESULT:");
|
||||
Serial1.print(" Status: ");
|
||||
Serial1.println(configLoaded ? "✅ LOADED" : "❌ FAILED");
|
||||
Serial1.print(" Source: ");
|
||||
Serial1.println(source);
|
||||
Serial1.print(" Device ID: ");
|
||||
Serial1.println(strlen(config.deviceId) > 0 ? config.deviceId : "[Empty]");
|
||||
Serial1.print(" Verified: ");
|
||||
Serial1.println(config.verified ? "YES" : "NO");
|
||||
|
||||
if (configLoaded) {
|
||||
Serial1.println("✅ Configuration ready");
|
||||
}
|
||||
}
|
||||
|
||||
// تابع دیباگ برای نمایش وضعیت حافظهها
|
||||
inline void memoryStatus() {
|
||||
Serial1.println("\n🔍 MEMORY STATUS");
|
||||
Serial1.println("================");
|
||||
|
||||
// تست SPI Flash
|
||||
Serial1.print("SPI Flash: ");
|
||||
Serial1.println(testFlashCommunication() ? "✅ Available" : "❌ Not available");
|
||||
|
||||
// تست EEPROM داخلی
|
||||
Serial1.print("Internal EEPROM: ");
|
||||
Serial1.println(eepromIsAvailable() ? "✅ Available" : "❌ Not available");
|
||||
|
||||
// وضعیت کانفیگ فعلی
|
||||
Serial1.print("Config in RAM: ");
|
||||
Serial1.println(config.valid ? "✅ Valid" : "❌ Invalid");
|
||||
|
||||
Serial1.println("================\n");
|
||||
}
|
||||
|
||||
// تابع ریست کامل (برای تست)
|
||||
inline void resetAllConfig() {
|
||||
Serial1.println("\n⚠️ RESETTING ALL CONFIGURATION");
|
||||
|
||||
// پاک کردن SPI Flash
|
||||
if (testFlashCommunication()) {
|
||||
flashSectorErase(CONFIG_ADDRESS);
|
||||
Serial1.println("✅ SPI Flash erased");
|
||||
}
|
||||
|
||||
// پاک کردن EEPROM
|
||||
eepromClearConfig();
|
||||
|
||||
// ایجاد کانفیگ پیشفرض
|
||||
createDefaultConfig();
|
||||
saveConfig();
|
||||
|
||||
Serial1.println("✅ All configuration reset to defaults\n");
|
||||
}
|
||||
|
||||
#endif // MEMORY_H
|
||||
Reference in New Issue
Block a user