ESP8266: WiFi Schaltuhr – Daten-Layout und Definitionen

In diesem Teil geht es um die Daten, die wir halten und speichern müssen.
Diese können wir schon mal in systemrelevante und funktionsrelevante Daten unterteilen. Systemrelevant sind z.B. die SSID des WLAN, die Passphrase zum anmelden usw..
Funktionsrelevant sind die Schaltzeiten, die wir über das Formular eingeben und ändern können.

Systemrelevante Daten:

Hier haben wir zunächst mal die SSID und die Passphrase zur Anmeldung am WLAN. die wir uns im EEPROM merken. Ausserdem berücksichtigen wir gleich die Weiter-Entwicklung dieses Projekts.
Wie sich herausgestellt hat, ist es sinnvoll, die Einstellungen über ein Passwort zu schützen. Dabei geht es weniger um „Hacker“ als darum, dass der 3-jährige Sohnemann nicht zufällig irgendwelche Einstellungen ändert 🙂 …

Also kommen noch hinzu: das Administrator-Passwort und der eindeutige Node-Name des ESPs.

Für die NTP-Zugriffe werden wir den Server und den Port ebenfalls variable halten. Also speichern wir beide Variablen ebenfalls ins EEPROM.

Damit wären wir wohl für alle Eventualitäten gewappnet. Unsere System-Variablen sind jetzt:

static String ntpServerName;
static String wlanSSID;
static String wlanPassphrase;
static bool useDhcp;
static String wwwServerIP;
static String wwwServerPort;
static String nodeName;
static String adminPasswd;
static unsigned int localUDPPort;

Jetzt gibt es einige Besonderheit in der EEPROM-Library: die Positionen und Längen einige System-Variablen sind bereits vordefiniert. Ihr müsst diese Vorgaben nicht nutzen, ich für meinen Teil fand das Feature einfach praktisch.
Allerdings decken sich die vordefinierten System-Variablen nicht mit denen, die wir oben festgelegt haben. In der dsEeprom.h sind die Positionen und Löngen für folgende Systemvariablen vordefiniert:

wlanSSID
wlanPassphrase
wwwServerIP
wwwServerPort
nodeName
adminPasswd

In der Headerdatei dsEeprom.h findet ihr diese vordefinierten Längen- und Positions-Angaben. Sie sollten ausreichend gross dimensioniert sein, aber ihr könnt sie ggf. anpassen:

#define EEPROM_MAXLEN_WLAN_SSID 32 // max. length a SSID may have
#define EEPROM_MAXLEN_WLAN_PASSPHRASE 64 // max. length of a WLAN passphrase
#define EEPROM_MAXLEN_SERVER_IP 19 // max. length for the server IP
#define EEPROM_MAXLEN_SERVER_PORT 4 // max. length for the server port
#define EEPROM_MAXLEN_NODENAME 32 // max. lenght of the (generated) nodename
#define EEPROM_MAXLEN_ADMIN_PASSWORD 32 // max. length for admin password
...
#define EEPROM_POS_WLAN_SSID EEPROM_STD_DATA_BEGIN
#define EEPROM_POS_WLAN_PASSPHRASE (EEPROM_POS_WLAN_SSID + EEPROM_MAXLEN_WLAN_SSID + EEPROM_LEADING_LENGTH)
#define EEPROM_POS_SERVER_IP (EEPROM_POS_WLAN_PASSPHRASE + EEPROM_MAXLEN_WLAN_PASSPHRASE + EEPROM_LEADING_LENGTH)
#define EEPROM_POS_SERVER_PORT (EEPROM_POS_SERVER_IP + EEPROM_MAXLEN_SERVER_IP + EEPROM_LEADING_LENGTH)
#define EEPROM_POS_NODENAME (EEPROM_POS_SERVER_PORT + EEPROM_MAXLEN_SERVER_PORT + EEPROM_LEADING_LENGTH)
#define EEPROM_POS_ADMIN_PASSWORD (EEPROM_POS_NODENAME + EEPROM_MAXLEN_NODENAME + EEPROM_LEADING_LENGTH)
#define EEPROM_STD_DATA_END (EEPROM_POS_ADMIN_PASSWORD + EEPROM_MAXLEN_ADMIN_PASSWORD + EEPROM_LEADING_LENGTH)
//
#define EEPROM_EXT_DATA_BEGIN EEPROM_STD_DATA_END
//
...

