Magstripe reader, reversed reading?

Hello folks, Im planning on building an magstripe reader, I found the code by stephen king, and it works great, but i want to modify it so it can read swipes from the other direction.

I've changed the writebit function so it writes the binaries to the buffer in reversed order, it should work, and it does... in about 1 swipe out of 5, the program gets very buggy, in most swipes it just prints half the track or nothing at all. Anyone here who knows what might be wrong?

Original code can be found here:
http://arduino.cc/forum/index.php/topic,7909.0.html

Here is the modified code:

/*
 * Magnetic Stripe Reader
 * by Stephan King http://www.kingsdesign.com
 *
 * Reads a magnetic stripe.
 *
 */
 
int cld1Pin = 5;            // Card status pin
int rdtPin = 2;             // Data pin
int reading = 0;            // Reading status
volatile int buffer[400];   // Buffer for data
volatile int i = 0;         // Buffer counter
volatile int bit = 0;       // global bit
char cardData[40];          // holds card info
int charCount = 0;          // counter for info
int DEBUG = 0;
int ib = 400;
 
void setup() {
  Serial.begin(9600); 
 
  // The interrupts are key to reliable
  // reading of the clock and data feed
  attachInterrupt(0, changeBit, CHANGE);
  attachInterrupt(1, writeBit, FALLING);
}
 
void loop(){
 
  // Active when card present
  while(digitalRead(cld1Pin) == LOW){
    reading = 1;
  }     
 
  // Active when read is complete
  // Reset the buffer
  if(reading == 1) {  
 
    if (DEBUG == 1) {
      printBuffer();
    }
 
    decode();
    reading = 0;
    i = 0;
 
    int l;
    for (l = 0; l < 40; l = l + 1) {
      cardData[l] = '\n';
    }
 
    charCount = 0;
  }
}
 
// Flips the global bit
void changeBit(){
  if (bit == 0) {
    bit = 1;
  } else {
    bit = 0;
  }
}
 
// Writes the bit to the buffer
void writeBit(){
  buffer[ib] = bit;
  ib--;
}
 
// prints the buffer
void printBuffer(){
  int j;
  for (j = 0; j < 200; j = j + 1) {
    Serial.println(buffer[j]);
  }
}
 
int getStartSentinal(){
  int j;
  int queue[5];
  int sentinal = 0;
 
  for (j = 0; j < 400; j = j + 1) {
    queue[4] = queue[3];
    queue[3] = queue[2];
    queue[2] = queue[1];
    queue[1] = queue[0];
    queue[0] = buffer[j];
 
    if (DEBUG == 1) {
      Serial.print(queue[0]);
      Serial.print(queue[1]);
      Serial.print(queue[2]);
      Serial.print(queue[3]);
      Serial.println(queue[4]);
    }
 
    if (queue[0] == 0 & queue[1] == 1 & queue[2] == 0 & queue[3] == 1 & queue[4] == 1) {
      sentinal = j - 4;
      break;
    }
  }
 
  if (DEBUG == 1) {
    Serial.print("sentinal:");
    Serial.println(sentinal);
    Serial.println("");
  }
 
  return sentinal;
}
 
void decode() {
  int sentinal = getStartSentinal();
  int j;
  int i = 0;
  int k = 0;
  int thisByte[5];
 
  for (j = sentinal; j < 400 - sentinal; j = j + 1) {
    thisByte[i] = buffer[j];
    i++;
    if (i % 5 == 0) {
      i = 0;
      if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0) {
        break;
      }
      printMyByte(thisByte);
    }
  }
 
  Serial.print("Stripe_Data:");
  for (k = 0; k < charCount; k = k + 1) {
    Serial.print(cardData[k]);
  }
  Serial.println("");
 
}
 
void printMyByte(int thisByte[]) {
  int i;
  for (i = 0; i < 5; i = i + 1) {
    if (DEBUG == 1) {
      Serial.print(thisByte[i]);
    }
}
    if (DEBUG == 1) {
      Serial.print("\t");
      Serial.print(decodeByte(thisByte));
      Serial.println("");
    }
 
    cardData[charCount] = decodeByte(thisByte);
    charCount ++;
}
 
char decodeByte(int thisByte[]) {
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
      return '0';
    }
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
      return '1';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
      return '2';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
      return '3';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
      return '4';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
      return '5';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
      return '6';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
      return '7';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
      return '8';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
      return '9';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
      return ':';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
      return ';';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
      return '<';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
      return '=';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
      return '>';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
      return '?';
    }
}

Original function:

void writeBit(){
  buffer[i] = bit;
  i++;
}

My function:

int ib = 400;
...
void writeBit(){
  buffer[ib] = bit;
  ib--;
}

Also its worth to mention that i found the modified code by user 'wan' in this old thread: http://arduino.cc/forum/index.php/topic,7909.0.html
But that code only works if you are certain of the ending char on the track, wich is not always the case unfortunately.
Would be awesome if someone could give me a hint on what might be wrong.
Thanks!

Common array mistake: You declared buffer with: "volatile int buffer[400];"

This means there are elements from 0 to 399 since arrays are 0-based.

So in your code, buffer[ib] when ib is 400, doesn't work.

I dont think that is what causing these issues, but I might be wrong, I've tried setting ib to 399 and a few lower values. with the same results, where most swipes only return a part of the complete data (track), and the program tends to freeze aswell and returns nothing at all when i swipe.
Thanks for your reply, I appreciate all help I can get.

Edit: Not sure if its any help, but heres the serial log after 10 swipes, as you can see only 2 swipes were correct. And one swipe did not even print out "Stripe_Data:".

