Custom function not recognizing other functions

So I am creating a custom library for a school project with my group and we hit a snag when implementing it. We are using a custom library for an LCD display and for a PS/2 keyboard. We are wanting to condense the amount of code needed to get user input from the keyboard display it on the LCD and check if it is a valid input. This means the custom library named Functions.h needs to use those libraries to do the functions it needs to. I have them both included in the .cpp and .h file for our custom library but that doesn't solve it. Any suggestions to try would be very helpful! I can also attach my cpp and h code if that is need to clarify anything about my code.

#include <Functions.h>
#include <PS2Keyboard.h>
#include <LiquidCrystal_I2C.h>


const int KeyData = 8; //data pin of keyboard
const int KeyClock = 3; //clock pin of keyboard
char welcome[]="RISC-V Demo"; //welcome message
char input; //var to handle keystrokes
String command=""; //var to store the completed command that will be checked to see if valid
int commandIndex=0; //var to know where at in command to take a char away when backspace is pressed
String numConvert=""; //var that will be need to be converted to int
String listOfCommands="1. ADD 2. SUB 3. AND";
int commandNum; //var for switch statement linked to the command entered by the user
int numConvertIndex=0; //var to know where at in numConvert to take a char away when backspace is pressed
int bitStream[32]; //var to store the bits to be sent to the FPGA

PS2Keyboard keyboard; //declare instance of keyboard
LiquidCrystal_I2C lcd(0x27,20,4); //delcare instance of lcd
functions fpga;

void setup() {
  lcd.init(); //start lcd
  lcd.backlight(); //turns lcd backlight on
  delay(1000);
  keyboard.begin(KeyData, KeyClock); //starts keyboard
  for(int j=0; j<2; j++){ //loops to display the welcome message
  for(int i=0; i<4; i++){
    lcd.setCursor(5,i);
    lcd.print(welcome);
    delay(500);
    lcd.clear();
      }
  }

}

void loop() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Enter your command:");
  lcd.setCursor(0,1);
  lcd.print(command);
  delay(50);
  if(keyboard.available()){
    input=keyboard.read();

    if(input == PS2_DELETE){ //if the keystroke is the backspace, remove the last keystroke from the command string and change commandIndex accordingly
      if(commandIndex!=0){
        command.remove(commandIndex-1);
        commandIndex-=1;}
      }
      else if(input == PS2_ENTER){ //if enter is pressed check to see a vaild command then run the command
      //code needs to be inserted to change the command into a respecting int value to be used in the switch statement below
        commandNum = fpga.which_command(command);
      
      
      
      switch (commandNum){
        
        case 1://if the add command is entered ask for numbers
          fpga.ADD(bitStream);
          fpga.transmit(bitStream);
          command="";
          break;
        
        
        
        
        case 2:
        fpga.SUB(bitStream);
        fpga.transmit(bitStream);
        command="";
        break;

        case 3:
        fpga.AND(bitStream);
        fpga.transmit(bitStream);
        command="";
        break;

          default:
          lcd.setCursor(2,0);
          lcd.print("Invalid command");
          command="";
          delay(50);
       }

      }
      else if (isAlphaNumeric(input)){
        command.concat(input);
        command.toUpperCase();
        commandIndex++;
      }
      else{
        lcd.setCursor(0,2);
        lcd.print("That's not a vaild input");
      }
  delay(100);
  }
}

Error Message

Arduino: 1.8.5 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp: In member function 'void functions::user_input()':

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:234:4: error: 'lcd' was not declared in this scope

lcd.clear();

^

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:240:4: error: 'input' was not declared in this scope

input = keyboard.read();

^

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:240:12: error: 'keyboard' was not declared in this scope

input = keyboard.read();

^

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:295:3: error: 'lcd' was not declared in this scope

lcd.clear();

^

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:300:3: error: 'input' was not declared in this scope

input = keyboard.read();

^

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:300:11: error: 'keyboard' was not declared in this scope

input = keyboard.read();

^

exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

C:\Users\Kyle\Documents\Arduino\libraries\Custom_lib\Functions.cpp:234:4: error: 'lcd' was not declared in this scope

    lcd.clear();

    ^

In your Functions.cpp file at line 234: you are trying to use "lcd" without declaring it first.
Perhaps you need to declare it in your Function.h
make sure to include all appropriate headers.

"custom library named Functions.h needs to use those libraries to do the functions it needs to. I have them both included in the .cpp and .h file for our custom library but that doesn't solve it."

