String message = "" and switch case

I'm tearing my hair out with this. I want to 'switch' depending on the first (in this case) two characters of a String. I can take my message as an array of char and do switch ( message[0]) or any other single position case ('A') and it works. But when I try the type of switch case below the result is always as shown. How do I get round this?

void DecodeLoco();
char message[10] = {"#B00100T"};
void setup(){
} 
void loop() {
  message[7]='C';
  DecodeLoco();
}

  void DecodeLoco(){
      // switch command is
      // "#BOAAAAP
      //ignore the leading '#'
      
      String locomess ="";      
      locomess += message;
      locomess.toUpperCase();
      locomess = locomess.substring(1); // strip off leading #      
      String lococmd = locomess.substring(0,2);
         switch (lococmd){
           case("B0"): {  //point move cmd 
                      // do movepoint 
                      break; 
                       }       
           default : break;
      }
  }

Arduino: 1.6.3 (Windows 7), Board: "Arduino Uno"

sketch_may07a.ino: In function 'void DecodeLoco()':

sketch_may07a.ino:20:25: error: switch quantity not an integer

Error compiling.

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.

Line 20 is:
switch (lococmd){

Regards
Dave

Try calling void DecodeLoco() after you define message.

A switch/case can only work on integral data types (e.g., int, long, char, byte, etc.) but you are passing it a string. Also, the String class is convenient and brings a lot to the table, but it eats far too many resources while it's at that table. Use a C string (lower case 's') instead and your code size will shrink considerably. If the first character of your string (e.g., 'B') is unique across cases, you could use something like:

   switch (toupper(message[1])) {
      case 'B': 
         // code that does something...
         break; 
                            
     default:                         // Defensive debug code...

       Serial.print("I shouldn't be here. message[1] = ");
       Serial.println(toupper(message[1]));
       break;
  }

Get rid of locomess and lococmd, you don't need them. Also, while your code is in the IDE, use Ctrl-T to reformat the code before you post it. It's difficult to read your formatting. Also, you don't need braces for case statement blocks.

Thanks EconJack,
Not what I was hoping to hear but at least I can avoid being bald. I guess the 'switch' function in C is not as powerful as that in Pascal, my preferred language. Thanks for the tip on the braces in the case blocks, and the control-T formatting if it makes it easier for others, for my own use I prefer the indenting shown.
Unfortunately I need to decode based on the first two chars hence my using 'Strings'. I'm already using char arrays where I decode based solely on one char. So I guess I'm down to a set of IF's.
Regards
Dave

If you only need to do the switch based on two characters, you can do it like this:

int lococmd = ((locomess.charAt(0) << 8) & 0xff00) | (locomess.charAt(1) & 0xff);

switch (lococmd){
        case ('B' << 8) | '0':
            break;
}

Regards,
Ray L.

RayLivingston:
If you only need to do the switch based on two characters, you can do it like this:

int lococmd = ((locomess.charAt(0) << 8) & 0xff00) | ((locomess.charAt(1) << 8) & 0xff);

switch (lococmd){
       case (‘B’ << 8) | ‘0’:
           break;
}




Regards,
Ray L.

Now that’s what I call genius! Not only that it could be used to compare over two chars of a char array. Just one query surely you don’t need to left shift the ‘charAt(1)’ just the one at charAt(0) or have I not quite ‘got it’ yet.

Thanks Ray
Dave

DavidI:
Now that’s what I call genius! Not only that it could be used to compare over two chars of a char array. Just one query surely you don’t need to left shift the ‘charAt(1)’ just the one at charAt(0) or have I not quite ‘got it’ yet.

Thanks Ray
Dave

Right. Typo, now fixed.

Regards,
Ray L.

I want to 'switch' depending on the first (in this case) two characters of a String.

If you are just looking for specific character strings in the characters captured, you can do it like below.

// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

//A very simple example of sending a string of characters 
//from the serial monitor, capturing the individual 
//characters into a String, then evaluating the contents 
//of the String to possibly perform an action (on/off board LED).

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial on/off test 0021"); // so I can keep track
}

void loop() {

  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }

  if (readString.length() >0) {
    Serial.println(readString);

    if(readString.indexOf("on") >=0)
    {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    }

    if(readString.indexOf("off") >=0)
    {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }

    readString="";
  } 
}

I'm tearing my hair out with this.

sketch_may07a.ino: In function 'void DecodeLoco()':

sketch_may07a.ino:20:25: error: switch quantity not an integer

Error compiling.

I'm not sure what part of this is so hard to understand.

If you only need to do the switch based on the first two characters, and your string is a char pointer, you can cheat by telling your compiler to pretend that your string is actually a pointer to an int value.

char *hello = "Hello!";

switch(*((int*)hello)) {
}

The catch is that you need to know that on your processor an int is two bytes, and you have to know whether ints are big-endian or little-endian.

The ascii for uppercase 'H' is 0x48, and for a lowercase 'e' is 0x65. So on a big-endian chip, the code above will match on a case 0x4865, and on a little-endian chip it will match on 0x6548.

But once you get it right, it isn't going to change so long as this code is running on an arduino.

With respect to why switch isn't very powerful: a C switch is usually compiled down to a computed goto where it makes sense to do that. The compiler will generate code for each case and will make a table of offsets matching the switch cases. It can then directly jump to the relevant code without a series of tedious if() statements.

That is: under the hood, a switch() trades expressive power and size (the table takes room!) for speed.
[/code]

michinyon:
I'm not sure what part of this is so hard to understand.

