parse string and if statements

Hi i am trying to separate an incoming string (from python running on a pi) i have already been able to do one statement and implement it in my code but i'm now trying to send multiple statements and drop them into the code but its not working, i have established that i am receiving the data through the serial monitor so i think i need to tweak my code, I'm hoping someone will be able to help me. My arduino code is:

#include <DmxMaster.h>

String st, channel, msgvalue;
int val1;
int val2;
int val3;
int val4;
int val5;
int valint;


void setup() {
   pinMode(13, OUTPUT);
   Serial.begin(9600); // opens serial port, sets data rate to 9600 bps

}

void loop() {
  DmxMaster.write(1, val1);
  DmxMaster.write(2, val2);
  DmxMaster.write(3, val3);
  DmxMaster.write(4, val4);
  DmxMaster.write(5, val5);

Serial.println(st);


  if (Serial.available())
  {
     st = String("");
     while(Serial.available())
     {
        st = st + char(Serial.read());
        delay(1);
     }

     parseData();
     //Serial.print(st);
     //Serial.print("\t");
     //Serial.print(msgChar);
     //Serial.print("\t");
     //Serial.println(val);

  }
  
     if (channel=="c1"){
     val1 = valint;
     }
     else if (channel=="c2"){
     val2= valint;
     }
     else if (channel=="c3"){
     val3 = valint;
     }
     else if (channel=="c4"){
     val4 = valint;
     }
     else if (channel =="c5"){
     val5 = valint;
     }  
}


void parseData()
{
   if(st.indexOf(":")>=0)
   {
     channel = st.substring(0,(st.indexOf(":")));
     msgvalue = st.substring(st.indexOf(":")+1);
     valint = (msgvalue.toInt());
   }
   else
   {
     channel = st;
     msgvalue = 0;
   }
}

my python code is as follows:

import serial

ser = serial.Serial('/dev/ttyAMA0'.9600)

while True:
       command = raw_input("enter level")
       if command == '1':
            ser.write('c1:255')
            ser.write('c2:0')
            ser.write('c3:0')
            ser.write('c4:255')
            ser.write('c5:0')

