//Code written by Alex Wulff and DFRobot.com. For contact info visit www.AlexWulff.com

// bytes necessary for communication with NFC Reader
const unsigned char wake[24]={
  0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00};
const unsigned char firmware[9]={0x00, 0x00, 0xFF, 0x02, 0xFE, 0xD4, 0x02, 0x2A, 0x00};
const unsigned char tag[11]={0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD4, 0x4A, 0x01, 0x00, 0xE1, 0x00};
const unsigned char std_ACK[25] = {
  0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0C, \
0xF4, 0xD5, 0x4B, 0x01, 0x01, 0x00, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00};
unsigned char old_id[5];
unsigned char receive_ACK[25];

// setting up Serial for NFC Reader
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#define print1Byte(args) Serial1.write(args)
#define print1lnByte(args)  Serial1.write(args),Serial1.println()
#else
#include "WProgram.h"
#define print1Byte(args) Serial1.print(args,BYTE)
#define print1lnByte(args)  Serial1.println(args,BYTE)
#endif

// pins utilized on Leonardo and constants
#define IR_SENSOR         A0
#define BUZZER            10
#define FLAG_RESET_TIME   5000

void setup(){
  Serial1.begin(115200);
  
  pinMode(BUZZER, OUTPUT);
  pinMode(IR_SENSOR, INPUT);
  
  wake_card();
  delay(100);
  read_ACK(15);
}

long lastFlag = 0;
bool flag = false;

void loop(){

  // get current distance from IR sensor
  int distance = getDistance();
  
  send_tag(); 
  read_ACK(25);
  delay(100);
  
  if (!cmp_id()) {
    if (test_ACK()) {

      // NFC device detected. Play tone!
      tone(BUZZER, 440, 200);
      delay(400);
      tone(BUZZER, 800, 200);
      delay(400);
      tone(BUZZER, 2000, 200);
      delay(400);
      tone(BUZZER, 300, 200);
      delay(400);
      
      lastFlag = millis();
      flag = true;
    }
  }

  // only turn on buzzer if there's no NFC tag and distance < 10
  if(distance < 10 && flag == false) {
    analogWrite(BUZZER, 255);
  }

  else {
    digitalWrite(BUZZER, LOW);
  }

  // reset flag after 5 seconds
  if (millis() - lastFlag > FLAG_RESET_TIME) {
    flag = false;
  }
  
  copy_id();
}

int getDistance(void) {
  return 2076.0 / (analogRead(IR_SENSOR) - 11.0);
}

void copy_id (void) {//save old id
  int ai, oi;
  for (oi=0, ai=19; oi<5; oi++,ai++) {
    old_id[oi] = receive_ACK[ai];
  }
}
 
char cmp_id (void){//return true if find id is old
  int ai, oi;
  for (oi=0,ai=19; oi<5; oi++,ai++) {
    if (old_id[oi] != receive_ACK[ai])
      return 0;
  }
  return 1;
}

int test_ACK (void) {// return true if receive_ACK accord with std_ACK
  int i;
  for (i=0; i<19; i++) {
    if (receive_ACK[i] != std_ACK[i])
      return 0;
  }
  return 1;
}

void UART1_Send_Byte(unsigned char command_data){//send byte to device
  print1Byte(command_data);
#if defined(ARDUINO) && ARDUINO >= 100
  Serial1.flush();// complete the transmission of outgoing serial data 
#endif
} 

void read_ACK(unsigned char temp){//read ACK into reveive_ACK[]
  unsigned char i;
  for(i=0;i<temp;i++) {
    receive_ACK[i]= Serial1.read();
  }
}

void wake_card(void){//send wake[] to device
  unsigned char i;
  for(i=0;i<24;i++) //send command
    UART1_Send_Byte(wake[i]);
}

void firmware_version(void){//send fireware[] to device
  unsigned char i;
  for(i=0;i<9;i++) //send command
    UART1_Send_Byte(firmware[i]);
}

void send_tag(void){//send tag[] to device
  unsigned char i;
  for(i=0;i<11;i++) //send command
    UART1_Send_Byte(tag[i]);
}
