Seeking help.

I've foud a project on the internet that suits my needs.
A door opener using the lowcost RFID RD522 and a Arduino
The mechanism is the following:
Scan the Master Card followed bij a unknown card.
The unknown card ID is stored on the SDcard and is a 'known' card from that moment on.

And the use of a known card grants access.

Removing a card is don by scanning the master followed by the card to be removed.
But the function removeCard empties the complete database.
And that is a unwanted behaviour.
What I found out is that the file cards.txt (containing valid cards) is replaced by an empty file called cardsTemp.txt

I've already contacted the poster of the source and he admits that his code is flaw, but on my help request there is nou action from him.

And I very much want to make things working.

Is there anyone of you(cracks) who can help me with this problem.

I had to truncate the code, because the 9000 character limit.

Thanx in advance
regards Piet.

#include <SPI.h>
#include <Wire.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <SdFat.h>

#define MFRC_RST_PIN 9
#define MFRC_SS_PIN  10
#define SD_SS_PIN    8

#define STATE_STARTUP       0
#define STATE_STARTUP_ERROR 1
#define STATE_STARTING      2
#define STATE_WAITING       3
#define STATE_SCAN_INVALID  4
#define STATE_SCAN_VALID    5
#define STATE_SCAN_MASTER   6
#define STATE_ADDED_CARD    7
#define STATE_REMOVED_CARD  8

#define REDPIN 6
#define GREENPIN 7
#define RELAYPIN 5

const int cardSize = 4;
byte masterCard[cardSize] = {86,187,140,117};
byte readCard[cardSize] = {0,0,0,0};

// Create MFRC522 instance
MFRC522 mfrc522(MFRC_SS_PIN, MFRC_RST_PIN);
// Set the LCD I2C address
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

SdFat sd;

byte currentState = STATE_STARTUP;
unsigned long LastStateChangeTime;
unsigned long StateWaitTime;

char cardFile[] = "cards.txt";
char cardTempFile[] = "cardsTemp.txt";

//------------------------------------------------------------------------------------
void PrintCard(byte printCard[cardSize])
{
  int index;

  Serial.print("Card - ");
  for(index = 0; index < 4; index++)
  {
    if (index > 0)
    {
      Serial.print(",");
    }
    Serial.print(printCard[index]);
  }
  Serial.println(" ");
}

//------------------------------------------------------------------------------------
boolean findCard()
{
  byte currentCard[cardSize];
  char text[10];
  char c1;
  int  index;
  int  value;

  Serial.print("find ");
  PrintCard(readCard);

  // open input file
  ifstream readStr(cardFile);

  // check for open error
  if (!readStr.is_open())
  {
    return false;
  }

  index = 0;
  // read until input fails
  while (!readStr.eof()) 
  {
    readStr >> value >> c1; 

    if (readStr.fail()) 
    {
      break;
    }

    currentCard[index] = value;
    
    index++;
    if (index > 3)
    {
      Serial.print("file read ");
      PrintCard(currentCard);
      if ((memcmp(currentCard, readCard, 4)) == 0)
      {
        return true;
      } 
      index = 0;
    }
  }

  return false;
}

//------------------------------------------------------------------------------------
void addCard()
{
  int index;
  SdFile writeFile;

Serial.print("add ");
PrintCard(readCard);
  Serial.println(cardFile);
  Serial.println(O_RDWR);
  Serial.println(O_CREAT);
  Serial.println(O_AT_END);
  if (writeFile.open(cardFile, O_RDWR | O_CREAT | O_AT_END))
  { 
    for(index = 0; index < 4; index++)
    // Serial.print(index);
    {
      writeFile.print(readCard[index]); 
      writeFile.print(",");
    }
    writeFile.close();
  }
  return;
}

//------------------------------------------------------------------------------------
void removeCard()
{
  byte currentCard[cardSize];
  char text[10];
  char c1;
  int  readIndex, writeIndex;
  int  value;
  SdFile writeFile;

  //Serial.print("remove ");
  //PrintCard(readCard);

  // open input file
  ifstream readStr(cardFile);

  // check for open error
  if (!readStr.is_open())
  {
    return;
  }

  if (writeFile.open(cardTempFile, O_RDWR | O_CREAT | O_AT_END))
  {
    readIndex = 0;

    while (!readStr.eof()) 
    {
      readStr >> value >> c1; 

      if (readStr.fail()) 
      {
        break;
      }

      currentCard[readIndex] = value;
    
      readIndex++;
      if (readIndex > 3)
      {
        //Serial.print("file write ");
        //PrintCard(currentCard);
        if (!((memcmp(currentCard, readCard, 4)) == 0))
        {
          for (writeIndex = 0; writeIndex < 4; writeIndex++)
          {
            writeFile.print(currentCard[writeIndex]); 
            writeFile.print(",");
          }
          writeFile.close();
        }
      } 
      readIndex = 0;
    }
  }

  sd.remove(cardFile);
  sd.rename(cardTempFile, cardFile);
  
  return;
}

Rest of the code is ommited, 9000 character limit oof the forum.

Rest of the code is ommited, 9000 character limit oof the forum.

If you use Reply (not the Quick Reply field), you can attach your code, using the Additional Options link.

Find where the good file is being replaced and comment it out.

Which Arduino are you running the code on? There are two files open at a time. Each of them uses a 512 byte buffer. On a 328-based Arduino, that is half the SRAM. You could be running out of memory.

"Each of them uses a 512 byte buffer. On a 328-based Arduino, that is half the SRAM. "
Yep, two 512 byte file, 1K of the 2K SRAM.
There are a lot of libraries called out, those are likely using a lotof SRAM as well. What does the compiler say about how much dynamic memory is used when the code is compiled?

