]> cvs.zerfleddert.de Git - proxmark3-svn/blame_incremental - armsrc/appmain.c
Trying automagic version stuff
[proxmark3-svn] / armsrc / appmain.c
... / ...
CommitLineData
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#ifdef WITH_LCD
12#include "fonts.h"
13#include "LCD.h"
14#endif
15
16
17//=============================================================================
18// A buffer where we can queue things up to be sent through the FPGA, for
19// any purpose (fake tag, as reader, whatever). We go MSB first, since that
20// is the order in which they go out on the wire.
21//=============================================================================
22
23BYTE ToSend[256];
24int ToSendMax;
25static int ToSendBit;
26
27void BufferClear(void)
28{
29 memset(BigBuf,0,sizeof(BigBuf));
30 DbpString("Buffer cleared");
31}
32
33void ToSendReset(void)
34{
35 ToSendMax = -1;
36 ToSendBit = 8;
37}
38
39void ToSendStuffBit(int b)
40{
41 if(ToSendBit >= 8) {
42 ToSendMax++;
43 ToSend[ToSendMax] = 0;
44 ToSendBit = 0;
45 }
46
47 if(b) {
48 ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
49 }
50
51 ToSendBit++;
52
53 if(ToSendBit >= sizeof(ToSend)) {
54 ToSendBit = 0;
55 DbpString("ToSendStuffBit overflowed!");
56 }
57}
58
59//=============================================================================
60// Debug print functions, to go out over USB, to the usual PC-side client.
61//=============================================================================
62
63void DbpString(char *str)
64{
65 /* this holds up stuff unless we're connected to usb */
66 if (!UsbConnected())
67 return;
68
69 UsbCommand c;
70 c.cmd = CMD_DEBUG_PRINT_STRING;
71 c.ext1 = strlen(str);
72 memcpy(c.d.asBytes, str, c.ext1);
73
74 UsbSendPacket((BYTE *)&c, sizeof(c));
75 // TODO fix USB so stupid things like this aren't req'd
76 SpinDelay(50);
77}
78
79void DbpIntegers(int x1, int x2, int x3)
80{
81 /* this holds up stuff unless we're connected to usb */
82 if (!UsbConnected())
83 return;
84
85 UsbCommand c;
86 c.cmd = CMD_DEBUG_PRINT_INTEGERS;
87 c.ext1 = x1;
88 c.ext2 = x2;
89 c.ext3 = x3;
90
91 UsbSendPacket((BYTE *)&c, sizeof(c));
92 // XXX
93 SpinDelay(50);
94}
95
96//-----------------------------------------------------------------------------
97// Read an ADC channel and block till it completes, then return the result
98// in ADC units (0 to 1023). Also a routine to average 32 samples and
99// return that.
100//-----------------------------------------------------------------------------
101static int ReadAdc(int ch)
102{
103 DWORD d;
104
105 ADC_CONTROL = ADC_CONTROL_RESET;
106 ADC_MODE = ADC_MODE_PRESCALE(32) | ADC_MODE_STARTUP_TIME(16) |
107 ADC_MODE_SAMPLE_HOLD_TIME(8);
108 ADC_CHANNEL_ENABLE = ADC_CHANNEL(ch);
109
110 ADC_CONTROL = ADC_CONTROL_START;
111 while(!(ADC_STATUS & ADC_END_OF_CONVERSION(ch)))
112 ;
113 d = ADC_CHANNEL_DATA(ch);
114
115 return d;
116}
117
118static int AvgAdc(int ch)
119{
120 int i;
121 int a = 0;
122
123 for(i = 0; i < 32; i++) {
124 a += ReadAdc(ch);
125 }
126
127 return (a + 15) >> 5;
128}
129
130void MeasureAntennaTuning(void)
131{
132 BYTE *dest = (BYTE *)BigBuf;
133 int i, ptr = 0, adcval = 0, peak = 0, peakv = 0, peakf = 0;;
134 int vLf125 = 0, vLf134 = 0, vHf = 0; // in mV
135
136 UsbCommand c;
137
138 DbpString("Measuring antenna characteristics, please wait.");
139 memset(BigBuf,0,sizeof(BigBuf));
140
141/*
142 * Sweeps the useful LF range of the proxmark from
143 * 46.8kHz (divisor=255) to 600kHz (divisor=19) and
144 * read the voltage in the antenna, the result left
145 * in the buffer is a graph which should clearly show
146 * the resonating frequency of your LF antenna
147 * ( hopefully around 95 if it is tuned to 125kHz!)
148 */
149 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
150 for (i=255; i>19; i--) {
151 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
152 SpinDelay(20);
153 // Vref = 3.3V, and a 10000:240 voltage divider on the input
154 // can measure voltages up to 137500 mV
155 adcval = ((137500 * AvgAdc(ADC_CHAN_LF)) >> 10);
156 if (i==95) vLf125 = adcval; // voltage at 125Khz
157 if (i==89) vLf134 = adcval; // voltage at 134Khz
158
159 dest[i] = adcval>>8; // scale int to fit in byte for graphing purposes
160 if(dest[i] > peak) {
161 peakv = adcval;
162 peak = dest[i];
163 peakf = i;
164 ptr = i;
165 }
166 }
167
168 // Let the FPGA drive the high-frequency antenna around 13.56 MHz.
169 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
170 SpinDelay(20);
171 // Vref = 3300mV, and an 10:1 voltage divider on the input
172 // can measure voltages up to 33000 mV
173 vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10;
174
175 c.cmd = CMD_MEASURED_ANTENNA_TUNING;
176 c.ext1 = (vLf125 << 0) | (vLf134 << 16);
177 c.ext2 = vHf;
178 c.ext3 = peakf | (peakv << 16);
179 UsbSendPacket((BYTE *)&c, sizeof(c));
180}
181
182void SimulateTagHfListen(void)
183{
184 BYTE *dest = (BYTE *)BigBuf;
185 int n = sizeof(BigBuf);
186 BYTE v = 0;
187 int i;
188 int p = 0;
189
190 // We're using this mode just so that I can test it out; the simulated
191 // tag mode would work just as well and be simpler.
192 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP);
193
194 // We need to listen to the high-frequency, peak-detected path.
195 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
196
197 FpgaSetupSsc();
198
199 i = 0;
200 for(;;) {
201 if(SSC_STATUS & (SSC_STATUS_TX_READY)) {
202 SSC_TRANSMIT_HOLDING = 0xff;
203 }
204 if(SSC_STATUS & (SSC_STATUS_RX_READY)) {
205 BYTE r = (BYTE)SSC_RECEIVE_HOLDING;
206
207 v <<= 1;
208 if(r & 1) {
209 v |= 1;
210 }
211 p++;
212
213 if(p >= 8) {
214 dest[i] = v;
215 v = 0;
216 p = 0;
217 i++;
218
219 if(i >= n) {
220 break;
221 }
222 }
223 }
224 }
225 DbpString("simulate tag (now type bitsamples)");
226}
227
228void ReadMem(int addr)
229{
230 const DWORD *data = ((DWORD *)addr);
231 int i;
232
233 DbpString("Reading memory at address");
234 DbpIntegers(0, 0, addr);
235 for (i = 0; i < 8; i+= 2)
236 DbpIntegers(0, data[i], data[i+1]);
237}
238
239void SendVersion(void)
240{
241 char temp[48]; /* Limited data payload in USB packets */
242 DbpString("Prox/RFID mark3 RFID instrument");
243 FpgaGatherVersion(temp, sizeof(temp));
244 DbpString(temp);
245}
246
247// samy's sniff and repeat routine
248void SamyRun()
249{
250 DbpString("Stand-alone mode! No PC necessary.");
251
252 // 3 possible options? no just 2 for now
253#define OPTS 2
254
255 int high[OPTS], low[OPTS];
256
257 // Oooh pretty -- notify user we're in elite samy mode now
258 LED(LED_RED, 200);
259 LED(LED_ORANGE, 200);
260 LED(LED_GREEN, 200);
261 LED(LED_ORANGE, 200);
262 LED(LED_RED, 200);
263 LED(LED_ORANGE, 200);
264 LED(LED_GREEN, 200);
265 LED(LED_ORANGE, 200);
266 LED(LED_RED, 200);
267
268 int selected = 0;
269 int playing = 0;
270
271 // Turn on selected LED
272 LED(selected + 1, 0);
273
274 for (;;)
275 {
276 UsbPoll(FALSE);
277 WDT_HIT();
278
279 // Was our button held down or pressed?
280 int button_pressed = BUTTON_HELD(1000);
281 SpinDelay(300);
282
283 // Button was held for a second, begin recording
284 if (button_pressed > 0)
285 {
286 LEDsoff();
287 LED(selected + 1, 0);
288 LED(LED_RED2, 0);
289
290 // record
291 DbpString("Starting recording");
292
293 // wait for button to be released
294 while(BUTTON_PRESS())
295 WDT_HIT();
296
297 /* need this delay to prevent catching some weird data */
298 SpinDelay(500);
299
300 CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
301 DbpString("Recorded");
302 DbpIntegers(selected, high[selected], low[selected]);
303
304 LEDsoff();
305 LED(selected + 1, 0);
306 // Finished recording
307
308 // If we were previously playing, set playing off
309 // so next button push begins playing what we recorded
310 playing = 0;
311 }
312
313 // Change where to record (or begin playing)
314 else if (button_pressed)
315 {
316 // Next option if we were previously playing
317 if (playing)
318 selected = (selected + 1) % OPTS;
319 playing = !playing;
320
321 LEDsoff();
322 LED(selected + 1, 0);
323
324 // Begin transmitting
325 if (playing)
326 {
327 LED(LED_GREEN, 0);
328 DbpString("Playing");
329 // wait for button to be released
330 while(BUTTON_PRESS())
331 WDT_HIT();
332 DbpIntegers(selected, high[selected], low[selected]);
333 CmdHIDsimTAG(high[selected], low[selected], 0);
334 DbpString("Done playing");
335 if (BUTTON_HELD(1000) > 0)
336 {
337 DbpString("Exiting");
338 LEDsoff();
339 return;
340 }
341
342 /* We pressed a button so ignore it here with a delay */
343 SpinDelay(300);
344
345 // when done, we're done playing, move to next option
346 selected = (selected + 1) % OPTS;
347 playing = !playing;
348 LEDsoff();
349 LED(selected + 1, 0);
350 }
351 else
352 while(BUTTON_PRESS())
353 WDT_HIT();
354 }
355 }
356}
357
358
359/*
360OBJECTIVE
361Listen and detect an external reader. Determine the best location
362for the antenna.
363
364INSTRUCTIONS:
365Inside the ListenReaderField() function, there is two mode.
366By default, when you call the function, you will enter mode 1.
367If you press the PM3 button one time, you will enter mode 2.
368If you press the PM3 button a second time, you will exit the function.
369
370DESCRIPTION OF MODE 1:
371This mode just listens for an external reader field and lights up green
372for HF and/or red for LF. This is the original mode of the detectreader
373function.
374
375DESCRIPTION OF MODE 2:
376This mode will visually represent, using the LEDs, the actual strength of the
377current compared to the maximum current detected. Basically, once you know
378what kind of external reader is present, it will help you spot the best location to place
379your antenna. You will probably not get some good results if there is a LF and a HF reader
380at the same place! :-)
381
382LIGHT SCHEME USED:
383*/
384static const char LIGHT_SCHEME[] = {
385 0x0, /* ---- | No field detected */
386 0x1, /* X--- | 14% of maximum current detected */
387 0x2, /* -X-- | 29% of maximum current detected */
388 0x4, /* --X- | 43% of maximum current detected */
389 0x8, /* ---X | 57% of maximum current detected */
390 0xC, /* --XX | 71% of maximum current detected */
391 0xE, /* -XXX | 86% of maximum current detected */
392 0xF, /* XXXX | 100% of maximum current detected */
393};
394static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
395
396void ListenReaderField(int limit)
397{
398 int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;
399 int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;
400 int mode=1, display_val, display_max, i;
401
402#define LF_ONLY 1
403#define HF_ONLY 2
404
405 LEDsoff();
406
407 lf_av=lf_max=ReadAdc(ADC_CHAN_LF);
408
409 if(limit != HF_ONLY) {
410 DbpString("LF 125/134 Baseline:");
411 DbpIntegers(lf_av,0,0);
412 lf_baseline= lf_av;
413 }
414
415 hf_av=hf_max=ReadAdc(ADC_CHAN_HF);
416
417 if (limit != LF_ONLY) {
418 DbpString("HF 13.56 Baseline:");
419 DbpIntegers(hf_av,0,0);
420 hf_baseline= hf_av;
421 }
422
423 for(;;) {
424 if (BUTTON_PRESS()) {
425 SpinDelay(500);
426 switch (mode) {
427 case 1:
428 mode=2;
429 DbpString("Signal Strength Mode");
430 break;
431 case 2:
432 default:
433 DbpString("Stopped");
434 LEDsoff();
435 return;
436 break;
437 }
438 }
439 WDT_HIT();
440
441 if (limit != HF_ONLY) {
442 if(mode==1) {
443 if (abs(lf_av - lf_baseline) > 10) LED_D_ON();
444 else LED_D_OFF();
445 }
446
447 ++lf_count;
448 lf_av_new= ReadAdc(ADC_CHAN_LF);
449 // see if there's a significant change
450 if(abs(lf_av - lf_av_new) > 10) {
451 DbpString("LF 125/134 Field Change:");
452 DbpIntegers(lf_av,lf_av_new,lf_count);
453 lf_av= lf_av_new;
454 if (lf_av > lf_max)
455 lf_max = lf_av;
456 lf_count= 0;
457 }
458 }
459
460 if (limit != LF_ONLY) {
461 if (mode == 1){
462 if (abs(hf_av - hf_baseline) > 10) LED_B_ON();
463 else LED_B_OFF();
464 }
465
466 ++hf_count;
467 hf_av_new= ReadAdc(ADC_CHAN_HF);
468 // see if there's a significant change
469 if(abs(hf_av - hf_av_new) > 10) {
470 DbpString("HF 13.56 Field Change:");
471 DbpIntegers(hf_av,hf_av_new,hf_count);
472 hf_av= hf_av_new;
473 if (hf_av > hf_max)
474 hf_max = hf_av;
475 hf_count= 0;
476 }
477 }
478
479 if(mode == 2) {
480 if (limit == LF_ONLY) {
481 display_val = lf_av;
482 display_max = lf_max;
483 } else if (limit == HF_ONLY) {
484 display_val = hf_av;
485 display_max = hf_max;
486 } else { /* Pick one at random */
487 if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
488 display_val = hf_av;
489 display_max = hf_max;
490 } else {
491 display_val = lf_av;
492 display_max = lf_max;
493 }
494 }
495 for (i=0; i<LIGHT_LEN; i++) {
496 if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
497 if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
498 if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
499 if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
500 if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
501 break;
502 }
503 }
504 }
505 }
506}
507
508void UsbPacketReceived(BYTE *packet, int len)
509{
510 UsbCommand *c = (UsbCommand *)packet;
511
512 switch(c->cmd) {
513 case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
514 AcquireRawAdcSamples125k(c->ext1);
515 break;
516
517 case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
518 ModThenAcquireRawAdcSamples125k(c->ext1,c->ext2,c->ext3,c->d.asBytes);
519 break;
520
521 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
522 AcquireRawAdcSamplesIso15693();
523 break;
524
525 case CMD_BUFF_CLEAR:
526 BufferClear();
527 break;
528
529 case CMD_READER_ISO_15693:
530 ReaderIso15693(c->ext1);
531 break;
532
533 case CMD_SIMTAG_ISO_15693:
534 SimTagIso15693(c->ext1);
535 break;
536
537 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
538 AcquireRawAdcSamplesIso14443(c->ext1);
539 break;
540
541 case CMD_READ_SRI512_TAG:
542 ReadSRI512Iso14443(c->ext1);
543 break;
544
545 case CMD_READER_ISO_14443a:
546 ReaderIso14443a(c->ext1);
547 break;
548
549 case CMD_SNOOP_ISO_14443:
550 SnoopIso14443();
551 break;
552
553 case CMD_SNOOP_ISO_14443a:
554 SnoopIso14443a();
555 break;
556
557 case CMD_SIMULATE_TAG_HF_LISTEN:
558 SimulateTagHfListen();
559 break;
560
561 case CMD_SIMULATE_TAG_ISO_14443:
562 SimulateIso14443Tag();
563 break;
564
565 case CMD_SIMULATE_TAG_ISO_14443a:
566 SimulateIso14443aTag(c->ext1, c->ext2); // ## Simulate iso14443a tag - pass tag type & UID
567 break;
568
569 case CMD_MEASURE_ANTENNA_TUNING:
570 MeasureAntennaTuning();
571 break;
572
573 case CMD_LISTEN_READER_FIELD:
574 ListenReaderField(c->ext1);
575 break;
576
577 case CMD_HID_DEMOD_FSK:
578 CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
579 break;
580
581 case CMD_HID_SIM_TAG:
582 CmdHIDsimTAG(c->ext1, c->ext2, 1); // Simulate HID tag by ID
583 break;
584
585 case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
586 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
587 SpinDelay(200);
588 LED_D_OFF(); // LED D indicates field ON or OFF
589 break;
590
591 case CMD_READ_TI_TYPE:
592 ReadTItag();
593 break;
594
595 case CMD_WRITE_TI_TYPE:
596 WriteTItag(c->ext1,c->ext2,c->ext3);
597 break;
598
599 case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {
600 UsbCommand n;
601 if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
602 n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
603 } else {
604 n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
605 }
606 n.ext1 = c->ext1;
607 memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD));
608 UsbSendPacket((BYTE *)&n, sizeof(n));
609 break;
610 }
611 case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
612 BYTE *b = (BYTE *)BigBuf;
613 memcpy(b+c->ext1, c->d.asBytes, 48);
614 break;
615 }
616 case CMD_SIMULATE_TAG_125K:
617 LED_A_ON();
618 SimulateTagLowFrequency(c->ext1, 1);
619 LED_A_OFF();
620 break;
621 case CMD_READ_MEM:
622 ReadMem(c->ext1);
623 break;
624 case CMD_SET_LF_DIVISOR:
625 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->ext1);
626 break;
627 case CMD_VERSION:
628 SendVersion();
629 break;
630#ifdef WITH_LCD
631 case CMD_LCD_RESET:
632 LCDReset();
633 break;
634 case CMD_LCD:
635 LCDSend(c->ext1);
636 break;
637#endif
638 case CMD_SETUP_WRITE:
639 case CMD_FINISH_WRITE:
640 case CMD_HARDWARE_RESET:
641 USB_D_PLUS_PULLUP_OFF();
642 SpinDelay(1000);
643 SpinDelay(1000);
644 RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;
645 for(;;) {
646 // We're going to reset, and the bootrom will take control.
647 }
648 break;
649
650 default:
651 DbpString("unknown command");
652 break;
653 }
654}
655
656void AppMain(void)
657{
658 memset(BigBuf,0,sizeof(BigBuf));
659 SpinDelay(100);
660
661 LED_D_OFF();
662 LED_C_OFF();
663 LED_B_OFF();
664 LED_A_OFF();
665
666 UsbStart();
667
668 // The FPGA gets its clock from us from PCK0 output, so set that up.
669 PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0);
670 PIO_DISABLE = (1 << GPIO_PCK0);
671 PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0;
672 // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
673 PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK |
674 PMC_CLK_PRESCALE_DIV_4;
675 PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0);
676
677 // Reset SPI
678 SPI_CONTROL = SPI_CONTROL_RESET;
679 // Reset SSC
680 SSC_CONTROL = SSC_CONTROL_RESET;
681
682 // Load the FPGA image, which we have stored in our flash.
683 FpgaDownloadAndGo();
684
685#ifdef WITH_LCD
686
687 LCDInit();
688
689 // test text on different colored backgrounds
690 LCDString(" The quick brown fox ", &FONT6x8,1,1+8*0,WHITE ,BLACK );
691 LCDString(" jumped over the ", &FONT6x8,1,1+8*1,BLACK ,WHITE );
692 LCDString(" lazy dog. ", &FONT6x8,1,1+8*2,YELLOW ,RED );
693 LCDString(" AaBbCcDdEeFfGgHhIiJj ", &FONT6x8,1,1+8*3,RED ,GREEN );
694 LCDString(" KkLlMmNnOoPpQqRrSsTt ", &FONT6x8,1,1+8*4,MAGENTA,BLUE );
695 LCDString("UuVvWwXxYyZz0123456789", &FONT6x8,1,1+8*5,BLUE ,YELLOW);
696 LCDString("`-=[]_;',./~!@#$%^&*()", &FONT6x8,1,1+8*6,BLACK ,CYAN );
697 LCDString(" _+{}|:\\\"<>? ",&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
698
699 // color bands
700 LCDFill(0, 1+8* 8, 132, 8, BLACK);
701 LCDFill(0, 1+8* 9, 132, 8, WHITE);
702 LCDFill(0, 1+8*10, 132, 8, RED);
703 LCDFill(0, 1+8*11, 132, 8, GREEN);
704 LCDFill(0, 1+8*12, 132, 8, BLUE);
705 LCDFill(0, 1+8*13, 132, 8, YELLOW);
706 LCDFill(0, 1+8*14, 132, 8, CYAN);
707 LCDFill(0, 1+8*15, 132, 8, MAGENTA);
708
709#endif
710
711 for(;;) {
712 UsbPoll(FALSE);
713 WDT_HIT();
714
715 if (BUTTON_HELD(1000) > 0)
716 SamyRun();
717 }
718}
Impressum, Datenschutz