Switch case state machine not entering cases when reading serial

Hey
I am trying to implement a switch case in my program in conjunction with a serial function i found on youtube Using Serial.read() with Arduino | Part 2 - YouTube .see code below.
The serial works as intended, but if i add a serial USB_serial_read_string(); String a = usb_data; in any of the cases the cases after (in this example _idle, _read, _error, _init) will not be entered even tho a "USB.println(state)" indicates that the state is correct and the cases before the read statement work fine.

So my question is why will the USB.println( ) not execute below state = _conf if i enter "4\n" , "5\n" or "9\n" in the Serial Monitor?

#include <Wire.h>
#include <SPI.h>

#define USB Serial

const unsigned int MAX_MESSAGE_LENGTH = 100;
static char usb_data[MAX_MESSAGE_LENGTH];

const int SSN = 10;   //need to verify
const int INTN = 25;  //need to verify

enum CDCState { _stop,
                _start,
                _conf,
                _idle,
                _read,
                _error,
                _init };
volatile enum CDCState state = _init;


void setup() {
  SPI.begin();
  USB.begin(115200);
}

void loop() {
  if (USB.available()) {
    USB_serial_read_string();
    USB.println(usb_data);

    if (usb_data[0] == '0') {
      state = _stop;
    } else if (usb_data[0] == '1') {
      state = _start;
    } else if (usb_data[0] == '2') {
      state = _conf;
    } else if (usb_data[0] == '3') {
      state = _idle;
    } else if (usb_data[0] == '4') {
      state = _read;
    } else if (usb_data[0] == '5') {
      state = _error;
    } else if (usb_data[0] == '9') {
      state = _init;
    } else {
      state = _idle;
    }
    usb_data[0] = 0;
    USB.println(state);
  }


  switch (state) {

    case _stop:
      USB.println("In stop");
      state = _idle;
      break;

    case _start:
      USB.println("In start");
      state = _start;
      break;

    case _conf:
      USB.println("In conf");
      USB_serial_read_string();
      String a = usb_data;
      USB_serial_read_string();
      String b = usb_data;
      USB.println(a);
      USB.println(b);
      usb_data[0] = 0;
      state = _idle;
      break;

    case _idle:
      //empty
      state = _idle;
      break;

    case _read:
      USB.println("In read");
      state = _idle;
      break;

    case _error:
      USB.println("In error");
      state = _idle;
      break;

    case _init:
      USB.println("In init");
      state = _idle;
      break;

    default:
      state = _idle;
  }
}



void USB_serial_read_string(void) {
  //read PC to MCU until terminating char '\n'

  char inByte = 0;
  static unsigned int usb_data_pos = 0;
  while (inByte != '\n') {  //polling
    while (USB.available() > 0) {
      inByte = USB.read();
      if (inByte != '\n' && (usb_data_pos - MAX_MESSAGE_LENGTH - 1)) {
        usb_data[usb_data_pos++] = inByte;
      } else {
        usb_data[usb_data_pos] = '\0';
        //reset array for next data transmission
        usb_data_pos = 0;
      }
    }
  }
}

switch works on a variable which is of type char or int.
Try:
switch ((int)state) {

Or maybe remove the volatile keyword in the definition of state

no.... it's perfectly fine with any integral or enumeration type (or of a class type implicitly convertible to such an integral or enumeration type).

don't trust the arduino's documentation for the C++ language specification... :slight_smile:

volatile won't hurt either but it's useless since there is no interrupts involved here


if you have data in your buffer after the \n you won't exit the while loop

Hey again thank you two for the responses,

I tried to replace all my customUSB_serial_read_string() function with Arduino's String insertName = Serial.readStringUntil('\n'); to rule out any loops, but it still does not enter any switch case below _conf (or whichever case the read is in) :confused: . I think ill go to Atmel Studio to see if i can get some other results

rather than your clumsy USB_serial_read_string() function, I would suggest to study Serial Input Basics to handle this

Not to be rude, but I don't change car manufacturers when I get a flat tire. The problem here is the coding, not the IDE... or the hardware.
C

hehe thats true

switch/case will not work properly when you declare a variable with an initializer. Try encasing the _conf case statements with curly brackets to limit the scope of the variables.

that's a good catch indeed, missed a and b being locally declared

Thanks for the clarification :slight_smile:

yeaahhh, it works :slight_smile: :slight_smile:

glad to hear. I would still recommend you to revisit the code for USB_serial_read_string() as the inner while() will prevent you from exiting the englobing while() if there is data pending in the serial buffer after an '\n'

may be just

...
else {
        usb_data[usb_data_pos] = '\0';
        //reset array for next data transmission
        usb_data_pos = 0;
        break;  // <<== don't keep going after receiving the end marker
      }
1 Like

consider

// demonstration of state changes

#define USB Serial

enum CDCState {
    _stop,
    _start,
    _conf,
    _idle,
    _read,
    _error,
    _init,
    StateLast,
};

const char *stateStr [] = {
    "_stop",
    "_start",
    "_conf",
    "_idle",
    "_read",
    "_error",
    "_init",
    "StateLast",
};

CDCState state = _init;
CDCState stateLst;

char buf [80];

// -----------------------------------------------------------------------------
void loop ()
{
    if (stateLst != state)  {
        Serial.print   (state);
        Serial.print   (" ");
        Serial.println (stateStr [state]);
        stateLst = state;
    }

    if (Serial.available()) {
        int n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        buf [n] = '\0';
        int st  = buf [0] - '0';
        if (StateLast > state)  {
            state    = (CDCState) st;
        }
        Serial.print   (" set ");
        Serial.print   (state);
        Serial.print   (" ");
        Serial.println (stateStr [state]);
    }

    else {
        switch (state) {
        case _stop:
            state = _idle;
            break;
    
        case _start:
            state = _start;
            break;
    
        case _conf:
            if (strlen (& buf [1]))
                Serial.println (& buf [1]);
            state = _idle;
            break;
    
        case _idle:
            state = _idle;
            break;
    
        case _read:
            state = _idle;
            break;
    
        case _error:
            state = _idle;
            break;
    
        case _init:
            state = _idle;
            break;
    
        default:
            break;
        }
    }
}

// -----------------------------------------------------------------------------
void setup()
{
    USB.begin(115200);
}
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.