/*************************************************************************** * * * MultiPass - Univfersal RFID Reader * * * * Copyright (C) 2015 GizmoLab.co.za ` * * * *************************************************************************** * * * This source code is free for non-commercial use only. It or parts of it * * may not be used in any commercial application without written * * authorization from the authror * * * *************************************************************************** *************************************************************************** * * Revision History * * Date What * 20150731 Rev0 * ***************************************************************************/ #include "TimerOne.h" #include "Wire.h" #include "LiquidCrystal_I2C.h" LiquidCrystal_I2C lcd(0x27,16,2); //add, 16x2 lcd int ledPin = 13; // LED connected to digital pin 13 int inEMPin = 6; // sensing digital pin 7 int inHIDPin = 7; // sensing digital pin 7 #define maxHIDBuf 1000 //reduce to 100 or so for debugging #define maxEMBuf 200 //reduce to 100 or so for debugging #define debug 0 // 0=disabled, 1= loq debug printing, 2 = high debug mode int LCDdebug = 0; // LCD debub mode, used with push button debugpin int debugPin = 2; //char rawHID[maxHIDBuf]; unsigned int final[65]; unsigned long CountryCode = 0; unsigned long ManufacturerCode = 0; unsigned long FacilityCode = 0; unsigned long CardNumber = 0; unsigned long RawNumber = 0; int debugvalue = 0; int HID_detected = 0; int EM_detected = 0; int errorbit = 0; #define ValidRelay 12 //green #define ValidLED 12 //green #define ReadyLED 11 //red void setup() { lcd.init(); // initialize the lcd lcd.backlight(); lcd.setCursor(0,0); lcd.print("Reader 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(ledPin, OUTPUT); // sets the digital pin 13 as output for scope monitoring pinMode(inEMPin, INPUT); // sets the digital pin 6 as input to sense receiver input signal pinMode(inHIDPin, INPUT); // sets the digital pin 7 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; HID_detected = 0; EM_detected = 0; CountryCode = 0; ManufacturerCode = 0; FacilityCode = 0; CardNumber = 0; RawNumber = 0; if(debug >= 1){ Serial.print("\nready..."); } // Wait for card to be detected while (digitalRead(inEMPin) == 0) {} // Wait for Initial high state // read EM cards, MUST be done before HID, to prevent false HID reads if (HID_detected == 0) { loop = 0; while (loop <= 3) { HID_detected = 0; EM_detected = 0; read_EM(); if (EM_detected == 1) {break;} loop = loop + 1; } } // Read HID cards, MUST be done after EM, to prevent false HID reads if (EM_detected == 0) { loop = 0; while (loop <= 3) { HID_detected = 0; EM_detected = 0; read_HID(); if (HID_detected == 1) {break;} loop = loop + 1; } } if ((EM_detected == 1) || (HID_detected == 1)) { if(debug >= 1) { Serial.print("\nEM: Manufacturer: "); Serial.print((unsigned long) ManufacturerCode); Serial.print("\nFacility Code: "); Serial.print((unsigned long) FacilityCode); Serial.print("\nCard: "); Serial.print((unsigned long) CardNumber); } lcd.clear(); lcd.setCursor(0,0); if(debug >= 1) { lcd.print((int)debugvalue); lcd.print("-"); lcd.print((int)HID_detected); lcd.print("-"); lcd.print((int)EM_detected); lcd.print(".."); } if(LCDdebug == 0) { if (HID_detected == 1) { lcd.print("HID");} else if (EM_detected == 1) { lcd.print("EM");} else { lcd.print("??");} lcd.print(": "); lcd.print((unsigned long)ManufacturerCode); lcd.print(" "); lcd.print((unsigned long)RawNumber); lcd.setCursor(0,1); lcd.print((unsigned long)FacilityCode); lcd.print("-"); lcd.print((unsigned long)CardNumber); Control_Valid(2000); lcd.clear(); lcd.setCursor(0,0); lcd.print("Reader Ready!"); lcd.setCursor(0,1); } } else { } EM_detected = 0; HID_detected = 0; } // Read and convert HID signal void read_HID(void) { char rawHID[maxHIDBuf]; int index = 0; long freq = 0; errorbit = 0; HID_detected = 0; // Measure 1000 pulse lengths while (index <= maxHIDBuf) { freq = pulseIn(inHIDPin, HIGH); rawHID[index++] = freq; } if(debug == 2) { for(int i = 0; i < maxHIDBuf -1; i++) { Serial.print((int)rawHID[i]); Serial.print("/"); } Serial.println("///raw data"); delay(200); } // process this buffer if (errorbit <= 10) { for(int i = 1; i < maxHIDBuf; i++) { int v = rawHID[i]; if(v >= 20 && v <= 38) { rawHID[i] = 0; } else if(v >= 40 && v <= 59) { rawHID[i] = 1; } else if(v >= 62 && v <= 68) { rawHID[i] = 0; rawHID[i++] = 0; } else if(v >= 15 && v <= 19) { rawHID[i] = rawHID[i - 1]; errorbit++; } else { rawHID[i] = 9; // error code errorbit++; } } // next, search for a "start tag" of 15 high bits in a row int samecnt = 0; int start = -1; int lastv = 0; for(int i = 0; i < maxHIDBuf; i++) { if(rawHID[i] == lastv) { // inside one same bit pattern, keep scanning samecnt++; } else { // got new bit pattern if(samecnt >= 15 && lastv == 1) { // got a start tag prefix, record index and exit start = i; break; } // either group of 0s, or fewer than 15 1s, so not a valid tag, keep scanning samecnt = 1; lastv = rawHID[i]; } } // if a valid prefix tag was found, process the buffer if(start > 0 && start < (maxHIDBuf - 5*90)) { //adjust to allow room for full dataset past start point // process_FSKBuf(start); int lastv = 0; int samecnt = 0; char manch[91]; int manchindex = 0; int HIDtype = 9; if(debug >= 1) { Serial.println("got a valid prefix, processing data buffer..."); } for(int i = start + 1; i < maxHIDBuf && manchindex < 90; i++) { if(rawHID[i] == lastv) { samecnt++; } else { // got a new bit value, process the last group if(samecnt >= 3 && samecnt <= 8) { manch[manchindex++] = lastv; } else if(samecnt >= 9 && samecnt <= 14) { // assume a double bit, so record as two separate bits manch[manchindex++] = lastv; manch[manchindex++] = lastv; } else if(samecnt >= 15 && lastv == 0) { if(debug >= 1) { Serial.println("got end tag"); } // got an end tag, exit break; } else { // last bit group was either too long or too short if(debug >= 1) { Serial.print("****got bad bit pattern in buffer, count: "); Serial.print(samecnt); Serial.print(", value: "); Serial.println(lastv); } //err_flash(3); //return; } samecnt = 1; lastv = rawHID[i]; } //new bit pattern } if(debug == 2) { Serial.print("\nSingle bit string before mach decode: "); for(int i = 0; i < manchindex; i++) { Serial.print((int)manch[i]); Serial.print("/"); } delay(200); Serial.print("Single bit string length: "); Serial.print(manchindex); } if ( manchindex <= 88) {return;} if (manchindex == 89){ manchindex++; if (manch[manchindex-1] == 0){ manch[manchindex] = 1; } if (manch[manchindex-1] == 1){ manch[manchindex] = 0; } } if(debug == 2) { Serial.print("\nSingle bit string before mach decode: "); for(int i = 0; i < manchindex; i++) { Serial.print((int)manch[i]); Serial.print("/"); } delay(200); Serial.print("Single bit string length: "); Serial.print(manchindex); } if(debug >= 1) { Serial.println("converting manchester code to binary..."); } // got manchester version, convert to final bits for(int i = 0, findex = 0; i < 88; i += 2, findex++) { if(manch[i] == 1 && manch[i+1] == 0) { final[findex] = 1; } else if(manch[i] == 0 && manch[i+1] == 1) { final[findex] = 0; } else { // invalid manchester code, exit if(debug >= 1) { Serial.println("****got invalid manchester code"); } //err_flash(3); //return; } } } else { if(debug >= 1) { Serial.println("no valid data found in buffer"); } } if(debug == 2) { for(int i = 0; i < maxHIDBuf; i++) { Serial.print((int)rawHID[i]); Serial.print("/"); } } if(debug >= 1) { Serial.print("///\nbuffer stats: zeroes:"); Serial.print("/errs:"); Serial.println(errorbit); delay(1000); } } // end of conversion int hid; hid = 99; HID_detected = 0; hid = Decode_HID(); if (hid <= 50) {HID_detected = 1;} } int Decode_HID() { // Determine if 26 or 35bit HID int HIDtype26 = 0; int HIDtype35 = 0; int HIDtype = 88; for(int i = 1, k = 17; i < 1+18; i++, k--) { HIDtype26 |= (int)final[i] << k; } for(int i = 1, k = 8; i < 1+9; i++, k--) { HIDtype35 |= (int)final[i] << k; } if (HIDtype26 == 2049){ HIDtype = 26; ManufacturerCode = 2049; } else if (HIDtype35 == 4){ HIDtype = 35; ManufacturerCode = 4; } else { HIDtype = 99; ManufacturerCode = 9999; } int par = 0; RawNumber = 0; FacilityCode = 0; CardNumber = 0; if (HIDtype == 26){ // convert bits 28 thru 28+16 into a 16 bit integer for(int i = 28, k = 15; i < 28+16; i++, k--) { CardNumber |= (int)final[i] << k; } int paritybit = final[28+16]; for(int i = 0; i < 45; i++) { par ^= final[i]; } // convert bits 20 thru 20+8 into a 16 bit integer for(int i = 20, k = 7; i < 20+8; i++, k--) { FacilityCode |= (int)final[i] << k; } } else if (HIDtype == 35){ // convert bits 28 thru 28+16 into a 16 bit integer for(int i = 24, k = 19; i < 24+20; i++, k--) { CardNumber |= (int)final[i] << k; } int paritybit = final[28+16]; for(int i = 0; i < 45; i++) { par ^= final[i]; } // convert bits 20 thru 20+8 into a 16 bit integer for(int i = 12, k = 11; i < 12+12; i++, k--) { FacilityCode |= (int)final[i] << k; } } if ((HIDtype == 26)||(HIDtype == 35)){ RawNumber = FacilityCode; RawNumber = (RawNumber << 16) | CardNumber; } return HIDtype; } // --------------------------------------------------------------------------------- // Read and convert EM signal void read_EM (void) { // first convert pulse durations into raw bits unsigned int HighTimer = 0; unsigned int LowTimer = 0; unsigned int rawEM[maxEMBuf]; unsigned int multibit[maxEMBuf]; unsigned int singlebit[maxEMBuf]; unsigned int bitcounter = 0; int i = 0; int ii = 0; int iii = 0; int bit1 = 0; int bit2 = 0; int singlebitcounter = 0; int Hindex = 0; int Lindex = 0; RawNumber = 0; FacilityCode = 0; CardNumber = 0; //Serial.print("\nCapture Starts"); while (i < maxEMBuf -2) { while (digitalRead(inEMPin) == 1) { HighTimer++;} // increment timer while input pin is high rawEM[i] = HighTimer; HighTimer = 0; i++; while (digitalRead(inEMPin) == 0) { LowTimer++;} // increment timer while input pin is low rawEM[i] = LowTimer; LowTimer = 0; i++; } //Serial.print("\nCapture Ends "); if(debug >= 1) { Serial.print("\nHigh Low (starts with high): "); for(int i = 0; i <= maxEMBuf-2; i++) { Serial.print((unsigned int)rawEM[i]); Serial.print("/"); } } // Completed - captured data set // Convert HighTimer into ones and LowTimer into zeros errorbit = 0; while (ii < maxEMBuf -2) { errorbit = 0; Hindex = ii; Lindex = ii + 1; //convert zoro, 2nd, 4th.. into ones, can be single or double bits, depending on length if (rawEM[Hindex] < 80) { multibit[bitcounter] = 1; } if (rawEM[Hindex] >= 80) { multibit[bitcounter] = 1; bitcounter = bitcounter + 1; multibit[bitcounter] = 1; } //convert 1st, 3rd, 5th.. into zeros, can be single or double bits, dfepending on length bitcounter = bitcounter + 1; if (rawEM[Lindex] < 80) { multibit[bitcounter] = 0; } if (rawEM[Lindex] >= 80) { multibit[bitcounter] = 0; bitcounter = bitcounter + 1; multibit[bitcounter] = 0; } bitcounter = bitcounter + 1; ii = ii + 2; } //Completed Covert HighTimer into ones and LowTimer into zeros if(debug >= 2) { Serial.print("\nMultibit: "); for(int i = 0; i <= bitcounter; i++) { Serial.print((unsigned int)multibit[i]); } } // Start - covert multibit into single bit number while (iii < bitcounter -2 ) { bit1 = iii; bit2 = iii + 1; if ((multibit[bit1] == 1) && (multibit[bit2] == 0)){ singlebit[singlebitcounter] = 1; } else if ((multibit[bit1] == 0) && (multibit[bit2] == 1)){ singlebit[singlebitcounter] = 0; } else { singlebit[singlebitcounter] = 9; } if (singlebitcounter >= maxEMBuf -4) {break;} singlebitcounter = singlebitcounter + 1; iii = iii+2; } if(debug >= 2) { Serial.print("\nSinglebit: "); for(int i = 0; i <= singlebitcounter; i++) { Serial.print((unsigned int)singlebit[i]); } } //completed - multibit to singlebit conversion // start - EM4100 conversion 65 bits with start header int lastv = 0; int samecnt = 0; int start = 0; for(int i = 0; i <= singlebitcounter; i++) { if(singlebit[i] == lastv) { // inside one same bit pattern, keep scanning samecnt++; } else { // got new bit pattern if(samecnt >= 9 && lastv == 1) { // got a start tag prefix, record index and exit start = i; if (start + 55 < singlebitcounter) { break; } } samecnt = 1; lastv = singlebit[i]; } } for(int i = 0; i < 55; i++) { final[i] = singlebit[start+i]; if (final[i] > 1) {errorbit = 1;} } if(debug >= 1) { if (errorbit >= 1) { Serial.print("\ndetected card: INVALID");} if (errorbit == 0) { Serial.print("\ndetected card: VALID\n");} Serial.print((unsigned int)singlebitcounter); Serial.print(" -Detected card: "); for(int i = 0; i < 55; i++) { Serial.print((unsigned int)final[i]);} } // start to decode number EM_detected = 0; if (errorbit == 0){ EM_detected = Decode_EM4100(); if (RawNumber > 999999999) {EM_detected = 0;} else if (RawNumber <= 10) {EM_detected = 0;} } // completed decoding // end of read_EM function } int Decode_EM4100(){ // 0000p0000p 0000p0000p0000p0000p0000p0000p0000p0000p ppppp //0001111101000000000001010111101011110100001100000001110 //00011110 00000000 01011111 10111010 00110000 0011 10 ManufacturerCode = 0; FacilityCode = 0; CardNumber = 0; RawNumber = 0; int byte1 = 0; int byte2 = 0; int byte3 = 0; int byte4 = 0; int byte5 = 0; int byte6 = 0; int byte7 = 0; int byte8 = 0; int byte9 = 0; int byte10 = 0; for(int i = 0, k = 3; i < 4; i++, k--) { byte1 |= (int)final[i] << k; } for(int i = 5, k = 3; i < 9; i++, k--) { byte2 |= (int)final[i] << k; } for(int i = 10, k = 3; i < 14; i++, k--) { byte3 |= (int)final[i] << k; } for(int i = 15, k = 3; i < 19; i++, k--) { byte4 |= (int)final[i] << k; } for(int i = 20, k = 3; i < 24; i++, k--) { byte5 |= (int)final[i] << k; } for(int i = 25, k = 3; i < 29; i++, k--) { byte6 |= (int)final[i] << k; } for(int i = 30, k = 3; i < 34; i++, k--) { byte7 |= (int)final[i] << k; } for(int i = 35, k = 3; i < 39; i++, k--) { byte8 |= (int)final[i] << k; } for(int i = 40, k = 3; i < 44; i++, k--) { byte9 |= (int)final[i] << k; } for(int i = 45, k = 3; i < 49; i++, k--) { byte10 |= (int)final[i] << k; } ManufacturerCode = 0; RawNumber = 0; FacilityCode = 0; CardNumber = 0; ManufacturerCode = (byte1 << 4) | byte2; RawNumber = (RawNumber << 4) | byte3; RawNumber = (RawNumber << 4) | byte4; RawNumber = (RawNumber << 4) | byte5; RawNumber = (RawNumber << 4) | byte6; RawNumber = (RawNumber << 4) | byte7; RawNumber = (RawNumber << 4) | byte8; RawNumber = (RawNumber << 4) | byte9; RawNumber = (RawNumber << 4) | byte10; FacilityCode = (FacilityCode << 4) | byte3; FacilityCode = (FacilityCode << 4) | byte4; FacilityCode = (FacilityCode << 4) | byte5; FacilityCode = (FacilityCode << 4) | byte6; CardNumber = (CardNumber << 4) | byte7; CardNumber = (CardNumber << 4) | byte8; CardNumber = (CardNumber << 4) | byte9; CardNumber = (CardNumber << 4) | byte10; /* Serial.print("\nbyte1: "); Serial.print((unsigned int) byte1); Serial.print(" byte2: "); Serial.print((unsigned int) byte2); Serial.print("\nbyte3: "); Serial.print((unsigned int) byte3); Serial.print(" byte4: "); Serial.print((unsigned int) byte4); Serial.print(" byte5: "); Serial.print((unsigned int) byte5); Serial.print(" byte6: "); Serial.print((unsigned int) byte6); Serial.print(" byte7: "); Serial.print((unsigned int) byte7); Serial.print(" byte8: "); Serial.print((unsigned int) byte8); Serial.print(" byte9: "); Serial.print((unsigned int) byte9); */ return 1; } //----------------------------------------------------------------------- void Control_Valid(int duration){ digitalWrite(ReadyLED, 0); digitalWrite(ValidLED, 1); digitalWrite(ValidRelay, 1); delay(duration); //typical is 2000 for 2sec digitalWrite(ReadyLED, 1); digitalWrite(ValidLED, 0); digitalWrite(ValidRelay, 0); }