A while within a while is causing a freeze

Hi Guys, I'm working with a Maduino LoRa Radio I know you like people to post all the code but, mine is split between three files to keep it manageable. The code is getting long. Is this the right forum to post a lot of code? Should I post them all separately? I've tried isolating the problem but, when I do things work fine. Maybe I'm running out of memory or something?

Here is the file that triggers the freeze:

#include "pedestalInfo.h"
#include <EEPROM.h>  // include EEPROM library
#include <stdlib.h> // might be needed for itoa()

String pedestalName;
unsigned int pedNameLenActual;
unsigned int pedNameLenMax = 9;
const int pedNameEepromAddr = 0;
int pedestalNameSize;

void writeToEeprom();
void pedestalInfo();

void pedestalInfo() {
  // EEPROM CHECK
  if (EEPROM.read(0) == 0) {
    Serial.println("");
    Serial.println("Enter a pedestal label up to 9 characters");
    Serial.println("or hit enter to auto generate: ");
    ////////////////////////
    ////  FIRST WHILE / WHLE WHICH WORKS FINE
    ////////////////////////
    while (Serial.available() == 0) {         // wait for at least a carriage return
    }
    while (Serial.available() > 0) {
      pedestalName = Serial.readString(); // if string entered, else should trigger
      if (pedestalName == "\r\n") {          // user simply hits enter on keyboard
        char randomName[10];      
        itoa(millis(), randomName, 16);   // https://fresh2refresh.com/c-programming/c-type-casting/c-itoa-function/
        pedestalName = String(randomName); 
      }
      else {
        if (pedestalName.length() > pedNameLenMax) {
          pedestalName.remove(pedNameLenMax, 100);
        }
      }
      writeToEeprom();
 
    }
  }
  else {
    Serial.print("Current Pedestal Name is: ");
    int newStrLen = EEPROM.read(pedNameEepromAddr);
    char data[newStrLen + 1];
    for (int i = 0; i < newStrLen; i++) {
      data[i] = EEPROM.read(pedNameEepromAddr + 1 + i);
      Serial.write(data[i]);
    }
    data[newStrLen] = '\0';
    
    Serial.println(" ");
    Serial.println("Type in a new name or just hit enter to keep the current:");
    while (Serial.available() == 0) {         // wait for at least a carriage return
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    ///////// FREEZE BUG STARTS HERE: 2nd WHILE / WHILE, IT IS COMMENTED OUT
    ///////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    while (Serial.available() > 0) {
      pedestalName = Serial.readString(); // if string entered, else should trigger
      if (pedestalName == "\r\n") {
        Serial.println("Pedestal name staying the same"); 
      }  
      else {
        if (pedestalName.length() > pedNameLenMax) {
          pedestalName.remove(pedNameLenMax, 100);
        }
     
        writeToEeprom();  // i'm commented this out, NOT THE PROBLEM
        
      }
    }
    */
    ////////////////////////////////////
    ///////// FREEZE BUG ENDS HERE
    ////////////////////////////////////
  }
}

void writeToEeprom() {   // doesn't appear to be the bug, I've tried commenting it out. 
  Serial.println("Remember: Pedestal Name Limited to 9 characters.");
  Serial.print("The pedestal name is: ");
  Serial.println(pedestalName);
  Serial.print("The length of the pedestal name is = ");    // this is debug
  pedNameLenActual = pedestalName.length();
  Serial.println(pedNameLenActual);
  // prepare for EEPROM: convert pedestalName to char https://arduinogetstarted.com/reference/arduino-string-tochararray
  byte pedestalNameAsChar[pedestalName.length() + 1];
  pedestalName.toCharArray(pedestalNameAsChar, pedestalName.length() + 1);
  for (int i = 0; i < pedestalName.length() + 1; i++) {
    Serial.write(pedestalNameAsChar[i]);        // debug: can't use Serial.print for ascii
  }
  Serial.println(" ");
  pedestalNameSize = sizeof(pedestalNameAsChar);   //get the size of the char array
  Serial.print("sizeof in bytes = ");                  // debug
  Serial.println(pedestalNameSize);
  Serial.println("Lets get this new name written to the EEPROM");
  Serial.println(" ");
  // EEPROM : Writing pedestalNameAsChar, length first.
  // https://roboticsbackend.com/arduino-write-string-in-eeprom/
  // https://docs.arduino.cc/learn/built-in-libraries/eeprom
  EEPROM.write(pedNameEepromAddr, pedestalNameSize);
  for (int j = 0; j < pedestalNameSize + 1; j++) { // 1st byte contains the length
    EEPROM.write(pedNameEepromAddr + 1 + j, pedestalNameAsChar[j]); // now write the name
  }
}

Does anyone need to see the other files?

Thank you.

Looks like you got the first two characters of "Set Frequency failed" before it went into a loop. Try changing the first few chars of that message to something unique and see if that is it.

Thank you for replying. I made that change below:

NOTE: If I run the files independently, There is no issue.

  • If I run tx-retransmit-working-attempting-grab-pedestal-name by itself there are no issues : if I comment out the call to pedestallinfo.cpp
  • If I run pedestallinfo.cpp by itself, no issues.

I wonder if the numerous while statements are causing the arduino to run out of memory? Or perhaps :

while (Serial.available() == 0) {         // wait for at least a carriage return
    }
    while (Serial.available() > 0) { ....

isn't the best way of doing what I want?

Your use of the String class is most likely the issue. Your board is based on the ATmega328 which doesn't have a lot of memory. You should ditch all your String variables (which dynamically allocate memory and can lead to issues) in favor of just using char arrays a.k.a strings (lowercase s)

As for your issue, it really depends on the Serial baud rate. When you print() something, it just goes into a buffer and gets clocked out via hardware interrupt so the code could be much further along than what you are seeing on the Serial Monitor. Are you running at 115200?

I'm running at 9600. Interesting about using strings vs char arrays. It is behaving like a memory issue. I'll spend some time switching it all over to char. I tried to do that initially but, ran into other issues. Thank you for the suggestion.

Capitalization matters. I was referring to the String class vs. C/C++ strings which are char arrays. The String class dynamically grows as needed whenever you add characters to it, but at the expense or possibly fragmenting memory and these little processors do not stand a chance.

You may get better results is you reserve space for your String that is large enough to handle the biggest input.

One other observation. You didn't post your compilation summary, so we don't know if you're running low on ram, or on code space, or both. If you have lots of code headroom, many of your Serial.println("blablabla") strings could be moved to codespace using the F macro.
Serial.println(F("blablabla:)); moves that unchanging string to code space, freeing up ram.
If you want more info,
F() Macro docs
C

Be aware that millis() can eventually be 10 digits which will not fit in a 10-character cString.

Note:
I might be missing it but I don't see a while within a while.

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