Get IP address from string

Hi there!

I'd like to start out with saying i am not facing any issues with the ethernet shield/networking. I am just facing a simple programming issue.
So i made a application that will transfer data between a pc and arduino (what it is is not relevant to the question).
Now the pc sends a command that goes like this: "TRACE_IP=[insert IP here]".
When the arduino receives it i need it to remove the "TRACE_IP=" part so i am just left with the IP number.
And after that i need to separate it again like for example i have an ip of "192.168.159.182" i need it to return 4 integers that contain the first part of the ip, then the next one should get the second part of the ip. etc. so i am then left with "192" "168" "159" "182".
Now i am having problems with splitting this. Oh and i cant just go ahead and make each one 3 characters long since ip addresses can vary in size so sometimes it might be "192.168.159.4" or "10.80.0.145"

Does somebody know the solution? Any help would be appreciated :slight_smile:

My code (that is relevant to the question):

else if ( currentLine.startsWith("TRACE_IP")) {
      // The server send us the IP address we need to traceroute to.
      // Let's get the IP address from the message
      Serial.print("Starting trace");
      currentLine.remove(0, 8);
      Serial.print(currentLine);
     /* int Parts[4] = {0,0,0,0};
      int Part = 0;
      for ( int i=0; i<currentLine.length(); i++ )
      {
        char c = currentLine[i];
        if ( c == '.' )
        {
          Part++;
          continue;
        }
        Parts[Part] *= 10;
        Parts[Part] += c - '0';
      }
      */ //this code doesn't work correctly, the beginning is correct but the last one it fails at.
      IPAddress ip(Parts[0], Parts[1], Parts[2], Parts[3] );
      delay(500);
      ICMPEchoReply echoReply = ping(ip, 1, 5);
      {
    sprintf(buffer,
            ReplyMessage, // Defined in strings.c
            echoReply.data.seq,  // sequence is always 0 when BAD_RESPONSE status
            echoReply.addr[0],
            echoReply.addr[1],
            echoReply.addr[2],
            echoReply.addr[3],
            REQ_DATASIZE,
            millis() - echoReply.data.time, // time is working for both PING and TraceRoute (TLL=0) router response
            
            
            echoReply.ttl,   // TTL equals set TTL when TraceRoute(TLL=0) router response
            echoReply.status); // Equals 0 for Ping and 3 for TraceRoute(TLL=0) router response
    }
    client.print("TRACE_RESULTS"); //Command for the server to know that the next data it receives is the traceroute
    client.print(buffer);
      currentLine = "";
      }
    }

PS. "currentLine" is the incoming line from the PC, it is reported as a whole

Don't use Strings. Stick to plain char buffers and Use strtok() and atoi() to segment and parse your input

(See this discussion where I provided a code sample to parse integers - answer #5 will help as well)

PS/ you don't need an array of int to store your IP numbers, the byte type (0 to 255) is enough

Or use sscanf:

  const char * str = "192.168.1.2";
  uint8_t ip[4];
  sscanf(str, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);

Pieter

sscanf() would work but that adds a lot of code to your program

J-M-L:
sscanf() would work but that adds a lot of code to your program

True, on an UNO or Leonardo, I'd probably use strtok and atoi. If you have enough resources available, like on a Mega, ARM or ESP board, I think sscanf is easier than having to implement it yourself.

Pieter

Yep - or if your program is really small then sure why not use more memory that's fine - but it is good to know other technics in case memory becomes a challenge

Sadly i am seriously desperate to save those last few bytes since i am using 95% of the programming storage and 74% RAM (but it is more like 99% since the arduino would just stop working after 75%)
I was so desperate i completely stripped a library so i would get around 2KB of free space again but even that is used now. So i'll probably need some tips on saving RAM and programming space too :confused:

In that case, how did you do with the suggestion in reply #4?

So i added

 const char * str = "192.168.1.2";
  uint8_t ip[4];
  sscanf(str, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);

and modified it a bit so it would work with the code but sadly another issue occurred. I only have 10 BYTES (Literally) left of programming storage :o .
So i need another piece of code that will split it into 4 pieces.
I only need the splitting part since i already removed the command that goes before the IP address that is send by the pc, the IP address is inside currentLine

Also in reply #4 i won't think that will do what i need it to do, i am probably wrong tho

CrazyVito11:
Sadly i am seriously desperate to save those last few bytes since i am using 95% of the programming storage and 74% RAM (but it is more like 99% since the arduino would just stop working after 75%)

The compiler only tells you about RAM used by global variables etc. Local variables and dynamically allocated memory are not included in that 74%.

I think you need to reconsider your board choice and get something with more memory that's better suited for demanding things like networking.

CrazyVito11:
So i added

 const char * str = "192.168.1.2";

uint8_t ip[4];
  sscanf(str, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]);



