Split string

Hey guys,

I'm working on a project parsing XML data from a website (http://www.ivb.at/smartinfo/ivb_smartinfo_kernel.php?olifServerId=84&autorefresh=20&default_autorefresh=20&routeId=&stopId=Breitweg&optDir=-1&nRows=4&showArrivals=n&optTime=now&time=&allLines=y&app=sionline).

The code looks like this:

#include <SPI.h>
#include <string.h>
#include <Ethernet.h>
#include "HT1632.h"

#define MAX_STRING_LEN  20
#define DATA 2
#define WR   3
#define CS   4
#define CS2  5
#define CS3  6
#define CS4  7

HT1632LEDMatrix matrix = HT1632LEDMatrix(DATA, WR, CS, CS2, CS3, CS4);

char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {
  '<', '/', '\0'};
int len;

boolean tagFlag = false;
boolean dataFlag = false;

byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x0D, 0x52, 0xBD };
byte ip[] = { 
  192, 168, 2, 3 };
byte server[] = { 
  83, 175, 126, 90 };

EthernetClient client;

void setup()
{
  Serial.begin(9600);
  matrix.begin(HT1632_COMMON_16NMOS);
  Serial.println("Starting IVB.at");
  Serial.println("connecting...");
  Ethernet.begin(mac, ip);
  delay(0);

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET /smartinfo/ivb_smartinfo_kernel.php?olifServerId=84&autorefresh=20&default_autorefresh=20&routeId=&stopId=Absam%20Dorf&optDir=-1&nRows=4&showArrivals=n&optTime=now&time=&allLines=y&app=sionline HTTP/1.0");    
    client.println("Host: www.ivb.at");  
    client.println();
    delay(10);
  } 
  else {
    Serial.println("connection failed");
    matrix.clearScreen(); 
    matrix.setTextSize(1);
    matrix.setTextColor(1);
    {
      matrix.setCursor(0, 0);
      matrix.print("Bitte   beachten");
      matrix.setCursor(0, 8);
      matrix.print("Fahrplan");
      matrix.writeScreen();
    }
    delay(100);
  }  
}

void loop() {

  // Read serial data in from web:
  while (client.available()) {
    serialEvent(); 
  }

  if (!client.connected()) {
    //Serial.println();
    //Serial.println("Disconnected");
    client.stop();

    // Time until next update
    //Serial.println("Waiting");
    for (int t = 1; t <= 15; t++) {
      delay(1000); // 1 minute
    }

    if (client.connect(server, 80)) {
      //Serial.println("Reconnected");
      client.println("GET /smartinfo/ivb_smartinfo_kernel.php?olifServerId=84&autorefresh=20&default_autorefresh=20&routeId=&stopId=Absam%20Dorf&optDir=-1&nRows=4&showArrivals=n&optTime=now&time=&allLines=y&app=sionline HTTP/1.0");    
      client.println("Host: www.ivb.at");
      matrix.clearScreen();  
      client.println();
      delay(0);
    } 
    else {
      Serial.println("Reconnect failed");
    }       
  }
}

// Process each char from web
void serialEvent() {

  // Read a char
  char inChar = client.read();
  //Serial.print(".");

  if (inChar == '<') {
    addChar(inChar, tmpStr);
    tagFlag = true;
    dataFlag = false;

  } 
  else if (inChar == '>') {
    addChar(inChar, tmpStr);

    if (tagFlag) {      
      strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
    }

    // Clear tmp
    clearStr(tmpStr);

    tagFlag = false;
    dataFlag = true;      

  } 
  else if (inChar != 10) {
    if (tagFlag) {
      // Add tag char to string
      addChar(inChar, tmpStr);

      // Check for </XML> end tag, ignore it
      if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
        clearStr(tmpStr);
        tagFlag = false;
        dataFlag = false;
      }
    }

    if (dataFlag) {
      // Add data char to string
      addChar(inChar, dataStr);
    }
  }  

  // If a LF, process the line
  if (inChar == 10 ) {

    /*
      Serial.print("routeStr: ");
     Serial.println(directionStr);
     Serial.print("directionStr: ");
     Serial.println(directionStr);
     */

    // Find specific tags and print data
    if (matchTag("<time>")) {
      Serial.print(" Abfahrt: ");
      Serial.print(dataStr);
      String stringOne = dataStr;
      Serial.println(stringOne);
      String stringTwo = stringOne;
      stringTwo.replace("min","'");
      stringTwo.replace(":","");
      matrix.setTextSize(1);
      matrix.setTextColor(1);
      {
        matrix.setCursor(24, 0);
        matrix.println(stringTwo);
        matrix.writeScreen();
      }

    }
    if (matchTag("<direction>")) {
      Serial.print(" Ziel: ");
      Serial.print(dataStr);
      String reportString = dataStr;
      char mostSignificantDigit = reportString.charAt(0);
      matrix.setTextSize(1);
      matrix.setTextColor(1);
      {
        matrix.setCursor(16, 0);
        matrix.println(mostSignificantDigit);
        matrix.writeScreen();
      }
    }
    if (matchTag("<route>")) {
      Serial.print(" Linie: ");
      Serial.print(dataStr); 
      matrix.setTextSize(1);
      matrix.setTextColor(1);
      {
        matrix.setCursor(0, 0);
        matrix.print(dataStr);
        matrix.writeScreen();
      }
      }
      
    // Clear all strings
    clearStr(tmpStr);
    clearStr(tagStr);
    clearStr(dataStr);

    // Clear Flags
    tagFlag = false;
    dataFlag = false;
  }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
  int len = strlen(str);
  for (int c = 0; c < len; c++) {
    str[c] = 0;
  }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
  char *tagMsg  = "<TRUNCATED_TAG>";
  char *dataMsg = "-TRUNCATED_DATA-";

  // Check the max size of the string to make sure it doesn't grow too
  // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
  // and replace it with a warning message.
  if (strlen(str) > MAX_STRING_LEN - 2) {
    if (tagFlag) {
      clearStr(tagStr);
      strcpy(tagStr,tagMsg);
    }
    if (dataFlag) {
      clearStr(dataStr);
      strcpy(dataStr,dataMsg);
    }

    // Clear the time buffer and flags to stop current processing 
    clearStr(tmpStr);
    tagFlag = false;
    dataFlag = false;

  } 
  else {
    // Add char to string
    str[strlen(str)] = ch;
  }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
  if ( strcmp(tagStr, searchTag) == 0 ) {
    return true;
  } 
  else {
    return false;
  }
}

