]> cvs.zerfleddert.de Git - proxmark3-svn/blob - armsrc/lfops.c
added better tracing capabilities, fixed some reader issues
[proxmark3-svn] / armsrc / lfops.c
1 //-----------------------------------------------------------------------------
2 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
3 // at your option, any later version. See the LICENSE.txt file for the text of
4 // the license.
5 //-----------------------------------------------------------------------------
6 // Miscellaneous routines for low frequency tag operations.
7 // Tags supported here so far are Texas Instruments (TI), HID
8 // Also routines for raw mode reading/simulating of LF waveform
9 //-----------------------------------------------------------------------------
10
11 #include "proxmark3.h"
12 #include "apps.h"
13 #include "util.h"
14 #include "hitag2.h"
15 #include "crc16.h"
16 #include "string.h"
17
18 void AcquireRawAdcSamples125k(int at134khz)
19 {
20 if (at134khz)
21 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
22 else
23 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
24
25 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
26
27 // Connect the A/D to the peak-detected low-frequency path.
28 SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
29
30 // Give it a bit of time for the resonant antenna to settle.
31 SpinDelay(50);
32
33 // Now set up the SSC to get the ADC samples that are now streaming at us.
34 FpgaSetupSsc();
35
36 // Now call the acquisition routine
37 DoAcquisition125k();
38 }
39
40 // split into two routines so we can avoid timing issues after sending commands //
41 void DoAcquisition125k(void)
42 {
43 uint8_t *dest = (uint8_t *)BigBuf;
44 int n = sizeof(BigBuf);
45 int i;
46
47 memset(dest, 0, n);
48 i = 0;
49 for(;;) {
50 if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
51 AT91C_BASE_SSC->SSC_THR = 0x43;
52 LED_D_ON();
53 }
54 if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
55 dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
56 i++;
57 LED_D_OFF();
58 if (i >= n) break;
59 }
60 }
61 Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
62 dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
63 }
64
65 void ModThenAcquireRawAdcSamples125k(int delay_off, int period_0, int period_1, uint8_t *command)
66 {
67 int at134khz;
68
69 /* Make sure the tag is reset */
70 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
71 SpinDelay(2500);
72
73 // see if 'h' was specified
74 if (command[strlen((char *) command) - 1] == 'h')
75 at134khz = TRUE;
76 else
77 at134khz = FALSE;
78
79 if (at134khz)
80 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
81 else
82 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
83
84 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
85
86 // Give it a bit of time for the resonant antenna to settle.
87 SpinDelay(50);
88 // And a little more time for the tag to fully power up
89 SpinDelay(2000);
90
91 // Now set up the SSC to get the ADC samples that are now streaming at us.
92 FpgaSetupSsc();
93
94 // now modulate the reader field
95 while(*command != '\0' && *command != ' ') {
96 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
97 LED_D_OFF();
98 SpinDelayUs(delay_off);
99 if (at134khz)
100 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
101 else
102 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
103
104 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
105 LED_D_ON();
106 if(*(command++) == '0')
107 SpinDelayUs(period_0);
108 else
109 SpinDelayUs(period_1);
110 }
111 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
112 LED_D_OFF();
113 SpinDelayUs(delay_off);
114 if (at134khz)
115 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
116 else
117 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
118
119 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
120
121 // now do the read
122 DoAcquisition125k();
123 }
124
125 /* blank r/w tag data stream
126 ...0000000000000000 01111111
127 1010101010101010101010101010101010101010101010101010101010101010
128 0011010010100001
129 01111111
130 101010101010101[0]000...
131
132 [5555fe852c5555555555555555fe0000]
133 */
134 void ReadTItag(void)
135 {
136 // some hardcoded initial params
137 // when we read a TI tag we sample the zerocross line at 2Mhz
138 // TI tags modulate a 1 as 16 cycles of 123.2Khz
139 // TI tags modulate a 0 as 16 cycles of 134.2Khz
140 #define FSAMPLE 2000000
141 #define FREQLO 123200
142 #define FREQHI 134200
143
144 signed char *dest = (signed char *)BigBuf;
145 int n = sizeof(BigBuf);
146 // int *dest = GraphBuffer;
147 // int n = GraphTraceLen;
148
149 // 128 bit shift register [shift3:shift2:shift1:shift0]
150 uint32_t shift3 = 0, shift2 = 0, shift1 = 0, shift0 = 0;
151
152 int i, cycles=0, samples=0;
153 // how many sample points fit in 16 cycles of each frequency
154 uint32_t sampleslo = (FSAMPLE<<4)/FREQLO, sampleshi = (FSAMPLE<<4)/FREQHI;
155 // when to tell if we're close enough to one freq or another
156 uint32_t threshold = (sampleslo - sampleshi + 1)>>1;
157
158 // TI tags charge at 134.2Khz
159 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
160
161 // Place FPGA in passthrough mode, in this mode the CROSS_LO line
162 // connects to SSP_DIN and the SSP_DOUT logic level controls
163 // whether we're modulating the antenna (high)
164 // or listening to the antenna (low)
165 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
166
167 // get TI tag data into the buffer
168 AcquireTiType();
169
170 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
171
172 for (i=0; i<n-1; i++) {
173 // count cycles by looking for lo to hi zero crossings
174 if ( (dest[i]<0) && (dest[i+1]>0) ) {
175 cycles++;
176 // after 16 cycles, measure the frequency
177 if (cycles>15) {
178 cycles=0;
179 samples=i-samples; // number of samples in these 16 cycles
180
181 // TI bits are coming to us lsb first so shift them
182 // right through our 128 bit right shift register
183 shift0 = (shift0>>1) | (shift1 << 31);
184 shift1 = (shift1>>1) | (shift2 << 31);
185 shift2 = (shift2>>1) | (shift3 << 31);
186 shift3 >>= 1;
187
188 // check if the cycles fall close to the number
189 // expected for either the low or high frequency
190 if ( (samples>(sampleslo-threshold)) && (samples<(sampleslo+threshold)) ) {
191 // low frequency represents a 1
192 shift3 |= (1<<31);
193 } else if ( (samples>(sampleshi-threshold)) && (samples<(sampleshi+threshold)) ) {
194 // high frequency represents a 0
195 } else {
196 // probably detected a gay waveform or noise
197 // use this as gaydar or discard shift register and start again
198 shift3 = shift2 = shift1 = shift0 = 0;
199 }
200 samples = i;
201
202 // for each bit we receive, test if we've detected a valid tag
203
204 // if we see 17 zeroes followed by 6 ones, we might have a tag
205 // remember the bits are backwards
206 if ( ((shift0 & 0x7fffff) == 0x7e0000) ) {
207 // if start and end bytes match, we have a tag so break out of the loop
208 if ( ((shift0>>16)&0xff) == ((shift3>>8)&0xff) ) {
209 cycles = 0xF0B; //use this as a flag (ugly but whatever)
210 break;
211 }
212 }
213 }
214 }
215 }
216
217 // if flag is set we have a tag
218 if (cycles!=0xF0B) {
219 DbpString("Info: No valid tag detected.");
220 } else {
221 // put 64 bit data into shift1 and shift0
222 shift0 = (shift0>>24) | (shift1 << 8);
223 shift1 = (shift1>>24) | (shift2 << 8);
224
225 // align 16 bit crc into lower half of shift2
226 shift2 = ((shift2>>24) | (shift3 << 8)) & 0x0ffff;
227
228 // if r/w tag, check ident match
229 if ( shift3&(1<<15) ) {
230 DbpString("Info: TI tag is rewriteable");
231 // only 15 bits compare, last bit of ident is not valid
232 if ( ((shift3>>16)^shift0)&0x7fff ) {
233 DbpString("Error: Ident mismatch!");
234 } else {
235 DbpString("Info: TI tag ident is valid");
236 }
237 } else {
238 DbpString("Info: TI tag is readonly");
239 }
240
241 // WARNING the order of the bytes in which we calc crc below needs checking
242 // i'm 99% sure the crc algorithm is correct, but it may need to eat the
243 // bytes in reverse or something
244 // calculate CRC
245 uint32_t crc=0;
246
247 crc = update_crc16(crc, (shift0)&0xff);
248 crc = update_crc16(crc, (shift0>>8)&0xff);
249 crc = update_crc16(crc, (shift0>>16)&0xff);
250 crc = update_crc16(crc, (shift0>>24)&0xff);
251 crc = update_crc16(crc, (shift1)&0xff);
252 crc = update_crc16(crc, (shift1>>8)&0xff);
253 crc = update_crc16(crc, (shift1>>16)&0xff);
254 crc = update_crc16(crc, (shift1>>24)&0xff);
255
256 Dbprintf("Info: Tag data: %x%08x, crc=%x",
257 (unsigned int)shift1, (unsigned int)shift0, (unsigned int)shift2 & 0xFFFF);
258 if (crc != (shift2&0xffff)) {
259 Dbprintf("Error: CRC mismatch, expected %x", (unsigned int)crc);
260 } else {
261 DbpString("Info: CRC is good");
262 }
263 }
264 }
265
266 void WriteTIbyte(uint8_t b)
267 {
268 int i = 0;
269
270 // modulate 8 bits out to the antenna
271 for (i=0; i<8; i++)
272 {
273 if (b&(1<<i)) {
274 // stop modulating antenna
275 LOW(GPIO_SSC_DOUT);
276 SpinDelayUs(1000);
277 // modulate antenna
278 HIGH(GPIO_SSC_DOUT);
279 SpinDelayUs(1000);
280 } else {
281 // stop modulating antenna
282 LOW(GPIO_SSC_DOUT);
283 SpinDelayUs(300);
284 // modulate antenna
285 HIGH(GPIO_SSC_DOUT);
286 SpinDelayUs(1700);
287 }
288 }
289 }
290
291 void AcquireTiType(void)
292 {
293 int i, j, n;
294 // tag transmission is <20ms, sampling at 2M gives us 40K samples max
295 // each sample is 1 bit stuffed into a uint32_t so we need 1250 uint32_t
296 #define TIBUFLEN 1250
297
298 // clear buffer
299 memset(BigBuf,0,sizeof(BigBuf));
300
301 // Set up the synchronous serial port
302 AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DIN;
303 AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN;
304
305 // steal this pin from the SSP and use it to control the modulation
306 AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
307 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
308
309 AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
310 AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
311
312 // Sample at 2 Mbit/s, so TI tags are 16.2 vs. 14.9 clocks long
313 // 48/2 = 24 MHz clock must be divided by 12
314 AT91C_BASE_SSC->SSC_CMR = 12;
315
316 AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(0);
317 AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(32) | AT91C_SSC_MSBF;
318 AT91C_BASE_SSC->SSC_TCMR = 0;
319 AT91C_BASE_SSC->SSC_TFMR = 0;
320
321 LED_D_ON();
322
323 // modulate antenna
324 HIGH(GPIO_SSC_DOUT);
325
326 // Charge TI tag for 50ms.
327 SpinDelay(50);
328
329 // stop modulating antenna and listen
330 LOW(GPIO_SSC_DOUT);
331
332 LED_D_OFF();
333
334 i = 0;
335 for(;;) {
336 if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
337 BigBuf[i] = AT91C_BASE_SSC->SSC_RHR; // store 32 bit values in buffer
338 i++; if(i >= TIBUFLEN) break;
339 }
340 WDT_HIT();
341 }
342
343 // return stolen pin to SSP
344 AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
345 AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT;
346
347 char *dest = (char *)BigBuf;
348 n = TIBUFLEN*32;
349 // unpack buffer
350 for (i=TIBUFLEN-1; i>=0; i--) {
351 for (j=0; j<32; j++) {
352 if(BigBuf[i] & (1 << j)) {
353 dest[--n] = 1;
354 } else {
355 dest[--n] = -1;
356 }
357 }
358 }
359 }
360
361 // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc
362 // if crc provided, it will be written with the data verbatim (even if bogus)
363 // if not provided a valid crc will be computed from the data and written.
364 void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc)
365 {
366 if(crc == 0) {
367 crc = update_crc16(crc, (idlo)&0xff);
368 crc = update_crc16(crc, (idlo>>8)&0xff);
369 crc = update_crc16(crc, (idlo>>16)&0xff);
370 crc = update_crc16(crc, (idlo>>24)&0xff);
371 crc = update_crc16(crc, (idhi)&0xff);
372 crc = update_crc16(crc, (idhi>>8)&0xff);
373 crc = update_crc16(crc, (idhi>>16)&0xff);
374 crc = update_crc16(crc, (idhi>>24)&0xff);
375 }
376 Dbprintf("Writing to tag: %x%08x, crc=%x",
377 (unsigned int) idhi, (unsigned int) idlo, crc);
378
379 // TI tags charge at 134.2Khz
380 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
381 // Place FPGA in passthrough mode, in this mode the CROSS_LO line
382 // connects to SSP_DIN and the SSP_DOUT logic level controls
383 // whether we're modulating the antenna (high)
384 // or listening to the antenna (low)
385 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
386 LED_A_ON();
387
388 // steal this pin from the SSP and use it to control the modulation
389 AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
390 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
391
392 // writing algorithm:
393 // a high bit consists of a field off for 1ms and field on for 1ms
394 // a low bit consists of a field off for 0.3ms and field on for 1.7ms
395 // initiate a charge time of 50ms (field on) then immediately start writing bits
396 // start by writing 0xBB (keyword) and 0xEB (password)
397 // then write 80 bits of data (or 64 bit data + 16 bit crc if you prefer)
398 // finally end with 0x0300 (write frame)
399 // all data is sent lsb firts
400 // finish with 15ms programming time
401
402 // modulate antenna
403 HIGH(GPIO_SSC_DOUT);
404 SpinDelay(50); // charge time
405
406 WriteTIbyte(0xbb); // keyword
407 WriteTIbyte(0xeb); // password
408 WriteTIbyte( (idlo )&0xff );
409 WriteTIbyte( (idlo>>8 )&0xff );
410 WriteTIbyte( (idlo>>16)&0xff );
411 WriteTIbyte( (idlo>>24)&0xff );
412 WriteTIbyte( (idhi )&0xff );
413 WriteTIbyte( (idhi>>8 )&0xff );
414 WriteTIbyte( (idhi>>16)&0xff );
415 WriteTIbyte( (idhi>>24)&0xff ); // data hi to lo
416 WriteTIbyte( (crc )&0xff ); // crc lo
417 WriteTIbyte( (crc>>8 )&0xff ); // crc hi
418 WriteTIbyte(0x00); // write frame lo
419 WriteTIbyte(0x03); // write frame hi
420 HIGH(GPIO_SSC_DOUT);
421 SpinDelay(50); // programming time
422
423 LED_A_OFF();
424
425 // get TI tag data into the buffer
426 AcquireTiType();
427
428 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
429 DbpString("Now use tiread to check");
430 }
431
432 void SimulateTagLowFrequency(int period, int gap, int ledcontrol)
433 {
434 int i;
435 uint8_t *tab = (uint8_t *)BigBuf;
436
437 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);
438
439 AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
440
441 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
442 AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
443
444 #define SHORT_COIL() LOW(GPIO_SSC_DOUT)
445 #define OPEN_COIL() HIGH(GPIO_SSC_DOUT)
446
447 i = 0;
448 for(;;) {
449 while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)) {
450 if(BUTTON_PRESS()) {
451 DbpString("Stopped");
452 return;
453 }
454 WDT_HIT();
455 }
456
457 if (ledcontrol)
458 LED_D_ON();
459
460 if(tab[i])
461 OPEN_COIL();
462 else
463 SHORT_COIL();
464
465 if (ledcontrol)
466 LED_D_OFF();
467
468 while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK) {
469 if(BUTTON_PRESS()) {
470 DbpString("Stopped");
471 return;
472 }
473 WDT_HIT();
474 }
475
476 i++;
477 if(i == period) {
478 i = 0;
479 if (gap) {
480 SHORT_COIL();
481 SpinDelayUs(gap);
482 }
483 }
484 }
485 }
486
487 /* Provides a framework for bidirectional LF tag communication
488 * Encoding is currently Hitag2, but the general idea can probably
489 * be transferred to other encodings.
490 *
491 * The new FPGA code will, for the LF simulator mode, give on SSC_FRAME
492 * (PA15) a thresholded version of the signal from the ADC. Setting the
493 * ADC path to the low frequency peak detection signal, will enable a
494 * somewhat reasonable receiver for modulation on the carrier signal
495 * that is generated by the reader. The signal is low when the reader
496 * field is switched off, and high when the reader field is active. Due
497 * to the way that the signal looks like, mostly only the rising edge is
498 * useful, your mileage may vary.
499 *
500 * Neat perk: PA15 can not only be used as a bit-banging GPIO, but is also
501 * TIOA1, which can be used as the capture input for timer 1. This should
502 * make it possible to measure the exact edge-to-edge time, without processor
503 * intervention.
504 *
505 * Arguments: divisor is the divisor to be sent to the FPGA (e.g. 95 for 125kHz)
506 * t0 is the carrier frequency cycle duration in terms of MCK (384 for 125kHz)
507 *
508 * The following defines are in carrier periods:
509 */
510 #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */
511 #define HITAG_T_1_MIN 24 /* T[1] should be 26..30 */
512 #define HITAG_T_EOF 40 /* T_EOF should be > 36 */
513 #define HITAG_T_WRESP 208 /* T_wresp should be 204..212 */
514
515 static void hitag_handle_frame(int t0, int frame_len, char *frame);
516 //#define DEBUG_RA_VALUES 1
517 #define DEBUG_FRAME_CONTENTS 1
518 void SimulateTagLowFrequencyBidir(int divisor, int t0)
519 {
520 #if DEBUG_RA_VALUES || DEBUG_FRAME_CONTENTS
521 int i = 0;
522 #endif
523 char frame[10];
524 int frame_pos=0;
525
526 DbpString("Starting Hitag2 emulator, press button to end");
527 hitag2_init();
528
529 /* Set up simulator mode, frequency divisor which will drive the FPGA
530 * and analog mux selection.
531 */
532 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_SIMULATOR);
533 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
534 SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
535 RELAY_OFF();
536
537 /* Set up Timer 1:
538 * Capture mode, timer source MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
539 * external trigger rising edge, load RA on rising edge of TIOA, load RB on rising
540 * edge of TIOA. Assign PA15 to TIOA1 (peripheral B)
541 */
542
543 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1);
544 AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME;
545 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
546 AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK |
547 AT91C_TC_ETRGEDG_RISING |
548 AT91C_TC_ABETRG |
549 AT91C_TC_LDRA_RISING |
550 AT91C_TC_LDRB_RISING;
551 AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN |
552 AT91C_TC_SWTRG;
553
554 /* calculate the new value for the carrier period in terms of TC1 values */
555 t0 = t0/2;
556
557 int overflow = 0;
558 while(!BUTTON_PRESS()) {
559 WDT_HIT();
560 if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
561 int ra = AT91C_BASE_TC1->TC_RA;
562 if((ra > t0*HITAG_T_EOF) | overflow) ra = t0*HITAG_T_EOF+1;
563 #if DEBUG_RA_VALUES
564 if(ra > 255 || overflow) ra = 255;
565 ((char*)BigBuf)[i] = ra;
566 i = (i+1) % 8000;
567 #endif
568
569 if(overflow || (ra > t0*HITAG_T_EOF) || (ra < t0*HITAG_T_0_MIN)) {
570 /* Ignore */
571 } else if(ra >= t0*HITAG_T_1_MIN ) {
572 /* '1' bit */
573 if(frame_pos < 8*sizeof(frame)) {
574 frame[frame_pos / 8] |= 1<<( 7-(frame_pos%8) );
575 frame_pos++;
576 }
577 } else if(ra >= t0*HITAG_T_0_MIN) {
578 /* '0' bit */
579 if(frame_pos < 8*sizeof(frame)) {
580 frame[frame_pos / 8] |= 0<<( 7-(frame_pos%8) );
581 frame_pos++;
582 }
583 }
584
585 overflow = 0;
586 LED_D_ON();
587 } else {
588 if(AT91C_BASE_TC1->TC_CV > t0*HITAG_T_EOF) {
589 /* Minor nuisance: In Capture mode, the timer can not be
590 * stopped by a Compare C. There's no way to stop the clock
591 * in software, so we'll just have to note the fact that an
592 * overflow happened and the next loaded timer value might
593 * have wrapped. Also, this marks the end of frame, and the
594 * still running counter can be used to determine the correct
595 * time for the start of the reply.
596 */
597 overflow = 1;
598
599 if(frame_pos > 0) {
600 /* Have a frame, do something with it */
601 #if DEBUG_FRAME_CONTENTS
602 ((char*)BigBuf)[i++] = frame_pos;
603 memcpy( ((char*)BigBuf)+i, frame, 7);
604 i+=7;
605 i = i % sizeof(BigBuf);
606 #endif
607 hitag_handle_frame(t0, frame_pos, frame);
608 memset(frame, 0, sizeof(frame));
609 }
610 frame_pos = 0;
611
612 }
613 LED_D_OFF();
614 }
615 }
616 DbpString("All done");
617 }
618
619 static void hitag_send_bit(int t0, int bit) {
620 if(bit == 1) {
621 /* Manchester: Loaded, then unloaded */
622 LED_A_ON();
623 SHORT_COIL();
624 while(AT91C_BASE_TC1->TC_CV < t0*15);
625 OPEN_COIL();
626 while(AT91C_BASE_TC1->TC_CV < t0*31);
627 LED_A_OFF();
628 } else if(bit == 0) {
629 /* Manchester: Unloaded, then loaded */
630 LED_B_ON();
631 OPEN_COIL();
632 while(AT91C_BASE_TC1->TC_CV < t0*15);
633 SHORT_COIL();
634 while(AT91C_BASE_TC1->TC_CV < t0*31);
635 LED_B_OFF();
636 }
637 AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset clock for the next bit */
638
639 }
640 static void hitag_send_frame(int t0, int frame_len, const char const * frame, int fdt)
641 {
642 OPEN_COIL();
643 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
644
645 /* Wait for HITAG_T_WRESP carrier periods after the last reader bit,
646 * not that since the clock counts since the rising edge, but T_wresp is
647 * with respect to the falling edge, we need to wait actually (T_wresp - T_g)
648 * periods. The gap time T_g varies (4..10).
649 */
650 while(AT91C_BASE_TC1->TC_CV < t0*(fdt-8));
651
652 int saved_cmr = AT91C_BASE_TC1->TC_CMR;
653 AT91C_BASE_TC1->TC_CMR &= ~AT91C_TC_ETRGEDG; /* Disable external trigger for the clock */
654 AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; /* Reset the clock and use it for response timing */
655
656 int i;
657 for(i=0; i<5; i++)
658 hitag_send_bit(t0, 1); /* Start of frame */
659
660 for(i=0; i<frame_len; i++) {
661 hitag_send_bit(t0, !!(frame[i/ 8] & (1<<( 7-(i%8) ))) );
662 }
663
664 OPEN_COIL();
665 AT91C_BASE_TC1->TC_CMR = saved_cmr;
666 }
667
668 /* Callback structure to cleanly separate tag emulation code from the radio layer. */
669 static int hitag_cb(const char* response_data, const int response_length, const int fdt, void *cb_cookie)
670 {
671 hitag_send_frame(*(int*)cb_cookie, response_length, response_data, fdt);
672 return 0;
673 }
674 /* Frame length in bits, frame contents in MSBit first format */
675 static void hitag_handle_frame(int t0, int frame_len, char *frame)
676 {
677 hitag2_handle_command(frame, frame_len, hitag_cb, &t0);
678 }
679
680 // compose fc/8 fc/10 waveform
681 static void fc(int c, int *n) {
682 uint8_t *dest = (uint8_t *)BigBuf;
683 int idx;
684
685 // for when we want an fc8 pattern every 4 logical bits
686 if(c==0) {
687 dest[((*n)++)]=1;
688 dest[((*n)++)]=1;
689 dest[((*n)++)]=0;
690 dest[((*n)++)]=0;
691 dest[((*n)++)]=0;
692 dest[((*n)++)]=0;
693 dest[((*n)++)]=0;
694 dest[((*n)++)]=0;
695 }
696 // an fc/8 encoded bit is a bit pattern of 11000000 x6 = 48 samples
697 if(c==8) {
698 for (idx=0; idx<6; idx++) {
699 dest[((*n)++)]=1;
700 dest[((*n)++)]=1;
701 dest[((*n)++)]=0;
702 dest[((*n)++)]=0;
703 dest[((*n)++)]=0;
704 dest[((*n)++)]=0;
705 dest[((*n)++)]=0;
706 dest[((*n)++)]=0;
707 }
708 }
709
710 // an fc/10 encoded bit is a bit pattern of 1110000000 x5 = 50 samples
711 if(c==10) {
712 for (idx=0; idx<5; idx++) {
713 dest[((*n)++)]=1;
714 dest[((*n)++)]=1;
715 dest[((*n)++)]=1;
716 dest[((*n)++)]=0;
717 dest[((*n)++)]=0;
718 dest[((*n)++)]=0;
719 dest[((*n)++)]=0;
720 dest[((*n)++)]=0;
721 dest[((*n)++)]=0;
722 dest[((*n)++)]=0;
723 }
724 }
725 }
726
727 // prepare a waveform pattern in the buffer based on the ID given then
728 // simulate a HID tag until the button is pressed
729 void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
730 {
731 int n=0, i=0;
732 /*
733 HID tag bitstream format
734 The tag contains a 44bit unique code. This is sent out MSB first in sets of 4 bits
735 A 1 bit is represented as 6 fc8 and 5 fc10 patterns
736 A 0 bit is represented as 5 fc10 and 6 fc8 patterns
737 A fc8 is inserted before every 4 bits
738 A special start of frame pattern is used consisting a0b0 where a and b are neither 0
739 nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)
740 */
741
742 if (hi>0xFFF) {
743 DbpString("Tags can only have 44 bits.");
744 return;
745 }
746 fc(0,&n);
747 // special start of frame marker containing invalid bit sequences
748 fc(8, &n); fc(8, &n); // invalid
749 fc(8, &n); fc(10, &n); // logical 0
750 fc(10, &n); fc(10, &n); // invalid
751 fc(8, &n); fc(10, &n); // logical 0
752
753 WDT_HIT();
754 // manchester encode bits 43 to 32
755 for (i=11; i>=0; i--) {
756 if ((i%4)==3) fc(0,&n);
757 if ((hi>>i)&1) {
758 fc(10, &n); fc(8, &n); // low-high transition
759 } else {
760 fc(8, &n); fc(10, &n); // high-low transition
761 }
762 }
763
764 WDT_HIT();
765 // manchester encode bits 31 to 0
766 for (i=31; i>=0; i--) {
767 if ((i%4)==3) fc(0,&n);
768 if ((lo>>i)&1) {
769 fc(10, &n); fc(8, &n); // low-high transition
770 } else {
771 fc(8, &n); fc(10, &n); // high-low transition
772 }
773 }
774
775 if (ledcontrol)
776 LED_A_ON();
777 SimulateTagLowFrequency(n, 0, ledcontrol);
778
779 if (ledcontrol)
780 LED_A_OFF();
781 }
782
783
784 // loop to capture raw HID waveform then FSK demodulate the TAG ID from it
785 void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
786 {
787 uint8_t *dest = (uint8_t *)BigBuf;
788 int m=0, n=0, i=0, idx=0, found=0, lastval=0;
789 uint32_t hi=0, lo=0;
790
791 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
792 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
793
794 // Connect the A/D to the peak-detected low-frequency path.
795 SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
796
797 // Give it a bit of time for the resonant antenna to settle.
798 SpinDelay(50);
799
800 // Now set up the SSC to get the ADC samples that are now streaming at us.
801 FpgaSetupSsc();
802
803 for(;;) {
804 WDT_HIT();
805 if (ledcontrol)
806 LED_A_ON();
807 if(BUTTON_PRESS()) {
808 DbpString("Stopped");
809 if (ledcontrol)
810 LED_A_OFF();
811 return;
812 }
813
814 i = 0;
815 m = sizeof(BigBuf);
816 memset(dest,128,m);
817 for(;;) {
818 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
819 AT91C_BASE_SSC->SSC_THR = 0x43;
820 if (ledcontrol)
821 LED_D_ON();
822 }
823 if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
824 dest[i] = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
825 // we don't care about actual value, only if it's more or less than a
826 // threshold essentially we capture zero crossings for later analysis
827 if(dest[i] < 127) dest[i] = 0; else dest[i] = 1;
828 i++;
829 if (ledcontrol)
830 LED_D_OFF();
831 if(i >= m) {
832 break;
833 }
834 }
835 }
836
837 // FSK demodulator
838
839 // sync to first lo-hi transition
840 for( idx=1; idx<m; idx++) {
841 if (dest[idx-1]<dest[idx])
842 lastval=idx;
843 break;
844 }
845 WDT_HIT();
846
847 // count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
848 // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere
849 // between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
850 for( i=0; idx<m; idx++) {
851 if (dest[idx-1]<dest[idx]) {
852 dest[i]=idx-lastval;
853 if (dest[i] <= 8) {
854 dest[i]=1;
855 } else {
856 dest[i]=0;
857 }
858
859 lastval=idx;
860 i++;
861 }
862 }
863 m=i;
864 WDT_HIT();
865
866 // we now have a set of cycle counts, loop over previous results and aggregate data into bit patterns
867 lastval=dest[0];
868 idx=0;
869 i=0;
870 n=0;
871 for( idx=0; idx<m; idx++) {
872 if (dest[idx]==lastval) {
873 n++;
874 } else {
875 // a bit time is five fc/10 or six fc/8 cycles so figure out how many bits a pattern width represents,
876 // an extra fc/8 pattern preceeds every 4 bits (about 200 cycles) just to complicate things but it gets
877 // swallowed up by rounding
878 // expected results are 1 or 2 bits, any more and it's an invalid manchester encoding
879 // special start of frame markers use invalid manchester states (no transitions) by using sequences
880 // like 111000
881 if (dest[idx-1]) {
882 n=(n+1)/6; // fc/8 in sets of 6
883 } else {
884 n=(n+1)/5; // fc/10 in sets of 5
885 }
886 switch (n) { // stuff appropriate bits in buffer
887 case 0:
888 case 1: // one bit
889 dest[i++]=dest[idx-1];
890 break;
891 case 2: // two bits
892 dest[i++]=dest[idx-1];
893 dest[i++]=dest[idx-1];
894 break;
895 case 3: // 3 bit start of frame markers
896 dest[i++]=dest[idx-1];
897 dest[i++]=dest[idx-1];
898 dest[i++]=dest[idx-1];
899 break;
900 // When a logic 0 is immediately followed by the start of the next transmisson
901 // (special pattern) a pattern of 4 bit duration lengths is created.
902 case 4:
903 dest[i++]=dest[idx-1];
904 dest[i++]=dest[idx-1];
905 dest[i++]=dest[idx-1];
906 dest[i++]=dest[idx-1];
907 break;
908 default: // this shouldn't happen, don't stuff any bits
909 break;
910 }
911 n=0;
912 lastval=dest[idx];
913 }
914 }
915 m=i;
916 WDT_HIT();
917
918 // final loop, go over previously decoded manchester data and decode into usable tag ID
919 // 111000 bit pattern represent start of frame, 01 pattern represents a 1 and 10 represents a 0
920 for( idx=0; idx<m-6; idx++) {
921 // search for a start of frame marker
922 if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
923 {
924 found=1;
925 idx+=6;
926 if (found && (hi|lo)) {
927 Dbprintf("TAG ID: %x%08x (%d)",
928 (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
929 /* if we're only looking for one tag */
930 if (findone)
931 {
932 *high = hi;
933 *low = lo;
934 return;
935 }
936 hi=0;
937 lo=0;
938 found=0;
939 }
940 }
941 if (found) {
942 if (dest[idx] && (!dest[idx+1]) ) {
943 hi=(hi<<1)|(lo>>31);
944 lo=(lo<<1)|0;
945 } else if ( (!dest[idx]) && dest[idx+1]) {
946 hi=(hi<<1)|(lo>>31);
947 lo=(lo<<1)|1;
948 } else {
949 found=0;
950 hi=0;
951 lo=0;
952 }
953 idx++;
954 }
955 if ( dest[idx] && dest[idx+1] && dest[idx+2] && (!dest[idx+3]) && (!dest[idx+4]) && (!dest[idx+5]) )
956 {
957 found=1;
958 idx+=6;
959 if (found && (hi|lo)) {
960 Dbprintf("TAG ID: %x%08x (%d)",
961 (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
962 /* if we're only looking for one tag */
963 if (findone)
964 {
965 *high = hi;
966 *low = lo;
967 return;
968 }
969 hi=0;
970 lo=0;
971 found=0;
972 }
973 }
974 }
975 WDT_HIT();
976 }
977 }
978
979 /*------------------------------
980 * T5555/T5557/T5567 routines
981 *------------------------------
982 */
983
984 /* T55x7 configuration register definitions */
985 #define T55x7_POR_DELAY 0x00000001
986 #define T55x7_ST_TERMINATOR 0x00000008
987 #define T55x7_PWD 0x00000010
988 #define T55x7_MAXBLOCK_SHIFT 5
989 #define T55x7_AOR 0x00000200
990 #define T55x7_PSKCF_RF_2 0
991 #define T55x7_PSKCF_RF_4 0x00000400
992 #define T55x7_PSKCF_RF_8 0x00000800
993 #define T55x7_MODULATION_DIRECT 0
994 #define T55x7_MODULATION_PSK1 0x00001000
995 #define T55x7_MODULATION_PSK2 0x00002000
996 #define T55x7_MODULATION_PSK3 0x00003000
997 #define T55x7_MODULATION_FSK1 0x00004000
998 #define T55x7_MODULATION_FSK2 0x00005000
999 #define T55x7_MODULATION_FSK1a 0x00006000
1000 #define T55x7_MODULATION_FSK2a 0x00007000
1001 #define T55x7_MODULATION_MANCHESTER 0x00008000
1002 #define T55x7_MODULATION_BIPHASE 0x00010000
1003 #define T55x7_BITRATE_RF_8 0
1004 #define T55x7_BITRATE_RF_16 0x00040000
1005 #define T55x7_BITRATE_RF_32 0x00080000
1006 #define T55x7_BITRATE_RF_40 0x000C0000
1007 #define T55x7_BITRATE_RF_50 0x00100000
1008 #define T55x7_BITRATE_RF_64 0x00140000
1009 #define T55x7_BITRATE_RF_100 0x00180000
1010 #define T55x7_BITRATE_RF_128 0x001C0000
1011
1012 /* T5555 (Q5) configuration register definitions */
1013 #define T5555_ST_TERMINATOR 0x00000001
1014 #define T5555_MAXBLOCK_SHIFT 0x00000001
1015 #define T5555_MODULATION_MANCHESTER 0
1016 #define T5555_MODULATION_PSK1 0x00000010
1017 #define T5555_MODULATION_PSK2 0x00000020
1018 #define T5555_MODULATION_PSK3 0x00000030
1019 #define T5555_MODULATION_FSK1 0x00000040
1020 #define T5555_MODULATION_FSK2 0x00000050
1021 #define T5555_MODULATION_BIPHASE 0x00000060
1022 #define T5555_MODULATION_DIRECT 0x00000070
1023 #define T5555_INVERT_OUTPUT 0x00000080
1024 #define T5555_PSK_RF_2 0
1025 #define T5555_PSK_RF_4 0x00000100
1026 #define T5555_PSK_RF_8 0x00000200
1027 #define T5555_USE_PWD 0x00000400
1028 #define T5555_USE_AOR 0x00000800
1029 #define T5555_BITRATE_SHIFT 12
1030 #define T5555_FAST_WRITE 0x00004000
1031 #define T5555_PAGE_SELECT 0x00008000
1032
1033 /*
1034 * Relevant times in microsecond
1035 * To compensate antenna falling times shorten the write times
1036 * and enlarge the gap ones.
1037 */
1038 #define START_GAP 250
1039 #define WRITE_GAP 160
1040 #define WRITE_0 144 // 192
1041 #define WRITE_1 400 // 432 for T55x7; 448 for E5550
1042
1043 // Write one bit to card
1044 void T55xxWriteBit(int bit)
1045 {
1046 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
1047 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
1048 if (bit == 0)
1049 SpinDelayUs(WRITE_0);
1050 else
1051 SpinDelayUs(WRITE_1);
1052 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1053 SpinDelayUs(WRITE_GAP);
1054 }
1055
1056 // Write one card block in page 0, no lock
1057 void T55xxWriteBlock(int Data, int Block)
1058 {
1059 unsigned int i;
1060
1061 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
1062 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
1063
1064 // Give it a bit of time for the resonant antenna to settle.
1065 // And for the tag to fully power up
1066 SpinDelay(150);
1067
1068 // Now start writting
1069 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1070 SpinDelayUs(START_GAP);
1071
1072 // Opcode
1073 T55xxWriteBit(1);
1074 T55xxWriteBit(0); //Page 0
1075 // Lock bit
1076 T55xxWriteBit(0);
1077
1078 // Data
1079 for (i = 0x80000000; i != 0; i >>= 1)
1080 T55xxWriteBit(Data & i);
1081
1082 // Page
1083 for (i = 0x04; i != 0; i >>= 1)
1084 T55xxWriteBit(Block & i);
1085
1086 // Now perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550,
1087 // so wait a little more)
1088 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
1089 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER);
1090 SpinDelay(20);
1091 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
1092 }
1093
1094 // Copy HID id to card and setup block 0 config
1095 void CopyHIDtoT5567(int hi, int lo)
1096 {
1097 int data1, data2, data3;
1098
1099 // Ensure no more than 44 bits supplied
1100 if (hi>0xFFF) {
1101 DbpString("Tags can only have 44 bits.");
1102 return;
1103 }
1104
1105 // Build the 3 data blocks for supplied 44bit ID
1106 data1 = 0x1D000000; // load preamble
1107
1108 for (int i=0;i<12;i++) {
1109 if (hi & (1<<(11-i)))
1110 data1 |= (1<<(((11-i)*2)+1)); // 1 -> 10
1111 else
1112 data1 |= (1<<((11-i)*2)); // 0 -> 01
1113 }
1114
1115 data2 = 0;
1116 for (int i=0;i<16;i++) {
1117 if (lo & (1<<(31-i)))
1118 data2 |= (1<<(((15-i)*2)+1)); // 1 -> 10
1119 else
1120 data2 |= (1<<((15-i)*2)); // 0 -> 01
1121 }
1122
1123 data3 = 0;
1124 for (int i=0;i<16;i++) {
1125 if (lo & (1<<(15-i)))
1126 data3 |= (1<<(((15-i)*2)+1)); // 1 -> 10
1127 else
1128 data3 |= (1<<((15-i)*2)); // 0 -> 01
1129 }
1130
1131 // Program the 3 data blocks for supplied 44bit ID
1132 // and the block 0 for HID format
1133 T55xxWriteBlock(data1,1);
1134 T55xxWriteBlock(data2,2);
1135 T55xxWriteBlock(data3,3);
1136
1137 // Config for HID (RF/50, FSK2a, Maxblock=3)
1138 T55xxWriteBlock(T55x7_BITRATE_RF_50 |
1139 T55x7_MODULATION_MANCHESTER |
1140 3 << T55x7_MAXBLOCK_SHIFT,
1141 0);
1142
1143 DbpString("DONE!");
1144 }
1145
1146 // Define 9bit header for EM410x tags
1147 #define EM410X_HEADER 0x1FF
1148 #define EM410X_ID_LENGTH 40
1149
1150 void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo)
1151 {
1152 int i, id_bit;
1153 uint64_t id = EM410X_HEADER;
1154 uint64_t rev_id = 0; // reversed ID
1155 int c_parity[4]; // column parity
1156 int r_parity = 0; // row parity
1157
1158 // Reverse ID bits given as parameter (for simpler operations)
1159 for (i = 0; i < EM410X_ID_LENGTH; ++i) {
1160 if (i < 32) {
1161 rev_id = (rev_id << 1) | (id_lo & 1);
1162 id_lo >>= 1;
1163 } else {
1164 rev_id = (rev_id << 1) | (id_hi & 1);
1165 id_hi >>= 1;
1166 }
1167 }
1168
1169 for (i = 0; i < EM410X_ID_LENGTH; ++i) {
1170 id_bit = rev_id & 1;
1171
1172 if (i % 4 == 0) {
1173 // Don't write row parity bit at start of parsing
1174 if (i)
1175 id = (id << 1) | r_parity;
1176 // Start counting parity for new row
1177 r_parity = id_bit;
1178 } else {
1179 // Count row parity
1180 r_parity ^= id_bit;
1181 }
1182
1183 // First elements in column?
1184 if (i < 4)
1185 // Fill out first elements
1186 c_parity[i] = id_bit;
1187 else
1188 // Count column parity
1189 c_parity[i % 4] ^= id_bit;
1190
1191 // Insert ID bit
1192 id = (id << 1) | id_bit;
1193 rev_id >>= 1;
1194 }
1195
1196 // Insert parity bit of last row
1197 id = (id << 1) | r_parity;
1198
1199 // Fill out column parity at the end of tag
1200 for (i = 0; i < 4; ++i)
1201 id = (id << 1) | c_parity[i];
1202
1203 // Add stop bit
1204 id <<= 1;
1205
1206 Dbprintf("Started writing %s tag ...", card ? "T55x7":"T5555");
1207 LED_D_ON();
1208
1209 // Write EM410x ID
1210 T55xxWriteBlock((uint32_t)(id >> 32), 1);
1211 T55xxWriteBlock((uint32_t)id, 2);
1212
1213 // Config for EM410x (RF/64, Manchester, Maxblock=2)
1214 if (card)
1215 // Writing configuration for T55x7 tag
1216 T55xxWriteBlock(T55x7_BITRATE_RF_64 |
1217 T55x7_MODULATION_MANCHESTER |
1218 2 << T55x7_MAXBLOCK_SHIFT,
1219 0);
1220 else
1221 // Writing configuration for T5555(Q5) tag
1222 T55xxWriteBlock(0x1F << T5555_BITRATE_SHIFT |
1223 T5555_MODULATION_MANCHESTER |
1224 2 << T5555_MAXBLOCK_SHIFT,
1225 0);
1226
1227 LED_D_OFF();
1228 Dbprintf("Tag %s written with 0x%08x%08x\n", card ? "T55x7":"T5555",
1229 (uint32_t)(id >> 32), (uint32_t)id);
1230 }
Impressum, Datenschutz