susteem mis võimaldab läbipääsu kasutades RFID (Raadiosagedustuvastus) tehnoloogiat.
Süsteem on ehitatud ATmega128 AVR kontrolleri baasil. Kontrolleri külge on ühendatud 2×16-kohaline LCD ekraan ja RFID-lugeja. Süsteemi juhtivad kaks programmi. Üks neist jookseb kontrolleri peal, teine arvutil kus asub ka süsteemi andmebaas. Programmid suhtlevad omavahel RS232 liidese kaudu.
Allpool on toodud mõlema programmi tööalgorütmid.
rfid.c
// RFID reader with Interstudy ATmegal28 board // Reader pins : Enable - PD3, Serout - PD2 (RXD1) // Reads and displays ID // Includes #include <avr/io.h> #include <util/delay.h> #include <homelab/usart.h> #include "lcd.h" #include "pin.h" // Configuration #define RFID_BAUDRATE 2400 #define RFID_BAUD_VALUE (((F_CPU / (RFID_BAUDRATE * 16UL))) - 1) #define RFID_ENABLE PORTPIN(D, 3) #define RFID_RX PORTPIN(D, 2) #define LED_GREEN PORTPIN(C, 3) #define LED_RED PORTPIN(C, 5) #define LED_YELLOW PORTPIN(C, 4) #define LED_DEBUG PORTPIN(B, 7) // // Определение USART интерфейса // usart port = USART(0); // // Display initialization // void display_init(void) { lcd_init(LCD_DISP_ON); lcd_clrscr(); lcd_puts(" RFID reader\n waiting for ID"); } char read_access() { // Access char c; // Wait for character int nMaxIter = 10; bool bResult = false; while( bResult == false ) { bResult = usart_try_read_char( port, &c ); // Wait for reply some time, but not forever --nMaxIter; _delay_ms(100); if( nMaxIter <= 0 ) break; } // Got result if( bResult == false ) { c = '0'; } return c; } // // Write ID on display // void display_write_id(char *id, char c) { lcd_gotoxy(0, 0); lcd_puts("ID: "); lcd_puts(id); lcd_gotoxy(0, 1); lcd_puts("Access: "); lcd_gotoxy(8, 1); // Обозначение знака непосредственно на экране lcd_alpha_write_char(c); } // // UART configuring // void uart_setup() { // Setup serial interface SET_BIT(UCSR1B, RXEN); // Activate RX only SET_BIT(UCSR1C, UCSZ0); // 8 data bits, 1 stop bit, no parity SET_BIT(UCSR1C, UCSZ1); // Set baud rate UBRR1L = (RFID_BAUD_VALUE & 0xFF); UBRR1H = (RFID_BAUD_VALUE >> 8); } // // Wait for UART incoming data // void uart_wait_rx() { while (!IS_BIT_SET(UCSR1A, RXC)) { } } // // Read UART data // inline unsigned char uart_read() { return UDR1; } // // RFID interface initialization // void rfid_init(void) { // Setup UART uart_setup(); // Setup enable and RX pin pin_setup_output(RFID_ENABLE); pin_setup_input(RFID_RX); } void usart_init(void) { // Настройка USART интерфейса usart_init_async(port, USART_DATABITS_8, USART_STOPBITS_ONE, USART_PARITY_NONE, USART_BAUDRATE_ASYNC(9600)); } // // RFID ID reading // void rfid_read_id(char *id) { enum States { BEGIN, DATA, END } state = BEGIN; unsigned char data; unsigned char digits = 0; // Enable RFID with low signal pin_clear(RFID_ENABLE); // Cycle until tag ID received while (1) { // Wait for data uart_wait_rx(); data = uart_read(); // Toggle debug indicator pin_toggle(LED_DEBUG); // What's present state and what's next ? switch (state) { // Begin state - we expect start byte (0x0A) case BEGIN: // Got the start ? if (data == 0x0A) { state = DATA; // Disable RFID pin_set(RFID_ENABLE); } break; // Data state - we expect 10 bytes of ID case DATA: // Fill ID string id[digits++] = data; // All digits arrived ? if (digits == 10) state = END; break; // End state - we expect end byte (0x0D) case END: // Got the end ? if (data == 0x0D) { // Terminate the string id[digits] = '\0'; // Сказать компьютеру привет usart_send_string(port, id); // All done - return return; } // Any other case - restart else { state = BEGIN; // Enable RFID with low signal pin_clear(RFID_ENABLE); } break; } } } // // Main function // int main(void) { char id[11]; // Initialization display_init(); rfid_init(); usart_init(); // Setup indicator pins pin_setup_output(LED_GREEN); pin_setup_output(LED_RED); pin_setup_output(LED_YELLOW); pin_setup_output(LED_DEBUG); // Turn off green LED pin_set(LED_GREEN); pin_set(LED_RED); pin_set(LED_YELLOW); // Endless loop while (1) { // Read RFID tag ID rfid_read_id(id); // Turn off green LED pin_set(LED_GREEN); pin_set(LED_RED); pin_clear(LED_YELLOW); char c = read_access(); // Display ID display_write_id(id, c); // Light green LED if( c == '0' ) { pin_clear(LED_RED); } else { pin_clear(LED_GREEN); } // Delay for next try _delay_ms(5000); pin_set(LED_YELLOW); pin_set(LED_GREEN); pin_set(LED_RED); } }
main.c
// ############################################################################ #include <stdlib.h> #include <stdio.h> #include <windows.h> #include <windef.h> #define BTN_NEW 100 #define BTN_EDIT 101 #define BTN_CONNECT 102 #define IDD_NEW 200 #define IDC_STC1 201 #define IDC_STC2 202 #define IDC_TAG 203 #define IDC_ACCESS 204 #define IDD_EDIT 1000 #define IDC_ACCESS2 1001 #define IDC_TAG2 1002 #define IDC_STC3 1003 #define IDC_STC4 1004 #define IDC_DELETE 1007 /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); /* Make the class name into a global variable */ char szClassName[ ] = "WindowsApp"; char *dbFile = "rfid.txt"; char *logFile = "rfid.log"; #define LOG_LINES 15 #define LOG_COLUMNS 200 char logline[LOG_LINES][LOG_COLUMNS]; size_t logpos = 0; char bConnected = 0; // ############################################################################ HMODULE hInst; HANDLE hCom, hThread; HWND hLog, hComPort; HWND hNew, hEdit, hConnect; HWND hCombo; // ############################################################################ // Переменные которые хранят данные из диалогов New и Edit char szTag[500]; char szAccess[500]; // ############################################################################ int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; /* This is the handle for our window */ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon(hThisInstance, 500); //LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(hThisInstance, 500);//LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "RFID", /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 544, /* The programs width */ 375, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam; } // ############################################################################ char check_id( char *id ) { size_t nIdLen = strlen(id); int nCount = SendMessage( hCombo, CB_GETCOUNT, 0, 0 ); int i; for( i = 0; i < nCount; i++ ) { char lpItem[500]; SendMessage( hCombo, CB_GETLBTEXT, i, (int) &lpItem ); if( strncmp( lpItem, id, nIdLen ) == 0 ) { return lpItem[nIdLen+1]; } } return 0; } // ############################################################################ char logz( char *lpData, DWORD nSize ) { // Open a handle to the specified com port. HANDLE hFile = CreateFile( logFile, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // default security attributes OPEN_ALWAYS, // must use 0, // not overlapped I/O NULL ); // hTemplate must be NULL for comm devices if(hFile == INVALID_HANDLE_VALUE) { // Handle the error. printf("CreateFile failed with error %d. File %s\n", GetLastError(), logFile); return 0; } // The starting point is the current end-of-file position. SetFilePointer( hFile, 0, 0, FILE_END ); if( nSize == 0 ) nSize = strlen( lpData ); DWORD nNumberOfBytesToWrite; WriteFile( hFile, lpData, nSize, &nNumberOfBytesToWrite, 0 ); // End of file CloseHandle( hFile ); // Add string to logline strncpy( &logline[logpos][0], lpData, LOG_COLUMNS - 1 ); logpos++; if( logpos >= LOG_LINES ) logpos = 0; // Make a log for text box char *lpResult = malloc( LOG_COLUMNS * LOG_LINES ); *lpResult = 0; int i = 0; for( i = logpos; i < LOG_LINES; i++ ) { strcat( lpResult, &logline[i][0] ); strcat( lpResult, "\r\n" ); } for( i = 0; i < logpos; i++ ) { strcat( lpResult, &logline[i][0] ); strcat( lpResult, "\r\n" ); } SendMessage( hLog, WM_SETTEXT, 0, (int) lpResult ); free( lpResult ); return 1; } // ############################################################################ logzf( char *lpData, ... ) { char buffer[LOG_COLUMNS]; va_list args; va_start (args, lpData); vsprintf (buffer,lpData, args); //perror (buffer); logz( buffer, strlen(buffer) ); va_end (args); } // ############################################################################ void read_file() { DWORD lpNumberOfBytesRead; // Open a handle to the specified com port. HANDLE hDB = CreateFile( dbFile, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // default security attributes OPEN_EXISTING, // must use OPEN_EXISTING 0, // not overlapped I/O NULL ); // hTemplate must be NULL for comm devices if(hDB == INVALID_HANDLE_VALUE) { // Handle the error. logzf("CreateFile failed with error %d. File %s\n", GetLastError(), dbFile); MessageBox( 0, "Could not load key file", "Error", MB_OK ); return; } // Read to memory size_t nSize = GetFileSize( hDB, 0 ); char *lpBuffer = (char *) malloc( nSize + 1 ); ReadFile( hDB, lpBuffer, nSize, &lpNumberOfBytesRead, 0 ); lpBuffer[lpNumberOfBytesRead] = 0; // End of file CloseHandle( hDB ); // Compare ids int i = 0; char *lpstart = lpBuffer; outer_loop: while( lpBuffer[i] ) { if( lpBuffer[i] == 0 ) { break; } if( lpBuffer[i] == '\r' ) { lpBuffer[i] = 0; //MessageBox( 0, lpstart, "info", MB_OK ); if( *lpstart != '\r' && *lpstart != 0 ) { SendMessage( hCombo, CB_ADDSTRING, 0, (int) lpstart ); } lpstart = &lpBuffer[i + 1]; } i++; } free( lpBuffer ); return; } // ############################################################################ void write_file() { DWORD lpNumberOfBytesWritten; // Open a handle to the specified com port. FILE *pFile = fopen( dbFile, "w+" ); if(pFile == 0) { // Handle the error. logzf("CreateFile failed with error %d. File %s\n", GetLastError(), dbFile); MessageBox( 0, "Could not load key file", "Error", MB_OK ); return; } int nCount = SendMessage( hCombo, CB_GETCOUNT, 0, 0 ); int i; for( i = 0; i < nCount; i++ ) { char lpItem[500]; SendMessage( hCombo, CB_GETLBTEXT, i, (int) &lpItem ); //MessageBox( 0, lpItem, "Error", MB_OK ); //WriteFile( dbFile, &lpItem, strlen(lpItem), &lpNumberOfBytesWritten, 0 ); //WriteFile( dbFile, "\r", 1, &lpNumberOfBytesWritten, 0 ); fwrite( &lpItem, strlen(lpItem), 1, pFile ); fwrite( "\r", 1, 1, pFile ); } //WriteFile( dbFile, "\r", 1, &lpNumberOfBytesWritten, 0 ); fwrite( "\r", 1, 1, pFile ); //CloseHandle( hDB ); fclose( pFile ); } // ############################################################################ BOOL CALLBACK NewDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: { return TRUE; } case WM_COMMAND: { switch(LOWORD(wParam)) { case IDOK: { GetDlgItemText(hwnd, IDC_TAG, szTag, sizeof(szTag)); GetDlgItemText(hwnd, IDC_ACCESS, szAccess, sizeof(szAccess)); EndDialog(hwnd, IDOK); break; } case IDCANCEL: { EndDialog(hwnd, IDCANCEL); break; } } break; } default: { return FALSE; } } return TRUE; } // ############################################################################ BOOL CALLBACK EditDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: { SetDlgItemText(hwnd, IDC_TAG2, szTag); SetDlgItemText(hwnd, IDC_ACCESS2, szAccess); return TRUE; } case WM_COMMAND: { switch(LOWORD(wParam)) { case IDOK: { GetDlgItemText(hwnd, IDC_TAG2, szTag, sizeof(szTag)); GetDlgItemText(hwnd, IDC_ACCESS2, szAccess, sizeof(szAccess)); EndDialog(hwnd, IDOK); break; } case IDC_DELETE: { EndDialog(hwnd, IDC_DELETE); break; } case IDCANCEL: { EndDialog(hwnd, IDCANCEL); break; } } break; } default: { return FALSE; } } return TRUE; } // ############################################################################ void PrintCommState(DCB dcb) { // Print some of the DCB structure values logzf( "BaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d", dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits ); } DWORD WINAPI read_com( LPVOID lpParam ) { // Read data char lpBuffer[200]; DWORD lpNumberOfBytesRead; while( ReadFile(hCom, lpBuffer, sizeof(lpBuffer), &lpNumberOfBytesRead, 0) ) { lpBuffer[lpNumberOfBytesRead] = 0; char id = check_id(lpBuffer); // Send to AVR DWORD nNumberOfBytesToWrite; WriteFile( hCom, &id, 1, &nNumberOfBytesToWrite, 0 ); char szTime[100]; GetTimeFormat( 0, 0, NULL, "HH':'mm':'ss", szTime, sizeof(szTime) ); char szDate[100]; GetDateFormat( 0, 0, NULL, "dd'.'MM'.'yyyy", szDate, sizeof(szDate) ); // Log logzf( "[%s %s] ID: %s, Access: %c", szDate, szTime, lpBuffer, id ); } logzf("ReadFile fail."); ExitThread( 0 ); return 0; } char connect_com() { DCB dcb; //HANDLE hCom; BOOL fSuccess; char pcCommPort[30]; // Most systems have a COM1 port GetWindowTextA( hComPort, pcCommPort, sizeof(pcCommPort) ); // Open a handle to the specified com port. hCom = CreateFile( pcCommPort, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access NULL, // default security attributes OPEN_EXISTING, // must use OPEN_EXISTING 0, // not overlapped I/O NULL ); // hTemplate must be NULL for comm devices if(hCom == INVALID_HANDLE_VALUE) { // Handle the error. logzf( "CreateFile failed with error %d.", GetLastError()); return 0; } // Initialize the DCB structure. ZeroMemory(&dcb, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); // Build on the current configuration by first retrieving all current // settings. fSuccess = GetCommState(hCom, &dcb); if (!fSuccess) { // Handle the error. logzf("GetCommState failed with error %d.", GetLastError()); return 0; } PrintCommState(dcb); // Output to console // Fill in some DCB values and set the com state: // 57,600 bps, 8 data bits, no parity, and 1 stop bit. dcb.BaudRate = CBR_9600; // baud rate dcb.ByteSize = 8; // data size, xmit and rcv dcb.Parity = NOPARITY; // parity bit dcb.StopBits = ONESTOPBIT; // stop bit fSuccess = SetCommState(hCom, &dcb); if (!fSuccess) { // Handle the error. logzf("SetCommState failed with error %d.", GetLastError()); return 0; } // Get the comm config again. fSuccess = GetCommState(hCom, &dcb); if (!fSuccess) { // Handle the error. logzf("GetCommState failed with error %d.", GetLastError()); return 0; } PrintCommState(dcb); // Output to console hThread = CreateThread( NULL, 0, read_com, 0, 0, NULL ); logzf( "Connected to port %s", pcCommPort ); return 1; } char disconnect_com() { TerminateThread( hThread, 0 ); CloseHandle( hCom ); logzf( "COM port disconnected" ); return 0; } // ############################################################################ /* This function is called by the Windows function DispatchMessage() */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) /* handle the messages */ { case WM_CREATE: { hInst = GetModuleHandle(NULL); hLog = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 0, 0, 100, 100, hwnd, 0, hInst, NULL); hComPort = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "COM1", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, hwnd, 0, hInst, NULL); hCombo = CreateWindow("COMBOBOX", "ComboBox", WS_CHILD | WS_VISIBLE | CBS_SORT | CBS_DROPDOWNLIST, 10, 50, 250, 20, hwnd, 0, hInst, 0); hNew = CreateWindow("BUTTON", "New", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 140, 70, 100, 25, hwnd, (HMENU) BTN_NEW, hInst, 0); hEdit = CreateWindow("BUTTON", "Edit", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 140, 70, 100, 25, hwnd, (HMENU) BTN_EDIT, hInst, 0); hConnect = CreateWindow("BUTTON", "Connect", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 140, 70, 100, 25, hwnd, (HMENU) BTN_CONNECT, hInst, 0); HFONT hfDefault = GetStockObject(DEFAULT_GUI_FONT); SendMessage(hLog, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); SendMessage(hNew, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); SendMessage(hConnect, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); SendMessage(hComPort, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); SendMessage(hCombo, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); read_file(); SendMessage( hCombo, CB_SETCURSEL, 0, 0 ); logz( "Program ready", 13 ); break; } case WM_COMMAND: switch(wParam) { case BTN_NEW: { logz( "Add new tag", 11 ); int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_NEW), hwnd, NewDlgProc); if(ret != IDOK) { break; } // Добавление нового RFID char szTemp[500]; snprintf( szTemp, sizeof(szTemp), "%s %s", szTag, szAccess ); int nCur = SendMessage( hCombo, CB_ADDSTRING, 0, (int) szTemp ); SendMessage( hCombo, CB_SETCURSEL, nCur, 0 ); write_file(); break; } case BTN_EDIT: { logz( "Edit new tag", 12 ); int nCur = SendMessage( hCombo, CB_GETCURSEL, 0, 0 ); SendMessage( hCombo, CB_GETLBTEXT, nCur, (int) &szTag ); // Разделение RFID-тега и уровня доступа char *lpSpace = strrchr( szTag, ' ' ); *lpSpace = 0; strcpy( szAccess, &lpSpace[1] ); int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_EDIT), hwnd, EditDlgProc); if(ret != IDOK && ret != IDC_DELETE) { break; } SendMessage( hCombo, CB_DELETESTRING, nCur, 0 ); if(ret == IDOK) { char szTemp[500]; snprintf( szTemp, sizeof(szTemp), "%s %s", szTag, szAccess ); nCur = SendMessage( hCombo, CB_ADDSTRING, 0, (int) szTemp ); SendMessage( hCombo, CB_SETCURSEL, nCur, 0 ); } else { SendMessage( hCombo, CB_SETCURSEL, 0, 0 ); } write_file(); break; } case BTN_CONNECT: { if( bConnected == 0 ) bConnected = connect_com(); else bConnected = disconnect_com(); if( bConnected == 0 ) SetWindowTextA( hConnect, "Connect" ); else SetWindowTextA( hConnect, "Disconnect" ); break; } } break; case WM_SIZE: { RECT rcClient; GetClientRect(hwnd, &rcClient); SetWindowPos(hLog, NULL, 0, 0, rcClient.right, rcClient.bottom - 32, SWP_NOZORDER); SetWindowPos(hCombo, NULL, 0, rcClient.bottom - 30, 200, 200, SWP_NOZORDER); SetWindowPos(hNew, NULL, 200, rcClient.bottom - 30, 50, 26, SWP_NOZORDER); SetWindowPos(hEdit, NULL, 200 + 50, rcClient.bottom - 30, 50, 26, SWP_NOZORDER); SetWindowPos(hComPort, NULL, 200 + 50 * 2 + 10, rcClient.bottom - 30, 50, 26, SWP_NOZORDER); SetWindowPos(hConnect, NULL, 200 + 50 * 3 + 10, rcClient.bottom - 30, 100, 26, SWP_NOZORDER); break; } case WM_DESTROY: { if( bConnected == 1 ) bConnected = disconnect_com(); // Выход. Сохранение. write_file(); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; } default: /* for messages that we don't deal with */ { return DefWindowProc (hwnd, message, wParam, lParam); } } return 0; } // ############################################################################