It's easy to forget the apparently simple things that confused you as a beginner when you become an expert

PaulMurrayCbr:
If you only need to do the switch based on the first two characters, and your string is a char pointer, you can cheat by telling your compiler to pretend that your string is actually a pointer to an int value.

char *hello = "Hello!";

switch(((int)hello)) {
}




The catch is that you need to know that on your processor an int is two bytes, and you have to know whether ints are big-endian or little-endian.

The ascii for uppercase 'H' is 0x48, and for a lowercase 'e' is 0x65. So on a big-endian chip, the code above will match on a case 0x4865, and on a little-endian chip it will match on 0x6548.

But once you get it right, it isn't going to change so long as this code is running on an arduino.

With respect to why switch isn't very powerful: a C switch is usually compiled down to a computed goto where it makes sense to do that. The compiler will generate code for each case and will make a table of offsets matching the switch cases. It can then directly jump to the relevant code without a series of tedious if() statements.

That is: under the hood, a switch() trades expressive power and size (the table takes room!) for speed.
[/code]

Thanks Paul, another ingenious solution and also a clear explanation of Switch. Am I right in thinking that essentially it's a 'union' between a string and an int?
Dave.

switch(((int)hello)) {

My mind just boggled.

I'm tearing my hair out with this. I want to 'switch' depending on the first (in this case) two characters of a String.

You can't do that, so don't try.

switch is not for comparing strings. End of argument.

zoomkat:
If you are just looking for specific character strings in the characters captured, you can do it like below.

snip......

String readString;

snip....

Thanks, it was good to be reminded/shown '.indexOf' unfortunately, as you say, it picks up the characters anywhere in the string, which in my particular instance isn't sufficient.

BTW, when I pasted the code into the IDE I wondered why 'readString' came up in red letters, seems that the IDE recognised readString as part of 'stream.readString()' which had me going for a while until I subtituted Read for readString and everything still worked!

zoomkat:
If you are just looking for specific character strings in the characters captured, you can do it like below.

snip......

String readString;

snip....

Thanks, it was good to be reminded/shown '.indexOf' unfortunately, as you say, it picks up the characters anywhere in the string, which in my particular instance isn't sufficient.

BTW, when I pasted the code into the IDE I wondered why 'readString' came up in red letters, seems that the IDE recognised readString as part of 'stream.readString()' which had me going for a while until I subtituted Read for readString and everything still worked!

But what I couldn’t work out was why the following was working but not if I tried to do it with two ascii chars

  if (Serial.available() > 0) {
    //read a byte at a time into message until read \nl
   readmessage();
    
    // now decide what to do based on first char in message
  
      switch (message[0]){
         case '#': {      //loconet message
                    DecodeLoco();
                    break;
                   }  
         case '-':
         case '+':
         case '0':
         case '1':
         case '2':
         case '3':
         case '4':
         case '5':
         case '6':
         case '7':
         case '8':
         case '9': {   //numeric
                    messptr =0;
                    int inc = atoi(message);
                    if (inc != 0) {    // only numbers so move the prior selected servo
                        if (servnum >0){
                        moveservo(servnum,last[servnum]+=inc);
                        }
                        else {
                          pstring = "No servo selected";
                          Serial.println(pstring);
                      }
                    }
                    break;
                   }
         case 'S':
         case 's':{  //servo select message returns 1..4 if valid or -1 if invalid
                   if (servoselect(message)>0) {
                       servnum = servoselect(message);
                   }
                   break;
                   }
         case ('R'):   
         case ('r'): {  // next char is the servo number
                   if (servoselect(message)>0) {
                       servnum = servoselect(message);
                       moveservo(servnum,thrown[servnum-1]);
                   }
                    break;          
                   }
         case ('L'):
         case ('l'):{
                   if (servoselect(message)>0) {
                       servnum = servoselect(message);
                       moveservo(servnum,closed[servnum-1]);;
                    }                     
                     break;
                    }
          case ('C'):
          case ('c'):{
                   if (servoselect(message)>0) {
                       servnum = servoselect(message);
                       moveservo(servnum,(thrown[servnum-1]+closed[servnum-1])/2);
                    }
                    break;
                    }
          case ('P'):
          case ('p'): { //enter programming mode. determine servo number
                        if (servoselect(message)>0) {
                           servnum = servoselect(message);
                           pmode = servnum;
                           pstring = "programming servo: " + String(servnum);
                           Serial.println(pstring);
                           pstring = "Move servo to the \'t\' position";
                           Serial.println(pstring);
                           pstring = "then press \'t\'<ret>";
                           Serial.println(pstring);
                        }
                        
                       break;      
                      }
          case('T'):
etc etc

But what I couldn't work out was why the following was working but not if I tried to do it with two ascii chars

Quite simple, really. A character IS an integer value that the switch statement can operate with.

A String, on the other hand, is NOT an integer value.

PaulS:
Quite simple, really. A character IS an integer value that the switch statement can operate with.

A String, on the other hand, is NOT an integer value.

True, but but before I discovered 'String.h' and having, to my dismay, found that if I wanted a string it had to be an array of chars, to me, my array of chars was a string; with which 'Switch' was working perfectly! Further on I needed to make decisions based on two chars in my string I eventually discovered String.h and assumed there was a function I hadn't yet discovered in that which would allow it to be used with Switch.
BTW, as Ray's solution demonstrates beautifully and readably,two chars do make an integer! (here a smiley is needed)
Regards
Dave