Help with program function calls

Hi

I’ve got what I think is a fairly simple bunch of function calls that are made through IF statements. The function call to ‘processCmd’ works however the test to see if the string ‘thing’ contains ‘X’ does not. Guessing that there could be a problem with calling functions within functions and stack calls but I’m not sure.

Help appreciated…

John

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete
bool validmsg = true;
String thisString = "";
String Cmd;
long number = 0;

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}


void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
	Serial.println(number);
	number=number + 23;//no reason just checking...
	Serial.println(number);
	Serial.println("The Command is :" + Cmd);
    Serial.println("Finished");
	
    // clear the string:
    inputString = "";
    stringComplete = false;
	validmsg = false;
  }
}
//----------------- Problem appears in this function call ----------------------------
void processCmd(String thing){
  Serial.println("processCmd is " + thing);//test if made it here so far
  if(thing == "X"){
    Serial.println("Made it this far");//test if thing = X. No idea why this does not work, logically it looks OK.
  }
}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
	if (inChar == '#'){
		validmsg = true;
	}
    if (inChar == '\n') {
		stringComplete = true;
		ParseCom(inputString);
      
    }
  }
}
void ParseCom(String Command){
	if (validmsg && stringComplete){
		thisString = Command.substring(Command.indexOf('#') + 1, Command.indexOf('-'));
		//char c = thisString.charAt(1);
		number = thisString.toInt();
		//Cmd = Command.charAt(Command.length()-1);
		
		Cmd = Command.substring(Command.indexOf('-')+1);
		Serial.println("ParseCom - The Command is :" + Cmd);
		processCmd(Cmd);
	}
	else
	{
		Serial.println("Incorrect message format");
	}
	
	
}

StringParsing1.ino (2.18 KB)

You can make your code a little easier to read if you place the cursor in the Source Code Window of the IDE and do Ctrl-T before you post your code. It will reformat your code to a common C style. Also, in the while loop where you read the Serial object, most would define inChar outside the loop. I haven't looked at the assembler, but my guess is that it only defines it once so it will likely have no impact on the code, but if that's not the case, it makes sense to define it before entering the loop.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

When using Cstrings you must use strcmp() to compare values rather than ==

...R

What format is the program expecting ?

What have you got the line ending set to in the Serial monitor ?

Hi,
Welcome to the forum.

What are you trying to accomplish, what do you enter on the monitor and what do you expect to be sent back?
This may help.

Serial Input Basics
and
Serial data - how to process without blocking

Tom... :slight_smile:

I want to control a stepper motor, so the msg format is #nnnn-x\n, # just a chr to verify a valid msg with the serial string ending with '\n'. nnnn is the number steps and x represents a control chr for the A4988 stepper controller (step size, step direction, chip enable).

The stepper controller requires a pulse to make a single step which is nnnn. I have this working ok using a timer interrupt.

All seems to work ok except for the if statement inside the function processCmd. Would it be better if I called this function from void Loop() instead of from within the previous function?

I've read a bit regarding string.h so I might give it another shot!

Bodge Out

Running your program I input

#1234-X

with the Serial monitor line ending set to Newline and got back

ParseCom - The Command is :X

processCmd is X

1234
1257
The Command is :X

Finished

Is that what you expect/want ?
If not then what should the output be ?

That's exactly what I get, however what is not occurring is within the IF statement in the function void processCmd(String thing). Here I'm testing for a Cmd in this case 'X' with a println just to see if the IF function works. It does not and I have no idea why, ant thoughts,

Bodge

Try this

void processCmd(String thing)
{
  Serial.println("In processCmd thing is : ");
  Serial.print(">>");
  Serial.print(thing);
  Serial.println("<<");
  
  Serial.println("processCmd is " + thing);//test if made it here so far
  if (thing == "X")
  {
    Serial.println("Made it this far");//test if thing = X. No idea why this does not work, logically it looks OK.
  }
}

The output is :

ParseCom - The Command is :X

In processCmd thing is : 
>>X
<<
processCmd is X

1234
1257
The Command is :X

Finished

Note what is printed for the value of thing.
Does it equal “X” ?

Still have the same issue:

