]> git.zerfleddert.de Git - proxmark3-svn/blame - armsrc/appmain.c
iso14443b modifications (#804)
[proxmark3-svn] / armsrc / appmain.c
CommitLineData
15c4dc5a 1//-----------------------------------------------------------------------------
15c4dc5a 2// Jonathan Westhues, Mar 2006
3// Edits by Gerhard de Koning Gans, Sep 2007 (##)
bd20f8f4 4//
5// This code is licensed to you under the terms of the GNU GPL, version 2 or,
6// at your option, any later version. See the LICENSE.txt file for the text of
7// the license.
8//-----------------------------------------------------------------------------
9// The main application code. This is the first thing called after start.c
10// executes.
15c4dc5a 11//-----------------------------------------------------------------------------
12
b8e461ff 13#include <stdarg.h>
14
902cb3c0 15#include "usb_cdc.h"
16#include "cmd.h"
e30c654b 17#include "proxmark3.h"
15c4dc5a 18#include "apps.h"
472345da 19#include "fpga.h"
f7e3ed82 20#include "util.h"
9ab7a6c7 21#include "printf.h"
22#include "string.h"
15c4dc5a 23#include "legicrf.h"
1b902aa0 24#include "legicrfsim.h"
b8e461ff 25#include "hitag2.h"
26#include "hitagS.h"
d9de20fa 27#include "iso15693.h"
31abe49f 28#include "lfsampling.h"
3000dc4e 29#include "BigBuf.h"
c89274cc 30#include "mifareutil.h"
d10e08ae 31#include "pcf7931.h"
050aa18b 32#include "i2c.h"
fc52fbd4 33#include "hfsnoop.h"
34#include "fpgaloader.h"
15c4dc5a 35#ifdef WITH_LCD
902cb3c0 36 #include "LCD.h"
15c4dc5a 37#endif
43591e64 38
a9104f7e 39static uint32_t hw_capabilities;
15c4dc5a 40
e46fe044 41// Craig Young - 14a stand-alone code
854fdf15 42#ifdef WITH_ISO14443a
e46fe044
CY
43 #include "iso14443a.h"
44#endif
45
15c4dc5a 46//=============================================================================
47// A buffer where we can queue things up to be sent through the FPGA, for
48// any purpose (fake tag, as reader, whatever). We go MSB first, since that
49// is the order in which they go out on the wire.
50//=============================================================================
51
6a1f2d82 52#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits
53uint8_t ToSend[TOSEND_BUFFER_SIZE];
15c4dc5a 54int ToSendMax;
55static int ToSendBit;
56struct common_area common_area __attribute__((section(".commonarea")));
57
15c4dc5a 58void ToSendReset(void)
59{
60 ToSendMax = -1;
61 ToSendBit = 8;
62}
63
64void ToSendStuffBit(int b)
65{
66 if(ToSendBit >= 8) {
67 ToSendMax++;
68 ToSend[ToSendMax] = 0;
69 ToSendBit = 0;
70 }
71
72 if(b) {
73 ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
74 }
75
76 ToSendBit++;
77
6a1f2d82 78 if(ToSendMax >= sizeof(ToSend)) {
15c4dc5a 79 ToSendBit = 0;
80 DbpString("ToSendStuffBit overflowed!");
81 }
82}
83
84//=============================================================================
85// Debug print functions, to go out over USB, to the usual PC-side client.
86//=============================================================================
87
88void DbpString(char *str)
89{
9440213d 90 byte_t len = strlen(str);
91 cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len);
15c4dc5a 92}
93
94#if 0
95void DbpIntegers(int x1, int x2, int x3)
96{
902cb3c0 97 cmd_send(CMD_DEBUG_PRINT_INTEGERS,x1,x2,x3,0,0);
15c4dc5a 98}
99#endif
100
101void Dbprintf(const char *fmt, ...) {
102// should probably limit size here; oh well, let's just use a big buffer
103 char output_string[128];
104 va_list ap;
105
106 va_start(ap, fmt);
107 kvsprintf(fmt, output_string, 10, ap);
108 va_end(ap);
e30c654b 109
15c4dc5a 110 DbpString(output_string);
111}
112
9455b51c 113// prints HEX & ASCII
d19929cb 114void Dbhexdump(int len, uint8_t *d, bool bAsci) {
9455b51c 115 int l=0,i;
116 char ascii[9];
d19929cb 117
9455b51c 118 while (len>0) {
119 if (len>8) l=8;
120 else l=len;
121
122 memcpy(ascii,d,l);
d19929cb 123 ascii[l]=0;
9455b51c 124
125 // filter safe ascii
d19929cb 126 for (i=0;i<l;i++)
9455b51c 127 if (ascii[i]<32 || ascii[i]>126) ascii[i]='.';
d19929cb 128
129 if (bAsci) {
130 Dbprintf("%-8s %*D",ascii,l,d," ");
131 } else {
132 Dbprintf("%*D",l,d," ");
133 }
134
9455b51c 135 len-=8;
136 d+=8;
137 }
138}
139
15c4dc5a 140//-----------------------------------------------------------------------------
141// Read an ADC channel and block till it completes, then return the result
142// in ADC units (0 to 1023). Also a routine to average 32 samples and
143// return that.
144//-----------------------------------------------------------------------------
145static int ReadAdc(int ch)
2d51da38 146{
3b692427 147 // Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value.
050aa18b 148 // AMPL_HI is a high impedance (10MOhm || 1MOhm) output, the input capacitance of the ADC is 12pF (typical). This results in a time constant
9b32625c 149 // of RC = (0.91MOhm) * 12pF = 10.9us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged.
3b692427 150 //
151 // The maths are:
152 // If there is a voltage v_in at the input, the voltage v_cap at the capacitor (this is what we are measuring) will be
153 //
9b32625c 154 // v_cap = v_in * (1 - exp(-SHTIM/RC)) = v_in * (1 - exp(-40us/10.9us)) = v_in * 0,97 (i.e. an error of 3%)
15c4dc5a 155
2d51da38
I
156 AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
157 AT91C_BASE_ADC->ADC_MR =
9b32625c 158 ADC_MODE_PRESCALE(63) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz
159 ADC_MODE_STARTUP_TIME(1) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us
160 ADC_MODE_SAMPLE_HOLD_TIME(15); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us
3b692427 161
2d51da38
I
162 AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);
163 AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
15c4dc5a 164
2d51da38
I
165 while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) {};
166
050aa18b 167 return AT91C_BASE_ADC->ADC_CDR[ch] & 0x3ff;
15c4dc5a 168}
169
9ca155ba 170int AvgAdc(int ch) // was static - merlok
15c4dc5a 171{
172 int i;
173 int a = 0;
174
175 for(i = 0; i < 32; i++) {
176 a += ReadAdc(ch);
177 }
178
179 return (a + 15) >> 5;
180}
181
050aa18b 182static int AvgAdc_Voltage_HF(void)
183{
184 int AvgAdc_Voltage_Low, AvgAdc_Voltage_High;
185
186 AvgAdc_Voltage_Low= (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10;
187 // if voltage range is about to be exceeded, use high voltage ADC channel if available (RDV40 only)
188 if (AvgAdc_Voltage_Low > MAX_ADC_HF_VOLTAGE_LOW - 300) {
189 AvgAdc_Voltage_High = (MAX_ADC_HF_VOLTAGE_HIGH * AvgAdc(ADC_CHAN_HF_HIGH)) >> 10;
190 if (AvgAdc_Voltage_High >= AvgAdc_Voltage_Low) {
191 return AvgAdc_Voltage_High;
192 }
193 }
194 return AvgAdc_Voltage_Low;
195}
196
197static int AvgAdc_Voltage_LF(void)
198{
199 return (MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10;
200}
201
fdcfbdcc 202void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[])
15c4dc5a 203{
9b32625c 204 int i, adcval = 0, peak = 0;
15c4dc5a 205
206/*
207 * Sweeps the useful LF range of the proxmark from
208 * 46.8kHz (divisor=255) to 600kHz (divisor=19) and
209 * read the voltage in the antenna, the result left
210 * in the buffer is a graph which should clearly show
211 * the resonating frequency of your LF antenna
212 * ( hopefully around 95 if it is tuned to 125kHz!)
213 */
fdcfbdcc
RAB
214
215 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
b014c96d 216 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
2d51da38
I
217 SpinDelay(50);
218
2bdd68c3 219 for (i=255; i>=19; i--) {
fdcfbdcc 220 WDT_HIT();
15c4dc5a 221 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
222 SpinDelay(20);
050aa18b 223 adcval = AvgAdc_Voltage_LF();
fdcfbdcc
RAB
224 if (i==95) *vLf125 = adcval; // voltage at 125Khz
225 if (i==89) *vLf134 = adcval; // voltage at 134Khz
15c4dc5a 226
2d51da38 227 LF_Results[i] = adcval >> 9; // scale int to fit in byte for graphing purposes
2bdd68c3 228 if(LF_Results[i] > peak) {
fdcfbdcc 229 *peakv = adcval;
2bdd68c3 230 peak = LF_Results[i];
fdcfbdcc 231 *peakf = i;
9f693930 232 //ptr = i;
15c4dc5a 233 }
234 }
235
2bdd68c3 236 for (i=18; i >= 0; i--) LF_Results[i] = 0;
fdcfbdcc
RAB
237
238 return;
239}
240
241void MeasureAntennaTuningHfOnly(int *vHf)
242{
15c4dc5a 243 // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
fdcfbdcc
RAB
244 LED_A_ON();
245 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
15c4dc5a 246 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
247 SpinDelay(20);
050aa18b 248 *vHf = AvgAdc_Voltage_HF();
fdcfbdcc 249 LED_A_OFF();
fdcfbdcc
RAB
250 return;
251}
252
253void MeasureAntennaTuning(int mode)
254{
255 uint8_t LF_Results[256] = {0};
256 int peakv = 0, peakf = 0;
257 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
258
259 LED_B_ON();
260
261 if (((mode & FLAG_TUNE_ALL) == FLAG_TUNE_ALL) && (FpgaGetCurrent() == FPGA_BITSTREAM_HF)) {
262 // Reverse "standard" order if HF already loaded, to avoid unnecessary swap.
263 MeasureAntennaTuningHfOnly(&vHf);
264 MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results);
265 } else {
266 if (mode & FLAG_TUNE_LF) {
267 MeasureAntennaTuningLfOnly(&vLf125, &vLf134, &peakf, &peakv, LF_Results);
268 }
269 if (mode & FLAG_TUNE_HF) {
270 MeasureAntennaTuningHfOnly(&vHf);
271 }
272 }
15c4dc5a 273
d040cb90 274 cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125>>1 | (vLf134>>1<<16), vHf, peakf | (peakv>>1<<16), LF_Results, 256);
d19929cb 275 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
2bdd68c3 276 LED_B_OFF();
277 return;
15c4dc5a 278}
279
280void MeasureAntennaTuningHf(void)
281{
282 int vHf = 0; // in mV
283
284 DbpString("Measuring HF antenna, press button to exit");
285
3b692427 286 // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
287 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
288 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
289
15c4dc5a 290 for (;;) {
050aa18b 291 SpinDelay(500);
292 vHf = AvgAdc_Voltage_HF();
e30c654b 293
15c4dc5a 294 Dbprintf("%d mV",vHf);
295 if (BUTTON_PRESS()) break;
296 }
297 DbpString("cancelled");
3b692427 298
299 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
300
15c4dc5a 301}
302
303
15c4dc5a 304void ReadMem(int addr)
305{
f7e3ed82 306 const uint8_t *data = ((uint8_t *)addr);
15c4dc5a 307
308 Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",
309 addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
310}
311
312/* osimage version information is linked in */
313extern struct version_information version_information;
314/* bootrom version information is pointed to from _bootphase1_version_pointer */
0fa01ec7 315extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__;
472345da 316
050aa18b 317
a9104f7e 318void set_hw_capabilities(void)
319{
320 if (I2C_is_available()) {
321 hw_capabilities |= HAS_SMARTCARD_SLOT;
322 }
323
324 if (false) { // TODO: implement a test
325 hw_capabilities |= HAS_EXTRA_FLASH_MEM;
326 }
327}
328
329
15c4dc5a 330void SendVersion(void)
331{
a9104f7e 332 set_hw_capabilities();
333
8e074056 334 char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */
335 char VersionString[USB_CMD_DATA_SIZE] = { '\0' };
e30c654b 336
337 /* Try to find the bootrom version information. Expect to find a pointer at
15c4dc5a 338 * symbol _bootphase1_version_pointer, perform slight sanity checks on the
339 * pointer, then use it.
340 */
341 char *bootrom_version = *(char**)&_bootphase1_version_pointer;
342 if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {
8e074056 343 strcat(VersionString, "bootrom version information appears invalid\n");
15c4dc5a 344 } else {
345 FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
8e074056 346 strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
15c4dc5a 347 }
e30c654b 348
15c4dc5a 349 FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
8e074056 350 strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
e30c654b 351
472345da 352 for (int i = 0; i < fpga_bitstream_num; i++) {
353 strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1);
050aa18b 354 strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1);
472345da 355 }
050aa18b 356
357 // test availability of SmartCard slot
358 if (I2C_is_available()) {
359 strncat(VersionString, "SmartCard Slot: available\n", sizeof(VersionString) - strlen(VersionString) - 1);
360 } else {
361 strncat(VersionString, "SmartCard Slot: not available\n", sizeof(VersionString) - strlen(VersionString) - 1);
362 }
363
e6153040 364 // Send Chip ID and used flash memory
0fa01ec7 365 uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start;
366 uint32_t compressed_data_section_size = common_area.arg1;
a9104f7e 367 cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString));
15c4dc5a 368}
369
bfb01844 370// measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
371// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the UsbCommand structure included.
67b7d6fa 372void printUSBSpeed(void)
bfb01844 373{
374 Dbprintf("USB Speed:");
67b7d6fa 375 Dbprintf(" Sending USB packets to client...");
bfb01844 376
67b7d6fa 377 #define USB_SPEED_TEST_MIN_TIME 1500 // in milliseconds
bfb01844 378 uint8_t *test_data = BigBuf_get_addr();
67b7d6fa 379 uint32_t end_time;
bfb01844 380
67b7d6fa 381 uint32_t start_time = end_time = GetTickCount();
382 uint32_t bytes_transferred = 0;
383
bfb01844 384 LED_B_ON();
67b7d6fa 385 while(end_time < start_time + USB_SPEED_TEST_MIN_TIME) {
386 cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE);
387 end_time = GetTickCount();
388 bytes_transferred += USB_CMD_DATA_SIZE;
bfb01844 389 }
390 LED_B_OFF();
391
67b7d6fa 392 Dbprintf(" Time elapsed: %dms", end_time - start_time);
393 Dbprintf(" Bytes transferred: %d", bytes_transferred);
394 Dbprintf(" USB Transfer Speed PM3 -> Client = %d Bytes/s",
395 1000 * bytes_transferred / (end_time - start_time));
bfb01844 396
397}
398
c89274cc
CY
399/**
400 * Prints runtime information about the PM3.
401**/
67b7d6fa 402void SendStatus(void)
c89274cc
CY
403{
404 BigBuf_print_status();
405 Fpga_print_status();
43591e64 406#ifdef WITH_SMARTCARD
407 I2C_print_status();
408#endif
c89274cc 409 printConfig(); //LF Sampling config
67b7d6fa 410 printUSBSpeed();
c89274cc 411 Dbprintf("Various");
43591e64 412 Dbprintf(" MF_DBGLEVEL........%d", MF_DBGLEVEL);
413 Dbprintf(" ToSendMax..........%d", ToSendMax);
414 Dbprintf(" ToSendBit..........%d", ToSendBit);
bfb01844 415
416 cmd_send(CMD_ACK,1,0,0,0,0);
c89274cc 417}
15c4dc5a 418
a2937cea 419#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone)
15c4dc5a 420
15c4dc5a 421#define OPTS 2
422
86a83668
MHS
423void StandAloneMode()
424{
425 DbpString("Stand-alone mode! No PC necessary.");
15c4dc5a 426 // Oooh pretty -- notify user we're in elite samy mode now
427 LED(LED_RED, 200);
428 LED(LED_ORANGE, 200);
429 LED(LED_GREEN, 200);
430 LED(LED_ORANGE, 200);
431 LED(LED_RED, 200);
432 LED(LED_ORANGE, 200);
433 LED(LED_GREEN, 200);
434 LED(LED_ORANGE, 200);
435 LED(LED_RED, 200);
436
86a83668
MHS
437}
438
439#endif
440
441
442
443#ifdef WITH_ISO14443a_StandAlone
444void StandAloneMode14a()
445{
446 StandAloneMode();
447 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
448
15c4dc5a 449 int selected = 0;
44964fd1 450 bool playing = false, GotoRecord = false, GotoClone = false;
451 bool cardRead[OPTS] = {false};
86a83668
MHS
452 uint8_t readUID[10] = {0};
453 uint32_t uid_1st[OPTS]={0};
454 uint32_t uid_2nd[OPTS]={0};
c89274cc
CY
455 uint32_t uid_tmp1 = 0;
456 uint32_t uid_tmp2 = 0;
457 iso14a_card_select_t hi14a_card[OPTS];
15c4dc5a 458
15c4dc5a 459 LED(selected + 1, 0);
460
461 for (;;)
462 {
6e82300d 463 usb_poll();
86a83668 464 WDT_HIT();
15c4dc5a 465 SpinDelay(300);
466
44964fd1 467 if (GotoRecord || !cardRead[selected])
15c4dc5a 468 {
44964fd1 469 GotoRecord = false;
15c4dc5a 470 LEDsoff();
471 LED(selected + 1, 0);
472 LED(LED_RED2, 0);
473
474 // record
86a83668 475 Dbprintf("Enabling iso14443a reader mode for [Bank: %u]...", selected);
15c4dc5a 476 /* need this delay to prevent catching some weird data */
477 SpinDelay(500);
86a83668
MHS
478 /* Code for reading from 14a tag */
479 uint8_t uid[10] ={0};
480 uint32_t cuid;
481 iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
15c4dc5a 482
86a83668
MHS
483 for ( ; ; )
484 {
485 WDT_HIT();
c89274cc
CY
486 if (BUTTON_PRESS()) {
487 if (cardRead[selected]) {
488 Dbprintf("Button press detected -- replaying card in bank[%d]", selected);
489 break;
490 }
491 else if (cardRead[(selected+1)%OPTS]) {
492 Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS);
493 selected = (selected+1)%OPTS;
44964fd1 494 break;
c89274cc
CY
495 }
496 else {
497 Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
498 SpinDelay(300);
499 }
500 }
c04a4b60 501 if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0, true))
86a83668
MHS
502 continue;
503 else
504 {
505 Dbprintf("Read UID:"); Dbhexdump(10,uid,0);
506 memcpy(readUID,uid,10*sizeof(uint8_t));
c89274cc 507 uint8_t *dst = (uint8_t *)&uid_tmp1;
86a83668
MHS
508 // Set UID byte order
509 for (int i=0; i<4; i++)
510 dst[i] = uid[3-i];
c89274cc 511 dst = (uint8_t *)&uid_tmp2;
86a83668
MHS
512 for (int i=0; i<4; i++)
513 dst[i] = uid[7-i];
c89274cc
CY
514 if (uid_1st[(selected+1)%OPTS] == uid_tmp1 && uid_2nd[(selected+1)%OPTS] == uid_tmp2) {
515 Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping.");
516 }
517 else {
518 if (uid_tmp2) {
519 Dbprintf("Bank[%d] received a 7-byte UID",selected);
520 uid_1st[selected] = (uid_tmp1)>>8;
521 uid_2nd[selected] = (uid_tmp1<<24) + (uid_tmp2>>8);
522 }
523 else {
524 Dbprintf("Bank[%d] received a 4-byte UID",selected);
525 uid_1st[selected] = uid_tmp1;
526 uid_2nd[selected] = uid_tmp2;
527 }
528 break;
529 }
86a83668
MHS
530 }
531 }
c89274cc
CY
532 Dbprintf("ATQA = %02X%02X",hi14a_card[selected].atqa[0],hi14a_card[selected].atqa[1]);
533 Dbprintf("SAK = %02X",hi14a_card[selected].sak);
86a83668
MHS
534 LEDsoff();
535 LED(LED_GREEN, 200);
536 LED(LED_ORANGE, 200);
537 LED(LED_GREEN, 200);
538 LED(LED_ORANGE, 200);
15c4dc5a 539
540 LEDsoff();
541 LED(selected + 1, 0);
15c4dc5a 542
c89274cc 543 // Next state is replay:
44964fd1 544 playing = true;
3fe4ff4f 545
44964fd1 546 cardRead[selected] = true;
86a83668 547 }
c89274cc 548 /* MF Classic UID clone */
44964fd1 549 else if (GotoClone)
3fe4ff4f 550 {
44964fd1 551 GotoClone=false;
c89274cc
CY
552 LEDsoff();
553 LED(selected + 1, 0);
554 LED(LED_ORANGE, 250);
3fe4ff4f 555
3fe4ff4f 556
c89274cc
CY
557 // record
558 Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]);
3fe4ff4f 559
c89274cc
CY
560 // wait for button to be released
561 while(BUTTON_PRESS())
562 {
563 // Delay cloning until card is in place
564 WDT_HIT();
565 }
566 Dbprintf("Starting clone. [Bank: %u]", selected);
567 // need this delay to prevent catching some weird data
568 SpinDelay(500);
569 // Begin clone function here:
570 /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
571 UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}};
572 memcpy(c.d.asBytes, data, 16);
573 SendCommand(&c);
574
575 Block read is similar:
576 UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}};
577 We need to imitate that call with blockNo 0 to set a uid.
578
579 The get and set commands are handled in this file:
580 // Work with "magic Chinese" card
581 case CMD_MIFARE_CSETBLOCK:
582 MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
583 break;
584 case CMD_MIFARE_CGETBLOCK:
585 MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
586 break;
587
588 mfCSetUID provides example logic for UID set workflow:
589 -Read block0 from card in field with MifareCGetBlock()
590 -Configure new values without replacing reserved bytes
591 memcpy(block0, uid, 4); // Copy UID bytes from byte array
592 // Mifare UID BCC
593 block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
594 Bytes 5-7 are reserved SAK and ATQA for mifare classic
595 -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it
596 */
597 uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0};
598 // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo
599 MifareCGetBlock(0x3F, 1, 0, oldBlock0);
600 if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
601 Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
44964fd1 602 playing = true;
c89274cc
CY
603 }
604 else {
605 Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]);
606 memcpy(newBlock0,oldBlock0,16);
607 // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic)
608
609 newBlock0[0] = uid_1st[selected]>>24;
610 newBlock0[1] = 0xFF & (uid_1st[selected]>>16);
611 newBlock0[2] = 0xFF & (uid_1st[selected]>>8);
612 newBlock0[3] = 0xFF & (uid_1st[selected]);
613 newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3];
614 // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain
615 MifareCSetBlock(0, 0xFF,0, newBlock0);
616 MifareCGetBlock(0x3F, 1, 0, testBlock0);
617 if (memcmp(testBlock0,newBlock0,16)==0)
618 {
619 DbpString("Cloned successfull!");
44964fd1 620 cardRead[selected] = false; // Only if the card was cloned successfully should we clear it
621 playing = false;
622 GotoRecord = true;
c89274cc
CY
623 selected = (selected+1) % OPTS;
624 }
625 else {
626 Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
44964fd1 627 playing = true;
c89274cc
CY
628 }
629 }
630 LEDsoff();
631 LED(selected + 1, 0);
15c4dc5a 632
86a83668 633 }
15c4dc5a 634 // Change where to record (or begin playing)
44964fd1 635 else if (playing) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
15c4dc5a 636 {
15c4dc5a 637 LEDsoff();
638 LED(selected + 1, 0);
639
640 // Begin transmitting
44964fd1 641 LED(LED_GREEN, 0);
642 DbpString("Playing");
643 for ( ; ; ) {
644 WDT_HIT();
645 int button_action = BUTTON_HELD(1000);
646 if (button_action == 0) { // No button action, proceed with sim
647 uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break
648 Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected);
649 if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) {
650 DbpString("Mifare Classic");
651 SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); // Mifare Classic
c89274cc 652 }
44964fd1 653 else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) {
654 DbpString("Mifare Ultralight");
655 SimulateIso14443aTag(2,uid_1st[selected],uid_2nd[selected],data); // Mifare Ultralight
15c4dc5a 656 }
44964fd1 657 else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) {
658 DbpString("Mifare DESFire");
659 SimulateIso14443aTag(3,uid_1st[selected],uid_2nd[selected],data); // Mifare DESFire
660 }
661 else {
662 Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
663 SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data);
c89274cc 664 }
c89274cc 665 }
44964fd1 666 else if (button_action == BUTTON_SINGLE_CLICK) {
667 selected = (selected + 1) % OPTS;
668 Dbprintf("Done playing. Switching to record mode on bank %d",selected);
669 GotoRecord = true;
670 break;
671 }
672 else if (button_action == BUTTON_HOLD) {
673 Dbprintf("Playtime over. Begin cloning...");
674 GotoClone = true;
675 break;
676 }
677 WDT_HIT();
15c4dc5a 678 }
44964fd1 679
680 /* We pressed a button so ignore it here with a delay */
681 SpinDelay(300);
682 LEDsoff();
683 LED(selected + 1, 0);
15c4dc5a 684 }
685 }
686}
a2937cea 687#elif WITH_LF_StandAlone
86a83668
MHS
688// samy's sniff and repeat routine
689void SamyRun()
e46fe044 690{
86a83668
MHS
691 StandAloneMode();
692 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
e46fe044 693
53e2f2fa 694 int tops[OPTS], high[OPTS], low[OPTS];
15c4dc5a 695 int selected = 0;
696 int playing = 0;
3fe4ff4f 697 int cardRead = 0;
15c4dc5a 698
699 // Turn on selected LED
700 LED(selected + 1, 0);
701
702 for (;;)
703 {
6e82300d 704 usb_poll();
86a83668 705 WDT_HIT();
15c4dc5a 706
707 // Was our button held down or pressed?
708 int button_pressed = BUTTON_HELD(1000);
709 SpinDelay(300);
710
711 // Button was held for a second, begin recording
3fe4ff4f 712 if (button_pressed > 0 && cardRead == 0)
15c4dc5a 713 {
714 LEDsoff();
715 LED(selected + 1, 0);
716 LED(LED_RED2, 0);
717
718 // record
719 DbpString("Starting recording");
720
721 // wait for button to be released
722 while(BUTTON_PRESS())
723 WDT_HIT();
724
725 /* need this delay to prevent catching some weird data */
726 SpinDelay(500);
727
53e2f2fa 728 CmdHIDdemodFSK(1, &tops[selected], &high[selected], &low[selected], 0);
729 if (tops[selected] > 0)
730 Dbprintf("Recorded %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
731 else
732 Dbprintf("Recorded %x %x%08x", selected, high[selected], low[selected]);
15c4dc5a 733
734 LEDsoff();
735 LED(selected + 1, 0);
736 // Finished recording
737
738 // If we were previously playing, set playing off
739 // so next button push begins playing what we recorded
740 playing = 0;
3fe4ff4f 741
742 cardRead = 1;
743
744 }
745
746 else if (button_pressed > 0 && cardRead == 1)
747 {
748 LEDsoff();
749 LED(selected + 1, 0);
750 LED(LED_ORANGE, 0);
751
752 // record
53e2f2fa 753 if (tops[selected] > 0)
754 Dbprintf("Cloning %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
755 else
756 Dbprintf("Cloning %x %x%08x", selected, high[selected], low[selected]);
3fe4ff4f 757
758 // wait for button to be released
759 while(BUTTON_PRESS())
760 WDT_HIT();
761
762 /* need this delay to prevent catching some weird data */
763 SpinDelay(500);
764
5f84531b 765 CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)), 0x1D);
53e2f2fa 766 if (tops[selected] > 0)
767 Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
768 else
769 Dbprintf("Cloned %x %x%08x", selected, high[selected], low[selected]);
3fe4ff4f 770
771 LEDsoff();
772 LED(selected + 1, 0);
773 // Finished recording
774
775 // If we were previously playing, set playing off
776 // so next button push begins playing what we recorded
777 playing = 0;
778
779 cardRead = 0;
780
15c4dc5a 781 }
782
783 // Change where to record (or begin playing)
784 else if (button_pressed)
785 {
786 // Next option if we were previously playing
787 if (playing)
788 selected = (selected + 1) % OPTS;
789 playing = !playing;
790
791 LEDsoff();
792 LED(selected + 1, 0);
793
794 // Begin transmitting
795 if (playing)
796 {
797 LED(LED_GREEN, 0);
798 DbpString("Playing");
799 // wait for button to be released
800 while(BUTTON_PRESS())
801 WDT_HIT();
53e2f2fa 802 if (tops[selected] > 0)
803 Dbprintf("%x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
804 else
805 Dbprintf("%x %x%08x", selected, high[selected], low[selected]);
806
807 CmdHIDsimTAG(tops[selected], high[selected], low[selected], 0);
15c4dc5a 808 DbpString("Done playing");
809 if (BUTTON_HELD(1000) > 0)
810 {
811 DbpString("Exiting");
812 LEDsoff();
813 return;
814 }
815
816 /* We pressed a button so ignore it here with a delay */
817 SpinDelay(300);
818
819 // when done, we're done playing, move to next option
820 selected = (selected + 1) % OPTS;
821 playing = !playing;
822 LEDsoff();
823 LED(selected + 1, 0);
824 }
825 else
826 while(BUTTON_PRESS())
827 WDT_HIT();
828 }
829 }
830}
15c4dc5a 831
e46fe044 832#endif
15c4dc5a 833/*
834OBJECTIVE
835Listen and detect an external reader. Determine the best location
836for the antenna.
837
838INSTRUCTIONS:
839Inside the ListenReaderField() function, there is two mode.
840By default, when you call the function, you will enter mode 1.
841If you press the PM3 button one time, you will enter mode 2.
842If you press the PM3 button a second time, you will exit the function.
843
844DESCRIPTION OF MODE 1:
845This mode just listens for an external reader field and lights up green
846for HF and/or red for LF. This is the original mode of the detectreader
847function.
848
849DESCRIPTION OF MODE 2:
850This mode will visually represent, using the LEDs, the actual strength of the
851current compared to the maximum current detected. Basically, once you know
852what kind of external reader is present, it will help you spot the best location to place
853your antenna. You will probably not get some good results if there is a LF and a HF reader
854at the same place! :-)
855
856LIGHT SCHEME USED:
857*/
858static const char LIGHT_SCHEME[] = {
859 0x0, /* ---- | No field detected */
860 0x1, /* X--- | 14% of maximum current detected */
861 0x2, /* -X-- | 29% of maximum current detected */
862 0x4, /* --X- | 43% of maximum current detected */
863 0x8, /* ---X | 57% of maximum current detected */
864 0xC, /* --XX | 71% of maximum current detected */
865 0xE, /* -XXX | 86% of maximum current detected */
866 0xF, /* XXXX | 100% of maximum current detected */
867};
868static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
869
870void ListenReaderField(int limit)
871{
050aa18b 872 int lf_av, lf_av_new=0, lf_baseline= 0, lf_max;
873 int hf_av, hf_av_new=0, hf_baseline= 0, hf_max;
15c4dc5a 874 int mode=1, display_val, display_max, i;
875
050aa18b 876#define LF_ONLY 1
877#define HF_ONLY 2
878#define REPORT_CHANGE_PERCENT 5 // report new values only if they have changed at least by REPORT_CHANGE_PERCENT
879#define MIN_HF_FIELD 300 // in mode 1 signal HF field greater than MIN_HF_FIELD above baseline
880#define MIN_LF_FIELD 1200 // in mode 1 signal LF field greater than MIN_LF_FIELD above baseline
3b692427 881
882
883 // switch off FPGA - we don't want to measure our own signal
884 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
885 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
15c4dc5a 886
887 LEDsoff();
888
050aa18b 889 lf_av = lf_max = AvgAdc_Voltage_LF();
15c4dc5a 890
891 if(limit != HF_ONLY) {
050aa18b 892 Dbprintf("LF 125/134kHz Baseline: %dmV", lf_av);
15c4dc5a 893 lf_baseline = lf_av;
894 }
895
050aa18b 896 hf_av = hf_max = AvgAdc_Voltage_HF();
897
15c4dc5a 898 if (limit != LF_ONLY) {
050aa18b 899 Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av);
15c4dc5a 900 hf_baseline = hf_av;
901 }
902
903 for(;;) {
050aa18b 904 SpinDelay(500);
15c4dc5a 905 if (BUTTON_PRESS()) {
15c4dc5a 906 switch (mode) {
907 case 1:
908 mode=2;
909 DbpString("Signal Strength Mode");
910 break;
911 case 2:
912 default:
913 DbpString("Stopped");
914 LEDsoff();
915 return;
916 break;
917 }
050aa18b 918 while (BUTTON_PRESS());
15c4dc5a 919 }
920 WDT_HIT();
921
922 if (limit != HF_ONLY) {
3b692427 923 if(mode == 1) {
050aa18b 924 if (lf_av - lf_baseline > MIN_LF_FIELD)
3b692427 925 LED_D_ON();
926 else
927 LED_D_OFF();
15c4dc5a 928 }
e30c654b 929
050aa18b 930 lf_av_new = AvgAdc_Voltage_LF();
15c4dc5a 931 // see if there's a significant change
050aa18b 932 if (ABS((lf_av - lf_av_new)*100/(lf_av?lf_av:1)) > REPORT_CHANGE_PERCENT) {
933 Dbprintf("LF 125/134kHz Field Change: %5dmV", lf_av_new);
15c4dc5a 934 lf_av = lf_av_new;
935 if (lf_av > lf_max)
936 lf_max = lf_av;
15c4dc5a 937 }
938 }
939
940 if (limit != LF_ONLY) {
941 if (mode == 1){
050aa18b 942 if (hf_av - hf_baseline > MIN_HF_FIELD)
3b692427 943 LED_B_ON();
944 else
945 LED_B_OFF();
15c4dc5a 946 }
e30c654b 947
050aa18b 948 hf_av_new = AvgAdc_Voltage_HF();
949
15c4dc5a 950 // see if there's a significant change
050aa18b 951 if (ABS((hf_av - hf_av_new)*100/(hf_av?hf_av:1)) > REPORT_CHANGE_PERCENT) {
952 Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new);
15c4dc5a 953 hf_av = hf_av_new;
954 if (hf_av > hf_max)
955 hf_max = hf_av;
15c4dc5a 956 }
957 }
e30c654b 958
15c4dc5a 959 if(mode == 2) {
960 if (limit == LF_ONLY) {
961 display_val = lf_av;
962 display_max = lf_max;
963 } else if (limit == HF_ONLY) {
964 display_val = hf_av;
965 display_max = hf_max;
966 } else { /* Pick one at random */
967 if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
968 display_val = hf_av;
969 display_max = hf_max;
970 } else {
971 display_val = lf_av;
972 display_max = lf_max;
973 }
974 }
975 for (i=0; i<LIGHT_LEN; i++) {
976 if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
977 if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
978 if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
979 if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
980 if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
981 break;
982 }
983 }
984 }
985 }
986}
987
f7e3ed82 988void UsbPacketReceived(uint8_t *packet, int len)
15c4dc5a 989{
990 UsbCommand *c = (UsbCommand *)packet;
15c4dc5a 991
902cb3c0 992// Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]);
993
15c4dc5a 994 switch(c->cmd) {
995#ifdef WITH_LF
31abe49f
MHS
996 case CMD_SET_LF_SAMPLING_CONFIG:
997 setSamplingConfig((sample_config *) c->d.asBytes);
998 break;
15c4dc5a 999 case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
b9957414 1000 cmd_send(CMD_ACK,SampleLF(c->arg[0], c->arg[1]),0,0,0,0);
15c4dc5a 1001 break;
15c4dc5a 1002 case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
1003 ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
1004 break;
b014c96d 1005 case CMD_LF_SNOOP_RAW_ADC_SAMPLES:
31abe49f 1006 cmd_send(CMD_ACK,SnoopLF(),0,0,0,0);
b014c96d 1007 break;
7e67e42f 1008 case CMD_HID_DEMOD_FSK:
be59094d 1009 CmdHIDdemodFSK(c->arg[0], 0, 0, 0, 1);
7e67e42f 1010 break;
1011 case CMD_HID_SIM_TAG:
be59094d 1012 CmdHIDsimTAG(c->arg[0], c->arg[1], c->arg[2], 1);
7e67e42f 1013 break;
abd6112f 1014 case CMD_FSK_SIM_TAG:
1015 CmdFSKsimTAG(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1016 break;
1017 case CMD_ASK_SIM_TAG:
1018 CmdASKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1019 break;
872e3d4d 1020 case CMD_PSK_SIM_TAG:
1021 CmdPSKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1022 break;
1023 case CMD_HID_CLONE_TAG:
5f84531b
SS
1024 CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x1D);
1025 break;
1026 case CMD_PARADOX_CLONE_TAG:
1027 // Paradox cards are the same as HID, with a different preamble, so we can reuse the same function
1028 CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x0F);
7e67e42f 1029 break;
a1f3bb12 1030 case CMD_IO_DEMOD_FSK:
3fe4ff4f 1031 CmdIOdemodFSK(c->arg[0], 0, 0, 1);
a1f3bb12 1032 break;
3fe4ff4f 1033 case CMD_IO_CLONE_TAG:
9f669cb2 1034 CopyIOtoT55x7(c->arg[0], c->arg[1]);
a1f3bb12 1035 break;
66707a3b 1036 case CMD_EM410X_DEMOD:
1037 CmdEM410xdemod(c->arg[0], 0, 0, 1);
1038 break;
2d4eae76 1039 case CMD_EM410X_WRITE_TAG:
1040 WriteEM410x(c->arg[0], c->arg[1], c->arg[2]);
1041 break;
7e67e42f 1042 case CMD_READ_TI_TYPE:
1043 ReadTItag();
1044 break;
1045 case CMD_WRITE_TI_TYPE:
1046 WriteTItag(c->arg[0],c->arg[1],c->arg[2]);
1047 break;
1048 case CMD_SIMULATE_TAG_125K:
31d1caa5 1049 LED_A_ON();
7e67e42f 1050 SimulateTagLowFrequency(c->arg[0], c->arg[1], 1);
31d1caa5 1051 LED_A_OFF();
7e67e42f 1052 break;
1053 case CMD_LF_SIMULATE_BIDIR:
1054 SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);
1055 break;
3fe4ff4f 1056 case CMD_INDALA_CLONE_TAG:
2414f978 1057 CopyIndala64toT55x7(c->arg[0], c->arg[1]);
1058 break;
3fe4ff4f 1059 case CMD_INDALA_CLONE_TAG_L:
2414f978 1060 CopyIndala224toT55x7(c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6]);
1061 break;
1c611bbd 1062 case CMD_T55XX_READ_BLOCK:
8e99ec25 1063 T55xxReadBlock(c->arg[0], c->arg[1], c->arg[2]);
1c611bbd 1064 break;
1065 case CMD_T55XX_WRITE_BLOCK:
1066 T55xxWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]);
1067 break;
be2d41b7 1068 case CMD_T55XX_WAKEUP:
1069 T55xxWakeUp(c->arg[0]);
1c611bbd 1070 break;
66837a03 1071 case CMD_T55XX_RESET_READ:
1072 T55xxResetRead();
1073 break;
3fe4ff4f 1074 case CMD_PCF7931_READ:
1c611bbd 1075 ReadPCF7931();
1c611bbd 1076 break;
dc4300ba 1077 case CMD_PCF7931_WRITE:
d10e08ae 1078 WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]);
dc4300ba 1079 break;
818e15b0
S
1080 case CMD_PCF7931_BRUTEFORCE:
1081 BruteForcePCF7931(c->arg[0], (c->arg[1] & 0xFF), c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128);
1082 break;
1c611bbd 1083 case CMD_EM4X_READ_WORD:
7666f460 1084 EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]);
1c611bbd 1085 break;
1086 case CMD_EM4X_WRITE_WORD:
7666f460 1087 EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]);
1c611bbd 1088 break;
dbf6e824
CY
1089 case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation
1090 CmdAWIDdemodFSK(c->arg[0], 0, 0, 1);
7cfc777b 1091 break;
709665b5 1092 case CMD_VIKING_CLONE_TAG:
1093 CopyVikingtoT55xx(c->arg[0], c->arg[1], c->arg[2]);
1094 break;
e04475c4 1095 case CMD_COTAG:
1096 Cotag(c->arg[0]);
1097 break;
15c4dc5a 1098#endif
1099
d19929cb 1100#ifdef WITH_HITAG
1101 case CMD_SNOOP_HITAG: // Eavesdrop Hitag tag, args = type
1102 SnoopHitag(c->arg[0]);
1103 break;
1104 case CMD_SIMULATE_HITAG: // Simulate Hitag tag, args = memory content
1105 SimulateHitagTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
1106 break;
1107 case CMD_READER_HITAG: // Reader for Hitag tags, args = type and function
1108 ReaderHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes);
1109 break;
4e12287d
RS
1110 case CMD_SIMULATE_HITAG_S:// Simulate Hitag s tag, args = memory content
1111 SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes);
1112 break;
1113 case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file
7b6e3205 1114 check_challenges_cmd((bool)c->arg[0], (byte_t*)c->d.asBytes, (uint8_t)c->arg[1]);
4e12287d
RS
1115 break;
1116 case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge
7b6e3205 1117 ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], false);
1118 break;
1119 case CMD_READ_HITAG_S_BLK:
1120 ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], true);
4e12287d
RS
1121 break;
1122 case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge
52244230
HJ
1123 if ((hitag_function)c->arg[0] < 10) {
1124 WritePageHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes,c->arg[2]);
1125 }
1126 else if ((hitag_function)c->arg[0] >= 10) {
1127 WriterHitag((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes, c->arg[2]);
1128 }
4e12287d 1129 break;
d19929cb 1130#endif
f168b263 1131
15c4dc5a 1132#ifdef WITH_ISO15693
1133 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
1134 AcquireRawAdcSamplesIso15693();
1135 break;
d9de20fa 1136
1137 case CMD_SNOOP_ISO_15693:
1138 SnoopIso15693();
9455b51c 1139 break;
1140
1141 case CMD_ISO_15693_COMMAND:
1142 DirectTag15693Command(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
1143 break;
1144
1145 case CMD_ISO_15693_FIND_AFI:
1146 BruteforceIso15693Afi(c->arg[0]);
1147 break;
1148
1149 case CMD_ISO_15693_DEBUG:
1150 SetDebugIso15693(c->arg[0]);
1151 break;
15c4dc5a 1152
15c4dc5a 1153 case CMD_READER_ISO_15693:
1154 ReaderIso15693(c->arg[0]);
1155 break;
7e67e42f 1156 case CMD_SIMTAG_ISO_15693:
3fe4ff4f 1157 SimTagIso15693(c->arg[0], c->d.asBytes);
7e67e42f 1158 break;
15c4dc5a 1159#endif
1160
7e67e42f 1161#ifdef WITH_LEGICRF
1162 case CMD_SIMULATE_TAG_LEGIC_RF:
1b902aa0 1163 LegicRfSimulate(c->arg[0]);
7e67e42f 1164 break;
3612a8a8 1165
7e67e42f 1166 case CMD_WRITER_LEGIC_RF:
1167 LegicRfWriter(c->arg[1], c->arg[0]);
1168 break;
3612a8a8 1169
15c4dc5a 1170 case CMD_READER_LEGIC_RF:
1171 LegicRfReader(c->arg[0], c->arg[1]);
1172 break;
15c4dc5a 1173#endif
1174
1175#ifdef WITH_ISO14443b
15c4dc5a 1176 case CMD_READ_SRI512_TAG:
51d4f6f1 1177 ReadSTMemoryIso14443b(0x0F);
15c4dc5a 1178 break;
7e67e42f 1179 case CMD_READ_SRIX4K_TAG:
51d4f6f1 1180 ReadSTMemoryIso14443b(0x7F);
7e67e42f 1181 break;
132a0217 1182 case CMD_SNOOP_ISO_14443B:
51d4f6f1 1183 SnoopIso14443b();
7e67e42f 1184 break;
132a0217 1185 case CMD_SIMULATE_TAG_ISO_14443B:
51d4f6f1 1186 SimulateIso14443bTag();
7e67e42f 1187 break;
7cf3ef20 1188 case CMD_ISO_14443B_COMMAND:
1189 SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
1190 break;
15c4dc5a 1191#endif
1192
1193#ifdef WITH_ISO14443a
7e67e42f 1194 case CMD_SNOOP_ISO_14443a:
5cd9ec01 1195 SnoopIso14443a(c->arg[0]);
7e67e42f 1196 break;
15c4dc5a 1197 case CMD_READER_ISO_14443a:
902cb3c0 1198 ReaderIso14443a(c);
15c4dc5a 1199 break;
7e67e42f 1200 case CMD_SIMULATE_TAG_ISO_14443a:
28afbd2b 1201 SimulateIso14443aTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); // ## Simulate iso14443a tag - pass tag type & UID
7e67e42f 1202 break;
3fe4ff4f 1203
5acd09bd 1204 case CMD_EPA_PACE_COLLECT_NONCE:
902cb3c0 1205 EPA_PACE_Collect_Nonce(c);
5acd09bd 1206 break;
3bb07d96
FM
1207 case CMD_EPA_PACE_REPLAY:
1208 EPA_PACE_Replay(c);
1209 break;
7e67e42f 1210
15c4dc5a 1211 case CMD_READER_MIFARE:
f168b263 1212 ReaderMifare(c->arg[0]);
15c4dc5a 1213 break;
20f9a2a1
M
1214 case CMD_MIFARE_READBL:
1215 MifareReadBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1216 break;
981bd429 1217 case CMD_MIFAREU_READBL:
f168b263 1218 MifareUReadBlock(c->arg[0],c->arg[1], c->d.asBytes);
981bd429 1219 break;
8258f409 1220 case CMD_MIFAREUC_AUTH:
1221 MifareUC_Auth(c->arg[0],c->d.asBytes);
a631936e 1222 break;
981bd429 1223 case CMD_MIFAREU_READCARD:
75377d29 1224 MifareUReadCard(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
117d9ec2 1225 break;
f168b263 1226 case CMD_MIFAREUC_SETPWD:
1227 MifareUSetPwd(c->arg[0], c->d.asBytes);
1228 break;
20f9a2a1
M
1229 case CMD_MIFARE_READSC:
1230 MifareReadSector(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1231 break;
1232 case CMD_MIFARE_WRITEBL:
1233 MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1234 break;
4973f23d 1235 //case CMD_MIFAREU_WRITEBL_COMPAT:
1236 //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes);
1237 //break;
981bd429 1238 case CMD_MIFAREU_WRITEBL:
4973f23d 1239 MifareUWriteBlock(c->arg[0], c->arg[1], c->d.asBytes);
f168b263 1240 break;
c48c4d78 1241 case CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES:
1242 MifareAcquireEncryptedNonces(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1243 break;
20f9a2a1
M
1244 case CMD_MIFARE_NESTED:
1245 MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
f397b5cc
M
1246 break;
1247 case CMD_MIFARE_CHKKEYS:
1248 MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
20f9a2a1
M
1249 break;
1250 case CMD_SIMULATE_MIFARE_CARD:
1251 Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1252 break;
8556b852
M
1253
1254 // emulator
1255 case CMD_MIFARE_SET_DBGMODE:
1256 MifareSetDbgLvl(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1257 break;
1258 case CMD_MIFARE_EML_MEMCLR:
1259 MifareEMemClr(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1260 break;
1261 case CMD_MIFARE_EML_MEMSET:
1262 MifareEMemSet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1263 break;
1264 case CMD_MIFARE_EML_MEMGET:
1265 MifareEMemGet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1266 break;
1267 case CMD_MIFARE_EML_CARDLOAD:
1268 MifareECardLoad(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
0675f200
M
1269 break;
1270
1271 // Work with "magic Chinese" card
3a05a1e7
OM
1272 case CMD_MIFARE_CWIPE:
1273 MifareCWipe(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1274 break;
3fe4ff4f 1275 case CMD_MIFARE_CSETBLOCK:
0675f200 1276 MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
545a1f38 1277 break;
3fe4ff4f 1278 case CMD_MIFARE_CGETBLOCK:
545a1f38 1279 MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
8556b852 1280 break;
3fe4ff4f 1281 case CMD_MIFARE_CIDENT:
1282 MifareCIdent();
1283 break;
b62a5a84
M
1284
1285 // mifare sniffer
1286 case CMD_MIFARE_SNIFFER:
5cd9ec01 1287 SniffMifare(c->arg[0]);
b62a5a84 1288 break;
a631936e 1289
20f9a2a1
M
1290#endif
1291
7e67e42f 1292#ifdef WITH_ICLASS
cee5a30d 1293 // Makes use of ISO14443a FPGA Firmware
1294 case CMD_SNOOP_ICLASS:
1295 SnoopIClass();
1296 break;
1e262141 1297 case CMD_SIMULATE_TAG_ICLASS:
ff7bb4ef 1298 SimulateIClass(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
1e262141 1299 break;
1300 case CMD_READER_ICLASS:
1301 ReaderIClass(c->arg[0]);
1302 break;
c3963755 1303 case CMD_READER_ICLASS_REPLAY:
aa53efc3 1304 ReaderIClass_Replay(c->arg[0], c->d.asBytes);
c3963755 1305 break;
aa53efc3 1306 case CMD_ICLASS_EML_MEMSET:
e80aeb96
MHS
1307 emlSet(c->d.asBytes,c->arg[0], c->arg[1]);
1308 break;
aa53efc3 1309 case CMD_ICLASS_WRITEBLOCK:
3ac22ee1 1310 iClass_WriteBlock(c->arg[0], c->d.asBytes);
1311 break;
1312 case CMD_ICLASS_READCHECK: // auth step 1
1313 iClass_ReadCheck(c->arg[0], c->arg[1]);
aa53efc3 1314 break;
1315 case CMD_ICLASS_READBLOCK:
3ac22ee1 1316 iClass_ReadBlk(c->arg[0]);
aa53efc3 1317 break;
3ac22ee1 1318 case CMD_ICLASS_AUTHENTICATION: //check
aa53efc3 1319 iClass_Authentication(c->d.asBytes);
1320 break;
1321 case CMD_ICLASS_DUMP:
3ac22ee1 1322 iClass_Dump(c->arg[0], c->arg[1]);
aa53efc3 1323 break;
1324 case CMD_ICLASS_CLONE:
3ac22ee1 1325 iClass_Clone(c->arg[0], c->arg[1], c->d.asBytes);
aa53efc3 1326 break;
cee5a30d 1327#endif
fc52fbd4 1328
0472d76d 1329#ifdef WITH_HFSNOOP
1330 case CMD_HF_SNIFFER:
1331 HfSnoop(c->arg[0], c->arg[1]);
1332 break;
fc52fbd4 1333 case CMD_HF_PLOT:
1334 HfPlot();
1335 break;
0472d76d 1336#endif
fc52fbd4 1337
43591e64 1338#ifdef WITH_SMARTCARD
1339 case CMD_SMART_ATR: {
1340 SmartCardAtr();
1341 break;
1342 }
1343 case CMD_SMART_SETCLOCK:{
1344 SmartCardSetClock(c->arg[0]);
1345 break;
1346 }
1347 case CMD_SMART_RAW: {
1348 SmartCardRaw(c->arg[0], c->arg[1], c->d.asBytes);
1349 break;
1350 }
1351 case CMD_SMART_UPLOAD: {
1352 // upload file from client
1353 uint8_t *mem = BigBuf_get_addr();
1354 memcpy( mem + c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE);
1355 cmd_send(CMD_ACK,1,0,0,0,0);
1356 break;
1357 }
1358 case CMD_SMART_UPGRADE: {
1359 SmartCardUpgrade(c->arg[0]);
1360 break;
1361 }
1362#endif
cee5a30d 1363
7e67e42f 1364 case CMD_BUFF_CLEAR:
117d9ec2 1365 BigBuf_Clear();
15c4dc5a 1366 break;
15c4dc5a 1367
1368 case CMD_MEASURE_ANTENNA_TUNING:
fdcfbdcc 1369 MeasureAntennaTuning(c->arg[0]);
15c4dc5a 1370 break;
1371
1372 case CMD_MEASURE_ANTENNA_TUNING_HF:
1373 MeasureAntennaTuningHf();
1374 break;
1375
1376 case CMD_LISTEN_READER_FIELD:
1377 ListenReaderField(c->arg[0]);
1378 break;
1379
15c4dc5a 1380 case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
1381 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1382 SpinDelay(200);
1383 LED_D_OFF(); // LED D indicates field ON or OFF
1384 break;
1385
1c611bbd 1386 case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K:
1c611bbd 1387 LED_B_ON();
117d9ec2 1388 uint8_t *BigBuf = BigBuf_get_addr();
1c611bbd 1389 for(size_t i=0; i<c->arg[1]; i += USB_CMD_DATA_SIZE) {
1390 size_t len = MIN((c->arg[1] - i),USB_CMD_DATA_SIZE);
3000dc4e 1391 cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,i,len,BigBuf_get_traceLen(),BigBuf+c->arg[0]+i,len);
1c611bbd 1392 }
1393 // Trigger a finish downloading signal with an ACK frame
3000dc4e 1394 cmd_send(CMD_ACK,1,0,BigBuf_get_traceLen(),getSamplingConfig(),sizeof(sample_config));
d3b1f4e4 1395 LED_B_OFF();
1c611bbd 1396 break;
15c4dc5a 1397
1398 case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
8c8317a5 1399 // iceman; since changing fpga_bitstreams clears bigbuff, Its better to call it before.
1400 // to be able to use this one for uploading data to device
1401 // arg1 = 0 upload for LF usage
1402 // 1 upload for HF usage
1403 if (c->arg[1] == 0)
1404 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
1405 else
1406 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
1407
117d9ec2 1408 uint8_t *b = BigBuf_get_addr();
3fe4ff4f 1409 memcpy(b+c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE);
1c611bbd 1410 cmd_send(CMD_ACK,0,0,0,0,0);
1411 break;
1412 }
15c4dc5a 1413 case CMD_READ_MEM:
1414 ReadMem(c->arg[0]);
1415 break;
1416
1417 case CMD_SET_LF_DIVISOR:
8c8317a5 1418 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
15c4dc5a 1419 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);
1420 break;
1421
1422 case CMD_SET_ADC_MUX:
1423 switch(c->arg[0]) {
1424 case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break;
1425 case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break;
1426 case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break;
1427 case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break;
1428 }
1429 break;
1430
1431 case CMD_VERSION:
1432 SendVersion();
1433 break;
c89274cc 1434 case CMD_STATUS:
67b7d6fa 1435 SendStatus();
c89274cc
CY
1436 break;
1437 case CMD_PING:
1438 cmd_send(CMD_ACK,0,0,0,0,0);
1439 break;
15c4dc5a 1440#ifdef WITH_LCD
1441 case CMD_LCD_RESET:
1442 LCDReset();
1443 break;
1444 case CMD_LCD:
1445 LCDSend(c->arg[0]);
1446 break;
1447#endif
1448 case CMD_SETUP_WRITE:
1449 case CMD_FINISH_WRITE:
1c611bbd 1450 case CMD_HARDWARE_RESET:
1451 usb_disable();
15c4dc5a 1452 SpinDelay(1000);
1453 SpinDelay(1000);
1454 AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
1455 for(;;) {
1456 // We're going to reset, and the bootrom will take control.
1457 }
1c611bbd 1458 break;
15c4dc5a 1459
1c611bbd 1460 case CMD_START_FLASH:
15c4dc5a 1461 if(common_area.flags.bootrom_present) {
1462 common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;
1463 }
1c611bbd 1464 usb_disable();
15c4dc5a 1465 AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
1466 for(;;);
1c611bbd 1467 break;
e30c654b 1468
15c4dc5a 1469 case CMD_DEVICE_INFO: {
902cb3c0 1470 uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
1471 if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
1c611bbd 1472 cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0);
1473 break;
1474 }
1475 default:
15c4dc5a 1476 Dbprintf("%s: 0x%04x","unknown command:",c->cmd);
1c611bbd 1477 break;
15c4dc5a 1478 }
1479}
1480
1481void __attribute__((noreturn)) AppMain(void)
1482{
1483 SpinDelay(100);
9e8255d4 1484 clear_trace();
15c4dc5a 1485 if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
1486 /* Initialize common area */
1487 memset(&common_area, 0, sizeof(common_area));
1488 common_area.magic = COMMON_AREA_MAGIC;
1489 common_area.version = 1;
1490 }
1491 common_area.flags.osimage_present = 1;
1492
3d057cfb
SG
1493 LEDsoff();
1494
3fe4ff4f 1495 // Init USB device
050aa18b 1496 usb_enable();
15c4dc5a 1497
1498 // The FPGA gets its clock from us from PCK0 output, so set that up.
1499 AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;
1500 AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0;
1501 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0;
1502 // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
1503 AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK |
0472d76d 1504 AT91C_PMC_PRES_CLK_4; // 4 for 24Mhz pck0, 2 for 48 MHZ pck0
15c4dc5a 1505 AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0;
1506
1507 // Reset SPI
1508 AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
1509 // Reset SSC
1510 AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
1511
1512 // Load the FPGA image, which we have stored in our flash.
7cc204bf 1513 // (the HF version by default)
1514 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
15c4dc5a 1515
9ca155ba 1516 StartTickCount();
902cb3c0 1517
15c4dc5a 1518#ifdef WITH_LCD
15c4dc5a 1519 LCDInit();
15c4dc5a 1520#endif
1521
902cb3c0 1522 byte_t rx[sizeof(UsbCommand)];
1523 size_t rx_len;
1524
15c4dc5a 1525 for(;;) {
902cb3c0 1526 if (usb_poll()) {
1527 rx_len = usb_read(rx,sizeof(UsbCommand));
1528 if (rx_len) {
1529 UsbPacketReceived(rx,rx_len);
1530 }
1531 }
15c4dc5a 1532 WDT_HIT();
1533
a2937cea 1534#ifdef WITH_LF_StandAlone
e46fe044 1535#ifndef WITH_ISO14443a_StandAlone
15c4dc5a 1536 if (BUTTON_HELD(1000) > 0)
1537 SamyRun();
e46fe044
CY
1538#endif
1539#endif
1540#ifdef WITH_ISO14443a
1541#ifdef WITH_ISO14443a_StandAlone
1542 if (BUTTON_HELD(1000) > 0)
1543 StandAloneMode14a();
1544#endif
15c4dc5a 1545#endif
1546 }
1547}
Impressum, Datenschutz