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
ConfigurationManager.cpp
- Committer:
- acesrobertm
- Date:
- 2017-09-25
- Revision:
- 0:a56239ae90c2
File content as of revision 0:a56239ae90c2:
#include "ConfigurationManager.h" void ConfigurationManager::remove_all_chars(char* str, char c) { char *pr = str, *pw = str; while (*pr) { *pw = *pr++; pw += (*pw != c); } *pw = '\0'; } bool ConfigurationManager::isValidIpString(char* ip) { bool isValid = false; int strLength = strlen(ip); int numPeriods = 0; // Verify that the length is within bounds. if (strLength >= IP_STRING_MIN_LENGTH && strLength <= IP_STRING_MAX_LENGTH) { // Verify that there are three periods in the string. for (int charIndex = 0; charIndex < strLength; charIndex++) { numPeriods += (ip[charIndex] == '.'); } isValid = (numPeriods == 3); } return isValid; } int ConfigurationManager::parse_tftp_config(char* data) { int dataLength = strlen(data); int paramStart = 0; int paramNameLength = 0; int paramValueLength = 0; char paramName[CONFIG_PARAM_NAME_MAX_LENGTH + 1] = ""; char paramValue[CONFIG_PARAM_VALUE_MAX_LENGTH + 1] = ""; bool paramComplete = false; // Get the parameter name for (int charIndex = 0; charIndex <= dataLength; charIndex++) { // Check for end of the parameter name. if (data[charIndex] == '=') { paramNameLength = charIndex - paramStart; } // Check for the end of the parameter value. if (data[charIndex] == '\r' || data[charIndex] == '\n' || data[charIndex] == ' ' || charIndex == dataLength) { int paramValueStart = (paramStart + paramNameLength + 1); paramValueLength = charIndex - paramValueStart; // Handle oversized input strings. if (paramNameLength > CONFIG_PARAM_NAME_MAX_LENGTH || paramValueLength > CONFIG_PARAM_VALUE_MAX_LENGTH) { paramComplete = true; } if (!paramComplete && paramNameLength > 0 && paramValueLength > 0) { // Get the name and value strings. memcpy(paramName, data + paramStart, paramNameLength); paramName[paramNameLength] = 0; memcpy(paramValue, data + paramValueStart, paramValueLength); paramValue[paramValueLength] = 0; printf(" %s=%s\n", paramName, paramValue); // Store the parameter value. if (!strcmp(paramName, configName_enableAccess)) { config_enableAccess = (paramValue[0] == '1'); } else if (!strcmp(paramName, configName_ipAddress) && isValidIpString(paramValue)) { strcpy(config_ipAddress, paramValue); } else if (!strcmp(paramName, configName_netMask) && isValidIpString(paramValue)) { strcpy(config_netMask, paramValue); } else if (!strcmp(paramName, configName_gateway) && isValidIpString(paramValue)) { strcpy(config_gateway, paramValue); } else if (!strcmp(paramName, configName_codeFileName) && strlen(paramValue) <= CONFIG_PARAM_VALUE_MAX_LENGTH) { strcpy(config_codeFileName, paramValue); } else if (!strcmp(paramName, configName_ntpServer) && isValidIpString(paramValue)) { strcpy(config_ntpServer, paramValue); } else if (!strcmp(paramName, configName_usbBaud)) { config_usbBaud = atoi(paramValue); } } paramComplete = true; } // Reset for the next parameter. if (data[charIndex] == '\n') { paramStart = charIndex + 1; paramNameLength = 0; paramValueLength = 0; paramName[0] = 0; paramValue[0] = 0; paramComplete = false; } } return 0; } int ConfigurationManager::parse_tftp_codes(char* tftp_data) { unsigned short codeList[CODE_TABLE_SIZE / 2] = {0}; unsigned int dataLength = strlen(tftp_data); int codeStart = 0; int codeLength = 0; int codeIndex = 0; char codeString[ACCESS_CODE_MAX_LENGTH + 1] = ""; bool codeComplete = true; // Get the parameter name for (int charIndex = 0; charIndex <= dataLength; charIndex++) { if (tftp_data[charIndex] >= '0' && tftp_data[charIndex] <= '9') { if (codeComplete) { codeStart = charIndex; codeLength = 0; } codeLength += 1; codeComplete = false; } else // not a number character { codeComplete = true; // Ensure that the code is of the correct size. if (codeIndex < (CODE_TABLE_SIZE / 2) && codeLength >= ACCESS_CODE_MIN_LENGTH && codeLength <= ACCESS_CODE_MAX_LENGTH) { memcpy(codeString, tftp_data + codeStart, codeLength); codeString[codeLength] = 0; unsigned short codeValue = atoi(codeString); // Store the code in a temporary list to use when updating the EEPROM. codeList[codeIndex] = codeValue; // Format and print the list of access codes with multiple codes per line. //printf(ACCESS_CODE_PRINT_FORMAT, codeValue); codeIndex++; // New line of access codes if (codeIndex % ACCESS_CODE_NUM_COLS == 0) { //printf("\n"); } } } } printf("Downloaded %d codes.\n\n", codeIndex); // Update the EEPROM with the current network list of codes. mCodeMem->SyncAccessCodes(codeList, codeIndex); return 0; } // Set the IP address options from the configuration parameters and connect to the network. int ConfigurationManager::connectEthernet(char* mac_addr, char* ip_addr, const bool withDhcp, const bool printStats) { int connectResult; mEth->set_dhcp(withDhcp); // Reconfigure the network for a static address if specified. if (!withDhcp && isValidIpString(config_ipAddress) && isValidIpString(config_netMask) && (strlen(config_gateway) == 0 || isValidIpString(config_gateway))) { mEth->set_network(config_ipAddress, config_netMask, config_gateway); } // Attempt network connection connectResult = mEth->connect(); if (connectResult >= 0) { strcpy(mac_addr, mEth->get_mac_address()); strcpy(ip_addr, mEth->get_ip_address()); if (printStats) { printf("Network Connected:\n"); printf(" mac: %s\n", mac_addr); printf(" ip: %s\n", ip_addr); printf(" mask: %s\n", mEth->get_netmask()); printf(" gate: %s\n", mEth->get_gateway()); } } else { printf("Failed to connect to the network. %d\n", connectResult); } return connectResult; } void ConfigurationManager::updateClock() { // Set the real time clock using NTP printf("\nSending NTP query to %s...\n", config_ntpServer); int ntp_result = _ntp.setTime(mEth, config_ntpServer); if (ntp_result < 0) { printf("Failed to send.\n"); } lastUpdatedTimeSeconds = time(NULL); return; } void ConfigurationManager::setupNetwork() { printf("\nEstablishing DHCP network connection...\n"); // Ethernet Setup: Connect to the netowrk using DHCP _tftp = new TFTPClient(mEth); int connectResult = connectEthernet(_mac_addr, _ip_addr); if (connectResult >= 0) { // Reconfigure the network settings for a temporary static IP address // This is required to free port 68 for the DHCP option query in the next step. strcpy(config_ipAddress, mEth->get_ip_address()); strcpy(config_netMask, mEth->get_netmask()); strcpy(config_gateway, mEth->get_gateway()); mEth->disconnect(); connectResult = connectEthernet(_mac_addr, _ip_addr, 0, 1); // Get the IP address of the TFTP server via DHCP offer message. printf("\nGetting the TFTP server address via DHCP...\n"); DHCPOptions ops(mEth); int optionResult = ops.getOptions(config_tftpServer, _mac_addr); if (optionResult >= 0) { //updateConfiguration(); } else { printf("Failed to get options from DHCP: %d\n", optionResult); } } else if (connectResult == NSAPI_ERROR_DHCP_FAILURE) { // Retry DHCP until it works. // If the error is not due to DHCP, then continue without network features. printf("Resetting...\n"); wait(RESET_PAUSE_SECONDS); NVIC_SystemReset(); } } void ConfigurationManager::update() { // Periodically update the controller configuration from TFTP. if ((time(NULL) - lastUpdatedConfigSeconds) > CONFIG_UPDATE_INTERVAL_SECS) { mUpdateStep = UPDATE_STEP_INITIATE; lastUpdatedConfigSeconds = time(NULL); } if (mUpdateStep == UPDATE_STEP_INITIATE) { // Build TFTP filename from the MAC address. char tftp_filename[MAC_STRING_LENGTH + 1] = ""; strcpy(tftp_filename, _mac_addr); remove_all_chars(tftp_filename, ':'); strcat(tftp_filename, ".cnf"); printf("Getting config file %s from %s...\n", tftp_filename, config_tftpServer); int tftpResult = _tftp->readFile(_tftp_data, config_tftpServer, tftp_filename); if (tftpResult < 0) { printf(" TFTP config file request failed: %d\n", tftpResult); } else { mUpdateStep = UPDATE_STEP_CONFIG_FILE_REQUEST_SENT; } } else if (mUpdateStep == UPDATE_STEP_CONFIG_FILE_REQUEST_SENT) { // Wait for the TFTP response from the server. int tftp_result = _tftp->update(); if (tftp_result == 1) { printf("TFTP Success.\n\n"); mUpdateStep = UPDATE_STEP_CONFIG_FILE_RECEIVED; } else { printf(" Failed to retrieve configuration file: %d\n", tftp_result); } } else if (mUpdateStep == UPDATE_STEP_CONFIG_FILE_RECEIVED) // retrieve file succeeded { int currentUsbBaud = config_usbBaud; parse_tftp_config(_tftp_data); if (config_usbBaud > 0 && config_usbBaud != currentUsbBaud) { printf("\nSetting USB Serial Baud: %d\n \n", config_usbBaud); // Leave extra space because setting baud rate deletes some characters. //usbUART.baud(config_usbBaud); } printf("\nConfiguring static network connection...\n"); mEth->disconnect(); connectEthernet(_mac_addr, _ip_addr, 0, 1); printf("\nGetting code list file %s from %s...\n", config_codeFileName, config_tftpServer); // Get list of access codes from the specified file on the TFTP server. int tftpResult = _tftp->readFile(_tftp_data, config_tftpServer, config_codeFileName); if (tftpResult < 0) { printf("Failed to send config file request.\n"); } else { mUpdateStep = UPDATE_STEP_CODES_FILE_REQUEST_SENT; } } else if (mUpdateStep == UPDATE_STEP_CODES_FILE_REQUEST_SENT) { // Wait for the TFTP response from the server. int tftp_result = _tftp->update(); if (tftp_result == 1) { printf("TFTP Success.\n\n"); mUpdateStep = UPDATE_STEP_CODES_FILE_RECEIVED; } else { printf(" Failed to retrieve code list: %d\n", tftp_result); } } else if (mUpdateStep == UPDATE_STEP_CODES_FILE_RECEIVED) { parse_tftp_codes(_tftp_data); mUpdateStep = UPDATE_STEP_IDLE; } // Periodically update the RTC via NTP. if ((time(NULL) - lastUpdatedTimeSeconds) > TIME_UPDATE_INTERVAL_SECS) { updateClock(); } // Check the status of any ongoing NTP updates. int ntp_result = _ntp.update(); if (ntp_result < 0) { printf("NTP query failed.\n\n"); } else if (ntp_result > 0) { unsigned int ctTime = time(NULL); printf("Time is now (UTC): %s\n\n", ctime(&ctTime)); } }