and modified it a bit so it would work with the code but sadly another issue occurred. I only have 10 BYTES (Literally) left of programming storage :o .
So i need another piece of code that will split it into 4 pieces.
I only need the splitting part since i already removed the command that goes before the IP address that is send by the pc, the IP address is inside currentLine

Also in reply #4 i won't think that will do what i need it to do, i am probably wrong tho

The point was that you should NOT use sscanf when low on memory.

Pieter

Simple parsing code would be something like this.

int intval = 0 ;  // temporary for building up value on the fly
byte part = 0 ; // index into ip_addr
byte ip_addr [4] ;

int i = 0 ;
while (true)
{
  if (buf[i] == '.' || buf[i] == 0)  // part separator / end of string
  {
    ip_addr [part++] = intval ;  // store next byte
    if (buf[i] == 0 || parts == 4)  // done if 4 parts parsed or end of string
      break ;
    intval = 0 ;
  }
  else if ('0' <= buf[i] && buf[i] <= '9')
  {
    intval = intval * 10 + buf[i]-'0' ;  // build up value from decimal digits.
    if (intval > 255)
      break ;
  }
  else
    break ;
  i++ ;  // step to next char
}
if (parts == 4)
  // have a valid result...
else
  // bad string

Why don't you go with my recommendation?

IPAddress ip;
if (ip.fromString(str)) {   // str = char * or String
  // it is a valid IP address
}

J-M-L: I did but that used too much storage
oqibidipo: That sadly it didn't work, I checked it with the arduino serial monitor, with my server and even with wireshark but it just doesn't do anything. but when i force an ip (hard code it in) it does work so there is something wrong with splitting the IP from the string.

I am now testing this on a MEGA2560 but later i'll still try to put it on a UNO since i already ordered 3 of them from china (not that it is that expensive, but it is just a waste since i am not going to use that many of them) Of course if it just isn't possible to put it on a UNO i'll just order 3 arduino mega's from china (I'm sorry Arduino :frowning: )

An UNO has four times less RAM then a MEGA, so that probably won't work at all. It has much less flash as well.

Pieter

PieterP:
An UNO has four times less RAM then a MEGA, so that probably won't work at all. It has much less flash as well.

Pieter

I guess i'll just have to order some mega's then :confused:
It does kinda suck that it doesn't fit on a uno

CrazyVito11:
oqibidipo: That sadly it didn't work, I checked it with the arduino serial monitor, with my server and even with wireshark but it just doesn't do anything. but when i force an ip (hard code it in) it does work so there is something wrong with splitting the IP from the string.

Is there something in the string after the IP address, including CR/LF?
IPAddress::fromString() returns false if there is anything but numbers and dots.

oqibidipo:
Is there something in the string after the IP address, including CR/LF?
IPAddress::fromString() returns false if there is anything but numbers and dots.

That is a good one!
I think it probably will since i send a line from my computer so it will probably add a new line to it.
How can i check or better yet remove the NL when the string contains it?

Also i have made up my mind of getting a MEGA, i'm going to do it differently. The UNO's will just be a client, no display at all. This reduced the size immediately down to only 55% of the program memory :o.

Using the String class is a bad idea...

oqibidipo:
Is there something in the string after the IP address, including CR/LF?
IPAddress::fromString() returns false if there is anything but numbers and dots.

I don't think it is a CR or LF issue since i had to force the server application to send it and then you would immediately see it on the serial monitor. So something else is going wrong