#include <LiquidCrystal.h>
#include <Keypad.h>
#include <Servo.h>
// Defining PIN number for system entry
#define CORRECT_PIN "3112"
// Variable which when true will trigger the alarm
volatile boolean alarmState = false;
// Declaring variables for incorrect PIN entry
// And petrol type and quantity
int incorrectEntries = 0;
int petrolType = 0;
int petrolQuantity = 0;
String prompt = "Enter PIN: ";
// Specifying pins for rows and columns
const byte ROWS = 4;
const byte COLS = 4;
byte rowPins[ROWS] = {5, 4, 3, 2};
byte colPins[COLS] = {A3, A2, A1, A0};
// specifying key matrix
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
// Setting pins for LCD display
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// specifying keypad map
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
lcd.begin(16, 2);
lcd.print("Enter PIN: ");
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// Calling function for intial key presses for PIN
pinAccess(incorrectEntries);
// Calling function to get pump letter
getPump();
// Calling function to get pertrol type
getPetrolType(petrolType);
// Calling function to get spacer letter (A)
getSpacer(petrolType);
// Calling function to get petrol quantity
getPetrolQuantity(petrolQuantity, petrolType);
// Calling function to display total cost
displayTotal(assignPrice(petrolType) * petrolQuantity);
}
// Records user input for PIN
void pinAccess(int &incorrectEntries) {
// Variables to record PIN input and amount of input
static char pinInput[5];
static byte pinIndex = 0;
char key;
// infinite loop
while (true) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
if (key) {
// If key is a number and have room in array then record key
if (pinIndex < 4 && key >= '0' && key <= '9') {
pinInput[pinIndex++] = key;
lcd.print("*");
} else if (key == '#') {
// If key is # then check if array matches CORRECT_PIN
// Nullifying the # so PINs can be compared accurately
pinInput[pinIndex] = '\0';
if (validatePIN(pinInput, incorrectEntries)) {
// If PINs match, reset array and index counter
memset(pinInput, '\0', sizeof(pinInput));
pinIndex = 0;
break;
}
}
}
}
}
// Checks if user input matches PIN
boolean validatePIN(char pinInput[], int &incorrectEntries) {
lcd.clear();
// If PINs match, grant entry
if (strcmp(pinInput, CORRECT_PIN) == 0) {
lcd.print("Entry Granted");
incorrectEntries = 0;
nonBlockingDelay(2500);
return true;
// If PINs do not match entry denied
} else {
lcd.print("Entry Denied");
incorrectEntries++;
nonBlockingDelay(2500);
if (incorrectEntries >= 3) {
incorrect();
incorrectEntries = 0;
}
lcd.clear();
lcd.print("Enter PIN: ");
prompt = "Enter PIN: ";
return false;
}
}
// Locks system if PIN incorrect 3 times
void incorrect() {
lcd.clear();
lcd.print("System Locked...");
for (int i = 0; i < 45; i++) {
blinkLED();
}
lcd.clear();
lcd.print("Enter PIN:");
prompt = "Enter PIN: ";
}
// Flashes LED at 1 Hz
void blinkLED() {
digitalWrite(LED_BUILTIN, HIGH);
nonBlockingDelay(500);
digitalWrite(LED_BUILTIN, LOW);
nonBlockingDelay(500);
}
// Customised delay function such that alarm can still be triggered
void nonBlockingDelay(int delayTime) {
char key;
long startTime = millis();
while (millis() - startTime < delayTime) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
if (key == '#') {
alarmState = false;
digitalWrite(LED_BUILTIN, LOW);
delayTime = 0;
lcd.clear();
lcd.print(prompt);
break;
}
}
}
// Checks if the alarm key has been pressed
void alarmCheck(char key) {
if (key == '*') {
// sets alarm to true and calls alarm method if '*' pressed
alarmState = true;
alarm(alarmState);
}
}
// Shows alarm message and blinks LED, waits for # key press
void alarm(volatile boolean &alarmState) {
char key;
lcd.clear();
lcd.print("ALARM");
while (alarmState) {
blinkLED();
}
}
// Alerts user to an invalid user entry
void invalidEntry() {
lcd.clear();
lcd.print("Invalid Entry");
nonBlockingDelay(2000);
}
// Prompts for pump and takes user entry
void getPump() {
lcd.clear();
lcd.print("Pump ID: ");
prompt = "Pump ID: ";
char key;
while (true) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
if (key) {
// If entry is letter then advise of selected pump
if (key >= 'A' && key <= 'D') {
lcd.clear();
lcd.print("Pump ");
lcd.print(key);
lcd.print(" Selected");
nonBlockingDelay(2500);
break;
// If entry is not a letter then invalid entry
} else if (key >= '0' && key <= '9') {
invalidEntry();
lcd.clear();
lcd.print("Pump ID: ");
prompt = "Pump ID: ";
}
}
}
}
// Prompts for petrol type and takes user entry
void getPetrolType(int &petrolType) {
char key;
lcd.clear();
lcd.print("Enter Order:");
prompt = "Enter Order:";
while (true) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
// If entry is a valid fuel type then display entry
if (key >= '1' && key <= '5') {
petrolType = key - '0';
lcd.print(petrolType);
break;
// calls invalid entry if not valid petrol type
} else if ((key >= '6' && key <= '9') ||(key >= 'A' && key <= 'D')) {
invalidEntry();
lcd.clear();
lcd.print("Enter Order:");
prompt = "Enter Order:";
}
}
}
// Prompts user for spacer (A)
void getSpacer(int petrolType) {
char key;
while (true) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
// checks if 'A' is entered if not then calls invalid entry
if (key == 'A') {
lcd.print('A');
break;
} else if ((key >= '0' && key <= '9') ||(key >= 'B' && key <= 'D')) {
invalidEntry();
lcd.clear();
lcd.print("Enter Order:");
prompt = "Enter Order:";
lcd.print(petrolType);
}
}
}
// Prompts user for quantity of petrol
void getPetrolQuantity(int &petrolQuantity, int petrolType) {
static char orderInput[3];
int orderIndex = 0;
char key;
lcd.clear();
lcd.print("Enter Order:");
prompt = "Enter Order:";
lcd.print(petrolType);
lcd.print("A");
while (true) {
// Listens for key input
key = keypad.getKey();
// Checks if alarm triggered
alarmCheck(key);
// If letter is entered then call invalid entry
if (key >= 'A' && key <= 'D') {
invalidEntry();
lcd.clear();
lcd.print("Enter Order:");
prompt = "Enter Order:";
lcd.print(petrolType);
lcd.print("A");
if (orderIndex == 1) {
lcd.print(orderInput[0]);
}
// if number is entered then add to array tracking petrol quantity
} else if (key >= '0' && key <= '9') {
if (orderIndex < 2) {
orderInput[orderIndex++] = key;
lcd.print(key);
}
// if '#' is entered then save quantity to variable
} else if (key == '#') {
orderInput[orderIndex] = '\0';
petrolQuantity = atoi(orderInput);
break;
}
}
}
// Takes petrol type and returns the assigned price
int assignPrice(int petrolType) {
switch (petrolType) {
case 1:
return 119;
case 2:
return 130;
case 3:
return 99;
case 4:
return 160;
case 5:
return 110;
default:
return 0;
}
}
// Takes total cost of petrol and displays it to user
void displayTotal(int cost) {
lcd.clear();
lcd.print("Total: $");
lcd.print(cost / 100);
lcd.print(".");
lcd.print(cost % 100);
nonBlockingDelay(10000);
lcd.clear();
lcd.print("Enter PIN: ");
prompt = "Enter PIN: ";
}