Bug in validating a code stored in EEPROM?

So I have never used the EEPROM to store a “Secret code” and I have this code working for the most part except when I put in an incorrect code some times the Arduino gets hung up on validating to see if the input was correct. I really don’t know where to start with a bug like this.

My code is attached.

any tips or insight would be much appreciated!

Candle_Prop_in_progress.ino (7.06 KB)

// sketch_06_EEPROM_example
// have the new code recorded now to save it to EEPROM

#include <EasyButton.h>
#include <EEPROM.h>

#define Gled 11
#define Rled 12
#define Yled 13

#define butt1 7
#define butt2 6
#define butt3 5
#define butt4 4
#define butt5 3

EasyButton Button1(butt1);
EasyButton Button2(butt2);
EasyButton Button3(butt3);
EasyButton Button4(butt4);
EasyButton ButtonP(butt5);

const byte eepromValid = 123;

const int maximumButtonInputs = 4;

int combination[4] = {1, 2, 3, 4};
int buttonReadings[maximumButtonInputs];

int code;

int userInputCount = 0;

boolean locked = true;

boolean programModeActive = false;

// MY Functions

void readSecretCode()
{
  byte reading;
  int i;
  reading = EEPROM.read(0);
  if(reading == eepromValid) // only read EEPROM if signature byte is correct.
  {
   for(int i=0; i < maximumButtonInputs; i++)
   {
    combination[i] = EEPROM.read(i+1); 
   }
  }
}


void setup()
{
  pinMode(Gled, OUTPUT);
  pinMode(Rled, OUTPUT);
  pinMode(Yled, OUTPUT);

  digitalWrite(Gled, LOW);
  digitalWrite(Rled, LOW);
  digitalWrite(Yled, LOW);
  
  Serial.begin(9600);
  
  readSecretCode();

  for(int c=0; c<maximumButtonInputs; c++)
  {
    Serial.print(combination[c]);
  }
  Serial.println();
  Serial.println("Enter the secret code or press program button.");
}

void loop()
{
  
 Button1.update();
 Button2.update();
 Button3.update();
 Button4.update();
 ButtonP.update();

 if(Button1.IsPushed())
  {
   buttonReadings[userInputCount] = 1;
   userInputCount++;
   delay(10);
   Serial.print("1"); 
  }

 if(Button2.IsPushed())
  {
    buttonReadings[userInputCount] = 2;
    userInputCount++;
    delay(10);
    Serial.print("2");
  }

 if(Button3.IsPushed())
  {
    buttonReadings[userInputCount] = 3;
    userInputCount++;
    delay(10);
    Serial.print("3");
  }

 if(Button4.IsPushed())
  {
    buttonReadings[userInputCount] = 4;
    userInputCount++;
    delay(10);
    Serial.print("4");
  } 
 
 if(ButtonP.IsPushed()) // is the program button pushed?
 {
  Serial.println("Going into programming mode");
  if(programModeActive == false) //If not already in program mode turn it on.
  {
    programModeActive = true; //remember we are in program mode.
    digitalWrite(Yled, HIGH);
    Serial.println("Program button pushed");
  }
  /*else
  {
    programModeActive = false;  // If we are in pogram modew but button was not pushed, turn it off
    digitalWrite(Yled, LOW);
    listenToCodeInput();
  } */
 if(programModeActive == true)
 {
  Serial.println("Now in programming mode!");
  Serial.println();
  int d = 0;
  for(d=0; d < maximumButtonInputs; d++)
  {
    buttonReadings[d] = 0;
  }
  programModeActive = true;
  listenToCodeInput(); // See what the user is seting the combo to.
 }
 }
 else if(userInputCount == 4 && programModeActive == false)
 {
  Serial.println("Validating code");
  programModeActive = false;
  validateCode();
 }
}


// Records the button inputs
void listenToCodeInput(){
 int i = 0;
 for(i=0; i < maximumButtonInputs; i++)
 {
  buttonReadings[i] = 0; 
 }

 int currentButtonPress = 0;  //position conter for the array.

 do
 {
  // This is where I need to watch for button presses
  Button1.update();
  Button2.update();
  Button3.update();
  Button4.update();
  
  if(Button1.IsPushed())
  {
   buttonReadings[currentButtonPress] = 1;
   currentButtonPress++;
   delay(10);
   Serial.print("1"); 
  }

  if(Button2.IsPushed())
  {
    buttonReadings[currentButtonPress] = 2;
    currentButtonPress++;
    delay(10);
    Serial.print("2");
  }

  if(Button3.IsPushed())
  {
    buttonReadings[currentButtonPress] = 3;
    currentButtonPress++;
    delay(10);
    Serial.print("3");
  }

  if(Button4.IsPushed())
  {
    buttonReadings[currentButtonPress] = 4;
    currentButtonPress++;
    delay(10);
    Serial.print("4");
  } 
 }
 while(currentButtonPress < maximumButtonInputs);
 
 Serial.println();
 Serial.println("All four digits have been entered!");
 programModeActive = true;
 
 validateCode();
}

