Go Down

Topic: Trying to Parse serial string and sending return string (Read 2002 times) previous topic - next topic

Bicycler

Apr 17, 2012, 03:42 am Last Edit: Apr 17, 2012, 05:42 am by Nick Gammon Reason: 1
I have been working on a script to interface my arduino to a serial device sending TAP (Telocator Alphanumeric Protocol). I am testing my code using a terminal program that can send scripts. I am able to send and recieve strings, but I'm hitting a road block trying to figure out how to parse a string coming from the termial program. Example TAP string might look like <STX>101<CR>TEST PAGE><CR><ETX>32><CR> and I would like to parse the 101 or TEST PAGE and based on that send out another string from arduino, possibly <CR><ESC><EOT><CR>. My code looks like this so far. I am also attaching a screen shot of what the debug window looks like after sending a script from the terminal program. The following link is to a previous post that helped get me started with the code. Greatly appreciate help or comments on the code. http://arduino.cc/forum/index.php/topic,99198.0/topicseen.html

Code: [Select]
/*===========================  

Modified original code by Fayaz Kadir http://fayazkadir.com/blog/?p=2291

DESCRIPTION: If you send a string starting with "CR" and ending with "ESC",
the Arduino responds back with "$Y" for valid data string, or $N for invalid data string.  

============================*/
 #define NUL 0
 #define SOH 1
 #define STX 2
 #define ETX 3
 #define EOT 4
 #define ACK 6
 #define CR  13
 #define ESC 27
 #define ID "ID="
 #define SP  32
 #include <SoftwareSerial.h>
  // software serial #1: TX = digital pin 2, RX = digital pin 3
 SoftwareSerial portOne(2, 3);
 char string[128];
 char string1[6]= {0x0D,0x49,0x44,0x3D,'\n'}; //[CR][ID=]
 char string2[] ={0x02,0x31,0x30,0x31,0x0D,0x54,0x45,0x53,0x54,0x20,0x50,0x41,0x47,0x45,
                 0x0D,0x03,0x33,0x32,0x0D}; //[STX][101][CR][TEST][SP][CR][ETX][32][CR]
 int i=0;  
 int string_len;  
 char inByte;  
 int last_inByte;  

 void setup() {  
  portOne.begin(9600); //INTIALISING THE SERIAL PORT  
  Serial.begin(9600);
 }  
 void loop()  // LOOP FUNCTION  
 {  
 inByte = portOne.read();  
 string_len=0;  
 if (inByte == 13) read_serial();  // If Start of line (CR) is found, call read_serial() function  
 }  
 void read_serial()  // FUNCTION FOR READING THE SERIAL MESSAGE  
 {  
 Serial.println ("CR FOUND and reading");  // THE SOL (Start of Line) found notice.  
 Serial.print("READ :CR\n");  //Saying that it has read "!" on the serial port
 portOne.print("\n");
 portOne.write(ID);
 portOne.write(CR);
 while (inByte!= (ESC)) // As long as EOL not found, keep reading  
 if (portOne.available() > 0) // if new data is available  
 {inByte = portOne.read(); // Read new byte  
 Serial.print("READ : "); // Display the new byte  
 string[string_len] = inByte; // Save the data in a character array  
 Serial.println(string[string_len]); // Print the characters that was recieved  
 string_len++;}
 
 else if (inByte== (SP))  
 {Serial.println("EOL not available, data string invalid"); // If EOL not in the string  
 Serial.println("$N"); //FAIL SIGNATURE
    break;  
 }  
 if (inByte == (ESC))
 {  
 Serial.println ("eol FOUND, and full string was ");  // Echoes Success Message  
 Serial.println ("$Y"); //SUCCESS SIGNATURE  
 for (i=0;i<(string_len-1);i++) Serial.print(string[i]);
 portOne.write(string1);
 portOne.write(string2);
 Serial.print("\n");  
 }  
}


Moderator edit: [code] ... [/code] tags added. (Nick Gammon)

PaulS

You got a carriage return from portOne, so you call read_serial. Why isn't the function called read_portOne?

