#include #include #include #define KP_ROWS 4 #define KP_COLS 4 char keys[KP_ROWS][KP_COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','.'} }; byte rowPins[KP_ROWS] = {A3, A2, A0, A1}; byte colPins[KP_COLS] = {8, 9, 10, 11}; Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KP_ROWS, KP_COLS); #define LCD_ROWS 2 #define LCD_COLS 16 LiquidCrystal lcd(2, 3, 4, 5, 6, 7); #define SELF_TEST_LABEL "Self testing..." #define SELF_TEST_ERROR_LABEL "Error: " #define UID_LABEL "UID:" #define PWD_LABEL "PWD:" #define LOGIN_IN_PROGRESS "Login..." #define LOGIN_FAILED "Login failed" #define LOGIN_SUCCESS "Access granted" #define UID_MAX_LEN 12 #define PWD_MAX_LEN 12 String uid; String password; enum Status { Uid, Password, SelfTest, LoginInProgress, LoginFailed, LoginSuccess }; Status status = Uid; #define MAX_IDLE_TIME 20 unsigned long lastActivity = 0; #define LOGIN_FAILED_TIME 2 #define SELF_TEST_INTERVAL 60 #define SELF_TEST_ERROR_INTERVAL 2 #define MAX_SELF_TEST_TIME 5 unsigned long lastSelfTest = 0; #define SELF_TEST_NO_ERROR '0' int lastSelfTestResult = SELF_TEST_NO_ERROR; void setup() { Serial.begin(9600); Serial.println("Starting..."); lcd.begin(LCD_COLS, LCD_ROWS); lcd.blink(); lcd.noAutoscroll(); selfTest(); } String makeChars(char c, int count) { char str[count + 1]; memset(str, c, count); str[count] = 0; return String(str); } bool handleUidPassword(String& str, int maxLength, char key) { int len = str.length(); if (key >= '0' && key <= '9') { if (len < maxLength) { str += key; return true; } } else if (key == 'C' || key == '*') { if (len > 0) { str = str.substring(0, len - 1); return true; } else if (status == Password) { status = Uid; return true; } } return false; } void loop() { unsigned long secs = millis() / 1000; if (handleKeyPad()) { lastActivity = secs; updateLcd(); } if ((uid.length() != 0 || password.length() != 0) && secs - lastActivity >= MAX_IDLE_TIME) { askUidPassword(); } if (uid.length() == 0 && password.length() == 0 && secs - lastSelfTest >= SELF_TEST_INTERVAL) { selfTest(); } } bool handleKeyPad() { char key = keypad.getKey(); if (key != NO_KEY) { if (status == Uid) { if (key == '#') { if (uid.length() != 0) { status = Password; return true; } } else { return handleUidPassword(uid, UID_MAX_LEN, key); } } else if (status == Password) { if (key == '#') { if (password.length() != 0) { login(uid, password); return true; } } else { return handleUidPassword(password, PWD_MAX_LEN, key); } } } return false; } void updateLcd() { Serial.println("Update LCD"); lcd.clear(); if (status == Uid || status == Password) { lcd.setCursor(0, 0); lcd.print(UID_LABEL); lcd.print(uid); lcd.setCursor(0, 1); lcd.print(PWD_LABEL); lcd.print(makeChars('*', password.length())); if (status == Uid) { lcd.setCursor(strlen(UID_LABEL) + uid.length(), 0); } else { lcd.setCursor(strlen(PWD_LABEL) + password.length(), 1); } } else if (status == SelfTest) { lcd.print(SELF_TEST_LABEL); if (lastSelfTestResult != SELF_TEST_NO_ERROR) { lcd.setCursor(0, 1); lcd.print(SELF_TEST_ERROR_LABEL); lcd.print(lastSelfTestResult); } } else if (status == LoginInProgress) { lcd.print(LOGIN_IN_PROGRESS); } else if (status == LoginFailed) { lcd.print(LOGIN_FAILED); } else if (status == LoginSuccess) { lcd.print(LOGIN_SUCCESS); } } void askUidPassword() { status = Uid; uid = ""; password = ""; updateLcd(); } void login(String uid, String password) { status = LoginInProgress; updateLcd(); delay(LOGIN_FAILED_TIME * 1000); Serial.println(uid); Serial.println(password); status = LoginSuccess; updateLcd(); delay(LOGIN_FAILED_TIME * 1000); askUidPassword(); } void selfTest() { lastSelfTest = SELF_TEST_NO_ERROR; status = SelfTest; updateLcd(); bool test = true; while (test) { unsigned long secs = millis() / 1000; Serial.println("Self Testing"); while (Serial.available() == 0 && (millis() / 1000) - secs < MAX_SELF_TEST_TIME); if (Serial.available() > 0) { lastSelfTestResult = Serial.read(); if (lastSelfTestResult == SELF_TEST_NO_ERROR) { test = false; } else { updateLcd(); delay(SELF_TEST_ERROR_INTERVAL * 1000); } } } lastSelfTest = millis() / 1000; askUidPassword(); }