/*
July 16, 2020
This will be use to explore the use of 4x4 keypad for
1. T9 text entry
2. A, B, C, and D will be use for the menu operations
Author: George Bantique ( TechToTinker )
*/
#include "LiquidCrystal_I2C.h"
#include "Wire.h"
#include "Keypad.h"
#define DEFAULT_DELAY 300
LiquidCrystal_I2C lcd(0x27,16,2);
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
int x = 0; // Holds the LCD x position
int y = 0; // Holds the LCD y position
int minValue = 0; // Lower character location for T9 text entry
int maxValue = 0; // Max character location for T9 text entry
int keyPressTime = 200; // Number of loops check of the key
String msg = ""; // Holds the msg
String num = ""; // Holds the key
String alpha = "!@_$%? ABC DEF GHI JKL MNO PQRS TUV WXYZ * # "; // Characters for T9 text entry
char hexaKeys[ROWS][COLS] = { // Character matrix for the keypad
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {7, 6, 5, 4}; // pin assignments for keypad rows
byte colPins[COLS] = {3, 2, 1, 0}; // pin assignments for keypad columns
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
byte charUp[8] = { // arrow up character for LCD
B00100,
B01110,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte charDown[8] = { // arrow down character for LCD
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B01110,
B00100
};
byte charUpDown[8] = { // arrow up and down character for LCD
B00100,
B01110,
B11111,
B00000,
B00000,
B11111,
B01110,
B00100
};
byte menuLevel = 0; // Level 0: no menu display, display anything you like
// Level 1: display main menu
// Level 2: display sub menu
// Level 3: display sub menu of sub menu
byte menu = 1; // holds the menu level
byte sub = 1; // holds the sub menu level
String inputStr, keyStr, outputStr;
int input, output, keyword, inputLength, keyLength;
void setup()
{
lcd.init(); // initialized the LCD as 16 characters with 2 lines
lcd.createChar(0, charUp); // arrow up character
lcd.createChar(1, charDown); // arrow down character
lcd.createChar(2, charUpDown); // arrow up and down character
updateLevel_0(); // display the HOME screen
}
void loop() {
// Process the keys
processkey();
// Do other stuffs here
}
void processkey() {
char key = customKeypad.getKey();
if (isAlpha(key)) { // check if key press is a letter
processKeys(key); // process it according to keys
}
}
void parseKey(int minValue, int maxValue, char keyPress) {
int ch = minValue;
char key = keyPress;
if (keyPress == '*') { // if *, means backspace
if ( (x > 0) || (y > 0) ) { // prevent backspace when no character yet
x = x - 1; // go back to previous character position
lcd.setCursor(x,y); // set the new lcd position
lcd.print("*"); // write *, which means for editing
msg.remove(msg.length() - 1); // remove the last character from the string
}
} else {
for (int i = 0; i < keyPressTime; i++) {
if (key == keyPress) { // make sure that same key is press
lcd.setCursor(x, y); // set the lcd position
lcd.print(alpha[ch]); // print the character according to the character position
ch++; // increment character position
if (ch > maxValue) { // if the character counter reached the max value
ch = minValue; // reset to min value
i = 0; // reset the loop counter
}
}
key = customKeypad.getKey(); // get the keypress
delay(10); // delay for some time
}
x++; // increment the x position
msg += alpha[ch - 1]; // add the character to the variable msg
if (x > 15) { // if the lcd reached the rightmost position
y = 1; // then wrap to the next line
x = 0; // in first character in the left
}
}
}
void enterMSG() {
char key;
lcd.clear(); // clear the LCD display
x = 0; // init the x position to zero
y = 0; // init the y position to zero
msg = ""; // clear the msg variable
do {
key = customKeypad.getKey();
if (key == '1') { // if a key is pressed,
parseKey(0, 6, key); // compare it to the alpha string array
} else if (key == '2') {
parseKey(7, 10, key);
} else if (key == '3') {
parseKey(11, 14, key);
} else if (key == '4') {
parseKey(15, 18, key);
} else if (key == '5') {
parseKey(19, 22, key);
} else if (key == '6') {
parseKey(23, 26, key);
} else if (key == '7') {
parseKey(27, 31, key);
} else if (key == '8') {
parseKey(32, 35, key);
} else if (key == '9') {
parseKey(36, 40, key);
} else if (key == '0') {
parseKey(43, 44, key);
} else if (key == '*') {
parseKey(41, 42, key);
} else if (key == '#') {
// do nothing
}
} while (key != '#'); // exit the loop when # is pressed
lcd.setCursor(0, 0); // these are for verification only
lcd.print("Msg Inputed"); // feel free to modify it and
lcd.setCursor(0, 1); // adapt to your specific requirements
lcd.print(msg);
delay(2000);
}
void nextline(){
char key;
lcd.clear(); // clear the LCD display
x = 0; // init the x position to zero
y = 0; // init the y position to zero
num = ""; // clear the key variable
do {
key = customKeypad.getKey();
if (key == '1') { // if a key is pressed,
parseKey(0, 6, key); // compare it to the alpha string array
} else if (key == '2') {
parseKey(7, 10, key);
} else if (key == '3') {
parseKey(11, 14, key);
} else if (key == '4') {
parseKey(15, 18, key);
} else if (key == '5') {
parseKey(19, 22, key);
} else if (key == '6') {
parseKey(23, 26, key);
} else if (key == '7') {
parseKey(27, 31, key);
} else if (key == '8') {
parseKey(32, 35, key);
} else if (key == '9') {
parseKey(36, 40, key);
} else if (key == '0') {
parseKey(43, 44, key);
} else if (key == '*') {
parseKey(41, 42, key);
} else if (key == '#') {
// do nothing
}
} while (key != '#');
lcd.setCursor(0, 0); // these are for verification only
lcd.print("Key Inputed"); // feel free to modify it and
lcd.setCursor(0, 1); // adapt to your specific requirements
lcd.print(num);
delay(2000);
}
void inputCheck() {
msg = inputStr;
inputLength = inputStr.length();
int i = 0;
while (i < inputLength) {
if (inputStr[i] > 95 && inputStr[i] < 123) {
inputStr[i] -= 32;
}
i++;
}
}
void keyCheck() {
num = keyStr;
inputLength = inputStr.length();
keyLength = keyStr.length();
int i = 0;
while (i < keyLength) {
if (keyStr[i] > 95 && keyStr[i] < 123) {
keyStr[i] -= 32;
}
else if (!isAlpha(keyStr[i])) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Only Alphabet");
delay (2000);
break;
}
i++;
}
while (keyLength < inputLength) { //make the key as long as the input phrase
keyStr = keyStr + keyStr;
keyLength = keyStr.length();
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Cipher: ");
delay(2000);
}
void encodeStr() {
int i = 0, j = 0;
while (i < inputLength) {
if (isWhitespace(inputStr[i])) {
i++;
}
else if (!isAlpha(inputStr[i])) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(inputStr[i]);
i++;
}
else {
input = inputStr[i];
keyword = keyStr[j];
output = (((input - 65) + (keyword - 65)));
if (output > 25) {
output = output + 39;
}
else {
output = output + 65;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(output);
i++;
j++;
}
}
}
void decodeStr() {
int i = 0, j = 0;
while (i < inputLength) {
if (isWhitespace(inputStr[i])) {
i++;
}
else if (!isAlpha(inputStr[i])) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(inputStr[i]);
i++;
}
else {
input = inputStr[i];
keyword = keyStr[j];
output = (((input - 65) - (keyword - 65)));
if (output < 0) {
output = output + 91;
}
else {
output = output + 65;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(output);
i++;
j++;
}
}
}
void processKeys(char keyPressed) {
switch (menuLevel) {
case 0: // Level 0, home screen
switch ( keyPressed ) {
case 'D': // Enter
menu = 1;
menuLevel = 1; // go to main menu
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'A': // Up
break;
case 'B': // Down
break;
case 'C': // Back
break;
menuLevel = 0; // go to home screen
updateLevel_0(); // show home screen
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
case 1: // Level 1, main menu
switch ( keyPressed ) {
case 'D': // Enter
sub = 1;
menuLevel = 2; // go to sub menu
updateLevel_2(); // show sub menu
delay(DEFAULT_DELAY);
break;
case 'A': // Up
menu--;
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'B': // Down
menu++;
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'C': // Back
menuLevel = 0; // hide menu, go back to level 0
updateLevel_0(); // show home screen
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
case 2: // Level 2, sub menu
switch ( keyPressed ) {
case 'D': // Enter
if (sub == 1) { // Create Msg
lcd.clear();
lcd.print("Enter message");
delay(1000);
enterMSG();
lcd.clear();
lcd.print("Enter Key");
delay(1000);
nextline();
lcd.clear();
inputCheck();
keyCheck();
encodeStr();
lcd.clear();
menuLevel = 2; // go to sub menu
updateLevel_2(); // show sub menu
} else if (sub == 2) { // Send SMS
menuLevel = 2; // go to sub menu
updateLevel_2(); // show sub menu
}
delay(DEFAULT_DELAY);
break;
case 'A': // Up
sub--;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'B': // Down
sub++;
updateLevel_2(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'C': // Back
menuLevel = 1; // go back to level 1
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
case 3:
switch (keyPressed) {
case 'D': // Enter
if (sub == 2) { // Decode Msg
lcd.clear();
lcd.print("Enter message");
delay(1000);
enterMSG();
lcd.clear();
lcd.print("Enter Key");
delay(1000);
nextline();
delay(2000);
lcd.clear();
inputCheck();
keyCheck();
decodeStr();
delay(2000);
lcd.clear();
menuLevel = 2; // go to sub menu
updateLevel_2(); // show sub menu
} else if (sub == 2) {
menuLevel = 2; // go to sub menu
updateLevel_2(); // show sub menu
}
delay(DEFAULT_DELAY);
break;
case 'A': // Up
sub--;
updateLevel_2();
delay(DEFAULT_DELAY);
break;
case 'B': // Down
sub++;
updateLevel_2(); // show main menu
delay(DEFAULT_DELAY);
break;
case 'C': // Back
menuLevel = 1; // go back to level 1
updateLevel_1(); // show main menu
delay(DEFAULT_DELAY);
break;
default:
break;
}
break;
default:
break;
}
}
void updateLevel_0() {
lcd.clear();
lcd.println("Keypad Msg ");
lcd.setCursor(0, 1);
lcd.println(" D for menu ");
}
void updateLevel_1 () {
switch (menu) {
case 0:
menu = 1;
break;
case 1:
lcd.clear();
lcd.print(">Create Msg ");
lcd.setCursor(0, 1);
lcd.print(" Decode Msg ");
lcd.setCursor(15, 1);
lcd.write((byte)1); // down arrow
break;
case 2:
lcd.clear();
lcd.print(" Create Msg ");
lcd.setCursor(0, 1);
lcd.print(">Decode Msg ");
lcd.setCursor(15, 1);
lcd.write((byte)0); // up arrow
break;
case 3:
menu = 2;
break;
}
}
void updateLevel_2 () {
switch (menu) {
case 0:
break;
case 1: // Messages
switch (sub) {
case 0:
break;
case 1:
lcd.clear();
lcd.print(" Messages: ");
lcd.setCursor(0, 1);
lcd.print(" Create MSG ");
lcd.setCursor(15, 1);
lcd.write((byte)0); // up arrow
break;
default:
break;
}
break;
case 2: // Relay 2
switch (sub) {
case 0:
break;
case 1:
lcd.clear();
lcd.print(" Decode Msg: ");
lcd.setCursor(0, 1);
lcd.print(" Enter Msg ");
lcd.setCursor(15, 1);
lcd.write((byte)0); // up arrow
break;
default:
break;
}
break;
case 3:
sub = 2;
break;
}
}