Weiter möchte ich an dieser Stelle jetzt gar nicht auf die Library eingehen. Das erledige ich, inkl. der Beschreibung der Logging Library, in einem eigenen Kapitel.

Da ich die Library so wie sie ist verwende, ist die für mich erste, relevante Datenposition EEPROM_STD_DATA_END oder EEPROM_EXT_DATA_BEGIN. Die sind beide gleich … ihr habt also die Wahl. Ich verwende hier EEPROM_STD_DATA_END.

Jetzt kommen unsere Gedanken vom Anfang ins Spiel:
Neben den obigen Daten wollten wir als weitere Systemdaten den NTP-Server und der Port, der verwendet werden soll, abspeichern.
Um das Ganze übersichtlich zu halten, definieren wir erst mal einen Startpunkt:

#define EEPROM_ADD_SYS_VARS_BEGIN EEPROM_STD_DATA_END

Als nächsten legen wir die Länge der Einträge fest. Für den NTP-Server benötigen wir mindestens 15 Zeichen ( IPV4-Adresse ). Legen wir also noch eine Handvoll drauf und legen die maximale Länge des Eintrags mit 20 Zeichen fest. Der Port ( max. 65536 ) ergibt sich von selbst. Auch diese Daten werden als String hinterlegt:

#define EEPROM_MAXLEN_NTP_SERVER_NAME 20
#define EEPROM_MAXLEN_NTP_SERVER_PORT 5

Somit ergeben sich als Positionen:

#define EEPROM_POS_NTP_SERVER_NAME (EEPROM_ADD_SYS_VARS_BEGIN)
#define EEPROM_POS_NTP_SERVER_PORT (EEPROM_POS_NTP_SERVER_NAME + EEPROM_MAXLEN_NTP_SERVER_NAME + EEPROM_LEADING_LENGTH)

Schliesslich setzen wir noch einen Merker auf das Ende der effektiven Systemdaten und definieren den Anfang der externen Daten neu. Das muss nicht sein, dient aber der Übersichtlichkeit:

#define EEPROM_ADD_SYS_VARS_END (EEPROM_POS_NTP_SERVER_PORT + EEPROM_MAXLEN_NTP_SERVER_PORT + EEPROM_LEADING_LENGTH)
#define EEPROM_EXT_DATA_BEGIN EEPROM_ADD_SYS_VARS_END

Damit wären wir bei den funktionsrelevanten Daten angekommen:

Die Daten für die Schaltvorgänge entnehmen wir der Vorgabe. Wir brauchen eine Tabelle mit acht Zeilen. Jede Zeile enthält einen Namen sowie zwei Schaltzyklen für jeweils einen Ausgang. Ausserdem die beiden Flags für externe Übersteuerung, jeweils ein Markierungsflag pro Zeit und einen Modus für den Ausgang.

Ausser den beiden Flags sind alle Felder der Einfachheit halber als String definiert. Das Ganze ergibt dann folgende Struktur:

struct _action_entry {
String name;
String mode;
bool enabled_1;
String hourFrom_1;
String minuteFrom_1;
String hourTo_1;
String minuteTo_1;
bool extEnable_1;
bool enabled_2;
String hourFrom_2;
String minuteFrom_2;
String hourTo_2;
String minuteTo_2;
bool extEnable_2;
};

Dazu definieren wir uns die Anzahl der Zeilen:

#define MAX_ACTION_TABLE_LINES 8

und legen anschliessend die Tabelle als globale Variable an:

struct _action_entry tblEntry[MAX_ACTION_TABLE_LINES];

In einem „normalen“ Programm würde man möglichst vermeiden, globale Variablen zu verwenden. Das gilt allgemein als schlechter Programmierstil.
Bei µControllern sieht das anders aus. Hier ist gerade das RAM meist sehr knapp bemessen. Da Parameter über den Stack übergeben werden benötigen siejeweils mehr oder zumindest genaus so viel Speicher zusätzlich wie die Instanz der Variablen selbst. Hinzu kommt, dass das Holen der Variablen vom Stack u.U. zusätzliche (wertvolle) Arbeitstakte benötigt.
Deshalb ist es von Vorteil bei µControllern die Variablen möglichst global zu halten.

