Pages: [1]   Go Down
Author Topic: Problem mit Stringworks  (Read 84 times)
0 Members and 1 Guest are viewing this topic.
Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 7
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Leute,
ich arbeite momentan an einem Funkmelder system und habe ein kleines Problem mit dem Stringworks, dessen Ursache ich nicht finden kann.
Wäre super wenn mir jemand helfen könnte.
Das Problem besteht darin, dass ich einen String via Serieller Schnittstelle schicke, der wie folgt aussieht:
"Alarm Alle,TEXTNACHRICHT" und sich aus dem Keyword Alarm, einem Leerzeichen, dem Adressaten, einem Komma und der Nachricht zusammensetzt.
Da mein Funkmodul (RFM12BSP) mit der RFM12B-Library nur 128Byte große Nachrichten verschicken kann, möchte ich die Nachricht auf 128Byte kürzen und die letzten 8 Byte durch "-cutoff-" ersetzten.
Dafür benutzte ich momentan folgenden Code:
Code:
if(idFound)                                                                                     //If interface found
        {
            Serial.println("Sending message...: ");
            String pl = ("[" + (String)millis() + "] ALARM - " + name + " - ");                                          //prepare the message to send
            if((message.length()) > (127 - (pl.length())))
            {
                message.trim();
                message = message.substring(0, (127 - (pl.length() + 8)));                                     //Cut the message to the max length
                message = (message + "-cutoff-");                //append a cutoff info            
            }
            pl = (pl + message);
            Serial.println(pl.length());
            Serial.println(pl);
            //Serial.println("...");
            sendSize = pl.length();
            Serial.print("Message size: ");
            Serial.print(sendSize);
            Serial.println(" / 128");
            pl.toCharArray(payload, 128);                                                               //convert message to char array for sending
            radio.Send(GATEWAYID, payload, sendSize, requestACK);            //send the message
            Serial.println("DONE!");
Ich habe jedoch momentan das Problem, das ich für die eigentlich Nachricht die ich im Befehl mitsende nur 25 Zeichen nutzen kann, da ansonsten der String (pl) leer zu sein scheint.
Ich nutzte einen Anduino Duemilanove mit dem ATMEGA328P-PJ.
Wäre super wenn jemand des Rätsels lösung hätte.

Nette Grüße
Dr_Console
« Last Edit: July 31, 2014, 07:47:56 am by Dr_Console » Logged

Offline Offline
Faraday Member
**
Karma: 105
Posts: 3619
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Am besten du verzichtest erst mal auf die String Klasse. Das geht auch mit normalen C Strings, d.h. char Arrays:
Code:
const int MAX_LENGTH = 128;

const char name[] PROGMEM = "Test";
const char cutoff[] PROGMEM = "-cutoff-";

char message[] = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345";

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  char buffer[MAX_LENGTH + 1];

  //wenn name nicht als PROGMEM deklariert ist im Format String %s statt %S verwenden!
  int originalSize = snprintf_P(buffer, sizeof(buffer), PSTR("[%lu] ALARM - %S - %s"), millis(), name, message);

  Serial.print(F("original size: ")); Serial.println(originalSize);

  if(originalSize > MAX_LENGTH)
  {
     strcpy_P(buffer +  MAX_LENGTH - strlen_P(cutoff), cutoff);
  }

  Serial.println(buffer);
  Serial.print(F("New size: ")); Serial.println(strlen(buffer));

  Serial.println('\n');
  delay(2000);
}

Ist eigentlich recht simpel.

Anmerkung dazu. snprintf() begrenzt den String schon auf 128 Zeichen, da man natürlich nicht über die Array Grenzen schreiben darf. Deshalb wird der Rückgabe-Wert von snprintf() ausgewertet:
http://www.cplusplus.com/reference/cstdio/snprintf/
"The number of characters that would have been written if n had been sufficiently large, not counting the terminating null character."

Damit hat man die Länge des ursprünglichen Strings auch wenn er nicht ganz im Puffer steht.

Eine andere Möglichkeit wäre strncat():
http://www.cplusplus.com/reference/cstring/strncat/
Dann muss man aber wegen der maximalen Länge noch etwas rumrechnen. snprintf() ist zwar vom compilierten Code her umfangreicher, aber hier einfacher. Und man hat gleich die Integer -> String Konvertierung dabei.


Am Anfang wenn millis() noch klein ist, hat der String genau 128 Zeichen und passt. Aber nach 10 Sekunden wächst millis() um eine Ziffer. Dann kommt "-cutoff-" smiley

Wenn der name String veränderbar sein muss und daher nicht im PROGMEM stehen kann einfach %s statt %S verwenden! Wenn du bei %S einen String übergibst der nicht mit PROGMEM deklariert ist erhältst du Müll!
Kurz:
%s = normaler String im RAM
%S = PROGMEM String der nur im Flash steht


Selbst wenn man die String Klasse verwendet, ist das hier übrigens unnötig:
Code:
pl.toCharArray(payload, 128);
Die Klasse unterstützt inzwischen c_str():
http://www.cplusplus.com/reference/string/string/c_str/
Auch wenn das leider nicht auf der Reference Seite dokumentiert ist. Dadurch erhält man einen read-only Zeiger auf das interne Array des Objekts und muss nicht noch mal extra einen Puffer anlegen und noch mehr Speicher verschwenden.

Was du da vielleicht auch nicht beachtet hast ist bei dir das payload Array 129 Byte haben müsste. Aus dem gleichen Grund weshalb ich char buffer[MAX_LENGTH + 1] mache. Man braucht noch Platz für den Null-Terminator am Ende jedes Strings.


Ein Grund weshalb die Arduino String Klasse so schlecht ist wird hier gezeigt:
http://www.gammon.com.au/forum/?id=12112
Quote
Method      Time   Memory   Sketch
                       µS    Used     Size
            
C-string      44     517      1782
String      2480     526      3746
Braucht mehr Speicher und ist elendig langsam.

Das liegt unter anderem daran dass ständig der allokierte Speicherbereich mit realloc() vergrößert wird und Objekte mit Destruktoren gelöscht werden. Wenn du z.B. zwei Strings mit + zusammenfügst wird der erste vergrößert, die Daten kopiert und dann der Speicher für den zweiten freigegeben. Das dauert.
Die STL String Klasse die auf der Seite auch gezeigt wird ist unter anderem schneller weil der vom String belegte Speicher um mehr als nur 1 Byte wächst und das dadurch weniger oft gemacht werden muss.

printf() frisst zwar auch massig Ressourcen, aber es ist auch sehr viel flexibler. Generell kann man mit C Strings viel mehr machen als mit der String Klasse.
« Last Edit: Today at 02:47:30 pm by Serenifly » Logged

Pages: [1]   Go Up
Jump to: