#include #include #include // https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html #include "utils.h" #include "bitmanip.h" #include "timer.h" #include "usart.h" #include "interrupt.h" // USART #define USART_BAUDRATE 115200 // TIMER #define PERIOD 2000 #define PRESCALE_VALUE 1024 // can be 1, 8, 64, 256, 1024 #define STRLEN_LITERAL(str) (sizeof(str) / sizeof(str[0]) - 1) // -1 to remove the null terminator, only works with string literals, not with pointers // END MACROS // FUNCTION PROTOTYPES void uart_init(); // char uart_rx(void); void uart_tx(char c); void uart_printstr(const char* str); void check_str(char input, volatile char compare_str[], unsigned int length); void reset_message(); void ask_for_username(); void ask_for_password(); void on_error(); void on_success(); // GLOBAL VARIABLES typedef enum { USERNAME, PASSWORD } State; volatile char username[] = "admin"; volatile char password[] = "password"; volatile char username_input[100] = {0}; volatile char password_input[100] = {0}; volatile int input_index = 0; volatile State state = USERNAME; volatile int input_match = FALSE; volatile int username_correct = FALSE; volatile int password_correct = FALSE; void uart_init() { UBRR0H = (unsigned char) (BAUD_PRESCALER(USART_BAUDRATE) >> 8); // 20.11.5 : UBRRnL and UBRRnH – USART Baud Rate Registers UBRR0L = (unsigned char) BAUD_PRESCALER(USART_BAUDRATE); UCSR0C |= ASYNCHRONOUS | PARITY_DISABLED | STOP_ONE_BIT | DATA_EIGHT_BIT; // 20.11.4 : set Frame Format UCSR0B |= RECEIVER_ENABLED | TRANSMITTER_ENABLED | INTERRUPT_RECEIVER_ENABLED; // 20.11.3 : enable Receiver and Transmitter, and interrupt on receiver } // char uart_rx(void) { // while (TEST(UCSR0A, RXC0) == 0); // 20.11.2 : do nothing until there are unread data in the receive buffer (UDRn), (RXCn flag in UCSRnA register set to 1 when buffer has data) // return UDR0; // 20.11.1 : get data in buffer, UDRn – USART I/O Data Register (read and write) // } void uart_tx(char c) { while (TEST(UCSR0A, UDRE0) == 0); // 20.11.2 : do nothing until UDRn buffer is empty, (UDREn flag in UCSRnA register set to 1 when buffer empty) UDR0 = (unsigned char) c; // 20.11.1 : Put data into buffer, UDRn – USART I/O Data Register (read and write) } void uart_printstr(const char* str) { while (*str) { uart_tx(*str); str++; } } ISR(USART_RX_vect) { // Table 12-7 : we select the code for USART Receive // char received_char = uart_rx(); char received_char = UDR0; // read received character if (received_char == '\b' || received_char == 127) { // if backspace is received if (input_index <= 0) return; input_index--; uart_tx('\b'); // Move cursor back uart_tx(' '); // Erase the character on screen uart_tx('\b'); // Move cursor back again } else if (received_char == '\n' || received_char == '\r') { // if enter is received if (state == USERNAME) { // if (input_index == STRLEN_LITERAL(username) && input_match) { // username_correct = TRUE; // } else { // username_correct = FALSE; // uart_printstr("(error1)"); // } if (compare_str(username_input, username, STRLEN_LITERAL(username))) { username_correct = TRUE; } else { username_correct = FALSE; uart_printstr("(error1)"); } input_match = FALSE; state = PASSWORD; input_index = 0; uart_tx('\r'); // Move cursor to next line uart_tx('\n'); ask_for_password(); } else if (state == PASSWORD) { if (!username_correct) { uart_printstr("(error2)"); return reset_message(); } if (input_index != STRLEN_LITERAL(password)) { uart_printstr("(error3)"); return reset_message(); } if (!input_match) { uart_printstr("(error4)"); return reset_message(); } uart_tx('\r'); // Move cursor to next line uart_tx('\n'); on_success(); } } else { fill_str(received_char); if (state == USERNAME) { // check_str(received_char, username, STRLEN_LITERAL(username)); uart_tx(received_char); } else if (state == PASSWORD) { // check_str(received_char, password, STRLEN_LITERAL(password)); uart_tx('*'); } input_index++; } } void fill_str(char input) { if (input_index >= 100) { uart_printstr("(error8)"); return; } if (state == USERNAME) { username_input[input_index] = input; } else if (state == PASSWORD) { password_input[input_index] = input; } } int compare_str() { char input_str[100] = {0}; char compare_str[100] = {0}; if (state == USERNAME) { compare_str = username; input_str = username_input; } else if (state == PASSWORD) { compare_str = password; input_str = password_input; } int length = STRLEN_LITERAL(compare_str); int index = 0; while (*compare_str) { if (index >= length) { uart_printstr("(error5)"); return FALSE; } if (input_str[index] != *compare_str) { uart_printstr("(error6)"); return FALSE; } compare_str++; index++; } for (int i = 0; i < length; i++) { if (input[i] != compare_str[i]) { return FALSE; } } return TRUE; } void check_str(char input, volatile char compare_str[], unsigned int length) { if (input_index >= length) { // index has not already been incremented, so we need to compare greater or equal uart_printstr("(error5)"); input_match = FALSE; return; } if (input != compare_str[input_index]) { uart_printstr("(error6)"); input_match = FALSE; return; } // if we reach this point, the input character matches the compare_str character if (input_index == 0) { input_match = TRUE; return; } // if we reach this point, the input character is not the first character of the compare_str if (input_match == FALSE) { // if any previous character did not match, we don't need to check the next character uart_printstr("(error7)"); return; } input_match = TRUE; } void reset_message() { input_index = 0; input_match = FALSE; username_correct = FALSE; password_correct = FALSE; state = USERNAME; uart_tx('\r'); // Move cursor to next line uart_tx('\n'); on_error(); ask_for_username(); } void ask_for_username() { uart_printstr("Enter your login: \r\n username: "); } void ask_for_password() { uart_printstr(" password: "); } void on_error() { uart_printstr("Bad combinaison username/password\r\n\r\n"); } void on_success() { uart_printstr("Hello spectre!\r\nShall we play a game?\r\n"); } // ask for username and password // `screen /dev/ttyUSB0 115200` int main() { uart_init(); ask_for_username(); SREG |= ENABLE_GLOBAL_INTERRUPT; // 7.3.1 : Status Register, bit 7 : I – Global Interrupt Enable while(1); }