]> git.zerfleddert.de Git - proxmark3-svn/blob - armsrc/iso15693.c
ADD: test_t55x7_psk.lua, a script which writes to block 0 (configation) of a T55x7...
[proxmark3-svn] / armsrc / iso15693.c
1 //-----------------------------------------------------------------------------
2 // Jonathan Westhues, split Nov 2006
3 // Modified by Greg Jones, Jan 2009
4 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011
5 //
6 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
7 // at your option, any later version. See the LICENSE.txt file for the text of
8 // the license.
9 //-----------------------------------------------------------------------------
10 // Routines to support ISO 15693. This includes both the reader software and
11 // the `fake tag' modes, but at the moment I've implemented only the reader
12 // stuff, and that barely.
13 // Modified to perform modulation onboard in arm rather than on PC
14 // Also added additional reader commands (SELECT, READ etc.)
15 //-----------------------------------------------------------------------------
16 // The ISO 15693 describes two transmission modes from reader to tag, and 4
17 // transmission modes from tag to reader. As of Mar 2010 this code only
18 // supports one of each: "1of4" mode from reader to tag, and the highspeed
19 // variant with one subcarrier from card to reader.
20 // As long, as the card fully support ISO 15693 this is no problem, since the
21 // reader chooses both data rates, but some non-standard tags do not. Further for
22 // the simulation to work, we will need to support all data rates.
23 //
24 // VCD (reader) -> VICC (tag)
25 // 1 out of 256:
26 // data rate: 1,66 kbit/s (fc/8192)
27 // used for long range
28 // 1 out of 4:
29 // data rate: 26,48 kbit/s (fc/512)
30 // used for short range, high speed
31 //
32 // VICC (tag) -> VCD (reader)
33 // Modulation:
34 // ASK / one subcarrier (423,75 khz)
35 // FSK / two subcarriers (423,75 khz && 484,28 khz)
36 // Data Rates / Modes:
37 // low ASK: 6,62 kbit/s
38 // low FSK: 6.67 kbit/s
39 // high ASK: 26,48 kbit/s
40 // high FSK: 26,69 kbit/s
41 //-----------------------------------------------------------------------------
42 // added "1 out of 256" mode (for VCD->PICC) - atrox 20100911
43
44
45 // Random Remarks:
46 // *) UID is always used "transmission order" (LSB), which is reverse to display order
47
48 // TODO / BUGS / ISSUES:
49 // *) writing to tags takes longer: we miss the answer from the tag in most cases
50 // -> tweak the read-timeout times
51 // *) signal decoding from the card is still a bit shaky.
52 // *) signal decoding is unable to detect collissions.
53 // *) add anti-collission support for inventory-commands
54 // *) read security status of a block
55 // *) sniffing and simulation do only support one transmission mode. need to support
56 // all 8 transmission combinations
57 // *) remove or refactor code under "depricated"
58 // *) document all the functions
59
60
61 #include "../include/proxmark3.h"
62 #include "util.h"
63 #include "apps.h"
64 #include "string.h"
65 #include "../common/iso15693tools.h"
66 #include "../common/cmd.h"
67
68
69 #define arraylen(x) (sizeof(x)/sizeof((x)[0]))
70
71 ///////////////////////////////////////////////////////////////////////
72 // ISO 15693 Part 2 - Air Interface
73 // This section basicly contains transmission and receiving of bits
74 ///////////////////////////////////////////////////////////////////////
75
76 #define FrameSOF Iso15693FrameSOF
77 #define Logic0 Iso15693Logic0
78 #define Logic1 Iso15693Logic1
79 #define FrameEOF Iso15693FrameEOF
80
81 #define Crc(data,datalen) Iso15693Crc(data,datalen)
82 #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen)
83 #define sprintUID(target,uid) Iso15693sprintUID(target,uid)
84
85 int DEBUG=0;
86
87
88 // ---------------------------
89 // Signal Processing
90 // ---------------------------
91
92 // prepare data using "1 out of 4" code for later transmission
93 // resulting data rate is 26,48 kbit/s (fc/512)
94 // cmd ... data
95 // n ... length of data
96 static void CodeIso15693AsReader(uint8_t *cmd, int n)
97 {
98 int i, j;
99
100 ToSendReset();
101
102 // Give it a bit of slack at the beginning
103 for(i = 0; i < 24; i++) {
104 ToSendStuffBit(1);
105 }
106
107 // SOF for 1of4
108 ToSendStuffBit(0);
109 ToSendStuffBit(1);
110 ToSendStuffBit(1);
111 ToSendStuffBit(1);
112 ToSendStuffBit(1);
113 ToSendStuffBit(0);
114 ToSendStuffBit(1);
115 ToSendStuffBit(1);
116 for(i = 0; i < n; i++) {
117 for(j = 0; j < 8; j += 2) {
118 int these = (cmd[i] >> j) & 3;
119 switch(these) {
120 case 0:
121 ToSendStuffBit(1);
122 ToSendStuffBit(0);
123 ToSendStuffBit(1);
124 ToSendStuffBit(1);
125 ToSendStuffBit(1);
126 ToSendStuffBit(1);
127 ToSendStuffBit(1);
128 ToSendStuffBit(1);
129 break;
130 case 1:
131 ToSendStuffBit(1);
132 ToSendStuffBit(1);
133 ToSendStuffBit(1);
134 ToSendStuffBit(0);
135 ToSendStuffBit(1);
136 ToSendStuffBit(1);
137 ToSendStuffBit(1);
138 ToSendStuffBit(1);
139 break;
140 case 2:
141 ToSendStuffBit(1);
142 ToSendStuffBit(1);
143 ToSendStuffBit(1);
144 ToSendStuffBit(1);
145 ToSendStuffBit(1);
146 ToSendStuffBit(0);
147 ToSendStuffBit(1);
148 ToSendStuffBit(1);
149 break;
150 case 3:
151 ToSendStuffBit(1);
152 ToSendStuffBit(1);
153 ToSendStuffBit(1);
154 ToSendStuffBit(1);
155 ToSendStuffBit(1);
156 ToSendStuffBit(1);
157 ToSendStuffBit(1);
158 ToSendStuffBit(0);
159 break;
160 }
161 }
162 }
163 // EOF
164 ToSendStuffBit(1);
165 ToSendStuffBit(1);
166 ToSendStuffBit(0);
167 ToSendStuffBit(1);
168
169 // And slack at the end, too.
170 for(i = 0; i < 24; i++) {
171 ToSendStuffBit(1);
172 }
173 }
174
175 // encode data using "1 out of 256" sheme
176 // data rate is 1,66 kbit/s (fc/8192)
177 // is designed for more robust communication over longer distances
178 static void CodeIso15693AsReader256(uint8_t *cmd, int n)
179 {
180 int i, j;
181
182 ToSendReset();
183
184 // Give it a bit of slack at the beginning
185 for(i = 0; i < 24; i++) {
186 ToSendStuffBit(1);
187 }
188
189 // SOF for 1of256
190 ToSendStuffBit(0);
191 ToSendStuffBit(1);
192 ToSendStuffBit(1);
193 ToSendStuffBit(1);
194 ToSendStuffBit(1);
195 ToSendStuffBit(1);
196 ToSendStuffBit(1);
197 ToSendStuffBit(0);
198
199 for(i = 0; i < n; i++) {
200 for (j = 0; j<=255; j++) {
201 if (cmd[i]==j) {
202 ToSendStuffBit(1);
203 ToSendStuffBit(0);
204 } else {
205 ToSendStuffBit(1);
206 ToSendStuffBit(1);
207 }
208 }
209 }
210 // EOF
211 ToSendStuffBit(1);
212 ToSendStuffBit(1);
213 ToSendStuffBit(0);
214 ToSendStuffBit(1);
215
216 // And slack at the end, too.
217 for(i = 0; i < 24; i++) {
218 ToSendStuffBit(1);
219 }
220 }
221
222
223 // Transmit the command (to the tag) that was placed in ToSend[].
224 static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *wait)
225 {
226 int c;
227
228 // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
229 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
230 if(*wait < 10) { *wait = 10; }
231
232 // for(c = 0; c < *wait;) {
233 // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
234 // AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
235 // c++;
236 // }
237 // if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
238 // volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
239 // (void)r;
240 // }
241 // WDT_HIT();
242 // }
243
244 c = 0;
245 for(;;) {
246 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
247 AT91C_BASE_SSC->SSC_THR = cmd[c];
248 c++;
249 if(c >= len) {
250 break;
251 }
252 }
253 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
254 volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
255 (void)r;
256 }
257 WDT_HIT();
258 }
259 *samples = (c + *wait) << 3;
260 }
261
262 //-----------------------------------------------------------------------------
263 // Transmit the command (to the reader) that was placed in ToSend[].
264 //-----------------------------------------------------------------------------
265 static void TransmitTo15693Reader(const uint8_t *cmd, int len, int *samples, int *wait)
266 {
267 int c = 0;
268 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K);
269 if(*wait < 10) { *wait = 10; }
270
271 for(;;) {
272 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
273 AT91C_BASE_SSC->SSC_THR = cmd[c];
274 c++;
275 if(c >= len) {
276 break;
277 }
278 }
279 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
280 volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
281 (void)r;
282 }
283 WDT_HIT();
284 }
285 *samples = (c + *wait) << 3;
286 }
287
288
289 // Read from Tag
290 // Parameters:
291 // receivedResponse
292 // maxLen
293 // samples
294 // elapsed
295 // returns:
296 // number of decoded bytes
297 static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed)
298 {
299 int c = 0;
300 uint8_t *dest = (uint8_t *)BigBuf;
301 int getNext = 0;
302
303 int8_t prev = 0;
304
305 // NOW READ RESPONSE
306 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
307 //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
308 c = 0;
309 getNext = FALSE;
310 for(;;) {
311 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
312 AT91C_BASE_SSC->SSC_THR = 0x43;
313 }
314 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
315 int8_t b;
316 b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
317
318 // The samples are correlations against I and Q versions of the
319 // tone that the tag AM-modulates, so every other sample is I,
320 // every other is Q. We just want power, so abs(I) + abs(Q) is
321 // close to what we want.
322 if(getNext) {
323 int8_t r;
324
325 if(b < 0) {
326 r = -b;
327 } else {
328 r = b;
329 }
330 if(prev < 0) {
331 r -= prev;
332 } else {
333 r += prev;
334 }
335
336 dest[c++] = (uint8_t)r;
337
338 if(c >= 2000) {
339 break;
340 }
341 } else {
342 prev = b;
343 }
344
345 getNext = !getNext;
346 }
347 }
348
349 //////////////////////////////////////////
350 /////////// DEMODULATE ///////////////////
351 //////////////////////////////////////////
352
353 int i, j;
354 int max = 0, maxPos=0;
355
356 int skip = 4;
357
358 // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL
359
360 // First, correlate for SOF
361 for(i = 0; i < 100; i++) {
362 int corr = 0;
363 for(j = 0; j < arraylen(FrameSOF); j += skip) {
364 corr += FrameSOF[j]*dest[i+(j/skip)];
365 }
366 if(corr > max) {
367 max = corr;
368 maxPos = i;
369 }
370 }
371 // DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));
372
373 int k = 0; // this will be our return value
374
375 // greg - If correlation is less than 1 then there's little point in continuing
376 if ((max/(arraylen(FrameSOF)/skip)) >= 1)
377 {
378
379 i = maxPos + arraylen(FrameSOF)/skip;
380
381 uint8_t outBuf[20];
382 memset(outBuf, 0, sizeof(outBuf));
383 uint8_t mask = 0x01;
384 for(;;) {
385 int corr0 = 0, corr1 = 0, corrEOF = 0;
386 for(j = 0; j < arraylen(Logic0); j += skip) {
387 corr0 += Logic0[j]*dest[i+(j/skip)];
388 }
389 for(j = 0; j < arraylen(Logic1); j += skip) {
390 corr1 += Logic1[j]*dest[i+(j/skip)];
391 }
392 for(j = 0; j < arraylen(FrameEOF); j += skip) {
393 corrEOF += FrameEOF[j]*dest[i+(j/skip)];
394 }
395 // Even things out by the length of the target waveform.
396 corr0 *= 4;
397 corr1 *= 4;
398
399 if(corrEOF > corr1 && corrEOF > corr0) {
400 // DbpString("EOF at %d", i);
401 break;
402 } else if(corr1 > corr0) {
403 i += arraylen(Logic1)/skip;
404 outBuf[k] |= mask;
405 } else {
406 i += arraylen(Logic0)/skip;
407 }
408 mask <<= 1;
409 if(mask == 0) {
410 k++;
411 mask = 0x01;
412 }
413 if((i+(int)arraylen(FrameEOF)) >= 2000) {
414 DbpString("ran off end!");
415 break;
416 }
417 }
418 if(mask != 0x01) { // this happens, when we miss the EOF
419 // TODO: for some reason this happens quite often
420 if (DEBUG) Dbprintf("error, uneven octet! (extra bits!) mask=%02x", mask);
421 if (mask<0x08) k--; // discard the last uneven octet;
422 // 0x08 is an assumption - but works quite often
423 }
424 // uint8_t str1 [8];
425 // itoa(k,str1);
426 // strncat(str1," octets read",8);
427
428 // DbpString( str1); // DbpString("%d octets", k);
429
430 // for(i = 0; i < k; i+=3) {
431 // //DbpString("# %2d: %02x ", i, outBuf[i]);
432 // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);
433 // }
434
435 for(i = 0; i < k; i++) {
436 receivedResponse[i] = outBuf[i];
437 }
438 } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))
439 return k; // return the number of bytes demodulated
440
441 /// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));
442
443 }
444
445
446 // Now the GetISO15693 message from sniffing command
447 static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed)
448 {
449 int c = 0;
450 uint8_t *dest = (uint8_t *)BigBuf;
451 int getNext = 0;
452
453 int8_t prev = 0;
454
455 // NOW READ RESPONSE
456 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
457 //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
458 c = 0;
459 getNext = FALSE;
460 for(;;) {
461 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
462 AT91C_BASE_SSC->SSC_THR = 0x43;
463 }
464 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
465 int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
466
467 // The samples are correlations against I and Q versions of the
468 // tone that the tag AM-modulates, so every other sample is I,
469 // every other is Q. We just want power, so abs(I) + abs(Q) is
470 // close to what we want.
471 if (getNext) {
472 int8_t r;
473
474 if(b < 0) {
475 r = -b;
476 } else {
477 r = b;
478 }
479 if(prev < 0) {
480 r -= prev;
481 } else {
482 r += prev;
483 }
484
485 dest[c++] = (uint8_t)r;
486
487 if(c >= 20000) {
488 break;
489 }
490 } else {
491 prev = b;
492 }
493
494 getNext = !getNext;
495 }
496 }
497
498 //////////////////////////////////////////
499 /////////// DEMODULATE ///////////////////
500 //////////////////////////////////////////
501
502 int i, j;
503 int max = 0, maxPos=0;
504
505 int skip = 4;
506
507 // if(GraphTraceLen < 1000) return; // THIS CHECKS FOR A BUFFER TO SMALL
508
509 // First, correlate for SOF
510 for(i = 0; i < 19000; i++) {
511 int corr = 0;
512 for(j = 0; j < arraylen(FrameSOF); j += skip) {
513 corr += FrameSOF[j]*dest[i+(j/skip)];
514 }
515 if(corr > max) {
516 max = corr;
517 maxPos = i;
518 }
519 }
520 // DbpString("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip));
521
522 int k = 0; // this will be our return value
523
524 // greg - If correlation is less than 1 then there's little point in continuing
525 if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1
526 {
527
528 i = maxPos + arraylen(FrameSOF)/skip;
529
530 uint8_t outBuf[20];
531 memset(outBuf, 0, sizeof(outBuf));
532 uint8_t mask = 0x01;
533 for(;;) {
534 int corr0 = 0, corr1 = 0, corrEOF = 0;
535 for(j = 0; j < arraylen(Logic0); j += skip) {
536 corr0 += Logic0[j]*dest[i+(j/skip)];
537 }
538 for(j = 0; j < arraylen(Logic1); j += skip) {
539 corr1 += Logic1[j]*dest[i+(j/skip)];
540 }
541 for(j = 0; j < arraylen(FrameEOF); j += skip) {
542 corrEOF += FrameEOF[j]*dest[i+(j/skip)];
543 }
544 // Even things out by the length of the target waveform.
545 corr0 *= 4;
546 corr1 *= 4;
547
548 if(corrEOF > corr1 && corrEOF > corr0) {
549 // DbpString("EOF at %d", i);
550 break;
551 } else if(corr1 > corr0) {
552 i += arraylen(Logic1)/skip;
553 outBuf[k] |= mask;
554 } else {
555 i += arraylen(Logic0)/skip;
556 }
557 mask <<= 1;
558 if(mask == 0) {
559 k++;
560 mask = 0x01;
561 }
562 if((i+(int)arraylen(FrameEOF)) >= 2000) {
563 DbpString("ran off end!");
564 break;
565 }
566 }
567 if(mask != 0x01) {
568 DbpString("sniff: error, uneven octet! (discard extra bits!)");
569 /// DbpString(" mask=%02x", mask);
570 }
571 // uint8_t str1 [8];
572 // itoa(k,str1);
573 // strncat(str1," octets read",8);
574
575 // DbpString( str1); // DbpString("%d octets", k);
576
577 // for(i = 0; i < k; i+=3) {
578 // //DbpString("# %2d: %02x ", i, outBuf[i]);
579 // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]);
580 // }
581
582 for(i = 0; i < k; i++) {
583 receivedResponse[i] = outBuf[i];
584 }
585 } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip))
586 return k; // return the number of bytes demodulated
587
588 /// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2));
589 }
590
591
592 static void BuildIdentifyRequest(void);
593 //-----------------------------------------------------------------------------
594 // Start to read an ISO 15693 tag. We send an identify request, then wait
595 // for the response. The response is not demodulated, just left in the buffer
596 // so that it can be downloaded to a PC and processed there.
597 //-----------------------------------------------------------------------------
598 void AcquireRawAdcSamplesIso15693(void)
599 {
600 uint8_t *dest = (uint8_t *)BigBuf;
601
602 int c = 0;
603 int getNext = 0;
604 int8_t prev = 0;
605
606 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
607 BuildIdentifyRequest();
608
609 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
610
611 // Give the tags time to energize
612 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
613 SpinDelay(100);
614
615 // Now send the command
616 FpgaSetupSsc();
617 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
618
619 c = 0;
620 for(;;) {
621 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
622 AT91C_BASE_SSC->SSC_THR = ToSend[c];
623 c++;
624 if(c == ToSendMax+3) {
625 break;
626 }
627 }
628 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
629 volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
630 (void)r;
631 }
632 WDT_HIT();
633 }
634
635 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
636
637 c = 0;
638 getNext = FALSE;
639 for(;;) {
640 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
641 AT91C_BASE_SSC->SSC_THR = 0x43;
642 }
643 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
644 int8_t b;
645 b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
646
647 // The samples are correlations against I and Q versions of the
648 // tone that the tag AM-modulates, so every other sample is I,
649 // every other is Q. We just want power, so abs(I) + abs(Q) is
650 // close to what we want.
651 if(getNext) {
652 int8_t r;
653
654 if(b < 0) {
655 r = -b;
656 } else {
657 r = b;
658 }
659 if(prev < 0) {
660 r -= prev;
661 } else {
662 r += prev;
663 }
664
665 dest[c++] = (uint8_t)r;
666
667 if(c >= 2000) {
668 break;
669 }
670 } else {
671 prev = b;
672 }
673
674 getNext = !getNext;
675 }
676 }
677 }
678
679
680 void RecordRawAdcSamplesIso15693(void)
681 {
682 uint8_t *dest = (uint8_t *)BigBuf;
683
684 int c = 0;
685 int getNext = 0;
686 int8_t prev = 0;
687
688 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
689 // Setup SSC
690 FpgaSetupSsc();
691
692 // Start from off (no field generated)
693 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
694 SpinDelay(200);
695
696 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
697
698 SpinDelay(100);
699
700 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
701
702 c = 0;
703 getNext = FALSE;
704 for(;;) {
705 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
706 AT91C_BASE_SSC->SSC_THR = 0x43;
707 }
708 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
709 int8_t b;
710 b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
711
712 // The samples are correlations against I and Q versions of the
713 // tone that the tag AM-modulates, so every other sample is I,
714 // every other is Q. We just want power, so abs(I) + abs(Q) is
715 // close to what we want.
716 if(getNext) {
717 int8_t r;
718
719 if(b < 0) {
720 r = -b;
721 } else {
722 r = b;
723 }
724 if(prev < 0) {
725 r -= prev;
726 } else {
727 r += prev;
728 }
729
730 dest[c++] = (uint8_t)r;
731
732 if(c >= 7000) {
733 break;
734 }
735 } else {
736 prev = b;
737 }
738
739 getNext = !getNext;
740 WDT_HIT();
741 }
742 }
743 Dbprintf("fin record");
744 }
745
746
747 // Initialize the proxmark as iso15k reader
748 // (this might produces glitches that confuse some tags
749 void Iso15693InitReader() {
750 LED_A_ON();
751 LED_B_ON();
752 LED_C_OFF();
753 LED_D_OFF();
754
755 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
756 // Setup SSC
757 // FpgaSetupSsc();
758
759 // Start from off (no field generated)
760 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
761 SpinDelay(10);
762
763 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
764 FpgaSetupSsc();
765
766 // Give the tags time to energize
767 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
768 SpinDelay(250);
769
770 LED_A_ON();
771 LED_B_OFF();
772 LED_C_OFF();
773 LED_D_OFF();
774 }
775
776 ///////////////////////////////////////////////////////////////////////
777 // ISO 15693 Part 3 - Air Interface
778 // This section basicly contains transmission and receiving of bits
779 ///////////////////////////////////////////////////////////////////////
780
781 // Encode (into the ToSend buffers) an identify request, which is the first
782 // thing that you must send to a tag to get a response.
783 static void BuildIdentifyRequest(void)
784 {
785 uint8_t cmd[5];
786
787 uint16_t crc;
788 // one sub-carrier, inventory, 1 slot, fast rate
789 // AFI is at bit 5 (1<<4) when doing an INVENTORY
790 cmd[0] = (1 << 2) | (1 << 5) | (1 << 1);
791 // inventory command code
792 cmd[1] = 0x01;
793 // no mask
794 cmd[2] = 0x00;
795 //Now the CRC
796 crc = Crc(cmd, 3);
797 cmd[3] = crc & 0xff;
798 cmd[4] = crc >> 8;
799
800 CodeIso15693AsReader(cmd, sizeof(cmd));
801 }
802
803 // uid is in transmission order (which is reverse of display order)
804 static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber )
805 {
806 uint8_t cmd[13];
807
808 uint16_t crc;
809 // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
810 // followed by teh block data
811 // one sub-carrier, inventory, 1 slot, fast rate
812 cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit
813 // READ BLOCK command code
814 cmd[1] = 0x20;
815 // UID may be optionally specified here
816 // 64-bit UID
817 cmd[2] = uid[0];
818 cmd[3] = uid[1];
819 cmd[4] = uid[2];
820 cmd[5] = uid[3];
821 cmd[6] = uid[4];
822 cmd[7] = uid[5];
823 cmd[8] = uid[6];
824 cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique)
825 // Block number to read
826 cmd[10] = blockNumber;//0x00;
827 //Now the CRC
828 crc = Crc(cmd, 11); // the crc needs to be calculated over 12 bytes
829 cmd[11] = crc & 0xff;
830 cmd[12] = crc >> 8;
831
832 CodeIso15693AsReader(cmd, sizeof(cmd));
833 }
834
835 // Now the VICC>VCD responses when we are simulating a tag
836 static void BuildInventoryResponse( uint8_t *uid)
837 {
838 uint8_t cmd[12];
839
840 uint16_t crc;
841 // one sub-carrier, inventory, 1 slot, fast rate
842 // AFI is at bit 5 (1<<4) when doing an INVENTORY
843 //(1 << 2) | (1 << 5) | (1 << 1);
844 cmd[0] = 0; //
845 cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported
846 // 64-bit UID
847 cmd[2] = uid[7]; //0x32;
848 cmd[3] = uid[6]; //0x4b;
849 cmd[4] = uid[5]; //0x03;
850 cmd[5] = uid[4]; //0x01;
851 cmd[6] = uid[3]; //0x00;
852 cmd[7] = uid[2]; //0x10;
853 cmd[8] = uid[1]; //0x05;
854 cmd[9] = uid[0]; //0xe0;
855 //Now the CRC
856 crc = Crc(cmd, 10);
857 cmd[10] = crc & 0xff;
858 cmd[11] = crc >> 8;
859
860 CodeIso15693AsReader(cmd, sizeof(cmd));
861 }
862
863 // Universal Method for sending to and recv bytes from a tag
864 // init ... should we initialize the reader?
865 // speed ... 0 low speed, 1 hi speed
866 // **recv will return you a pointer to the received data
867 // If you do not need the answer use NULL for *recv[]
868 // return: lenght of received data
869 int SendDataTag(uint8_t *send, int sendlen, int init, int speed, uint8_t **recv) {
870
871 int samples = 0;
872 int tsamples = 0;
873 int wait = 0;
874 int elapsed = 0;
875
876 LED_A_ON();
877 LED_B_ON();
878 LED_C_OFF();
879 LED_D_OFF();
880
881 int answerLen=0;
882 uint8_t *answer = (((uint8_t *)BigBuf) + 3660);
883 if (recv!=NULL) memset(BigBuf + 3660, 0, 100);
884
885 if (init) Iso15693InitReader();
886
887 if (!speed) {
888 // low speed (1 out of 256)
889 CodeIso15693AsReader256(send, sendlen);
890 } else {
891 // high speed (1 out of 4)
892 CodeIso15693AsReader(send, sendlen);
893 }
894
895 LED_A_ON();
896 LED_B_OFF();
897
898 TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);
899 // Now wait for a response
900 if (recv!=NULL) {
901 LED_A_OFF();
902 LED_B_ON();
903 answerLen = GetIso15693AnswerFromTag(answer, 100, &samples, &elapsed) ;
904 *recv=answer;
905 }
906
907 LED_A_OFF();
908 LED_B_OFF();
909 LED_C_OFF();
910 LED_D_OFF();
911
912 return answerLen;
913 }
914
915
916 // --------------------------------------------------------------------
917 // Debug Functions
918 // --------------------------------------------------------------------
919
920 // Decodes a message from a tag and displays its metadata and content
921 #define DBD15STATLEN 48
922 void DbdecodeIso15693Answer(int len, uint8_t *d) {
923 char status[DBD15STATLEN+1]={0};
924 uint16_t crc;
925
926 if (len>3) {
927 if (d[0]&(1<<3))
928 strncat(status,"ProtExt ",DBD15STATLEN);
929 if (d[0]&1) {
930 // error
931 strncat(status,"Error ",DBD15STATLEN);
932 switch (d[1]) {
933 case 0x01:
934 strncat(status,"01:notSupp",DBD15STATLEN);
935 break;
936 case 0x02:
937 strncat(status,"02:notRecog",DBD15STATLEN);
938 break;
939 case 0x03:
940 strncat(status,"03:optNotSupp",DBD15STATLEN);
941 break;
942 case 0x0f:
943 strncat(status,"0f:noInfo",DBD15STATLEN);
944 break;
945 case 0x10:
946 strncat(status,"10:dontExist",DBD15STATLEN);
947 break;
948 case 0x11:
949 strncat(status,"11:lockAgain",DBD15STATLEN);
950 break;
951 case 0x12:
952 strncat(status,"12:locked",DBD15STATLEN);
953 break;
954 case 0x13:
955 strncat(status,"13:progErr",DBD15STATLEN);
956 break;
957 case 0x14:
958 strncat(status,"14:lockErr",DBD15STATLEN);
959 break;
960 default:
961 strncat(status,"unknownErr",DBD15STATLEN);
962 }
963 strncat(status," ",DBD15STATLEN);
964 } else {
965 strncat(status,"NoErr ",DBD15STATLEN);
966 }
967
968 crc=Crc(d,len-2);
969 if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) )
970 strncat(status,"CrcOK",DBD15STATLEN);
971 else
972 strncat(status,"CrcFail!",DBD15STATLEN);
973
974 Dbprintf("%s",status);
975 }
976 }
977
978
979
980 ///////////////////////////////////////////////////////////////////////
981 // Functions called via USB/Client
982 ///////////////////////////////////////////////////////////////////////
983
984 void SetDebugIso15693(uint32_t debug) {
985 DEBUG=debug;
986 Dbprintf("Iso15693 Debug is now %s",DEBUG?"on":"off");
987 return;
988 }
989
990
991
992 //-----------------------------------------------------------------------------
993 // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector
994 // all demodulation performed in arm rather than host. - greg
995 //-----------------------------------------------------------------------------
996 void ReaderIso15693(uint32_t parameter )
997 {
998 LED_A_ON();
999 LED_B_ON();
1000 LED_C_OFF();
1001 LED_D_OFF();
1002
1003 uint8_t *answer1 = (((uint8_t *)BigBuf) + 3660); //
1004 uint8_t *answer2 = (((uint8_t *)BigBuf) + 3760);
1005 uint8_t *answer3 = (((uint8_t *)BigBuf) + 3860);
1006
1007 int answerLen1 = 0;
1008 int answerLen2 = 0;
1009 int answerLen3 = 0;
1010 int i = 0;
1011 int samples = 0;
1012 int tsamples = 0;
1013 int wait = 0;
1014 int elapsed = 0;
1015 uint8_t TagUID[8] = {0x00};
1016
1017
1018 // Blank arrays
1019 memset(BigBuf + 3660, 0x00, 300);
1020
1021 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
1022
1023 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
1024 // Setup SSC
1025 FpgaSetupSsc();
1026
1027 // Start from off (no field generated)
1028 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1029 SpinDelay(200);
1030
1031 // Give the tags time to energize
1032 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
1033 SpinDelay(200);
1034
1035 LED_A_ON();
1036 LED_B_OFF();
1037 LED_C_OFF();
1038 LED_D_OFF();
1039
1040 // FIRST WE RUN AN INVENTORY TO GET THE TAG UID
1041 // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME
1042
1043 // Now send the IDENTIFY command
1044 BuildIdentifyRequest();
1045
1046 TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);
1047
1048 // Now wait for a response
1049 answerLen1 = GetIso15693AnswerFromTag(answer1, 100, &samples, &elapsed) ;
1050
1051 if (answerLen1 >=12) // we should do a better check than this
1052 {
1053 TagUID[0] = answer1[2];
1054 TagUID[1] = answer1[3];
1055 TagUID[2] = answer1[4];
1056 TagUID[3] = answer1[5];
1057 TagUID[4] = answer1[6];
1058 TagUID[5] = answer1[7];
1059 TagUID[6] = answer1[8]; // IC Manufacturer code
1060 TagUID[7] = answer1[9]; // always E0
1061
1062 }
1063
1064 Dbprintf("%d octets read from IDENTIFY request:", answerLen1);
1065 DbdecodeIso15693Answer(answerLen1,answer1);
1066 Dbhexdump(answerLen1,answer1,true);
1067
1068 // UID is reverse
1069 if (answerLen1 >= 12)
1070 Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX",
1071 TagUID[7],TagUID[6],TagUID[5],TagUID[4],
1072 TagUID[3],TagUID[2],TagUID[1],TagUID[0]);
1073
1074
1075 Dbprintf("%d octets read from SELECT request:", answerLen2);
1076 DbdecodeIso15693Answer(answerLen2,answer2);
1077 Dbhexdump(answerLen2,answer2,true);
1078
1079 Dbprintf("%d octets read from XXX request:", answerLen3);
1080 DbdecodeIso15693Answer(answerLen3,answer3);
1081 Dbhexdump(answerLen3,answer3,true);
1082
1083 // read all pages
1084 if (answerLen1 >= 12 && DEBUG) {
1085 i=0;
1086 while (i < 32) { // sanity check, assume max 32 pages
1087 BuildReadBlockRequest(TagUID,i);
1088 TransmitTo15693Tag(ToSend,ToSendMax,&tsamples, &wait);
1089 answerLen2 = GetIso15693AnswerFromTag(answer2, 100, &samples, &elapsed);
1090 if (answerLen2 > 0) {
1091 Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2);
1092 DbdecodeIso15693Answer(answerLen2,answer2);
1093 Dbhexdump(answerLen2,answer2,true);
1094 if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr
1095 }
1096 i++;
1097 }
1098 }
1099
1100 LED_A_OFF();
1101 LED_B_OFF();
1102 LED_C_OFF();
1103 LED_D_OFF();
1104 }
1105
1106 // Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
1107 // all demodulation performed in arm rather than host. - greg
1108 void SimTagIso15693(uint32_t parameter, uint8_t *uid)
1109 {
1110 LED_A_ON();
1111 LED_B_ON();
1112 LED_C_OFF();
1113 LED_D_OFF();
1114
1115 uint8_t *buf = (((uint8_t *)BigBuf) + 3660); //
1116
1117 int answerLen1 = 0;
1118 int samples = 0;
1119 int tsamples = 0;
1120 int wait = 0;
1121 int elapsed = 0;
1122
1123 memset(buf, 0x00, 100);
1124
1125 FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
1126
1127 SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
1128
1129 FpgaSetupSsc();
1130
1131 // Start from off (no field generated)
1132 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1133 SpinDelay(200);
1134
1135 LED_A_OFF();
1136 LED_B_OFF();
1137 LED_C_ON();
1138 LED_D_OFF();
1139
1140 // Listen to reader
1141 answerLen1 = GetIso15693AnswerFromSniff(buf, 100, &samples, &elapsed) ;
1142
1143 if (answerLen1 >=1) // we should do a better check than this
1144 {
1145 // Build a suitable reponse to the reader INVENTORY cocmmand
1146 // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below.
1147
1148 BuildInventoryResponse(uid);
1149
1150 TransmitTo15693Reader(ToSend, ToSendMax, &tsamples, &wait);
1151 }
1152
1153 Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1,
1154 buf[0], buf[1], buf[2], buf[3],
1155 buf[4], buf[5], buf[6], buf[7], buf[8]);
1156
1157 Dbprintf("Simulationg uid: %x %x %x %x %x %x %x %x",
1158 uid[0], uid[1], uid[2], uid[3],
1159 uid[4], uid[5], uid[6], uid[7]);
1160
1161 LED_A_OFF();
1162 LED_B_OFF();
1163 LED_C_OFF();
1164 LED_D_OFF();
1165 }
1166
1167
1168 // Since there is no standardized way of reading the AFI out of a tag, we will brute force it
1169 // (some manufactures offer a way to read the AFI, though)
1170 void BruteforceIso15693Afi(uint32_t speed)
1171 {
1172 uint8_t data[20];
1173 uint8_t *recv=data;
1174 int datalen=0, recvlen=0;
1175
1176 Iso15693InitReader();
1177
1178 // first without AFI
1179 // Tags should respond wihtout AFI and with AFI=0 even when AFI is active
1180
1181 data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
1182 ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
1183 data[1]=ISO15_CMD_INVENTORY;
1184 data[2]=0; // mask length
1185 datalen=AddCrc(data,3);
1186 recvlen=SendDataTag(data,datalen,0,speed,&recv);
1187 WDT_HIT();
1188 if (recvlen>=12) {
1189 Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2]));
1190 }
1191
1192 // now with AFI
1193
1194 data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
1195 ISO15_REQ_INVENTORY | ISO15_REQINV_AFI | ISO15_REQINV_SLOT1;
1196 data[1]=ISO15_CMD_INVENTORY;
1197 data[2]=0; // AFI
1198 data[3]=0; // mask length
1199
1200 for (int i=0;i<256;i++) {
1201 data[2]=i & 0xFF;
1202 datalen=AddCrc(data,4);
1203 recvlen=SendDataTag(data,datalen,0,speed,&recv);
1204 WDT_HIT();
1205 if (recvlen>=12) {
1206 Dbprintf("AFI=%i UID=%s",i,sprintUID(NULL,&recv[2]));
1207 }
1208 }
1209 Dbprintf("AFI Bruteforcing done.");
1210
1211 }
1212
1213 // Allows to directly send commands to the tag via the client
1214 void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]) {
1215
1216 int recvlen=0;
1217 uint8_t *recvbuf=(uint8_t *)BigBuf;
1218 // UsbCommand n;
1219
1220 if (DEBUG) {
1221 Dbprintf("SEND");
1222 Dbhexdump(datalen,data,true);
1223 }
1224
1225 recvlen=SendDataTag(data,datalen,1,speed,(recv?&recvbuf:NULL));
1226
1227 if (recv) {
1228 LED_B_ON();
1229 cmd_send(CMD_ACK,recvlen>48?48:recvlen,0,0,recvbuf,48);
1230 LED_B_OFF();
1231
1232 if (DEBUG) {
1233 Dbprintf("RECV");
1234 DbdecodeIso15693Answer(recvlen,recvbuf);
1235 Dbhexdump(recvlen,recvbuf,true);
1236 }
1237 }
1238
1239 }
1240
1241
1242
1243
1244 // --------------------------------------------------------------------
1245 // -- Misc & deprecated functions
1246 // --------------------------------------------------------------------
1247
1248 /*
1249
1250 // do not use; has a fix UID
1251 static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid)
1252 {
1253 uint8_t cmd[12];
1254
1255 uint16_t crc;
1256 // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
1257 // followed by teh block data
1258 // one sub-carrier, inventory, 1 slot, fast rate
1259 cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
1260 // System Information command code
1261 cmd[1] = 0x2B;
1262 // UID may be optionally specified here
1263 // 64-bit UID
1264 cmd[2] = 0x32;
1265 cmd[3]= 0x4b;
1266 cmd[4] = 0x03;
1267 cmd[5] = 0x01;
1268 cmd[6] = 0x00;
1269 cmd[7] = 0x10;
1270 cmd[8] = 0x05;
1271 cmd[9]= 0xe0; // always e0 (not exactly unique)
1272 //Now the CRC
1273 crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes
1274 cmd[10] = crc & 0xff;
1275 cmd[11] = crc >> 8;
1276
1277 CodeIso15693AsReader(cmd, sizeof(cmd));
1278 }
1279
1280
1281 // do not use; has a fix UID
1282 static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid)
1283 {
1284 uint8_t cmd[14];
1285
1286 uint16_t crc;
1287 // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
1288 // followed by teh block data
1289 // one sub-carrier, inventory, 1 slot, fast rate
1290 cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
1291 // READ Multi BLOCK command code
1292 cmd[1] = 0x23;
1293 // UID may be optionally specified here
1294 // 64-bit UID
1295 cmd[2] = 0x32;
1296 cmd[3]= 0x4b;
1297 cmd[4] = 0x03;
1298 cmd[5] = 0x01;
1299 cmd[6] = 0x00;
1300 cmd[7] = 0x10;
1301 cmd[8] = 0x05;
1302 cmd[9]= 0xe0; // always e0 (not exactly unique)
1303 // First Block number to read
1304 cmd[10] = 0x00;
1305 // Number of Blocks to read
1306 cmd[11] = 0x2f; // read quite a few
1307 //Now the CRC
1308 crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
1309 cmd[12] = crc & 0xff;
1310 cmd[13] = crc >> 8;
1311
1312 CodeIso15693AsReader(cmd, sizeof(cmd));
1313 }
1314
1315 // do not use; has a fix UID
1316 static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t CmdCode)
1317 {
1318 uint8_t cmd[14];
1319
1320 uint16_t crc;
1321 // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
1322 // followed by teh block data
1323 // one sub-carrier, inventory, 1 slot, fast rate
1324 cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
1325 // READ BLOCK command code
1326 cmd[1] = CmdCode;
1327 // UID may be optionally specified here
1328 // 64-bit UID
1329 cmd[2] = 0x32;
1330 cmd[3]= 0x4b;
1331 cmd[4] = 0x03;
1332 cmd[5] = 0x01;
1333 cmd[6] = 0x00;
1334 cmd[7] = 0x10;
1335 cmd[8] = 0x05;
1336 cmd[9]= 0xe0; // always e0 (not exactly unique)
1337 // Parameter
1338 cmd[10] = 0x00;
1339 cmd[11] = 0x0a;
1340
1341 // cmd[12] = 0x00;
1342 // cmd[13] = 0x00; //Now the CRC
1343 crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
1344 cmd[12] = crc & 0xff;
1345 cmd[13] = crc >> 8;
1346
1347 CodeIso15693AsReader(cmd, sizeof(cmd));
1348 }
1349
1350 // do not use; has a fix UID
1351 static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], uint8_t CmdCode)
1352 {
1353 uint8_t cmd[14];
1354
1355 uint16_t crc;
1356 // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block
1357 // followed by teh block data
1358 // one sub-carrier, inventory, 1 slot, fast rate
1359 cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit
1360 // READ BLOCK command code
1361 cmd[1] = CmdCode;
1362 // UID may be optionally specified here
1363 // 64-bit UID
1364 cmd[2] = 0x32;
1365 cmd[3]= 0x4b;
1366 cmd[4] = 0x03;
1367 cmd[5] = 0x01;
1368 cmd[6] = 0x00;
1369 cmd[7] = 0x10;
1370 cmd[8] = 0x05;
1371 cmd[9]= 0xe0; // always e0 (not exactly unique)
1372 // Parameter
1373 cmd[10] = 0x05; // for custom codes this must be manufcturer code
1374 cmd[11] = 0x00;
1375
1376 // cmd[12] = 0x00;
1377 // cmd[13] = 0x00; //Now the CRC
1378 crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes
1379 cmd[12] = crc & 0xff;
1380 cmd[13] = crc >> 8;
1381
1382 CodeIso15693AsReader(cmd, sizeof(cmd));
1383 }
1384
1385
1386
1387
1388 */
1389
1390
Impressum, Datenschutz