The first thing you do in read_serial() is send stuff to portOne. Why? The device on the other end is already sending you data.

You really need to work on making your code readable. { followed immediately by code makes it very hard to match up a closing }.

Code: [Select]
if (portOne.available() > 0) // if new data is available 
  {
  }
  else if (inByte== (SP)) 
  {
  } 

In what possible way do these go together?

What do the () around SP and ESC contribute?

You have an array called string. It is NOT a string. A string is a NULL terminated array of chars. Nary a NULL in sight in your code. Why not?

Bicycler

#2
Apr 18, 2012, 04:20 am Last Edit: Apr 18, 2012, 05:56 am by Nick Gammon Reason: 1

You got a carriage return from portOne, so you call read_serial. Why isn't the function called read_portOne?

The first thing you do in read_serial() is send stuff to portOne. Why? The device on the other end is already sending you data.


Your absolutely right. I will change the code to read_portOne and also clean up the rest of the code. The reason I'm sending data to portOne is simply to see the exchange of data between the two serial ports. In the TAP protocol, when the sending device sends a Carriage return every 1-2 seconds until it recieves "ID=" from (in my experiment) the Arduino. This exchange continues seceral times until the sending device sends the actual data message it has.



Code: [Select]
if (portOne.available() > 0) // if new data is available  
 {
 }
 else if (inByte== (SP))  
 {
 }  

In what possible way do these go together?


They don't, just experimenting with the code. If the space bar is pressed, or 0x20 charachter is recieved the "Invalid" message is sent to Serial.print.
I removed the ( ) do nothing, I removed them from the code.


You have an array called string. It is NOT a string. A string is a NULL terminated array of chars. Nary a NULL in sight in your code. Why not?

Well, this part I'm not sure about. I can rename the array to something other than string, but I would appreciate any help with
for (i=0;i<(string_len-1);i++) Serial.print(string);
and parsing information from this data, not just sending it to Serial.print.


Moderator edit: Fixed up nested quotes. (Nick Gammon)

PaulS

Quote
but I would appreciate any help with
for (i=0;i<(string_len-1);i++) Serial.print(string);
and parsing information from this data, not just sending it to Serial.print.

The point is that you can't use any of the string functions, like strtok() for parsing, until you have a string. All you have now is a non-NULL terminated array of characters called string, which is not a string. Rename the array to buffer, to eliminate the confusion.

Then, after each character is added, append a NULL, so you have a NULL terminated array of chars, also known as a string, so that you CAN use strtok(), strlen(), and the other string handling functions.

maccoa

hello you can read this .

the skect print on serial1 -> read on serial2 ->strtok the string -> put the result in a arrray -> when serial2 read $ -> serial print the entire array.

the sketch is in dev and i am a newbie sorry for the "bordel" but if it can help you  :D
Code: [Select]
#include <Flash.h>  // Flash lib for dev

char indata[35];  // to store incoming data
byte index = 0;
char str[35];   // string to copy inData
int valbrut, ind, divi;  // nbs entier
float val;               // nbs virgule
int errors = 0;
char time[]= "13:13/17/04/12"; //for dev


float storedata[28] = { }; // tableau de de type float

void setup()
{
Serial.begin(57600);        // usb to pc
Serial1.begin(57600);      // to simul send datta
Serial2.begin(57600);      // receive data
}

