extracting an ip address from a long string

Hello everyone,
Ia currently working on a project of getting an IP addresses from a device through Serial communication (RS232 and max3232 adapter) and compering them into addresses I have stored on my Arduino.

When the device is starting up I am sending the data from serial port 1 into a string variable, and print it out on the serial monitor (through serial port 1) I tried getting the data into char array but there are to many characters the device is sending before he start sending the addresses.

The issue is that the device is sending a lot of text among the IP addresses, and I have no clue how would I compare the addresses (Isolate and compare).

The addresses are always sent in a way that before they are displayed, the device is printing " = ", and when he done sending the first address he is starting a new line (n). And again, sending text, after the text " = " and then addresses and then new line.

I read the string commands and examples on the Arduino website, but again no clue. I started to look on other string commands (like: strncpy) but i dont know how to use them in my project.

String txt;

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

void loop() {
  if(Serial1.available()==0){}
  txt = Serial1.readString();
  Serial.println(txt);
}

Example is:
texttext = 000.000.000.0
texttext = 000.00.00.00

Any help would be appreciated, Thanks Ahead.

Strtok

you could use the string tokeniser strtok() with delimiters " =" (plus any others required)
http://www.cplusplus.com/reference/cstring/strtok/

once you find the token texttext the following token is the ip address

Seems like I cant do it with a string,

String txt;
char triger [4]= " = ";
void setup() {
Serial.begin(9600);
Serial1.begin(9600);
}

void loop() { 
  if(Serial1.available()==0){}
  txt = Serial1.readString();
  char *ip;
  ip = strtok(txt, " = ");
//  Serial.println("ip is", ip);
}

test_serial:15:25: error: cannot convert 'String' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'
ip = strtok(txt, " = ");
^
exit status 1
cannot convert 'String' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

No, you can't do it with a string. You need to read it into a char array.

