#include /* Terminal I/O support */ #include /* Error number definitions */ #include /* String function definitions */ #include /* Standard I/O */ #include /* File descriptor manipulation */ #include /* For sleep(); */ #include /* for time, localtime. strftime */ #include /* for .... signal handling ... */ #include int keypad; // Global, to be able to gracefully close on SIGTERM... char line1[21]; char line2[21]; char line3[21]; char line4[21]; char userid[10]; char pincode[10]; enum DOOR { LOCKED, UNLOCKED } lock_status; enum STATE { WAITING, USERID_INPUT, INVALID_USERID, PIN_INPUT, INVALID_PIN, VALIDATE_USER, LOCK_PROCESS, CHECKING_STATUS } interaction_state; void sighandler ( int sig ) { char tbuffer[23]; time_t current_time; struct tm ctm; current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(tbuffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf ("%s: Caught signal %d, ", tbuffer, sig); fflush(stdout); switch (sig) { case SIGHUP: signal(SIGHUP,sighandler); /* dont die on sighup */ printf("SIGHUP Ignored\n"); fflush(stdout); break; case SIGINT: case SIGTERM: printf("closing keypad and terminating.\n"); write( keypad, "", 1); tcdrain( keypad ); close ( keypad ); exit(0); break; } } int validate_user ( const char* user, const char* pin ) { if ( ( strncmp( user, "123456", 8 ) == 0 ) && ( strncmp( pin, "1234", 6 ) == 0 ) ) return 1; return 0; } int open_port ( char* device ) { int f; struct termios tio; f = open ( device, O_RDWR | O_NOCTTY ); if ( f < 0 ) { perror(device); return(-1); } // Fixed settings: 9600bps, 8 bits, // no parity, no flow-control, // local mode, read enabled tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD; tio.c_cflag &= ~CRTSCTS; tio.c_iflag = IGNPAR; tio.c_oflag = 0; tio.c_lflag = 0; // Non-canonical read, no other options. tio.c_cc[VMIN] = 0; // Expect 1 characters, always. tio.c_cc[VTIME] = 254; // Wait for a max of 25 seconds tcsetattr(f,TCSANOW,&tio); // Apply this now. return f; } void clear_lcd (int fd) { write( fd, "", 1); tcdrain(fd); } void output ( int fd, const char *data ) { int res; int i; char c; for (i = 0; ( i < strlen(data) && i < 20) ; i++) { c = data[i]; res = write( fd, &c, 1); if ( res < 0 ) perror; } if ( i < 20 ) { write( fd, "\n", 1 ); } tcdrain(fd); // Flush the buffer } void update_lcd( int fd ) { clear_lcd( fd ); output( fd, line1 ); output( fd, line2 ); output( fd, line3 ); output( fd, line4 ); } /* void set_locking ( int fd ) { int res; clear_lcd( fd ); res = write( fd, "\n LOCKING", 14); if ( res < 0 ) perror; tcdrain(fd); // Flush the buffer } */ int main ( int argc, char** argv) { int res; char buffer[30]; time_t current_time; struct tm ctm; bzero ( line1, 21 ); bzero ( line2, 21 ); bzero ( line3, 21 ); bzero ( line4, 21 ); keypad = open_port( "/dev/ttyUSB0" ); if ( keypad < 0 ) { perror( "/dev/ttyUSB0" ); return(-1); } signal( SIGHUP, sighandler); signal( SIGINT, sighandler); signal( SIGTERM, sighandler); clear_lcd( keypad ); interaction_state = CHECKING_STATUS; // Not doing lock-stuff yet, hard-coding it. lock_status = LOCKED; for ( ;; ) { switch ( interaction_state ) { case CHECKING_STATUS: { bzero ( line1, 21 ); bzero ( line2, 21 ); bzero ( line3, 21 ); bzero ( line4, 21 ); // Do an actual check of the status, and set lock_status. if ( lock_status == LOCKED ) { strncpy( line1, " HiGLUG Access.", 20); strncpy( line2, "The door is locked.", 20); strncpy( line3, "Enter ID to unlock", 20); strncpy( line4, "UserID: ", 20); } if ( lock_status == UNLOCKED ) { strncpy( line1, " HiGLUG Access.", 20); strncpy( line2, " DOOR IS OPEN", 20); strncpy( line3, " Welcome", 20); strncpy( line4, "Press a key to lock", 20); } interaction_state = WAITING; update_lcd( keypad ); } case WAITING: { bzero( buffer , 16 ); tcflush(keypad, TCIFLUSH); // Flush the serial input buffer. // Wait for a keypress, with a timeout. res = read ( keypad, buffer, 2 ); if ( res < 0 ) { perror("state WATITING"); break; } // If the key-wait times out, set state to CHECKING_STATUS and break. if ( res == 0 ) { interaction_state = CHECKING_STATUS; break; } // If the key-wait gives a character, check state: // On lock_status == UNLOCKED, set state to LOCK_PROCESS and break. if ( lock_status == UNLOCKED ) { interaction_state = LOCK_PROCESS; break; } else { // On lock_status == LOCKED, blank previous data from userid, // set the first character to the key pressed, and set state to USERID_INPUT. bzero(userid, 10); userid[0] = buffer[0]; strncat( line4, "*", 1); update_lcd( keypad ); interaction_state = USERID_INPUT; } } case USERID_INPUT: { bzero( buffer , 16 ); //tcflush(keypad, TCIFLUSH); // Flush the serial input buffer. // Wait for a keypress, with a timeout. res = read ( keypad, buffer, 1 ); if ( res < 0 ) { perror("State USERID_INPUT"); break; } // If the key-wait times out, set state to INVALID_USERID and break. if ( res == 0 ) { interaction_state = INVALID_USERID; current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: Timed out, failing userid entry\n", buffer); break; } // If the key-wait returns a character, check the current strlen of userid: // If the strlen is too large (more than 8 characters), set state to INVALID_USERID and break if ( ! ( strlen(userid) < 9 ) ) { current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: UserID entered is too long.\n", buffer); interaction_state = INVALID_USERID; break; } if ( buffer[0] == '!' ) // ESCAPE/CANCEL { interaction_state = CHECKING_STATUS; break; } // If the strlen is OK, compare it to \n. On a recieved \n: if ( buffer[0] == '\n' ) { // bzero pincode, set state to PIN_INPUT and break bzero(pincode, 10); strncpy( line1, " HiGLUG Access.", 20); strncpy( line2, " User ID entered.", 20); strncpy( line3, " Enter PIN code", 20); strncpy( line4, "PIN: ", 20); update_lcd( keypad ); interaction_state = PIN_INPUT; break; } // Append the character to userid. userid[ strlen(userid) ] = buffer[0]; // Append an asterisk to line4 strncat( line4, "*", 1); update_lcd( keypad ); break; } case INVALID_USERID: { // Set the display to inform about invalid data. strncpy( line1, " ERROR IN INPUT", 20); strncpy( line2, "The entered data was", 20); strncpy( line3, " not accepted.", 20); strncpy( line4, "Press a key to retry", 20); update_lcd( keypad ); // Wait for a keypress, with a timeout. tcflush(keypad, TCIFLUSH); // Flush the serial input buffer. res = read ( keypad, buffer, 2 ); // Set state to CHECKING_STATUS and break. interaction_state = CHECKING_STATUS; break; } case PIN_INPUT: { bzero( buffer , 16 ); // Wait for a keypress, with a timeout. res = read ( keypad, buffer, 1 ); if ( res < 0 ) { perror("State PIN_INPUT"); break; } // If the key-wait times out, set state to INVALID_PIN and break. if ( res == 0 ) { interaction_state = INVALID_PIN; current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: Timed out PIN, failing user\n", buffer); break; } // If the key-wait returns a character, check the current strlen of pincode: // If the strlen is too large (more than 6 characters), set state to INVALID_PIN and break if ( ! ( strlen(pincode) < 7 ) ) { current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: PIN code entered is too long.\n", buffer); interaction_state = INVALID_PIN; break; } if ( buffer[0] == '!' ) // ESCAPE/CANCEL { interaction_state = CHECKING_STATUS; break; } // If the strlen is OK, compare it to \n. On a recieved \n: if ( buffer[0] == '\n' ) { // set state to VALIDATE_USER and break interaction_state = VALIDATE_USER; break; } // Append the character to pincode. pincode[ strlen(pincode) ] = buffer[0]; // Append an asterisk to line4 strncat( line4, "*", 1); update_lcd( keypad ); break; } case INVALID_PIN: { // Set the display to inform about invalid pincode. strncpy( line1, " ERROR IN INPUT", 20); strncpy( line2, "The entered data was", 20); strncpy( line3, " not accepted.", 20); strncpy( line4, "Press a key to retry", 20); update_lcd( keypad ); // Wait for a keypress, with a timeout. tcflush(keypad, TCIFLUSH); // Flush the serial input buffer. res = read ( keypad, buffer, 2 ); // Set state to CHECKING_STATUS and break. interaction_state = CHECKING_STATUS; break; } case VALIDATE_USER: { // Do magic stuff. If the user is valid, set state to LOCK_PROCESS. // stub code if ( validate_user ( userid, pincode ) ) { current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: UserID %s unlocked the door\n", buffer, userid); strncpy( line1, " HiGLUG Access.", 20); strncpy( line2, " User data verified", 20); strncpy( line3, " UNLOCKING", 20); strncpy( line4, " Welcome", 20); update_lcd( keypad ); interaction_state = LOCK_PROCESS; } // If the user is invalid, set state to INVALID_PIN and break. else { interaction_state = INVALID_PIN; break; } } case LOCK_PROCESS: { if ( lock_status == LOCKED ) { // STUB!! TODO sleep(5); lock_status = UNLOCKED; } else { clear_lcd( keypad ); res = write( keypad, "\n LOCKING", 14); if ( res < 0 ) perror; tcdrain(keypad); // Flush the buffer // STUB!! TODO sleep(5); lock_status = LOCKED; current_time = time(NULL); ctm = *(localtime(¤t_time)); strftime(buffer,22,"%Y-%m-%d - %H:%M:%S",&ctm); printf("%s: Door locked from keypad\n", buffer, userid); } // If lock_status == LOCKED, unlock. // If lock_status == UNLOCED, lock. // Set state to CHECKING_STATUS and break interaction_state = CHECKING_STATUS; break; } default: { interaction_state = WAITING; break; } } } close ( keypad ); }