void loop(){
// string array for dev
FLASH_STRING_ARRAY(frocom2, PSTR("$ Prêt;0019;1;1;zst;\r"), PSTR("Kesseltemp.;0126;2;2;°C;\r"), PSTR("Abgastemp.;0060;3;1;°C;\r"), PSTR("Abgastemp S;0070;11;1;°C;\r"), PSTR("Kesselstrg ;0091;4;1;%;\r"),
PSTR("Primärluft ;0000;5;1;%;\r"), PSTR("Rest O2 ist;0000;6;10;%;\r"), PSTR("O2 Regler  ;0100;7;1;%;\r"), PSTR("Sekundärluft;0000;8;1;%;\r"), PSTR("Saugzug Soll;0000;9;1;%;\r"), PSTR("SaugzugIst;0000;10;1;U;\r"),
PSTR("Einschub Ist;0000;12;1;%;\r"), PSTR("O2 Regler Pell ;0031;13;1;%;\r"), PSTR("Füllstand: ;20700;14;207;%;\r"), PSTR("Ansauggeschw.;0454;15;100;m/s;\r"), PSTR("Strom Austrags;0595;16;1000;A;\r"),
PSTR("Fühler 1;0149;17;2;°C;\r"), PSTR("Kesselsoll ;0080;18;2;°C;\r"), PSTR("Pufferoben ;0000;20;2;°C;\r"), PSTR("Pufferunten ;0000;21;2;°C;\r"), PSTR("Pufferpumpe ;8192;22;1;%;\r"), PSTR("Boiler 1;0124;23;2;°C;\r"),
PSTR("Vorlauf 1;0036;24;2;°C;\r"), PSTR("HK Pumpe 1;0000;26;1; ;\r"), PSTR("HK Pumpe 2;0000;27;1; ;\r"), PSTR("Aussentemp;0030;28;2;°C;\r"), PSTR("Kollektortemp;0000;29;2;°C;\r"),
PSTR("Betriebsstunden;1221;30;1;h;\r"), PSTR("Fehler;Kein Fehler ;99;1;storedata; \r"));
// serial1 send data every 0.5sec for dev
frocom2[0].print(Serial1); Serial1.println();
delay(500);
frocom2[1].print(Serial1); Serial1.println();
delay(500);
/*frocom2[2].print(Serial1); Serial1.println();
delay(1000);
frocom2[3].print(Serial1); Serial1.println();
delay(1000);
frocom2[4].print(Serial1); Serial1.println();
delay(1000);
frocom2[5].print(Serial1); Serial1.println();
delay(1000);
frocom2[6].print(Serial1); Serial1.println();
delay(1000);
frocom2[7].print(Serial1); Serial1.println();
delay(1000);
frocom2[8].print(Serial1); Serial1.println();
delay(1000);
frocom2[9].print(Serial1); Serial1.println();
delay(1000);
frocom2[10].print(Serial1); Serial1.println();
delay(1000);
frocom2[11].print(Serial1); Serial1.println();
delay(1000);
frocom2[12].print(Serial1); Serial1.println();
delay(1000);
frocom2[13].print(Serial1); Serial1.println();
delay(1000);
frocom2[14].print(Serial1); Serial1.println();
delay(1000);
frocom2[15].print(Serial1); Serial1.println();
delay(1000);
frocom2[16].print(Serial1); Serial1.println();
delay(1000);
frocom2[17].print(Serial1); Serial1.println();
delay(1000);
frocom2[18].print(Serial1); Serial1.println();
delay(1000);
frocom2[19].print(Serial1); Serial1.println();
delay(1000);
frocom2[20].print(Serial1); Serial1.println();
delay(1000);
frocom2[21].print(Serial1); Serial1.println();
delay(1000);
frocom2[22].print(Serial1); Serial1.println();
delay(1000);
frocom2[23].print(Serial1); Serial1.println();
delay(1000);
frocom2[24].print(Serial1); Serial1.println();
delay(1000);
frocom2[25].print(Serial1); Serial1.println();
delay(1000);
frocom2[26].print(Serial1); Serial1.println();
delay(1000);
frocom2[27].print(Serial1); Serial1.println();
delay(1000);
frocom2[28].print(Serial1); Serial1.println();
delay(500);*/
    while(Serial2.available() > 0)
   {
     
char aChar = Serial2.read();
if(aChar == '\n')           // cariage return is the end of  one data
{
                            // End of record detected. Time to parse

strcpy(str,indata);             // copy inData into str



//Serial.print("str=");               // for dev
//Serial.println(str);
//Serial.print("indata=");
//Serial.println(indata);
//Serial.println();


    char *chpt = strtok(str, ";");
    if (chpt == NULL) {
        Serial.println("First strok returns NULL");
        ++errors;
    }

    if (errors == 0) {
        chpt = strtok(NULL, ";");
        if (chpt == NULL) {
            Serial.println("Second strok returns NULL");
            ++errors;
        }
        else {
            valbrut = atof(chpt);
        }
    }

    if (errors == 0) {
        chpt = strtok(NULL, ";");
        if (chpt == NULL) {
            Serial.println("Third  strok returns NULL");
            ++errors;
        }
        else {
            ind = atof(chpt);
        }
    }

    if (errors == 0) {
        chpt = strtok(NULL, ";\r\n");
        if (chpt == NULL) {
            Serial.println("Fourth strok returns NULL");
            ++errors;
            // This is an input error: do something to handle it.
        }
        divi = atof(chpt);
    }
    if (errors == 0)
      val=valbrut/divi;
     
     /*   Serial.print(ind);
        Serial.print(";");
        Serial.print(val);
        Serial.println();*/
   


   index = 0;
   indata[index] = NULL;
 
}
else
{
  indata[index] = aChar;
   index++;
   indata[index] = '\0'; // Keep the string NULL terminated
        storedata[ind] = val;
  if(aChar == '$')
  {
Serial.print(time); //for dev
Serial.print(":");
/*Serial.print(storedata[0]);
Serial.print(":");*/
Serial.print(storedata[1]);
Serial.print(":");
Serial.print(storedata[2]);
Serial.print(":");
Serial.print(storedata[3]);
Serial.print(":");
Serial.print(storedata[4]);
Serial.print(":");         
Serial.print(storedata[5]);
Serial.print(":");   
Serial.print(storedata[6]);
Serial.print(":");
Serial.print(storedata[7]);
Serial.print(":");
Serial.print(storedata[8]);
Serial.print(":");
Serial.print(storedata[9]);
Serial.print(":");
Serial.print(storedata[10]);
Serial.print(":");
Serial.print(storedata[11]);
Serial.print(":");
Serial.print(storedata[12]);
Serial.print(":");
Serial.print(storedata[13]);
Serial.print(":");
Serial.print(storedata[14]);
Serial.print(":");
Serial.print(storedata[15]);
Serial.print(":");
Serial.print(storedata[16]);
Serial.print(":");
Serial.print(storedata[17]);
Serial.print(":");
Serial.print(storedata[18]);
Serial.print(":");
Serial.print(storedata[19]);
Serial.print(":");
Serial.print(storedata[20]);
Serial.print(":");
Serial.print(storedata[21]);
Serial.print(":");
Serial.print(storedata[22]);
Serial.print(":");
Serial.print(storedata[23]);
Serial.print(":");
Serial.print(storedata[24]);
Serial.print(":");
Serial.print(storedata[25]);
Serial.print(":");
Serial.print(storedata[26]);
Serial.print(":");
Serial.print(storedata[27]);
Serial.print(":");
Serial.print(storedata[28]);
Serial.print(":");
Serial.println();

  }
}
   }
}