The code works pretty good when i print the strings in the serial monitor - i get 4 rows of data:

Linie: D Ziel:  Abfahrt: 2 min
Linie: E Ziel:  Abfahrt: 16 min
Linie: D Ziel:  Abfahrt: 16 min
Linie: D Ziel:  Abfahrt: 10:51

But when I print the data on my LED matrix, I just get one row of data and not four rows (Photo1).

Has anyone an idea how to 'split' the string?
(e.g. String 1:

D
Kurhaus
9 min
,

String 2:
D
Hauptbahnhof
09:49
)

Thanks!

At the moment you are telling it specifically to always print on line 0. Your matrix.setCursor(???, 0) instructions do that.

Maybe you should think about replacing the 0 with a variable that you increment each time you want to go to a new line?

Thank you for your answer!

That's exactly the problem!
But how can i define that e.g.

E Hauptbahnhof 5 min

is in line 1 and

D Kurhaus 11:06

is in line 2? Maybe with the matchtag?

You could do it matching the contents of the lines (or part contents, like D and E). Remember, you can access individual characters inside a c string with [] - so tmpstr[3] would be the 4th character of the string.

Thanks again :slight_smile:
I can't access individual characters, because the strings change all the time!
The whole thing consists of four

? ? ? min

parts (http://www.ivb.at/smartinfo/ivb_smartinfo_kernel.php?olifServerId=84&autorefresh=20&default_autorefresh=20&routeId=&stopId=Breitweg&optDir=-1&nRows=4&showArrivals=n&optTime=now&time=&allLines=y&app=sionline).
The structure is always the same, but the data (?) changes!

I can't access individual characters, because the strings change all the time!

No, it doesn't. You get some data. That data is constant until you get some more.

You're already splitting the string.

    if (matchTag("<route>")) {
      Serial.print(" Linie: ");
      Serial.print(dataStr); 
      matrix.setTextSize(1);
      matrix.setTextColor(1);
      {
        matrix.setCursor(0, 0);
        matrix.print(dataStr);
        matrix.writeScreen();
      }
      }

That, unless I am mistaken, results in "D" or "E" in dataStr. You can look at dataStr (maybe look at character 0, as dataStr[0]) and see which letter it is. Then use that to decide which row to do your printing on...

Oh, and

      String reportString = dataStr;
      char mostSignificantDigit = reportString.charAt(0);

is just plain daft.

char mostSignificantDigit = dataStr[0];

is all that is needed, and it will stop your Arduino crashing after a while from fragmented memory. Well, it would if you got rid of all the other String objects too...

Thank you so much for your help!
I will try all the tips now 8)

Another thing I was thinking of: to work with the String indexOf() and define the structure there!

No. Stay away from String. String is evil.

You have all the tools you need working with C strings (character arrays).

strtok()
strchr()
strrchr()
strstr()
strrstr()
strcmp()
...etc

Wow! Thanks 8)

I've tried your tips and I just can't get this thing to work! :0
As I said, it's no problem to print the data in the serial monitor - I get 4 rows of data, exactly as i want it.

On the LED matrix all the data stays in 1 row! I really don't know what I could do...

Do you fancy sharing your changed code with us?

I've tried it with the most significant digit:

if (matchTag("<route>")) {
      char mostSignificantDigit1 = dataStr[0];
      char mostSignificantDigit2 = dataStr[1];
      Serial.print(" Linie: ");
      Serial.print(dataStr); 
      matrix.setTextSize(1);
      matrix.setTextColor(1);
      {
        matrix.setCursor(0, 0);
        matrix.print(mostSignificantDigit1);
        matrix.writeScreen();
      }
      {
        matrix.setCursor(0, 8);
        matrix.print(mostSignificantDigit2);
        matrix.writeScreen();
      }
      
      }

The problem is, that the data can change from D to E to DE...

What's with the extra { and } in your code?

As Majenko says, you've got some extra { and } in your code. I suspect that these are places where you intended to put 'if' statements to select which line to display on but for some reason you haven't added them.

You probably want to have something like:

if(strcmp(dataStr, "E") == 0)
{
    matrix.setCursor(0, 0);
    matrix.print(mostSignificantDigit1);
    matrix.writeScreen();
}

etc

Thank you! I've deleted the extra { } and added the if function and it looks pretty good 8)