Weird switch case behavior

Hello all,
it's embarrassing, but I'm struggling trying to understand why a simple and trivial switch...case code block is not working as expected. Since the code is not compact at all, here's a logical recap of it:

uint8_t machineState = 0;
void setup() {
  // setup code
}
void loop() {
  switch (machineState) {
    case 0:
      // other code
      machineState = 1;
      break;
    case 1:
      // other code
      if(conditionMet) {
        machineState = 2;
      }
      break;
    case 2:
      // other code
      if(conditionMet) {
        machineState = 3;
      } else {
        machineState = 1;
      }
      break;
    case 3:
      // other code
      break;
  }
}

While running the program, I can move between states 0, 1 and 2 but not on state 3. Code inside case 3: section is NEVER executed. Most surprising part: if I put, outside switch case code, Serial.println(machineState), when being in state 3, the variable is effectively printed as 3, but code inside case 3: seems to be totally ignored. I've also added, even if not needed, a default: section without improvement. Removing case 3: section in favor of a if(machineState==3) will execute the code.
I've checked the code so many times that it seems impossible that such a weird behavior could happen.
Am I missing some (big) detail of this control structure?
Many thanks to any who can give me some hints.

Please make a minimum complete example. The problem is in the code you did not post.

Do you have all warnings turned up in the IDE preferences? You may learn something that by default the IDE does not report.

Do you perchance declare any local variables in the code you elided?

a7

1 Like

Hello gabrielebellini

I assume that you have written the programme by yourself, then it is quite easy to find the error.

There's a trick to figuring out why something isn't working:

Use a logic analyzer to see what happens.
Put Serial.print statements at various places in the code to see the values of variables and determine whether they meet your expectations.

Have a nice day and enjoy coding in C++.

Thank you and yes, you're right, my code it's too much recapped :slight_smile:

void loop() {
  switch (machineState) {
    case 0: 
...
    case 2: // Listen Mode STATUS
      char text[NDIGIT]="---";
      dispOut(text,NDIGIT,OUTENAPIN,255);
      while (irCodesCount < 3) {
        if ((millis() - time) > 1000 * IDLE_TIME_1) {
          machineState = 1;
          immediateExit = 1;
          Serial.println(F("[S2] Timeout reached, returning to RUN STATUS [S1]"));
          fadeOut(OUTENAPIN, 1);
        }
        if (immediateExit) break;
        if (IrReceiver.decode()) {
          if (irCodeToDigitPlusOne(IrReceiver.decodedIRData.command)) {                           // if valid 0-9 keystroke detected
            irCodes[irCodesCount] = irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1;    // write corresponding array item
            Serial.print(F("[S2] Valid keypress received: "));
            Serial.println(irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1);
            text[irCodesCount]=irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1+'0';
            dispOut(text,NDIGIT,OUTENAPIN,255);
            irCodesCount++;                                                                     // increment array pointer
            time=millis();                                                                      // reset timer for timeout
          }
          IrReceiver.resume();                                                                      // enable IR capture again
        }
      }
      if (immediateExit) break;
      if (irCodes[0]*100+irCodes[1]*10+irCodes[2] == DEVICE_ID) {
        for(uint8_t i=0; i<5; i++) {
          dim(OUTENAPIN,0);
          delay(100);
          dim(OUTENAPIN,255);
          delay(100);
        }
        Serial.println(F("[S2] ID matches! Entering SETUP STATUS [S3]"));
        machineState = 3;
      } else {
        Serial.println(F("[S2] ID doesn't match. Returning to RUN STATUS [S1]"));
        fadeOut(OUTENAPIN,1);
        machineState = 1;
      }
      break;
    case 3: // Setup mode STATUS
      Serial.println(F("[S3]"));  //this code portion (when in state 3) doesn't execute
      text[0]="-";
      text[2]="-";
      EEPROM.get(0,text[1]);
      dispOut(text,NDIGIT,OUTENAPIN,255);
      break;
  }
  if(machineState==3) Serial.println(F("[S3]"));  //this code executes (when in state 3)
}

For example, if going from state 2 to state 1 text [S2] ID doesn't match. Returning to RUN STATUS [S1] is sent to serial, and the code of state 1 is executed. If going from state 2 to state 3, "[S2] ID matches! Entering SETUP STATUS [S3] is sent to serial, but code in state 3 is ignored by the switch...case control structure. I can give the whole code, but I don't know if state 0 and 1 codes could be helpful for the solution.

