/*************************************************************************** * * * PetPass - Animal RFID Reader * * * * Copyright (C) 2015 GizmoLab.co.za ` * * * *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * *************************************************************************** * * Revision History * * Date What * 20150819 Rev0 * 20150907 Rev0a added mute and clear button ***************************************************************************/ #include "TimerOne.h" #include "Wire.h" #include "LiquidCrystal_I2C.h" #include LiquidCrystal_I2C lcd(0x27,16,2); //add, 16x2 lcd int inEMPin = 6; // sensing digital pin 7 #define maxASKBuf 300 //reduce to 100 or so for debugging #define debug 0 // 0=disabled, 1= loq debug printing, 2 = high debug mode //char rawFSK[maxFSKBuf]; //unsigned int final[65]; unsigned long CountryCode = 0; unsigned long CardNumber = 0; unsigned long CardNumberMSB = 0; int FDX_detected = 0; int errorbit = 0; int MuteState = 0; int ClearButtonState = 0; #define ValidRelay 2 //green #define ValidLED 12 //green #define ReadyLED 11 //red #define ClearPin 3 //push-button consider internal pullup and then default to 1 not 0 void setup() { Serial.begin(9600); Timer1.initialize(8); // initialize timer1, and set the frequency; this drives both the LC tank as well as the pulse timing clock // note: modify this as needed to achieve resonance and good match with the desired tags // the argument value is in microseconds per RF cycle, so 8us will yield RF of 125kHz, 7us --> 143kHz, etc. Timer1.pwm(9, 512); // setup pwm on pin 9, 50% duty cycle pinMode(inEMPin, INPUT); // sets the digital pin 6 as input to sense receiver input signal pinMode(ReadyLED, OUTPUT); pinMode(ValidLED, OUTPUT); pinMode(ValidRelay, OUTPUT); pinMode(ClearPin, INPUT_PULLUP); // use internal pull up, no button press = 1, 0 when button pressed digitalWrite(ReadyLED, 1); digitalWrite(ValidLED, 0); digitalWrite(ValidRelay, 0); // detect current state of clear button, if pressed whie startup, toggle the mute state in eeprom ClearButtonState = digitalRead(ClearPin); // 1= no press,01 = press //Read current mute state from eeprom if (EEPROM.read(0) == 1) {MuteState = 1;} // 1 = not mute else {MuteState = 0;} // 0 = mute //Clear button press detected = Toggle mute state and update eeprom if clear button pressed if (ClearButtonState == 0) { if (MuteState == 1) {MuteState = 0;} else if (MuteState == 0) {MuteState = 1;} EEPROM.write(0,MuteState); ClearButtonState = 1; } lcd.init(); // initialize the lcd lcd.backlight(); lcd.setCursor(0,0); //lcd.print("Reader Ready!"); if (MuteState == 1) {lcd.print("Reader Ready! ");} else {lcd.print("Reader Ready! M");} if(debug >= 1) { Serial.print("Reader Started."); } } void loop() { int loop; FDX_detected = 0; CountryCode = 0; CardNumber = 0; // if(debug >= 0){ Serial.print("\nready..."); } // Wait for card to be detected while (digitalRead(inEMPin) == 0) {} // Wait for Initial high state loop = 0; while (loop <= 3) { FDX_detected = 0; read_fdx(); if (FDX_detected == 1) {break;} loop = loop + 1; } // Control_Valid(500); if (FDX_detected == 1) { lcd.clear(); lcd.setCursor(0,0); lcd.print("FDX-B Detected"); lcd.setCursor(0,1); LeadingZeros(CountryCode, 3); lcd.print((unsigned long)CountryCode); lcd.print("-"); LeadingZeros(CardNumber, 12); lcd.print((unsigned long)CardNumber); Control_Valid(2000); // Wait for rest button to be pressed while (digitalRead(ClearPin) == 1) {} // Wait for Initial high state lcd.clear(); lcd.setCursor(0,0); if (MuteState == 1) {lcd.print("Reader Ready! ");} else {lcd.print("Reader Ready! M");} ClearButtonState = 1; //lcd.clear(); //lcd.setCursor(0,0); //if (MuteState == 1) { lcd.print("Reader Ready! M");} //else if (MuteState == 0) { lcd.print("Reader Ready! ");} //lcd.setCursor(0,1); } } //----------------------------------------------------------------------- void LeadingZeros(unsigned long Value, int Digits) { if (Digits == 3){ if ((Value > 0) && (Value <= 9)) { lcd.print("00");} else if ((Value > 9) && (Value <= 99)) { lcd.print("0");} else if ((Value > 99) && (Value <= 999)){ lcd.print("");} else {} } if (Digits == 12){ if ((Value > 0) && (Value <= 9)) { lcd.print("0000000000");} else if ((Value > 9) && (Value <= 99)) { lcd.print("000000000");} else if ((Value > 99) && (Value <= 999)){ lcd.print("00000000");} else if ((Value > 999) && (Value <= 9999)){ lcd.print("0000000");} else if ((Value > 99999) && (Value <= 999999)){ lcd.print("000000");} else if ((Value > 999999) && (Value <= 9999999)){ lcd.print("00000");} else if ((Value > 9999999) && (Value <= 99999999)){ lcd.print("0000");} else if ((Value > 99999999) && (Value <= 999999999)){ lcd.print("000");} else if ((Value > 999999999) && (Value <= 9999999999)){ lcd.print("00");} else if ((Value > 9999999999) && (Value <= 99999999999)){ lcd.print("0");} else if ((Value > 99999999999) && (Value <= 999999999999)){ lcd.print("");} else if ((Value > 999999999999) && (Value <= 9999999999999)){ lcd.print("");} else {} } } // Read and convert ASK signal void read_fdx (void) { // first convert pulse durations into raw bits unsigned long HighTimer = 0; unsigned long LowTimer = 0; byte rawASK[maxASKBuf]; byte multibit[maxASKBuf]; // byte crcarray[64]; unsigned long singlebit[150]; //128 needed errorbit = 0; CountryCode = 0; CardNumber = 0; int i = 0; int ii = 0; unsigned int bitcounter = 0; int Hindex = 0; // Serial.print("\nwaiting"); // Start - capture new data set while (digitalRead(inEMPin) == 0) {} // Wait for Initial high state digitalWrite(ReadyLED, 0); // Serial.print("\nCapture Starts"); while (i < maxASKBuf -2) { while (digitalRead(inEMPin) == 1) { HighTimer++;} // increment timer while input pin is high rawASK[i] = HighTimer; HighTimer = 0; i++; while (digitalRead(inEMPin) == 0) { LowTimer++;} // increment timer while input pin is low rawASK[i] = LowTimer; LowTimer = 0; i++; } // Serial.print("\nCapture Ends "); if(debug >= 1) { Serial.print("\nHigh Low (starts with high: "); for(int i = 0; i < maxASKBuf-2; i++) { Serial.print((unsigned int)rawASK[i]); Serial.print("/"); } } // Completed - capture new data set // biphase decode timer values ii = 0; bitcounter = 0; while (ii < maxASKBuf -4) { errorbit = 0; Hindex = ii; if ((rawASK[Hindex] <= 10) || (rawASK[Hindex] >= 100)){ //<=10 to >= 100 multibit[bitcounter] = 9; } else if (rawASK[Hindex] >= 32) { // >=40 multibit[bitcounter] = 1; } else if ( (rawASK[Hindex] <= 35) && (rawASK[Hindex+1] <= 31) ){ // <=30 and <=30 multibit[bitcounter] = 0; ii = ii + 1; } else {multibit[bitcounter] = 9;} bitcounter = bitcounter + 1; ii = ii + 1; } //Completed Covert HighTimer into ones and LowTimer into zeros if(debug >= 1) { Serial.print("\nbits: "); Serial.print((unsigned int)bitcounter); Serial.print(" Multibit: "); for(int i = 0; i < bitcounter-1; i++) { Serial.print((unsigned int)multibit[i]); } } // search for 11bit start header "0000 0000 00 1" int samecnt = 0; int start = -1; int lastv = 0; for(int i = 0; i < bitcounter-1; i++) { if(multibit[i] == lastv) { // inside one same bit pattern, keep scanning samecnt++; } else { // got new bit pattern if(samecnt >= 10 && lastv == 0) { // got a start tag prefix, record index and exit //if (multibit[i+1] == 1) { start = i+1; break; //} } // either group of 0s, or fewer than 15 1s, so not a valid tag, keep scanning samecnt = 1; lastv = multibit[i]; } } if(debug >= 1) { Serial.print("\nStart: "); Serial.print((int)start); } // if a valid prefix tag was found, process the buffer // Serial.print("\nsingle : "); if(start >= 0 && start <= ( bitcounter - 55)) { //adjust to allow room for full dataset past start point int count1 = 0; for(int i = start; i <= start+127; i++) { singlebit[count1] = (unsigned long)multibit[i]; if (singlebit[count1] >= 2) {errorbit = errorbit + 1;} count1 = count1+1; } //first 38 bits is id // 1101 1000 1 0001 1101 1 1110 1000 1 0000 0000 1 0000 00 10 1 0011 0111 1 00000000 1 00000001 1 1100 1110 1 0100 1000 1 00000000100000000100000000100000000001 // 8 17 26 35 41 // Serial.print("\nbits: "); // Serial.print((unsigned int)count1); if(debug >= 1) { Serial.print("\nValid "); for(int i =0; i <= 127; i++) { Serial.print(singlebit[i]); } } for(int i = 0, k = 0; i < 8; i++, k++) { CardNumber |= singlebit[i] << k; //crcarray[i] = singlebit[i]; } for(int i = 9, k = 8; i < 17; i++, k++) { CardNumber |= singlebit[i] << k; //crcarray[i-1] = singlebit[i]; } for(int i = 18, k = 16; i < 26; i++, k++) { CardNumber |= singlebit[i] << k; //crcarray[i-2] = singlebit[i]; } for(int i = 27, k = 24; i < 35; i++, k++) { CardNumber |= singlebit[i] << k; //crcarray[i-3] = singlebit[i]; } for(int i = 36, k = 0; i < 42; i++, k++) { CardNumberMSB |= singlebit[i] << k; //crcarray[i-4] = singlebit[i]; } for(int i = 42, k = 0; i < 44; i++, k++) { CountryCode |= singlebit[i] << k; //crcarray[i-4] = singlebit[i]; } for(int i = 45, k = 2; i < 53; i++, k++) { CountryCode |= singlebit[i] << k; //crcarray[i-5] = singlebit[i]; } //----------------- /* for(int i = 54, k = 0; i < 62; i++, k++) { crcarray[i-6] = singlebit[i]; } for(int i = 63, k = 0; i < 71; i++, k++) { crcarray[i-7] = singlebit[i]; } unsigned long crcValue = 0; unsigned int crcCalc = 0; for(int i = 72, k = 0; i < 80; i++, k++) { crcValue |= singlebit[i] << k; } for(int i = 81, k = 8; i < 89; i++, k++) { crcValue |= singlebit[i] << k; } */ // crcCalc = calc_crc(crcarray,63); //Calculate CRC on-the-fly // Serial.print("\ndone detected\n"); } else { // Serial.print("\ninvalid"); errorbit = errorbit +1;} if ((CountryCode > 1) && (CardNumber > 1) && (errorbit == 0)) { FDX_detected = 1; if(debug >= 1) { Serial.print("\nCC: "); Serial.print((unsigned long) CountryCode); Serial.print("-"); Serial.print((unsigned long) CardNumber); } } else {FDX_detected == 0;} digitalWrite(ReadyLED, 1); } void Control_Valid(int duration){ int duration1 = 0; int duration2 = 0; duration1 = duration/4; duration2 = duration - duration1; digitalWrite(ReadyLED, 0); digitalWrite(ValidLED, 1); digitalWrite(ValidRelay, MuteState); delay(duration1); //typical is 2000 for 2sec digitalWrite(ValidRelay, 0); delay(duration2); //typical is 2000 for 2sec digitalWrite(ReadyLED, 1); digitalWrite(ValidLED, 0); digitalWrite(ValidRelay, 0); }