#include "TimerOne.h" #include "Wire.h" #include "LiquidCrystal_I2C.h" 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; #define ValidRelay 2 //green #define ValidLED 12 //green #define ReadyLED 11 //red void setup() { lcd.init(); // initialize the lcd lcd.backlight(); lcd.setCursor(0,0); lcd.print("FDX Ready!"); 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); digitalWrite(ReadyLED, 1); digitalWrite(ValidLED, 0); digitalWrite(ValidRelay, 0); 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"); 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); lcd.clear(); lcd.setCursor(0,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, 1); 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); }