Merge pull request #2616 from jmichelp/fix14b
[RRG-proxmark3.git] / armsrc / pcf7931.c
blob2d56943af66a5277c2c9957e4731c69e08e3a533
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 #include "pcf7931.h"
18 #include "proxmark3_arm.h"
19 #include "cmd.h"
20 #include "BigBuf.h"
21 #include "fpgaloader.h"
22 #include "ticks.h"
23 #include "dbprint.h"
24 #include "util.h"
25 #include "lfsampling.h"
26 #include "string.h"
28 #define T0_PCF 8 //period for the pcf7931 in us
29 #define ALLOC 16
31 size_t DemodPCF7931(uint8_t **outBlocks, bool ledcontrol) {
33 // 2021 iceman, memor
34 uint8_t bits[256] = {0x00};
35 uint8_t blocks[8][16];
37 uint8_t *dest = BigBuf_get_addr();
39 int g_GraphTraceLen = BigBuf_max_traceLen();
40 if (g_GraphTraceLen > 18000) {
41 g_GraphTraceLen = 18000;
44 int i = 2, j, lastval, bitidx, half_switch;
45 int clock = 64;
46 int tolerance = clock / 8;
47 int pmc, block_done;
48 int lc, warnings = 0;
49 size_t num_blocks = 0;
50 int lmin = 64, lmax = 192;
51 uint8_t dir;
53 BigBuf_Clear_keep_EM();
54 LFSetupFPGAForADC(LF_DIVISOR_125, true);
55 DoAcquisition_default(0, true, ledcontrol);
57 /* Find first local max/min */
58 if (dest[1] > dest[0]) {
59 while (i < g_GraphTraceLen) {
60 if (!(dest[i] > dest[i - 1]) && dest[i] > lmax) {
61 break;
63 i++;
65 dir = 0;
66 } else {
67 while (i < g_GraphTraceLen) {
68 if (!(dest[i] < dest[i - 1]) && dest[i] < lmin) {
69 break;
71 i++;
73 dir = 1;
76 lastval = i++;
77 half_switch = 0;
78 pmc = 0;
79 block_done = 0;
81 for (bitidx = 0; i < g_GraphTraceLen; i++) {
83 if ((dest[i - 1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i - 1] < dest[i] && dir == 0 && dest[i] < lmin)) {
84 lc = i - lastval;
85 lastval = i;
87 // Switch depending on lc length:
88 // Tolerance is 1/8 of clock rate (arbitrary)
89 if (ABS(lc - clock / 4) < tolerance) {
90 // 16T0
91 if ((i - pmc) == lc) { // 16T0 was previous one
92 // It's a PMC
93 i += (128 + 127 + 16 + 32 + 33 + 16) - 1;
94 lastval = i;
95 pmc = 0;
96 block_done = 1;
97 } else {
98 pmc = i;
100 } else if (ABS(lc - clock / 2) < tolerance) {
101 // 32TO
102 if ((i - pmc) == lc) { // 16T0 was previous one
103 // It's a PMC !
104 i += (128 + 127 + 16 + 32 + 33) - 1;
105 lastval = i;
106 pmc = 0;
107 block_done = 1;
108 } else if (half_switch == 1) {
109 bits[bitidx++] = 0;
110 half_switch = 0;
111 } else
112 half_switch++;
113 } else if (ABS(lc - clock) < tolerance) {
114 // 64TO
115 bits[bitidx++] = 1;
116 } else {
117 // Error
118 if (++warnings > 10) {
120 if (g_dbglevel >= DBG_EXTENDED) {
121 Dbprintf("Error: too many detection errors, aborting");
124 return 0;
128 if (block_done == 1) {
129 if (bitidx == 128) {
130 for (j = 0; j < 16; ++j) {
131 blocks[num_blocks][j] =
132 128 * bits[j * 8 + 7] +
133 64 * bits[j * 8 + 6] +
134 32 * bits[j * 8 + 5] +
135 16 * bits[j * 8 + 4] +
136 8 * bits[j * 8 + 3] +
137 4 * bits[j * 8 + 2] +
138 2 * bits[j * 8 + 1] +
139 bits[j * 8]
142 num_blocks++;
144 bitidx = 0;
145 block_done = 0;
146 half_switch = 0;
149 if (i < g_GraphTraceLen) {
150 dir = (dest[i - 1] > dest[i]) ? 0 : 1;
154 if (bitidx == 255) {
155 bitidx = 0;
158 if (num_blocks == 4) {
159 break;
162 memcpy(outBlocks, blocks, 16 * num_blocks);
163 return num_blocks;
166 bool IsBlock0PCF7931(uint8_t *block) {
167 // assuming all RFU bits are set to 0
168 // if PAC is enabled password is set to 0
169 if (block[7] == 0x01) {
170 if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) &&
171 !memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7)) {
172 return true;
175 } else if (block[7] == 0x00) {
176 if (!memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7)) {
177 return true;
180 return false;
183 bool IsBlock1PCF7931(const uint8_t *block) {
184 // assuming all RFU bits are set to 0
186 uint8_t rb1 = block[14] & 0x80;
187 uint8_t rfb = block[14] & 0x7f;
188 uint8_t rlb = block[15];
190 if (block[10] == 0
191 && block[11] == 0
192 && block[12] == 0
193 && block[13] == 0) {
194 // block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled
195 if (rfb <= rlb
196 && rfb <= 9
197 && rlb <= 9
198 && ((rfb <= 1 && rlb >= 1) || rb1)) {
199 return true;
203 return false;
206 void ReadPCF7931(bool ledcontrol) {
207 int found_blocks = 0; // successfully read blocks
208 int max_blocks = 8; // readable blocks
209 uint8_t memory_blocks[8][17]; // PCF content
210 uint8_t single_blocks[8][17]; // PFC blocks with unknown position
211 int single_blocks_cnt = 0;
213 size_t n; // transmitted blocks
214 uint8_t tmp_blocks[4][16]; // temporary read buffer
216 uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
217 int errors = 0; // error counter
218 int tries = 0; // tries counter
220 memset(memory_blocks, 0, 8 * 17 * sizeof(uint8_t));
221 memset(single_blocks, 0, 8 * 17 * sizeof(uint8_t));
223 int i = 0, j = 0;
225 do {
226 i = 0;
228 memset(tmp_blocks, 0, 4 * 16 * sizeof(uint8_t));
229 n = DemodPCF7931((uint8_t **)tmp_blocks, ledcontrol);
230 if (!n)
231 ++errors;
233 // exit if no block is received
234 if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
236 if (g_dbglevel >= DBG_INFO)
237 Dbprintf("[!!] Error, no tag or bad tag");
239 return;
241 // exit if too many errors during reading
242 if (tries > 50 && (2 * errors > tries)) {
244 if (g_dbglevel >= DBG_INFO) {
245 Dbprintf("[!!] Error reading the tag, only partial content");
248 goto end;
251 // our logic breaks if we don't get at least two blocks
252 if (n < 2) {
253 // skip if all 0s block or no blocks
254 if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
255 continue;
257 // add block to single blocks list
258 if (single_blocks_cnt < max_blocks) {
259 for (i = 0; i < single_blocks_cnt; ++i) {
260 if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
261 j = 1;
262 break;
265 if (j != 1) {
266 memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
267 print_result("got single block", single_blocks[single_blocks_cnt], 16);
268 single_blocks_cnt++;
270 j = 0;
272 ++tries;
273 continue;
276 if (g_dbglevel >= DBG_EXTENDED)
277 Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
279 for (i = 0; i < n; ++i) {
280 print_result("got consecutive blocks", tmp_blocks[i], 16);
283 i = 0;
284 if (!found_0_1) {
285 while (i < n - 1) {
286 if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i + 1])) {
287 found_0_1 = 1;
288 memcpy(memory_blocks[0], tmp_blocks[i], 16);
289 memcpy(memory_blocks[1], tmp_blocks[i + 1], 16);
290 memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
291 // block 1 tells how many blocks are going to be sent
292 max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
293 found_blocks = 2;
295 Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
297 // handle the following blocks
298 for (j = i + 2; j < n; ++j) {
299 memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
300 memory_blocks[found_blocks][ALLOC] = 1;
301 ++found_blocks;
303 break;
305 ++i;
307 } else {
308 // Trying to re-order blocks
309 // Look for identical block in memory blocks
310 while (i < n - 1) {
311 // skip all zeroes blocks
312 if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
313 for (j = 1; j < max_blocks - 1; ++j) {
314 if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j + 1][ALLOC]) {
315 memcpy(memory_blocks[j + 1], tmp_blocks[i + 1], 16);
316 memory_blocks[j + 1][ALLOC] = 1;
317 if (++found_blocks >= max_blocks) goto end;
321 if (memcmp(tmp_blocks[i + 1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
322 for (j = 0; j < max_blocks; ++j) {
323 if (!memcmp(tmp_blocks[i + 1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) - 1][ALLOC]) {
324 if (j == 0) {
325 memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16);
326 memory_blocks[max_blocks - 1][ALLOC] = 1;
327 } else {
328 memcpy(memory_blocks[j - 1], tmp_blocks[i], 16);
329 memory_blocks[j - 1][ALLOC] = 1;
331 if (++found_blocks >= max_blocks) goto end;
335 ++i;
338 ++tries;
339 if (BUTTON_PRESS()) {
340 if (g_dbglevel >= DBG_EXTENDED)
341 Dbprintf("Button pressed, stopping.");
343 goto end;
345 } while (found_blocks < max_blocks);
347 end:
348 Dbprintf("-----------------------------------------");
349 Dbprintf("Memory content:");
350 Dbprintf("-----------------------------------------");
351 for (i = 0; i < max_blocks; ++i) {
352 if (memory_blocks[i][ALLOC])
353 print_result("Block", memory_blocks[i], 16);
354 else
355 Dbprintf("<missing block %d>", i);
357 Dbprintf("-----------------------------------------");
359 if (found_blocks < max_blocks) {
360 Dbprintf("-----------------------------------------");
361 Dbprintf("Blocks with unknown position:");
362 Dbprintf("-----------------------------------------");
363 for (i = 0; i < single_blocks_cnt; ++i)
364 print_result("Block", single_blocks[i], 16);
366 Dbprintf("-----------------------------------------");
368 reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
371 static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol) {
372 uint32_t tab[1024] = {0}; // data times frame
373 uint32_t u = 0;
374 uint8_t parity = 0;
375 bool comp = 0;
377 //BUILD OF THE DATA FRAME
378 //alimentation of the tag (time for initializing)
379 AddPatternPCF7931(init_delay, 0, 8192 / 2 * T0_PCF, tab);
380 AddPatternPCF7931(8192 / 2 * T0_PCF + 319 * T0_PCF + 70, 3 * T0_PCF, 29 * T0_PCF, tab);
381 //password indication bit
382 AddBitPCF7931(1, tab, l, p);
383 //password (on 56 bits)
384 AddBytePCF7931(pass[0], tab, l, p);
385 AddBytePCF7931(pass[1], tab, l, p);
386 AddBytePCF7931(pass[2], tab, l, p);
387 AddBytePCF7931(pass[3], tab, l, p);
388 AddBytePCF7931(pass[4], tab, l, p);
389 AddBytePCF7931(pass[5], tab, l, p);
390 AddBytePCF7931(pass[6], tab, l, p);
391 //programming mode (0 or 1)
392 AddBitPCF7931(0, tab, l, p);
394 //block address on 6 bits
395 for (u = 0; u < 6; ++u) {
396 if (address & (1 << u)) { // bit 1
397 ++parity;
398 AddBitPCF7931(1, tab, l, p);
399 } else { // bit 0
400 AddBitPCF7931(0, tab, l, p);
404 //byte address on 4 bits
405 for (u = 0; u < 4; ++u) {
406 if (byte & (1 << u)) { // bit 1
407 parity++;
408 AddBitPCF7931(1, tab, l, p);
409 } else // bit 0
410 AddBitPCF7931(0, tab, l, p);
413 //data on 8 bits
414 for (u = 0; u < 8; u++) {
415 if (data & (1 << u)) { // bit 1
416 parity++;
417 AddBitPCF7931(1, tab, l, p);
418 } else //bit 0
419 AddBitPCF7931(0, tab, l, p);
422 //parity bit
423 if ((parity % 2) == 0)
424 AddBitPCF7931(0, tab, l, p); //even parity
425 else
426 AddBitPCF7931(1, tab, l, p);//odd parity
428 //time access memory
429 AddPatternPCF7931(5120 + 2680, 0, 0, tab);
431 //conversion of the scale time
432 for (u = 0; u < 500; ++u)
433 tab[u] = (tab[u] * 3) / 2;
435 //compensation of the counter reload
436 while (!comp) {
437 comp = 1;
438 for (u = 0; tab[u] != 0; ++u)
439 if (tab[u] > 0xFFFF) {
440 tab[u] -= 0xFFFF;
441 comp = 0;
445 SendCmdPCF7931(tab, ledcontrol);
448 /* Write on a byte of a PCF7931 tag
449 * @param address : address of the block to write
450 @param byte : address of the byte to write
451 @param data : data to write
453 void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data, bool ledcontrol) {
455 if (g_dbglevel >= DBG_INFO) {
456 Dbprintf("Initialization delay : %d us", init_delay);
457 Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
460 Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
461 Dbprintf("Block address : %02x", address);
462 Dbprintf("Byte address : %02x", byte);
463 Dbprintf("Data : %02x", data);
465 uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
467 RealWritePCF7931(password, init_delay, l, p, address, byte, data, ledcontrol);
471 /* Send a trame to a PCF7931 tags
472 * @param tab : array of the data frame
475 void SendCmdPCF7931(const uint32_t *tab, bool ledcontrol) {
476 uint16_t u = 0, tempo = 0;
478 if (g_dbglevel >= DBG_INFO) {
479 Dbprintf("Sending data frame...");
482 FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
483 FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz
484 FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
486 if (ledcontrol) LED_A_ON();
488 // steal this pin from the SSP and use it to control the modulation
489 AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
490 AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
492 //initialization of the timer
493 AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
494 AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
495 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
496 AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; // clock at 48/32 MHz
497 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
499 // Assert a sync signal. This sets all timers to 0 on next active clock edge
500 AT91C_BASE_TCB->TCB_BCR = 1;
502 tempo = AT91C_BASE_TC0->TC_CV;
503 for (u = 0; tab[u] != 0; u += 3) {
504 // modulate antenna
505 HIGH(GPIO_SSC_DOUT);
506 while (tempo != tab[u]) {
507 tempo = AT91C_BASE_TC0->TC_CV;
510 // stop modulating antenna
511 LOW(GPIO_SSC_DOUT);
512 while (tempo != tab[u + 1]) {
513 tempo = AT91C_BASE_TC0->TC_CV;
516 // modulate antenna
517 HIGH(GPIO_SSC_DOUT);
518 while (tempo != tab[u + 2]) {
519 tempo = AT91C_BASE_TC0->TC_CV;
523 if (ledcontrol) LED_A_OFF();
524 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
525 SpinDelay(200);
527 AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
531 /* Add a byte for building the data frame of PCF7931 tags
532 * @param b : byte to add
533 * @param tab : array of the data frame
534 * @param l : offset on low pulse width
535 * @param p : offset on low pulse positioning
537 bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int32_t l, int32_t p) {
538 uint32_t u;
539 for (u = 0; u < 8; ++u) {
540 if (byte & (1 << u)) { //bit is 1
541 if (AddBitPCF7931(1, tab, l, p) == 1) return true;
542 } else { //bit is 0
543 if (AddBitPCF7931(0, tab, l, p) == 1) return true;
547 return false;
550 /* Add a bits for building the data frame of PCF7931 tags
551 * @param b : bit to add
552 * @param tab : array of the data frame
553 * @param l : offset on low pulse width
554 * @param p : offset on low pulse positioning
556 bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p) {
557 uint8_t u = 0;
559 //we put the cursor at the last value of the array
560 for (u = 0; tab[u] != 0; u += 3) { };
562 if (b == 1) { //add a bit 1
563 if (u == 0)
564 tab[u] = 34 * T0_PCF + p;
565 else
566 tab[u] = 34 * T0_PCF + tab[u - 1] + p;
568 tab[u + 1] = 6 * T0_PCF + tab[u] + l;
569 tab[u + 2] = 88 * T0_PCF + tab[u + 1] - l - p;
570 return false;
571 } else { //add a bit 0
573 if (u == 0)
574 tab[u] = 98 * T0_PCF + p;
575 else
576 tab[u] = 98 * T0_PCF + tab[u - 1] + p;
578 tab[u + 1] = 6 * T0_PCF + tab[u] + l;
579 tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p;
580 return false;
582 return true;
585 /* Add a custom pattern in the data frame
586 * @param a : delay of the first high pulse
587 * @param b : delay of the low pulse
588 * @param c : delay of the last high pulse
589 * @param tab : array of the data frame
591 bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab) {
592 uint32_t u = 0;
593 for (u = 0; tab[u] != 0; u += 3) {} //we put the cursor at the last value of the array
595 tab[u] = (u == 0) ? a : a + tab[u - 1];
596 tab[u + 1] = b + tab[u];
597 tab[u + 2] = c + tab[u + 1];
599 return true;