#include "pico/stdlib.h"
#include <stdio.h>
#include <string.h>
#include "hardware/timer.h"
#define ID_LENGTH 6
#define PASSWORD_LENGTH 4
#define NUM_USERS 5
#define MAX_ATTEMPTS 3
// Definir los GPIOs para filas(Salidas) y columnas(Entradas)
#define ROW_1 2
#define ROW_2 3
#define ROW_3 4
#define ROW_4 5
#define COL_1 6
#define COL_2 7
#define COL_3 8
#define COL_4 9
const uint32_t maskOuts = 0b00000000000000000000000000111100;
const uint32_t maskIns = 0b00000000000000000000001111000000;
// GPIO adicional para indicar la detección de teclas
#define LED_ACCESO 10 //Led verde
#define LED_NE_IC 11 //Led rojo
#define LED_ID 12 // Led amarillo
// Matriz de teclas de la membrana matriz keyborad
const char keypad[4][4] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}};
// Estructura para la base de datos de usuarios
typedef struct
{
char ID[ID_LENGTH + 1]; // ID de 6 caracteres + nulo
char PASSWORD[PASSWORD_LENGTH + 1]; // Contraseña de 4 caracteres + nulo
int blocked; // Estado de bloqueo del usuario (0 = no bloqueado, 1 = bloqueado)
int attempts; // Contador de intentos fallidos
} User;
// Base de datos de usuarios
User users[NUM_USERS] = {
{"123456", "1234", 0, 0},
{"234567", "2345", 0, 0},
{"345678", "3456", 0, 0},
{"456789", "4567", 0, 0},
{"567890", "5678", 0, 0}};
int8_t getUserInput(char *ID, char *PASSWORD);
void setUpKeypad();
char getKey();
int verify_data(const char *ID, const char *PASSWORD);
bool change_password(char *ID, char *PASSWORD);
int main()
{
stdio_init_all(); // Inicializar la consola para depuración
setUpKeypad(); // Configurar GPIOs del teclado y LEDs
while (true)
{
char ID[ID_LENGTH + 1] = {'\0'}; // Buffer para ID
char PASSWORD[PASSWORD_LENGTH + 1] = {'\0'}; // Buffer para la contraseña
// Obtener ID y contraseña; si el tiempo se excede, retornar al inicio del bucle
int8_t user_input = getUserInput(ID, PASSWORD);
if (user_input == -1)
{
printf("Acceso denegado para ID por falta de tiempo: %s\n", ID);
// Encender LED rojo indicando que se superó el tiempo límite
gpio_put(LED_NE_IC, 1);
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0);
continue; // Volver al inicio del bucle para esperar una nueva entrada
}
else if(user_input == 2)
{ // Cambio de contraseña
(change_password(ID, PASSWORD))? printf("Contraseña cambiada exitosamente.\n"): printf("Contraseña no cambiada.\n");
continue;
}
// Verificar los datos obtenidos del usuario
int result = verify_data(ID, PASSWORD);
switch (result)
{
case 3: // ID no encontrado
printf("ID no encontrado: %s\n", ID);
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido por 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
break;
case 2: // Acceso concedido
printf("Acceso concedido. ID: %s\n", ID);
gpio_put(LED_ACCESO, 1); // Encender LED verde
sleep_ms(5000); // Mantener LED encendido por 5 segundos
gpio_put(LED_ACCESO, 0); // Apagar LED
break;
case 1: // Usuario bloqueado
printf("Usuario bloqueado: %s\n", ID);
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido por 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
break;
default: // Datos incorrectos
printf("Acceso denegado para ID: %s\n", ID);
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido por 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
break;
}
}
return 0;
}
// Inicializar como deben de ser los gpios
void setUpKeypad()
{
gpio_init_mask(maskOuts); // Inicializar GPIOs de salidas
gpio_set_dir_out_masked(maskOuts); // Configurar como salida
gpio_init_mask(maskIns); // Inicializar GPIOs de entradas
gpio_set_dir_in_masked(maskIns); // Configurar como entrada
// Configurar columnas como entradas con pull-down
gpio_pull_down(COL_1);
gpio_pull_down(COL_2);
gpio_pull_down(COL_3);
gpio_pull_down(COL_4);
// Inicializar LED_ACCESO como salida
gpio_init(LED_ACCESO);
gpio_set_dir(LED_ACCESO, GPIO_OUT);
// Inicializar LED_NE_IC como salida
gpio_init(LED_NE_IC);
gpio_set_dir(LED_NE_IC, GPIO_OUT);
// Inicializar LED_ID como salida
gpio_init(LED_ID);
gpio_set_dir(LED_ID, GPIO_OUT);
}
// Función para obtener la entrada del usuario con límite de tiempo de 10 segundos
int8_t getUserInput(char *ID, char *PASSWORD)
{
absolute_time_t start_time;
bool first_key_detected = false;
// Leer el ID del usuario con límite de tiempo
for (int i = 0; i < ID_LENGTH; i++)
{
char key = '\0';
// Esperar hasta que se presione una tecla
while (key == '\0')
{
gpio_put(LED_ID, !first_key_detected);
key = getKey(); // Leer la tecla presionada
sleep_ms(250);
// Si se detecta la primera tecla, iniciar el temporizador
if (!first_key_detected && key != '\0')
{
first_key_detected = true;
start_time = get_absolute_time(); // Obtener tiempo de inicio para los 10 segundos
}
// Verificar si se ha superado el límite de tiempo de 10 segundos
if (first_key_detected && absolute_time_diff_us(start_time, get_absolute_time()) > 30 * 1000000)
{
// Se excedió el tiempo
printf("Tiempo límite excedido. Fallo en la entrada de datos.\n");
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
// Resetear ID y PASSWORD como prevención y volver al estado inicial para prender el led amarillo
memset(ID, '\0', ID_LENGTH + 1);
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
return -1;
}
}
printf("%c\n", key);
ID[i] = key; // Asignar la tecla presionada al ID
}
ID[ID_LENGTH] = '\0'; // Agregar carácter nulo al final
bool isPasswordChange = true;
for(uint8_t i = 0; i < ID_LENGTH; i++)
{
if (ID[i] != '#') isPasswordChange = false;
}
if(isPasswordChange == true){
printf("Cambio de contraseña activado.\n");
return 2;
}
printf("%s\n", ID);
bool LED_ID_state = true;
absolute_time_t startYellowLEDTime = get_absolute_time();
// Leer la contraseña del usuario con límite de tiempo
for (int i = 0; i < PASSWORD_LENGTH; i++)
{
char key = '\0';
// Esperar hasta que se presione una tecla
while (key == '\0')
{
if(absolute_time_diff_us(startYellowLEDTime, get_absolute_time()) > 1 * 1000000)
{ // Cambiar estado de LED amarillo cada 2 seg.
gpio_put(LED_ID, LED_ID_state);
LED_ID_state = !LED_ID_state;
startYellowLEDTime = get_absolute_time();
}
key = getKey(); // Leer la tecla presionada
sleep_ms(250);
// Verificar si se ha superado el límite de tiempo de 10 segundos
if (first_key_detected && absolute_time_diff_us(start_time, get_absolute_time()) > 30 * 1000000)
{
// Se excedió el tiempo
printf("Tiempo límite excedido. Fallo en la entrada de datos.\n");
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
// Resetear ID y PASSWORD como prevención y volver al estado inicial
memset(ID, '\0', ID_LENGTH + 1);
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
return -1;
}
}
PASSWORD[i] = key; // Asignar la tecla presionada a la contraseña
printf("%c\n", key);
}
PASSWORD[PASSWORD_LENGTH] = '\0'; // Agregar carácter nulo al final
gpio_put(LED_ID, 0); // Apagar LED amarillo antes de verificar datos
printf("%s\n", PASSWORD);
return 1;
}
// Función para leer la tecla presionada
char getKey()
{
for (int row = 0; row < 4; row++)
{
// Poner todas las filas en bajo
gpio_clr_mask(maskOuts);
// Activar (poner en alto) la fila actual
switch (row)
{
case 0:
gpio_put(ROW_1, 1);
break;
case 1:
gpio_put(ROW_2, 1);
break;
case 2:
gpio_put(ROW_3, 1);
break;
case 3:
gpio_put(ROW_4, 1);
break;
}
// Leer columnas y verificar qué tecla se presionó
if (gpio_get(COL_1))
return keypad[row][0];
if (gpio_get(COL_2))
return keypad[row][1];
if (gpio_get(COL_3))
return keypad[row][2];
if (gpio_get(COL_4))
return keypad[row][3];
}
return '\0'; // No se presionó ninguna tecla
}
// Verificar los datos del usuario en la base de datos
int verify_data(const char *ID, const char *PASSWORD)
{
for (int i = 0; i < NUM_USERS; i++)
{
if (strcmp(users[i].ID, ID) == 0)
{
// Verificar si el usuario ya está bloqueado
if (users[i].blocked)
{
return 1; // Usuario bloqueado
}
// Verificar la contraseña
if (strcmp(users[i].PASSWORD, PASSWORD) == 0)
{
// Contraseña correcta, resetear intentos fallidos
users[i].attempts = 0;
return 2; // Datos correctos
}
else
{
// Contraseña incorrecta, incrementar el contador de intentos fallidos
users[i].attempts++;
// Bloquear al usuario si ha alcanzado el número máximo de intentos
if (users[i].attempts >= MAX_ATTEMPTS)
{
users[i].blocked = 1;
printf("El usuario con ID: %s ha sido bloqueado por demasiados intentos fallidos.\n", ID);
return 1; // Usuario bloqueado
}
// Devolver 0 para indicar que la contraseña es incorrecta
return 0;
}
}
}
return 3; // ID no encontrado
}
bool change_password(char *ID, char *PASSWORD)
{
absolute_time_t start_time;
bool first_key_detected = false;
// Leer el ID del usuario con límite de tiempo
for (int i = 0; i < ID_LENGTH; i++)
{
char key = '\0';
// Esperar hasta que se presione una tecla
while (key == '\0')
{
gpio_put(LED_ID, !first_key_detected);
key = getKey(); // Leer la tecla presionada
sleep_ms(250);
// Si se detecta la primera tecla, iniciar el temporizador
if (!first_key_detected && key != '\0')
{
first_key_detected = true;
start_time = get_absolute_time(); // Obtener tiempo de inicio para los 10 segundos
}
// Verificar si se ha superado el límite de tiempo de 10 segundos
if (first_key_detected && absolute_time_diff_us(start_time, get_absolute_time()) > 30 * 1000000)
{
// Se excedió el tiempo
printf("Tiempo límite excedido. Fallo en la entrada de datos.\n");
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
// Resetear ID y PASSWORD como prevención y volver al estado inicial para prender el led amarillo
memset(ID, '\0', ID_LENGTH + 1);
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
return false;
}
}
printf("%c\n", key);
ID[i] = key; // Asignar la tecla presionada al ID
}
ID[ID_LENGTH] = '\0'; // Agregar carácter nulo al final
printf("%s\n", ID);
bool isUserFound = false;
int userIndx = 0;
for (int i = 0; i < NUM_USERS; i++)
{
if (strcmp(users[i].ID, ID) == 0)
{
// Verificar si el usuario ya está bloqueado
if (users[i].blocked)
{
printf("Este usuario se encuentra bloqueado. ");
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
return false; // Usuario bloqueado
}
else
{
printf("Usuario encontrado. Ingresar contraseña actual.\n");
}
isUserFound = true;
userIndx = i;
}
else if(i == (NUM_USERS - 1) && !isUserFound){
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
printf("Usuario no encontrado. ");
return false;
}
}
bool LED_ID_state = true;
absolute_time_t startYellowLEDTime = get_absolute_time();
// Leer la contraseña del usuario con límite de tiempo
for (int i = 0; i < PASSWORD_LENGTH; i++)
{
char key = '\0';
// Esperar hasta que se presione una tecla
while (key == '\0')
{
if(absolute_time_diff_us(startYellowLEDTime, get_absolute_time()) > 1 * 1000000)
{ // Cambiar estado de LED amarillo cada seg.
gpio_put(LED_ID, LED_ID_state);
LED_ID_state = !LED_ID_state;
startYellowLEDTime = get_absolute_time();
}
key = getKey(); // Leer la tecla presionada
sleep_ms(250);
// Verificar si se ha superado el límite de tiempo de 10 segundos
if (first_key_detected && absolute_time_diff_us(start_time, get_absolute_time()) > 30 * 1000000)
{
// Se excedió el tiempo
printf("Tiempo límite excedido. Fallo en la entrada de datos.\n");
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
// Resetear ID y PASSWORD como prevención y volver al estado inicial
memset(ID, '\0', ID_LENGTH + 1);
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
return false;
}
}
PASSWORD[i] = key; // Asignar la tecla presionada a la contraseña
printf("%c\n", key);
}
PASSWORD[PASSWORD_LENGTH] = '\0'; // Agregar carácter nulo al final
gpio_put(LED_ID, 0); // Apagar LED amarillo antes de verificar datos
printf("%s\n", PASSWORD);
if (strcmp(users[userIndx].PASSWORD, PASSWORD) == 0)
{
printf("Contraseña actual correcta. Ingresar nueva contraseña.\n");
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
absolute_time_t startYellowLEDTime = get_absolute_time();
// Leer la contraseña del usuario con límite de tiempo
for (int i = 0; i < PASSWORD_LENGTH; i++)
{
char key = '\0';
// Esperar hasta que se presione una tecla
while (key == '\0')
{
if(absolute_time_diff_us(startYellowLEDTime, get_absolute_time()) > 2 * 1000000)
{ // Cambiar estado de LED amarillo cada 2 seg.
gpio_put(LED_ID, LED_ID_state);
LED_ID_state = !LED_ID_state;
startYellowLEDTime = get_absolute_time();
}
key = getKey(); // Leer la tecla presionada
sleep_ms(250);
// Verificar si se ha superado el límite de tiempo de 30 segundos
if (first_key_detected && absolute_time_diff_us(start_time, get_absolute_time()) > 50 * 1000000)
{
// Se excedió el tiempo
printf("Tiempo límite excedido. Fallo en la entrada de datos.\n");
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
// Resetear ID y PASSWORD como prevención y volver al estado inicial
memset(ID, '\0', ID_LENGTH + 1);
memset(PASSWORD, '\0', PASSWORD_LENGTH + 1);
return false;
}
}
PASSWORD[i] = key; // Asignar la tecla presionada a la contraseña
printf("%c\n", key);
}
PASSWORD[PASSWORD_LENGTH] = '\0'; // Agregar carácter nulo al final
gpio_put(LED_ID, 0); // Apagar LED amarillo antes de verificar datos
printf("%s\n", PASSWORD);
strcpy(users[userIndx].PASSWORD, PASSWORD); // Cambio de contraseña efectuado
}
else
{ // Contraseña incorrecta
// Devolver false para indicar que la contraseña es incorrecta
printf("Contraseña actual incorrecta.\n");
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_NE_IC, 1); // Encender LED rojo
sleep_ms(2000); // Mantener LED encendido 2 segundos
gpio_put(LED_NE_IC, 0); // Apagar LED
return false;
}
gpio_put(LED_ID, 0); // Apagar LED amarillo
gpio_put(LED_ACCESO, 1); // Encender LED rojo
sleep_ms(10000); // Mantener LED encendido 2 segundos
gpio_put(LED_ACCESO, 0); // Apagar LED
return true;
}