Add a print to show what machineState is actually set to on entering the switch

Thank you Paul, but this problem is so weird that I have no other cards to play! If going from state 2 to 1 everything's ok, but going from state 2 to 3, even if the machineState variable is set to 3, won't execute code inside the case 3: section.
Even setting the machineState=3 in initial variable definition won't execute the code of case 3: section.
That doesn't have any explanation for me. I'm sure I'm missing something: I'm not a professional coder, but never imagined to be stuck on a switch...case structure :smiley:

Encapsulate your code between case XXX: and break; with a set of extra {} brackets.

1 Like

That's exactly what I did.

void loop() {
  Serial.println(machineState);
  switch (machineState) {
    case 0: 
...

will print continuously '3' on serial console (when in state 3), but code in case 3: won't be executed.
Strange enough to ask in this forum :slight_smile:

Sorry for not having posted before, here's the whole code:

//#define DECODE_DENON        // Includes Sharp
//#define DECODE_JVC
//#define DECODE_KASEIKYO
//#define DECODE_PANASONIC    // alias for DECODE_KASEIKYO
//#define DECODE_LG
//#define DECODE_NEC          // Includes Apple and Onkyo
#define DECODE_SAMSUNG
//#define DECODE_SONY
//#define DECODE_RC5
//#define DECODE_RC6

//#define DECODE_BOSEWAVE
//#define DECODE_LEGO_PF
//#define DECODE_MAGIQUEST
//#define DECODE_WHYNTER
//#define DECODE_FAST

//#define DECODE_DISTANCE_WIDTH // Universal decoder for pulse distance width protocols
//#define DECODE_HASH         // special decoder for all protocols

//#define DECODE_BEO          // This protocol must always be enabled manually, i.e. it is NOT enabled if no protocol is defined. It prevents decoding of SONY!

//#define DEBUG               // Activate this for lots of lovely debug output from the decoders.

//#define RAW_BUFFER_LENGTH  180  // Default is 112 if DECODE_MAGIQUEST is enabled, otherwise 100.

#define DEVICE_ID 412   // device identifier (must be unique in range [000-999])

#define INTERRPIN 2     // interrupt pin connected to proximity sensor
#define SEROUTPIN 3     // serial data pin (output to displays)
#define SERCLKPIN 4     // serial clock pin (output to displays)
#define SERLATPIN 5     // serial latch out pin (output to displays)
#define OUTENAPIN 6     // display output enable (active low, output to displays)
#define NDIGIT    3     // number of display digits

#define BTN_ENTER 104   // IR code for ENTER button
#define BTN_y       7   // IR code for YES button (VOL +)
#define BTN_INFO   31   // IR code for INFO button (show DEVICE_ID)
#define BTN_EVENT 108   // IR code for EVENT BUTTON (simulate event)

#define IDLE_TIME_1  10  // timeout [s] of waiting for IR state
#define IDLE_TIME_2  30  // display idle time [s] on events absence
#define IDLE_TIME_3   3  // maximum period [s] after which the counter per minute variable is flattened to 0 (during Run state)

#define TEXT_DISP_TIME   2 // period [s] of text display (running mode)
#define COUNT_DISP_TIME 10 // period [s] of count display (running mode)
#define PAUSE_TIME       1 // period [s] of pause between text and count

#include <Arduino.h>
#include <EEPROM.h>
#include "PinDefinitionsAndMore.h" // Define macros for input and output pin etc.
#include <IRremote.hpp>

uint8_t machineState = 0;         // machine state register
uint8_t irCodesCount = 0;         // receiver IR codes counter
uint8_t immediateExit = 0;        // routine exit flag
uint16_t irCodes[3] = {0, 0, 0};  // IR codes array
uint32_t time;                    // for keeping track of timeouts
uint32_t calculatedCrc;           // calculated EEPROM CRC checksum during POST
uint32_t storedCrc;               // stored EEPROM CRC checksum
uint8_t seconds;                  // for displaying multiple rows
uint16_t eventsMin = 0;           // calculated events (or meters) per minute
uint8_t idleDisplay = 0;          // display status flag
uint8_t counterMode;              // 'E' for event counter [pcs/min], 'S' for speed meter [m/min]
uint16_t circum;                  // circumference length [mm] for speed meter mode
char name[6];                     // production line name (to be displayed)
char text[NDIGIT];                // text buffer for displaying strings               

const char defaultName[6] = "ABCDEF";       //default name of production line (EEPROM restore)
const uint16_t DEF_CIRCUM = 200;            // default circumference length [mm] for speed meter mode (EEPROM restore)
const uint32_t DEF_STORED_CRC = 0x807ED417; //default satored CRC of EEPROM (must be recalculated at each byte change!!!)
const uint8_t msgTime = 2;                  // message time duration [s]
const uint8_t charMap[60] = {
//  SEGMENT      CHAR
//  abcdefg.
  0b00000000, // SPACE
  0b01100001, // !
  0b01000100, // "
  0b00000000, // #
  0b00000000, // $
  0b00000000, // %
  0b00000000, // &
  0b01000000, // '
  0b10011100, // (
  0b11110000, // )
  0b00000000, // *
  0b00000000, // +
  0b00000000, // ,
  0b00000010, // -
  0b00000001, // .
  0b01001010, // /
  0b11111100, // 0
  0b01100000, // 1
  0b11011010, // 2 
  0b11110010, // 3 
  0b01100110, // 4 
  0b10110110, // 5 
  0b10111110, // 6 
  0b11100000, // 7 
  0b11111110, // 8
  0b11110110, // 9
  0b00000000, // :
  0b00000000, // ;
  0b00000000, // <
  0b00010010, // =
  0b00000000, // >
  0b11001010, // ?
  0b00000000, // @
  0b11101110, // A 
  0b00111110, // B 
  0b00011010, // C 
  0b01111010, // D 
  0b10011110, // E 
  0b10001110, // F 
  0b10111100, // G 
  0b01101110, // H 
  0b00001100, // I
  0b01111000, // J
  0b01101110, // K
  0b00011100, // L  
  0b11101100, // M  
  0b00101010, // N  
  0b11111100, // O  
  0b11001110, // P  
  0b11100110, // Q  
  0b00001010, // R  
  0b10110110, // S  
  0b00011110, // T  
  0b01111100, // U  
  0b00111000, // V  
  0b01010100, // W  
  0b01101110, // X  
  0b01110110, // Y  
  0b11011010, // Z  
  0b11111111  // [ (ALL)
};

volatile uint32_t t1_us=0;                    // t1 event [microseconds] (note: isr managed variables must be volatile!)
volatile uint32_t t2_us=0;                    // t2 event [microseconds] (note: isr managed variables must be volatile!)
volatile uint32_t t2_ms=0;                    // t1 event [milliseconds] (note: isr managed variables must be volatile!)
volatile uint32_t events=0;                   // events counter (note: isr managed variables must be volatile!)

//               __                __
//              |  |              |  |
// _____________|  |______________|  |_________________
//                 ^                 ^
//                 t1                t2
//

void setup() {
  pinMode(SEROUTPIN, OUTPUT);       // pin mode definition
  pinMode(SERCLKPIN, OUTPUT);
  pinMode(SERLATPIN, OUTPUT);
  pinMode(OUTENAPIN, OUTPUT);

  attachInterrupt(digitalPinToInterrupt(INTERRPIN), isr0, FALLING);  // interrupt pin to service routine association

  Serial.begin(115200);
  // Just to know which program is running on my Arduino
  Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

  // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);

  Serial.print(F("Ready to receive IR signals of protocols: "));
  printActiveIRProtocols(&Serial);
  Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
}

void loop() {
  Serial.println(machineState);
  switch (machineState) {
    case 0: // Power On Self Test STATE
      immediateExit = 0;
      // display test
      dispOut("[[[",NDIGIT,OUTENAPIN,255); // light on all display's segments
      fadeIn(OUTENAPIN, 1);
      fadeOut(OUTENAPIN, 1);
      fadeIn(OUTENAPIN, 1);
      fadeOut(OUTENAPIN, 1);
      // EEPROM test
      Serial.print(F("[S0] EEPROM byte length: "));
      Serial.println(EEPROM.length());
      Serial.print(F("[S0] Calculated CRC32 of EEPROM data: 0x"));
      calculatedCrc = eeprom_crc(0, EEPROM.length()-4);
      Serial.println(calculatedCrc, HEX);
      Serial.print(F("[S0] Stored CRC32 of EEPROM data: 0x"));
      EEPROM.get(EEPROM.length()-4, storedCrc);
      Serial.println(storedCrc, HEX);

      for (uint32_t i = 0; i < EEPROM.length() ; i++) {
        if ((i % 64) == 0)
          Serial.println();
        Serial.print(EEPROM[i], HEX);
        Serial.print(" ");
      }
      Serial.println();

      if (storedCrc != calculatedCrc) {
        Serial.println(F("[S0] Calculated CRC32 doesn't match stored CRC32 of EEPROM data. Possible data corruption! Set EEPROM to default values? [y]"));
        do {
          while (!IrReceiver.decode()) {
            if ((((millis()/1000)%(msgTime*3))/msgTime)==0) {                   // prints CRC
              dispOut("CRC",NDIGIT,OUTENAPIN,255);
            }
            if ((((millis()/1000)%(msgTime*3))/msgTime)==1) {                   // prints ERR
              dispOut("ERR",NDIGIT,OUTENAPIN,255);
            }
            if ((((millis()/1000)%(msgTime*3))/msgTime)==2) {                   // prints blanks
              dispOut("   ",NDIGIT,OUTENAPIN,255);
            }
          }
          if(IrReceiver.decodedIRData.command == BTN_y) {
            Serial.println(F("[S0] Setting EEPROM data to default values..."));
            EEPROM.update(0,'E');             // default: 'E'vent counter mode;
            EEPROM.put(1,DEF_CIRCUM);         // default length of circumference for speed meter mode (uint16_t -> 2 bytes)
            EEPROM.put(3,defaultName);        // default name of production line (6 chars)
            for (uint16_t i=9;i<EEPROM.length()-4;i++) {
              EEPROM.update(i,0xff);                              // fill rest of the EEPROM with 0xff
            }
            EEPROM.put(EEPROM.length()-4,DEF_STORED_CRC);         // write last 4 EEPROM bytes with default CRC32 of all EEPROM (warning: must be recalculated for each default byte change)
            immediateExit = 1;
          }
          IrReceiver.resume();
        }
        while (!immediateExit);
      }
      counterMode=EEPROM.read(0);               // get counter mode from EEPROM
      EEPROM.get(1,circum);                     // get circumference length from EEPROM
      EEPROM.get(3,name);                       // get production line name from EEPROM
      Serial.print("[S0] Power On Self Test success, entering RUN STATUS [S1]");
      machineState = 1;
      break;
    case 1: // RUN state
      immediateExit = 0;
      if ((millis()-t2_ms)>IDLE_TIME_2*1000 && idleDisplay==0) {
        fadeOut(OUTENAPIN,1);
        Serial.println(F("[S1] No events for a while. Idling display."));
      } 
      if ((millis()-t2_ms)>IDLE_TIME_2*1000) {
        idleDisplay=1;
      } else {
        idleDisplay=0;
      }

      if((micros()-t2_us)<IDLE_TIME_3*1000000 && t2_us!=t1_us) {
        if(counterMode=='E') { // we are counting 'E'vents per minute (pieces per minute)
          eventsMin = 60000000/(t2_us-t1_us); // events per minute
        }
        if(counterMode=='S') { // we are counting 'S'peed (meters per minute)
          eventsMin = 60000*circum/(t2_us-t1_us); // meters per minute
        }
      } else {
        eventsMin = 0;
      }
      if (!idleDisplay) {   // display TEXT1 + TEXT2 + PAUSE + COUNT per MIN + PAUSE
        if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME) {
          dispOut("   ",NDIGIT,OUTENAPIN,255); // light off all display's segments
        } else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME+TEXT_DISP_TIME) {
                 for(uint8_t i=0;i<3;i++) text[i]=name[i];                 
                 dispOut(text,NDIGIT,OUTENAPIN,255);
               } else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<PAUSE_TIME+2*TEXT_DISP_TIME) {
                        for(uint8_t i=0;i<3;i++) text[i]=name[i+3];                 
                        dispOut(text,NDIGIT,OUTENAPIN,255);
                      } else if (((millis()/1000)%(2*TEXT_DISP_TIME+2*PAUSE_TIME+COUNT_DISP_TIME))<2*PAUSE_TIME+2*TEXT_DISP_TIME) {
                               dispOut("   ",NDIGIT,OUTENAPIN,255); // light off all display's segments
                             } else {
                                 if(eventsMin>99) text[0]=eventsMin/100+'0';
                                 else text[0]=' ';
                                 if(eventsMin>9) text[1]=(eventsMin/10)%10+'0';
                                 else text[1]=' ';
                                 text[2]=eventsMin%10+'0';
                                 dispOut(text,NDIGIT,OUTENAPIN,255);
                               }
      }

      if (IrReceiver.decode()) {
        Serial.println(IrReceiver.decodedIRData.command);     // LINE TO BE REMOVED - ONLY FOR TEST
        
        switch(IrReceiver.decodedIRData.command) {
          case BTN_INFO:    // INFO button pressed: show DEVICE ID on display
            text[0]=DEVICE_ID/100+'0';
            text[1]=(DEVICE_ID-100*(text[0]-'0'))/10+'0';
            text[2]=DEVICE_ID-100*(text[0]-'0')-10*(text[1]-'0')+'0';
            Serial.println(F("[S1] Received INFO command, print DEVICE_ID on display"));
            dispOut(text,NDIGIT,OUTENAPIN,255);
            fadeOut(OUTENAPIN,1);
            break;
          case BTN_ENTER:   // ENTER button pressed: enter LISTEN status
            machineState = 2;
            Serial.println(F("[S1] Received ENTER command, entering LISTEN STATUS [S2]"));
            time=millis();
            irCodesCount = 0;
            break;
          case BTN_EVENT:   // EVENT button pressed: simulate event
            Serial.println(F("[S1] Received EVENT command, simulating event."));
            t1_us=t2_us;
            t2_us=micros();
            t2_ms=millis();
            events++;
            break;
        }
        IrReceiver.resume(); // Enable receiving of the next value
      }
      break;
    case 2: // Listen Mode STATUS
      char text[NDIGIT]="---";
      dispOut(text,NDIGIT,OUTENAPIN,255);
      while (irCodesCount < 3) {
        if ((millis() - time) > 1000 * IDLE_TIME_1) {
          machineState = 1;
          immediateExit = 1;
          Serial.println(F("[S2] Timeout reached, returning to RUN STATUS [S1]"));
          fadeOut(OUTENAPIN, 1);
        }
        if (immediateExit) break;
        if (IrReceiver.decode()) {
          if (irCodeToDigitPlusOne(IrReceiver.decodedIRData.command)) {                           // if valid 0-9 keystroke detected
            irCodes[irCodesCount] = irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1;    // write corresponding array item
            Serial.print(F("[S2] Valid keypress received: "));
            Serial.println(irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1);
            text[irCodesCount]=irCodeToDigitPlusOne(IrReceiver.decodedIRData.command) -1+'0';
            dispOut(text,NDIGIT,OUTENAPIN,255);
            irCodesCount++;                                                                     // increment array pointer
            time=millis();                                                                      // reset timer for timeout
          }
          IrReceiver.resume();                                                                      // enable IR capture again
        }
      }
      if (immediateExit) break;
      if (irCodes[0]*100+irCodes[1]*10+irCodes[2] == DEVICE_ID) {
        for(uint8_t i=0; i<5; i++) {
          dim(OUTENAPIN,0);
          delay(100);
          dim(OUTENAPIN,255);
          delay(100);
        }
        Serial.println(F("[S2] ID matches! Entering SETUP STATUS [S3]"));
        machineState = 3;
      } else {
        Serial.println(F("[S2] ID doesn't match. Returning to RUN STATUS [S1]"));
        fadeOut(OUTENAPIN,1);
        machineState = 1;
      }
      break;
    case 3: // Setup mode STATUS
      Serial.println(F("[S3]"));
      text[0]="-";
      text[2]="-";
      EEPROM.get(0,text[1]);
      dispOut(text,NDIGIT,OUTENAPIN,255);
      break;
  }
  //if(machineState==3) Serial.println(F("[S3]"));
}

