Trouble with Serial.readStringUntil('\n')

hello everyone ,
i have a question about one of the Serial functions that i will glad if you help me to solve it .
in my project i need to get as an input several times different strings which go to different variable so i decided to use the String object and read the data from the terminal using Serial.readStringUntil('\n') . the first read worked and i had the chance to write in the monitor my input but after i went to the second string/variable i needed to read using the same function it looks like it skip the command and don't allow me to write the input in the monitor.
what can be the problem ?
with best regards.
Dror

can you post the text you're entering and the results from the serial monitor?

Probably the second and third functions are timing out after 1 second (which is the default timeout, I think).

Are you checking Serial.available() before reading the first string? You need to do that before reading each string, otherwise it will time out.

You might get some ideas from Robin's updated serial input basics.

hello gcjr , i posting the code in this replay , as you can see in the parse_menu function in the conditional statement of command F i use function recvWithEndMarker(offset_str) but it seems i can't enter and write in the monitor the offset value. 

/**
*\file bridge_tester.ino
*
*\brief Testing system to test flow of work in the bridge box 
*\author 
*/

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
#include <string.h>

// Below is not needed if interrupt driven. Safe to remove if not using.
#if defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_Timer1
  #include <TimerOne.h>
#elif defined(USE_MP3_REFILL_MEANS) && USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer
  #include <SimpleTimer.h>
#endif

//############## OBJECT INSTANCING #######################
SdFat sd;
SFEMP3Shield MP3player;

//############## FUNCTION DECLERATION #######################
// void parse_menu(string *command);
//###########################################################

int ptt_input = 2 ;
int audio_signal_int=A0;
const int BUFFER_SIZE_COMMAND=3;
void setup(){
  //Define variable
  uint8_t result;  //result code from some function as to be tested at later time.
  Serial.begin(115200);
  //DEFINE THE INPUT PINS 
  /*
  SPI USED PINS:
  D13- SCK
  D12- CIPO
  D11- COPI
  D10- SS
  */
  pinMode(ptt_input,INPUT);
  pinMode(audio_signal_int, INPUT);

  Serial.print(F("F_CPU = "));
  Serial.println(F_CPU);
  Serial.print(F("Free RAM = ")); // available in Version 1.0 F() bases the string to into Flash, to use less SRAM.
  Serial.print(FreeRam(), DEC);  // FreeRam() is provided by SdFatUtil.h
  Serial.println(F(" Should be a base line of 1028, on ATmega328 when using INTx"));

    //Initialize the SdCard.
  if(!sd.begin(SD_SEL, SPI_FULL_SPEED)) sd.initErrorHalt();
  // depending upon your SdCard environment, SPI_HAVE_SPEED may work better.
  //NOTE- name of folder cannot be with "_" for some reason 
  if(!sd.chdir("/sine")) sd.errorHalt("sd.chdir");
  Serial.println("The name of the TRACKS you can play are : ");
  sd.ls();

  //START THE MP3 
  result= MP3player.begin();
  if(result != 0) {
    Serial.print(F("Error code: "));
    Serial.print(result);
    Serial.println(F(" when trying to start MP3 player"));
    if( result == 6 ) {
      Serial.println(F("Warning: patch file not found, skipping.")); // can be removed for space, if needed.
      Serial.println(F("Use the \"d\" command to verify SdCard can be read")); // can be removed for space, if needed.
    }
  } 

  #if defined(__BIOFEEDBACK_MEGA__) // or other reasons, of your choosing.
  // Typically not used by most shields, hence commented out.
  Serial.println(F("Applying ADMixer patch."));
  if(MP3player.ADMixerLoad("admxster.053") == 0) {
    Serial.println(F("Setting ADMixer Volume."));
    MP3player.ADMixerVol(-3);
  }
#endif

  help();

}
void loop(){
  char characther;
  int ndx=0;
  char str[BUFFER_SIZE_COMMAND];
  #if defined(USE_MP3_REFILL_MEANS) \
    && ( (USE_MP3_REFILL_MEANS == USE_MP3_SimpleTimer) \
    ||   (USE_MP3_REFILL_MEANS == USE_MP3_Polled)      )

  MP3player.available();
#endif
  if(Serial.available()) {
    //parse_menu(Serial.read()); // get command from serial input
    while(Serial.available()>0){
       characther=Serial.read();
       if (characther != '\n') {
            str[ndx] = characther;
            ndx++;
            if (ndx >= BUFFER_SIZE_COMMAND) {
                ndx = BUFFER_SIZE_COMMAND - 1;
            }
        }
        else {
            str[ndx] = '\0'; // terminate the string
            ndx = 0;
            // newData = true;
        }

    }
    parse_menu(str);
    
  }
  delay(1000);

}

