Serial - how to deal with multi-character command?

Right now I have this code that handles serial data.

Currently, it takes a command in the format Sbbbb (where b represents 1 byte of data), Mbbbbbbb, Lbbbbbbbbbbbbbbb, etc.

I’d like to change the command to something more descriptive, for example:

“COMMANDbbbb”

I’ve been puzzling over how to handle this, though, and I can’t seem to sort out how to do it without using a String (the string class) which everyone says to avoid. I am willing to have a fixed buffer size for each command, but I don’t know how to check the first however many letters and see if they refer to a command. I tried to look for examples of this, but I really couldn’t find anything. Most of the examples I could find used a single character for the commands, specifically sidestepping the problem I was looking for a solution to.

What I have now is this (called from loop):

void processSerial() {
	while (Serial.available() > 0) {
		if (SerRXidx < SerRXmax && rxing==2) { //rxing=2 when it's in the process of receiving a command over serial, so it should be recording what it gets into the buffer. rxing=0 means it's not receiving anything, and 1 indicates that it's busy with RF tx/rx
                 txrxbuffer[SerRXidx]= Serial.read(); //this is a 32-byte long byte buffer
                 SerRXidx++;
                 if (SerRXidx==SerRXmax) {
                 		handleSerialCommand(); //we're done now - this uses the global txrx buffer to get the data it needs.
                 	resetSer();
                 }
		} else if (rxing==0) {
			byte rcv=Serial.read();
			if (rcv=='S') {
				SerRXmax=4;
				rxing=2;
			} else if (rcv=='M') {
				SerRXmax=7;
				rxing=2;
			} else if (rcv=='L') {
				SerRXmax=15;
				rxing=2;
			} else if (rcv=='E') {
				SerRXmax=31;
				rxing=2;
			} else if (rcv=='C') {
				SerRXmax=26;
				rxing=2;
			} else {
				resetSer();
			}
		}
		lastSer=millis();
        }
}

void resetSer() {
	if (rxing==2) {
		rxing=0;
	}
	if (lastSer) {
		lastSer=0;
		Serial.print("\r\n");
	}
	SerRXmax=0;
	SerRXidx=0;
}

This code works

Look at the examples in serial input basics. They read in all the data first. Then you can study it at your leisure to decide what to do. There is also a parse example.

If you can use a single character command it makes sense to do so. There is no more information value in “move” compared with ‘m’

…R

I would pull the entire command in first and then pull it apart. For example:

void loop()
{
   char msg[20];    // Or whatever length you need for one command
   int charsRead;

   if (Serial.available() > 0) {
      charsRead = Serial.readBytesUntil('\n', msg, sizeof(msg) - 1);  // Look for newline or max of 19 chars
      msg[charsRead] = '\0';                 // Overwrite newline with null to make a string
      // pull string apart 
   }
   // whatever you need to do
}

This reads the Serial object until either a newline character is read or a max of 19 chars (msg[20] - 1). You then add the null character to make a string. From there you can use either strtok(), strstr(), or other string processing functions to extract what you need. My guess is that once you see "COMMAND", then &msg[7] starts the data.

Thanks, Robin - that thread is a real resource, it seems to be a lot more practical than the official reference pages, not that that's a particularly high bar.

The single character commands are so convenient on the Arduino side, but I'd like something a bit more professional - I'd like to use the conventions used for AT commands (what I'm making is a serial-to-cheapo-RF bridge).

This really gives me some things to go with on this project, and I think I'm back on track.

http:/www.gammon.com.au/serial

Also Gammon Forum : Electronics : Microprocessors : State machines

I suggest that what you need is a regular expression library. Google "arduino regex" and Hey!

With a little luck, a set of regular expressions will be able to parse lines of input in a way that is helpful.

Hmm. I might want to look at this myself :slight_smile: