├── LICENSE ├── README.md ├── magspoof.ino ├── on-a-breadboard.jpg └── soldered.jpg /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Lin Zhemin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Magspoof 2 | ======== 3 | This project is a merged clone of samyk's [magspoof] (https://github.com/samyk/magspoof) and joshlf's [magspoof] (https://github.com/joshlf/magspoof). 4 | Samy has written a very detailed blog and recorded a brilliant video on YouTube. I would like to copy what they did but couldn't find ATtiny85. Hence, I tried to port the programmes on Arduino Nano. 5 | 6 | The circuit is copied from Samy. L293D works at 5V, so there's no problem using a USB powerbank for demonstration. 7 | 8 | 9 | Known Issues 10 | ============ 11 | 1. Track 1 needs a better coil. If you can send Track 2 but not Track 1, try to improve it. 12 | 1. I can't send characters. I will update the code once I solve it. 13 | 14 | 15 | LICENSE 16 | ======= 17 | No idea about their respective licenses. My extra work goes 18 | -------------------------------------------------------------------------------- /magspoof.ino: -------------------------------------------------------------------------------- 1 | // Copied from https://github.com/joshlf/magspoof.git 2 | // and https://github.com/samyk/magspoof.git 3 | // and port something to Arduino Nano 4 | // - miaoski 5 | 6 | void setPolarity(int polarity); 7 | void playBit(int bit); 8 | 9 | #define PIN_A 3 // left pin, to L293D pin 2 10 | #define PIN_B 4 // right pin, to L293D pin 7 11 | #define ENABLE_PIN 13 12 | #define BUTTON_PIN 12 13 | #define CLOCK_US 400 14 | #define BETWEEN_ZERO 53 // 53 zeros between track1 & 2 15 | 16 | int polarity = 0; 17 | unsigned int curTrack = 0; 18 | char revTrack[80]; 19 | 20 | const int sublen[] = { 32, 48, 48 }; 21 | const int bitlen[] = { 7, 5, 5 }; 22 | 23 | const char* tracks[] = { 24 | "%B4503111122223333^MIAOSKI LIN ^2010200999909999999900990000000?", // Track 1; %BPAN^NAME^YYMMSSSCVV? + LRC 25 | ";4503111122223333=200120099999999?" // Track 2 ;PAN=YYMMSSSDIS? + LRC 26 | }; 27 | 28 | void setup() { 29 | pinMode(PIN_A, OUTPUT); 30 | pinMode(PIN_B, OUTPUT); 31 | pinMode(BUTTON_PIN, INPUT_PULLUP); 32 | Serial.begin(9600); 33 | storeRevTrack(2); 34 | } 35 | 36 | // Set the polarity of the elctromagnet. 37 | void setPolarity(int polarity) { 38 | if (polarity) { 39 | digitalWrite(PIN_B, LOW); 40 | digitalWrite(PIN_A, HIGH); 41 | } else { 42 | digitalWrite(PIN_A, LOW); 43 | digitalWrite(PIN_B, HIGH); 44 | } 45 | } 46 | 47 | void playBit(int bit) { 48 | polarity ^= 1; 49 | setPolarity(polarity); 50 | delayMicroseconds(CLOCK_US); 51 | 52 | if (bit == 1) { 53 | polarity ^= 1; 54 | setPolarity(polarity); 55 | } 56 | 57 | delayMicroseconds(CLOCK_US); 58 | } 59 | 60 | // when reversing 61 | void reverseTrack(int track) { 62 | int i = 0; 63 | track--; // index 0 64 | polarity = 0; 65 | 66 | while(revTrack[i++] != '\0'); 67 | i--; 68 | while(i--) 69 | for (int j = bitlen[track]-1; j >= 0; j--) 70 | playBit((revTrack[i] >> j) & 1); 71 | } 72 | 73 | // plays out a full track, calculating CRCs and LRC 74 | void playTrack(int track) 75 | { 76 | int tmp, crc, lrc = 0; 77 | track--; // index 0 78 | polarity = 0; 79 | 80 | // enable H-bridge and LED 81 | digitalWrite(ENABLE_PIN, HIGH); 82 | 83 | // First put out a bunch of leading zeros. 84 | for(int i = 0; i < 25; i++) 85 | playBit(0); 86 | 87 | Serial.print("Sending: "); 88 | for(int i = 0; tracks[track][i] != '\0'; i++) { 89 | Serial.print(tracks[track][i]); // The delay that Track 1 needs. 90 | crc = 1; 91 | tmp = tracks[track][i] - sublen[track]; 92 | 93 | for(int j = 0; j < bitlen[track]-1; j++) { 94 | crc ^= (tmp & 1); 95 | lrc ^= (tmp & 1) << j; 96 | playBit(tmp & 1); 97 | tmp >>= 1; 98 | } 99 | playBit(crc); 100 | } 101 | Serial.println(); 102 | 103 | // finish calculating and send last "byte" (LRC) 104 | tmp = lrc; 105 | crc = 1; 106 | for(int j = 0; j < bitlen[track]-1; j++) { 107 | crc ^= tmp & 1; 108 | playBit(tmp & 1); 109 | tmp >>= 1; 110 | } 111 | playBit(crc); 112 | 113 | // if track 1, play 2nd track in reverse (like swiping back?) 114 | /* 115 | if(track == 0) { 116 | for(int i = 0; i < BETWEEN_ZERO; i++) 117 | playBit(0); 118 | reverseTrack(2); 119 | } 120 | */ 121 | // finish with 0's 122 | for (int i = 0; i < 25; i++) 123 | playBit(0); 124 | 125 | digitalWrite(PIN_A, LOW); 126 | digitalWrite(PIN_B, LOW); 127 | digitalWrite(ENABLE_PIN, LOW); 128 | } 129 | 130 | 131 | 132 | // stores track for reverse usage later 133 | void storeRevTrack(int track) { 134 | int i, tmp, crc, lrc = 0; 135 | track--; // index 0 136 | polarity = 0; 137 | 138 | for (i = 0; tracks[track][i] != '\0'; i++) { 139 | crc = 1; 140 | tmp = tracks[track][i] - sublen[track]; 141 | 142 | for (int j = 0; j < bitlen[track]-1; j++) { 143 | crc ^= tmp & 1; 144 | lrc ^= (tmp & 1) << j; 145 | tmp & 1 ? 146 | (revTrack[i] |= 1 << j) : 147 | (revTrack[i] &= ~(1 << j)); 148 | tmp >>= 1; 149 | } 150 | crc ? 151 | (revTrack[i] |= 1 << 4) : 152 | (revTrack[i] &= ~(1 << 4)); 153 | } 154 | 155 | // finish calculating and send last "byte" (LRC) 156 | tmp = lrc; 157 | crc = 1; 158 | for (int j = 0; j < bitlen[track]-1; j++) { 159 | crc ^= tmp & 1; 160 | tmp & 1 ? 161 | (revTrack[i] |= 1 << j) : 162 | (revTrack[i] &= ~(1 << j)); 163 | tmp >>= 1; 164 | } 165 | crc ? 166 | (revTrack[i] |= 1 << 4) : 167 | (revTrack[i] &= ~(1 << 4)); 168 | 169 | i++; 170 | revTrack[i] = '\0'; 171 | } 172 | 173 | 174 | void loop() { 175 | memset(revTrack, 1, sizeof(revTrack)); 176 | while(digitalRead(BUTTON_PIN) == HIGH); 177 | 178 | delay(50); 179 | while(digitalRead(BUTTON_PIN) == HIGH); 180 | Serial.print("Track "); 181 | Serial.println(1 + (curTrack % 2)); 182 | playTrack(1 + (curTrack++ % 2)); 183 | delay(400); 184 | } 185 | -------------------------------------------------------------------------------- /on-a-breadboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaoski/magspoof/ad18220df81f185c715a8c2e173d696271aa89c4/on-a-breadboard.jpg -------------------------------------------------------------------------------- /soldered.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miaoski/magspoof/ad18220df81f185c715a8c2e173d696271aa89c4/soldered.jpg --------------------------------------------------------------------------------