Um die Daten abzulegen und auszulesen fehlt jetzt noch die Länge. Hierzu definieren wir:

#define EEPROM_MAXLEN_TBL_ROW_NAME 15
#define EEPROM_MAXLEN_TBL_ROW_MODE 5
#define EEPROM_MAXLEN_TBL_ENABLED EEPROM_MAXLEN_BOOLEAN
#define EEPROM_MAXLEN_TBL_HR_FROM 2
#define EEPROM_MAXLEN_TBL_MIN_FROM 2
#define EEPROM_MAXLEN_TBL_HR_TO 2
#define EEPROM_MAXLEN_TBL_MIN_TO 2
#define EEPROM_MAXLEN_TBL_EXT_ENABLED EEPROM_MAXLEN_BOOLEAN

Für den frei definierbaren Namen einer Tabellenzeile ( eines Ausgangs ) legen wir mal 15 Zeichen als Maximum fest. Das sollte ausreichen. Den Modus legen wir mit 5 Zeichen fest – mehr als „on“, „off“, „auto“ werden wir hier nicht ablegen.
Die Stunden und Minuten sind jeweils zweistellig.
BOOLEAN für die Flags ist bereits in der Library definiert.

Fehlen noch die Positionen. Das ist jetzt etwas schwierig, denn die Anzahl der Zeilen wollen wir ja möglichst flexibel halten. Mein Ansatz dazu: wir definieren nur die Positionen des ersten Datensatzes ( der ersten Zeile ) und rechnen von da ausgehen die Positionen der anderen Zeilen hoch.

Wie weiter oben schon erwähnt fangen unsere Daten ab Position EEPROM_EXT_DATA_BEGIN an. Somoit ergibt sich folgendes Layout:

#define EEPROM_ACTION_TBL_ENTRY_START EEPROM_EXT_DATA_BEGIN
#define EEPROM_POS_TBL_ROW_NAME EEPROM_EXT_DATA_BEGIN
//
DEFAULT_HTTP_SERVER_IP
//
#define EEPROM_POS_TBL_ENABLED1 (EEPROM_POS_TBL_ROW_MODE + EEPROM_MAXLEN_TBL_ROW_MODE + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_HR1_FROM (EEPROM_POS_TBL_ENABLED1 + EEPROM_MAXLEN_TBL_ENABLED + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_MIN1_FROM (EEPROM_POS_TBL_HR1_FROM + EEPROM_MAXLEN_TBL_HR_FROM + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_HR1_TO (EEPROM_POS_TBL_MIN1_FROM + EEPROM_MAXLEN_TBL_MIN_FROM + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_MIN1_TO (EEPROM_POS_TBL_HR1_TO + EEPROM_MAXLEN_TBL_HR_TO + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_EXT1_ENABLED (EEPROM_POS_TBL_MIN1_TO + EEPROM_MAXLEN_TBL_MIN_TO + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_ENABLED2 (EEPROM_POS_TBL_EXT1_ENABLED + EEPROM_MAXLEN_TBL_EXT_ENABLED + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_HR2_FROM (EEPROM_POS_TBL_ENABLED2 + EEPROM_MAXLEN_TBL_ENABLED + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_MIN2_FROM (EEPROM_POS_TBL_HR2_FROM + EEPROM_MAXLEN_TBL_HR_FROM + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_HR2_TO (EEPROM_POS_TBL_MIN2_FROM + EEPROM_MAXLEN_TBL_MIN_FROM + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_MIN2_TO (EEPROM_POS_TBL_HR2_TO + EEPROM_MAXLEN_TBL_HR_TO + EEPROM_LEADING_LENGTH)
//
#define EEPROM_POS_TBL_EXT2_ENABLED (EEPROM_POS_TBL_MIN2_TO + EEPROM_MAXLEN_TBL_MIN_TO + EEPROM_LEADING_LENGTH)
//
#define EEPROM_ACTION_TBL_ENTRY_END (EEPROM_POS_TBL_EXT2_ENABLED + EEPROM_MAXLEN_TBL_EXT_ENABLED + EEPROM_LEADING_LENGTH)

