code.ino
  1  // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  #define PIEZO 3
  6  #define CLOCK2 10
  7  #define DATA2 9
  8  #define CARD2 23
  9  
 10  #define TRACK1_LEN 79
 11  #define BUFF 30
 12  uint8_t track1[TRACK1_LEN+BUFF];
 13  uint8_t scratch[TRACK1_LEN+BUFF];
 14  
 15  #define RIGHT 1
 16  #define LEFT 0
 17  
 18  #define BYTELENGTH 7 // 6 + 1 parity
 19  
 20  //#define _SERIAL 1
 21  #define _KEYBOARD 1
 22  
 23  void shifttrack(byte track[], byte shiftbuffer[], uint8_t dir);
 24  uint8_t verifycard(byte track[]);
 25  
 26  void beep(uint8_t pin, long freq, long dur) {
 27    long d = 500000/ freq;
 28  
 29    for (long i=0; i< freq * dur / 2000; i++) {
 30      digitalWrite(pin, HIGH);
 31      delayMicroseconds(d);
 32      digitalWrite(pin, LOW);
 33      delayMicroseconds(d);
 34    }  
 35  }
 36  
 37  
 38  void setup()
 39  {
 40  #ifdef _SERIAL
 41    Serial.begin(9600); // USB is always 12 Mbit/sec
 42  #endif
 43   
 44    pinMode(5, OUTPUT);
 45    pinMode(PIEZO, OUTPUT);
 46    digitalWrite(5, LOW);
 47    
 48    beep(PIEZO, 4000, 200);
 49  }
 50  
 51  //http://stripesnoop.sourceforge.net/devel/magtek-app.pdf
 52  
 53  void loop()
 54  {
 55    while (digitalRead(CARD2));
 56    uint8_t zeros = 0;
 57    
 58    // card was swiped!
 59    // check clocked in data
 60    for (uint8_t t1 = 0; t1 < TRACK1_LEN; t1++) {
 61      track1[t1] = 0;
 62      for (uint8_t b=0; b < BYTELENGTH; b++) {
 63  
 64        // wait while clock is high
 65        while (digitalRead(CLOCK2) && !digitalRead(CARD2));
 66        // we sample on the falling edge!
 67        uint8_t x = digitalRead(DATA2);
 68        if (!x) {
 69        // data is LSB and inverted!
 70          track1[t1] |= _BV(b);
 71        }
 72        // heep hanging out while its low
 73        while (!digitalRead(CLOCK2) && !digitalRead(CARD2));
 74       
 75      }
 76      
 77      if ((t1 == 0) && (track1[t1] == 0)) {
 78       // get rid of leading 0's
 79       zeros++;
 80       t1--;
 81       continue;
 82      }
 83      
 84      if (zeros < 4) {
 85        t1--;
 86       continue;
 87      }
 88      if ((t1 == 1) && (track1[t1] == 0)) {
 89       t1 = -1;
 90       zeros = 1;
 91       continue;
 92      }
 93    }
 94    
 95    // shift left until we have no more starting zero bits!
 96    while ((track1[0] & 0x1) == 0 ) {
 97      shifttrack(track1, scratch, LEFT);
 98    }
 99  
100    if (!verifycard(track1)) {
101      // Serial.println("flippy?");
102      
103      // didnt pass verification, perhaps we can try flipping it around?
104      for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) 
105       scratch[i] = 0;  // clear out the scratch
106       
107      for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
108        // for each bit starting with the MSB of the LAST 'byte' to the LSB of the first byte
109        for (int8_t j=0; j < 7; j++) {
110           if (track1[TRACK1_LEN+BUFF-1-i] & _BV(6-j))
111             scratch[i] |= _BV(j);            
112        } 
113      }
114      
115      for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
116        track1[i] = scratch[i];
117      }
118      
119      // get rid of leading zero bits and possible single bit flips
120      while (((track1[0] & 0x1) == 0) || track1[1] == 0)
121        shifttrack(track1, scratch, LEFT);
122    }
123      
124    if (verifycard(track1)) {
125  
126  #ifdef _SERIAL
127      Serial.println("Swiped!");
128      for (uint8_t i = 0; i < TRACK1_LEN; i++) {
129        Serial.print(track1[i], HEX); 
130        Serial.print(" "); 
131      }
132      Serial.println();
133      for (uint8_t i = 0; i < TRACK1_LEN; i++) {
134  #if ARDUINO >= 100
135        Serial.write((track1[i] & 0x3F)+0x20);
136  #else
137        Serial.print((track1[i] & 0x3F)+0x20, BYTE); 
138  #endif
139        Serial.print(" "); 
140      }
141      Serial.println();
142      for (uint8_t i = 0; i < 6; i++) {
143        for (uint8_t j = 0; j < 7; j++) {
144         if (track1[i] & _BV(j)) {
145           Serial.print('1');
146         } else {
147           Serial.print('0');
148         }
149        }
150      }
151      Serial.println();
152  #endif
153  
154      // FIND PAN
155      uint8_t i=2;
156      while ((track1[i] & 0x3F) != 0x3E) {
157  #if ARDUINO >= 100
158   #ifdef _SERIAL
159          Serial.write((track1[i] & 0x3F)+0x20);
160   #endif
161   #ifdef _KEYBOARD
162          Keyboard.write((track1[i] & 0x3F)+0x20);
163   #endif
164  #else
165   #ifdef _SERIAL
166          Serial.print((track1[i] & 0x3F)+0x20, BYTE); 
167   #endif
168   #ifdef _KEYBOARD
169          Keyboard.print((track1[i] & 0x3F)+0x20, BYTE);
170   #endif
171  #endif
172        i++;
173      }
174      i++;
175      char fname[26], lname[26];
176      
177      // LAST NAME
178      uint8_t j=0;
179      while ((track1[i] & 0x3F) != 0xF) {
180  #ifdef _SERIAL
181  #if ARDUINO >= 100
182        Serial.write((track1[i] & 0x3F)+0x20);
183  #else
184        Serial.print((track1[i] & 0x3F)+0x20, BYTE); 
185  #endif
186  #endif
187        lname[j++] = (track1[i] & 0x3F)+0x20;
188        i++;
189      }
190      lname[j] = 0;
191      i++;
192      j=0;
193      // FIRST NAME
194      while ((track1[i] & 0x3F) != 0x3E) {
195  #ifdef _SERIAL
196  #if ARDUINO >= 100
197        Serial.write((track1[i] & 0x3F)+0x20);
198  #else
199        Serial.print((track1[i] & 0x3F)+0x20, BYTE); 
200  #endif
201  #endif
202        
203        fname[j++] = (track1[i] & 0x3F)+0x20;
204  
205        i++;
206      }
207      fname[j] = 0;
208      i++;
209      char y1, y2, m1, m2;
210      y1 = (track1[i++] & 0x3F)+0x20;
211      y2 = (track1[i++] & 0x3F)+0x20;
212      m1 = (track1[i++] & 0x3F)+0x20;
213      m2 = (track1[i++] & 0x3F)+0x20;
214    
215  #ifdef _KEYBOARD
216        Keyboard.print('\t');
217  #if ARDUINO >= 100
218        Keyboard.write(m1);
219        Keyboard.write(m2);
220        Keyboard.write(y1);
221        Keyboard.write(y2);
222  #else
223        Keyboard.print(m1, BYTE);
224        Keyboard.print(m2, BYTE);
225        Keyboard.print(y1, BYTE);
226        Keyboard.print(y2, BYTE);
227  #endif
228      
229        Keyboard.print('\t'); // tab to amount
230        Keyboard.print('\t'); // tab to invoice
231        Keyboard.print('\t'); // tab to description
232        Keyboard.print("HOPE conference kits from Adafruit.com");
233        Keyboard.print('\t'); // tab to customer ID
234        Keyboard.print('\t'); // tab to first name
235        Keyboard.print(fname);
236        Keyboard.print('\t'); // tab to last name
237        Keyboard.print(lname);
238        
239        for (uint8_t i=0; i<5; i++) {
240          Keyboard.set_modifier(MODIFIERKEY_SHIFT);
241          Keyboard.set_key1(KEY_TAB);
242          Keyboard.send_now();
243          Keyboard.set_modifier(0);
244          Keyboard.set_key1(0);
245          Keyboard.send_now();
246        }
247  
248  #endif
249  
250      beep(PIEZO, 4000, 200);
251    } else {
252      beep(PIEZO, 1000, 200);
253      
254  #ifdef _SERIAL
255        Serial.println("Failed!");
256        for (uint8_t i = 0; i < TRACK1_LEN; i++) {
257          Serial.print(track1[i], HEX); 
258          Serial.print(" "); 
259        }
260        Serial.println();
261        for (uint8_t i = 0; i < 6; i++) {
262          for (uint8_t j = 0; j < 7; j++) {
263           if (track1[i] & _BV(j)) {
264             Serial.print('1');
265           } else {
266             Serial.print('0');
267           }
268          }
269        }
270      }
271      Serial.println();
272  #endif
273    
274    //Serial.println(zeros, DEC);
275    
276    for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
277      track1[i] = scratch[i] = 0;
278    }
279    
280    while (! digitalRead(CARD2));
281    return;
282  }
283  
284  uint8_t verifycard(byte track[]) {
285    uint8_t parityok = 1;
286    
287    // calculate parity for each byte
288    for (uint8_t i = 0; i < TRACK1_LEN; i++) {
289      uint8_t p = 1;
290      for (uint8_t j = 0; j < 6; j++) {
291        if (track1[i] & _BV(j))
292          p++;
293      }
294      p %= 2;
295      if (p != track1[i] >> 6) {
296        //Serial.print("Bad parity on ");
297        //Serial.println(track1[i], HEX);
298        parityok = 0;
299      }
300      if (track1[i] == 0x1F) break;
301    }
302    
303    if ((track1[0] == 0x45) && (track1[1] == 0x62) && parityok) {
304      return 1;
305    }
306    return 0;
307  }
308  
309  // We use this to s
310  void shifttrack(byte track[], byte shiftbuffer[], uint8_t dir) {
311    if (dir == RIGHT) {
312      // shift right
313       uint8_t x =0;
314      
315      for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
316        shiftbuffer[i] = ((track[i] << 1) | x) & 0x3F;
317        x = (track[i]>>6) & 0x1; // snag the parity bit
318      } 
319    } else {
320      // left
321      uint8_t x =0;
322      
323      for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
324        x = track[i+1] & 0x1; // snag the bit
325        shiftbuffer[i] = ((track[i] >> 1) | (x << 6));
326  
327      } 
328    }
329    
330    for (uint8_t i = 0; i < TRACK1_LEN+BUFF; i++) {
331      track[i] = shiftbuffer[i];
332    }
333  }