/*
 * Exemple d'utilisation du lecteur Rfid de parallax
 * Application: Systéme d'ouverture de porte avec gâche électrique
 */
 
/* Include pour le port série software */
#include <SoftwareSerial.h>
 
/* Définition des broches */
#define PIN_ENABLE 2
#define PIN_RX 3
#define PIN_TX 4 // Non utilisé
#define PIN_GACHE 13
 
/* Constantes Parallax RFID */
#define CODE_LEN 10      // Taille d'un ID rfid
#define START_BYTE 0x0A  // Byte de start
#define STOP_BYTE 0x0D   // Byte de stop
 
/* Définition des constantes d'usage */
#define UNLOCK_TIME 2 // en secondes
#define RETRY_DELAY 2 // en secondes
 
/* Macro de gestion hardware */
#define enableRfid() digitalWrite(PIN_ENABLE, LOW)
#define disableRfid() digitalWrite(PIN_ENABLE, HIGH)
#define flushRfid() while(rfid.available() > 0) rfid.read()
 
#define enableGache() digitalWrite(PIN_GACHE, HIGH)
#define disableGache() digitalWrite(PIN_GACHE, LOW)
#define unlock() enableGache(); delay(UNLOCK_TIME * 1000); disableGache()
 
/* Base de donnée des ID de tag valide */
char* tagId[] = {
  "0000C153EC", // tag 1
  "0000CAAAAA", // tag 2
  "0001111A1A", // tag 3
};
 
/* Base de donnée des nom de tag valide */
char* tagNom[] = {
  "Eleve 1",    // tag 1
  "Eleve 2",    // tag 2
  "Eleve 3",    // tag 3
};
 
/* Nombre de tag dans la bdd */
const byte nbTag = 3;
 
/* Buffer contenant le tag en cours de lecture */
char tag[CODE_LEN];
 
/* Déclaration d'une instance de SoftwareSerial pour communiquer avec le lecteur rfid */
SoftwareSerial rfid(PIN_RX, PIN_TX);
 
/* Fonction setup() */
void setup() {
 
  /* Initialisation du port série hardware */
  Serial.begin(9600);
 
  /* Initialisation du port série software */
  rfid.begin(2400);
 
  /* Mise en OUTPUT de la broche ENABLE du lecteur RFID */
  pinMode(PIN_ENABLE,OUTPUT);
  disableRfid();
 
  /* Mise en OUTPUT de la broche câblé sur la gachette électrique */
  pinMode(PIN_GACHE,OUTPUT);
  disableGache(); 
}
 
/* Fonction loop() */
void loop() { 
 
  /* Récupération d'un ID valide ou non (fonction bloquante) */
  getRfidTag();
 
  /* index: résultat de la fonction isCodeValid() */
  int index;
 
  /* Si le tag est présent dans la bdd */
  if((index = isCodeValid()) >= 0) {
 
    /* Affichage du msg d'accès, et du nom de la personne */
    Serial.println("Acces autorise");
    Serial.println(tagNom[index]);
    unlock();
  } 
  else {
    /* Sinon affichage  */
    Serial.println("Acces non autorise");
 
    /* Attente avant de pouvoir repasser une carte */
    delay(RETRY_DELAY * 1000);
  }
   
  /* Vide le buffer série du lecteur rfid (évite de lire des données parasites) */
  flushRfid();
} 
 
/*
 * Fonction lisant un ID rfid depuis le port série software, et ne rendant la main qu'une fois un code rfid correctement recu
 */
void getRfidTag() {
  /* Activation du lecteur RFID */
  enableRfid();
 
waitTag: /* Etiquette de rappel */
 
  do {
    /* Attente d'au moins un octet sur le port série */
    while(rfid.available() < 1);
 
    /* Attente du byte de start */
  } 
  while(rfid.read() != START_BYTE);
 
  /* i: variable d'itération */
  byte i;
 
  /* Lecture du tag */
  for(i = 0; i < CODE_LEN; i++) {
 
    /* Attente d'au moins un octet sur le port série */
    while(rfid.available() < 1);
 
    /* Si jamais une erreur de lecture ce produit, et que le lecteur rfid retourne STOP_BYTE */
    if((tag[i] = rfid.read()) == STOP_BYTE) 
      /* On quitte la boucle */
      break;
  }
 
  /* Si i est différent de CODE_LEN c'est qu'il y a eu une erreur de lecture */
  if(i != CODE_LEN)
    /* On reprend donc depuis le début */
    goto waitTag; 
 
  /* Attente d'au moins un octet sur le port série */
  while(rfid.available() < 1);
 
  /* Si l'octet suivant n'est pas le byte de stop c'est qu'il y a un probléme de syncro */
  if(rfid.read() != STOP_BYTE)
    /* On reprend donc depuis le début */
    goto waitTag;
 
  /* Désactivation du lecteur rfid */
  disableRfid();
}
 
/*
 * Retourne l'indice du tableau tagNom correspondant au tag rfid si celui ci est présent dans le tableau tagId, sinon -1
 */
int isCodeValid() {
  /* Passe en revu chaque tag en bdd */
  for(byte i = 0; i < nbTag; i++)
    /* Si un tag correspond */
    if(memcmp(tag, tagId[i], CODE_LEN) == 0)
      /* on retourne son indice */
      return i;
 
  /* Si aucun tag ne correspond, on retourne -1 */
  return -1;
}