Um die gesamte Grösse der Tabelle im EEPROM zu erhalten, brauchen wir die Länge eines Datensatzes. Diese erhalten wir durch:

#define EEPROM_ACTION_TBL_ENTRY_LENGTH (EEPROM_ACTION_TBL_ENTRY_END - EEPROM_ACTION_TBL_ENTRY_START)

Multiplizieren wir diesen Wert mit der Anzahl der Tabellen-Zeilen und addieren diesen Wert auf den Anfang der Tabelle im EEPROM, erhalten wir die Endposition der Daten im EEPROM:

#define EEPROM_EXT_DATA_END (EEPROM_ACTION_TBL_ENTRY_START + (EEPROM_ACTION_TBL_ENTRY_LENGTH * MAX_ACTION_TABLE_LINES))

Was jetzt noch fehlt sind die Funktionen zum Lesen und Schreiben der Daten. Diese Funktionen nutzen die API der dsEeprom-Klasse. Weitere Informationen dazu sind in der Beschreibung der dsEeprom-Library zu finden.
Deshalb liste ich die Funktionen einfach mal ohne weiteren Kommentar hier auf.

Unsere zusätzlichen Systemvariablen behandeln wir in zwei eigenen Funktionen:

//
// ------------------------------------------------------------------------
//
// ---------- store additional sytem and environmental settings to EEPROM
//
// ------------------------------------------------------------------------
//
int storeAddSysvars()
{
int retVal = 0;

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing NTP-Server: %s to [%d]\n“, ntpServerName.c_str(), EEPROM_POS_NTP_SERVER_NAME );
}

eeprom.storeString( ntpServerName, EEPROM_MAXLEN_NTP_SERVER_NAME, EEPROM_POS_NTP_SERVER_NAME );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing NTP-Server port: %s to [%d]\n“, ntpServerPort.c_str(), EEPROM_POS_NTP_SERVER_PORT );
}

eeprom.storeString( ntpServerPort, EEPROM_MAXLEN_NTP_SERVER_PORT, EEPROM_POS_NTP_SERVER_PORT );

return( retVal );
}

//
// ————————————————————————
//
// ———- restore additional sysvars to EEPROM
//
// ————————————————————————
//
int restoreAddSysvars()
{
int retVal = 0;

eeprom.restoreString( ntpServerName, EEPROM_POS_NTP_SERVER_NAME, EEPROM_MAXLEN_NTP_SERVER_NAME );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored NTP-Server: %s\n“, ntpServerName.c_str());
}

eeprom.restoreString( ntpServerPort, EEPROM_POS_NTP_SERVER_PORT, EEPROM_MAXLEN_NTP_SERVER_PORT );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored NTP-Port: %s\n“, ntpServerPort.c_str());
}

return( retVal );
}

Dann das Schreiben der System-Variablen:

//
// ------------------------------------------------------------------------
//
// ---------- store sytem and environmental settings to EEPROM
//
// ------------------------------------------------------------------------
//
int storeAdminSettings()
{
int retVal = 0;
unsigned long crcCalc;

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing SSID: %s to [%d]\n“, wlanSSID.c_str(), EEPROM_POS_WLAN_SSID );
}

eeprom.storeString( wlanSSID, EEPROM_MAXLEN_WLAN_SSID, EEPROM_POS_WLAN_SSID );

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing Passphrase: %s to [%d]\n“, wlanPassphrase.c_str(), EEPROM_POS_WLAN_PASSPHRASE );
}

eeprom.storeString( wlanPassphrase, EEPROM_MAXLEN_WLAN_PASSPHRASE, EEPROM_POS_WLAN_PASSPHRASE );

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing ServerIP: %s to [%d]\n“, wwwServerIP.c_str(), EEPROM_POS_SERVER_IP );
}

eeprom.storeString( wwwServerIP, EEPROM_MAXLEN_SERVER_IP, EEPROM_POS_SERVER_IP );

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing ServerPort: %s to [%d]\n“, wwwServerPort.c_str(),EEPROM_POS_SERVER_PORT );
}