// sketch specific function declarations

uint32_t eeprom_crc(uint16_t firstByte, uint16_t lastByte)
{

  const uint32_t crc_table[16] =
  {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
    0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
    0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
  };

  uint32_t crc = ~0L;

  for (uint16_t index = firstByte ; index < lastByte ; ++index)
  {
    crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4);
    crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4);
    crc = ~crc;
  }
  return crc;
}

uint8_t irCodeToDigitPlusOne (uint8_t code) {
  switch(code)  // formatted to be less 'long'
    {
    case 4:      return(2);
    case 5:      return(3);
    case 6:      return(4);
    case 8:      return(5);
    case 9:      return(6);
    case 10:     return(7);
    case 12:     return(8);
    case 13:     return(9);
    case 14:     return(10);
    case 17:     return(1);
    default:     return(0);
    }
}

void dispOut (char text[], uint8_t n, uint8_t pin, uint8_t dim) {
  //analogWrite(pin, 255);                                              // dim to 0%
  for(uint8_t i=n; i > 0; i--) {
    shiftOut(SEROUTPIN, SERCLKPIN, LSBFIRST, charMap[text[i-1]-32]);  // serial send chars
  }
  digitalWrite(SERLATPIN, HIGH);                                      // latch out
  digitalWrite(SERLATPIN, LOW);
  analogWrite(pin, 255-dim);                                          // dim to desired value
}

