// knihovny pro LCD přes I2C
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ------------------------------------------------ KEYPAD ------------------------------------------------
const byte numRows = 4; //number of rows on the keypad
const byte numCols = 3; //number of columns on the keypad
char keymap[numRows][numCols]=
{
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
// http://learning.grobotronics.com/2013/07/using-a-3x4-keypad/
/*
Keypad Pin 1 ?> Arduino Pin 7
Keypad Pin 2 ?> Arduino Pin 5
Keypad Pin 3 ?> Arduino Pin 8
Keypad Pin 4 ?> Arduino Pin 2
Keypad Pin 5 ?> Arduino Pin 6
Keypad Pin 6 ?> Arduino Pin 3
Keypad Pin 7 ?> Arduino Pin 4
*/
byte rowPins[numRows] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[numCols]= {8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
char key_2[4] = {'A', 'B', 'C', '2'};
char key_3[4] = {'D', 'E', 'F', '3'};
char key_4[4] = {'G', 'H', 'I', '4'};
char key_5[4] = {'J', 'K', 'L', '5'};
char key_6[4] = {'M', 'N', 'O', '6'};
char key_7[5] = {'P', 'Q', 'R', 'S', '7'};
char key_8[4] = {'T', 'U', 'V', '8'};
char key_9[5] = {'W', 'X', 'Y', 'Z', '9'};
// ------------------------------------------------ LCD ------------------------------------------------
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x3F for a 16 chars and 2 line display
// https://omerk.github.io/lcdchargen/
byte lineVertical[8] = {
B00100,
B00100,
B00100,
B00100,
B00100,
B00100,
B00100,
B00100
};
byte lineHorizontal[8] = {
B00000,
B00000,
B00000,
B11111,
B00000,
B00000,
B00000,
B00000
};
byte corner[8] = {
B00100,
B00100,
B00100,
B11111,
B00100,
B00100,
B00100,
B00100
};
// ----------------------------------------------- GLOBALS ------------------------------------------------
const String password_1 = "TANK";
const String password_2 = "TRINITY";
const String password_3 = "CYPHER";
const String password_4 = "SMITH";
String input_password = "";
String prev_input = "";
byte pwdToCheck = 1; // n-th password to check
char newKey = ' '; // key to be added to input_password
char previousKey = ' '; // previously pushed button
bool blUpdateInput = false;
bool keyProcessed = false;
bool showMsg = true;
int sameBtnPushedCounter = 0; // how many times the same button was pushed
const int pushLimit = 1200; // time limit for pushing the same key
const int inputMaxLen = 18;
unsigned long pushDelay = millis();
unsigned long delayToBlink = millis();
char keyFromBlink = NO_KEY;
enum {initMsgState, checkPwdState, displayTaskState, getKeyState, solvedState, blinkState};
unsigned char currentState = initMsgState;
// Prototyping
void waitForButton();
char blink();
void drawRectangle();
void initMsg();
void finalMsg();
void task1();
void task2();
void task3();
void task4();
bool checkPwd(String pwdToCompare);
void setup() {
Serial.begin(9600);
//
input_password.reserve(inputMaxLen);
//
lcd.init();
lcd.createChar(0, lineVertical);
lcd.createChar(1, lineHorizontal);
lcd.createChar(2, corner);
lcd.clear();
lcd.noBacklight();
}
void loop() {
switch (currentState) {
case initMsgState:
lcd.setCursor(2,1);
lcd.print(F("MATRIX - GCAxxxx"));
drawRectangle();
delay(2500);
initMsg();
//
currentState = displayTaskState;
break;
case displayTaskState:
switch (pwdToCheck) {
case 1:
task1();
break;
case 2:
task2();
break;
case 3:
task3();
break;
case 4:
task4();
break;
default:
break;
}
//
currentState = getKeyState;
break;
case checkPwdState:
switch (pwdToCheck) {
case 1:
if (checkPwd(password_1)) {
pwdToCheck++;
}
currentState = displayTaskState;
break;
case 2:
if (checkPwd(password_2)) {
pwdToCheck++;
}
currentState = displayTaskState;
break;
case 3:
if (checkPwd(password_3)) {
pwdToCheck++;
}
currentState = displayTaskState;
break;
case 4:
if (checkPwd(password_4)) {
finalMsg();
currentState = solvedState;
} else {
currentState = displayTaskState;
}
break;
default:
break;
}
break;
case getKeyState:
{
char key = keypad.getKey();
if (keyFromBlink != NO_KEY) {
key = keyFromBlink;
keyFromBlink = NO_KEY;
}
if (key) {
if (key == '*') {
// smazat posledni znak: https://arduino.stackexchange.com/questions/20174/arduino-subtracting-chars-from-strings
if (input_password.length() > 0) {
Serial.println(F("Last char deleted"));
int lastIndex = input_password.length() - 1;
input_password.remove(lastIndex);
} else {
Serial.println(F("PWD has no length - nothing to delete!"));
}
} else if (key == '#') {
// zkontrolovat heslo
if (input_password.length() < 1) {
Serial.println(F("PWD has no length - nothing to check!"));
} else {
Serial.println(F("Checking password"));
currentState = checkPwdState;
}
} else {
// jine klavesy
if (key == '1' || key == '0') {
// klavesa jen s jednim znakem
newKey = key;
sameBtnPushedCounter = 0;
blUpdateInput = true;
} else {
// klavesa s vice znaky
if (key == previousKey) {
// Time to update
if (millis() - pushDelay > pushLimit) {
sameBtnPushedCounter = 0;
previousKey = ' ';
blUpdateInput = true;
}else{
sameBtnPushedCounter++;
blUpdateInput = false;
}
} else {
sameBtnPushedCounter = 0;
}
//
if (key == '2') {
newKey = key_2[sameBtnPushedCounter % sizeof(key_2) / sizeof(key_2[0])];
} else if (key == '3') {
newKey = key_3[sameBtnPushedCounter % sizeof(key_3) / sizeof(key_3[0])];
} else if (key == '4') {
newKey = key_4[sameBtnPushedCounter % sizeof(key_4) / sizeof(key_4[0])];
} else if (key == '5') {
newKey = key_5[sameBtnPushedCounter % sizeof(key_5) / sizeof(key_5[0])];
} else if (key == '6') {
newKey = key_6[sameBtnPushedCounter % sizeof(key_6) / sizeof(key_6[0])];
} else if (key == '7') {
newKey = key_7[sameBtnPushedCounter % sizeof(key_7) / sizeof(key_7[0])];
} else if (key == '8') {
newKey = key_8[sameBtnPushedCounter % sizeof(key_8) / sizeof(key_8[0])];
} else if (key == '9') {
newKey = key_9[sameBtnPushedCounter % sizeof(key_9) / sizeof(key_9[0])];
}
//
}
//
if (blUpdateInput) {
input_password += newKey;
} else {
if (sameBtnPushedCounter != 0) {
int lastIndex = input_password.length() - 1;
input_password.remove(lastIndex);
input_password += newKey;
} else {
input_password += newKey;
}
}
}
//
pushDelay = millis();
delayToBlink = millis();
previousKey = key;
} else if (millis() - delayToBlink > pushLimit) {
delayToBlink = millis();
currentState = blinkState;
}
// Update input
if (prev_input != input_password) {
if (input_password != "") {
Serial.print(F("Password: "));
Serial.println(input_password);
}
// LCD
/*
lcd.setCursor(0, 3);
lcd.print(F("> "));
lcd.setCursor(1, 3);
lcd.print(input_password);
*/
// Alternativa k vyse zakomentovanemu, aby neproblikaval display pri psani
if (input_password != "") {
if (prev_input.length() + 1 == input_password.length()) {
lcd.setCursor(prev_input.length() + 1, 3);
lcd.print(newKey);
} else if (prev_input.length() - 1 == input_password.length()) {
lcd.setCursor(prev_input.length(), 3);
lcd.print(" ");
lcd.setCursor(prev_input.length(), 3);
} else {
lcd.setCursor(prev_input.length(), 3);
lcd.print(" ");
lcd.setCursor(prev_input.length(), 3);
lcd.print(newKey);
}
} else {
lcd.setCursor(0, 3);
lcd.print(F("> "));
lcd.setCursor(1, 3);
}
//
prev_input = input_password;
}
// Max len
if (input_password.length() > inputMaxLen) {
Serial.println(F("Password too long"));
input_password = "";
// LCD
lcd.setCursor(0, 3);
lcd.print(F("> "));
lcd.setCursor(1, 3);
}
break;
}
case blinkState:
Serial.println(F("blink state start"));
keyFromBlink = blink();
Serial.println(F("blink state end"));
delayToBlink = millis();
currentState = getKeyState;
break;
case solvedState:
break;
default:
Serial.println(F("indifferent state"));
delay(1000);
break;
}
}
void initMsg() {
lcd.clear();
drawRectangle();
lcd.setCursor(2,1);
lcd.print(F("Pro pokracovani"));
lcd.setCursor(2,2);
lcd.print(F("vzdy stiskni #"));
waitForButton();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(F("Vedma te nyni prijme"));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Vim, ze jsi"));
lcd.setCursor(0, 1);
lcd.print(F("Kacer. Vis, proc te"));
lcd.setCursor(0, 2);
lcd.print(F("ke mne Morfeus"));
lcd.setCursor(0, 3);
lcd.print(F("privedl?"));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Tak co si"));
lcd.setCursor(0, 1);
lcd.print(F("myslis? Jsi"));
lcd.setCursor(0, 2);
lcd.print(F("Vyvoleny?"));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Podivam se"));
lcd.setCursor(0, 1);
lcd.print(F("na tebe."));
lcd.setCursor(0, 2);
lcd.print(F("Zajimave ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Zkus mi"));
lcd.setCursor(0, 1);
lcd.print(F("nejprve odpovedet"));
lcd.setCursor(0, 2);
lcd.print(F("na par otazek."));
waitForButton();
}
void finalMsg() {
Serial.println(F("printing final message"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Vyborne! Zda"));
lcd.setCursor(0, 1);
lcd.print(F("se, ze v tobe neco"));
lcd.setCursor(0, 2);
lcd.print(F("je. Presto uz ale"));
lcd.setCursor(0, 3);
lcd.print(F("vis, co ti reknu ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Je mi, lito,"));
lcd.setCursor(0, 1);
lcd.print(F("dite. Ale ty nejsi"));
lcd.setCursor(0, 2);
lcd.print(F("Vyvoleny. Mas ten"));
lcd.setCursor(0, 3);
lcd.print(F("dar, ale zda se, ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: ze na neco"));
lcd.setCursor(0, 1);
lcd.print(F("cekas. Morfeus tomu"));
lcd.setCursor(0, 2);
lcd.print(F("vsak veri tak slepe,"));
lcd.setCursor(0, 3);
lcd.print(F("ze by pro tebe ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: obetoval"));
lcd.setCursor(0, 1);
lcd.print(F("zivot. A tehdy se"));
lcd.setCursor(0, 2);
lcd.print(F("budes muset"));
lcd.setCursor(0, 3);
lcd.print(F("rozhodnout ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: V jedne"));
lcd.setCursor(0, 1);
lcd.print(F("ruce budes mit jeho"));
lcd.setCursor(0, 2);
lcd.print(F("zivot a v te druhe"));
lcd.setCursor(0, 3);
lcd.print(F("svuj. Jeden z ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: vas se bude"));
lcd.setCursor(0, 1);
lcd.print(F("muset obetovat. Kdo,"));
lcd.setCursor(0, 2);
lcd.print(F("je jen na tobe. Ted"));
lcd.setCursor(0, 3);
lcd.print(F("se ale vrat ..."));
waitForButton();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("VEDMA: Cislo, ktere"));
lcd.setCursor(0, 1);
lcd.print(F("potrebujes, je 1473."));
}
void task1() {
Serial.println(F("printing task 1"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("OTAZKA C.1: Jmeno"));
lcd.setCursor(0, 1);
lcd.print(F("operatora vasi"));
lcd.setCursor(0, 2);
lcd.print(F("posadky."));
lcd.setCursor(0, 3);
lcd.print(F(">"));
}
void task2() {
Serial.println(F("printing task 2"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("OTAZKA C.2: Jmeno"));
lcd.setCursor(0, 1);
lcd.print(F("zeny z vasi posadky,"));
lcd.setCursor(0, 2);
lcd.print(F("ktera te miluje."));
lcd.setCursor(0, 3);
lcd.print(F(">"));
}
void task3() {
Serial.println(F("printing task 3"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("OTAZKA C.3: Jmeno"));
lcd.setCursor(0, 1);
lcd.print(F("muze, ktery vas chce"));
lcd.setCursor(0, 2);
lcd.print(F("zradit."));
lcd.setCursor(0, 3);
lcd.print(F(">"));
}
void task4() {
Serial.println(F("printing task 4"));
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("OTAZKA C.4: Jmeno"));
lcd.setCursor(0, 1);
lcd.print(F("agenta, ktery te"));
lcd.setCursor(0, 2);
lcd.print(F("chce zabit."));
lcd.setCursor(0, 3);
lcd.print(F(">"));
}
bool checkPwd(String pwdToCompare) {
bool result = false;
if (input_password.length() < 1) {
return result;
}
lcd.clear();
drawRectangle();
if (input_password == pwdToCompare) {
lcd.setCursor(6, 1);
lcd.print(F("SPRAVNE"));
result = true;
} else {
lcd.setCursor(6, 1);
lcd.print(F("SPATNE"));
}
delay(2000);
input_password = ""; // reset the input password
lcd.clear();
return result;
}
void drawRectangle() {
lcd.setCursor(0,0);
lcd.write(byte(2));
lcd.setCursor(19,0);
lcd.write(byte(2));
lcd.setCursor(0,3);
lcd.write(byte(2));
lcd.setCursor(19,3);
lcd.write(byte(2));
for (int i=1;i<19;i++){
lcd.setCursor(i,0);
lcd.write(byte(1));
lcd.setCursor(i,3);
lcd.write(byte(1));
}
lcd.setCursor(0,1);
lcd.write(byte(0));
lcd.setCursor(19,1);
lcd.write(byte(0));
lcd.setCursor(0,2);
lcd.write(byte(0));
lcd.setCursor(19,2);
lcd.write(byte(0));
}
void waitForButton() {
delay(200);
while (1) {
char key = keypad.getKey();
if (key == '#') {
return;
}
}
}
char blink() {
unsigned long previousMillis = 0;
const long interval = 500;
bool blinkOn = true;
while (1) {
char key = keypad.getKey();
if (key) {
lcd.noCursor();
return key;
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (blinkOn) {
lcd.noCursor();
blinkOn = false;
} else {
lcd.cursor();
blinkOn = true;
}
}
}
}