Magnetic Stripe Card Reader!

Below we have a magnetic card reader made at the HACKMIAMI labs. It reads track 2 found on most magnetic striped cards (i.e. credit cards, drivers licenses, and student ids). Something interesting to point out, while testing the equipment with an old student ID card from a local university we found out it holds the person’s social security number on the card. The SSN use to be the student ID number. I wouldn’t be surprised if other universities did the same. The magnetic card reader was made using a Sanguino (a beefy Arduino clone), an LCD found on SparkFun, and magnetic card reader from All Electronics.

Magnetic Card Reader

Things to Keep in Mind

The +5V and ground is provided by the sanguino. The LEDs are just for DEBUGGING and are not necessary. The LCD4Bit.h file used is modified so ports 18 – 23 on the sanguino are used for the LCD. You can download the LCD4bit here. An arduino or most other clones can be used for this project.

Schematic

Code

/*
 *   MAGNETIC STRIPE CARD READER with LCD ver. 0.2
 *   BY JP! ... email: jp @ hackmiami [dot] org
 *              web: http://www.hackmiami.org/
 *
 *   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 3 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.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see .
 *
 */
 
#include ;
 
LCD4Bit lcd = LCD4Bit(2);
int incomingByte = 0;
int charMax = 16;
int charCount = 0;
char ch[] = "                ";
 
boolean printToLCD = false;
 
int DATA = 1, CLOCK = 11, CARD_IN = 2, ENDSTOP = 10;
volatile int state = LOW;
 
int buf[255];
char actual_buf[255];
 
int i = 0;
 
void setup() {
 
  Serial.begin(9600);
 
  lcd.init(); //initialize the LCD
 
  // SET PINS AS INPUT
  pinMode(CARD_IN, INPUT);
  pinMode(CLOCK, INPUT);
  pinMode(DATA, INPUT);
  pinMode(ENDSTOP, INPUT);
 
  // SET PINS AS OUTPUT
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(0, OUTPUT);
 
  attachInterrupt(2, stateToHigh, FALLING); // Wait for card to start being pulled out, interupt 0 is digital pin 10
  attachInterrupt(0, stateToLow, FALLING); // Wait for card to be completely out, interupt 2 is digital pin 2
 
  Serial.println("Ready... ");
  lcd.printIn("Ready...");
}
 
void loop() {
 
  digitalWrite(7, digitalRead(ENDSTOP)); // ENDSTOP LED for debugging
  digitalWrite(6, digitalRead(CARD_IN)); // CARD_IN LED for debugging
 
  // IF YOU HAVE SOMETHING TO PRINT TO LCD, PRINT IT
  if (printToLCD) {
     lcd.clear();
 
     int j = 1;
     while(actual_buf[j] != '=' && j <= 16) {
        lcd.print(actual_buf[j]);
        j++;
     }
     lcd.commandWrite(0xC0);
     lcd.printIn("HACKMIAMI.ORG");
 
     printToLCD = false;
  }
 
}
 
// MAKE STATE GO HIGH AND START COLLECTING DATA
void stateToHigh() {
  digitalWrite(0, HIGH);
  state = HIGH;
  Serial.print("STATE: HIGH\n");
 
  // The data is synced to a clock. So everytime the clock rises there is data to be collected.
  attachInterrupt(1, getData, RISING); // interupt 1 is digital pin 11
}
 
// SET STATE TO LOW, no longer need to collect data so detach interrupt
void stateToLow() {
 
  detachInterrupt(1);
 
  Serial.print("\nSTATE: LOW\n");
 
  state = LOW;
  digitalWrite(0, LOW);
 
  Serial.print("\n");
  complement();
//  reverse();
  readBuf();
  Serial.print("\n");
 
  i = 0;
 
}
 
// DECODE WHAT IS WRITTEN ON THE CARD
void readBuf() {
 
  char values[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                   '8', '9', ':', ';', '<', '=', '>', '?'};
 
  int index = 0, val, k = 0, binbuf = 0, parity = 0, parity_error = false;
 
  Serial.print("RAW: ");
 
  for (int j = 0; j < i; j++) {
     Serial.print(buf[j]);
  }
 
  Serial.print("\n\n");
 
  // FIND START SENTINEL
  for (int j = 0; j < i - 5; j++) {
    if (buf[j] == 1 && buf[j + 1] == 1 && buf[j + 2] == 0 && buf[j + 3] == 1 && buf[j + 4] == 0) {
      k = j;
      break;
    }
  }
 
  int p = 0;
  for (int j = k; j < i; j++) {
 
    if ((j - k) % 5 == 4) {
 
      actual_buf[p] = values[binbuf];
      binbuf = 0;
 
      if ((parity % 2) == buf[j]) {
        parity_error = true;
      }
 
      parity = 0;
      p++;
    }
    else {
      binbuf += buf[j] * (int) ceil(pow(2, (j - k) % 5));
      parity += buf[j];
    }
 
  }
 
  for (int j = 0; j < p; j++) {
     Serial.print(actual_buf[j]);
  }
 
  Serial.print("\n");
  printToLCD = true;
 
  if (parity_error) {
    Serial.print("\nPARITY ERROR!");
  }
}
 