void dim (uint8_t pin, uint8_t dim) {
  analogWrite(pin, 255 - dim);
}

void fadeIn (uint8_t pin, uint8_t time) {
  for(uint16_t  i = 0; i < 256; i++) {
    analogWrite(pin, 255 - i);
    delay(4*time);
  }
}

void fadeOut (uint8_t pin, uint8_t time) {
  for(uint16_t  i = 0; i < 256; i++) {
    analogWrite(pin, i);
    delay(4*time);
  }
}

// Interrupt service routine: called at each rising edge of signal coming from proximity sensor.
// t1 value takes the t2 value, while t2 value become actual time (both micros() and millis() values).
// Event counter value is increased. 

void isr0() {
  t1_us=t2_us;
  t2_us=micros();
  t2_ms=millis();
  events++;
}

That is a problem. You should avoid declaring local variables in switch case statements.

Make text[] global, or enclose the entire action of any such case statement in "{}", recognizing that "text[]" won't exist outside the code block.

1 Like

Yes. Please @gabrielebellini go immediately to the preferences pane in the IDE and crank up all warnings and verbosity and so forth.

Why why why these are not enabled by default is a mystery.

After doing, heed the read ink and seek to remove all warnings issued, even when a warning is seems like it is just being picky and you "know" better.

a7

