An access controller for man doors at our facility. It receives Wiegand signals from a keypad/card reader and activates a relay to open the door. Access codes are stored in EEPROM. The active code list is updated from TFTP on a local server.
Dependencies: 24LCxx_I2C CardReader USBHOST
main.cpp
- Committer:
- acesrobertm
- Date:
- 2017-09-25
- Revision:
- 0:a56239ae90c2
File content as of revision 0:a56239ae90c2:
#if !FEATURE_LWIP #error [NOT_SUPPORTED] LWIP not supported for this target #endif #include <sstream> // std::istringstream #include <string> #include "mbed.h" #include "EthernetInterface.h" #include "TCPServer.h" #include "TCPSocket.h" #include "CardReader/ReaderWiegand.h" #include "CodeMemory.h" #include "ConfigurationManager.h" #define MAX_TCP_CONNECTIONS 5 #define HTTP_SERVER_PORT 80 #define DATA_SERVER_PORT 500 #define RELAY_PULSE_MS 2000 #define UNLATCH_FLASH_MS 50 #define UNLATCH_NUM_BEEPS 5 #define HTTP_STATUS_LINE "HTTP/1.0 200 OK" #define HTTP_HEADER_FIELDS "Content-Type: text/html; charset=utf-8" #define HTTP_MESSAGE_BODY "" \ "<html>" "\r\n" \ " <body style=\"display:flex;text-align:center\">" "\r\n" \ " <div style=\"margin:auto\">" "\r\n" \ " <h1>East Center Carport Door</h1>" "\r\n" \ " <p>Data Server Port: %d</p>" "\r\n" \ " <p>Number of button presses: %d</p>" "\r\n" \ " </div>" "\r\n" \ " </body>" "\r\n" \ "</html>" #define HTTP_RESPONSE HTTP_STATUS_LINE "\r\n" \ HTTP_HEADER_FIELDS "\r\n" \ "\r\n" \ HTTP_MESSAGE_BODY "\r\n" using namespace std; DigitalOut qx_led1(LED1); DigitalOut qx_led2(LED2); DigitalOut qx_relay(D12); DigitalOut qx_redReaderLed(D6); DigitalOut qx_greenReaderLed(D7); DigitalOut qx_readerBuzzer(D8); InterruptIn ix_usrBtn(USER_BUTTON); InterruptIn ix_tamper(D5); InterruptIn ix_doorLatched(D13); EthernetInterface* _eth; char* _mac_addr; char* _ip_addr; int button_presses = 0; char httpReq[100]; char httpResponse[100]; ReaderWiegand wgReader(D2, D4); CodeMemory codeMem; ConfigurationManager configManager(_eth, &codeMem); Timeout mRelayTimer; Timeout unlatchFlashTimer; RawSerial usbUART(USBTX, USBRX); volatile int rx_idx = 0; char usb_rx_buffer[USB_RX_MAX_LENGTH + 1]; // Interupt Routine to read in data from serial port void Rx_interrupt() { while ((usbUART.readable()) && rx_idx < USB_RX_MAX_LENGTH) { usb_rx_buffer[rx_idx] = usbUART.getc(); rx_idx++; } return; } void relayTimeout() { qx_led2 = 0; qx_relay = 0; } void relayTimerRestart() { mRelayTimer.detach(); mRelayTimer.attach_us(&relayTimeout, RELAY_PULSE_MS * 1000); } void usr_btn_pressed() { button_presses++; // Manual strike release relayTimerRestart(); qx_led2 = 1; qx_relay = 1; } void handle_tamper() { qx_greenReaderLed = !qx_greenReaderLed; qx_led2 = !qx_led2; } void handle_latch() { qx_redReaderLed = !qx_redReaderLed; } void unlatch_flash() { static int flash_count = 0; if (qx_relay) { if (qx_redReaderLed) { qx_redReaderLed = 0; qx_greenReaderLed = 1; if (flash_count++ < UNLATCH_NUM_BEEPS) { qx_readerBuzzer = 0; } } else { qx_redReaderLed = 1; qx_greenReaderLed = 0; qx_readerBuzzer = 1; } // Delay and call this function again. unlatchFlashTimer.detach(); unlatchFlashTimer.attach_us(&unlatch_flash, UNLATCH_FLASH_MS * 1000); } else { qx_redReaderLed = 1; qx_greenReaderLed = 1; qx_readerBuzzer = 1; flash_count = 0; } } void unlatchStrike() { relayTimerRestart(); qx_led2 = 1; qx_relay = 1; unlatch_flash(); return; } bool commandHasArg(string testString, string commandName) { int commandLength = commandName.length(); return ((testString.length() >= (commandLength + 2)) && (testString.find(" ") == commandLength) && testString.compare(0, commandLength, commandName) == 0); } unsigned short stringToCode(string codeStr) { unsigned short codeValue; istringstream iss(codeStr); iss >> codeValue; return codeValue; } void submitSerialCommand(string command) { command = command.substr(0, command.length() - 1); // Remove the new line character from the end of the command. // Remote access code commands if (!command.compare("help")) { //printProgStr(helpMessage); printf("This is the help command.\n"); } else if (!command.compare("list")) { codeMem.PrintAllAccessCodes(); } else if (!command.compare("log")) { codeMem.PrintRecentEvents(); } else if (commandHasArg(command, "log")) { string arg = command.substr(command.find(" ") + 1); if (!arg.compare("full")) { codeMem.PrintEventLog(); } } else if (!command.compare("clear eeprom")) { printf("Clearing EEPROM...\n"); codeMem.EEPROMClear(); printf("EEPROM Erased\n"); } else if (commandHasArg(command, "activate")) { unsigned short code = stringToCode(command.substr(command.find(" ") + 1)); int address = codeMem.ActivateAccessCode(code); if (address >= 0) { printf("Code Activated: Address %d\n", address); } else if (address == -1) { printf("Failed to Activate: Code Already Exists\n"); } else if (address == -2) { printf("Failed to Activate: Code Table Full\n"); } else { printf("Unknown Error\n"); } } else if (commandHasArg(command, "revoke")) { unsigned short code = stringToCode(command.substr(command.find(" ") + 1)); int address = codeMem.DeactivateAccessCode(code); if (address < 0) { printf("Failed to Revoke: Code Not Found\n"); } else { printf("Code Revoked: Address %d\n", address); } } else if (commandHasArg(command, "setsc")) { int afterFirstSpace = command.find(" ") + 1; int afterSecondSpace = command.find_last_of(" ") + 1; unsigned short specialIndex = stringToCode(command.substr(afterFirstSpace, afterSecondSpace - 1)); unsigned short specialCode = stringToCode(command.substr(afterSecondSpace)); // Ensure that there are at least two arguments if (afterSecondSpace > afterFirstSpace) { codeMem.SetSpecialCode(specialIndex, specialCode); } } // Remote door commands else if (commandHasArg(command, "door")) { string arg = command.substr(command.find(" ") + 1); if (!arg.compare("status")) { if (ix_doorLatched) { printf("Door Closed\n"); } else { printf("Door Open\n"); } } else if (!arg.compare("open")) { unlatchStrike(); printf("Unlatching Strike...\n"); } } return; } int main() { char mac_addr[MAC_STRING_LENGTH + 1] = ""; char ip_addr[IP_STRING_MAX_LENGTH + 1] = ""; _mac_addr = mac_addr; _ip_addr = ip_addr; usbUART.attach(&Rx_interrupt, Serial::RxIrq); // I/O Setup qx_redReaderLed = 1; qx_greenReaderLed = 1; qx_readerBuzzer = 1; ix_tamper.mode(PullUp); ix_tamper.fall(&handle_tamper); ix_doorLatched.mode(PullDown); ix_doorLatched.rise(&handle_latch); ix_usrBtn.fall(&usr_btn_pressed); printf("+------------------------------------------------+\n"); printf("| American Control & Engineering Service, Inc. |\n"); printf("| Door Access Controller |\n"); printf("+------------------------------------------------+\n"); // Print some art to the debug terminal, because America //printf("\n"); //asciiAces(); //asciiFlag(); TCPServer srv; TCPSocket clt_sock; SocketAddress clt_addr; srv.open(_eth); srv.bind(_eth->get_ip_address(), HTTP_SERVER_PORT); srv.listen(MAX_TCP_CONNECTIONS); printf("Beginning Main Loop\n"); while (true) { if (wgReader.isNew()) { uint16_t code = wgReader.card(); printf("RAW: %llu COUNT: %d CARD: %u\n", wgReader.bits(), wgReader.bitCount(), code); wgReader.old(); if (config_enableAccess && codeMem.FindAccessCode(code) >= 0) { unlatchStrike(); codeMem.WriteEvent(EVENT_KEYPAD_ACCESS_GRANTED, code); } } // Check for commands from the USB port. if (usb_rx_buffer[rx_idx - 1] == '\n') { usb_rx_buffer[rx_idx] = 0; string serial_command = usb_rx_buffer; submitSerialCommand(serial_command); rx_idx = 0; } configManager.update(); //srv.accept(&clt_sock, &clt_addr); //printf("accept %s:%d\n", clt_addr.get_ip_address(), clt_addr.get_port()); // Get browser request. //clt_sock.recv(httpReq, 100); //printf(httpReq); // Send status page to the browser. //sprintf(httpResponse, HTTP_RESPONSE, DATA_SERVER_PORT, button_presses); //clt_sock.send(httpResponse, strlen(httpResponse)); //clt_sock.close(); wait(0.01); } delete _eth; return 0; }