Maybe to prevent the memory issue, as you already are using the SDFat library, you may could implement one of it's example for open the file for read or write like this one:

// Ported to SdFat from the native Arduino SD library example by Bill Greiman
// On the Ethernet Shield, CS is pin 4. SdFat handles setting SS
const int chipSelect = 4;
/*
 SD card read/write

 This example shows how to read and write data to and from an SD card file
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4

 created   Nov 2010
 by David A. Mellis
 updated 2 Dec 2010
 by Tom Igoe
 modified by Bill Greiman 11 Apr 2011
 This example code is in the public domain.

 */
#include <SPI.h>
#include <SdFat.h>
SdFat sd;
SdFile myFile;

void setup() {
  Serial.begin(9600);
  while (!Serial) {}  // wait for Leonardo
  Serial.println("Type any character to start");
  while (Serial.read() <= 0) {}
  delay(400);  // catch Due reset problem

  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // change to SPI_FULL_SPEED for more performance.
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
    sd.initErrorHalt();
  }

  // open the file for write at end like the Native SD library
  if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
    sd.errorHalt("opening test.txt for write failed");
  }
  // if the file opened okay, write to it:
  Serial.print("Writing to test.txt...");
  myFile.println("testing 1, 2, 3.");

  // close the file:
  myFile.close();
  Serial.println("done.");

  // re-open the file for reading:
  if (!myFile.open("test.txt", O_READ)) {
    sd.errorHalt("opening test.txt for read failed");
  }
  Serial.println("test.txt:");

  // read from the file until there's nothing else in it:
  int data;
  while ((data = myFile.read()) >= 0) {
    Serial.write(data);
  }
  // close the file:
  myFile.close();
}

void loop() {
  // nothing happens after setup
}

I'm using the same logic in mine to open a file on SDCard with about 2Mb of size without problem with memory lake...

I have attached the complete source.
The board I'm using is a UNO
Is there also a memory of 512 buffer allocation for every opend file?

De schets gebruikt 21.588 bytes (66%) programma-opslagruimte. Maximum is 32.256 bytes.
Globale variabelen gebruiken 1.371 bytes (66%) van het dynamisch geheugen. Resteren 677 bytes voor lokale variabelen. Maximum is 2.048 bytes.
Translated.
Sketch uses 21.588 bytes (66%)
Global variables 1.371 (66%)
Rest 677 is for local variables.

best regards Piet.

Tasmanian_3.ino (7.54 KB)

Is there also a memory of 512 buffer allocation for every opend file?

Yes, and that buffer is not allocated until you open the file, so it does not show in the compile-time data reported when you build.

Since you are already using over half the memory, you can not open two files at a time.

So I have to read contents of the first file into an array, close that file.
Discard the card-id which has to be deleted from the array.
remove the file from the SDcard, open a new file and write the array to that file.
And subsequently clos the new file.

Is that the advisable approach?

best regards Piet.

Or use an Arduino Mega 2560, is that an option?

So I have to read contents of the first file into an array, close that file.
Discard the card-id which has to be deleted from the array.
remove the file from the SDcard, open a new file and write the array to that file.
And subsequently clos the new file.

Is that the advisable approach?

If the file is less than 512 bytes, that might work.

Or use an Arduino Mega 2560, is that an option?

Certainly.

Then I go for the Arduino Mega 2560.
It is now almost midnight in Europe, thus it will be tomorrow.

Thanks for the support so far.

best regards Piet.


I'm using the above layout with an Arduino Uno.
My plan is to replace the Uno by an Arduino Mega.

But when I connect the Mega with the same pins as used by the Uno, it won't work.
Is there a difference in pin designation between the Uno and Mega boards?

best regards Piet.

Yes, look them up. Notably, the SPI pins that you are probably using for the SD card are different. Also I2C is not on A4 and A5 on the Mega, IIRC.

I would not rewrite the whole file to invalidate an entry, I would use a valid/not valid flag stored with the id and change it in place.

Adding a new entry could reuse an invalid entry, or, if none exist, append it as before.

Whandall:
I would not rewrite the whole file to invalidate an entry, I would use a valid/not valid flag stored with the id and change it in place.

Adding a new entry could reuse an invalid entry, or, if none exist, append it as before.

Mmmmm... the problem is all scanned cards are not single entries in the file.
This is how it's stored in the file.
Each card in chunks of 4 bytes and all comma separated consecutive one after the other.

114,147,31,43,30,147,141,133,116,196,71,220,116,221,72,220,52,166,74,220,

card 1 : 114,147,31,43,
card 2 : 30,147,141,133,
card 3 : 116,196,71,220,
card 4 : 116,221,72,220,
card 5 : 52,166,74,220,
would be ideal to flag an invalid card.

And there is noting else to do than rewrite the readcard and writecard routines.

Unfortunately I think my programming skills are not developped enough.

best regards Piet.

Each card in chunks of 4 bytes and all comma separated consecutive one after the other.

The data does not NEED to be stored that way.

1 114,147, 31, 43
1  30,147,141,133
0 116,196, 71,220
1 116,221, 72,220
0  52,166, 74,220

Now, each record is fixed length and defines whether the code is valid (1 ) or not (0 ).

Yes I understand Paul.
But as I wrote, my programming skills are not that good that I can succesfully redesign the findCard(), addCard() and removeCard() functions.

I'm really puzzled.

best regards Piet.

Project will be scrapped, due to lack of skills, unfortunately.
Have to find an other solution.