Incoming string from serial to arrays?

Sorry for what might seem like a newb question, but here's what I'm trying to do.

I'm sending a string via serial to a linux console ie: "wget -qO- "http://192.168.1.2/myscript.php"

And it returns something like: "aaa:b ccc:d root@DD-WRT:~#"

I need to a strip off the shell line, break split my string on space, then split the two arrays via ":".

One thing is that it could return "aaa:b ccccccc:d eeee:f gg:h" or "aaa:b", so it has to be dynamic.

After the split, I need to loop thru each of the final array groupings so I can take element[1] and do a switch statement on that, then use element[0] for printing something else out to the console.

Like I said, sorry for the noob question. I'm a PHP developer and it's been years since I've played with C.

Like I said, sorry for the noob question

Two things…

  1. I’ve read your post twice and I cannot find the question.

  2. Does your question have something to do with an Arduino?

I presume that you want the Arduino to parse the output from the php script that runs in response to data sent by the Arduino.

If that is the case, I think you should look into having the php script return only the data that is of interest ("aaa:b ccccccc:d eeee:f gg:h" or "aaa:b").

Then, I'd look into the sscanf function. Using appropriate format options, you can parse the incoming string into 2 numbers and a string.

If the input is "aaa:b", the two numbers would be formed form aaa and b, and the string would be a NULL string.

If the input is "aaa:b ccccccc:d eeee:f gg:h", the two numbers would be formed form aaa and b, and the string would be "ccccccc:d eeee:f gg:h".

In a while loop, keep calling sscanf until you got a NULL string.

Ok let me try to better explain this. I have the Arduino connected to a Linux console. The Arduino sends "wget -qO- “http://192.168.1.2/myscript.php” and the console returns:
“aaa:n aaaa:n
root@DD-WRT:~#”

“a” is alpha-numeric, “n” is an int and each part is divided by a space. “a” should be no long than 12 chars long and I don’t think I will have more than 10 items.

So how do I take the output from the console and get the following array?
a[0][0] = aaa
a[0][1] = n
a[1][0] = aaaa
a[1][1] = n

What are you currently doing with the incoming serial data on the Arduino? Are you storing it in a char array? Is the array properly NULL terminated?

If you have an array, and it is properly NULL terminated, you can use sscanf:

char a[12];
int n;
char rest[128];
sscanf(charArray, "%[^:]%d %[^\0\n]", a, &n, rest);

The first part of the format statement (%[^:]) reads a string that is terminated by a :.

The next part (%d) converts everything that looks like a number to a number, until something in the input string does not look like a number (the space).

The last part ( %[^\0\n]) reads a string that is terminated by a NULL or a carriage return (i.e. the rest of the input string before the root part on the second line).

Do whatever you need to do with a and n. Then, copy rest into charArray, and repeat until rest is a NULL string.

Actually I haven't got any thing in place for the serial reading. I'm doing a \r\n at the end of my string from php.

I'm figuring i would do:

char charArray[512]; int i = 0; while(Serial.available() > 0) { charArray = Serial.read(); * i++;* }

That's a good start. You need to add charArray = '\0'; after the i++; statement, to make it a NULL terminated string. You should do some error checking. If i gets to be 637, you have a problem. Use sscanf on charArray, in a while loop, after charArray is filled.

Ok - It looks like I’m getting some where…

#include <string.h>
#define LED          13
#define SERIAL_SPEED 57600

void setup()
 {
    // Setup on-board LED (Output and On)
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // Set serial to 57600 bps
    Serial.begin(SERIAL_SPEED);

    char charArray[512];
    int i = 0;

    Serial.println("Hello");
    allflush();
    delay(5000);

    if(Serial.available() > 0)
     {
        while(Serial.available() > 0)
         {
           charArray[i] = Serial.read();
           i++;
         }

        charArray[i] = '\0';
   
        char a[12];
        int n;
        char rest[128];

        sscanf(charArray, "%[^:]%d %[^\0\n]", a, &n, rest);

        Serial.println(a);
        Serial.println(n);
     }
    else
     {
        Serial.println("No data.");
     }
 }

void loop()
 {

 }

void allflush()
 {
    delay(100);

    while(Serial.available()>0)
     {
       Serial.flush();
     }
 }

Now if I go into my terminal emulator and do “xxx:2” i get back xxx, but n shows -16419

:-/

What value does sscanf return?

It returns 1

According to the description...

http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/

...this means only one item was stored. In other words, a value was stored in a but not in n or rest.

