Store LCD Input

I have a school project where I create a Morse Code decoder. It goes like this:

The user will input a series of dots & dashes (dits & dahs, in Morse parlance)

This will display in the second line of an LCD Display

When the user indicates that they are done with a certain character, the dits & dahs in the second line will clear & the next free column in the first line will populate with the appropriate character, if it exists (I haven't sorted out an error state yet)

The display will look a bit like this:
State 0:
________ (Ignore this, necessary text to fix forum syntax)
.-_______
State 1:
A_______
-...______
State 2:
AB______
-.-.______
State 3:
ABC_____
_________(Ignore this, necessary text to fix forum syntax)

And so on

The only problem is that I have no way to store the second row's input to compare it to my list of Morse code conversions. I've looked into reading the second row of the LCD, but apparently that's too difficult of a task, according to those who know better than me in a long dead topic

Here is the code that I have written, even though it's not that far along & not too related to my problem, I figure it would be good to share with the class:

#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//Code graciously copied from Arduino documentation site https://docs.arduino.cc/learn/electronics/lcd-displays#hello-world-example
//The following declarations will need editing
int ledPin = 1;  // LED connected to digital pin 11
int pushPin = 7;    // pushbutton connected to digital pin 7
int val = 0;      // variable to store the read value
    char engChars[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','.',',','!','?','/','='};
    String morseInputs[]= {".-","-...","-.-.","-..",".","..-.","--.","....","..","-","-.-",".-..","--","-.","---",".--.","--.",".-.","...","-","..-","...-",".--","-..-","-.--","--..",".-.-.-","--..--","-.-.--","..--..","-..-.","-...-"};
void setup() 
  {
    Serial.begin(9600);
  }

void loop() 
  {
      testCorrectConversion();
  }

void LCDInput()
{

}
void testCorrectConversion()
  {
    //Run this when you make an edit to engChars[] or morseInputs[] and you want to ensure that they are accurate
    //This should print the character and its Morse equivalent
      
      //This section tests length of both arrays
    int engCharsLength = sizeof(engChars) / sizeof(engChars[0]);
    int morseInputsLength = sizeof(morseInputs) / sizeof(morseInputs[0]);
    // Serial.println("engCharsLength");
    // Serial.println(engCharsLength);
    // delay(1000);
    // Serial.println("morseInputsLength");
    // Serial.println(morseInputsLength);
    // delay(1000);
    for(int i = 0; i < engCharsLength; i++)
    {
    Serial.print(engChars[i]);
    Serial.print(" -> ");
    Serial.println(morseInputs[i]);
    }
    delay(1000);
  }

Why?
Are this not you who send the data to the LCD screen?
Instead of reading the data from LCD, is not a better to store it BEFORE sending to screen?

Yes I've considered that. I neglected to include that in my post.

In the past 20 minutes, I've considered making a method to take the inputs (dits & dahs) & store it in a character array.

Then maybe returning this result into another method that would compare it to morseInputs[] & if it exists in the array, take its index & return the appropriate index in engChars[]? Through that, I would be able to decode the Morse.

Am I getting somewhere here?

Where is your input coming from? You must be reading it in order to display it on the LCD, so just save it as part of the input routine. Will it be a normal button like a real morse code machine?

int ledPin = 1; // LED connected to digital pin 11
Pin 1 or 11?
Pin 1 is serial pin, not recommended use as digital pin.

The code you posted does not generate the printout that is in your topic.

The input will come from 3 buttons. One button to input a dit, a second for a dah, and third that indicates the user is done with the character & does as follows in my OP:

The third button, if pressed twice, will input a blank space.

I am still considering how to save the button inputs as dits & dahs.

Would this pseudocode work?

LCD.print(morseString)

int maxInputSize = 4 (longest valid Morse input is 5 inputs long)
char inputArray[maxInputSize] 

for(i = 0; i<maxInputSize; i++)
{
if (button1 pressed)
charArray[i] = .
else if (button2 pressed)
charArray[i] = -
}

//This should give me a character array of my inputs

String morseString = String(inputArray)

//I'm not used to working with C++ so I'm wary of running into null pointer exceptions here

& then doing the rest of the work as outlined here:

Finding the matching Morse code should be done with a for loop & a string comparison, no? That part seems easy enough.

I realize as I write this that every new morse conversion will reset my display. Any advice on how to resolve that?

I was considering doing something like this to solve that problem. I know this riddled with syntax errors (it's very nearly copy-paste code). I will cross that bridge when I get there but I would love some guidance on how to fix it up.

int lcdText = 15
memmove(engChars, & engChars[1], sizeof(lcdText) - 1);
for (int i = 0; i < 16; i++){
    lcd.print(engChars[i]);
  }
//This moves my new character input to the right of the previous character

How does all of this look? Are there any outstanding issues?

Yes. I did note that the declarations would need editing in the code, though.

I also mentioned that I knew the code so far wasn't related to my problem, I just figured it would be good practice to include what I had.

It sounds like you need something like this (using the Bounce2 library to handle the buttons)

const byte ditPin = 3;
const byte dahPin = 4;
const byte donePin = 5;

#include <Bounce2.h>

// INSTANTIATE  Button objects
Bounce2::Button ditButton = Bounce2::Button();
Bounce2::Button dahButton = Bounce2::Button();
Bounce2::Button doneButton = Bounce2::Button();

void setup() {

  // BUTTON SETUP 
  
  ditButton.attach( ditPin,  INPUT_PULLUP ); // USE INTERNAL PULL-UP
  diahButton.attach( dahPin,  INPUT_PULLUP ); // USE INTERNAL PULL-UP
  doneButton.attach( donePin,  INPUT_PULLUP ); // USE INTERNAL PULL-UP

  const int debounceTime = 10;  // milliseconds
  ditBbutton.interval(decounceTime); 
  dahBbutton.interval(decounceTime); 
  doneBbutton.interval(5decounceTime); 

  // INDICATE THAT THE LOW STATE CORRESPONDS TO PHYSICALLY PRESSING THE BUTTON
  ditButton.setPressedState(LOW); 
  dahButton.setPressedState(LOW); 
  doneButton.setPressedState(LOW); 
}

const byte morseCodeMax = 5;  // longest code plus trailing nul
char morseCode[morseCodeMax];
int morseIndex = 0; // current location within array

void loop() {
  // UPDATE THE BUTTON
  // YOU MUST CALL THIS EVERY LOOP
  ditButton.update();
  dahButton.update();
  doneButton.update();

  if ( ditButton.pressed() ) {
    morseCode[morseIndex] = '.';
    morseIndex++;
  }
  if ( dahButton.pressed() ) {
    morseCode[morseIndex] = '-';
    morseIndex++;
  }

  // make sure we do not exceed array
  if ( morseIndex >= morseCodeMax ) morseIndex--;
  
  if ( doneButton.pressed() ) {
    morseIndex = '\0';
    // decode your array into a character and display it
  }
}

An easier appproach would be to use 0 and 1 for your morse code so you only need numeric comparisons

I understand. My lab partner & I are going to try to do this with a while loop instead. Say:

while(end state pin LOW){
accept inputs; 
}
if (end state pin HIGH){ 
proceed with character assignment logic
}

Why would I not need a string. Aren't chars & strings different data types? Can you compare them?

Noted. Thank you for the heads up.

I was considering Debounce. What are the key differences between the two and why would I prefer one over the other?

Argh why didn't I think of using some binary?

I thought about this a bit more and since Morse code is a variable number of dits & dahs, you will need 3 states to represent dit, dah, and invalid
00 = invalid
01 = dit
10 = dah
11 = invalid

so you take a byte and break it up into 4 parts

76543210 (bit within byte)
aabbccdd

so, for example,
A = dit, dah (or maybe I got this backwards)
so that would be 01 10 00 00 = 0x60 = 96

J = dit, dah, dah, dah = 01 10 10 10 = 0x6C = 108

and so on...

I want to make it clear that this might be beyond my current ability. I am familiar with binary, of course, but I am not too comfortable with your method.

Also, I was thinking about this:

And I realized I forgot to include a way for the user to indicate that they are done with inputs. I could include

else if (button 3 pressed){
return;
}

Would this work? It seems simple enough

Very late update: We finished our project! We got full marks on it. We received quite a bit of help from a fellow student who is a better coder. We were also told that this would be easier with a Hash table assigning the morse code to the characters, but it would be memory intensive. Here is the code in its entirety:

#include <LiquidCrystal.h>
#define NOTE_A4 440
#define NOTE_G5 784

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 11, en = 12, d4 = 2, d5 = 3, d6 = 4, d7 = 5;  // LCD pin assignments
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int operation_mode = 1;                // sets operation mode for system, 0 for pushbuttons, 1 for telegraph key
bool demo = true;                      // enables demo mode for telegraph key
String demoMessage = "GO GAMECOCKS!";  // demo message that user will be taught how to write in morse

// Pin assignments
int ditPin = 6;      // Dit button connected to digital pin 6
int dahPin = 7;      // Dah button connected to digital pin 7
int endCharPin = 8;  // End character button connected to digital pin 8
int speakerPin = 9;  // Speaker output connected to digital pin 9
int keyerPin = 10;   // Telegraph keyer connected to digital pin 10
int resetPin = 13;   // Rest button clears the lcd, connected to digital pin 13

// dit and dah length initialization - change this to change dit and dah length for all modes of operation (200 ms works well)
int ditLength = 200;            // amount of time in ms for one dit
int dahLength = 3 * ditLength;  // dah length is 3 times dit length

int clicks = 0;  // to count if a double click occurs on endChar button

// Variables for debouncing logic
unsigned long lastDebounceTime = 0;
int debounceDelay = 50;     // amount of time necessary between inputs for system to recognize two inputs (in ms)
int lastKeyerState = HIGH;  // keyer initialized as HIGH due to pullup resistor
int reading;
int keyerState;
unsigned long timePressed;  // how long telegraph key is pressed down for

// Variables for release of keyer (dead time)
unsigned long releaseTime;  // calculated when telegraph key is disconnected
unsigned long deadTime;     // how long telegraph key is disconnecteed (dead time)

// extra variables for statistics and debugging
int retries;           // keeps track of how many times the user has to retry a morse input in the demo mode
String unbrokenMorse;  // can be printed to show the entire morse string at once

// string to hold mcurrent morse message and decoded message for all modes of operation
String morseCode = "";       // String to store Morse code input
String decodedMessage = "";  // String to store decoded message

// arrays of all english characters and their matching morse inputs
char engChars[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '.', ',', '!', '?', '/', '=' };
String morseInputs[] = { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", ".-.-.-", "--..--", "-.-.--", "..--..", "-..-.", "-...-" };

void setup() {
  Serial.begin(9600);
  // testCorrectConversion();         // uncomment this to check if morse inputs are correctly matched with their english translation
  pinMode(speakerPin, OUTPUT);        // initialize output for speaker
  pinMode(ditPin, INPUT_PULLUP);      // Dit pin will read HIGH unless button is pressed
  pinMode(dahPin, INPUT_PULLUP);      // Dah pin will read HIGH unless button is pressed
  pinMode(endCharPin, INPUT_PULLUP);  // endChar pin will read HIGH unless button is pressed
  pinMode(keyerPin, INPUT_PULLUP);    // keyer pin will read HIGH unless button is pressed
  pinMode(resetPin, INPUT_PULLUP);    // reset pin will read HIGH unless button is pressed
  lcd.begin(16, 2);                   // initalize size of LCD
  lcd.setCursor(0, 1);                // set cursor to first column of second row of LCD
}

// compares morseCode input to morseInputs array to find matching english charactes
void decodeMorse() {
  for (int i = 0; i < sizeof(morseInputs) / sizeof(morseInputs[0]); i++) {
    if (morseCode.equals(morseInputs[i])) {
      decodedMessage += engChars[i];
      // Serial.print(decodedMessage);
      break;
    }
  }
}

// Slightly altered decoding function for the demo operation
// Decodes the morse input, then checks if it matches the next letter of the demo message
// If it matches, that char is added to the decoded message, if it doesn't match, the character is not added and the user gets to try again
void decodeMorse(int index) {
  // compare morseCode input to morseInputs array to find matching english character
  for (int i = 0; i < sizeof(morseInputs) / sizeof(morseInputs[0]); i++) {
    if (morseCode.equals(morseInputs[i])) {
      if (demoMessage[index] == engChars[i]) {
        decodedMessage += engChars[i];
        // Serial.print(decodedMessage);
        break;
      } else {
        errorTone();
        retries += 1;
        lcd.setCursor(0, 1);
        lcd.print("                ");
        lcd.setCursor(0, 1);
        lcd.print(English_to_Morse(demoMessage, index));
        break;
      }
    }
  }
}

// Used when operation mode is 0
void buttonHandler() {
  // Dit button handler
  if (digitalRead(ditPin) == LOW) {
    clicks = 0;                                // reset click counter for endChar pin
    tone(speakerPin, NOTE_G5, ditLength);      // play tone for length of dit
    morseCode += ".";                          // add "." to morse code String
    lcd.setCursor(morseCode.length() - 1, 1);  // move cursor to end of morse code message
    lcd.print(".");                            // print the dit to the LCD
    delay(200);
  }
  // Dah button handler
  if (digitalRead(dahPin) == LOW) {
    clicks = 0;                                // reset click counter for endChar pin
    tone(speakerPin, NOTE_G5, dahLength);      // play tone for length of dah
    morseCode += "-";                          // add "-" to morse code string
    lcd.setCursor(morseCode.length() - 1, 1);  // move cursor to end of morse code message
    lcd.print("-");                            // print the dah to the LCD
    delay(200);
  }
  // endChar button handler
  if (digitalRead(endCharPin) == LOW) {
    if (clicks == 0) {
      decodeMorse();  // decode morse input to english character
      unbrokenMorse += morseCode;
      unbrokenMorse += " ";
      morseCode = "";                 // reset morse input string
      lcd.setCursor(0, 0);            // move lcd cursor to beginning of first line
      lcd.print(decodedMessage);      // print new decoded message to lcd
      lcd.setCursor(0, 1);            // move cursor to beginning of bottom row
      lcd.print("                ");  // clear the bottom row of morse (16 spaces)
      lcd.setCursor(0, 1);            // move cursor to beginning of bottom row
      delay(200);
      clicks += 1;  // increment counter for number of time endChar button has been pressed
      Serial.println(unbrokenMorse);
      // playMorse(unbrokenMorse);
    }
    // if clicks is 1, second push of endChar button registers as a double push and adds a space to the message
    else {
      lcd.setCursor(decodedMessage.length() - 1, 0);  // move cursor to end of decoded message
      decodedMessage += " ";                          // add a space to decoded message
      lcd.setCursor(0, 0);
      lcd.print(decodedMessage);  // print message
      delay(250);
      clicks = 0;  // reset clicks counter
    }
  }
}

// Used when operation mode is 1 and demo = false
void telegraphKeyHandler() {
  reading = digitalRead(keyerPin);

  if (reading != lastKeyerState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != keyerState) {
      keyerState = reading;
      if (digitalRead(keyerPin) == LOW) {
        tone(speakerPin, NOTE_G5);  // play tone
        unsigned long start = millis();

        while (digitalRead(keyerPin) == LOW) {
          timePressed = millis() - start;
        }

        if (timePressed < ditLength) {  // check if telegraph key was pressed for less than a dit length
          morseCode += ".";             // add a dit to the morse code string
          lcd.setCursor(morseCode.length() - 1, 1);
          lcd.print(".");    // print the dit to the lcd
        } else {             // if telegraph key is pressed longer than a dit, it is registered as a dah
          morseCode += "-";  // add a dah to the morse code string
          lcd.setCursor(morseCode.length() - 1, 1);
          lcd.print("-");  // print the dah to the lcd
        }
        delay(ditLength);    // a space of a dit is between each individual morse input
        noTone(speakerPin);  // turn off tone
      } else {
        releaseTime = millis();
        while (digitalRead(keyerPin) == HIGH) {
          deadTime = millis() - releaseTime;
          // if deadTime exceeds the length of 3 dits (1 dah), the character is considered finished and is then translated
          if (deadTime > dahLength) {
            decodeMorse();                  // decode morse input to english character
            morseCode = "";                 // reset morse input string
            lcd.setCursor(0, 0);            // move lcd cursor to beginning of first line
            lcd.print(decodedMessage);      // print new decoded message to lcd
            lcd.setCursor(0, 1);            // move cursor to beginning of bottom row
            lcd.print("                ");  // clear the bottom row of morse (16 spaces)
            lcd.setCursor(0, 1);            // move cursor to beginning of bottom row
            delay(200);
            // if deadTime exceeds the length of 7 dits, it's translated to a space
            if (decodedMessage.length() > 0 && deadTime > ditLength * 7) {
              lcd.setCursor(decodedMessage.length() - 1, 0);
              decodedMessage += " ";
              lcd.setCursor(0, 0);
              lcd.print(decodedMessage);
              break;  // breaks out of while loop so only one space is inserted into message no matter how long the deadTime is (facilitates learning morse)
            }
          }
        }
      }
    }
  }
  lastKeyerState = reading;  // update the last keyer state
}

// Very similar to telegraphKeyHandler, used when operation mode is 0 and demo = true
void demoTelegraphKeyHandler(int index) {
  reading = digitalRead(keyerPin);

  if (reading != lastKeyerState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != keyerState) {
      keyerState = reading;

      if (keyerState == LOW) {
        tone(speakerPin, NOTE_G5);  // play tone
        unsigned long start = millis();
        while (digitalRead(keyerPin) == LOW) {
          timePressed = millis() - start;
        }
        if (timePressed < ditLength) {  // check if telegraph key was pressed for less than a dit length
          morseCode += ".";             // add a dit to the morse code string
          lcd.setCursor(morseCode.length() - 1, 1);
          lcd.print(".");    // print the dit to the lcd
        } else {             // if telegraph key is pressed longer than a dit, it is registered as a dah
          morseCode += "-";  // add a dah to the morse code string
          lcd.setCursor(morseCode.length() - 1, 1);
          lcd.print("-");  // print the dah to the lcd
        }
        delay(ditLength);    // a space of a dit is between each individual morse input
        noTone(speakerPin);  // turn off tone
      } else {
        releaseTime = millis();
        while (digitalRead(keyerPin) == HIGH) {
          deadTime = millis() - releaseTime;
          // if deadTime exceeds the length of 3 dits (1 dah), the character is considered finished and is then translated
          if (deadTime > dahLength) {
            decodeMorse(index);         // decode morse input to english character
            morseCode = "";             // reset morse input string
            lcd.setCursor(0, 0);        // move lcd cursor to beginning of first line
            lcd.print(decodedMessage);  // print new decoded message to lcd
            delay(200);
            // no logic for spaces here, doesn't work with how long the demo takes, instead, spaces are handled by tranNewUser()
            break;
          }
        }
      }
    }
  }
  lastKeyerState = reading;  // update the last keyer state
}

// called when operation mode = 1 and demo = true
// Trains user on a dit, dah, and the demo message with the telegraph key until they get it all right
void trainNewUser() {

  while (demo == true) {
    if (operation_mode == 1) {
      lcd.setCursor(0, 0);
      lcd.print("Let's Practice!");
      delay(2000);
      lcd.clear();
      lcd.print("Here's a dit");
      lcd.setCursor(0, 1);
      lcd.print(".");
      tone(speakerPin, NOTE_G5, ditLength);
      delay(2000);
      lcd.clear();
      lcd.print("Try a dit:");

      while (morseCode != ".") {  // train the user on a dit
        telegraphKeyHandler();
        if (morseCode == "-") {
          morseCode = "";
          errorTone();
          retries += 1;
          lcd.setCursor(0, 0);
          lcd.print("Try again...");
          delay(2000);
          lcd.clear();
          lcd.print("Here's a dit");
          lcd.setCursor(0, 1);
          lcd.print(".");
          tone(speakerPin, NOTE_G5, ditLength);
          delay(2000);
          lcd.clear();
          lcd.print("Try a dit:");
        }
      }
      morseCode = "";
      lcd.setCursor(0, 0);
      lcd.clear();
      lcd.print("Nice!");
      delay(2000);
      lcd.clear();
      lcd.print("Now try a dah");
      lcd.setCursor(0, 1);
      lcd.print("-");
      tone(speakerPin, NOTE_G5, dahLength);
      delay(2000);
      lcd.clear();
      lcd.print("Try a dah:");

      while (morseCode != "-") {  // train the user on a dah
        telegraphKeyHandler();
        if (morseCode == ".") {
          morseCode = "";
          errorTone();
          retries += 1;
          lcd.setCursor(0, 0);
          lcd.print("Try again...");
          delay(2000);
          lcd.clear();
          lcd.print("Here's a dah");
          lcd.setCursor(0, 1);
          lcd.print("-");
          tone(speakerPin, NOTE_G5, dahLength);
          delay(2000);
          lcd.clear();
          lcd.print("Try a dah:");
        }
      }
      morseCode = "";
      lcd.setCursor(0, 0);
      lcd.clear();
      lcd.print("Nice!");
      delay(2000);
      lcd.clear();
      lcd.print(demoMessage);
      lcd.setCursor(0, 1);
      delay(2000);
      lcd.clear();

      while (decodedMessage != demoMessage) {  // train the user with the demo message
        for (int i = 0; i < demoMessage.length(); i++) {
          lcd.setCursor(i, 0);
          lcd.print(demoMessage.charAt(i));
          delay(500);
          lcd.setCursor(i, 0);
          lcd.print(" ");
          delay(500);
          lcd.setCursor(i, 0);
          lcd.print(demoMessage.charAt(i));
          delay(500);
          lcd.setCursor(0, 1);
          lcd.print(English_to_Morse(demoMessage, i));
          while (decodedMessage.charAt(i) != demoMessage.charAt(i)) {
            demoTelegraphKeyHandler(i);
            if (demoMessage.charAt(i) == ' ') {
              decodedMessage += ' ';
              delay(200);
              break;
            }
          }
          lcd.setCursor(0, 1);
          lcd.print("                ");
          // Serial.println(retries);
        }
      }
      delay(1000);
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Nice!");
      lcd.setCursor(0, 1);
      lcd.print("Only ");
      lcd.print(retries);  // print the number of retries for each user
      lcd.print(" retries!");
      delay(4000);
      lcd.clear();
      decodedMessage = "";
      retries = 0;  // reset retries counter
    }
  }
}

// Takes in a specific char index of a string and translates it and returns the matching morse string
String English_to_Morse(String inputString, int index) {
  String morse_translation;

  // compare morseCode input to morseInputs array to find matching english character
  for (int i = 0; i < sizeof(engChars) / sizeof(engChars[0]); i++) {
    if (inputString.charAt(index) == engChars[i]) {
      morse_translation += morseInputs[i];
      break;
    }
  }
  return morse_translation;
}

// Plays the tone for dits and dahs in a string of morse, spaces must be included in the string
void playMorse(String Morse) {
  for (int i = 0; i < Morse.length(); i++) {
    if (Morse.charAt(i) == '.') {
      tone(speakerPin, NOTE_G5, ditLength);
      delay(ditLength);
    }
    if (Morse.charAt(i) == '-') {
      tone(speakerPin, NOTE_G5, dahLength);
      delay(dahLength);
    }
    if (Morse.charAt(i) == ' ') {
      delay(dahLength);
    }
    delay(ditLength);
  }
}

// plays a sound that sounds like you made an error
void errorTone() {
  tone(speakerPin, A4, 500);
  delay(300);
  tone(speakerPin, A4, 500);
}

//Run this when you make an edit to engChars[] or morseInputs[] and you want to ensure that they are accurate
//This should print the character and its Morse equivalent
void testCorrectConversion() {
  //This section tests length of both arrays
  int engCharsLength = sizeof(engChars) / sizeof(engChars[0]);
  int morseInputsLength = sizeof(morseInputs) / sizeof(morseInputs[0]);

  for (int i = 0; i < engCharsLength; i++) {
    Serial.print(engChars[i]);
    Serial.print(" -> ");
    Serial.println(morseInputs[i]);
  }
  delay(1000);
}

// Main loop
void loop() {
  // reset button doesn't work with demo mode, only operation mode 0 and operation mode 1 with no demo
  if (digitalRead(resetPin) == LOW) {
    lcd.clear();
    morseCode = "";
    decodedMessage = "";
  }
  // Operation mode 0 uses three buttons as user inputs, the ditPin, the dahPin, and the endCharPin
  if (operation_mode == 0) {
    buttonHandler();
  }

  // Operation mode 1 uses the telegraph key as the input, where the length of each press matters and no input (dead time) equals a space
  if (operation_mode == 1) {
    if (demo == true) {
      trainNewUser();
    } else {
      telegraphKeyHandler();
    }
  }
}

Thank you all for the help!