This

 if (Serial.available())
  {
     st = String("");
     while(Serial.available())
     {
        st = st + char(Serial.read());
        delay(1);
     }

wont get you the whole string as serial read is much faster than the serial link. You nedd to add an end of string mark and look for that!

Mark

Thanks and just to be clear (i am a noob) but your saying ditch the delay and use an end of string mark?
If so how would I do that? Within my python code would I simply add ser.write('\n') to the end?
Thanks

'\n' might work, but it is sometimes two characters, so it can get confusing. Something like '*' or '&' might work better.

First, I'd get rid of the String class and use a char array. If the Serial device terminates the stream with a newline character ('\n'), like the Serial monitor does, then you could use something like:

const int MAXSIZE = 10;      // Whatever size you need...
int index = 0;
char myArray[MAXSIZE];

while (Serial.available() ) {
   myArray[index]  = Serial.read();
   if (myArray[index] == '\n') {     // The serial device terminated the input stream
      myArray[index] = '\0';     // Replace newline with null so we can treat it like a string
      break;
   }
   index++;               // Do this if stream still sending stuff...
}

I haven't tried this, but something close to this should work for you.

Ok, just tried the Serial.readStringUntil('*')
and now all i get is the letter c
so i will now try the array method, however if i use the array method how do i split the data up and how do i get the data into a variable so i can drop it into the DMXmaster part?

Check out the old reliable str*() C functions in string.h. In this case, strtok().

I'm still struggling with this
I am sending the following via serial to the arduino:

c1:255c2:0c3:0c4:255c5:0

i need to separate this into 5 variables, so it will eventually become

val1=255
val2=0
val3=0
val4=255
val5=0

so my first step would be to separate the incoming serial data into

c1:255
c2:0
c3:0
c4:255
c5:0

then to parse the data so that it drops the correct integer into the correct variable so the int in c1 becomes val1 etc. So essentially maybe i need to parse the data twice? is that possible?

Can someone give me an example of how to do this? I've played with econjack's response but got nowhere

I assume that there is a colon between 255 and c2.

Use strtok() with ':' as the separator.

Feed the first field "c1" into an ifelse chain that looks for "c1", "c2"...
If you find "c1" get the next field, convert it to int and store it as appropriate.

But in this case, if you always get "c1", "c2".. in order, just ignore those fields and stuff the values into the appropriate place.

Thats what i originally tried but it didn't work :-s this was my original code

#include <DmxMaster.h>

String st, channel, msgvalue;
int val1;
int val2;
int val3;
int val4;
int val5;
int valint;


void setup() {
   pinMode(13, OUTPUT);
   Serial.begin(9600); // opens serial port, sets data rate to 9600 bps

}

void loop() {
  DmxMaster.write(1, val1);
  DmxMaster.write(2, val2);
  DmxMaster.write(3, val3);
  DmxMaster.write(4, val4);
  DmxMaster.write(5, val5);

Serial.println(st);


  if (Serial.available())
  {
     st = String("");
     while(Serial.available())
     {
        st = st + char(Serial.read());
        delay(10);
        Serial.readStringUntil('*');
     }

     parseData();
     //Serial.print(st);
     //Serial.print("\t");
     //Serial.print(msgChar);
     //Serial.print("\t");
     //Serial.println(val);

  }
  
     if (channel=="c1"){
     val1 = valint;
     }
     else if (channel=="c2"){
     val2= valint;
     }
     else if (channel=="c3"){
     val3 = valint;
     }
     else if (channel=="c4"){
     val4 = valint;
     }
     else if (channel =="c5"){
     val5 = valint;
     }  
}


void parseData()
{
   if(st.indexOf(":")>=0)
   {
     channel = st.substring(0,(st.indexOf(":")));
     msgvalue = st.substring(st.indexOf(":")+1);
     valint = (msgvalue.toInt());
   }
   else
   {
     channel = st;
     msgvalue = 0;
   }
}

Sorry, I don't do Strings. No disparagement implied, just an old C guy.

Put the colon back between each data items, read the serial input into a null terminated array of chars until you get a newline character then use strtok() to split the data at the colons. I suggest that you put the parsed data into 2 arrays, one for channel numbers and one for values, then you can do the splitting using strtok() in a for loop to keep things neat and tidy.

Ok, so i can get the colon back between each piece of data but the rest is still boggling me, do you have an example? i have been looking at the strtok() example in the arduino cookbook but i still don't understand it. sorry to be such a novice and thanks for your help so far!

Something to play with. I am sure that this is not the best way to do this, but it is a start

char inData[] = "c1:255:c2:0:c3:0:c4:255:c5:0";
char* outData;

void setup() 
{
  Serial.begin(115200);

  outData = strtok(inData, ":");
  Serial.print(outData);
  Serial.print("\t");
  outData = strtok(NULL, ":");
  Serial.println(outData);

  for (int i = 0; i < 4; i++)
  {
    outData = strtok(NULL, ":");
    Serial.print(outData);
    Serial.print("\t");
    outData = strtok(NULL, ":");
    Serial.println(outData);
  }
}

void loop() 
{
}

Instead of printing the output as it is split from the input you could put it into variables to be used later.

Here is the same principle used to save the output to 2 arrays.

char inData[] = "c1:255:c2:230:c3:100:c4:205:c5:10";
char* channels[5];
char* values[5];

void setup() 
{
  Serial.begin(115200);

  channels[0] = strtok(inData, ":");
  Serial.print(channels[0]);
  Serial.print("\t");
  values[0] = strtok(NULL, ":");
  Serial.println(values[0]);

  for (int i = 1; i < 5; i++)
  {
    channels[i] = strtok(NULL, ":");
    Serial.print(channels[i]);
    Serial.print("\t");
    values[i] = strtok(NULL, ":");
    Serial.println(values[i]);
  }
}

void loop() 
{
}

Thanks a lot! I will give them ago tomorrow :slight_smile:

Hi i am trying to separate an incoming string (from python running on a pi) i have already been able to do one statement and implement it in my code but i'm now trying to send multiple statements and drop them into the code but its not working, i have established that i am receiving the data through the serial monitor so i think i need to tweak my code, I'm hoping someone will be able to help me

If you have control over the sending code, then incorporate a delimiter to indicate the data packets you want to capture (is the desired data packet the "c1:255:c2:230:c3:100:c4:205:c5:10" string?). Once you capture the data packet, The string functions are pretty simple to work with to extract what you want. Below is some test code using a comma , as a delimiter that captures a data packet into a String, then extracts some desired data.

//zoomkat 3-5-12 simple delimited ',' string  
//from serial port input (via serial monitor)
//and print result out serial port

String readString, substring;
//String servo1;
int loc; 

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like AA BB01/10/2014 CC12:23:25 DD32.2 EE5432 FF54.35,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    //if (c == '\n') {  //looks for end of data packet marker

    if (c == ',') {
      Serial.println(readString); //prints string to serial port out
      //do stuff      
      loc = readString.indexOf("BB");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+12);
      Serial.print("date is: ");
      Serial.println(substring);

      loc = readString.indexOf("CC");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+11);
      Serial.print("time is: ");
      Serial.println(substring);

      loc = readString.indexOf("DD");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+6);
      Serial.print("DD is: ");
      Serial.println(substring);

      loc = readString.indexOf("EE");
      //Serial.println(loc);
      substring = readString.substring(loc+2, loc+6);
      Serial.print("date is: ");
      Serial.println(substring);

      loc = readString.indexOf("FF");
      //Serial.println(loc);
      substring = readString.substring(loc+2);
      Serial.print("FF is: ");
      Serial.println(substring);      

      readString=""; //clears variable for new input
      substring=""; 

    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}