You might try...

  • Remove the delay
  • (Step #2) Loop until Serial.available() > 0
  • Loop until all characters have been read and stored -OR- a newline is read
  • If a newline has not yet been read, go back to Step #2
  • Ensure charArray is terminated
  • Call sscanf to separate the values

The delay is there to make sure it it gets all the stuff from the serial. I have tested the array for \0 at the end - and it is there. If I print the charArray, everything is there..

I've tried using codepad.org to do simulate this.. I'm getting the same results

void main()
 {
   char charArray[512];
   charArray[0] = 'x';
   charArray[1] = 'x';
   charArray[2] = 'x';
   charArray[3] = ':';
   charArray[4] = '4';
   charArray[5] = '\n';
   charArray[6] = '\0';

   printf(charArray);

   char a[12];
   int n;
   char rest[128];
   
   sscanf(charArray, "%[^:]%d%[^\0\n]", a, &n, rest);

   printf(a);
   printf("\n");
   printf(n);
 }

I pasted this code into a C++ application in Visual Studio, and stepped through it using the debugger. The : terminator is not consumed by the sscanf function, even though it is the delimiter for a. So, after a is extracted, the rest of the string for the format statement to deal with is ":4\n". Since : is not an integer value, parsing fails, and sscanf returns.

Add a : before the %d, to tell sscanf to ignore it, and cnt is now 2, and n is 4.

I changed charArray:

char charArray[512] = "xyz:4 abc:9 def:6\n";

Now, sscanf returns 3, with a = "xyz", n = 4, and rest = "abc:9 def:6\n".

int main()
{
      char charArray[512] = "xyz:4 abc:9 def:6\n";

      printf("%s", charArray);

      char a[12];
      int n;
      char rest[128];

      a[0] = '\0';
      rest[0] = '\0';
      n = 0;
      while(sscanf(charArray, "%[^:]:%d %[^\0\n]", a, &n, rest) > 0)
      {
            printf("a: [%s]\n", a);
            printf("n: %d\n", n);
            printf("rest: [%s]\n", rest);

            charArray[0] = '\0';
            strcpy(charArray, rest);
            rest[0] = '\0';
      }
      return 0;
}

Ok I can get “n” now… but rest is coming back with blank…

#include <string.h>
#define LED          13
#define SERIAL_SPEED 57600

void setup()
 {
    // Setup on-board LED (Output and On)
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // Set serial to 57600 bps
    Serial.begin(SERIAL_SPEED);

    char charArray[512];
    int i = 0;

    Serial.println("Hello");
    allflush();
    delay(5000);

    if(Serial.available() > 0)
     {
        while(Serial.available() > 0)
         {
           charArray[i] = Serial.read();
           i++;
         }

        charArray[i] = '\0';

        char a[12];
        int n;
        char rest[128];

      a[0] = '\0';
      rest[0] = '\0';
      n = 0;

        while(sscanf(charArray, "%[^:]:%d %[^\0\n]", a, &n, rest) > 0)
         {
            Serial.print("charArray: ");
            Serial.print(charArray);
            Serial.print("a: ");
            Serial.println(a);
            Serial.print("n: ");
            Serial.println(n);
            Serial.print("rest: ");
            Serial.println(rest);
            charArray[0] = '\0';
            strcpy(charArray, rest);
            rest[0] = '\0';            
         }
        Serial.print("charArray: ");
        Serial.println(charArray);
     }
    else
     {
        Serial.println("No data.");
     }
 }

void loop()
 {

 }

void allflush()
 {
    delay(100);

    while(Serial.available()>0)
     {
       Serial.flush();
     }
 }

Here’s the test from my terminal emulator.

Hello
xyz:4 abc:9 def:6
charArray: xyz:4 abc:9 def:6
a: xyz
n: 4
rest:
charArray:

Out of wanting to see if I can get it to work, I converted the code to PHP and it works there… But it doesn’t get me any close on the C side…

<?php
$charArray = "xyz:4 abc:9 def:6\n";

printf("%s", $charArray);

$a    = "\0";
$rest = "\0";
$n    = 0;

while(sscanf($charArray, '%[^:]:%d %[^\0\n]', $a, &$n, $rest) > 0)
 {
   printf("a: [%s]\n", $a);
   printf("n: %d\n", $n);
   printf("rest: [%s]\n", $rest);

   $charArray = $rest;
   $rest      = "\0";
 }
?>

Got it to work in ansi C, then had to tweak it…
ANSI C:

int main()
 {
    char charArray[512] = "xyz:4 abc:9 def:6\n";
    
    printf("%s", charArray);

    char a[12];
    int n;
    char rest[128];

    a[0]                = '\0';
    rest[0]             = '\0';
    n                   = 0;

    while(sscanf(charArray, "%[^:]:%d %[^\n]", a, &n, rest) > 0)
     {
       printf("a: [%s]\n", a);
       printf("n: %d\n", n);
       printf("rest: [%s]\n", rest);
       charArray[0] = '\0';
       strcpy(charArray, rest);
       rest[0] = '\0';
    }
   return 0;
 }

Arduino:

#include <string.h>
#define LED          13
#define SERIAL_SPEED 57600

void setup()
 {
    // Setup on-board LED (Output and On)
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // Set serial to 57600 bps
    Serial.begin(SERIAL_SPEED);

    char charArray[512];
    int i = 0;

    Serial.println("Hello");
    allflush();
    delay(5000);

    if(Serial.available() > 0)
     {
        while(Serial.available() > 0)
         {
           charArray[i] = Serial.read();
           i++;
         }

        charArray[i] = '\0';

        char a[12];
        int n;
        char rest[128];

      a[0] = '\0';
      rest[0] = '\0';
      n = 0;

        while(sscanf(charArray, "%[^:]:%d %[^\r]", a, &n, rest) > 0)
         {
            Serial.print("a: ");
            Serial.println(a);
            Serial.print("n: ");
            Serial.println(n);
            strcpy(charArray, rest);
            rest[0] = '\0';
         }

     }
    else
     {
        Serial.println("No data.");
     }
 }

void loop()
 {

 }

void allflush()
 {
    delay(100);

    while(Serial.available()>0)
     {
       Serial.flush();
     }
 }

Since it was the \0 that was causing the havock in the sscanf. In the ansi c, i just looked for \n and on the arduino \r. since a terminal send a \r on return… :-/