eeprom.storeString( wwwServerPort, EEPROM_MAXLEN_SERVER_PORT, EEPROM_POS_SERVER_PORT );

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing Nodename: %s to [%d]\n“, nodeName.c_str(), EEPROM_POS_NODENAME );
}

eeprom.storeString( nodeName, EEPROM_MAXLEN_NODENAME, EEPROM_POS_NODENAME );

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „storing adminPasswd: %s to [%d]\n“, adminPasswd.c_str() , EEPROM_POS_ADMIN_PASSWORD);
}

eeprom.storeString( adminPasswd, EEPROM_MAXLEN_ADMIN_PASSWORD, EEPROM_POS_ADMIN_PASSWORD );

eeprom.validate();

return( retVal );

}

Lesen der System-Variablen:

//
// ------------------------------------------------------------------------
//
// ---------- restore sytem and environmentsl settings to EEPROM
//
// ------------------------------------------------------------------------
//
int restoreAdminSettings()
{
int retVal = 0;
unsigned long crcCalc;
unsigned long crcRead;

if( eeprom.isValid() )
{
crcCalc = eeprom.crc( EEPROM_STD_DATA_BEGIN, EEPROM_EXT_DATA_END );

eeprom.restoreRaw( (char*) &crcRead, EEPROM_POS_CRC32, EEPROM_MAXLEN_CRC32, EEPROM_MAXLEN_CRC32);

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored crc: %x calc crc: %x\n“, crcRead, crcCalc);
}

if( (crcCalc == crcRead) )
{
eeprom.restoreString( wlanSSID, EEPROM_POS_WLAN_SSID, EEPROM_MAXLEN_WLAN_SSID );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored SSID: %s\n“, wlanSSID.c_str());
}

eeprom.restoreString( wlanPassphrase, EEPROM_POS_WLAN_PASSPHRASE, EEPROM_MAXLEN_WLAN_PASSPHRASE );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored Passphrase: %s\n“, wlanPassphrase.c_str());
}

eeprom.restoreString( wwwServerIP, EEPROM_POS_SERVER_IP, EEPROM_MAXLEN_SERVER_IP );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored ServerIP: %s\n“, wwwServerIP.c_str());
}

eeprom.restoreString( wwwServerPort, EEPROM_POS_SERVER_PORT, EEPROM_MAXLEN_SERVER_PORT );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored ServerPort: %s\n“, wwwServerPort.c_str());
}

eeprom.restoreString( nodeName, EEPROM_POS_NODENAME, EEPROM_MAXLEN_NODENAME );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored Nodename: %s\n“, nodeName.c_str());
}

eeprom.restoreString( adminPasswd, EEPROM_POS_ADMIN_PASSWORD, EEPROM_MAXLEN_ADMIN_PASSWORD );
if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, „restored adminPasswd: %s\n“, adminPasswd.c_str());
}

retVal = E_SUCCESS;
}
else
{
retVal = E_BAD_CRC;
}
}
else
{
retVal = E_INVALID_MAGIC;
}

return( retVal );

}

Speichern der Tabelle:

