#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo servoMotor;
#define ROWS 4
#define COLS 5
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeypad(keys), rowPins, colPins, ROWS, COLS);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
servoMotor.attach(10); // pin servo
Serial.begin(9600);
lcd.begin(16, 2);
lcd.backlight();
}
void loop() {
// step 1: setel static key
// CATATAN: key hanya bisa dengan biner 00 atau 01, sebab keterbatasan keyp
servoMotor.write(90);
int staticKey[2][1] = {{0},{1}}; // 01 dalam biner
// step 2: input pin
plaintext();
char pin[5]; // pin 4 digit + null terminator utk mengakhiri string array
int index = 0;
while(index < 4) {
char key = keypad.getKey();
if (key) {
pin[index++] = key;
lcd.setCursor(index-1,1);
lcd.print(key);
}
}
pin[4] = '0'; // null terminator
// step 3: konversi pin ke biner
int pinBinary[4][4];
for (int i = 0; i < 4; i++) {
int digit = pin[i] - '0'; // konversi char ke int agar bisa dihitung biner
for (int j = 3; j >= 0; j--) {
pinBinary[i][j] = digit % 2;
digit /= 2;
}
}
// step 4: enkripsi pinBinary dengan gerbang NAND
int jerry[2][4], tono[4][4];
// enkripsi NAND dari biner (digit 1 dgn dgn 2), dan (digit 3 dgn digit 4)
for (int i = 0; i < 4; i++) {
jerry[0][i] = !(pinBinary[0][i] && pinBinary[1][i]);
jerry[1][i] = !(pinBinary[2][i] && pinBinary[3][i]);
tono[i][2] = jerry[1][i];
}
// step 5: memasukkan data ke jerry dan tono (penyimpanan memory)
// enkripsi NAND dari jerry antara baris 1 dgn baris 2 (pasangan digit yang sama)
for (int i = 0; i < 4; i++) {
tono[i][3] = !(jerry[0][i] && jerry[1][i]); // output disimpan ke tono
}
// menyimpan key ke tono (key digit 1 ke tono kolom 1, key digit 2 ke tono)
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
tono[j][i] = staticKey[i][0];
}
}
// step 6: konversi tono ke kode ASCII
char suzu[5]; // 4-digit pin + null terminator
for (int i = 0; i < 4; i++) {
int ascii = 0;
for (int i = 0; < 4; j++) {
ascii += tono[i][j] * pow(2, 3, - j);
}
suzu[i] = ascii + '0'; // Convert int to char
}
suzu[4] = '\0'; // Null terminator
// step 7: menampilkan suzu (kode OTP)
OTP();
lcd.setCursor(0,1);
lcd.print(suzu);
delay(3000);
// validasi input pin
masukPin();
char input[5];
index = 0;
bool correctPin = false;
while(index < 4) {
char key = keypad.getKey();
if (key) {
input[index++] = key;
lcd.setCursor(index-1,1);
lcd.print("*");
}
}
input[4] = '\0'; // null terminator
if (strcmp(input, suzu) == 0) {
correctPin = true;
}
if (correctPin) {
bukaGerbang();
} else {
salahPin();
// menghitung percobaan yang salah
int incorrectAttempts = 1;
while (incorretAttempts < 3) {
// mengecek input apakah salah
index = 0;
while(index < 4) {
char key = keypad.getKey();
if (key) {
input[index++] = key;
lcd.setCursor(index-1,1);
lcd.print("*");
}
}
input[4] = '\0'; // null terminator
if (strcmp(input, suzu) != 0) {
incorrectAttempts++;
salahPin();
} else {
correctPin = true;
bukaGerbang();
break;
}
}
// jika pin input dimasukkan salah sebanyak 3 kali
if (incorrectAttempts == 3 && ! corretPin) {
brankasTerkunci();
}
}
}
// semua tampilan LCD
void plaintext() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Masukkan kunci");
}
void masukPin() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Masukkan PIN");
}
void OTP() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Berikut PIN OTP");
}
void bukaGerbang() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Akses Diterima!");
servoMotor.write(0); // servo terbuka
delay(5000);
}
void salahPin() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Salah, ulangi!");
}
void brankasTerkunci() {
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Brankas Terkunci");
tone(11, 1000); // suara buzzer
delay(2000);
noTone(11);
}