| 1 | //----------------------------------------------------------------------------- |
| 2 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, |
| 3 | // at your option, any later version. See the LICENSE.txt file for the text of |
| 4 | // the license. |
| 5 | //----------------------------------------------------------------------------- |
| 6 | // Miscellaneous routines for low frequency tag operations. |
| 7 | // Tags supported here so far are Texas Instruments (TI), HID |
| 8 | // Also routines for raw mode reading/simulating of LF waveform |
| 9 | //----------------------------------------------------------------------------- |
| 10 | |
| 11 | #include "proxmark3.h" |
| 12 | #include "apps.h" |
| 13 | #include "util.h" |
| 14 | #include "hitag2.h" |
| 15 | #include "crc16.h" |
| 16 | #include "string.h" |
| 17 | |
| 18 | void AcquireRawAdcSamples125k(int at134khz) |
| 19 | { |
| 20 | if (at134khz) |
| 21 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 22 | else |
| 23 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz |
| 24 | |
| 25 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); |
| 26 | |
| 27 | // Connect the A/D to the peak-detected low-frequency path. |
| 28 | SetAdcMuxFor(GPIO_MUXSEL_LOPKD); |
| 29 | |
| 30 | // Give it a bit of time for the resonant antenna to settle. |
| 31 | SpinDelay(50); |
| 32 | |
| 33 | // Now set up the SSC to get the ADC samples that are now streaming at us. |
| 34 | FpgaSetupSsc(); |
| 35 | |
| 36 | // Now call the acquisition routine |
| 37 | DoAcquisition125k(); |
| 38 | } |
| 39 | |
| 40 | // split into two routines so we can avoid timing issues after sending commands // |
| 41 | void DoAcquisition125k(void) |
| 42 | { |
| 43 | uint8_t *dest = (uint8_t *)BigBuf; |
| 44 | int n = sizeof(BigBuf); |
| 45 | int i; |
| 46 | |
| 47 | memset(dest, 0, n); |
| 48 | i = 0; |
| 49 | for(;;) { |
| 50 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { |
| 51 | AT91C_BASE_SSC->SSC_THR = 0x43; |
| 52 | LED_D_ON(); |
| 53 | } |
| 54 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { |
| 55 | dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; |
| 56 | i++; |
| 57 | LED_D_OFF(); |
| 58 | if (i >= n) break; |
| 59 | } |
| 60 | } |
| 61 | Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", |
| 62 | dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); |
| 63 | } |
| 64 | |
| 65 | void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command) |
| 66 | { |
| 67 | int at134khz; |
| 68 | |
| 69 | /* Make sure the tag is reset */ |
| 70 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 71 | SpinDelay(2500); |
| 72 | |
| 73 | // see if 'h' was specified |
| 74 | if (command[strlen((char *) command) - 1] == 'h') |
| 75 | at134khz = TRUE; |
| 76 | else |
| 77 | at134khz = FALSE; |
| 78 | |
| 79 | if (at134khz) |
| 80 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 81 | else |
| 82 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz |
| 83 | |
| 84 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); |
| 85 | |
| 86 | // Give it a bit of time for the resonant antenna to settle. |
| 87 | SpinDelay(50); |
| 88 | // And a little more time for the tag to fully power up |
| 89 | SpinDelay(2000); |
| 90 | |
| 91 | // Now set up the SSC to get the ADC samples that are now streaming at us. |
| 92 | FpgaSetupSsc(); |
| 93 | |
| 94 | // now modulate the reader field |
| 95 | while(*command != '\0' && *command != ' ') { |
| 96 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 97 | LED_D_OFF(); |
| 98 | SpinDelayUs(delay_off); |
| 99 | if (at134khz) |
| 100 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 101 | else |
| 102 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz |
| 103 | |
| 104 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); |
| 105 | LED_D_ON(); |
| 106 | if(*(command++) == '0') |
| 107 | SpinDelayUs(period_0); |
| 108 | else |
| 109 | SpinDelayUs(period_1); |
| 110 | } |
| 111 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 112 | LED_D_OFF(); |
| 113 | SpinDelayUs(delay_off); |
| 114 | if (at134khz) |
| 115 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 116 | else |
| 117 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz |
| 118 | |
| 119 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); |
| 120 | |
| 121 | // now do the read |
| 122 | DoAcquisition125k(); |
| 123 | } |
| 124 | |
| 125 | /* blank r/w tag data stream |
| 126 | ...0000000000000000 01111111 |
| 127 | 1010101010101010101010101010101010101010101010101010101010101010 |
| 128 | 0011010010100001 |
| 129 | 01111111 |
| 130 | 101010101010101[0]000... |
| 131 | |
| 132 | [5555fe852c5555555555555555fe0000] |
| 133 | */ |
| 134 | void ReadTItag(void) |
| 135 | { |
| 136 | // some hardcoded initial params |
| 137 | // when we read a TI tag we sample the zerocross line at 2Mhz |
| 138 | // TI tags modulate a 1 as 16 cycles of 123.2Khz |
| 139 | // TI tags modulate a 0 as 16 cycles of 134.2Khz |
| 140 | #define FSAMPLE 2000000 |
| 141 | #define FREQLO 123200 |
| 142 | #define FREQHI 134200 |
| 143 | |
| 144 | signed char *dest = (signed char *)BigBuf; |
| 145 | int n = sizeof(BigBuf); |
| 146 | // int *dest = GraphBuffer; |
| 147 | // int n = GraphTraceLen; |
| 148 | |
| 149 | // 128 bit shift register [shift3:shift2:shift1:shift0] |
| 150 | uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0; |
| 151 | |
| 152 | int i, cycles=0, samples=0; |
| 153 | // how many sample points fit in 16 cycles of each frequency |
| 154 | uint32_t sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI; |
| 155 | // when to tell if we're close enough to one freq or another |
| 156 | uint32_t threshold = (sampleslo - sampleshi + 1)>>1; |
| 157 | |
| 158 | // TI tags charge at 134.2Khz |
| 159 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 160 | |
| 161 | // Place FPGA in passthrough mode, in this mode the CROSS_LO line |
| 162 | // connects to SSP_DIN and the SSP_DOUT logic level controls |
| 163 | // whether we're modulating the antenna (high) |
| 164 | // or listening to the antenna (low) |
| 165 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); |
| 166 | |
| 167 | // get TI tag data into the buffer |
| 168 | AcquireTiType(); |
| 169 | |
| 170 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 171 | |
| 172 | for (i=0; i<n-1; i++) { |
| 173 | // count cycles by looking for lo to hi zero crossings |
| 174 | if ( (dest[i]<0) && (dest[i+1]>0) ) { |
| 175 | cycles++; |
| 176 | // after 16 cycles, measure the frequency |
| 177 | if (cycles>15) { |
| 178 | cycles=0; |
| 179 | samples=i-samples; // number of samples in these 16 cycles |
| 180 | |
| 181 | // TI bits are coming to us lsb first so shift them |
| 182 | // right through our 128 bit right shift register |
| 183 | shift0 = (shift0>>1) | (shift1 << 31); |
| 184 | shift1 = (shift1>>1) | (shift2 << 31); |
| 185 | shift2 = (shift2>>1) | (shift3 << 31); |
| 186 | shift3 >>= 1; |
| 187 | |
| 188 | // check if the cycles fall close to the number |
| 189 | // expected for either the low or high frequency |
| 190 | if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) { |
| 191 | // low frequency represents a 1 |
| 192 | shift3 |= (1<<31); |
| 193 | } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) { |
| 194 | // high frequency represents a 0 |
| 195 | } else { |
| 196 | // probably detected a gay waveform or noise |
| 197 | // use this as gaydar or discard shift register and start again |
| 198 | shift3 = shift2 = shift1 = shift0 = 0; |
| 199 | } |
| 200 | samples = i; |
| 201 | |
| 202 | // for each bit we receive, test if we've detected a valid tag |
| 203 | |
| 204 | // if we see 17 zeroes followed by 6 ones, we might have a tag |
| 205 | // remember the bits are backwards |
| 206 | if ( ((shift0 & 0x7fffff) == 0x7e0000) ) { |
| 207 | // if start and end bytes match, we have a tag so break out of the loop |
| 208 | if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) { |
| 209 | cycles = 0xF0B; //use this as a flag (ugly but whatever) |
| 210 | break; |
| 211 | } |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | // if flag is set we have a tag |
| 218 | if (cycles!=0xF0B) { |
| 219 | DbpString("Info: No valid tag detected."); |
| 220 | } else { |
| 221 | // put 64 bit data into shift1 and shift0 |
| 222 | shift0 = (shift0>>24) | (shift1 << 8); |
| 223 | shift1 = (shift1>>24) | (shift2 << 8); |
| 224 | |
| 225 | // align 16 bit crc into lower half of shift2 |
| 226 | shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff; |
| 227 | |
| 228 | // if r/w tag, check ident match |
| 229 | if ( shift3&(1<<15) ) { |
| 230 | DbpString("Info: TI tag is rewriteable"); |
| 231 | // only 15 bits compare, last bit of ident is not valid |
| 232 | if ( ((shift3>>16)^shift0)&0x7fff ) { |
| 233 | DbpString("Error: Ident mismatch!"); |
| 234 | } else { |
| 235 | DbpString("Info: TI tag ident is valid"); |
| 236 | } |
| 237 | } else { |
| 238 | DbpString("Info: TI tag is readonly"); |
| 239 | } |
| 240 | |
| 241 | // WARNING the order of the bytes in which we calc crc below needs checking |
| 242 | // i'm 99% sure the crc algorithm is correct, but it may need to eat the |
| 243 | // bytes in reverse or something |
| 244 | // calculate CRC |
| 245 | uint32_t crc=0; |
| 246 | |
| 247 | crc = update_crc16(crc, (shift0)&0xff); |
| 248 | crc = update_crc16(crc, (shift0>>8)&0xff); |
| 249 | crc = update_crc16(crc, (shift0>>16)&0xff); |
| 250 | crc = update_crc16(crc, (shift0>>24)&0xff); |
| 251 | crc = update_crc16(crc, (shift1)&0xff); |
| 252 | crc = update_crc16(crc, (shift1>>8)&0xff); |
| 253 | crc = update_crc16(crc, (shift1>>16)&0xff); |
| 254 | crc = update_crc16(crc, (shift1>>24)&0xff); |
| 255 | |
| 256 | Dbprintf("Info: Tag data: %x%08x, crc=%x", |
| 257 | (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF); |
| 258 | if (crc != (shift2&0xffff)) { |
| 259 | Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc); |
| 260 | } else { |
| 261 | DbpString("Info: CRC is good"); |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | void WriteTIbyte(uint8_t b) |
| 267 | { |
| 268 | int i = 0; |
| 269 | |
| 270 | // modulate 8 bits out to the antenna |
| 271 | for (i=0; i<8; i++) |
| 272 | { |
| 273 | if (b&(1<<i)) { |
| 274 | // stop modulating antenna |
| 275 | LOW(GPIO_SSC_DOUT); |
| 276 | SpinDelayUs(1000); |
| 277 | // modulate antenna |
| 278 | HIGH(GPIO_SSC_DOUT); |
| 279 | SpinDelayUs(1000); |
| 280 | } else { |
| 281 | // stop modulating antenna |
| 282 | LOW(GPIO_SSC_DOUT); |
| 283 | SpinDelayUs(300); |
| 284 | // modulate antenna |
| 285 | HIGH(GPIO_SSC_DOUT); |
| 286 | SpinDelayUs(1700); |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | void AcquireTiType(void) |
| 292 | { |
| 293 | int i, j, n; |
| 294 | // tag transmission is <20ms, sampling at 2M gives us 40K samples max |
| 295 | // each sample is 1 bit stuffed into a uint32_t so we need 1250 uint32_t |
| 296 | #define TIBUFLEN 1250 |
| 297 | |
| 298 | // clear buffer |
| 299 | memset(BigBuf,0,sizeof(BigBuf)); |
| 300 | |
| 301 | // Set up the synchronous serial port |
| 302 | AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN; |
| 303 | AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN; |
| 304 | |
| 305 | // steal this pin from the SSP and use it to control the modulation |
| 306 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; |
| 307 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; |
| 308 | |
| 309 | AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; |
| 310 | AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN; |
| 311 | |
| 312 | // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long |
| 313 | // 48/2 = 24 MHz clock must be divided by 12 |
| 314 | AT91C_BASE_SSC->SSC_CMR = 12; |
| 315 | |
| 316 | AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0); |
| 317 | AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF; |
| 318 | AT91C_BASE_SSC->SSC_TCMR = 0; |
| 319 | AT91C_BASE_SSC->SSC_TFMR = 0; |
| 320 | |
| 321 | LED_D_ON(); |
| 322 | |
| 323 | // modulate antenna |
| 324 | HIGH(GPIO_SSC_DOUT); |
| 325 | |
| 326 | // Charge TI tag for 50ms. |
| 327 | SpinDelay(50); |
| 328 | |
| 329 | // stop modulating antenna and listen |
| 330 | LOW(GPIO_SSC_DOUT); |
| 331 | |
| 332 | LED_D_OFF(); |
| 333 | |
| 334 | i = 0; |
| 335 | for(;;) { |
| 336 | if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { |
| 337 | BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer |
| 338 | i++; if(i >= TIBUFLEN) break; |
| 339 | } |
| 340 | WDT_HIT(); |
| 341 | } |
| 342 | |
| 343 | // return stolen pin to SSP |
| 344 | AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; |
| 345 | AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; |
| 346 | |
| 347 | char *dest = (char *)BigBuf; |
| 348 | n = TIBUFLEN*32; |
| 349 | // unpack buffer |
| 350 | for (i=TIBUFLEN-1; i>=0; i--) { |
| 351 | for (j=0; j<32; j++) { |
| 352 | if(BigBuf[i] & (1 << j)) { |
| 353 | dest[--n] = 1; |
| 354 | } else { |
| 355 | dest[--n] = -1; |
| 356 | } |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc |
| 362 | // if crc provided, it will be written with the data verbatim (even if bogus) |
| 363 | // if not provided a valid crc will be computed from the data and written. |
| 364 | void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) |
| 365 | { |
| 366 | if(crc == 0) { |
| 367 | crc = update_crc16(crc, (idlo)&0xff); |
| 368 | crc = update_crc16(crc, (idlo>>8)&0xff); |
| 369 | crc = update_crc16(crc, (idlo>>16)&0xff); |
| 370 | crc = update_crc16(crc, (idlo>>24)&0xff); |
| 371 | crc = update_crc16(crc, (idhi)&0xff); |
| 372 | crc = update_crc16(crc, (idhi>>8)&0xff); |
| 373 | crc = update_crc16(crc, (idhi>>16)&0xff); |
| 374 | crc = update_crc16(crc, (idhi>>24)&0xff); |
| 375 | } |
| 376 | Dbprintf("Writing to tag: %x%08x, crc=%x", |
| 377 | (unsigned int) idhi, (unsigned int) idlo, crc); |
| 378 | |
| 379 | // TI tags charge at 134.2Khz |
| 380 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz |
| 381 | // Place FPGA in passthrough mode, in this mode the CROSS_LO line |
| 382 | // connects to SSP_DIN and the SSP_DOUT logic level controls |
| 383 | // whether we're modulating the antenna (high) |
| 384 | // or listening to the antenna (low) |
| 385 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU); |
| 386 | LED_A_ON(); |
| 387 | |
| 388 | // steal this pin from the SSP and use it to control the modulation |
| 389 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; |
| 390 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; |
| 391 | |
| 392 | // writing algorithm: |
| 393 | // a high bit consists of a field off for 1ms and field on for 1ms |
| 394 | // a low bit consists of a field off for 0.3ms and field on for 1.7ms |
| 395 | // initiate a charge time of 50ms (field on) then immediately start writing bits |
| 396 | // start by writing 0xBB (keyword) and 0xEB (password) |
| 397 | // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer) |
| 398 | // finally end with 0x0300 (write frame) |
| 399 | // all data is sent lsb firts |
| 400 | // finish with 15ms programming time |
| 401 | |
| 402 | // modulate antenna |
| 403 | HIGH(GPIO_SSC_DOUT); |
| 404 | SpinDelay(50); // charge time |
| 405 | |
| 406 | WriteTIbyte(0xbb); // keyword |
| 407 | WriteTIbyte(0xeb); // password |
| 408 | WriteTIbyte( (idlo )&0xff ); |
| 409 | WriteTIbyte( (idlo>>8 )&0xff ); |
| 410 | WriteTIbyte( (idlo>>16)&0xff ); |
| 411 | WriteTIbyte( (idlo>>24)&0xff ); |
| 412 | WriteTIbyte( (idhi )&0xff ); |
| 413 | WriteTIbyte( (idhi>>8 )&0xff ); |
| 414 | WriteTIbyte( (idhi>>16)&0xff ); |
| 415 | WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo |
| 416 | WriteTIbyte( (crc )&0xff ); // crc lo |
| 417 | WriteTIbyte( (crc>>8 )&0xff ); // crc hi |
| 418 | WriteTIbyte(0x00); // write frame lo |
| 419 | WriteTIbyte(0x03); // write frame hi |
| 420 | HIGH(GPIO_SSC_DOUT); |
| 421 | SpinDelay(50); // programming time |
| 422 | |
| 423 | LED_A_OFF(); |
| 424 | |
| 425 | // get TI tag data into the buffer |
| 426 | AcquireTiType(); |
| 427 | |
| 428 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
| 429 | DbpString("Now use tiread to check"); |
| 430 | } |
| 431 | |
| 432 | void SimulateTagLowFrequency(int period, int gap, int ledcontrol) |
| 433 | { |
| 434 | int i; |
| 435 | uint8_t *tab = (uint8_t *)BigBuf; |
| 436 | |
| 437 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); |
| 438 | |
| 439 | AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK; |
| 440 | |
| 441 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; |
| 442 | AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK; |
| 443 | |
| 444 | #define SHORT_COIL() LOW(GPIO_SSC_DOUT) |
| 445 | #define OPEN_COIL() HIGH(GPIO_SSC_DOUT) |
| 446 | |
| 447 | i = 0; |
| 448 | for(;;) { |
| 449 | while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) { |
| 450 | if(BUTTON_PRESS()) { |
| 451 | DbpString("Stopped"); |
| 452 | return; |
| 453 | } |
| 454 | WDT_HIT(); |
| 455 | } |
| 456 | |
| 457 | if (ledcontrol) |
| 458 | LED_D_ON(); |
| 459 | |
| 460 | if(tab[i]) |
| 461 | OPEN_COIL(); |
| 462 | else |
| 463 | SHORT_COIL(); |
| 464 | |
| 465 | if (ledcontrol) |
| 466 | LED_D_OFF(); |
| 467 | |
| 468 | while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) { |
| 469 | if(BUTTON_PRESS()) { |
| 470 | DbpString("Stopped"); |
| 471 | return; |
| 472 | } |
| 473 | WDT_HIT(); |
| 474 | } |
| 475 | |
| 476 | i++; |
| 477 | if(i == period) { |
| 478 | i = 0; |
| 479 | if (gap) { |
| 480 | SHORT_COIL(); |
| 481 | SpinDelayUs(gap); |
| 482 | } |
| 483 | } |
| 484 | } |
| 485 | } |
| 486 | |
| 487 | /* Provides a framework for bidirectional LF tag communication |
| 488 | * Encoding is currently Hitag2, but the general idea can probably |
| 489 | * be transferred to other encodings. |
| 490 | * |
| 491 | * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME |
| 492 | * (PA15) a thresholded version of the signal from the ADC. Setting the |
| 493 | * ADC path to the low frequency peak detection signal, will enable a |
| 494 | * somewhat reasonable receiver for modulation on the carrier signal |
| 495 | * that is generated by the reader. The signal is low when the reader |
| 496 | * field is switched off, and high when the reader field is active. Due |
| 497 | * to the way that the signal looks like, mostly only the rising edge is |
| 498 | * useful, your mileage may vary. |
| 499 | * |
| 500 | * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also |
| 501 | * TIOA1, which can be used as the capture input for timer 1. This should |
| 502 | * make it possible to measure the exact edge-to-edge time, without processor |
| 503 | * intervention. |
| 504 | * |
| 505 | * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz) |
| 506 | * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz) |
| 507 | * |
| 508 | * The following defines are in carrier periods: |
| 509 | */ |
| 510 | #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ |
| 511 | #define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */ |
| 512 | #define HITAG_T_EOF 40 /* T_EOF should be > 36 */ |
| 513 | #define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */ |
| 514 | |
| 515 | static void hitag_handle_frame(int t0, int frame_len, char *frame); |
| 516 | //#define DEBUG_RA_VALUES 1 |
| 517 | #define DEBUG_FRAME_CONTENTS 1 |
| 518 | void SimulateTagLowFrequencyBidir(int divisor, int t0) |
| 519 | { |
| 520 | #if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS |
| 521 | int i = 0; |
| 522 | #endif |
| 523 | char frame[10]; |
| 524 | int frame_pos=0; |
| 525 | |
| 526 | DbpString("Starting Hitag2 emulator, press button to end"); |
| 527 | hitag2_init(); |
| 528 | |
| 529 | /* Set up simulator mode, frequency divisor which will drive the FPGA |
| 530 | * and analog mux selection. |
| 531 | */ |
| 532 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR); |
| 533 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); |
| 534 | SetAdcMuxFor(GPIO_MUXSEL_LOPKD); |
| 535 | RELAY_OFF(); |
| 536 | |
| 537 | /* Set up Timer 1: |
| 538 | * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger, |
| 539 | * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising |
| 540 | * edge of TIOA. Assign PA15 to TIOA1 (peripheral B) |
| 541 | */ |
| 542 | |
| 543 | AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); |
| 544 | AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; |
| 545 | AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; |
| 546 | AT91C_BASE_TC1->TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1 | |
| 547 | AT91C_TC_ETRGEDG_RISING | |
| 548 | AT91C_TC_ABETRG | |
| 549 | AT91C_TC_LDRA_RISING | |
| 550 | AT91C_TC_LDRB_RISING; |
| 551 | AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | |
| 552 | AT91C_TC_SWTRG; |
| 553 | |
| 554 | /* calculate the new value for the carrier period in terms of TC1 values */ |
| 555 | t0 = t0/2; |
| 556 | |
| 557 | int overflow = 0; |
| 558 | while(!BUTTON_PRESS()) { |
| 559 | WDT_HIT(); |
| 560 | if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { |
| 561 | int ra = AT91C_BASE_TC1->TC_RA; |
| 562 | if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1; |
| 563 | #if DEBUG_RA_VALUES |
| 564 | if(ra > 255 || overflow) ra = 255; |
| 565 | ((char*)BigBuf)[i] = ra; |
| 566 | i = (i+1) % 8000; |
| 567 | #endif |
| 568 | |
| 569 | if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) { |
| 570 | /* Ignore */ |
| 571 | } else if(ra >= t0*HITAG_T_1_MIN ) { |
| 572 | /* '1' bit */ |
| 573 | if(frame_pos < 8*sizeof(frame)) { |
| 574 | frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) ); |
| 575 | frame_pos++; |
| 576 | } |
| 577 | } else if(ra >= t0*HITAG_T_0_MIN) { |
| 578 | /* '0' bit */ |
| 579 | if(frame_pos < 8*sizeof(frame)) { |
| 580 | frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) ); |
| 581 | frame_pos++; |
| 582 | } |
| 583 | } |
| 584 | |
| 585 | overflow = 0; |
| 586 | LED_D_ON(); |
| 587 | } else { |
| 588 | if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) { |
| 589 | /* Minor nuisance: In Capture mode, the timer can not be |
| 590 | * stopped by a Compare C. There's no way to stop the clock |
| 591 | * in software, so we'll just have to note the fact that an |
| 592 | * overflow happened and the next loaded timer value might |
| 593 | * have wrapped. Also, this marks the end of frame, and the |
| 594 | * still running counter can be used to determine the correct |
| 595 | * time for the start of the reply. |
| 596 | */ |
| 597 | overflow = 1; |
| 598 | |
| 599 | if(frame_pos > 0) { |
| 600 | /* Have a frame, do something with it */ |
| 601 | #if DEBUG_FRAME_CONTENTS |
| 602 | ((char*)BigBuf)[i++] = frame_pos; |
| 603 | memcpy( ((char*)BigBuf)+i, frame, 7); |
| 604 | i+=7; |
| 605 | i = i % sizeof(BigBuf); |
| 606 | #endif |
| 607 | hitag_handle_frame(t0, frame_pos, frame); |
| 608 | memset(frame, 0, sizeof(frame)); |
| 609 | } |
| 610 | frame_pos = 0; |
| 611 | |
| 612 | } |
| 613 | LED_D_OFF(); |
| 614 | } |
| 615 | } |
| 616 | DbpString("All done"); |
| 617 | } |
| 618 | |
| 619 | static void hitag_send_bit(int t0, int bit) { |
| 620 | if(bit == 1) { |
| 621 | /* Manchester: Loaded, then unloaded */ |
| 622 | LED_A_ON(); |
| 623 | SHORT_COIL(); |
| 624 | while(AT91C_BASE_TC1->TC_CV < t0*15); |
| 625 | OPEN_COIL(); |
| 626 | while(AT91C_BASE_TC1->TC_CV < t0*31); |
| 627 | LED_A_OFF(); |
| 628 | } else if(bit == 0) { |
| 629 | /* Manchester: Unloaded, then loaded */ |
| 630 | LED_B_ON(); |
| 631 | OPEN_COIL(); |
| 632 | while(AT91C_BASE_TC1->TC_CV < t0*15); |
| 633 | SHORT_COIL(); |
| 634 | while(AT91C_BASE_TC1->TC_CV < t0*31); |
| 635 | LED_B_OFF(); |
| 636 | } |
| 637 | AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */ |
| 638 | |
| 639 | } |
| 640 | static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt) |
| 641 | { |
| 642 | OPEN_COIL(); |
| 643 | AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; |
| 644 | |
| 645 | /* Wait for HITAG_T_WRESP carrier periods after the last reader bit, |
| 646 | * not that since the clock counts since the rising edge, but T_wresp is |
| 647 | * with respect to the falling edge, we need to wait actually (T_wresp - T_g) |
| 648 | * periods. The gap time T_g varies (4..10). |
| 649 | */ |
| 650 | while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8)); |
| 651 | |
| 652 | int saved_cmr = AT91C_BASE_TC1->TC_CMR; |
| 653 | AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */ |
| 654 | AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */ |
| 655 | |
| 656 | int i; |
| 657 | for(i=0; i<5; i++) |
| 658 | hitag_send_bit(t0, 1); /* Start of frame */ |
| 659 | |
| 660 | for(i=0; i<frame_len; i++) { |
| 661 | hitag_send_bit(t0, !!(frame[i/ 8] & (1<<( 7-(i%8) ))) ); |
| 662 | } |
| 663 | |
| 664 | OPEN_COIL(); |
| 665 | AT91C_BASE_TC1->TC_CMR = saved_cmr; |
| 666 | } |
| 667 | |
| 668 | /* Callback structure to cleanly separate tag emulation code from the radio layer. */ |
| 669 | static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie) |
| 670 | { |
| 671 | hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt); |
| 672 | return 0; |
| 673 | } |
| 674 | /* Frame length in bits, frame contents in MSBit first format */ |
| 675 | static void hitag_handle_frame(int t0, int frame_len, char *frame) |
| 676 | { |
| 677 | hitag2_handle_command(frame, frame_len, hitag_cb, &t0); |
| 678 | } |
| 679 | |
| 680 | // compose fc/8 fc/10 waveform |
| 681 | static void fc(int c, int *n) { |
| 682 | uint8_t *dest = (uint8_t *)BigBuf; |
| 683 | int idx; |
| 684 | |
| 685 | // for when we want an fc8 pattern every 4 logical bits |
| 686 | if(c==0) { |
| 687 | dest[((*n)++)]=1; |
| 688 | dest[((*n)++)]=1; |
| 689 | dest[((*n)++)]=0; |
| 690 | dest[((*n)++)]=0; |
| 691 | dest[((*n)++)]=0; |
| 692 | dest[((*n)++)]=0; |
| 693 | dest[((*n)++)]=0; |
| 694 | dest[((*n)++)]=0; |
| 695 | } |
| 696 | // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples |
| 697 | if(c==8) { |
| 698 | for (idx=0; idx<6; idx++) { |
| 699 | dest[((*n)++)]=1; |
| 700 | dest[((*n)++)]=1; |
| 701 | dest[((*n)++)]=0; |
| 702 | dest[((*n)++)]=0; |
| 703 | dest[((*n)++)]=0; |
| 704 | dest[((*n)++)]=0; |
| 705 | dest[((*n)++)]=0; |
| 706 | dest[((*n)++)]=0; |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples |
| 711 | if(c==10) { |
| 712 | for (idx=0; idx<5; idx++) { |
| 713 | dest[((*n)++)]=1; |
| 714 | dest[((*n)++)]=1; |
| 715 | dest[((*n)++)]=1; |
| 716 | dest[((*n)++)]=0; |
| 717 | dest[((*n)++)]=0; |
| 718 | dest[((*n)++)]=0; |
| 719 | dest[((*n)++)]=0; |
| 720 | dest[((*n)++)]=0; |
| 721 | dest[((*n)++)]=0; |
| 722 | dest[((*n)++)]=0; |
| 723 | } |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | // prepare a waveform pattern in the buffer based on the ID given then |
| 728 | // simulate a HID tag until the button is pressed |
| 729 | void CmdHIDsimTAG(int hi, int lo, int ledcontrol) |
| 730 | { |
| 731 | int n=0, i=0; |
| 732 | /* |
| 733 | HID tag bitstream format |
| 734 | The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits |
| 735 | A 1 bit is represented as 6 fc8 and 5 fc10 patterns |
| 736 | A 0 bit is represented as 5 fc10 and 6 fc8 patterns |
| 737 | A fc8 is inserted before every 4 bits |
| 738 | A special start of frame pattern is used consisting a0b0 where a and b are neither 0 |
| 739 | nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10) |
| 740 | */ |
| 741 | |
| 742 | if (hi>0xFFF) { |
| 743 | DbpString("Tags can only have 44 bits."); |
| 744 | return; |
| 745 | } |
| 746 | fc(0,&n); |
| 747 | // special start of frame marker containing invalid bit sequences |
| 748 | fc(8, &n); fc(8, &n); // invalid |
| 749 | fc(8, &n); fc(10, &n); // logical 0 |
| 750 | fc(10, &n); fc(10, &n); // invalid |
| 751 | fc(8, &n); fc(10, &n); // logical 0 |
| 752 | |
| 753 | WDT_HIT(); |
| 754 | // manchester encode bits 43 to 32 |
| 755 | for (i=11; i>=0; i--) { |
| 756 | if ((i%4)==3) fc(0,&n); |
| 757 | if ((hi>>i)&1) { |
| 758 | fc(10, &n); fc(8, &n); // low-high transition |
| 759 | } else { |
| 760 | fc(8, &n); fc(10, &n); // high-low transition |
| 761 | } |
| 762 | } |
| 763 | |
| 764 | WDT_HIT(); |
| 765 | // manchester encode bits 31 to 0 |
| 766 | for (i=31; i>=0; i--) { |
| 767 | if ((i%4)==3) fc(0,&n); |
| 768 | if ((lo>>i)&1) { |
| 769 | fc(10, &n); fc(8, &n); // low-high transition |
| 770 | } else { |
| 771 | fc(8, &n); fc(10, &n); // high-low transition |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | if (ledcontrol) |
| 776 | LED_A_ON(); |
| 777 | SimulateTagLowFrequency(n, 0, ledcontrol); |
| 778 | |
| 779 | if (ledcontrol) |
| 780 | LED_A_OFF(); |
| 781 | } |
| 782 | |
| 783 | |
| 784 | // loop to capture raw HID waveform then FSK demodulate the TAG ID from it |
| 785 | void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol) |
| 786 | { |
| 787 | uint8_t *dest = (uint8_t *)BigBuf; |
| 788 | int m=0, n=0, i=0, idx=0, found=0, lastval=0; |
| 789 | uint32_t hi=0, lo=0; |
| 790 | |
| 791 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz |
| 792 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER); |
| 793 | |
| 794 | // Connect the A/D to the peak-detected low-frequency path. |
| 795 | SetAdcMuxFor(GPIO_MUXSEL_LOPKD); |
| 796 | |
| 797 | // Give it a bit of time for the resonant antenna to settle. |
| 798 | SpinDelay(50); |
| 799 | |
| 800 | // Now set up the SSC to get the ADC samples that are now streaming at us. |
| 801 | FpgaSetupSsc(); |
| 802 | |
| 803 | for(;;) { |
| 804 | WDT_HIT(); |
| 805 | if (ledcontrol) |
| 806 | LED_A_ON(); |
| 807 | if(BUTTON_PRESS()) { |
| 808 | DbpString("Stopped"); |
| 809 | if (ledcontrol) |
| 810 | LED_A_OFF(); |
| 811 | return; |
| 812 | } |
| 813 | |
| 814 | i = 0; |
| 815 | m = sizeof(BigBuf); |
| 816 | memset(dest,128,m); |
| 817 | for(;;) { |
| 818 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { |
| 819 | AT91C_BASE_SSC->SSC_THR = 0x43; |
| 820 | if (ledcontrol) |
| 821 | LED_D_ON(); |
| 822 | } |
| 823 | if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { |
| 824 | dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; |
| 825 | // we don't care about actual value, only if it's more or less than a |
| 826 | // threshold essentially we capture zero crossings for later analysis |
| 827 | if(dest[i] < 127) dest[i] = 0; else dest[i] = 1; |
| 828 | i++; |
| 829 | if (ledcontrol) |
| 830 | LED_D_OFF(); |
| 831 | if(i >= m) { |
| 832 | break; |
| 833 | } |
| 834 | } |
| 835 | } |
| 836 | |
| 837 | // FSK demodulator |
| 838 | |
| 839 | // sync to first lo-hi transition |
| 840 | for( idx=1; idx<m; idx++) { |
| 841 | if (dest[idx-1]<dest[idx]) |
| 842 | lastval=idx; |
| 843 | break; |
| 844 | } |
| 845 | WDT_HIT(); |
| 846 | |
| 847 | // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8) |
| 848 | // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere |
| 849 | // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10 |
| 850 | for( i=0; idx<m; idx++) { |
| 851 | if (dest[idx-1]<dest[idx]) { |
| 852 | dest[i]=idx-lastval; |
| 853 | if (dest[i] <= 8) { |
| 854 | dest[i]=1; |
| 855 | } else { |
| 856 | dest[i]=0; |
| 857 | } |
| 858 | |
| 859 | lastval=idx; |
| 860 | i++; |
| 861 | } |
| 862 | } |
| 863 | m=i; |
| 864 | WDT_HIT(); |
| 865 | |
| 866 | // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns |
| 867 | lastval=dest[0]; |
| 868 | idx=0; |
| 869 | i=0; |
| 870 | n=0; |
| 871 | for( idx=0; idx<m; idx++) { |
| 872 | if (dest[idx]==lastval) { |
| 873 | n++; |
| 874 | } else { |
| 875 | // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents, |
| 876 | // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets |
| 877 | // swallowed up by rounding |
| 878 | // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding |
| 879 | // special start of frame markers use invalid manchester states (no transitions) by using sequences |
| 880 | // like 111000 |
| 881 | if (dest[idx-1]) { |
| 882 | n=(n+1)/6; // fc/8 in sets of 6 |
| 883 | } else { |
| 884 | n=(n+1)/5; // fc/10 in sets of 5 |
| 885 | } |
| 886 | switch (n) { // stuff appropriate bits in buffer |
| 887 | case 0: |
| 888 | case 1: // one bit |
| 889 | dest[i++]=dest[idx-1]; |
| 890 | break; |
| 891 | case 2: // two bits |
| 892 | dest[i++]=dest[idx-1]; |
| 893 | dest[i++]=dest[idx-1]; |
| 894 | break; |
| 895 | case 3: // 3 bit start of frame markers |
| 896 | dest[i++]=dest[idx-1]; |
| 897 | dest[i++]=dest[idx-1]; |
| 898 | dest[i++]=dest[idx-1]; |
| 899 | break; |
| 900 | // When a logic 0 is immediately followed by the start of the next transmisson |
| 901 | // (special pattern) a pattern of 4 bit duration lengths is created. |
| 902 | case 4: |
| 903 | dest[i++]=dest[idx-1]; |
| 904 | dest[i++]=dest[idx-1]; |
| 905 | dest[i++]=dest[idx-1]; |
| 906 | dest[i++]=dest[idx-1]; |
| 907 | break; |
| 908 | default: // this shouldn't happen, don't stuff any bits |
| 909 | break; |
| 910 | } |
| 911 | n=0; |
| 912 | lastval=dest[idx]; |
| 913 | } |
| 914 | } |
| 915 | m=i; |
| 916 | WDT_HIT(); |
| 917 | |
| 918 | // final loop, go over previously decoded manchester data and decode into usable tag ID |
| 919 | // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0 |
| 920 | for( idx=0; idx<m-6; idx++) { |
| 921 | // search for a start of frame marker |
| 922 | if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) |
| 923 | { |
| 924 | found=1; |
| 925 | idx+=6; |
| 926 | if (found && (hi|lo)) { |
| 927 | Dbprintf("TAG ID: %x%08x (%d)", |
| 928 | (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); |
| 929 | /* if we're only looking for one tag */ |
| 930 | if (findone) |
| 931 | { |
| 932 | *high = hi; |
| 933 | *low = lo; |
| 934 | return; |
| 935 | } |
| 936 | hi=0; |
| 937 | lo=0; |
| 938 | found=0; |
| 939 | } |
| 940 | } |
| 941 | if (found) { |
| 942 | if (dest[idx] && (!dest[idx+1]) ) { |
| 943 | hi=(hi<<1)|(lo>>31); |
| 944 | lo=(lo<<1)|0; |
| 945 | } else if ( (!dest[idx]) && dest[idx+1]) { |
| 946 | hi=(hi<<1)|(lo>>31); |
| 947 | lo=(lo<<1)|1; |
| 948 | } else { |
| 949 | found=0; |
| 950 | hi=0; |
| 951 | lo=0; |
| 952 | } |
| 953 | idx++; |
| 954 | } |
| 955 | if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) ) |
| 956 | { |
| 957 | found=1; |
| 958 | idx+=6; |
| 959 | if (found && (hi|lo)) { |
| 960 | Dbprintf("TAG ID: %x%08x (%d)", |
| 961 | (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); |
| 962 | /* if we're only looking for one tag */ |
| 963 | if (findone) |
| 964 | { |
| 965 | *high = hi; |
| 966 | *low = lo; |
| 967 | return; |
| 968 | } |
| 969 | hi=0; |
| 970 | lo=0; |
| 971 | found=0; |
| 972 | } |
| 973 | } |
| 974 | } |
| 975 | WDT_HIT(); |
| 976 | } |
| 977 | } |