// GET DATA AND ADD TO BUFFER
void getData() {
  buf[i] = digitalRead(DATA);
  i++;
}
 
// FLIP THE ORDER IN WHICH THE DATA WAS READ
void reverse() {
  int buff[255];
  int c = 0;
  for (int j = i - 1; j >= 0; j--) {
    buff[c] = buf[j];
    c++;
  }
 
  for (int j = 0; j < i; j++) {
     buf[j] = buff[j];
  }
 
}
// INVERT THE 1's TO 0's AND VICE VERSA
void complement() {
   for (int j = 0; j < i; j++) {
      (buf[j] == 1) ? buf[j] = 0 : buf[j] = 1;
   }
}

21 Comments

  1. Ashish Anand says:

    Hey,

    I’m using your GPL code for an article in a hacking magazine. Hope its okay!

  2. jp says:

    Go right ahead! Just mention HackMiami in the magazine as well. Let me know when it is published.

  3. benc says:

    Hello,

    Thanks for this great tutorial!
    I am interesting in making a personnal card-reader but I don’t find any MR read head. Does anybody know where I can buy it?
    Thanks

  4. jp says:

    I bought the magnetic card reader at allelectronics.com for $4 american. It’s the best price I’ve found.

  5. rad says:

    I tried to modif the code for the Arduino Diecimila and using an Omron reader and all I get as a read are characters. here is the code below. Thanks for help

    ==============================================================================
    /*
    * MAGNETIC STRIPE CARD READER with LCD ver. 0.2
    * BY JP! … email: jp @ hackmiami [dot] org
    * web: http://www.hackmiami.org/
    *
    * 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 3 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.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program. If not, see .
    *
    */

    /*#include ;

    LCD4Bit lcd = LCD4Bit(2);
    int incomingByte = 0;
    int charMax = 16;
    int charCount = 0;
    char ch[] = ” “;

    boolean printToLCD = false;
    */

    int DATA =3, CLOCK = 11, CARD_IN = 2;
    volatile int state = LOW;

    int buf[255];
    char actual_buf[255];

    int i = 0;

    void setup() {

    Serial.begin(9600);

    //lcd.init(); //initialize the LCD

    // SET PINS AS INPUT
    pinMode(CARD_IN, INPUT);
    pinMode(CLOCK, INPUT);
    pinMode(DATA, INPUT);
    //pinMode(ENDSTOP, INPUT);

    // SET PINS AS OUTPUT
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(0, OUTPUT);

    attachInterrupt(1, stateToHigh, FALLING); // Wait for card to start being pulled out, interupt 0 is digital pin 10
    attachInterrupt(0, stateToLow, FALLING); // Wait for card to be completely out, interupt 2 is digital pin 2

    Serial.println(“Ready… “);
    //lcd.printIn(“Ready…”);
    }

    void loop() {

    //digitalWrite(7, digitalRead(ENDSTOP)); // ENDSTOP LED for debugging
    //digitalWrite(6, digitalRead(CARD_IN)); // CARD_IN LED for debugging

    // IF YOU HAVE SOMETHING TO PRINT TO LCD, PRINT IT
    /* if (printToLCD) {
    lcd.clear();

    int j = 1;
    while(actual_buf[j] != ‘=’ && j <= 16) {
    lcd.print(actual_buf[j]);
    j++;
    }
    lcd.commandWrite(0xC0);
    lcd.printIn(“HACKMIAMI.ORG”);

    printToLCD = false;
    }
    */
    }

    // MAKE STATE GO HIGH AND START COLLECTING DATA
    void stateToHigh() {
    digitalWrite(3, HIGH);
    state = HIGH;
    Serial.print(“STATE: HIGH\n”);

    // The data is synced to a clock. So everytime the clock rises there is data to be collected.
    attachInterrupt(1, getData, RISING); // interupt 1 is digital pin 11
    }

    // SET STATE TO LOW, no longer need to collect data so detach interrupt
    void stateToLow() {

    detachInterrupt(1);

    Serial.print(“\nSTATE: LOW\n”);

    state = LOW;
    digitalWrite(3, LOW);

    Serial.print(“\n”);
    complement();
    // reverse();
    readBuf();
    Serial.print(“\n”);

    i = 0;

    }

    // DECODE WHAT IS WRITTEN ON THE CARD
    void readBuf() {

    char values[] = {’0′, ’1′, ’2′, ’3′, ’4′, ’5′, ’6′, ’7′,
    ’8′, ’9′, ‘:’, ‘;’, ”, ‘?’};

    int index = 0, val, k = 0, binbuf = 0, parity = 0, parity_error = false;

    Serial.print(“RAW: “);

    for (int j = 0; j < i; j++) {
    Serial.print(buf[j]);
    }

    Serial.print(“\n\n”);

    // FIND START SENTINEL
    for (int j = 0; j < i – 5; j++) {
    if (buf[j] == 1 && buf[j + 1] == 1 && buf[j + 2] == 0 && buf[j + 3] == 1 && buf[j + 4] == 0) {
    k = j;
    break;
    }
    }

    int p = 0;
    for (int j = k; j < i; j++) {

    if ((j – k) % 5 == 4) {

    actual_buf[p] = values[binbuf];
    binbuf = 0;

    if ((parity % 2) == buf[j]) {
    parity_error = true;
    }

    parity = 0;
    p++;
    }
    else {
    binbuf += buf[j] * (int) ceil(pow(2, (j – k) % 5));
    parity += buf[j];
    }

    }

    for (int j = 0; j = 0; j–) {
    buff[c] = buf[j];
    c++;
    }

    for (int j = 0; j < i; j++) {
    buf[j] = buff[j];
    }

    }
    // INVERT THE 1′s TO 0′s AND VICE VERSA
    void complement() {
    for (int j = 0; j < i; j++) {
    (buf[j] == 1) ? buf[j] = 0 : buf[j] = 1;
    }
    }
    ============================================================================

  6. Rad says:

    I tried to tweak the code for Arduino Diecimila with no luck. Any help will be appreciated.

  7. jp says:

    Sorry for the late reply. Which Omron reader are you using?

  8. [...] sketch which takes web data and prints it on a thermal printer. I found a great tutorial for reading a magstripe reader with a Sanguino, so I’ll either adapt the code for Arudino use or just use a Sanguino. I haven’t [...]

  9. mantra says:

    Does the magnetic stripe card reader used in the project have a TTL interface?

  10. Jaime says:

    Hello i need to make a card reader whit Arduino Duemilanove (2009) and a Omron V3B-4K is it possible to use your code or need’s to be mod and to what pins i connect the reader

    TKS

  11. jp says:

    There is some modification to be done in order to get it to work with that Arduino and card reader. But it is definitely possible.

    I plan to revisit this project and make a non breadboard version of it.

  12. Jaime says:

    Can you give-me some direction to start pls the idea that i have is like this:
    have a LCD saying (Please Pass Card) (Invalid Card){When the card of a non authorized worker try to use the machine} (Machine ON) (Out of Service)
    I thinking to use the card reader a LCD and a relay to start the machine.

    My Arduino is going to arrive in 1 day to start the tests if you can point me in the right direction i will be very happy because I’m only starting to learn who to use this now. I have seen that the part of LCD and relay is not very difficult but card reader i think that is not so easy…

    TKS

    Jaime Branco

  13. spatialguru says:

    Any tips on getting custom card blanks and a writer? It can’t be _that_ hard can it? ;)

  14. sarun says:

    the above program will not work for arduino decimila or duemilanove because the program uses 3 interrupts which both the arduino’s don’t have [they have only 2 interrupts]

  15. nitroboozter says:

    hey can you please check if the connections in the diagram and the program’s pin connection are all correct.i have an ARDUINO MEGA and i tried connecting all the pins in the sanguino to the respective pins in the mega i am using a OMRON 3S4YR-SBR4N-50 manual half insert reader the connections i made are correct i checked it two three times

    OMRON PIN DETAIL FROM DATASHEET
    not connected — pin1
    read data (output) — pin2
    read clock (output) — pin3
    card load (output) — pin4
    card detection rear(output) — pin5
    card detection rear(input) — pin6
    card detection front(output) — pin7
    card detection front(input) — pin8
    vin — pin9
    ground — pin10

    ARDUINO MEGA PIN DETAIL
    pin1 — connected to omron pin2
    pin2 (interrupt 0)– connected to omron pin5
    pin3 (interrupt 1)– connected to omron pin3
    pin21(interrupt 2)– connected to omron pin4

    i have not connected any lcd and have removed all the codings for the lcd..when i’ve hooked it up the pc and check for the data using serial monitor all i get is Raw: and 2-3 line of spaces when i insert and remove a card.please tell me what i’m doing wrong???

  16. nitroboozter says:

    hey i have also changed the pin numbers in the program too

  17. gary parker says:

    im in miami were can i find this equipment locally what all do i need and a estimate of the price list

  18. good fella says:

    where is a legitimate person or site i can buy this equipment from.

  19. NeedHelp says:

    Nitroboozter do you have success now with arduino mega ?

  20. mike maloon says:

    i really loved this one i just need to know does this can be used to collect data from cards and then to be downloaded by using the program
    if it dont is there any other way to do it

Leave a Reply