ich habe ein kleines Programm, welches Kommandos per Ethernet bekommt, auswertet und darauf reagiert. Dabei wird der empfangene String an eine Funktion übergeben:
Loop (Ausschnitt)
while (client.connected()){
if (client.available()){
char c = client.read();
if (c == '\n' || c == '\r') {
Serial.flush();
Serial.println(cmdString);
//Resolve Command ->
result=resolveCmd(cmdString + "\r\n");
client.println(result);
client.flush();
cmdString="";
}
else {
cmdString += c;
}
}//if client.available
}//while client connected
Die zugehörige Funktion (Beispiel der Übergabe: "setport#13,1" => Port 13 auf high:
int resolveCmd(String cmdString) {
// **********SETPORT************
if (cmdString.startsWith("setport")) {
String temp;
temp=(cmdString.substring(cmdString.indexOf("#")+1,cmdString.indexOf(",")));
int iPort=temp.toInt();
temp=(cmdString.substring(cmdString.indexOf(",")+1,cmdString.indexOf(";") ));
int iValue=temp.toInt();
if (debug) {
Serial.print("Port ");
Serial.println(iPort);
Serial.print("Value ");
Serial.println(iValue);
}
digitalWrite(iPort,iValue);
return 1;
}
}
Passt soweit und läuft. Aber: Ich wollte meinen Code etwas modularer erstellen, d.h. Funktionalitäten in externe Files bringen. Dazu habe ich eine fEthernet.h / cpp erstellt:
.h:
#pragma once
void fEthernet_setup();
void fEthernet_socket_server();
int resolveCmd(String cmdString);
.cpp
void fEthernet_socket_server()
{
int i= resolveCmd("Test")
}
int resolveCmd(String cmdString)
{
}
Problem: egal was ich versuche, aber sobald ich Strings als Parameter beim Funktionsaufruf ausserhalb meiner *.ino verwende, meckert der Compiler. Innerhalb der eigentlichen ino läuft alles. Was könnte mein Fehler sein? Einen String innerhalb meiner Funktion zu Deklarieren funktioniert hingegen.
Nun habe ich ein wenig gegoogelt und gelesen, dass Strings auf dem Arduino keine gute Idee seien und man besser Character-Arrays nehmen sollte.
Frage: wie kann ich Methoden wie
-> startsWith
-> Substring + indexof
Auf einem ESP sind Arduino-String Objekte durchaus gebräuchlich, und sollten in .cpp Dateien nach #include <Arduino.h>
verwendbar sein.
Mir fällt außer dem fehlenden Semikolon nichts auf. Wie lautet denn die Fehlermeldung?
@Michael_x: du hast den entscheidenden Hinweis gegeben: das include der Arduino.h hatte ich zwar im cpp-File, nicht aber im Header. Da ich dort aber die Funktion "vorgestellt" habe, hat er mir das String angemeckert. Fehler:
int resolveCmd(String cmdString); -> 'String' was not declared in this scope + 'resolveCmd' cannot be used as a function.
Lösung:
#pragma once
#include <Arduino.h>. // <- hat gefehlt
void fEthernet_setup();
void fEthernet_socket_server();
int resolveCmd(String cmdString);
Keine Fehler... Super!
Aber: ist die Herangehensweise dennoch OK, oder ist die Verwendung von Strings nicht zu empfehlen (habe ich mal gelesen). Die Funktionen können durchaus 100x pro Tag aufgerufen werden. Mülle ich mir mit diesem Konzept den RAM zu, oder wird nach Verlassen der beiden Funktionen fEthernet_socket_server() und resolveCmd(String cmdString) der Speicher wieder freigegeben?
Wenn Du den String außerhalb der Funktion anlegst, kann ihn die Funktion auch nicht freigeben, da er ihr ja "nicht gehört".
Schau mal in die Doku nach der Methode reserve(Länge).
Damit kannst Du dem String eine Mindestlänge geben, so dass der nicht laufend verlängert und damit umkopiert werden muss. Die Länge solltest Du an der zu erwartetenden Maximallänge fest machen
Funktionsparameter werden normalerweise innerhalb einer Funktion als Kopie angelegt. Mit Zeigern oder Referenzen kann die originale Variable verwendet werden. Änderungen innerhalb der Funktion wirken sich dann auch auf die originale Variable aus. Mit int resolveCmd(const String& cmdString) ist der String innerhalb der Funktion konstant schreibgeschützt.
Hmmm .....
Konstant nicht, aber schreibgeschützt, in der Funktion.
Es kann nicht garantiert werden dass der String unverändert bleibt, wenn man eine Referenz nutzt. Jeder Thread oder jede ISR, welche da rein grätscht, kann den String ändern.
Ich rate dazu, jedes mal "read only" zu denken, wenn man "const" liest.
Beachtenswert: Das const zeigt seine Wirkung nur im jeweiligen Geltungsbereich.