boolean validateCode()
{
  Serial.println("In validate code function");
  delay(1000);
  Serial.println(programModeActive);
  delay(1000);
  
  int i = 0;
  for(i=0;i<maximumButtonInputs;i++)
  {
    Serial.print(buttonReadings[i]);
  }
  Serial.println();
  delay(1000);
  
 if(programModeActive == false)
  {
    Serial.println("The program mode is false!");
    if(buttonReadings[0] == combination[0] && buttonReadings[1] == combination[1] && buttonReadings[2] == combination[2] && buttonReadings[3] == combination[3])
    {
      digitalWrite(Gled, HIGH);
      digitalWrite(Rled, LOW);
      programModeActive = false;
      userInputCount = 0;
      Serial.println("Correct!");
      return true;
    }
    else if (buttonReadings[0] != combination[0] && buttonReadings[1] != combination[1] && buttonReadings[2] != combination[2] && buttonReadings[3] != combination[3])
    {
      digitalWrite(Rled, HIGH);
      digitalWrite(Gled, LOW);
      programModeActive = false;
      userInputCount = 0;
      Serial.println("Wrong!");
      return false;
    }
  }

 if(programModeActive == true)
 {
 
 Serial.println("Going to save secret code...");
 saveSecretCode();
 programModeActive = false;
 return false;
 Serial.println("Done saving code!");
 }
// If we are recording a new code, save and leave function
/* Serial.println("Going into the save secret Code function soon...");
 if(programModeActive == true)
  {
    Serial.println("saveSecretCode....");
   saveSecretCode();
   programModeActive = false;
   return false; 
   Serial.println("Out of save secret code!");
  }*/
}

// Saves a new code to eeprom
void saveSecretCode()
{
  EEPROM.write(0, 0); // clear out the signature. That way we know if we didn't finish the write successfully
  for (int i=0; i<maximumButtonInputs; i++)
  {
    EEPROM.write(i+1, buttonReadings[i]);
  }
  EEPROM.write(0, eepromValid);
  digitalWrite(Yled, LOW);
  Serial.println("Done Saving new code! Must RESTART!!!");
  return ;
}

/*void readSecretCode()
{
  byte reading;
  int i;
  reading = EEPROM.read(0);
  if(reading == eepromValid) // only read EEPROM if signature byte is correct.
  {
   for(int i=0; i < maximumButtonInputs; i++)
   {
    combination[i] = EEPROM.read(i+1); 
   }
  }
}*/



/* void initializeCode()
{
  byte codeSetMarker = EEPROM.read(0);
  if (codeSetMarker == codeSetMarkerValue)
  {
    code = readSecretCodeFromEEPROM();
  }
  else
  {
    code = defaultCode;
  }
}

int readSecretCodeFromEEPROM()
{
  byte high = EEPROM.read(1);
  byte low = EEPROM.read(2);
  return (high << 8) + low;
}

void saveSecretCodeToEEPROM()
{
  EEPROM.write(0, codeSetMarkerValue);
  EEPROM.write(1, highByte(code));
  EEPROM.write(2, lowByte(code));
}

void attemptUnlock()
{
  if (code == Serial.parseInt())
  {
    unlock();
  }
  else
  {
    Serial.println("Incorrect code");
  }
}

void lock()
{
  locked = true;
  Serial.println("LOCKED");
  digitalWrite(Rled, HIGH);
  digitalWrite(Gled, LOW);
}

void unlock()
{
  locked = false;
  Serial.println("UN-LOCKED");
  digitalWrite(Gled, HIGH);
  digitalWrite(Rled, LOW);
}

void changeCode()
{
  code = Serial.parseInt();
  saveSecretCodeToEEPROM();
  Serial.print("Code Changed to:");
  Serial.println(code);
} */
int combination[4] = {1, 2, 3, 4};
int buttonReadings[maximumButtonInputs];

Maybe you need to use long or long long to hold values of that size. Appropriate types do not waste memory.

  byte reading;

  reading = EEPROM.read(0);

Please explain the advantages of declaring a variable and initializing the variable using two lines of code, over declaring and initializing the variable using one line of code.

  byte reading = EEPROM.read(0);
const byte eepromValid = 123;

const int maximumButtonInputs = 4;

By convention, constants use all upper case names (and short ones).

  Serial.println("Enter the secret code or press program button.");
}

It's hardly a secret after you just told them what the code is.

Why are you delay()ing after each switch is pressed?

 if(programModeActive == true)
 {
 }
 else if(userInputCount == 4 && programModeActive == false)
 {

If programModeActive is not true, is there some other value, besides false, that it can have? If there isn't, and "maybe" is certainly not an option, then the test for false is useless.

 do
 {

The number of cases where do/while is appropriate is very, very small. I doubt that it is here.

 programModeActive = false;
 return false;
 Serial.println("Done saving code!");
 }

Typing code after a return statement is an exercise in futility.

It is entirely possible to have a function that has exactly one return statement. Writing code that way is a goal of every serious programmer. Rewrite your validateCode() function so that it has exactly one return statement.

Use Tools + Auto Format so that your code at least has the appearance of not having been typed by a drunken monkey.

When you want us to look at code EXERCISE YOUR DELETE KEY. We do NOT need to see, and wade through, all that commented out code.