Is there any way of reading a big amount of data into a char array?
From my knowledge, I will need the exact numbers of charterers in order to make it work, or just using:
char txt[] for example.
Again, the text is read thru Serial 1 (I'm using Arduino mega) and will be displayed in Serial 0 monitor.
I don't need to display the text, but I need to store it somewhere right?
Thank you all for you're help.

emribg:
Is there any way of reading a big amount of data into a char array?

depends on the amount of SRAM available and what you mean by a big amount of data.
You could define a static array of sufficient size to hold incomming text strings (how long are your Serial1 strings ?)

char data[2000]={0};

then calling Serial1.read() and store the characters in the array until you get the end of your data (string terminated by /n ??)
then depending on the complexity of your string using strtok() to parse the data, e.g.

#include <stdio.h>
#include <string.h>

int main ()
{
  char recordArray[] ="this is a test texttext = 192.168.0.254";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",recordArray);
  pch = strtok (recordArray," =");
  while (pch != NULL)
  {
    printf ("string found %s \n",pch);
    if (strstr(pch,"texttext") != NULL) {  // IP should be next
            pch = strtok (NULL, " =");
            printf ("IP string %s  ",pch);
            return 0;
           }
     pch = strtok (NULL, " =");
  }
  return -1;
}

gives

Splitting string "this is a test texttext = 192.168.0.254" into tokens:
string found this
string found is
string found a
string found test
string found texttext
IP string 192.168.0.254

if your string is as simple as "this is a test texttext = 192.168.0.254"; you could use strchr() to serach for = knowing the ip follows it

It would be helpful to know the exact specification for the character string. Post a link to the datasheet for this "device".

gfvalvo:
It would be helpful to know the exact specification for the character string. Post a link to the datasheet for this "device".

I'm terribly sorry but I can'y give the device datasheet (I don't remember it).

For answer number 6, if the message contain more lines, perhaps 9 lines before it starts to send the addresses (which by the way come with different text for each address for example: The Ethernet IP Address = xxx.xxx.xxx.xxx etc).
I'm currently not working with the device, i'm simulating it with my PC (Sending data with putty to the Serial1 port on the arduino) so i'm testing the code according to example text.
Would the code still be trigered by the " = " before the addresses are starting to show up (as you can see the pattern) and ends up with a newline?
Example text:
System is Starting...
This is a Test.
This is a Test.
This is a Test.
All the Addresses will displayed in a matter of seconds.
Example For Text Before The Addresses Will Be Displayed.
All addresses are Initializing...
Example for Ethernet IP Number 1 = 111.222.333.444
Example for Ethernet IP Number 2 = 444.555.666.777
Example for Ethernet IP Number 3 = 777.888.999.000
If all Addresses Are OK Print Addresses are OK.
If The Addresses Are NOT OK Print Addresses are NOT OK.
The System is Now Up And Running.

if you incomming text stream only has = before the IP address you scan each line for = if found the IP follows, e.g.

#include <stdio.h>
#include <string.h>

int main ()
{
  char *recordArray[] ={"System is Starting...",
         "This is a Test.",
         "This is a Test.",
         "This is a Test.",
         "This is a Test.",
         "All the Addresses will displayed in a matter of seconds.",
         "Example For Text Before The Addresses Will Be Displayed.",
         "All addresses are Initializing...",
         "Example for Ethernet IP Number 1 = 111.222.333.444",
         "Example for Ethernet IP Number 2 = 444.555.666.",
         "Example for Ethernet IP Number 3 = 777.888.999.000",
         "If all Addresses Are OK Print Addresses are OK.",
         "If The Addresses Are NOT OK Print Addresses are NOT OK.",
         "The System is Now Up And Running."};
  char * pch;
  for(int i=0;i<14;i++ ){
  printf ("\n string \"%s\" : ",recordArray[i]);
  if ((pch = strchr(recordArray[i],'=')) != NULL)
    printf ("IP found %s",pch+1);   // now save the IPaddress
  }
}

gives

 string "System is Starting..." :
 string "This is a Test." :
 string "This is a Test." :
 string "This is a Test." :
 string "This is a Test." :
 string "All the Addresses will displayed in a matter of seconds." :
 string "Example For Text Before The Addresses Will Be Displayed." :
 string "All addresses are Initializing..." :
 string "Example for Ethernet IP Number 1 = 111.222.333.444" : IP found  111.222.333.444
 string "Example for Ethernet IP Number 2 = 444.555.666." : IP found  444.555.666.
 string "Example for Ethernet IP Number 3 = 777.888.999.000" : IP found  777.888.999.000
 string "If all Addresses Are OK Print Addresses are OK." :
 string "If The Addresses Are NOT OK Print Addresses are NOT OK." :
 string "The System is Now Up And Running." :

if you may have other lines which contain = you would need to check for a valid IP address (which would probably be a good idea anyway)

First of all, huge thanks!!!
From what I understand, I need to include the whole text that the Serial1 receive and use it in the *recordArray (Because the text is different from what i gave as an example) is that correct?
And the next part will be comparing the ip addresses to ones I will store in the Arduino (example:
char ip1[20] = "222.333.444.555"; ) and then comparing it to what i get from Serial1 ?

Also, do you know any good website or article so i could learn it and implement those skills myself?
I know that those codes are more "C Style" than what I used to see in Arduino IDE and it kind of confusing to combine those stuff together although it is very similar. (for instance, reading the data from Serial1 into a char array instead of making it reading the addresses from known text message.)

emribg:
From what I understand, I need to include the whole text that the Serial1 receive and use it in the *recordArray "

as the information is received in a loop

  1. read it a line at a time up to the line terminator (probably \n but may be \r)
  2. use strchr() to search the line for an =, if found check for an IP address

for serial input examples have a look at
https://forum.arduino.cc/index.php?topic=396450.0

So I ended up using and testing the Example 3 from the Serial Input Basic code with a little change to the starts with and ends with (Credit to Robin2),

const byte numChars = 900;
char receivedChars[numChars];
char ip1[20]="111.222.33.444";

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
    Serial1.begin(9600);
}

void loop() {
    recvWithStartEndMarkers();
    showNewData();
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '=';
    char endMarker = '\n';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
     if(rc==ip1)
     Serial.println("IP1 is valid");
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

Now I need to compare the addresses (As suggested by horace), but I don't know what to use in order to compare the valid addresses to the received text (rc at the code).
Any suggestions?

after identifing a potential IP address (text following =) you could use sscanf() to extract four integer numbers from the text (if the sscanf fails it is not an IP address) and then compare the four number with those you are looking for

That means i have to copy the text to an int from char and than compare (strcpy and then 'if' for compareson?) Can you please give an example for this?

a small extension to the provious code

#include <stdio.h>
#include <string.h>

int main ()
{
  char *recordArray[] ={"System is Starting...",
         "This is a Test.",
         "This is a Test.",
         "This is a Test.",
         "This is a Test.",
         "All the Addresses will displayed in a matter of seconds.",
         "Example For Text Before The Addresses Will Be Displayed.",
         "All addresses are Initializing...",
         "Example for Ethernet IP Number 1 = 111.222.333.444",
         "Example for Ethernet IP Number 2 = 444.555.666.",
         "Example for Ethernet IP Number 3 = 777.888.999.000",
         "Example for Ethernet IP Number 4 = 777.888.abc.000",
         "If all Addresses Are OK Print Addresses are OK.",
         "If The Addresses Are NOT OK Print Addresses are NOT OK.",
         "The System is Now Up And Running."};
  char * pch;
  for(int i=0;i<14;i++ ){
  printf ("\n string \"%s\" : ",recordArray[i]);
  if ((pch = strchr(recordArray[i],'=')) != NULL) {
    printf ("\n     IP address ??? %s",pch+1);   // now check for valid IPaddress
    int ip1=0, ip2=0, ip3=0, ip4=0 ;
    if(sscanf(pch+1,"%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4)
        printf(" valid IP =  %03d.%03d.%03d.%03d ",ip1, ip2, ip3, ip4);
    else
        printf(" string is not a valid IP address");
  }
  }
}

gives

 string "System is Starting..." :
 string "This is a Test." :
 string "This is a Test." :
 string "This is a Test." :
 string "This is a Test." :
 string "All the Addresses will displayed in a matter of seconds." :
 string "Example For Text Before The Addresses Will Be Displayed." :
 string "All addresses are Initializing..." :
 string "Example for Ethernet IP Number 1 = 111.222.333.444" :
     IP address ???  111.222.333.444 valid IP =  111.222.333.444
 string "Example for Ethernet IP Number 2 = 444.555.666." :
     IP address ???  444.555.666. string is not a valid IP address
 string "Example for Ethernet IP Number 3 = 777.888.999.000" :
     IP address ???  777.888.999.000 valid IP =  777.888.999.000
 string "Example for Ethernet IP Number 4 = 777.888.abc.000" :
     IP address ???  777.888.abc.000 string is not a valid IP address
 string "If all Addresses Are OK Print Addresses are OK." :
 string "If The Addresses Are NOT OK Print Addresses are NOT OK." :

the function result of sscanf() reports the number of scuessful conversions (digital sperated by .) which for a valid IP address must be 4

So if i want it to check for an address that stored in my Arduino data (foe example: char ip1[20]="111.222.33.444")
I need to replace the:

if(sscanf(pch+1,"%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4)

to the address i want to check?
The checking is because the device can send the wrong address some times. thus i need to make sure the address that the device is sending are equals to the ones stored on the Arduino. In other words, the device sending valid addresses, but may send the wrong address.
Sorry for the understatement and thanks for the effort.

the sscanf() gives you the values ip1 ip2 ip3 and ip4
you then compare these with the corresponding values in the valid address you are expecting, e.g. just checking first two values

         int ip1_ok=777, ip2_ok=888;
         if(ip1==ip1_ok && ip2 == ip2_ok) printf(" OK !!!!");

But according to your code i'm only able to check data that i have stored, hence I used the 3rd example of the Serial Input Basic. I need to read and compare the data I receive from serial 1 port on my Arduino mega. In your code, its basically comparing the code I write ahead to another one which is not my intentions.
Again thanks for the huge effort.

emribg:
Now I need to compare the addresses (As suggested by horace), but I don't know what to use in order to compare the valid addresses to the received text (rc at the code).
Any suggestions?

I think a good way would be to store all your "valid addresses" in an array of 'const uint32_t' variables. Then, when a new IP address is received via Serial, copy each of its octets, one at a time, into a (null-terminated) cstring. From there, use atoi() an and bit shifting to create a uint32_t from the IP address. Once you have that, comparing it to the valid addresses in your array is trivial.

EDIT:
Actually, you don't even need to do the copy. atoi() will stop at the fist non-numeric character. Just use strtok() to step through the string with "." as the delimiter. The pointer returned from every strtok() call can be passed to atoi().