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
Diff: main.cpp
- Revision:
- 0:a56239ae90c2
diff -r 000000000000 -r a56239ae90c2 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Sep 25 19:02:40 2017 +0000 @@ -0,0 +1,381 @@ +#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; +}