You are yet "another victim " of Arduino misguided usage of the term "library".
Your program consist of multiple .h /.cpp files and they are compiled individually FIRST then linked together next.
That means each .h/.cpp pair has to have ALL necessary files "included".
And they have to be "included" in correct order.

Compiler is telling you they are NOT - simple as that.

Perhaps posting the "includes" lines of your "library" will help to point out the errors.

Your functions.cpp is trying to use a variable in your YourSketch.ino file.

To do this, it needs to have a declaration telling it what that variable is. Each .ino and .cpp file is compiled seperately, independently. They are linked together later by the linker. functions.cpp doesn't know what's in YourSketch.ino, you have to tell it.

So, add

extern LiquidCrystal_I2C lcd;

to your functions.cpp .

I would tend not to add it to functions.h, because functions.h is how 'functions' informs the other parts of your sketch what is in itself. If there is stuff in your main ino that other things need, then you would normally write a 'YourSketch.h' (or whatever the name of your man sketch is) and include that in the places that need it.

PaulMurrayCbr:
Your functions.cpp is trying to use a variable in your YourSketch.ino file.

To do this, it needs to have a declaration telling it what that variable is. Each .ino and .cpp file is compiled seperately, independently. They are linked together later by the linker. functions.cpp doesn't know what's in YourSketch.ino, you have to tell it.

So, add

extern LiquidCrystal_I2C lcd;

to your functions.cpp .

I would tend not to add it to functions.h, because functions.h is how 'functions' informs the other parts of your sketch what is in itself. If there is stuff in your main ino that other things need, then you would normally write a 'YourSketch.h' (or whatever the name of your man sketch is) and include that in the places that need it.

Putting the extern keyword in worked just fine for complying the code as for the includes that I have they are the following:

#include "Functions.h"
#include "Arduino.h"
#include "WString.h"
#include "PS2Keyboard.h"
#include "LiquidCrystal_I2C.h"

any other suggestions for building custom "libraries" for Arduino for future reference? Thanks!

If you write a custom 'library' for the lcd, lcd should not even be in the main ino sketch in my opinion. It should be in the libraries cpp file and be unknown to the rest of the other files in your project.

I'm currently working on a short tutorial (OK, it's already 30 pages because it also describes how to get to the solutions and some other stuff) how to use one of those 5 button lcd shields. It basically uses a C approach but takes advantage of polymorphism in object oriented programming (CPP).

CPP file

// needed so compiler knows about the used IO pins
#include "io.h"
// needed so compiler knows about LiquidCrystal class
#include <LiquidCrystal.h>

// default number of columsn and rows
static byte numCols = 16;
static byte numRows = 2;

// construct a LiquidCrystal object
LiquidCrystal lcd(pinLcdRS, pinLcdEna, pinLcdD4, pinLcdD5, pinLcdD6, pinLcdD7);

/*
  initialise the display
*/
void displayBegin()
{
  lcd.begin(numCols, numCols);
}

/*
  initialise the display with given number of columns and rows
  In:
    number of columns
    number of rows
*/
void displayBegin(int noOfColumns, int noOfRows)
{
  // remember number of columns and number of rows
  numCols = noOfColumns;
  numRows = noOfRows;
  displayBegin();
}

...
...

The H file contains the function prototypes that I think I will currently need; I haven't defined the final project yet so the needed functions might change.
H file

#ifndef DISPLAY_H
#define DISPLAY_H

void displayBegin();
void displayBegin(int noOfColumns, int noOfRows);
void displayClear();
void displayClear(int row);
void displayPrint(int x, int y, const char *txt);
void displayPrint(int x, int y, int number);
void displayPrint(int x, int y, char ch);

#endif

When you include the H file in e.g. the main sketch, the compiler only knows about the functions declared in the H file.

Functions used in e.g. the main sketch but not (yet) implemented in the CPP file will result in linker errors.

Using this approach forces the rest of your code to only use the known functions; the code in other files can not use any of the normal lcd methods.

Note:
This is not intended to be a real library but part of the project (multiple tabs in the IDE or to be located in the src subdirectory of the sketch directory).

Thanks for the help! I had never came across the extern keyword in any C++ coding that I've done in the past. The LCD and keyboard "libraries" are made by someone else and I don't plan on messing with the code that they already wrote because the LCD only needs 2 pins for data (SDA and SCL pins on our Mega) and the keyboard works better than I had hoped it would. In the long run I'm glad I came across this problem and got just a little more knowledge of how all this works.