//
// ------------------------------------------------------------------------
//
// ---------- store the table with action information to EEPROM
//
// ------------------------------------------------------------------------
//
int storeActionTable()
{
int retVal = 0;
unsigned long crcCalc;
int currLine;

for( currLine = 0; currLine < MAX_ACTION_TABLE_LINES; currLine++ ) { if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "name ........: %s[%d]\n", tblEntry[currLine].name.c_str(), EEPROM_POS_TBL_ROW_NAME + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].name, EEPROM_MAXLEN_TBL_ROW_NAME, EEPROM_POS_TBL_ROW_NAME + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "mode ........: %s[%d]\n", tblEntry[currLine].mode.c_str(), EEPROM_POS_TBL_ROW_MODE + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].mode, EEPROM_MAXLEN_TBL_ROW_MODE, EEPROM_POS_TBL_ROW_MODE+ (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "enabled_1 ...: %d[%d]\n", tblEntry[currLine].enabled_1, EEPROM_POS_TBL_ENABLED1 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeBoolean((char*)&tblEntry[currLine].enabled_1, EEPROM_POS_TBL_ENABLED1 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourFrom_1 ..: %s[%d]\n", tblEntry[currLine].hourFrom_1.c_str(), EEPROM_POS_TBL_HR1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].hourFrom_1, EEPROM_MAXLEN_TBL_HR_FROM, EEPROM_POS_TBL_HR1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteFrom_1 : %s[%d]\n", tblEntry[currLine].minuteFrom_1.c_str(), EEPROM_POS_TBL_MIN1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].minuteFrom_1, EEPROM_MAXLEN_TBL_MIN_FROM, EEPROM_POS_TBL_MIN1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourTo_1 ....: %s[%d]\n", tblEntry[currLine].hourTo_1.c_str(), EEPROM_POS_TBL_HR1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].hourTo_1, EEPROM_MAXLEN_TBL_HR_TO, EEPROM_POS_TBL_HR1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteTo_1 ..: %s[%d]\n", tblEntry[currLine].minuteTo_1.c_str(), EEPROM_POS_TBL_MIN1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].minuteTo_1, EEPROM_MAXLEN_TBL_MIN_TO, EEPROM_POS_TBL_MIN1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "extEnable_1 .: %d[%d]\n", tblEntry[currLine].extEnable_1, EEPROM_POS_TBL_EXT1_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeBoolean((char*)&tblEntry[currLine].extEnable_1, EEPROM_POS_TBL_EXT1_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "enabled_2 ...: %d[%d]\n", tblEntry[currLine].enabled_2, EEPROM_POS_TBL_ENABLED2 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeBoolean((char*)&tblEntry[currLine].enabled_2, EEPROM_POS_TBL_ENABLED2 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourFrom_2 ..: %s[%d]\n", tblEntry[currLine].hourFrom_2.c_str(), EEPROM_POS_TBL_HR2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].hourFrom_2, EEPROM_MAXLEN_TBL_HR_FROM, EEPROM_POS_TBL_HR2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteFrom_2 : %s[%d]\n", tblEntry[currLine].minuteFrom_2.c_str(), EEPROM_POS_TBL_MIN2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].minuteFrom_2, EEPROM_MAXLEN_TBL_MIN_FROM, EEPROM_POS_TBL_MIN2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourTo_2 ....: %s[%d]\n", tblEntry[currLine].hourTo_2.c_str(), EEPROM_POS_TBL_HR2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].hourTo_2, EEPROM_MAXLEN_TBL_HR_TO, EEPROM_POS_TBL_HR2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteTo_2 ..: %s[%d]\n", tblEntry[currLine].minuteTo_2.c_str(), EEPROM_POS_TBL_MIN2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeString(tblEntry[currLine].minuteTo_2, EEPROM_MAXLEN_TBL_MIN_TO, EEPROM_POS_TBL_MIN2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "extEnable_2 .: %d[%d]\n", tblEntry[currLine].extEnable_2, EEPROM_POS_TBL_EXT2_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.storeBoolean((char*)&tblEntry[currLine].extEnable_2, EEPROM_POS_TBL_EXT2_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); } eeprom.validate(); return( retVal ); }

und schliesslich noch das Lesen der Tabelle:


