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

CodeMemory.cpp

Committer:
acesrobertm
Date:
2017-09-25
Revision:
0:a56239ae90c2

File content as of revision 0:a56239ae90c2:


#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; 
}