Stripe_Data:;97522050
Stripe_Data:
Stripe_Data:;9752205069904049=20070000000000000000?=
Stripe_Data:
Stripe_Data:;975220506
Stripe_Data:
Stripe_Data:;9752205069904049=20070000000000000000?=

Stripe_Data:
Stripe_Data:

Sorry for bumping, but is anyone here have any thoughts about what might be wrong? Been trying to solve this for hours.

Don't know if it will help, but below is a sketch I used to read a $5 surplus mag card reader I bought 3 years ago or so. The sketch was posted here on the old forum by somebody and I don't recall if I had to tweek it or not.

/*
 * Magnetic Stripe Reader
 * by Stephan King http://www.kingsdesign.com
 *
 * Reads a magnetic stripe.
 * mag read pin1 = +5vdc, 2= data = d2, 3= clock =d3, 5= status = d5, 7 = gnd.
 */
 
int cld1Pin = 5;            // Card status pin
int rdtPin = 2;             // Data pin
int reading = 0;            // Reading status
volatile int buffer[400];   // Buffer for data
volatile int i = 0;         // Buffer counter
volatile int bit = 0;       // global bit
char cardData[40];          // holds card info
int charCount = 0;          // counter for info
int DEBUG = 0;
 
void setup() {
  Serial.begin(9600); 
 
  // The interrupts are key to reliable
  // reading of the clock and data feed
  attachInterrupt(0, changeBit, CHANGE);  //data on pin2
  attachInterrupt(1, writeBit, FALLING);  //clock on pin3
}
 
void loop(){
 
  // Active when card present
  while(digitalRead(cld1Pin) == LOW){
    reading = 1;
  }     
 
  // Active when read is complete
  // Reset the buffer
  if(reading == 1) {  
 
    if (DEBUG == 1) {
      printBuffer();
    }
 
    decode();
    reading = 0;
    i = 0;
 
    int l;
    for (l = 0; l < 40; l = l + 1) {
      cardData[l] = '\n';
    }
 
    charCount = 0;
  }
}
 
// Flips the global bit
void changeBit(){
  if (bit == 0) {
    bit = 1;
  } else {
    bit = 0;
  }
}
 
// Writes the bit to the buffer
void writeBit(){
  buffer[i] = bit;
  i++;
}
 
// prints the buffer
void printBuffer(){
  int j;
  for (j = 0; j < 200; j = j + 1) {
    Serial.println(buffer[j]);
  }
}
 
int getStartSentinal(){
  int j;
  int queue[5];
  int sentinal = 0;
 
  for (j = 0; j < 400; j = j + 1) {
    queue[4] = queue[3];
    queue[3] = queue[2];
    queue[2] = queue[1];
    queue[1] = queue[0];
    queue[0] = buffer[j];
 
    if (DEBUG == 1) {
      Serial.print(queue[0]);
      Serial.print(queue[1]);
      Serial.print(queue[2]);
      Serial.print(queue[3]);
      Serial.println(queue[4]);
    }
 
    if (queue[0] == 0 & queue[1] == 1 & queue[2] == 0 & queue[3] == 1 & queue[4] == 1) {
      sentinal = j - 4;
      break;
    }
  }
 
  if (DEBUG == 1) {
    Serial.print("sentinal:");
    Serial.println(sentinal);
    Serial.println("");
  }
 
  return sentinal;
}
 
void decode() {
  int sentinal = getStartSentinal();
  int j;
  int i = 0;
  int k = 0;
  int thisByte[5];
 
  for (j = sentinal; j < 400 - sentinal; j = j + 1) {
    thisByte[i] = buffer[j];
    i++;
    if (i % 5 == 0) {
      i = 0;
      if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0) {
        break;
      }
      printMyByte(thisByte);
    }
  }
 
  Serial.print("Stripe_Data:");
  for (k = 0; k < charCount; k = k + 1) {
    Serial.print(cardData[k]);
  }
  Serial.println("");
 
}
 
void printMyByte(int thisByte[]) {
  int i;
  for (i = 0; i < 5; i = i + 1) {
    if (DEBUG == 1) {
      Serial.print(thisByte[i]);
    }
}
    if (DEBUG == 1) {
      Serial.print("\t");
      Serial.print(decodeByte(thisByte));
      Serial.println("");
    }
 
    cardData[charCount] = decodeByte(thisByte);
    charCount ++;
}
 
char decodeByte(int thisByte[]) {
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
      return '0';
    }
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
      return '1';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 0){
      return '2';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 0 & thisByte[4] == 1){
      return '3';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
      return '4';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
      return '5';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 1){
      return '6';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 0 & thisByte[4] == 0){
      return '7';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
      return '8';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
      return '9';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 1){
      return ':';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 0 & thisByte[3] == 1 & thisByte[4] == 0){
      return ';';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
      return '<';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 0 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
      return '=';
    }
 
    if (thisByte[0] == 0 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 0){
      return '>';
    }
 
    if (thisByte[0] == 1 & thisByte[1] == 1 & thisByte[2] == 1 & thisByte[3] == 1 & thisByte[4] == 1){
      return '?';
    }
}

Thanks for your reply, but that code seems to be the exact same as the one im trying to modify to read backward swipes.

Ok, sorry that didn't help. Have you tried turning the mag reader upside down? :wink:

Hehe i wished that would work, the bits on the magstripe will still be recieved in a reversed order. :wink:

The first question is, does the device generate signals if swiped the other way around?

Have you tried to reverse the array of the bits read ?

I don't understand why you need two interrupts, just one is enough...

  ...
  attachInterrupt(1, writeBit, FALLING);  //clock on pin3
  ...

void writeBit()
{
  buffer[i++] = digitalRead(2);     // or if flipped bits:    buffer[i++] = 1- digitalRead(2); 
}

Hello! you have resolved this topic?

you can reading in reverse?

Thanks!!