My eyes hurt looking at this. Can't you at least use a for loop?

Instead of:

Code: [Select]

        Serial.print(storedata[1]);
        Serial.print(":");
        Serial.print(storedata[2]);
        Serial.print(":");
        Serial.print(storedata[3]);
        Serial.print(":");
        Serial.print(storedata[4]);
        Serial.print(":");         
        Serial.print(storedata[5]);
        Serial.print(":");   
        Serial.print(storedata[6]);
        Serial.print(":");
...
        Serial.print(storedata[27]);
        Serial.print(":");
        Serial.print(storedata[28]);
        Serial.print(":");


Do:

Code: [Select]

  for (int i = 1; i <= 28; i++)
    {
    Serial.print (storedata [i]);   
    Serial.print (":");
    }


Ditto further up for frocom2.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Bicycler

Then, after each character is added, append a NULL, so you have a NULL terminated array of chars, also known as a string, so that you CAN use strtok(), strlen(), and the other string handling functions.
[/quote]

Does this look better? I included buffer[bufferindex] = '\0'. Am I on track with NULL terminating the array?

#define NUL 0
  #define SOH 1
  #define STX 2
  #define ETX 3
  #define EOT 4
  #define ACK 6
  #define CR  13
  #define ESC 27
  #define ID "ID="
  #define SP  32
  #include <SoftwareSerial.h>
   // software serial #1: TX = digital pin 2, RX = digital pin 3
  SoftwareSerial portOne(2, 3);
  char buffer[128];
  char string1[6]= {0x0D,0x49,0x44,0x3D,'\n'}; //[CR][ID=]
  char string2[] ={0x02,0x31,0x30,0x31,0x0D,0x54,0x45,0x53,0x54,0x20,0x50,0x41,0x47,0x45,
                  0x0D,0x03,0x33,0x32,0x0D}; //[STX][101][CR][TEST][SP][CR][ETX][32][CR]
  int i=0; 
  int bufferindex = 0; 
  char inByte; 
  int last_inByte; 

  void setup()
  { 
   portOne.begin(9600);                     //INTIALISING THE SERIAL PORT 
   Serial.begin(9600);
  } 
  void loop()                               // LOOP FUNCTION 
  { 
  inByte = portOne.read(); 
  bufferindex=0; 
  if (inByte == 13) read_portOne();         // If Start of line (CR) is found, call read_portOne() function 
  } 
  void read_portOne()                       // FUNCTION FOR READING THE SERIAL MESSAGE 
  { 
  Serial.println ("CR FOUND and reading");  // THE SOL (Start of Line) found notice. 
  Serial.print("READ :CR\n");               //Saying that it has read "CR" on the serial port
  //portOne.print("\n");
  portOne.write("\n"ID);                    // Send "ID=" from arduino software serial port.
  portOne.write(CR);                        // Send "CR" from arduino software serial port.
  while (inByte!= ESC)                      // As long as Escape key not found, keep reading 
  if (portOne.available() > 0)              // if new data is available
  {
  inByte = portOne.read();                  // Read new byte
  buffer[bufferindex] = '\0';

  Serial.print("READ : ");                  // Display the new byte 
  buffer[bufferindex] = inByte;             // Save the data in a character array 
  Serial.println(buffer[bufferindex]);      // Print the characters that was recieved 
  bufferindex++;
 
  }
   if (inByte == ESC)
  { 
  Serial.println ("eol FOUND, and full string was ");  // Echoes Success Message 
  Serial.println ("$Y");                    //SUCCESS SIGNATURE 
  for (i=0;i<(bufferindex-1);i++) Serial.print(buffer);
  portOne.write(string1);
  portOne.write(string2);
  Serial.print("\n"); 
  } 
}