//----------------- Problem appears in this function call ----------------------------
void processCmd(String thing) {
  Serial.println("In processCmd thing is : ");
  Serial.print(">>");
  Serial.print(thing);
  Serial.println("<<");
  
  if (thing == "X") {
    Serial.println("Made it this far");//test if thing = X. No idea why this does not work, logically it looks OK.
  }
}

Just to explain, I have a number on control chrs to change for example the step direction or speed or to enable/disable the motor controller, I’ve just made it ‘X’ for the moment to try and resolve this issue. So the comparison of the var ‘thing’ and ‘X’ should result in a true result but for some reason it appears that program flow just jumps straight over the IF statement as if it was not even there.

Go to say I’ve not had this issue with PIC micro’s, weird…

Need to wear safety glasses I think!

Thanks

Bodge

the comparison of the var ‘thing’ and ‘X’ should result in a true result but for some reason it appears that program flow just jumps straight over the IF statement as if it was not even there.

No it doesn’t. In your program thing will never equal ‘X’ or any single character.

Look carefully at the output from my code in reply #8

In processCmd thing is : 
>>X
<<

The delimiters >> and << are there to show you where thing starts and ends when it is printed.
Why is the << on a new line ? The program does not output a newline so where did it come from I wonder ?

Need a bigger clue, then print the length of the thing variable in the function. How many characters is it ? How many characters are there in ‘X’ ?

debugging all of those functions tinkering with global variables makes for real spaghetti code, yeah?

don’t use String class
don’t use the SerialEvent

do have functions take an argument or arguments
do have functions return something

limit your global variables

something more like this, using your data template:

const size_t MAX_MESSAGE_BUFFER_LENGTH = 32;

struct Command {
  char command;
  int value;
};

//tested using this data:   #1234-x\n

template<class T> inline Print &operator << (Print &object, T argument)
{
  object.print(argument);
  return object;
}

void setup()
{
  Serial.begin(9600);
  if (Serial)
  {
    Serial << (F("let's go!\n"));
  }
}

void loop()
{
  if (const char* packet = checkForNewPacket(Serial, '#', '\n'))  // checks for message on Serial with start and end marker
  {
    Serial << (F("\nthis just in...\n")) << (packet) << (F("\n\n"));
    Command newCommand;
    if (parsePacket(newCommand, packet)) {
      processCommand(newCommand);
    } else {
      Serial << (F("Bad Packet"));
    }
  }
}

void processCommand(Command cmd) {
  switch (cmd.command) {
    case 'x':
      Serial << (F("x value: ")) << cmd.value;
      break;
    default:
      Serial << (F("UnknownCommand: ")) << cmd.command << (F(" value:")) << cmd.value;
      break;
  }
}


bool parsePacket(Command& cmd, const char* packet) {
  if (char* ptr = strchr(packet, '-')) {
    ptr++;
    cmd.command = *ptr;
    cmd.value = atoi(packet);
    return true;
  }
  return false;
}


const char* checkForNewPacket(Stream& stream, const char startMarker, const char endMarker)
{
  static char incomingMessage[MAX_MESSAGE_BUFFER_LENGTH] = "";
  static unsigned char idx = 0;
  static bool gotStartMarker = false;
  if (stream.available()) {
    if (!gotStartMarker) {
      if (stream.read() == startMarker) {
        gotStartMarker = true;
      }
    } else {
      incomingMessage[idx] = stream.read();
      if (incomingMessage[idx] == endMarker) {
        incomingMessage[idx] = '\0';
        idx = 0;
        gotStartMarker = false;
        if (!strlen(incomingMessage)) { //startMarker followed immediatly by endMarker (i.e.no data)
          //stream << (F("{\"error\":\"no data\"}\n"));  // you can return an error to sender here
          return nullptr;
        }
        //stream << (F("{\"success\":\"")) << (incomingMessage) << (F("\"}\n"));  // or return a success messaage
        return incomingMessage;
      } else {
        idx++;
        if (idx > MAX_MESSAGE_BUFFER_LENGTH - 1) {
          stream << (F("{\"error\":\"message exceeded ")) << (sizeof(incomingMessage) - 1) << (F(" chars\"}\n"));  // another error to sender here
          idx = 0;
          gotStartMarker = false;
          incomingMessage[idx] = '\0';
        }
      }
    }
  }
  return nullptr;
}

Aha..\n hence not to use String

Thanks everyone, got the message haha.

Bodge Out.