]> git.zerfleddert.de Git - proxmark3-svn/blob - armsrc/appmain.c
Implement version information storage and retrieval for the bootrom and the osimage.
[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 #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
23 BYTE ToSend[256];
24 int ToSendMax;
25 static int ToSendBit;
26
27 void BufferClear(void)
28 {
29 memset(BigBuf,0,sizeof(BigBuf));
30 DbpString("Buffer cleared");
31 }
32
33 void ToSendReset(void)
34 {
35 ToSendMax = -1;
36 ToSendBit = 8;
37 }
38
39 void 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
63 void 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
79 void 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 //-----------------------------------------------------------------------------
101 static 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
118 static 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
130 void 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
182 void 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
228 void 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
239 /* osimage version information is linked in */
240 extern struct version_information version_information;
241 void SendVersion(void)
242 {
243 char temp[48]; /* Limited data payload in USB packets */
244 DbpString("Prox/RFID mark3 RFID instrument");
245
246 /* Try to find the bootrom version information. For the time being, expect
247 * to find a pointer at address 0x1001fc, perform slight sanity checks on
248 * the pointer, then use it.
249 */
250 void *bootrom_version = *(void**)0x1001fc;
251 if( bootrom_version < (void*)0x100000 || bootrom_version > (void*)0x101000 ) {
252 DbpString("bootrom version information appears invalid");
253 } else {
254 FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
255 DbpString(temp);
256 }
257
258 FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
259 DbpString(temp);
260
261 FpgaGatherVersion(temp, sizeof(temp));
262 DbpString(temp);
263 }
264
265 // samy's sniff and repeat routine
266 void SamyRun()
267 {
268 DbpString("Stand-alone mode! No PC necessary.");
269
270 // 3 possible options? no just 2 for now
271 #define OPTS 2
272
273 int high[OPTS], low[OPTS];
274
275 // Oooh pretty -- notify user we're in elite samy mode now
276 LED(LED_RED, 200);
277 LED(LED_ORANGE, 200);
278 LED(LED_GREEN, 200);
279 LED(LED_ORANGE, 200);
280 LED(LED_RED, 200);
281 LED(LED_ORANGE, 200);
282 LED(LED_GREEN, 200);
283 LED(LED_ORANGE, 200);
284 LED(LED_RED, 200);
285
286 int selected = 0;
287 int playing = 0;
288
289 // Turn on selected LED
290 LED(selected + 1, 0);
291
292 for (;;)
293 {
294 UsbPoll(FALSE);
295 WDT_HIT();
296
297 // Was our button held down or pressed?
298 int button_pressed = BUTTON_HELD(1000);
299 SpinDelay(300);
300
301 // Button was held for a second, begin recording
302 if (button_pressed > 0)
303 {
304 LEDsoff();
305 LED(selected + 1, 0);
306 LED(LED_RED2, 0);
307
308 // record
309 DbpString("Starting recording");
310
311 // wait for button to be released
312 while(BUTTON_PRESS())
313 WDT_HIT();
314
315 /* need this delay to prevent catching some weird data */
316 SpinDelay(500);
317
318 CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
319 DbpString("Recorded");
320 DbpIntegers(selected, high[selected], low[selected]);
321
322 LEDsoff();
323 LED(selected + 1, 0);
324 // Finished recording
325
326 // If we were previously playing, set playing off
327 // so next button push begins playing what we recorded
328 playing = 0;
329 }
330
331 // Change where to record (or begin playing)
332 else if (button_pressed)
333 {
334 // Next option if we were previously playing
335 if (playing)
336 selected = (selected + 1) % OPTS;
337 playing = !playing;
338
339 LEDsoff();
340 LED(selected + 1, 0);
341
342 // Begin transmitting
343 if (playing)
344 {
345 LED(LED_GREEN, 0);
346 DbpString("Playing");
347 // wait for button to be released
348 while(BUTTON_PRESS())
349 WDT_HIT();
350 DbpIntegers(selected, high[selected], low[selected]);
351 CmdHIDsimTAG(high[selected], low[selected], 0);
352 DbpString("Done playing");
353 if (BUTTON_HELD(1000) > 0)
354 {
355 DbpString("Exiting");
356 LEDsoff();
357 return;
358 }
359
360 /* We pressed a button so ignore it here with a delay */
361 SpinDelay(300);
362
363 // when done, we're done playing, move to next option
364 selected = (selected + 1) % OPTS;
365 playing = !playing;
366 LEDsoff();
367 LED(selected + 1, 0);
368 }
369 else
370 while(BUTTON_PRESS())
371 WDT_HIT();
372 }
373 }
374 }
375
376
377 /*
378 OBJECTIVE
379 Listen and detect an external reader. Determine the best location
380 for the antenna.
381
382 INSTRUCTIONS:
383 Inside the ListenReaderField() function, there is two mode.
384 By default, when you call the function, you will enter mode 1.
385 If you press the PM3 button one time, you will enter mode 2.
386 If you press the PM3 button a second time, you will exit the function.
387
388 DESCRIPTION OF MODE 1:
389 This mode just listens for an external reader field and lights up green
390 for HF and/or red for LF. This is the original mode of the detectreader
391 function.
392
393 DESCRIPTION OF MODE 2:
394 This mode will visually represent, using the LEDs, the actual strength of the
395 current compared to the maximum current detected. Basically, once you know
396 what kind of external reader is present, it will help you spot the best location to place
397 your antenna. You will probably not get some good results if there is a LF and a HF reader
398 at the same place! :-)
399
400 LIGHT SCHEME USED:
401 */
402 static const char LIGHT_SCHEME[] = {
403 0x0, /* ---- | No field detected */
404 0x1, /* X--- | 14% of maximum current detected */
405 0x2, /* -X-- | 29% of maximum current detected */
406 0x4, /* --X- | 43% of maximum current detected */
407 0x8, /* ---X | 57% of maximum current detected */
408 0xC, /* --XX | 71% of maximum current detected */
409 0xE, /* -XXX | 86% of maximum current detected */
410 0xF, /* XXXX | 100% of maximum current detected */
411 };
412 static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
413
414 void ListenReaderField(int limit)
415 {
416 int lf_av, lf_av_new, lf_baseline= 0, lf_count= 0, lf_max;
417 int hf_av, hf_av_new, hf_baseline= 0, hf_count= 0, hf_max;
418 int mode=1, display_val, display_max, i;
419
420 #define LF_ONLY 1
421 #define HF_ONLY 2
422
423 LEDsoff();
424
425 lf_av=lf_max=ReadAdc(ADC_CHAN_LF);
426
427 if(limit != HF_ONLY) {
428 DbpString("LF 125/134 Baseline:");
429 DbpIntegers(lf_av,0,0);
430 lf_baseline= lf_av;
431 }
432
433 hf_av=hf_max=ReadAdc(ADC_CHAN_HF);
434
435 if (limit != LF_ONLY) {
436 DbpString("HF 13.56 Baseline:");
437 DbpIntegers(hf_av,0,0);
438 hf_baseline= hf_av;
439 }
440
441 for(;;) {
442 if (BUTTON_PRESS()) {
443 SpinDelay(500);
444 switch (mode) {
445 case 1:
446 mode=2;
447 DbpString("Signal Strength Mode");
448 break;
449 case 2:
450 default:
451 DbpString("Stopped");
452 LEDsoff();
453 return;
454 break;
455 }
456 }
457 WDT_HIT();
458
459 if (limit != HF_ONLY) {
460 if(mode==1) {
461 if (abs(lf_av - lf_baseline) > 10) LED_D_ON();
462 else LED_D_OFF();
463 }
464
465 ++lf_count;
466 lf_av_new= ReadAdc(ADC_CHAN_LF);
467 // see if there's a significant change
468 if(abs(lf_av - lf_av_new) > 10) {
469 DbpString("LF 125/134 Field Change:");
470 DbpIntegers(lf_av,lf_av_new,lf_count);
471 lf_av= lf_av_new;
472 if (lf_av > lf_max)
473 lf_max = lf_av;
474 lf_count= 0;
475 }
476 }
477
478 if (limit != LF_ONLY) {
479 if (mode == 1){
480 if (abs(hf_av - hf_baseline) > 10) LED_B_ON();
481 else LED_B_OFF();
482 }
483
484 ++hf_count;
485 hf_av_new= ReadAdc(ADC_CHAN_HF);
486 // see if there's a significant change
487 if(abs(hf_av - hf_av_new) > 10) {
488 DbpString("HF 13.56 Field Change:");
489 DbpIntegers(hf_av,hf_av_new,hf_count);
490 hf_av= hf_av_new;
491 if (hf_av > hf_max)
492 hf_max = hf_av;
493 hf_count= 0;
494 }
495 }
496
497 if(mode == 2) {
498 if (limit == LF_ONLY) {
499 display_val = lf_av;
500 display_max = lf_max;
501 } else if (limit == HF_ONLY) {
502 display_val = hf_av;
503 display_max = hf_max;
504 } else { /* Pick one at random */
505 if( (hf_max - hf_baseline) > (lf_max - lf_baseline) ) {
506 display_val = hf_av;
507 display_max = hf_max;
508 } else {
509 display_val = lf_av;
510 display_max = lf_max;
511 }
512 }
513 for (i=0; i<LIGHT_LEN; i++) {
514 if (display_val >= ((display_max/LIGHT_LEN)*i) && display_val <= ((display_max/LIGHT_LEN)*(i+1))) {
515 if (LIGHT_SCHEME[i] & 0x1) LED_C_ON(); else LED_C_OFF();
516 if (LIGHT_SCHEME[i] & 0x2) LED_A_ON(); else LED_A_OFF();
517 if (LIGHT_SCHEME[i] & 0x4) LED_B_ON(); else LED_B_OFF();
518 if (LIGHT_SCHEME[i] & 0x8) LED_D_ON(); else LED_D_OFF();
519 break;
520 }
521 }
522 }
523 }
524 }
525
526 void UsbPacketReceived(BYTE *packet, int len)
527 {
528 UsbCommand *c = (UsbCommand *)packet;
529
530 switch(c->cmd) {
531 case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K:
532 AcquireRawAdcSamples125k(c->ext1);
533 break;
534
535 case CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K:
536 ModThenAcquireRawAdcSamples125k(c->ext1,c->ext2,c->ext3,c->d.asBytes);
537 break;
538
539 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693:
540 AcquireRawAdcSamplesIso15693();
541 break;
542
543 case CMD_BUFF_CLEAR:
544 BufferClear();
545 break;
546
547 case CMD_READER_ISO_15693:
548 ReaderIso15693(c->ext1);
549 break;
550
551 case CMD_SIMTAG_ISO_15693:
552 SimTagIso15693(c->ext1);
553 break;
554
555 case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443:
556 AcquireRawAdcSamplesIso14443(c->ext1);
557 break;
558
559 case CMD_READ_SRI512_TAG:
560 ReadSRI512Iso14443(c->ext1);
561 break;
562
563 case CMD_READER_ISO_14443a:
564 ReaderIso14443a(c->ext1);
565 break;
566
567 case CMD_SNOOP_ISO_14443:
568 SnoopIso14443();
569 break;
570
571 case CMD_SNOOP_ISO_14443a:
572 SnoopIso14443a();
573 break;
574
575 case CMD_SIMULATE_TAG_HF_LISTEN:
576 SimulateTagHfListen();
577 break;
578
579 case CMD_SIMULATE_TAG_ISO_14443:
580 SimulateIso14443Tag();
581 break;
582
583 case CMD_SIMULATE_TAG_ISO_14443a:
584 SimulateIso14443aTag(c->ext1, c->ext2); // ## Simulate iso14443a tag - pass tag type & UID
585 break;
586
587 case CMD_MEASURE_ANTENNA_TUNING:
588 MeasureAntennaTuning();
589 break;
590
591 case CMD_LISTEN_READER_FIELD:
592 ListenReaderField(c->ext1);
593 break;
594
595 case CMD_HID_DEMOD_FSK:
596 CmdHIDdemodFSK(0, 0, 0, 1); // Demodulate HID tag
597 break;
598
599 case CMD_HID_SIM_TAG:
600 CmdHIDsimTAG(c->ext1, c->ext2, 1); // Simulate HID tag by ID
601 break;
602
603 case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control
604 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
605 SpinDelay(200);
606 LED_D_OFF(); // LED D indicates field ON or OFF
607 break;
608
609 case CMD_READ_TI_TYPE:
610 ReadTItag();
611 break;
612
613 case CMD_WRITE_TI_TYPE:
614 WriteTItag(c->ext1,c->ext2,c->ext3);
615 break;
616
617 case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: {
618 UsbCommand n;
619 if(c->cmd == CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K) {
620 n.cmd = CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K;
621 } else {
622 n.cmd = CMD_DOWNLOADED_RAW_BITS_TI_TYPE;
623 }
624 n.ext1 = c->ext1;
625 memcpy(n.d.asDwords, BigBuf+c->ext1, 12*sizeof(DWORD));
626 UsbSendPacket((BYTE *)&n, sizeof(n));
627 break;
628 }
629 case CMD_DOWNLOADED_SIM_SAMPLES_125K: {
630 BYTE *b = (BYTE *)BigBuf;
631 memcpy(b+c->ext1, c->d.asBytes, 48);
632 break;
633 }
634 case CMD_SIMULATE_TAG_125K:
635 LED_A_ON();
636 SimulateTagLowFrequency(c->ext1, 1);
637 LED_A_OFF();
638 break;
639 case CMD_READ_MEM:
640 ReadMem(c->ext1);
641 break;
642 case CMD_SET_LF_DIVISOR:
643 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, c->ext1);
644 break;
645 case CMD_VERSION:
646 SendVersion();
647 break;
648 #ifdef WITH_LCD
649 case CMD_LCD_RESET:
650 LCDReset();
651 break;
652 case CMD_LCD:
653 LCDSend(c->ext1);
654 break;
655 #endif
656 case CMD_SETUP_WRITE:
657 case CMD_FINISH_WRITE:
658 case CMD_HARDWARE_RESET:
659 USB_D_PLUS_PULLUP_OFF();
660 SpinDelay(1000);
661 SpinDelay(1000);
662 RSTC_CONTROL = RST_CONTROL_KEY | RST_CONTROL_PROCESSOR_RESET;
663 for(;;) {
664 // We're going to reset, and the bootrom will take control.
665 }
666 break;
667
668 default:
669 DbpString("unknown command");
670 break;
671 }
672 }
673
674 void AppMain(void)
675 {
676 memset(BigBuf,0,sizeof(BigBuf));
677 SpinDelay(100);
678
679 LED_D_OFF();
680 LED_C_OFF();
681 LED_B_OFF();
682 LED_A_OFF();
683
684 UsbStart();
685
686 // The FPGA gets its clock from us from PCK0 output, so set that up.
687 PIO_PERIPHERAL_B_SEL = (1 << GPIO_PCK0);
688 PIO_DISABLE = (1 << GPIO_PCK0);
689 PMC_SYS_CLK_ENABLE = PMC_SYS_CLK_PROGRAMMABLE_CLK_0;
690 // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz
691 PMC_PROGRAMMABLE_CLK_0 = PMC_CLK_SELECTION_PLL_CLOCK |
692 PMC_CLK_PRESCALE_DIV_4;
693 PIO_OUTPUT_ENABLE = (1 << GPIO_PCK0);
694
695 // Reset SPI
696 SPI_CONTROL = SPI_CONTROL_RESET;
697 // Reset SSC
698 SSC_CONTROL = SSC_CONTROL_RESET;
699
700 // Load the FPGA image, which we have stored in our flash.
701 FpgaDownloadAndGo();
702
703 #ifdef WITH_LCD
704
705 LCDInit();
706
707 // test text on different colored backgrounds
708 LCDString(" The quick brown fox ", &FONT6x8,1,1+8*0,WHITE ,BLACK );
709 LCDString(" jumped over the ", &FONT6x8,1,1+8*1,BLACK ,WHITE );
710 LCDString(" lazy dog. ", &FONT6x8,1,1+8*2,YELLOW ,RED );
711 LCDString(" AaBbCcDdEeFfGgHhIiJj ", &FONT6x8,1,1+8*3,RED ,GREEN );
712 LCDString(" KkLlMmNnOoPpQqRrSsTt ", &FONT6x8,1,1+8*4,MAGENTA,BLUE );
713 LCDString("UuVvWwXxYyZz0123456789", &FONT6x8,1,1+8*5,BLUE ,YELLOW);
714 LCDString("`-=[]_;',./~!@#$%^&*()", &FONT6x8,1,1+8*6,BLACK ,CYAN );
715 LCDString(" _+{}|:\\\"<>? ",&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
716
717 // color bands
718 LCDFill(0, 1+8* 8, 132, 8, BLACK);
719 LCDFill(0, 1+8* 9, 132, 8, WHITE);
720 LCDFill(0, 1+8*10, 132, 8, RED);
721 LCDFill(0, 1+8*11, 132, 8, GREEN);
722 LCDFill(0, 1+8*12, 132, 8, BLUE);
723 LCDFill(0, 1+8*13, 132, 8, YELLOW);
724 LCDFill(0, 1+8*14, 132, 8, CYAN);
725 LCDFill(0, 1+8*15, 132, 8, MAGENTA);
726
727 #endif
728
729 for(;;) {
730 UsbPoll(FALSE);
731 WDT_HIT();
732
733 if (BUTTON_HELD(1000) > 0)
734 SamyRun();
735 }
736 }
Impressum, Datenschutz