1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
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.
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 // Analyse bytes commands
17 //-----------------------------------------------------------------------------
18 #include "cmdanalyse.h"
20 #include <stdlib.h> // size_t
22 #include <ctype.h> // tolower
24 #include <inttypes.h> // PRIx64 macro
25 #include "commonutil.h" // reflect...
26 #include "comms.h" // clearCommandBuffer
27 #include "cmdparser.h" // command_t
28 #include "ui.h" // PrintAndLog
30 #include "crc16.h" // crc16 ccitt
31 #include "crc32.h" // crc32_ex
32 #include "legic_prng.h"
33 #include "cmddata.h" // g_DemodBuffer
36 #include "cliparser.h"
37 #include "generator.h" // generate nuid
38 #include "iso14b.h" // defines for ETU conversions
40 static int CmdHelp(const char *Cmd
);
42 static uint8_t calculateLRC(const uint8_t *d
, uint8_t n
) {
44 for (uint8_t i
= 0; i
< n
; i
++)
49 static uint16_t matrixadd ( uint8_t* bytes, uint8_t len){
62 static uint16_t shiftadd ( uint8_t* bytes, uint8_t len){
66 static uint16_t calcSumCrumbAdd(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
68 for (uint8_t i
= 0; i
< len
; i
++) {
69 sum
+= CRUMB(bytes
[i
], 0);
70 sum
+= CRUMB(bytes
[i
], 2);
71 sum
+= CRUMB(bytes
[i
], 4);
72 sum
+= CRUMB(bytes
[i
], 6);
75 return (sum
& 0xFFFF);
77 static uint16_t calcSumCrumbAddOnes(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
78 return (~calcSumCrumbAdd(bytes
, len
, mask
) & mask
);
80 static uint16_t calcSumNibbleAdd(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
82 for (uint8_t i
= 0; i
< len
; i
++) {
83 sum
+= NIBBLE_LOW(bytes
[i
]);
84 sum
+= NIBBLE_HIGH(bytes
[i
]);
87 return (sum
& 0xFFFF);
89 static uint16_t calcSumNibbleAddOnes(uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
90 return (~calcSumNibbleAdd(bytes
, len
, mask
) & mask
);
92 static uint16_t calcSumCrumbXor(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
94 for (uint8_t i
= 0; i
< len
; i
++) {
95 sum
^= CRUMB(bytes
[i
], 0);
96 sum
^= CRUMB(bytes
[i
], 2);
97 sum
^= CRUMB(bytes
[i
], 4);
98 sum
^= CRUMB(bytes
[i
], 6);
101 return (sum
& 0xFFFF);
103 static uint16_t calcSumNibbleXor(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
105 for (uint8_t i
= 0; i
< len
; i
++) {
106 sum
^= NIBBLE_LOW(bytes
[i
]);
107 sum
^= NIBBLE_HIGH(bytes
[i
]);
110 return (sum
& 0xFFFF);
112 static uint16_t calcSumByteXor(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
114 for (uint8_t i
= 0; i
< len
; i
++) {
118 return (sum
& 0xFFFF);
120 static uint16_t calcSumByteAdd(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
122 for (uint8_t i
= 0; i
< len
; i
++) {
126 return (sum
& 0xFFFF);
129 static uint16_t calcSumByteAddOnes(uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
130 return (~calcSumByteAdd(bytes
, len
, mask
) & mask
);
133 static uint16_t calcSumByteSub(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
135 for (uint8_t i
= 0; i
< len
; i
++) {
139 return (sum
& 0xFFFF);
141 static uint16_t calcSumByteSubOnes(uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
142 return (~calcSumByteSub(bytes
, len
, mask
) & mask
);
144 static uint16_t calcSumNibbleSub(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
146 for (uint8_t i
= 0; i
< len
; i
++) {
147 sum
-= NIBBLE_LOW(bytes
[i
]);
148 sum
-= NIBBLE_HIGH(bytes
[i
]);
151 return (sum
& 0xFFFF);
153 static uint16_t calcSumNibbleSubOnes(uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
154 return (~calcSumNibbleSub(bytes
, len
, mask
) & mask
);
157 // BSD shift checksum 8bit version
158 static uint16_t calcBSDchecksum8(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
160 for (uint8_t i
= 0; i
< len
; i
++) {
161 sum
= ((sum
& 0xFF) >> 1) | ((sum
& 0x1) << 7); // rotate accumulator
162 sum
+= bytes
[i
]; // add next byte
166 return (sum
& 0xFFFF);
168 // BSD shift checksum 4bit version
169 static uint16_t calcBSDchecksum4(const uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
171 for (uint8_t i
= 0; i
< len
; i
++) {
172 sum
= ((sum
& 0xF) >> 1) | ((sum
& 0x1) << 3); // rotate accumulator
173 sum
+= NIBBLE_HIGH(bytes
[i
]); // add high nibble
175 sum
= ((sum
& 0xF) >> 1) | ((sum
& 0x1) << 3); // rotate accumulator
176 sum
+= NIBBLE_LOW(bytes
[i
]); // add low nibble
180 return (sum
& 0xFFFF);
183 // 0xFF - ( n1 ^ n... )
184 static uint16_t calcXORchecksum(uint8_t *bytes
, uint8_t len
, uint32_t mask
) {
185 return 0xFF - calcSumByteXor(bytes
, len
, mask
);
189 //2148050707DB0A0E000001C4000000
191 // measuring LFSR maximum length
192 static int CmdAnalyseLfsr(const char *Cmd
) {
193 CLIParserContext
*ctx
;
194 CLIParserInit(&ctx
, "analyse lfsr",
195 "looks at LEGIC Prime's lfsr, iterates the first 48 values",
196 "analyse lfsr --iv 55"
201 arg_str1(NULL
, "iv", "<hex>", "init vector data (1 hex byte)"),
202 arg_str0(NULL
, "find", "<hex>", "lfsr data to find (1 hex byte)"),
205 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
207 uint8_t idata
[1] = {0};
208 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), idata
, sizeof(idata
), &iv_len
);
212 PrintAndLogEx(FAILED
, "Error parsing IV byte");
217 uint8_t fdata
[1] = {0};
218 res
= CLIParamHexToBuf(arg_get_str(ctx
, 2), fdata
, sizeof(fdata
), &f_len
);
222 PrintAndLogEx(FAILED
, "Error parsing FIND byte");
226 uint8_t iv
= idata
[0];
227 uint8_t find
= fdata
[0];
229 PrintAndLogEx(INFO
, "LEGIC Prime lfsr");
230 PrintAndLogEx(INFO
, "iv..... 0x%02X", iv
);
231 PrintAndLogEx(INFO
, "----+------+-------+--------------");
232 PrintAndLogEx(INFO
, " i# | lfsr | ^0x40 | 0x%02X ^ lfsr", find
);
233 PrintAndLogEx(INFO
, "----+------+-------+--------------");
235 for (uint8_t i
= 0x01; i
< 0x30; i
+= 1) {
237 legic_prng_forward(i
);
238 uint32_t lfsr
= legic_prng_get_bits(12); /* Any nonzero start state will work. */
239 PrintAndLogEx(INFO
, " %02X | %03X | %03X | %03X", i
, lfsr
, 0x40 ^ lfsr
, find
^ lfsr
);
241 PrintAndLogEx(INFO
, "----+------+-------+--------------");
245 static int CmdAnalyseLCR(const char *Cmd
) {
246 CLIParserContext
*ctx
;
247 CLIParserInit(&ctx
, "analyse lcr",
248 "Specifying the bytes of a UID with a known LRC will find the last byte value\n"
249 "needed to generate that LRC with a rolling XOR. All bytes should be specified in HEX.",
250 "analyse lcr -d 04008064BA -> Target (BA) requires final LRC XOR byte value: 5A"
255 arg_str1("d", "data", "<hex>", "bytes to calc missing XOR in a LCR"),
258 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
260 uint8_t data
[100] = {0x00};
261 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), data
, sizeof(data
), &dlen
);
265 PrintAndLogEx(FAILED
, "Error parsing bytes");
269 uint8_t finalXor
= calculateLRC(data
, (uint8_t)dlen
);
270 PrintAndLogEx(SUCCESS
, "Target [%02X] requires final LRC XOR byte value: " _YELLOW_("0x%02X"), data
[dlen
- 1], finalXor
);
271 PrintAndLogEx(NORMAL
, "");
275 static int CmdAnalyseCRC(const char *Cmd
) {
276 CLIParserContext
*ctx
;
277 CLIParserInit(&ctx
, "analyse crc",
278 "A stub method to test different crc implementations inside the PM3 sourcecode.\n"
279 "Just because you figured out the poly, doesn't mean you get the desired output",
280 "analyse crc -d 137AF00A0A0D"
285 arg_str1("d", "data", "<hex>", "bytes to calc crc"),
288 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
290 uint8_t data
[1024] = {0x00};
291 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), data
, sizeof(data
), &dlen
);
295 PrintAndLogEx(FAILED
, "Error parsing bytes");
299 PrintAndLogEx(INFO
, "\nTests with (%d) | %s", dlen
, sprint_hex(data
, (size_t)dlen
));
302 uint8_t uid
[] = {0x51, 0xf5, 0x7a, 0xd6}; //12 34 56
303 init_table(CRC_LEGIC
);
304 uint8_t legic8
= CRC8Legic(uid
, sizeof(uid
)) & 0xFF;
305 PrintAndLogEx(INFO
, "Legic 16 | %X (EF6F expected) [legic8 = %02x]", crc16_legic(data
, (size_t)dlen
, legic8
), legic8
);
306 init_table(CRC_FELICA
);
307 PrintAndLogEx(INFO
, "FeliCa | %X ", crc16_xmodem(data
, (size_t)dlen
));
309 PrintAndLogEx(INFO
, "\nTests of reflection. Current methods in source code");
310 PrintAndLogEx(INFO
, " reflect(0x3e23L,3) is %04X == 0x3e26", reflect(0x3e23L
, 3));
311 PrintAndLogEx(INFO
, " reflect8(0x80) is %02X == 0x01", reflect8(0x80));
312 PrintAndLogEx(INFO
, " reflect16(0x8000) is %04X == 0x0001", reflect16(0xc6c6));
314 uint8_t b1
= 0, b2
= 0;
316 compute_crc(CRC_14443_B
, data
, (size_t)dlen
, &b1
, &b2
);
317 uint16_t crcBB_1
= (uint16_t)(b1
<< 8 | b2
);
318 uint16_t bbb
= Crc16ex(CRC_14443_B
, data
, (size_t)dlen
);
319 PrintAndLogEx(INFO
, "ISO14443 crc B | %04x == %04x \n", crcBB_1
, bbb
);
322 // Test of CRC16, '123456789' string.
325 PrintAndLogEx(INFO
, "\n\nStandard test with 31 32 33 34 35 36 37 38 39 '123456789'\n\n");
326 uint8_t dataStr
[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };
327 legic8
= CRC8Legic(dataStr
, sizeof(dataStr
)) & 0xFF;
329 //these below has been tested OK.
330 PrintAndLogEx(INFO
, "Confirmed CRC Implementations");
331 PrintAndLogEx(INFO
, "-------------------------------------\n");
332 PrintAndLogEx(INFO
, "CRC 8 based\n\n");
333 PrintAndLogEx(INFO
, "LEGIC: CRC8 : %X (C6 expected)", legic8
);
334 PrintAndLogEx(INFO
, "MAXIM: CRC8 : %X (A1 expected)", CRC8Maxim(dataStr
, sizeof(dataStr
)));
335 PrintAndLogEx(INFO
, "-------------------------------------\n");
336 PrintAndLogEx(INFO
, "CRC16 based\n\n");
338 // input from commandline
339 PrintAndLogEx(INFO
, "CCITT | %X (29B1 expected)", Crc16ex(CRC_CCITT
, dataStr
, sizeof(dataStr
)));
341 uint8_t poll
[] = {0xb2, 0x4d, 0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f};
342 PrintAndLogEx(INFO
, "FeliCa | %04X (B37F expected)", Crc16ex(CRC_FELICA
, poll
+ 2, sizeof(poll
) - 4));
343 PrintAndLogEx(INFO
, "FeliCa | %04X (0000 expected)", Crc16ex(CRC_FELICA
, poll
+ 2, sizeof(poll
) - 2));
345 uint8_t sel_corr
[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01};
346 PrintAndLogEx(INFO
, "iCLASS | %04x (0143 expected)", Crc16ex(CRC_ICLASS
, sel_corr
, sizeof(sel_corr
) - 2));
347 PrintAndLogEx(INFO
, "---------------------------------------------------------------\n\n\n");
350 compute_crc(CRC_14443_A
, dataStr
, sizeof(dataStr
), &b1
, &b2
);
351 uint16_t crcAA
= (uint16_t)(b1
<< 8 | b2
);
352 PrintAndLogEx(INFO
, "ISO14443 crc A | %04x or %04x (BF05 expected)\n", crcAA
, Crc16ex(CRC_14443_A
, dataStr
, sizeof(dataStr
)));
355 compute_crc(CRC_14443_B
, dataStr
, sizeof(dataStr
), &b1
, &b2
);
356 uint16_t crcBB
= (uint16_t)(b1
<< 8 | b2
);
357 PrintAndLogEx(INFO
, "ISO14443 crc B | %04x or %04x (906E expected)\n", crcBB
, Crc16ex(CRC_14443_B
, dataStr
, sizeof(dataStr
)));
359 // ISO15693 crc (x.25)
360 compute_crc(CRC_15693
, dataStr
, sizeof(dataStr
), &b1
, &b2
);
361 uint16_t crcCC
= (uint16_t)(b1
<< 8 | b2
);
362 PrintAndLogEx(INFO
, "ISO15693 crc X25| %04x or %04x (906E expected)\n", crcCC
, Crc16ex(CRC_15693
, dataStr
, sizeof(dataStr
)));
365 compute_crc(CRC_ICLASS
, dataStr
, sizeof(dataStr
), &b1
, &b2
);
366 uint16_t crcDD
= (uint16_t)(b1
<< 8 | b2
);
367 PrintAndLogEx(INFO
, "ICLASS crc | %04x or %04x\n", crcDD
, Crc16ex(CRC_ICLASS
, dataStr
, sizeof(dataStr
)));
370 compute_crc(CRC_FELICA
, dataStr
, sizeof(dataStr
), &b1
, &b2
);
371 uint16_t crcEE
= (uint16_t)(b1
<< 8 | b2
);
372 PrintAndLogEx(INFO
, "FeliCa | %04x or %04x (31C3 expected)\n", crcEE
, Crc16ex(CRC_FELICA
, dataStr
, sizeof(dataStr
)));
376 crc32_ex(dataStr
, sizeof(dataStr
), (uint8_t *)&crc32
);
377 PrintAndLogEx(INFO
, "CRC32 (desfire) | %08x ( expected)", crc32
);
378 PrintAndLogEx(INFO
, "---------------------------------------------------------------\n\n\n");
383 static int CmdAnalyseCHKSUM(const char *Cmd
) {
385 CLIParserContext
*ctx
;
386 CLIParserInit(&ctx
, "analyse chksum",
387 "The bytes will be added with eachother and than limited with the applied mask\n"
388 "Finally compute ones' complement of the least significant bytes.",
389 "analyse chksum -d 137AF00A0A0D -> expected output: 0x61\n"
390 "analyse chksum -d 137AF00A0A0D -m FF"
395 arg_str1("d", "data", "<hex>", "bytes to calc checksum"),
396 arg_str0("m", "mask", "<hex>", "bit mask to limit the output (4 hex bytes max)"),
397 arg_lit0("v", "verbose", "verbose output"),
400 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
402 uint8_t data
[100] = {0x00};
403 memset(data
, 0x0, sizeof(data
));
404 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), data
, sizeof(data
), &dlen
);
407 PrintAndLogEx(FAILED
, "Error parsing bytes");
410 const char *m
= arg_get_str(ctx
, 2)->sval
[0];
411 bool verbose
= arg_get_lit(ctx
, 3);
419 PrintAndLogEx(FAILED
, "Mask value is max 4 hex bytes");
427 for (size_t i
= 0; i
< mlen
; i
++) {
430 if (c
>= 'a' && c
<= 'f')
432 // convert to numeric value
433 if (c
>= '0' && c
<= '9')
435 else if (c
>= 'A' && c
<= 'F')
445 PrintAndLogEx(INFO
, "Mask value 0x%x", mask
);
448 PrintAndLogEx(INFO
, "------------------+-------------+------------------+-----------------+------------------+-----------+-------------");
449 PrintAndLogEx(INFO
, " add | sub | add 1's compl | sub 1's compl | xor | |");
450 PrintAndLogEx(INFO
, "byte nibble crumb | byte nibble | byte nibble cumb | byte nibble | byte nibble cumb | BSD | 0xFF - (n^n)");
451 PrintAndLogEx(INFO
, "------------------+-------------+------------------+-----------------+------------------+-----------+-------------");
453 PrintAndLogEx(INFO
, "0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X 0x%X 0x%X | 0x%X 0x%X | 0x%X\n",
454 calcSumByteAdd(data
, (uint8_t)dlen
, mask
)
455 , calcSumNibbleAdd(data
, (uint8_t)dlen
, mask
)
456 , calcSumCrumbAdd(data
, (uint8_t)dlen
, mask
)
457 , calcSumByteSub(data
, (uint8_t)dlen
, mask
)
458 , calcSumNibbleSub(data
, (uint8_t)dlen
, mask
)
459 , calcSumByteAddOnes(data
, (uint8_t)dlen
, mask
)
460 , calcSumNibbleAddOnes(data
, (uint8_t)dlen
, mask
)
461 , calcSumCrumbAddOnes(data
, (uint8_t)dlen
, mask
)
462 , calcSumByteSubOnes(data
, (uint8_t)dlen
, mask
)
463 , calcSumNibbleSubOnes(data
, (uint8_t)dlen
, mask
)
464 , calcSumByteXor(data
, (uint8_t)dlen
, mask
)
465 , calcSumNibbleXor(data
, (uint8_t)dlen
, mask
)
466 , calcSumCrumbXor(data
, (uint8_t)dlen
, mask
)
467 , calcBSDchecksum8(data
, (uint8_t)dlen
, mask
)
468 , calcBSDchecksum4(data
, (uint8_t)dlen
, mask
)
469 , calcXORchecksum(data
, (uint8_t)dlen
, mask
)
474 static int CmdAnalyseDates(const char *Cmd
) {
475 CLIParserContext
*ctx
;
476 CLIParserInit(&ctx
, "analyse dates",
477 "Tool to look for date/time stamps in a given array of bytes",
485 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
487 PrintAndLogEx(NORMAL
, "To be implemented. Feel free to contribute!");
491 static int CmdAnalyseA(const char *Cmd
) {
492 CLIParserContext
*ctx
;
493 CLIParserInit(&ctx
, "analyse a",
494 "Iceman's personal garbage test command",
495 "analyse a -d 137AF00A0A0D"
500 arg_str1("d", "data", "<hex>", "bytes to manipulate"),
503 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
505 uint8_t data
[100] = {0x00};
506 memset(data
, 0x0, sizeof(data
));
507 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), data
, sizeof(data
), &dlen
);
510 PrintAndLogEx(FAILED
, "Error parsing bytes");
515 res
= mfc_algo_touch_one(data
, 0, 0, &key
);
516 if (res
== PM3_SUCCESS
) {
517 PrintAndLogEx(SUCCESS
, "KEY A | %012" PRIx64
, key
);
524 //uint8_t syncBit = 99;
525 // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from
526 // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111)
527 // we therefore look for a ...xx1111 11111111 00x11111xxxxxx... pattern
528 // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's)
529 # define SYNC_16BIT 0xB24D
530 uint32_t shiftReg = param_get32ex(Cmd, 0, 0xb24d, 16);
531 uint8_t bt = param_get8ex(Cmd, 1, 0xBB, 16);
532 uint8_t byte_offset = 99;
534 uint8_t rev = reflect8(bt);
535 PrintAndLogEx(INFO, "input %02x | %02x \n", bt, rev);
536 // add byte to shift register
537 shiftReg = shiftReg << 8 | rev;
539 PrintAndLogEx(INFO, "shiftreg after %08x | pattern %08x \n", shiftReg, SYNC_16BIT);
541 uint8_t n0 = 0, n1 = 0;
543 n0 = (rev & (uint8_t)(~(0xFF >> (8 - 4)))) >> 4;
544 n1 = (n1 << 4) | (rev & (uint8_t)(~(0xFF << 4)));
546 PrintAndLogEx(INFO, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1));
549 for (int i = 0; i < 16; i++) {
550 PrintAndLogEx(INFO, " (shiftReg >> %d) & 0xFFFF == %08x ---", i, ((shiftReg >> i) & 0xFFFF));
552 // kolla om SYNC_PATTERN finns.
553 if (((shiftReg >> 7) & 0xFFFF) == SYNC_16BIT) byte_offset = 7;
554 else if (((shiftReg >> 6) & 0xFFFF) == SYNC_16BIT) byte_offset = 6;
555 else if (((shiftReg >> 5) & 0xFFFF) == SYNC_16BIT) byte_offset = 5;
556 else if (((shiftReg >> 4) & 0xFFFF) == SYNC_16BIT) byte_offset = 4;
557 else if (((shiftReg >> 3) & 0xFFFF) == SYNC_16BIT) byte_offset = 3;
558 else if (((shiftReg >> 2) & 0xFFFF) == SYNC_16BIT) byte_offset = 2;
559 else if (((shiftReg >> 1) & 0xFFFF) == SYNC_16BIT) byte_offset = 1;
560 else if (((shiftReg >> 0) & 0xFFFF) == SYNC_16BIT) byte_offset = 0;
562 PrintAndLogEx(INFO, "Offset %u \n", byte_offset);
563 if (byte_offset != 99)
569 uint8_t p1 = (rev & (uint8_t)(~(0xFF << byte_offset)));
570 PrintAndLogEx(INFO, "Offset %u | leftovers %02x %s \n", byte_offset, p1, pb(p1));
575 pm3 --> da hex2bin 4db2 0100110110110010
577 //return PM3_SUCCESS;
579 // split byte into two parts.
580 uint8_t offset = 3, n0 = 0, n1 = 0;
582 for (uint8_t m=0; m<8; m++) {
584 n0 = (rev & (uint8_t)(~(0xFF >> (8-offset)))) >> offset;
585 n1 = (n1 << offset) | (rev & (uint8_t)(~(0xFF << offset)));
587 PrintAndLogEx(INFO, "rev %02X | %02X %s | %02X %s |\n", rev, n0, pb(n0), n1, pb(n1) );
589 // PrintAndLogEx(INFO, " (0xFF >> offset) == %s |\n", pb( (0xFF >> offset)) );
590 //PrintAndLogEx(INFO, "~(0xFF >> (8-offset)) == %s |\n", pb( (uint8_t)(~(0xFF >> (8-offset))) ) );
591 //PrintAndLogEx(INFO, " rev & xxx == %s\n\n", pb( (rev & (uint8_t)(~(0xFF << offset))) ));
594 // from A -- x bits into B and the rest into C.
596 for ( uint8_t i=0; i<8; i++){
597 PrintAndLogEx(INFO, "%u | %02X %s | %02X %s |\n", i, a, pb(a), b, pb(b) );
598 b = a & (a & (0xFF >> (8-i)));
603 // return PM3_SUCCESS;
607 uint8_t u14_c[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe8 }; // atqs w crc
608 uint8_t u14_w[] = {0x09, 0x78, 0x00, 0x92, 0x02, 0x54, 0x13, 0x02, 0x04, 0x2d, 0xe7 }; // atqs w crc
609 PrintAndLogEx(FAILED, "14a check wrong crc | %s\n", (check_crc(CRC_14443_A, u14_w, sizeof(u14_w))) ? "YES" : "NO");
610 PrintAndLogEx(SUCCESS, "14a check correct crc | %s\n", (check_crc(CRC_14443_A, u14_c, sizeof(u14_c))) ? "YES" : "NO");
613 uint8_t u14b[] = {0x05, 0x00, 0x08, 0x39, 0x73};
614 PrintAndLogEx(INFO, "14b check crc | %s\n", (check_crc(CRC_14443_B, u14b, sizeof(u14b))) ? "YES" : "NO");
617 uint8_t u15_c[] = {0x05, 0x00, 0x08, 0x39, 0x73}; // correct
618 uint8_t u15_w[] = {0x05, 0x00, 0x08, 0x39, 0x72}; // wrong
619 PrintAndLogEx(FAILED, "15 check wrong crc | %s\n", (check_crc(CRC_15693, u15_w, sizeof(u15_w))) ? "YES" : "NO");
620 PrintAndLogEx(SUCCESS, "15 check correct crc | %s\n", (check_crc(CRC_15693, u15_c, sizeof(u15_c))) ? "YES" : "NO");
622 // iCLASS test - wrong crc , swapped bytes.
623 uint8_t iclass_w[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x01, 0x43};
624 uint8_t iclass_c[] = { 0x40, 0xe1, 0xe1, 0xff, 0xfe, 0x5f, 0x02, 0x3c, 0x43, 0x01};
625 PrintAndLogEx(FAILED, "iCLASS check wrong crc | %s\n", (check_crc(CRC_ICLASS, iclass_w, sizeof(iclass_w))) ? "YES" : "NO");
626 PrintAndLogEx(SUCCESS, "iCLASS check correct crc | %s\n", (check_crc(CRC_ICLASS, iclass_c, sizeof(iclass_c))) ? "YES" : "NO");
629 uint8_t felica_w[] = {0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7e};
630 uint8_t felica_c[] = {0x12, 0x01, 0x01, 0x2e, 0x3d, 0x17, 0x26, 0x47, 0x80, 0x95, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f};
631 PrintAndLogEx(FAILED, "FeliCa check wrong crc | %s\n", (check_crc(CRC_FELICA, felica_w, sizeof(felica_w))) ? "YES" : "NO");
632 PrintAndLogEx(SUCCESS, "FeliCa check correct crc | %s\n", (check_crc(CRC_FELICA, felica_c, sizeof(felica_c))) ? "YES" : "NO");
634 PrintAndLogEx(NORMAL, "\n");
640 // uid(2e086b1a) nt(230736f6) ks(0b0008000804000e) nr(000000000)
641 // uid(2e086b1a) nt(230736f6) ks(0e0b0e0b090c0d02) nr(000000001)
642 // uid(2e086b1a) nt(230736f6) ks(0e05060e01080b08) nr(000000002)
643 //uint64_t d1[] = {0x2e086b1a, 0x230736f6, 0x0000001, 0x0e0b0e0b090c0d02};
644 //uint64_t d2[] = {0x2e086b1a, 0x230736f6, 0x0000002, 0x0e05060e01080b08};
646 // uid(17758822) nt(c0c69e59) ks(080105020705040e) nr(00000001)
647 // uid(17758822) nt(c0c69e59) ks(01070a05050c0705) nr(00000002)
648 //uint64_t d1[] = {0x17758822, 0xc0c69e59, 0x0000001, 0x080105020705040e};
649 //uint64_t d2[] = {0x17758822, 0xc0c69e59, 0x0000002, 0x01070a05050c0705};
651 // uid(6e442129) nt(8f699195) ks(090d0b0305020f02) nr(00000001)
652 // uid(6e442129) nt(8f699195) ks(03030508030b0c0e) nr(00000002)
653 // uid(6e442129) nt(8f699195) ks(02010f030c0d050d) nr(00000003)
654 // uid(6e442129) nt(8f699195) ks(00040f0f0305030e) nr(00000004)
655 //uint64_t d1[] = {0x6e442129, 0x8f699195, 0x0000001, 0x090d0b0305020f02};
656 //uint64_t d2[] = {0x6e442129, 0x8f699195, 0x0000004, 0x00040f0f0305030e};
659 uid(3e172b29) nt(039b7bd2) ks(0c0e0f0505080800) nr(00000001)
660 uid(3e172b29) nt(039b7bd2) ks(0e06090d03000b0f) nr(00000002)
663 uint64_t *keylistA = NULL, *keylistB = NULL;
664 uint32_t keycountA = 0, keycountB = 0;
665 // uint64_t d1[] = {0x3e172b29, 0x039b7bd2, 0x0000001, 0, 0x0c0e0f0505080800};
666 // uint64_t d2[] = {0x3e172b29, 0x039b7bd2, 0x0000002, 0, 0x0e06090d03000b0f};
667 uint64_t d1[] = {0x6e442129, 0x8f699195, 0x0000001, 0, 0x090d0b0305020f02};
668 uint64_t d2[] = {0x6e442129, 0x8f699195, 0x0000004, 0, 0x00040f0f0305030e};
670 keycountA = nonce2key(d1[0], d1[1], d1[2], 0, d1[3], d1[4], &keylistA);
671 keycountB = nonce2key(d2[0], d2[1], d2[2], 0, d2[3], d2[4], &keylistB);
675 PrintAndLogEx(FAILED, "Key test A failed\n");
678 PrintAndLogEx(SUCCESS, "KEY A | %012" PRIX64 " ", keylistA[0]);
683 PrintAndLogEx(FAILED, "Key test B failed\n");
686 PrintAndLogEx(SUCCESS, "KEY B | %012" PRIX64 " ", keylistB[0]);
693 // qsort(keylist, keycount, sizeof(*keylist), compare_uint64);
694 // keycount = intersection(last_keylist, keylist);
698 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961,
699 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3,
700 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c,
701 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9,
702 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a,
703 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba,
704 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b,
705 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe
709 0x7b5b8144a32f, 0x76b46ccc461e, 0x03c3c36ea7a2, 0x171414d31961,
710 0xe2bfc7153eea, 0x48023d1d1985, 0xff7e1a410953, 0x49a3110249d3,
711 0xe3515546d015, 0x667c2ac86f85, 0x5774a8d5d6a9, 0xe401c2ca602c,
712 0x3be7e5020a7e, 0x66dbec3cf90b, 0x4e13f1534605, 0x5c172e1e78c9
715 0xeafe51411fbf, 0xc579f0fcdd8f, 0x2146a0d745c3, 0xab31ca60171a,
716 0x3169130a5035, 0xde5e11ea4923, 0x96fe2aeb9924, 0x828b61e6fcba,
717 0x8211b0607367, 0xe2936b320f76, 0xaff501e84378, 0x82b31cedb21b,
718 0xb725d31d4cd3, 0x3b984145b2f1, 0x3b4adb3e82ba, 0x8779075210fe
725 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B,
726 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6,
727 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52,
728 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC, 0xB6E97F5F6776,
729 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F,
730 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD,
731 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8,
732 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244
737 0x0DEFED88E531, 0x7577AFA2E1BC, 0x14D7D7BDBEC3, 0xF5ABD3C6278B,
738 0xAABDFA08276F, 0xB77C275C10D6, 0xB6DD0B434080, 0xAAF2444499C6,
739 0x852D7F8EBF90, 0x3108821DB92C, 0xB3756A1FB685, 0xDFE627C86A52,
740 0x5D3C093EF375, 0x28C81D6FBF0E, 0x1204DF4D3ECC
743 0x2F87A1BDC230, 0xE43F502B984C, 0x8A776AB752D9, 0x9A58D96A472F,
744 0xEF3702E01916, 0x48A03B01D007, 0x14754B0D659E, 0x009AD1868FDD,
745 0x6082DB527C11, 0x4D666ADA4C0E, 0x2D461D05F163, 0x3596CFF0FEC8,
746 0x8CBD9258FE22, 0x00D29A7B304B, 0xBC33DC6C9244
750 // xor key A | xor key B
751 1 | 0DEFED88E531 | 2F87A1BDC230
752 2 | 7577AFA2E1BC | E43F502B984C
753 3 | 14D7D7BDBEC3 | 8A776AB752D9
754 4 | F5ABD3C6278B | 9A58D96A472F
755 5 | AABDFA08276F | EF3702E01916
756 6 | B77C275C10D6 | 48A03B01D007
757 7 | B6DD0B434080 | 14754B0D659E
758 8 | AAF2444499C6 | 009AD1868FDD
759 9 | 852D7F8EBF90 | 6082DB527C11
760 10 | 3108821DB92C | 4D666ADA4C0E
761 11 | B3756A1FB685 | 2D461D05F163
762 12 | DFE627C86A52 | 3596CFF0FEC8
763 13 | 5D3C093EF375 | 8CBD9258FE22
764 14 | 28C81D6FBF0E | 00D29A7B304B
765 15 | 1204DF4D3ECC | BC33DC6C9244
768 // generate xor table :)
770 for (uint8_t i=0; i<31; i++){
771 uint64_t a = keys[i] ^ keys[i+1];
772 PrintAndLogEx(INFO, "%u | %012" PRIX64 " | \n", i, a);
777 uint32_t id = param_get32ex(Cmd, 0, 0x93290142, 16);
778 uint8_t uid[6] = {0};
779 num_to_bytes(id,4,uid);
781 uint8_t key_s0a[] = {
782 uid[1] ^ uid[2] ^ uid[3] ^ 0x11,
785 (uid[0] + uid[1] + uid[2] + uid[3] ) ^ uid[3] ^ 0x19,
790 PrintAndLogEx(INFO, "UID | %s\n", sprint_hex(uid,4 ));
791 PrintAndLogEx(INFO, "KEY A | %s\n", sprint_hex(key_s0a, 6));
794 uint64_t foo[32] = {0};
797 foo[0] = bytes_to_num(key_s0a, 6);
799 //foo[16] = 0xcafe71411fbf;
800 foo[16] = 0xeafe51411fbf;
802 for (uint8_t i=0; i<15; i++){
803 foo[i+1] = foo[i] ^ xorA[i];
804 foo[i+16+1] = foo[i+16] ^ xorB[i];
807 for (uint8_t i=0; i<15; i++){
809 uint64_t b = foo[i+16];
811 PrintAndLogEx(INFO, "%02u | %012" PRIX64 " %s | %012" PRIX64 " %s\n",
814 ( a == keya[i])?"ok":"err",
816 ( b == keyb[i])?"ok":"err"
820 // return PM3_SUCCESS;
823 static int CmdAnalyseNuid(const char *Cmd
) {
824 CLIParserContext
*ctx
;
825 CLIParserInit(&ctx
, "analyse nuid",
826 "Generate 4byte NUID from 7byte UID",
827 "analyse nuid -d 11223344556677"
832 arg_str0("d", "data", "<hex>", "bytes to send"),
833 arg_lit0("t", "test", "self test"),
836 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
839 uint8_t uid
[7] = {0};
840 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), uid
, sizeof(uid
), &uidlen
);
841 bool selftest
= arg_get_lit(ctx
, 2);
845 PrintAndLogEx(FAILED
, "Error parsing bytes");
849 uint8_t nuid
[4] = {0};
851 /* src: https://www.nxp.com/docs/en/application-note/AN10927.pdf */
852 /* selftest1 UID 040D681AB52281 -> NUID 8F430FEF */
853 /* selftest2 UID 04183F09321B85 -> NUID 4F505D7D */
855 uint8_t uid_test1
[] = {0x04, 0x0d, 0x68, 0x1a, 0xb5, 0x22, 0x81};
856 uint8_t nuid_test1
[] = {0x8f, 0x43, 0x0f, 0xef};
857 uint8_t uid_test2
[] = {0x04, 0x18, 0x3f, 0x09, 0x32, 0x1b, 0x85};
858 uint8_t nuid_test2
[] = {0x4f, 0x50, 0x5d, 0x7d};
859 memcpy(uid
, uid_test1
, sizeof(uid
));
860 mfc_generate4b_nuid(uid
, nuid
);
862 PrintAndLogEx(INFO
, "Self tests");
863 bool test1
= (0 == memcmp(nuid
, nuid_test1
, sizeof(nuid
)));
864 PrintAndLogEx((test1
) ? SUCCESS
: FAILED
, "1. %s -> %s ( %s )"
865 , sprint_hex_inrow(uid_test1
, sizeof(uid_test1
))
866 , sprint_hex(nuid
, sizeof(nuid
))
867 , test1
? _GREEN_("ok") : _RED_("fail")
870 memcpy(uid
, uid_test2
, sizeof(uid
));
871 mfc_generate4b_nuid(uid
, nuid
);
872 bool test2
= (0 == memcmp(nuid
, nuid_test2
, sizeof(nuid
)));
873 PrintAndLogEx((test2
) ? SUCCESS
: FAILED
, "2. %s -> %s ( %s )\n"
874 , sprint_hex_inrow(uid_test2
, sizeof(uid_test2
))
875 , sprint_hex(nuid
, sizeof(nuid
))
876 , test2
? _GREEN_("ok") : _RED_("fail")
883 PrintAndLogEx(FAILED
, "Error parsing bytes");
887 mfc_generate4b_nuid(uid
, nuid
);
889 PrintAndLogEx(INFO
, "UID | %s \n", sprint_hex(uid
, 7));
890 PrintAndLogEx(INFO
, "NUID | %s \n", sprint_hex(nuid
, 4));
894 static int CmdAnalyseDemodBuffer(const char *Cmd
) {
895 CLIParserContext
*ctx
;
896 CLIParserInit(&ctx
, "analyse demodbuff",
897 "loads a binary string into DemodBuffer",
898 "analyse demodbuff -d 0011101001001011"
903 arg_str1("d", "data", "<bin>", "binary string to load"),
906 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
907 const char *s
= arg_get_str(ctx
, 1)->sval
[0];
908 size_t len
= MIN(strlen(s
), MAX_DEMOD_BUF_LEN
);
910 // add 1 for null terminator.
911 uint8_t *data
= calloc(len
+ 1, sizeof(uint8_t));
917 for (size_t i
= 0; i
<= strlen(s
); i
++) {
920 g_DemodBuffer
[i
] = 1;
922 g_DemodBuffer
[i
] = 0;
924 PrintAndLogEx(NORMAL
, "%c" NOLF
, c
);
929 PrintAndLogEx(NORMAL
, "");
930 g_DemodBufferLen
= len
;
932 PrintAndLogEx(HINT
, "Use `" _YELLOW_("data print") "` to view DemodBuffer");
936 static int CmdAnalyseFreq(const char *Cmd
) {
937 CLIParserContext
*ctx
;
938 CLIParserInit(&ctx
, "analyse freq",
946 arg_int0("F", "freq", "<int>", "resonating frequency F in hertz (Hz)"),
947 arg_int0("L", "cap", "<int>", "capacitance C in micro farads (F)"),
948 arg_int0("C", "ind", "<int>", "inductance in micro henries (H)"),
951 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
953 int F
= arg_get_int_def(ctx
, 1, 0);
954 int L
= arg_get_int_def(ctx
, 2, 0);
955 int C
= arg_get_int_def(ctx
, 3, 0);
958 const double c
= 299792458;
959 double len_125
= c
/ 125000;
960 double len_134
= c
/ 134000;
961 double len_1356
= c
/ 13560000;
963 double rf_range_125
= len_125
/ (M_PI
* 2);
964 double rf_range_134
= len_134
/ (M_PI
* 2);
965 double rf_range_1356
= len_1356
/ (M_PI
* 2);
967 PrintAndLogEx(INFO
, "Wavelengths");
968 PrintAndLogEx(INFO
, " 125 kHz has %f m, rf range %f m", len_125
, rf_range_125
);
969 PrintAndLogEx(INFO
, " 134 kHz has %f m, rf range %f m", len_134
, rf_range_134
);
970 PrintAndLogEx(INFO
, " 13.56 mHz has %f m, rf range %f m", len_1356
, rf_range_1356
);
972 PrintAndLogEx(INFO
, "Antenna lengths");
973 PrintAndLogEx(INFO
, " 125 kHz 1/2 = %f m, 1/4 = %f m", (len_125
/ 2), (len_125
/ 4));
974 PrintAndLogEx(INFO
, " 134 kHz 1/2 = %f m, 1/4 = %f m", (len_134
/ 2), (len_134
/ 4));
975 PrintAndLogEx(INFO
, " 13.56 mHz 1/2 = %f m, 1/4 = %f m", (len_1356
/ 2), (len_1356
/ 4));
978 if (F
== 0 && C
== 0 && L
== 0)
982 PrintAndLogEx(INFO
, "");
983 PrintAndLogEx(INFO
, "Resonant frequency calculator");
985 // From https://goodcalculators.com/resonant-frequency-calculator/
986 // Calc Resonant Frequency [Hz]
989 double calc_freq
= 1 / (2 * M_PI
* sqrtf((L
* C
)));
990 PrintAndLogEx(INFO
, "Resonating Frequency %lf Hz", calc_freq
);
992 // Calc Inductance [H]
993 // L = 1 / (4π2 f2 C)
995 double calc_inductance
= 1 / (4 * (M_PI
* M_PI
) * (F
* F
) * C
);
996 PrintAndLogEx(INFO
, "Inductance %lf Henries", calc_inductance
);
1000 // C = 1 / (4π2 f2 L)
1002 double calc_capacitance
= 1 / (4 * (M_PI
* M_PI
) * (F
* F
) * L
);
1003 PrintAndLogEx(INFO
, "Capacitance %lf Farads", calc_capacitance
);
1008 static int CmdAnalyseFoo(const char *Cmd
) {
1010 CLIParserContext
*ctx
;
1011 CLIParserInit(&ctx
, "analyse foo",
1012 "experiments of cliparse",
1013 "analyse foo -r a0000000a0002021"
1016 void *argtable
[] = {
1018 arg_str1("r", "raw", "<hex>", "raw bytes"),
1021 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
1026 CLIGetHexWithReturn(ctx
, 1, data
, &datalen
);
1028 uint8_t data3
[512] = {0};
1029 int data3len
= sizeof(data3
) - 1; // CLIGetStrWithReturn does not guarantee string to be null-terminated;
1030 CLIGetStrWithReturn(ctx
, 1, data3
, &data3len
);
1034 PrintAndLogEx(INFO
, "-r");
1035 PrintAndLogEx(INFO
, "Got: %s", sprint_hex_inrow(data
, (size_t)datalen
));
1036 PrintAndLogEx(INFO
, "Got: %s", data3
);
1039 g_GraphTraceLen
= 15000;
1041 for (int i
= 0; i
< 4095; i
++) {
1045 if (i
& 0x2000) o
|= 0x80; // corr_i_accum[13]
1047 if (i
& 0x1C00) o
|= 0x40; // corr_i_accum[12] | corr_i_accum[11] | corr_i_accum[10]
1049 if (i
& 0x0E00) o
|= 0x20; // corr_i_accum[12] | corr_i_accum[11] | corr_i_accum[9],
1050 o
|= (i
& 0x1F0) >> 4; // corr_i_accum[8:4]
1052 g_GraphBuffer
[i
] = o
;
1055 for (int i
= 0; i
< 4095; i
++) {
1058 // Send 8 bits of in phase tag signal
1059 //if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111)
1060 if ((i
& 0x3800) == 0 || (i
& 0x3800) == 0x3800) {
1061 o
|= (i
& 0xFF0) >> 4; // corr_i_out <= corr_i_accum[11:4];
1063 // truncate to maximum value
1064 //if (corr_i_accum[13] == 1'b0)
1065 if ((i
& 0x2000) == 0) {
1066 o
|= 0x7f; // corr_i_out <= 8'b01111111;
1069 g_GraphBuffer
[i
+ 5000] = o
;
1072 for (int i
= 0; i
< 4095; i
++) {
1074 g_GraphBuffer
[i
+ 10000] = o
;
1077 RepaintGraphWindow();
1082 static int CmdAnalyseUnits(const char *Cmd
) {
1084 CLIParserContext
*ctx
;
1085 CLIParserInit(&ctx
, "analyse units",
1086 "experiments of unit conversions found in HF. ETU (1/13.56mhz), US or SSP_CLK (1/3.39MHz)",
1087 "analyse uints --etu 10\n"
1088 "analyse uints --us 100\n"
1091 void *argtable
[] = {
1093 arg_int0(NULL
, "etu", "<dec>", "number in ETU"),
1094 arg_int0(NULL
, "us", "<dec>", "number in micro seconds (us)"),
1095 arg_lit0("t", "selftest", "self tests"),
1098 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
1100 int etu
= arg_get_int_def(ctx
, 1, -1);
1101 int us
= arg_get_int_def(ctx
, 2, -1);
1102 bool selftest
= arg_get_lit(ctx
, 3);
1106 PrintAndLogEx(INFO
, "US to ETU conversions");
1108 int32_t test
= US_TO_ETU(9);
1109 PrintAndLogEx(INFO
, " 9 US = %i ETU (expect 1) %s", test
, (test
== 1) ? _GREEN_("ok") : _RED_("fail"));
1111 test
= US_TO_ETU(10);
1112 PrintAndLogEx(INFO
, " 10 US = %i ETU (expect 1) %s", test
, (test
== 1) ? _GREEN_("ok") : _RED_("fail"));
1114 test
= US_TO_ETU(94);
1115 PrintAndLogEx(INFO
, " 94 US = %i ETU (expect 10) %s", test
, (test
== 10) ? _GREEN_("ok") : _RED_("fail"));
1117 test
= US_TO_ETU(95);
1118 PrintAndLogEx(INFO
, " 95 US = %i ETU (expect 10) %s", test
, (test
== 10) ? _GREEN_("ok") : _RED_("fail"));
1120 test
= US_TO_ETU(302);
1121 PrintAndLogEx(INFO
, " 302 US = %i ETU (expect 32) %s", test
, (test
== 10) ? _GREEN_("ok") : _RED_("fail"));
1122 PrintAndLogEx(NORMAL
, "");
1124 PrintAndLogEx(INFO
, "ETU to Micro seconds (µS) conversions");
1125 double test_us
= HF14_ETU_TO_US(1);
1126 PrintAndLogEx(INFO
, " 1 ETU = %3.2f US (expect 9.44) %s", test_us
, (test_us
== 9.44) ? _GREEN_("ok") : _RED_("fail"));
1127 test_us
= HF14_ETU_TO_US(10);
1128 PrintAndLogEx(INFO
, " 10 ETU = %4.2f US (expect 94.40) %s", test_us
, (test_us
== 94.40) ? _GREEN_("ok") : _RED_("fail"));
1129 test_us
= HF14_ETU_TO_US(32);
1130 PrintAndLogEx(INFO
, " 32 ETU = %5.2f US (expect 302.06) %s", test_us
, (test_us
== 320.06) ? _GREEN_("ok") : _RED_("fail"));
1132 PrintAndLogEx(NORMAL
, "");
1134 PrintAndLogEx(INFO
, "Microseconds (µS) to SSP CLK 3.39MHz conversions");
1135 PrintAndLogEx(INFO
, " 9 µS = %i SSP (expect 32) ", US_TO_SSP(9));
1136 PrintAndLogEx(INFO
, " 10 µS = %i SSP (expect 32 or 48) ", US_TO_SSP(10));
1137 PrintAndLogEx(INFO
, " 94 µS = %i SSP (expect 320) ", US_TO_SSP(94));
1138 PrintAndLogEx(INFO
, " 95 µS = %i SSP (expect 320 or 336) ", US_TO_SSP(95));
1139 PrintAndLogEx(INFO
, " 302 µS = %i SSP (expect 1024) ", US_TO_SSP(302));
1141 PrintAndLogEx(INFO
, " 4949000 µS = %i SSP ", US_TO_SSP(4949000));
1143 PrintAndLogEx(NORMAL
, "");
1145 PrintAndLogEx(INFO
, "SSP CLK 3.39MHz to US conversions");
1146 PrintAndLogEx(INFO
, " 32 SSP = %i US (expect 9 or 10) " _GREEN_("ok"), SSP_TO_US(32));
1147 PrintAndLogEx(INFO
, " 320 SSP = %i US (expect 94 or 95) " _GREEN_("ok"), SSP_TO_US(320));
1148 PrintAndLogEx(INFO
, "1024 SSP = %i US (expect 302) " _GREEN_("ok"), SSP_TO_US(1024));
1149 PrintAndLogEx(NORMAL
, "");
1151 PrintAndLogEx(INFO
, "ETU to SSP CLK 3.39MHz conversions");
1152 PrintAndLogEx(INFO
, " 1 ETU = %i SSP (expect 32) " _GREEN_("ok"), HF14_ETU_TO_SSP(1));
1153 PrintAndLogEx(INFO
, " 10 ETU = %i SSP (expect 320) " _GREEN_("ok"), HF14_ETU_TO_SSP(10));
1154 PrintAndLogEx(INFO
, " 32 ETU = %i SSP (expect 1024) " _GREEN_("ok"), HF14_ETU_TO_SSP(32));
1155 PrintAndLogEx(NORMAL
, "");
1157 PrintAndLogEx(INFO
, "SSP CLK 3.39MHz to ETU conversions");
1158 PrintAndLogEx(INFO
, "1024 SSP = %i ETU (expect 32) " _GREEN_("ok"), HF14_SSP_TO_ETU(1024));
1159 PrintAndLogEx(INFO
, " 320 SSP = %i ETU (expect 10) " _GREEN_("ok"), HF14_SSP_TO_ETU(320));
1160 PrintAndLogEx(INFO
, " 32 SSP = %i ETU (expect 1) " _GREEN_("ok"), HF14_SSP_TO_ETU(32));
1161 } else if (etu
> -1) {
1163 PrintAndLogEx(INFO
, " %i ETU = %3.2f µS", etu
, HF14_ETU_TO_US(etu
));
1164 PrintAndLogEx(INFO
, " %i ETU = %i SSP", etu
, HF14_ETU_TO_SSP(etu
));
1165 } else if (us
> -1) {
1166 PrintAndLogEx(INFO
, " %i µS = %3.2f ETU = %u SSP", us
, US_TO_ETU(us
), US_TO_SSP(us
));
1172 static command_t CommandTable
[] = {
1173 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
1174 {"lcr", CmdAnalyseLCR
, AlwaysAvailable
, "Generate final byte for XOR LRC"},
1175 {"crc", CmdAnalyseCRC
, AlwaysAvailable
, "Stub method for CRC evaluations"},
1176 {"chksum", CmdAnalyseCHKSUM
, AlwaysAvailable
, "Checksum with adding, masking and one's complement"},
1177 {"dates", CmdAnalyseDates
, AlwaysAvailable
, "Look for datestamps in a given array of bytes"},
1178 {"lfsr", CmdAnalyseLfsr
, AlwaysAvailable
, "LFSR tests"},
1179 {"a", CmdAnalyseA
, AlwaysAvailable
, "num bits test"},
1180 {"nuid", CmdAnalyseNuid
, AlwaysAvailable
, "create NUID from 7byte UID"},
1181 {"demodbuff", CmdAnalyseDemodBuffer
, AlwaysAvailable
, "Load binary string to DemodBuffer"},
1182 {"freq", CmdAnalyseFreq
, AlwaysAvailable
, "Calc wave lengths"},
1183 {"foo", CmdAnalyseFoo
, AlwaysAvailable
, "muxer"},
1184 {"units", CmdAnalyseUnits
, AlwaysAvailable
, "convert ETU <> US <> SSP_CLK (3.39MHz)"},
1185 {NULL
, NULL
, NULL
, NULL
}
1188 static int CmdHelp(const char *Cmd
) {
1189 (void)Cmd
; // Cmd is not used so far
1190 CmdsHelp(CommandTable
);
1194 int CmdAnalyse(const char *Cmd
) {
1195 clearCommandBuffer();
1196 return CmdsParse(CommandTable
, Cmd
);