1 Like

Because there are core files that throw warnings and will confuse the Arduino beginner :smiley:

2 Likes

Does this execute? If it does, add a
Serial.println(machineState);
after the next line to verify it actually contains 3

AI nonsense and subsequent replies deleted.

3 Likes

Will it?
Won't it generate an error?

https://en.cppreference.com/w/cpp/language/aggregate_initialization

Unfortunately only a warning - and you will not see it, if warnings are switched off ...

The language specifications might state "behavior undefined", but last time I checked, what actually happens with avr-gcc is that memory outside of the array bounds is overwritten, with unpredictable consequences.

Other compilers/linkers/run time components etc. may well do something different, and adverse consequences may not even become apparent.

1 Like

for a while... Murphy always makes these features apparent, when the customer is present and the deadline has passed.

5 Likes

Argh!!!! Strings are not char arrays, STRINGS-ARE-N-O-T-CHAR-ARRAYS :man_facepalming:
Fell into this trap in the past and again forgot to manage it in the correct way.
text is a char array that I already defined before setup(), but redefining it (as string) inside the switch...case block made this unpredictable behavior.
char text[3] is a declared and undefined array of 3 bytes, while char text[3]="---" defines a 3 element array with a 4 bytes string (the null termination). So, replacing

char text[NDIGIT]="---"

with

for(uint8_t i=0;i<NDIGIT;i++) {
  text[i]='-';
  }

fixed all my troubles.
The fact that a switch...case condition was never met, even with the evidence that it should, completely misled me.
Many, many thanks to all of you (and yes, I raised the verbosity level of the compile log of the IDE).

Also neatly steps past the problems that occur when you declare local variables in a switch/case. Without { embracing } the case code lines where you've done.

Which may well have been what made the code not work.

Someone might waste spend time seeing which of the two problems was actually making for the misbehaviour at the exact moment of.

a7