//
// ------------------------------------------------------------------------
//
// ---------- restore table with action information from EEPROM
//
// ------------------------------------------------------------------------
//
int restoreActionTable()
{
int retVal = 0;
unsigned long crcCalc;
unsigned long crcRead;
int currLine;

if( eeprom.isValid() )
{
crcCalc = eeprom.crc( EEPROM_STD_DATA_BEGIN, EEPROM_EXT_DATA_END );

eeprom.restoreRaw( (char*) &crcRead, EEPROM_POS_CRC32, EEPROM_MAXLEN_CRC32, EEPROM_MAXLEN_CRC32);

if( !beQuiet )
{
Logger.Log(LOGLEVEL_DEBUG, "restored crc: %x calc crc: %x\n", crcRead, crcCalc);
}

if( (crcCalc == crcRead) )
{

for( currLine = 0; currLine < MAX_ACTION_TABLE_LINES; currLine++ ) { eeprom.restoreString(tblEntry[currLine].name, EEPROM_POS_TBL_ROW_NAME + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_ROW_NAME ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "name ........: %s\n", tblEntry[currLine].name.c_str() ); } // eeprom.restoreString(tblEntry[currLine].mode, EEPROM_POS_TBL_ROW_MODE + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_ROW_MODE ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "mode ........: %s\n", tblEntry[currLine].mode.c_str() ); } // eeprom.restoreBoolean((char*)&tblEntry[currLine].enabled_1, EEPROM_POS_TBL_ENABLED1 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "enabled_1 ...: %d\n", tblEntry[currLine].enabled_1 ); } // eeprom.restoreString(tblEntry[currLine].hourFrom_1, EEPROM_POS_TBL_HR1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_HR_FROM ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourFrom_1 ..: %s\n", tblEntry[currLine].hourFrom_1.c_str() ); } // eeprom.restoreString(tblEntry[currLine].minuteFrom_1, EEPROM_POS_TBL_MIN1_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_MIN_FROM ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteFrom_1 : %s\n", tblEntry[currLine].minuteFrom_1.c_str() ); } // eeprom.restoreString(tblEntry[currLine].hourTo_1, EEPROM_POS_TBL_HR1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_HR_TO ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourTo_1 ....: %s\n", tblEntry[currLine].hourTo_1.c_str() ); } // eeprom.restoreString(tblEntry[currLine].minuteTo_1, EEPROM_POS_TBL_MIN1_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_MIN_TO ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteTo_1 ..: %s\n", tblEntry[currLine].minuteTo_1.c_str() ); } // eeprom.restoreBoolean((char*)&tblEntry[currLine].extEnable_1, EEPROM_POS_TBL_EXT1_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "extEnable_1 .: %d\n", tblEntry[currLine].extEnable_1 ); } // eeprom.restoreBoolean((char*)&tblEntry[currLine].enabled_2, EEPROM_POS_TBL_ENABLED2 + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "enabled_2 ...: %d\n", tblEntry[currLine].enabled_2 ); } // eeprom.restoreString(tblEntry[currLine].hourFrom_2, EEPROM_POS_TBL_HR2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_HR_FROM ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourFrom_2 ..: %s\n", tblEntry[currLine].hourFrom_2.c_str() ); } // eeprom.restoreString(tblEntry[currLine].minuteFrom_2, EEPROM_POS_TBL_MIN2_FROM + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_MIN_FROM ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteFrom_2 : %s\n", tblEntry[currLine].minuteFrom_2.c_str() ); } // eeprom.restoreString(tblEntry[currLine].hourTo_2, EEPROM_POS_TBL_HR2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_HR_TO ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "hourTo_2 ....: %s\n", tblEntry[currLine].hourTo_2.c_str() ); } // eeprom.restoreString(tblEntry[currLine].minuteTo_2, EEPROM_POS_TBL_MIN2_TO + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH), EEPROM_MAXLEN_TBL_MIN_TO ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "minuteTo_2 ..: %s\n", tblEntry[currLine].minuteTo_2.c_str() ); } // eeprom.restoreBoolean((char*)&tblEntry[currLine].extEnable_2, EEPROM_POS_TBL_EXT2_ENABLED + (currLine * EEPROM_ACTION_TBL_ENTRY_LENGTH) ); if( !beQuiet ) { Logger.Log(LOGLEVEL_DEBUG, "extEnable_2 .: %d\n", tblEntry[currLine].extEnable_2 ); } } } else { retVal = E_BAD_CRC; } } else { retVal = E_INVALID_MAGIC; } return( retVal ); }

Beim Lesen werden zusätzlich der CRC Wert und das "magic byte" ausgelesen und verglichen. Näheres dazu im Beitrag zur dsEeprom-Library.

Das wäre jetzt mal der Part mit den Daten gewesen. Die Beschreibung der Libraries folgt in einem eigenen Thema.
Im nächsten Schritt werden wir dann versuchen aus den ganzen Code-Fragmenten und weiteren Funktionen was sinnvolles zusammenzubauen.

Bid dahin viel Spass beim Nachbauen,
-ds-

Schreibe einen Kommentar