//change linux port baud rate 'sudo stty -F /dev/ttyACM1 9600'
#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 53
#define RST_PIN 5

MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class

MFRC522::MIFARE_Key key;

char inputBuffer[16];
char codigo[9];
char option1[] = "1";
char option2[] = "2";
byte nuidPICC[4];
char configured = '*';
int flag = 0;

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(20000L) ;
  SPI.begin(); // Init SPI bus
  rfid.PCD_Init(); // Init MFRC522
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }
}

void loop() {
   if (flag == 0) {
    configured = '*';
    Serial.println(configured);
    
    Serial.flush();
    delay(5000);
    
    Serial.println(configured);
    Serial.flush();
    
    flag = 1;
    Serial.println("configurando primeira execucao");
  }
  delay(500);
  if (Serial.available() > 0) {
    Serial.readBytes(inputBuffer, Serial.available());
    if (inputBuffer[0] == 'L') { //modo leitura
      configured = 'L';
      Serial.println("L - Modo Leitura configurado Arduino");
      Serial.flush();
      memset(inputBuffer, 0, 16);
    } else if (inputBuffer[0] == 'G') { //modo gravacao
      configured = 'G';
      Serial.println("G - Modo gravacao configurado Arduino");
      Serial.flush();
      memset(inputBuffer, 0, 16);
    } else if (configured == 'G') {
      Serial.println("gravando...");
      modo_gravacao();
      configured = '*';
      delay(100);
      memset(inputBuffer, 0, 16);
    } else if (inputBuffer[0] == '*') { //reativando arduino
      flag = 0;
    }
  }
  if (configured == 'L') {
    leCartao();
  }

}

void leCartao() {
  if ( ! rfid.PICC_IsNewCardPresent()) {
    return;
  }
  if (! rfid.PICC_ReadCardSerial()) {
    Serial.println("No serial read enabled");
    return;
  }

  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&
      piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
      piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("ERRO"));
    Serial.println("ERRO ARQUINO");
    return;
  }

  byte sector         = 1;
  byte blockAddr      = 4;
  byte trailerBlock   = 7;
  MFRC522::StatusCode status;
  byte buffer[18];
  byte size = sizeof(buffer);

  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A,
                                 trailerBlock, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK)
  {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(rfid.GetStatusCodeName(status));
    return;
  }
  status = rfid.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK)
  {
    Serial.print(F("MIFARE_Read() failed: "));
    Serial.println(rfid.GetStatusCodeName(status));
  }
  String bloco1;
  for (byte i = 0; i < 10; i++)
  {
    bloco1 += char(buffer[i]);
    //Serial.print(char(buffer[i]));
  }
  //bloco1.remove(10,11);
  Serial.println('#' + bloco1);
  Serial.flush();

  configured = '*';  

  rfid.PICC_HaltA();
  // Stop encryption on PCD
  rfid.PCD_StopCrypto1();
}

void modo_gravacao() {
  int count = 0;
  while ( ! rfid.PICC_IsNewCardPresent()) {
    delay(100);
    count ++;
  }

  //id.getBytes(buffer, 11);
  if ( ! rfid.PICC_ReadCardSerial())    {
    return;
  }

  byte block;
  byte len;
  MFRC522::StatusCode status;

  block = 4;
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A,
                                 block, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("PCD_Authenticate() failed: "));
    Serial.println(rfid.GetStatusCodeName(status));
    return;
  }
  //Grava no bloco 4

  status = rfid.MIFARE_Write(block, inputBuffer, 16);
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("MIFARE_Write() failed: "));
    Serial.println(rfid.GetStatusCodeName(status));
    return;
  }
  confirmarGravacao();
  rfid.PICC_HaltA(); // Halt PICC
  rfid.PCD_StopCrypto1();  // Stop encryption on PCD
  delay(1000);
}

void confirmarGravacao() {
  byte blockAddr      = 4;
  byte status;
  byte buffer[18];
  byte size = sizeof(buffer);

  status = rfid.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK)
  {
    //Serial.print(F("MIFARE_Read() failed: "));
    //Serial.println(rfid.GetStatusCodeName(status));
  }
  String bloco1;
  for (byte i = 0; i < 16; i++)
  {
    bloco1 += char(buffer[i]);
  }
  Serial.println('#' + bloco1);
  Serial.flush();
}

