]> cvs.zerfleddert.de Git - proxmark3-svn/blob - armsrc/appmain.c
Added hitune command for continuously measuring HF antenna tuning
[proxmark3-svn] / armsrc / appmain.c
1 //-----------------------------------------------------------------------------
2 // The main application code. This is the first thing called after start.c
3 // executes.
4 // Jonathan Westhues, Mar 2006
5 // Edits by Gerhard de Koning Gans, Sep 2007 (##)
6 //-----------------------------------------------------------------------------
7
8 #include <proxmark3.h>
9 #include <stdlib.h>
10 #include "apps.h"
11 #include "legicrf.h"
12 #ifdef WITH_LCD
13 #include "fonts.h"
14 #include "LCD.h"
15 #endif
16
17 #define va_list __builtin_va_list
18 #define va_start __builtin_va_start
19 #define va_arg __builtin_va_arg
20 #define va_end __builtin_va_end
21 int kvsprintf(char const *fmt, void *arg, int radix, va_list ap);
22
23 //=============================================================================
24 // A buffer where we can queue things up to be sent through the FPGA, for
25 // any purpose (fake tag, as reader, whatever). We go MSB first, since that
26 // is the order in which they go out on the wire.
27 //=============================================================================
28
29 BYTE ToSend[256];
30 int ToSendMax;
31 static int ToSendBit;
32 struct common_area common_area __attribute__((section(".commonarea")));
33
34 void BufferClear(void)
35 {
36 memset(BigBuf,0,sizeof(BigBuf));
37 DbpString("Buffer cleared");
38 }
39
40 void ToSendReset(void)
41 {
42 ToSendMax = -1;
43 ToSendBit = 8;
44 }
45
46 void ToSendStuffBit(int b)
47 {
48 if(ToSendBit >= 8) {
49 ToSendMax++;
50 ToSend[ToSendMax] = 0;
51 ToSendBit = 0;
52 }
53
54 if(b) {
55 ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
56 }
57
58 ToSendBit++;
59
60 if(ToSendBit >= sizeof(ToSend)) {
61 ToSendBit = 0;
62 DbpString("ToSendStuffBit overflowed!");
63 }
64 }
65
66 //=============================================================================
67 // Debug print functions, to go out over USB, to the usual PC-side client.
68 //=============================================================================
69
70 void DbpString(char *str)
71 {
72 /* this holds up stuff unless we're connected to usb */
73 if (!UsbConnected())
74 return;
75
76 UsbCommand c;
77 c.cmd = CMD_DEBUG_PRINT_STRING;
78 c.arg[0] = strlen(str);
79 memcpy(c.d.asBytes, str, c.arg[0]);
80
81 UsbSendPacket((BYTE *)&c, sizeof(c));
82 // TODO fix USB so stupid things like this aren't req'd
83 SpinDelay(50);
84 }
85
86 #if 0
87 void DbpIntegers(int x1, int x2, int x3)
88 {
89 /* this holds up stuff unless we're connected to usb */
90 if (!UsbConnected())
91 return;
92
93 UsbCommand c;
94 c.cmd = CMD_DEBUG_PRINT_INTEGERS;
95 c.arg[0] = x1;
96 c.arg[1] = x2;
97 c.arg[2] = x3;
98
99 UsbSendPacket((BYTE *)&c, sizeof(c));
100 // XXX
101 SpinDelay(50);
102 }
103 #endif
104
105 void Dbprintf(const char *fmt, ...) {
106 // should probably limit size here; oh well, let's just use a big buffer
107 char output_string[128];
108 va_list ap;
109
110 va_start(ap, fmt);
111 kvsprintf(fmt, output_string, 10, ap);
112 va_end(ap);
113
114 DbpString(output_string);
115 }
116
117 //-----------------------------------------------------------------------------
118 // Read an ADC channel and block till it completes, then return the result
119 // in ADC units (0 to 1023). Also a routine to average 32 samples and
120 // return that.
121 //-----------------------------------------------------------------------------
122 static int ReadAdc(int ch)
123 {
124 DWORD d;
125
126 AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
127 AT91C_BASE_ADC->ADC_MR =
128 ADC_MODE_PRESCALE(32) |
129 ADC_MODE_STARTUP_TIME(16) |
130 ADC_MODE_SAMPLE_HOLD_TIME(8);
131 AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);
132
133 AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
134 while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch)))
135 ;
136 d = AT91C_BASE_ADC->ADC_CDR[ch];
137
138 return d;
139 }
140
141 static int AvgAdc(int ch)
142 {
143 int i;
144 int a = 0;
145
146 for(i = 0; i < 32; i++) {
147 a += ReadAdc(ch);
148 }
149
150 return (a + 15) >> 5;
151 }
152
153 void MeasureAntennaTuning(void)
154 {
155 BYTE *dest = (BYTE *)BigBuf;
156 int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;
157 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
158
159 UsbCommand c;
160
161 DbpString("Measuring antenna characteristics, please wait.");
162 memset(BigBuf,0,sizeof(BigBuf));
163
164 /*
165 * Sweeps the useful LF range of the proxmark from
166 * 46.8kHz (divisor=255) to 600kHz (divisor=19) and
167 * read the voltage in the antenna, the result left
168 * in the buffer is a graph which should clearly show
169 * the resonating frequency of your LF antenna
170 * ( hopefully around 95 if it is tuned to 125kHz!)
171 */
172 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
173 for (i=255; i>19; i--) {
174 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
175 SpinDelay(20);
176 // Vref = 3.3V, and a 10000:240 voltage divider on the input
177 // can measure voltages up to 137500 mV
178 adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);
179 if (i==95) vLf125 = adcval; // voltage at 125Khz
180 if (i==89) vLf134 = adcval; // voltage at 134Khz
181
182 dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes
183 if(dest[i] > peak) {
184 peakv = adcval;
185 peak = dest[i];
186 peakf = i;
187 ptr = i;
188 }
189 }
190
191 // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
192 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
193 SpinDelay(20);
194 // Vref = 3300mV, and an 10:1 voltage divider on the input
195 // can measure voltages up to 33000 mV
196 vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
197
198 c.cmd = CMD_MEASURED_ANTENNA_TUNING;
199 c.arg[0] = (vLf125 << 0) | (vLf134 << 16);
200 c.arg[1] = vHf;
201 c.arg[2] = peakf | (peakv << 16);
202 UsbSendPacket((BYTE *)&c, sizeof(c));
203 }
204
205 void MeasureAntennaTuningHf(void)
206 {
207 int vHf = 0; // in mV
208
209 DbpString("Measuring HF antenna characteristics, press button to exit");
210
211 for (;;) {
212 // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
213 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
214 SpinDelay(20);
215 // Vref = 3300mV, and an 10:1 voltage divider on the input
216 // can measure voltages up to 33000 mV
217 vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
218
219 Dbprintf("%d mV",vHf);
220 if (BUTTON_PRESS()) break;
221 }
222 DbpString("cancelled");
223 }
224
225
226 void SimulateTagHfListen(void)
227 {
228 BYTE *dest = (BYTE *)BigBuf;
229 int n = sizeof(BigBuf);
230 BYTE v = 0;
231 int i;
232 int p = 0;
233
234 // We're using this mode just so that I can test it out; the simulated
235 // tag mode would work just as well and be simpler.
236 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
237
238 // We need to listen to the high-frequency, peak-detected path.
239 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
240
241 FpgaSetupSsc();
242
243 i = 0;
244 for(;;) {
245 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
246 AT91C_BASE_SSC->SSC_THR = 0xff;
247 }
248 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
249 BYTE r = (BYTE)AT91C_BASE_SSC->SSC_RHR;
250
251 v <<= 1;
252 if(r & 1) {
253 v |= 1;
254 }
255 p++;
256
257 if(p >= 8) {
258 dest[i] = v;
259 v = 0;
260 p = 0;
261 i++;
262
263 if(i >= n) {
264 break;
265 }
266 }
267 }
268 }
269 DbpString("simulate tag (now type bitsamples)");
270 }
271
272 void ReadMem(int addr)
273 {
274 const DWORD *data = ((DWORD *)addr);
275
276 Dbprintf("%x: %02x %02x %02x %02x %02x %02x %02x %02x",
277 addr, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
278 }
279
280 /* osimage version information is linked in */
281 extern struct version_information version_information;
282 /* bootrom version information is pointed to from _bootphase1_version_pointer */
283 extern char *_bootphase1_version_pointer, _flash_start, _flash_end;
284 void SendVersion(void)
285 {
286 char temp[48]; /* Limited data payload in USB packets */
287 DbpString("Prox/RFID mark3 RFID instrument");
288
289 /* Try to find the bootrom version information. Expect to find a pointer at
290 * symbol _bootphase1_version_pointer, perform slight sanity checks on the
291 * pointer, then use it.
292 */
293 char *bootrom_version = *(char**)&_bootphase1_version_pointer;
294 if( bootrom_version < &_flash_start || bootrom_version >= &_flash_end ) {
295 DbpString("bootrom version information appears invalid");
296 } else {
297 FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
298 DbpString(temp);
299 }
300
301 FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
302 DbpString(temp);
303
304 FpgaGatherVersion(temp, sizeof(temp));
305 DbpString(temp);
306 }
307
308 #ifdef WITH_LF
309 // samy's sniff and repeat routine
310 void SamyRun()
311 {
312 DbpString("Stand-alone mode! No PC necessary.");
313
314 // 3 possible options? no just 2 for now
315 #define OPTS 2
316
317 int high[OPTS], low[OPTS];
318
319 // Oooh pretty -- notify user we're in elite samy mode now
320 LED(LED_RED, 200);
321 LED(LED_ORANGE, 200);
322 LED(LED_GREEN, 200);
323 LED(LED_ORANGE, 200);
324 LED(LED_RED, 200);
325 LED(LED_ORANGE, 200);
326 LED(LED_GREEN, 200);
327 LED(LED_ORANGE, 200);
328 LED(LED_RED, 200);
329
330 int selected = 0;
331 int playing = 0;
332
333 // Turn on selected LED
334 LED(selected + 1, 0);
335
336 for (;;)
337 {
338 UsbPoll(FALSE);
339 WDT_HIT();
340
341 // Was our button held down or pressed?
342 int button_pressed = BUTTON_HELD(1000);
343 SpinDelay(300);
344
345 // Button was held for a second, begin recording
346 if (button_pressed > 0)
347 {
348 LEDsoff();
349 LED(selected + 1, 0);
350 LED(LED_RED2, 0);
351
352 // record
353 DbpString("Starting recording");
354
355 // wait for button to be released
356 while(BUTTON_PRESS())
357 WDT_HIT();
358
359 /* need this delay to prevent catching some weird data */
360 SpinDelay(500);
361
362 CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
363 Dbprintf("Recorded %x %x %x", selected, high[selected], low[selected]);
364
365 LEDsoff();
366 LED(selected + 1, 0);
367 // Finished recording
368
369 // If we were previously playing, set playing off
370 // so next button push begins playing what we recorded
371 playing = 0;
372 }
373
374 // Change where to record (or begin playing)
375 else if (button_pressed)
376 {
377 // Next option if we were previously playing
378 if (playing)
379 selected = (selected + 1) % OPTS;
380 playing = !playing;
381
382 LEDsoff();
383 LED(selected + 1, 0);
384
385 // Begin transmitting
386 if (playing)
387 {
388 LED(LED_GREEN, 0);
389 DbpString("Playing");
390 // wait for button to be released
391 while(BUTTON_PRESS())
392 WDT_HIT();
393 Dbprintf("%x %x %x", selected, high[selected], low[selected]);
394 CmdHIDsimTAG(high[selected], low[selected], 0);
395 DbpString("Done playing");
396 if (BUTTON_HELD(1000) > 0)
397 {
398 DbpString("Exiting");
399 LEDsoff();
400 return;
401 }
402
403 /* We pressed a button so ignore it here with a delay */
404 SpinDelay(300);
405
406 // when done, we're done playing, move to next option
407 selected = (selected + 1) % OPTS;
408 playing = !playing;
409 LEDsoff();
410 LED(selected + 1, 0);
411 }
412 else
413 while(BUTTON_PRESS())
414 WDT_HIT();
415 }
416 }
417 }
418 #endif
419
420 /*
421 OBJECTIVE
422 Listen and detect an external reader. Determine the best location
423 for the antenna.
424
425 INSTRUCTIONS:
426 Inside the ListenReaderField() function, there is two mode.
427 By default, when you call the function, you will enter mode 1.
428 If you press the PM3 button one time, you will enter mode 2.
429 If you press the PM3 button a second time, you will exit the function.
430
431 DESCRIPTION OF MODE 1:
432 This mode just listens for an external reader field and lights up green
433 for HF and/or red for LF. This is the original mode of the detectreader
434 function.
435
436 DESCRIPTION OF MODE 2:
437 This mode will visually represent, using the LEDs, the actual strength of the
438 current compared to the maximum current detected. Basically, once you know
439 what kind of external reader is present, it will help you spot the best location to place
440 your antenna. You will probably not get some good results if there is a LF and a HF reader
441 at the same place! :-)
442
443 LIGHT SCHEME USED:
444 */
445 static const char LIGHT_SCHEME[] = {
446 0x0, /* ---- | No field detected */
447 0x1, /* X--- | 14% of maximum current detected */
448 0x2, /* -X-- | 29% of maximum current detected */
449 0x4, /* --X- | 43% of maximum current detected */
450 0x8, /* ---X | 57% of maximum current detected */
451 0xC, /* --XX | 71% of maximum current detected */
452 0xE, /* -XXX | 86% of maximum current detected */
453 0xF, /* XXXX | 100% of maximum current detected */
454 };
455 static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
456
457 void ListenReaderField(int limit)
458 {
459 int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;
460 int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;
461 int mode=1, display_val, display_max, i;
462
463 #define LF_ONLY 1
464 #define HF_ONLY 2
465
466 LEDsoff();
467
468 lf_av=lf_max=ReadAdc(ADC_CHAN_LF);
469
470 if(limit != HF_ONLY) {
471 Dbprintf("LF 125/134 Baseline: %d", lf_av);
472 lf_baseline = lf_av;
473 }
474
475 hf_av=hf_max=ReadAdc(ADC_CHAN_HF);
476
477 if (limit != LF_ONLY) {
478 Dbprintf("HF 13.56 Baseline: %d", hf_av);
479 hf_baseline = hf_av;
480 }
481
482 for(;;) {
483 if (BUTTON_PRESS()) {
484 SpinDelay(500);
485 switch (mode) {
486 case 1:
487 mode=2;
488 DbpString("Signal Strength Mode");
489 break;
490 case 2:
491 default:
492 DbpString("Stopped");
493 LEDsoff();
494 return;
495 break;
496 }
497 }
498 WDT_HIT();
499
500 if (limit != HF_ONLY) {
501 if(mode==1) {
502 if (abs(lf_av - lf_baseline) > 10) LED_D_ON();
503 else LED_D_OFF();
504 }
505
506 ++lf_count;
507 lf_av_new= ReadAdc(ADC_CHAN_LF);
508 // see if there's a significant change
509 if(abs(lf_av - lf_av_new) > 10) {
510 Dbprintf("LF 125/134 Field Change: %x %x %x", lf_av, lf_av_new, lf_count);
511 lf_av = lf_av_new;
512 if (lf_av > lf_max)
513 lf_max = lf_av;
514 lf_count= 0;
515 }
516 }
517
518 if (limit != LF_ONLY) {
519 if (mode == 1){
520 if (abs(hf_av - hf_baseline) > 10) LED_B_ON();
521 else LED_B_OFF();
522 }
523
524 ++hf_count;
525 hf_av_new= ReadAdc(ADC_CHAN_HF);
526 // see if there's a significant change
527 if(abs(hf_av - hf_av_new) > 10) {
528 Dbprintf("HF 13.56 Field Change: %x %x %x", hf_av, hf_av_new, hf_count);
529 hf_av = hf_av_new;
530 if (hf_av > hf_max)
531 hf_max = hf_av;
532 hf_count= 0;
533 }
534 }
535
536 if(mode == 2) {
537 if (limit == LF_ONLY) {
538 display_val = lf_av;
539 display_max = lf_max;
540 } else if (limit == HF_ONLY) {
541 display_val = hf_av;
542 display_max = hf_max;
543 } else { /* Pick one at random */
544 if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
545 display_val = hf_av;
546 display_max = hf_max;
547 } else {
548 display_val = lf_av;
549 display_max = lf_max;
550 }
551 }
552 for (i=0; i<LIGHT_LEN; i++) {
553 if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
554 if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
555 if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
556 if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
557 if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
558 break;
559 }
560 }
561 }
562 }
563 }
564
565 void UsbPacketReceived(BYTE *packet, int len)
566 {
567 UsbCommand *c = (UsbCommand *)packet;
568
569 switch(c->cmd) {
570 #ifdef WITH_LF
571 case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
572 AcquireRawAdcSamples125k(c->arg[0]);
573 break;
574 #endif
575
576 #ifdef WITH_LF
577 case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
578 ModThenAcquireRawAdcSamples125k(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes);
579 break;
580 #endif
581
582 #ifdef WITH_ISO15693
583 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
584 AcquireRawAdcSamplesIso15693();
585 break;
586 #endif
587
588 case CMD_BUFF_CLEAR:
589 BufferClear();
590 break;
591
592 #ifdef WITH_ISO15693
593 case CMD_READER_ISO_15693:
594 ReaderIso15693(c->arg[0]);
595 break;
596 #endif
597
598 case CMD_READER_LEGIC_RF:
599 LegicRfReader();
600 break;
601
602 #ifdef WITH_ISO15693
603 case CMD_SIMTAG_ISO_15693:
604 SimTagIso15693(c->arg[0]);
605 break;
606 #endif
607
608 #ifdef WITH_ISO14443b
609 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
610 AcquireRawAdcSamplesIso14443(c->arg[0]);
611 break;
612 #endif
613
614 #ifdef WITH_ISO14443b
615 case CMD_READ_SRI512_TAG:
616 ReadSRI512Iso14443(c->arg[0]);
617 break;
618 case CMD_READ_SRIX4K_TAG:
619 ReadSRIX4KIso14443(c->arg[0]);
620 break;
621 #endif
622
623 #ifdef WITH_ISO14443a
624 case CMD_READER_ISO_14443a:
625 ReaderIso14443a(c->arg[0]);
626 break;
627 #endif
628
629 #ifdef WITH_ISO14443a
630 case CMD_READER_MIFARE:
631 ReaderMifare(c->arg[0]);
632 break;
633 #endif
634
635 #ifdef WITH_ISO14443b
636 case CMD_SNOOP_ISO_14443:
637 SnoopIso14443();
638 break;
639 #endif
640
641 #ifdef WITH_ISO14443a
642 case CMD_SNOOP_ISO_14443a:
643 SnoopIso14443a();
644 break;
645 #endif
646
647 case CMD_SIMULATE_TAG_HF_LISTEN:
648 SimulateTagHfListen();
649 break;
650
651 #ifdef WITH_ISO14443b
652 case CMD_SIMULATE_TAG_ISO_14443:
653 SimulateIso14443Tag();
654 break;
655 #endif
656
657 #ifdef WITH_ISO14443a
658 case CMD_SIMULATE_TAG_ISO_14443a:
659 SimulateIso14443aTag(c->arg[0], c->arg[1]); // ## Simulate iso14443a tag - pass tag type & UID
660 break;
661 #endif
662
663 case CMD_MEASURE_ANTENNA_TUNING:
664 MeasureAntennaTuning();
665 break;
666
667 case CMD_MEASURE_ANTENNA_TUNING_HF:
668 MeasureAntennaTuningHf();
669 break;
670
671 case CMD_LISTEN_READER_FIELD:
672 ListenReaderField(c->arg[0]);
673 break;
674
675 #ifdef WITH_LF
676 case CMD_HID_DEMOD_FSK:
677 CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
678 break;
679 #endif
680
681 #ifdef WITH_LF
682 case CMD_HID_SIM_TAG:
683 CmdHIDsimTAG(c->arg[0], c->arg[1], 1); // Simulate HID tag by ID
684 break;
685 #endif
686
687 case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
688 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
689 SpinDelay(200);
690 LED_D_OFF(); // LED D indicates field ON or OFF
691 break;
692
693 #ifdef WITH_LF
694 case CMD_READ_TI_TYPE:
695 ReadTItag();
696 break;
697 #endif
698
699 #ifdef WITH_LF
700 case CMD_WRITE_TI_TYPE:
701 WriteTItag(c->arg[0],c->arg[1],c->arg[2]);
702 break;
703 #endif
704
705 case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {
706 UsbCommand n;
707 if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
708 n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
709 } else {
710 n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
711 }
712 n.arg[0] = c->arg[0];
713 memcpy(n.d.asDwords, BigBuf+c->arg[0], 12*sizeof(DWORD));
714 UsbSendPacket((BYTE *)&n, sizeof(n));
715 break;
716 }
717
718 case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
719 BYTE *b = (BYTE *)BigBuf;
720 memcpy(b+c->arg[0], c->d.asBytes, 48);
721 break;
722 }
723
724 #ifdef WITH_LF
725 case CMD_SIMULATE_TAG_125K:
726 LED_A_ON();
727 SimulateTagLowFrequency(c->arg[0], 1);
728 LED_A_OFF();
729 break;
730 #endif
731
732 case CMD_READ_MEM:
733 ReadMem(c->arg[0]);
734 break;
735
736 case CMD_SET_LF_DIVISOR:
737 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->arg[0]);
738 break;
739
740 case CMD_SET_ADC_MUX:
741 switch(c->arg[0]) {
742 case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break;
743 case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break;
744 case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break;
745 case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break;
746 }
747 break;
748
749 case CMD_VERSION:
750 SendVersion();
751 break;
752
753 #ifdef WITH_LF
754 case CMD_LF_SIMULATE_BIDIR:
755 SimulateTagLowFrequencyBidir(c->arg[0], c->arg[1]);
756 break;
757 #endif
758
759 #ifdef WITH_LCD
760 case CMD_LCD_RESET:
761 LCDReset();
762 break;
763 case CMD_LCD:
764 LCDSend(c->arg[0]);
765 break;
766 #endif
767 case CMD_SETUP_WRITE:
768 case CMD_FINISH_WRITE:
769 case CMD_HARDWARE_RESET:
770 USB_D_PLUS_PULLUP_OFF();
771 SpinDelay(1000);
772 SpinDelay(1000);
773 AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
774 for(;;) {
775 // We're going to reset, and the bootrom will take control.
776 }
777 break;
778
779 case CMD_START_FLASH:
780 if(common_area.flags.bootrom_present) {
781 common_area.command = COMMON_AREA_COMMAND_ENTER_FLASH_MODE;
782 }
783 USB_D_PLUS_PULLUP_OFF();
784 AT91C_BASE_RSTC->RSTC_RCR = RST_CONTROL_KEY | AT91C_RSTC_PROCRST;
785 for(;;);
786 break;
787
788 case CMD_DEVICE_INFO: {
789 UsbCommand c;
790 c.cmd = CMD_DEVICE_INFO;
791 c.arg[0] = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS;
792 if(common_area.flags.bootrom_present) c.arg[0] |= DEVICE_INFO_FLAG_BOOTROM_PRESENT;
793 UsbSendPacket((BYTE*)&c, sizeof(c));
794 }
795 break;
796 default:
797 DbpString("unknown command");
798 break;
799 }
800 }
801
802 void __attribute__((noreturn)) AppMain(void)
803 {
804 SpinDelay(100);
805
806 if(common_area.magic != COMMON_AREA_MAGIC || common_area.version != 1) {
807 /* Initialize common area */
808 memset(&common_area, 0, sizeof(common_area));
809 common_area.magic = COMMON_AREA_MAGIC;
810 common_area.version = 1;
811 }
812 common_area.flags.osimage_present = 1;
813
814 LED_D_OFF();
815 LED_C_OFF();
816 LED_B_OFF();
817 LED_A_OFF();
818
819 UsbStart();
820
821 // The FPGA gets its clock from us from PCK0 output, so set that up.
822 AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0;
823 AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0;
824 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0;
825 // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
826 AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK |
827 AT91C_PMC_PRES_CLK_4;
828 AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0;
829
830 // Reset SPI
831 AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
832 // Reset SSC
833 AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
834
835 // Load the FPGA image, which we have stored in our flash.
836 FpgaDownloadAndGo();
837
838 #ifdef WITH_LCD
839
840 LCDInit();
841
842 // test text on different colored backgrounds
843 LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK );
844 LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE );
845 LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED );
846 LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN );
847 LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE );
848 LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW);
849 LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN );
850 LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
851
852 // color bands
853 LCDFill(0, 1+8* 8, 132, 8, BLACK);
854 LCDFill(0, 1+8* 9, 132, 8, WHITE);
855 LCDFill(0, 1+8*10, 132, 8, RED);
856 LCDFill(0, 1+8*11, 132, 8, GREEN);
857 LCDFill(0, 1+8*12, 132, 8, BLUE);
858 LCDFill(0, 1+8*13, 132, 8, YELLOW);
859 LCDFill(0, 1+8*14, 132, 8, CYAN);
860 LCDFill(0, 1+8*15, 132, 8, MAGENTA);
861
862 #endif
863
864 for(;;) {
865 UsbPoll(FALSE);
866 WDT_HIT();
867
868 #ifdef WITH_LF
869 if (BUTTON_HELD(1000) > 0)
870 SamyRun();
871 #endif
872 }
873 }
Impressum, Datenschutz