PaulS

Quote
Does this look better?

No. Was there some part of AFTER that you didn't understand?
Code: [Select]
void read_portOne()                       // FUNCTION FOR READING THE SERIAL MESSAGE
{
  Serial.println ("CR FOUND and reading");  // THE SOL (Start of Line) found notice.
  Serial.print("READ :CR\n");               //Saying that it has read "CR" on the serial port

  portOne.write("\n");
  portOne.write(ID);                    // Send "ID=" from arduino software serial port.
  portOne.write(CR);                        // Send "CR" from arduino software serial port.

  while (inByte!= ESC)
  {                      // As long as Escape key not found, keep reading
    if (portOne.available() > 0)              // if new data is available
    {
       inByte = portOne.read();                  // Read new byte

       buffer[bufferindex] = inByte;             // Save the data in a character array
       bufferindex++;
       buffer[bufferindex] = '\0';

       Serial.print("READ : ");                  // Display the new byte
       Serial.println(inByte);      // Print the characters that was recieved
    }

    if (inByte == ESC)
    {
       Serial.println ("eol FOUND, and full string was ");  // Echoes Success Message
       Serial.println ("$Y");                    //SUCCESS SIGNATURE
       Serial.print(buffer);
       portOne.write(string1);
       portOne.write(string2);
       Serial.print("\n");
    }
  }
}

Bicycler

Thanks PaulS. I am gaining a better understanding of the '\0' character. Still need to work on it though.
Thanks maccoa for the example of strtok.

Go Up