uint32_t millis_prv;

void parse_menu(String command){
  uint8_t result; // result code from some function as to be tested at later time.
  uint32_t offset=0;
  // Note these buffer may be desired to exist globably.
  // but do take much space if only needed temporarily, hence they are here.
  char title[30]; // buffer to contain the extract the Title from the current filehandles
  char artist[30]; // buffer to contain the extract the artist name from the current filehandles
  char album[30]; // buffer to contain the extract the album name from the current filehandles
  char file_name[30]="track001.mp3";
  char message[30];
  char offset_str[32];
  // bool new_data_offset=false;
  Serial.print(F("Received command: "));
  Serial.print(command);
  Serial.println(F(" "));
  //if s, stop the current track
  if(command=="s" || command=="S" ) {
    Serial.println(F("Stopping"));
    MP3player.stopTrack();
  // if 1-12, play corresponding track
  } else if (is_number(command)){
    Serial.println("passed the digit condition ");
    #if USE_MULTIPLE_CARDS
    sd.chvol(); // assign desired sdcard's volume.
    #endif
    //tell the MP3 Shield to play a track
    result = MP3player.playTrack(static_cast<uint8_t>(command.toInt()));

    //check result, see readme for error codes.
    if(result != 0) {
      Serial.print(F("Error code: "));
      Serial.print(result);
      Serial.println(F(" when trying to play track"));
    } else {

      Serial.println(F("Playing now"));
    }

  }else if(command == "f" || command =="F"){
    if(command == "F"){
      Serial.println("Define number of ms to advance the track");
      // offset_str=Serial.readStringUntil('\n');
      // offset=offset_str.toInt();
      recvWithEndMarker(offset_str);
      offset=static_cast<uint32_t>(atoi(offset_str));
      delay(1000);
      sprintf(message,"you chose offset of %d",offset);
      Serial.println(message);

      resetCharArray(offset_str,32);
    }




  } else if (command=="d"){
    if(!MP3player.isPlaying()){
      Serial.println(F("Files found (name date time size):"));
      sd.ls(LS_R | LS_DATE | LS_SIZE);
    } else {
      Serial.println(F("Busy Playing Files, try again later."));
    }
  } else if (command=="i"){
     MP3player.getAudioInfo();
  } else if (command=="h"){
    help();
  }
  

}

bool is_number(String str)
{
  for(byte i=0;i<str.length();i++)
  { 
    if(isDigit(str.charAt(i))) return true;
  }
  return false;
}

