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

Revision:
0:a56239ae90c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CodeMemory.cpp	Mon Sep 25 19:02:40 2017 +0000
@@ -0,0 +1,326 @@
+
+#include "CodeMemory.h"
+
+void CodeMemory::EEPROMClear()
+{
+  for (int i = 0 ; i < EEPROM_LENGTH ; i += 4)
+  {
+    _eeprom->Write(i, (int)0, C24LCXX_I2C::LittleEndian);
+  }
+}
+
+unsigned short CodeMemory::ReadAccessCode(unsigned short address)
+{
+  // Read two bytes at the specified address
+  short code;
+  _eeprom->Read((short)address, &code, C24LCXX_I2C::LittleEndian);
+ 
+  return code; 
+}
+
+void CodeMemory::WriteAccessCode(unsigned short address, unsigned short value)
+{
+  //Write the bytes into the eeprom memory.
+  _eeprom->Write(address, (short)value, C24LCXX_I2C::LittleEndian);
+  
+  return;
+}
+
+unsigned int CodeMemory::ReadEEPROMULong(unsigned short address)
+{
+  // Read four bytes at the specified address.
+  int value;
+  _eeprom->Read((short)address, &value, C24LCXX_I2C::LittleEndian);
+ 
+  return value; 
+}
+
+void CodeMemory::WriteEEPROMULong(unsigned short address, unsigned int value)
+{
+  _eeprom->Write((short)address, (int)value, C24LCXX_I2C::LittleEndian);
+  
+  return;
+}
+
+// Find the address of the specified code
+int CodeMemory::FindAccessCode(unsigned short code)
+{
+  return FindAccessCode(code, 0, CODE_TABLE_SIZE);
+}
+
+int CodeMemory::FindAccessCode(unsigned short code, unsigned short startAddress, unsigned short stopAddress)
+{
+  int address = startAddress;
+  while ((address < stopAddress) && (ReadAccessCode(address) != code))
+  {
+    address += 2;
+  }
+  
+  if (address >= stopAddress)
+  {
+    address = -1;
+  }
+  
+  return address; 
+}
+
+// **************************************************
+// EEPROM Access Code Functions
+// **************************************************
+
+int CodeMemory::ActivateAccessCode(unsigned short value)
+{
+  int address = FindAccessCode(value);
+  if (address >= 0)
+  {
+    return -1; // The code already exists in the list.
+  }
+  
+  // Find the address of the next available 16 bit code slot (zero valued)
+  address = FindAccessCode(0);
+  if (address >= 0)
+  {
+    WriteAccessCode(address, value);
+  }
+  else // Memory Full
+  {
+    address = -2;
+  }
+  
+  return address;
+}
+
+int CodeMemory::DeactivateAccessCode(unsigned short value)
+{
+  int address = FindAccessCode(value);
+  if (address < 0)
+  {
+    return -1; // The code was not found
+  }
+  else
+  {
+    // Erase the two bytes of data from eeprom
+    _eeprom->Write(address, (short)0, C24LCXX_I2C::LittleEndian);
+  }
+  
+  return address;
+}
+
+void CodeMemory::PrintAllAccessCodes()
+{
+  int address = 0;
+  while (address < CODE_TABLE_SIZE + SPECIAL_CODE_TABLE_SIZE)
+  {
+    unsigned int code = ReadAccessCode(address);
+    if (code > 0)
+    {
+      printf("%d - %d\n", address, code);
+    }
+    address += 2;
+  }
+  
+  return;
+}
+
+void CodeMemory::SyncAccessCodes(unsigned short* codeList, unsigned short codeCount)
+{
+    // Deactivate codes that don't exist in the new set.
+    for (int address = 0; address < CODE_TABLE_SIZE; address += 2)
+    {
+        unsigned short code = ReadAccessCode(address);
+        
+        if (code > 0)
+        {
+            // Search the new code list for this code.
+            unsigned short* codePtr = std::find(codeList, codeList + codeCount, code);
+            if (codePtr == codeList + codeCount)
+            {
+                // Code not found.
+                WriteAccessCode(address, 0);
+            }
+        }
+    }
+    
+    // Activate all codes in the code list. Duplicates will be ignored.
+    for (int codeIndex = 0; codeIndex < codeCount; codeIndex++)
+    {
+        ActivateAccessCode(codeList[codeIndex]);
+    }
+    
+    return;
+}
+
+// **************************************************
+// EEPROM Special Command Code Functions
+// **************************************************
+
+bool CodeMemory::IsSpecialCode(unsigned short specialCodeIndex, unsigned short code, unsigned short defaultCode)
+{
+  // Check for code index out of range
+  if (specialCodeIndex >= (SPECIAL_CODE_TABLE_SIZE / 2))
+  {
+    return false;
+  }
+  
+  // Check test code value against the default code or eeprom custom code
+  else
+  {
+    unsigned short eepromValue = ReadAccessCode(CODE_TABLE_SIZE + (specialCodeIndex * 2));
+    return ((eepromValue == 0) && (code == defaultCode)) || (code == eepromValue);
+  }
+}
+
+bool CodeMemory::SetSpecialCode(unsigned short specialCodeIndex, unsigned short code)
+{
+  // Don't allow duplicate codes
+  if (FindAccessCode(code, CODE_TABLE_SIZE, CODE_TABLE_SIZE + SPECIAL_CODE_TABLE_SIZE) < 0)
+  {
+    printf("Changing special code at index %d to %d\n", specialCodeIndex, code);
+    
+    WriteAccessCode(CODE_TABLE_SIZE + (specialCodeIndex * 2), code);
+    return true;
+  }
+  else
+  {
+    printf("Failed to change special code: Code Exists\n"); 
+    return false; // Code already exists in the special code table
+  }
+}
+
+// **************************************************
+// EEPROM Event Log
+// **************************************************
+
+int CodeMemory::LogPointerAddress()
+{
+  return CODE_TABLE_SIZE + SPECIAL_CODE_TABLE_SIZE;
+}
+
+int CodeMemory::FirstEventLogAddress()
+{
+  return LogPointerAddress() + EVENT_LOG_POINTER_SIZE + EVENT_LOG_TIME_BASE_SIZE;
+}
+
+int CodeMemory::EventLogEndAddress()
+{
+  return EEPROM_LENGTH;
+}
+
+void CodeMemory::PrintEvent(unsigned short eventAddress)
+{
+  unsigned char memByte;
+  _eeprom->Read((short)eventAddress, &memByte);
+  printf("%u:%u:%u\n", ReadEEPROMULong(eventAddress + 3), memByte, ReadAccessCode(eventAddress + 1));
+  
+  return;
+}
+
+int CodeMemory::GetLatestEventAddress()
+{
+  return ReadAccessCode(LogPointerAddress()); // Get the location of the last event
+}
+
+int CodeMemory::GetNextEventAddress()
+{
+  return GetNextEventAddress(GetLatestEventAddress());
+} 
+
+int CodeMemory::GetNextEventAddress(unsigned short startAddress)
+{
+  int address = startAddress;
+  
+  if (address < FirstEventLogAddress())
+  {
+    // Empty log, so point to the first slot 
+    address = FirstEventLogAddress();
+  }
+  else if ((address + EVENT_SIZE + (EVENT_SIZE - 1)) < EventLogEndAddress())
+  {
+    // No wrap necessary
+    address += EVENT_SIZE;
+  }
+  else
+  {
+    // Wrap to the beginning of the log
+    address = FirstEventLogAddress();
+  }
+  
+  return address;
+}
+
+int CodeMemory::GetPreviousEventAddress(unsigned short startAddress)
+{
+  int address = startAddress;
+  
+  if ((address - EVENT_SIZE) >= FirstEventLogAddress())
+  {
+    // No wrap necessary
+    address -= EVENT_SIZE;
+  }
+  else // Wrap to the end of the log
+  {
+    int eventLogLength = ((EventLogEndAddress() - FirstEventLogAddress()) / EVENT_SIZE);
+    address = FirstEventLogAddress() + ((eventLogLength * EVENT_SIZE) - EVENT_SIZE); // Last event address
+  }
+  
+  return address;
+}
+
+void CodeMemory::WriteEvent(unsigned char eventType, unsigned short eventValue)
+{
+  unsigned int currentTime = time(NULL);
+  
+  // Determine the location of the next event
+  int eventAddress = GetNextEventAddress();
+  WriteAccessCode(LogPointerAddress(), eventAddress);
+  
+  // Write the event type byte
+  _eeprom->Write(eventAddress, eventType);
+  
+  // Write the event value integer
+  WriteAccessCode(eventAddress + 1, eventValue);
+  
+  // Write the timestamp
+  WriteEEPROMULong(eventAddress + 3, currentTime);
+  
+  // Send the event code to the supervisor for SQL storage
+  printf("Evt:%lu:%u:%u\n", currentTime, eventType, eventValue);
+  
+  return; 
+}
+
+void CodeMemory::PrintEventLog()
+{
+  int oldestEventAddress = GetNextEventAddress();
+  int eventAddress = oldestEventAddress;
+  
+  // Print all of the events, oldest to newest
+  do
+  {
+    PrintEvent(eventAddress);
+    
+    // Increment to the next event in the log
+    eventAddress = GetNextEventAddress(eventAddress);
+  } while (eventAddress != oldestEventAddress);
+  
+  return;
+}
+
+void CodeMemory::PrintRecentEvents()
+{
+  PrintRecentEvents(10);
+  return;
+}
+
+void CodeMemory::PrintRecentEvents(unsigned short numEvents)
+{
+  int eventAddress = GetLatestEventAddress();
+
+  for (int eventIndex = 0; eventIndex < numEvents; eventIndex++)
+  {
+    PrintEvent(eventAddress);
+    eventAddress = GetPreviousEventAddress(eventAddress); 
+  }
+
+  return; 
+}
\ No newline at end of file