RFID reader reads too much (or too less)

Hello,
I'm using an Arduino in order to read some RFID tags and open a door if the tag is enabled. The program is really simple: Arduino reads the tag, then asks the main server what to do with an http GET. The answer is the number of "credits" that the tag has, so if it's greater than 0 then Arduino opens the door.

The problem is that sometimes (quite often) the server receives a request with a wrong tag, that could be shorter or longer than usual. This for example is (taken from the Apache logs) a "right2 request:

10.3.8.250 - - [31/Mar/2016:18:46:51 +0200] "GET /door/index.php?ID=54004E25506F" 200 24 "-" "-"

In this case the tag is too short:

10.3.8.250 - - [31/Mar/2016:18:46:35 +0200] "GET /door/index.php?ID=54" 200 21 "-" "-"

Sometimes is too long:

10.3.8.250 - - [31/Mar/2016:18:46:42 +0200] "GET /door/index.php?ID=54004E25506F54004E25506F\xfd\x02\x80" 200 21 "-" "-"

What's going on?

This is the code:

#include <SPI.h>         // needed for Arduino versions later than 0018 
#include <Ethernet2.h>
#include <TextFinder.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x21, 0x8c };
byte ip[] =  { 10, 3, 8, 250 };
byte gateway[] = { 10, 3 , 8, 1 };
byte subnet[] = { 255, 255, 255, 0 };
const IPAddress server(10, 3, 8, 254);
long lastRequestTime = 0;
float answer;
int buttonState = 0;
EthernetClient client;
String Request;

int RFIDResetPin = 2;
int DoorPin = 8;
int ExitButtonPin = 9;

/* SETUP */

void setup() {
  Serial.begin(9600);
  pinMode(ExitButtonPin, INPUT);
  pinMode(RFIDResetPin, OUTPUT);
  pinMode(DoorPin, OUTPUT);
  digitalWrite(RFIDResetPin, HIGH);
  digitalWrite(DoorPin, HIGH);
  Ethernet.begin(mac, ip, subnet, gateway);
  delay(2000);
}

/* LOOP */

void loop() {
  answer = 0;
  buttonState = digitalRead(ExitButtonPin);
  if (buttonState == HIGH) { //open the door if someone needs to exit
    digitalWrite(DoorPin, LOW);
    delay(5000);
    digitalWrite(DoorPin, HIGH);
  }
  else {
    digitalWrite(DoorPin, HIGH);
  }
  char tagString[13] = "";
  int index = 0;
  boolean reading = false;
  while (Serial.available()) {
    int readByte = Serial.read(); //read next available byte
    if (readByte == 2) reading = true; //begining of tag
    if (readByte == 3) reading = false; //end of tag
    if (reading && readByte != 2 && readByte != 10 && readByte != 13) {
      tagString[index] = readByte;  //store the tag
      index ++;
    }
  }
  checkTag(tagString); //Check if it is a match
  clearTag(tagString); //Clear the char of all value
  resetReader(); //Reset the RFID reader
}

void checkTag(char tag[]) {
  if (strlen(tag) == 0) return; //empty, no need to contunue
  if (strlen(tag) > 0) {
    if (client.connected()) {
      client.stop();
    }
    if (client.connect(server, 80)) {
      Request = "GET /door/index.php?ID=";
      String strtag(tag);
      Request += strtag;
      Request += "\r\n HTTP/1.1\r\nHost: arduino.server.local\r\n\r\n";
      client.println(Request);
      client.println();
    }
    lastRequestTime = millis();  // note the time of this connect attempt:

    if (client.connected() ) {  // if you're connected to the server:
      delay(1000);
      if (client.available()) {  // if there are bytes available from the server
        TextFinder response(client); // make an instance of TextFinder to search the response
        if (response.find("<answer>")) { // see if the response from the server contains <answer>
          answer = response.getFloat(); // get the answer
          client.stop(); // stop the client, and close the connection
        } else {
          client.stop(); // stop the client, and close the connection
          answer = 0;
        }
      }
      client.flush();
    }
    if (!client.connected()) {
      client.stop();
    }
    if (answer >= 1) {
      digitalWrite(DoorPin, LOW);
      delay(5000);
      digitalWrite(DoorPin, HIGH);
    }
  }
}

void resetReader() {
  digitalWrite(RFIDResetPin, LOW);
  digitalWrite(RFIDResetPin, HIGH);
  delay(150);
}

void clearTag(char one[]) {
  for (int i = 0; i < strlen(one); i++) {
    one[i] = 0;
  }
}

Thanks!

Matteo

    if (reading && readByte != 2 && readByte != 10 && readByte != 13) {
      tagString[index] = readByte;  //store the tag
      index ++;
    }

You are not creating a string. You are creating a char array.

  checkTag(tagString); //Check if it is a match

This function expects a string.

A string is a NULL terminated array of chars. You need to add a NULL after each character:

    if (reading && readByte != 2 && readByte != 10 && readByte != 13) {
      tagString[index] = readByte;  //store the tag
      index ++;
      tagString[index] = '\0'; // NULL terminate the array, creating a string
    }

Hello PaulS,
thanks for your suggestion!

Last Saturday I've been able to do the change, and at the beginning it seemed that the problem was solved. I've attached an rfid tag to the reader with some tape and it has read it correctly like 100 times. But today I've looked at the Apache logs and I can see that the problem occured again during the "normal" usage:

Good reading (for instance):
10.3.8.250 - - [09/May/2016:17:13:23 +0200] "GET /door/index.php?ID=37003EA5E14D" 200 19 "-" "-"

Error in reading, like if it hasn't been able to understand the end of the rfid tag:
10.3.8.250 - - [09/May/2016:17:13:29 +0200] "GET /door/index.php?ID=37003EA5E14D37003EA5E14D37003EA5E14D" 200 21 "-" "-"

Another error, this time too short:
10.3.8.250 - - [10/May/2016:18:45:17 +0200] "GET /door/index.php?ID=370" 200 21 "-" "-"

Any idea?

Thanks,
Matteo

Most likely your problem is that you always call

checkTag(tagString); //Check if it is a match
clearTag(tagString); //Clear the char of all value
resetReader(); //Reset the RFID reader

You should check tag only when it is received completely (when reading is false).

Why sometimes tag is too short ? Because you called checkTag before tag was received completely.

Why sometimes tag is too long ? Because you use delay(), and during a delay, your code is paused, it can't do anything else than waiting. When a delay() is elapsed, your code resume, so your while() loop will read all characters that were accumulated in the serial input buffer during this delay.

I haven't studied you code in details, so there may be other problems..

I've attached an rfid tag to the reader with some tape and it has read it correctly like 100 times.

What kind of reader is it? Both of the RFID readers that I have would have read the tag exactly once. Most RFID readers send data once when the tag comes into range, and then do not send data again until the tag goes out of range.

Most also send a fixed amount of data, so there is no need to guess how much data will arrive. Get too much? Discard the excess (or the whole mess). Get too little? Discard the mess.