void recvWithEndMarker(char* str) {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    int numChars=32;
    // && newData == false
    Serial.println("enter while loop");
    while (Serial.available() > 0 ) {
        rc = Serial.read();
        Serial.println(rc);
        if (rc != endMarker) {
            str[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            str[ndx] = '\0'; // terminate the string
            ndx = 0;
            // newData = true;
        }
    }
    // return newData;
}

void resetCharArray(char* str, int size)
{
    str[0] = '\0';  // Assign null character to the first element
    
    // Reset the rest of the elements to null as well
    for (int i = 1; i < size; i++)
    {
        str[i] = '\0';
    }
}



void help() {
  Serial.println(F("Test bridge:"));
  Serial.println(F(" courtesy of Dror Heller"));
  Serial.println(F("COMMANDS:"));
  Serial.println(F(" [1-12] to play a track"));
  Serial.println(F(" [f] play track001.mp3 by filename example"));
  Serial.println(F(" [F] same as [f] but with initial skip of 2 second"));
  Serial.println(F(" [s] to stop playing"));
  Serial.println(F(" [d] display directory of SdCard"));
  // Serial.println(F(" [+ or -] to change volume"));
  // Serial.println(F(" [> or <] to increment or decrement play speed by 1 factor"));
  Serial.println(F(" [i] retrieve current audio information (partial list)"));
  // Serial.println(F(" [p] to pause."));
  // Serial.println(F(" [t] to toggle sine wave test"));
  // Serial.println(F(" [S] Show State of Device."));
  // Serial.println(F(" [b] Play a MIDI File Beep"));
// #if !defined(__AVR_ATmega32U4__)
  // Serial.println(F(" [e] increment Spatial EarSpeaker, default is 0, wraps after 4"));
  // Serial.println(F(" [m] perform memory test. reset is needed after to recover."));
  // Serial.println(F(" [M] Toggle between Mono and Stereo Output."));
  // Serial.println(F(" [g] Skip to a predetermined offset of ms in current track."));
  // Serial.println(F(" [k] Skip a predetermined number of ms in current track."));
  // Serial.println(F(" [r] resumes play from 2s from begin of file"));
  // Serial.println(F(" [R] Resets and initializes VS10xx chip."));
  // Serial.println(F(" [O] turns OFF the VS10xx into low power reset."));
  // Serial.println(F(" [o] turns ON the VS10xx out of low power reset."));
  // Serial.println(F(" [D] to toggle SM_DIFF between inphase and differential output"));
  // Serial.println(F(" [V] Enable VU meter Test."));
  // Serial.println(F(" [B] Increament bass frequency by 10Hz"));
  // Serial.println(F(" [C] Increament bass amplitude by 1dB"));
  // Serial.println(F(" [T] Increament treble frequency by 1000Hz"));
  // Serial.println(F(" [E] Increament treble amplitude by 1dB"));
// #endif
  Serial.println(F(" [h] this help"));
}

while the code could be a lot cleaner, the biggest problem is that the buffer used to capture serial input is unnecessarily small when there are numeric value after the command use that buffer to capture the entire input up to a \n and avoid the need for additional buffers

look this over


char s [80];        // for use with sprintf()

char buf [80];
void loop ()
{
    if (Serial.available ()) {
        Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        parse_menu (buf);
    }
}

// -----------------------------------------------------------------------------
void parse_menu (
    char *command)
{
    Serial.print ("parse_menu: ");
    Serial.println (command);

    char c = tolower (command [0]);

    if (isdigit (c))  {
        sprintf (s, "  play track %d", atoi(command));
        Serial.println (s);
        return;
    }
   
    switch (c)  {
    case 's':
        Serial.println (F("  Stopping"));
        break;

    case 'f':
        int offset;
        sscanf (command, "%*s %d", &offset);

        sprintf (s,"  FF %d msec", offset);
        Serial.println (s);
        break;

    case 'd':
        Serial.println ("  d command");
        break;

    case 'i':
        Serial.println ("  d command");
        break;

    case 'h':
        help ();
        break;
    }
}

// -----------------------------------------------------------------------------
void help() {
  Serial.println(F("Test bridge:"));
  Serial.println(F(" courtesy of Dror Heller"));
  Serial.println(F("COMMANDS:"));
  Serial.println(F(" [1-12] to play a track"));
  Serial.println(F(" [f] play track001.mp3 by filename example"));
  Serial.println(F(" [F] same as [f] but with initial skip of 2 second"));
  Serial.println(F(" [s] to stop playing"));
  Serial.println(F(" [d] display directory of SdCard"));
  // Serial.println(F(" [+ or -] to change volume"));
  // Serial.println(F(" [> or <] to increment or decrement play speed by 1 factor"));
  Serial.println(F(" [i] retrieve current audio information (partial list)"));
  // Serial.println(F(" [p] to pause."));
  // Serial.println(F(" [t] to toggle sine wave test"));
  // Serial.println(F(" [S] Show State of Device."));
  // Serial.println(F(" [b] Play a MIDI File Beep"));
// #if !defined(__AVR_ATmega32U4__)
  // Serial.println(F(" [e] increment Spatial EarSpeaker, default is 0, wraps after 4"));
  // Serial.println(F(" [m] perform memory test. reset is needed after to recover."));
  // Serial.println(F(" [M] Toggle between Mono and Stereo Output."));
  // Serial.println(F(" [g] Skip to a predetermined offset of ms in current track."));
  // Serial.println(F(" [k] Skip a predetermined number of ms in current track."));
  // Serial.println(F(" [r] resumes play from 2s from begin of file"));
  // Serial.println(F(" [R] Resets and initializes VS10xx chip."));
  // Serial.println(F(" [O] turns OFF the VS10xx into low power reset."));
  // Serial.println(F(" [o] turns ON the VS10xx out of low power reset."));
  // Serial.println(F(" [D] to toggle SM_DIFF between inphase and differential output"));
  // Serial.println(F(" [V] Enable VU meter Test."));
  // Serial.println(F(" [B] Increament bass frequency by 10Hz"));
  // Serial.println(F(" [C] Increament bass amplitude by 1dB"));
  // Serial.println(F(" [T] Increament treble frequency by 1000Hz"));
  // Serial.println(F(" [E] Increament treble amplitude by 1dB"));
// #endif
  Serial.println(F(" [h] this help"));
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (115200);
}

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