renamed 'hf mfdes readdata, writedata' to 'read/write'
[RRG-proxmark3.git] / client / src / cmdhw.c
blobeed42dff564c4a0c3051e10995863f3a428a0874
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // Hardware commands
9 // low-level hardware control
10 //-----------------------------------------------------------------------------
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <ctype.h>
17 #include "cmdparser.h" // command_t
18 #include "cliparser.h"
19 #include "comms.h"
20 #include "usart_defs.h"
21 #include "ui.h"
22 #include "cmdhw.h"
23 #include "cmddata.h"
24 #include "commonutil.h"
25 #include "pm3_cmd.h"
26 #include "pmflash.h" // rdv40validation_t
27 #include "cmdflashmem.h" // get_signature..
29 static int CmdHelp(const char *Cmd);
31 static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
32 char asBuff[120];
33 memset(asBuff, 0, sizeof(asBuff));
34 uint32_t mem_avail = 0;
35 PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("Hardware") " ]");
37 switch (iChipID) {
38 case 0x270B0A40:
39 sprintf(asBuff, "AT91SAM7S512 Rev A");
40 break;
41 case 0x270B0A4F:
42 sprintf(asBuff, "AT91SAM7S512 Rev B");
43 break;
44 case 0x270D0940:
45 sprintf(asBuff, "AT91SAM7S256 Rev A");
46 break;
47 case 0x270B0941:
48 sprintf(asBuff, "AT91SAM7S256 Rev B");
49 break;
50 case 0x270B0942:
51 sprintf(asBuff, "AT91SAM7S256 Rev C");
52 break;
53 case 0x270B0943:
54 sprintf(asBuff, "AT91SAM7S256 Rev D");
55 break;
56 case 0x270C0740:
57 sprintf(asBuff, "AT91SAM7S128 Rev A");
58 break;
59 case 0x270A0741:
60 sprintf(asBuff, "AT91SAM7S128 Rev B");
61 break;
62 case 0x270A0742:
63 sprintf(asBuff, "AT91SAM7S128 Rev C");
64 break;
65 case 0x270A0743:
66 sprintf(asBuff, "AT91SAM7S128 Rev D");
67 break;
68 case 0x27090540:
69 sprintf(asBuff, "AT91SAM7S64 Rev A");
70 break;
71 case 0x27090543:
72 sprintf(asBuff, "AT91SAM7S64 Rev B");
73 break;
74 case 0x27090544:
75 sprintf(asBuff, "AT91SAM7S64 Rev C");
76 break;
77 case 0x27080342:
78 sprintf(asBuff, "AT91SAM7S321 Rev A");
79 break;
80 case 0x27080340:
81 sprintf(asBuff, "AT91SAM7S32 Rev A");
82 break;
83 case 0x27080341:
84 sprintf(asBuff, "AT91SAM7S32 Rev B");
85 break;
86 case 0x27050241:
87 sprintf(asBuff, "AT9SAM7S161 Rev A");
88 break;
89 case 0x27050240:
90 sprintf(asBuff, "AT91SAM7S16 Rev A");
91 break;
93 PrintAndLogEx(NORMAL, " --= uC: " _YELLOW_("%s"), asBuff);
95 switch ((iChipID & 0xE0) >> 5) {
96 case 1:
97 sprintf(asBuff, "ARM946ES");
98 break;
99 case 2:
100 sprintf(asBuff, "ARM7TDMI");
101 break;
102 case 4:
103 sprintf(asBuff, "ARM920T");
104 break;
105 case 5:
106 sprintf(asBuff, "ARM926EJS");
107 break;
109 PrintAndLogEx(NORMAL, " --= Embedded Processor: %s", asBuff);
111 switch ((iChipID & 0xF0000) >> 16) {
112 case 1:
113 sprintf(asBuff, "1K bytes");
114 break;
115 case 2:
116 sprintf(asBuff, "2K bytes");
117 break;
118 case 3:
119 sprintf(asBuff, "6K bytes");
120 break;
121 case 4:
122 sprintf(asBuff, "112K bytes");
123 break;
124 case 5:
125 sprintf(asBuff, "4K bytes");
126 break;
127 case 6:
128 sprintf(asBuff, "80K bytes");
129 break;
130 case 7:
131 sprintf(asBuff, "160K bytes");
132 break;
133 case 8:
134 sprintf(asBuff, "8K bytes");
135 break;
136 case 9:
137 sprintf(asBuff, "16K bytes");
138 break;
139 case 10:
140 sprintf(asBuff, "32K bytes");
141 break;
142 case 11:
143 sprintf(asBuff, "64K bytes");
144 break;
145 case 12:
146 sprintf(asBuff, "128K bytes");
147 break;
148 case 13:
149 sprintf(asBuff, "256K bytes");
150 break;
151 case 14:
152 sprintf(asBuff, "96K bytes");
153 break;
154 case 15:
155 sprintf(asBuff, "512K bytes");
156 break;
158 PrintAndLogEx(NORMAL, " --= Internal SRAM size: %s", asBuff);
160 switch ((iChipID & 0xFF00000) >> 20) {
161 case 0x19:
162 sprintf(asBuff, "AT91SAM9xx Series");
163 break;
164 case 0x29:
165 sprintf(asBuff, "AT91SAM9XExx Series");
166 break;
167 case 0x34:
168 sprintf(asBuff, "AT91x34 Series");
169 break;
170 case 0x37:
171 sprintf(asBuff, "CAP7 Series");
172 break;
173 case 0x39:
174 sprintf(asBuff, "CAP9 Series");
175 break;
176 case 0x3B:
177 sprintf(asBuff, "CAP11 Series");
178 break;
179 case 0x40:
180 sprintf(asBuff, "AT91x40 Series");
181 break;
182 case 0x42:
183 sprintf(asBuff, "AT91x42 Series");
184 break;
185 case 0x55:
186 sprintf(asBuff, "AT91x55 Series");
187 break;
188 case 0x60:
189 sprintf(asBuff, "AT91SAM7Axx Series");
190 break;
191 case 0x61:
192 sprintf(asBuff, "AT91SAM7AQxx Series");
193 break;
194 case 0x63:
195 sprintf(asBuff, "AT91x63 Series");
196 break;
197 case 0x70:
198 sprintf(asBuff, "AT91SAM7Sxx Series");
199 break;
200 case 0x71:
201 sprintf(asBuff, "AT91SAM7XCxx Series");
202 break;
203 case 0x72:
204 sprintf(asBuff, "AT91SAM7SExx Series");
205 break;
206 case 0x73:
207 sprintf(asBuff, "AT91SAM7Lxx Series");
208 break;
209 case 0x75:
210 sprintf(asBuff, "AT91SAM7Xxx Series");
211 break;
212 case 0x92:
213 sprintf(asBuff, "AT91x92 Series");
214 break;
215 case 0xF0:
216 sprintf(asBuff, "AT75Cxx Series");
217 break;
219 PrintAndLogEx(NORMAL, " --= Architecture identifier: %s", asBuff);
221 switch ((iChipID & 0x70000000) >> 28) {
222 case 0:
223 sprintf(asBuff, "ROM");
224 break;
225 case 1:
226 sprintf(asBuff, "ROMless or on-chip Flash");
227 break;
228 case 2:
229 sprintf(asBuff, "Embedded flash memory");
230 break;
231 case 3:
232 sprintf(asBuff, "ROM and Embedded flash memory\nNVPSIZ is ROM size\nNVPSIZ2 is Flash size");
233 break;
234 case 4:
235 sprintf(asBuff, "SRAM emulating ROM");
236 break;
238 switch ((iChipID & 0xF00) >> 8) {
239 case 0:
240 mem_avail = 0;
241 break;
242 case 1:
243 mem_avail = 8;
244 break;
245 case 2:
246 mem_avail = 16;
247 break;
248 case 3:
249 mem_avail = 32;
250 break;
251 case 5:
252 mem_avail = 64;
253 break;
254 case 7:
255 mem_avail = 128;
256 break;
257 case 9:
258 mem_avail = 256;
259 break;
260 case 10:
261 mem_avail = 512;
262 break;
263 case 12:
264 mem_avail = 1024;
265 break;
266 case 14:
267 mem_avail = 2048;
268 break;
271 PrintAndLogEx(NORMAL, " --= %s " _YELLOW_("%uK") " bytes ( " _YELLOW_("%2.0f%%") " used )"
272 , asBuff
273 , mem_avail
274 , mem_avail == 0 ? 0.0f : (float)mem_used / (mem_avail * 1024) * 100
278 switch ((iChipID & 0xF000) >> 12) {
279 case 0:
280 sprintf(asBuff, "None");
281 break;
282 case 1:
283 sprintf(asBuff, "8K bytes");
284 break;
285 case 2:
286 sprintf(asBuff, "16K bytes");
287 break;
288 case 3:
289 sprintf(asBuff, "32K bytes");
290 break;
291 case 5:
292 sprintf(asBuff, "64K bytes");
293 break;
294 case 7:
295 sprintf(asBuff, "128K bytes");
296 break;
297 case 9:
298 sprintf(asBuff, "256K bytes");
299 break;
300 case 10:
301 sprintf(asBuff, "512K bytes");
302 break;
303 case 12:
304 sprintf(asBuff, "1024K bytes");
305 break;
306 case 14:
307 sprintf(asBuff, "2048K bytes");
308 break;
310 PrintAndLogEx(NORMAL, " --= Second nonvolatile program memory size: %s", asBuff);
314 static int CmdDbg(const char *Cmd) {
316 CLIParserContext *ctx;
317 CLIParserInit(&ctx, "hw dbg",
318 "Set device side debug level output.\n"
319 "Note: option -4, this option may cause malfunction itself",
320 "hw dbg -1\n"
323 void *argtable[] = {
324 arg_param_begin,
325 arg_lit0("0", NULL, "no debug messages"),
326 arg_lit0("1", NULL, "error messages"),
327 arg_lit0("2", NULL, "plus information messages"),
328 arg_lit0("3", NULL, "plus debug messages"),
329 arg_lit0("4", NULL, "print even debug messages in timing critical functions"),
330 arg_param_end
332 CLIExecWithReturn(ctx, Cmd, argtable, true);
333 bool lv0 = arg_get_lit(ctx, 1);
334 bool lv1 = arg_get_lit(ctx, 2);
335 bool lv2 = arg_get_lit(ctx, 3);
336 bool lv3 = arg_get_lit(ctx, 4);
337 bool lv4 = arg_get_lit(ctx, 5);
338 CLIParserFree(ctx);
340 if ((lv0 + lv1 + lv2 + lv3 + lv4) > 1) {
341 PrintAndLogEx(INFO, "Can only set one debug level");
342 return PM3_EINVARG;
345 uint8_t dbg = 0;
346 if (lv0)
347 dbg = 0;
348 else if (lv1)
349 dbg = 1;
350 else if (lv2)
351 dbg = 2;
352 else if (lv3)
353 dbg = 3;
354 else if (lv4)
355 dbg = 4;
357 SendCommandNG(CMD_SET_DBGMODE, &dbg, sizeof(dbg));
358 return PM3_SUCCESS;
361 static int CmdDetectReader(const char *Cmd) {
362 CLIParserContext *ctx;
363 CLIParserInit(&ctx, "hw detectreader",
364 "Start to detect presences of reader field",
365 "hw detectreader -L\n"
368 void *argtable[] = {
369 arg_param_begin,
370 arg_lit0("L", "LF", "detect low frequence 125/134 kHz"),
371 arg_lit0("H", "HF", "detect high frequence 13.56 MHZ"),
372 arg_param_end
374 CLIExecWithReturn(ctx, Cmd, argtable, true);
375 bool lf = arg_get_lit(ctx, 1);
376 bool hf = arg_get_lit(ctx, 2);
377 CLIParserFree(ctx);
379 if ((lf + hf) > 1) {
380 PrintAndLogEx(INFO, "Can only set one frequence");
381 return PM3_EINVARG;
384 uint8_t arg = 0;
385 if (lf)
386 arg = 1;
387 else if (hf)
388 arg = 2;
390 PrintAndLogEx(INFO, "press pm3 button to change modes and finally exit");
391 clearCommandBuffer();
392 SendCommandNG(CMD_LISTEN_READER_FIELD, (uint8_t *)&arg, sizeof(arg));
393 return PM3_SUCCESS;
396 // ## FPGA Control
397 static int CmdFPGAOff(const char *Cmd) {
398 CLIParserContext *ctx;
399 CLIParserInit(&ctx, "hw fpgaoff",
400 "Turn of fpga and antenna field",
401 "hw fpgaoff\n"
404 void *argtable[] = {
405 arg_param_begin,
406 arg_param_end
408 CLIExecWithReturn(ctx, Cmd, argtable, true);
409 CLIParserFree(ctx);
411 clearCommandBuffer();
412 SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
413 return PM3_SUCCESS;
416 static int CmdLCD(const char *Cmd) {
417 CLIParserContext *ctx;
418 CLIParserInit(&ctx, "hw lcd",
419 "Send command/data to LCD",
420 "hw lcd -r AA -c 03 -> sends 0xAA three times"
423 void *argtable[] = {
424 arg_param_begin,
425 arg_int1("r", "raw", "<hex>", "data "),
426 arg_int1("c", "cnt", "<dec>", "number of times to send"),
427 arg_param_end
429 CLIExecWithReturn(ctx, Cmd, argtable, true);
430 CLIParserFree(ctx);
432 int r_len = 0;
433 uint8_t raw[1] = {0};
434 CLIGetHexWithReturn(ctx, 1, raw, &r_len);
435 int j = arg_get_int(ctx, 2);
436 if (j < 1) {
437 PrintAndLogEx(WARNING, "Count must be larger than zero");
438 return PM3_EINVARG;
441 while (j--) {
442 clearCommandBuffer();
443 SendCommandMIX(CMD_LCD, raw[0], 0, 0, NULL, 0);
445 return PM3_SUCCESS;
448 static int CmdLCDReset(const char *Cmd) {
449 CLIParserContext *ctx;
450 CLIParserInit(&ctx, "hw lcdreset",
451 "Hardware reset LCD",
452 "hw lcdreset\n"
455 void *argtable[] = {
456 arg_param_begin,
457 arg_param_end
459 CLIExecWithReturn(ctx, Cmd, argtable, true);
460 CLIParserFree(ctx);
461 clearCommandBuffer();
462 SendCommandNG(CMD_LCD_RESET, NULL, 0);
463 return PM3_SUCCESS;
466 static int CmdReadmem(const char *Cmd) {
467 CLIParserContext *ctx;
468 CLIParserInit(&ctx, "hw readmem",
469 "Read memory at decimal address from ARM chip flash.",
470 "hw readmem -a 10000"
473 void *argtable[] = {
474 arg_param_begin,
475 arg_u64_1("a", "adr", "<dec>", "address to read"),
476 arg_param_end
478 CLIExecWithReturn(ctx, Cmd, argtable, true);
479 uint32_t address = arg_get_u32(ctx, 1);
480 CLIParserFree(ctx);
481 clearCommandBuffer();
482 SendCommandNG(CMD_READ_MEM, (uint8_t *)&address, sizeof(address));
483 return PM3_SUCCESS;
486 static int CmdReset(const char *Cmd) {
487 CLIParserContext *ctx;
488 CLIParserInit(&ctx, "hw reset",
489 "Reset the Proxmark3 device.",
490 "hw reset"
493 void *argtable[] = {
494 arg_param_begin,
495 arg_param_end
497 CLIExecWithReturn(ctx, Cmd, argtable, true);
498 CLIParserFree(ctx);
499 clearCommandBuffer();
500 SendCommandNG(CMD_HARDWARE_RESET, NULL, 0);
501 PrintAndLogEx(INFO, "Proxmark3 has been reset.");
502 return PM3_SUCCESS;
506 * Sets the divisor for LF frequency clock: lets the user choose any LF frequency below
507 * 600kHz.
509 static int CmdSetDivisor(const char *Cmd) {
511 CLIParserContext *ctx;
512 CLIParserInit(&ctx, "hw setlfdivisor",
513 "Drive LF antenna at 12 MHz / (divisor + 1).",
514 "hw setlfdivisor -d 88"
517 void *argtable[] = {
518 arg_param_begin,
519 arg_u64_1("d", "div", "<dec>", "19 - 255 divisor value (def 95)"),
520 arg_param_end
522 CLIExecWithReturn(ctx, Cmd, argtable, true);
523 uint8_t arg = arg_get_u32_def(ctx, 1, 95);
524 CLIParserFree(ctx);
526 if (arg < 19) {
527 PrintAndLogEx(ERR, "Divisor must be between" _YELLOW_("19") " and " _YELLOW_("255"));
528 return PM3_EINVARG;
530 // 12 000 000 (12MHz)
531 clearCommandBuffer();
532 SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg));
533 PrintAndLogEx(SUCCESS, "Divisor set, expected " _YELLOW_("%.1f")" kHz", ((double)12000 / (arg + 1)));
534 return PM3_SUCCESS;
537 static int CmdSetMux(const char *Cmd) {
539 CLIParserContext *ctx;
540 CLIParserInit(&ctx, "hw setmux",
541 "Set the ADC mux to a specific value",
542 "hw setmux --hiraw -> set HIGH RAW"
545 void *argtable[] = {
546 arg_param_begin,
547 arg_lit0(NULL, "lopkd", "low peak"),
548 arg_lit0(NULL, "loraw", "low raw"),
549 arg_lit0(NULL, "hipkd", "high peak"),
550 arg_lit0(NULL, "hiraw", "high raw"),
551 arg_param_end
553 CLIExecWithReturn(ctx, Cmd, argtable, true);
554 bool lopkd = arg_get_lit(ctx, 1);
555 bool loraw = arg_get_lit(ctx, 2);
556 bool hipkd = arg_get_lit(ctx, 3);
557 bool hiraw = arg_get_lit(ctx, 4);
558 CLIParserFree(ctx);
560 if ((lopkd + loraw + hipkd + hiraw) > 1) {
561 PrintAndLogEx(INFO, "Can only set one mux");
562 return PM3_EINVARG;
565 uint8_t arg = 0;
566 if (lopkd)
567 arg = 0;
568 else if (loraw)
569 arg = 1;
570 else if (hipkd)
571 arg = 2;
572 else if (hiraw)
573 arg = 3;
575 clearCommandBuffer();
576 SendCommandNG(CMD_SET_ADC_MUX, (uint8_t *)&arg, sizeof(arg));
577 return PM3_SUCCESS;
580 static int CmdStandalone(const char *Cmd) {
581 CLIParserContext *ctx;
582 CLIParserInit(&ctx, "hw standalone",
583 "Start standalone mode",
584 "hw standalone -> start \n"
585 "hw standalone -a 1 -> start and send arg 1"
588 void *argtable[] = {
589 arg_param_begin,
590 arg_u64_0("a", "arg", "<dec>", "argument byte"),
591 arg_param_end
593 CLIExecWithReturn(ctx, Cmd, argtable, true);
594 uint8_t arg = arg_get_u32(ctx, 1);
595 CLIParserFree(ctx);
596 clearCommandBuffer();
597 SendCommandNG(CMD_STANDALONE, (uint8_t *)&arg, sizeof(arg));
598 return PM3_SUCCESS;
601 static int CmdTune(const char *Cmd) {
602 CLIParserContext *ctx;
603 CLIParserInit(&ctx, "hw tune",
604 "Measure antenna tuning",
605 "hw tune"
608 void *argtable[] = {
609 arg_param_begin,
610 arg_param_end
612 CLIExecWithReturn(ctx, Cmd, argtable, true);
613 CLIParserFree(ctx);
614 return CmdTuneSamples(Cmd);
617 static int CmdVersion(const char *Cmd) {
618 CLIParserContext *ctx;
619 CLIParserInit(&ctx, "hw version",
620 "Show version information about the connected Proxmark3",
621 "hw version"
624 void *argtable[] = {
625 arg_param_begin,
626 arg_param_end
628 CLIExecWithReturn(ctx, Cmd, argtable, true);
629 CLIParserFree(ctx);
630 pm3_version(true, false);
631 return PM3_SUCCESS;
634 static int CmdStatus(const char *Cmd) {
635 CLIParserContext *ctx;
636 CLIParserInit(&ctx, "hw status",
637 "Show runtime status information about the connected Proxmark3",
638 "hw status"
641 void *argtable[] = {
642 arg_param_begin,
643 arg_param_end
645 CLIExecWithReturn(ctx, Cmd, argtable, true);
646 CLIParserFree(ctx);
647 clearCommandBuffer();
648 PacketResponseNG resp;
649 SendCommandNG(CMD_STATUS, NULL, 0);
650 if (WaitForResponseTimeout(CMD_STATUS, &resp, 2000) == false) {
651 PrintAndLogEx(WARNING, "Status command timeout. Communication speed test timed out");
652 return PM3_ETIMEOUT;
654 return PM3_SUCCESS;
657 int handle_tearoff(tearoff_params_t *params, bool verbose) {
659 if (params == NULL)
660 return PM3_EINVARG;
662 clearCommandBuffer();
663 SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)params, sizeof(tearoff_params_t));
664 PacketResponseNG resp;
665 if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) {
666 PrintAndLogEx(WARNING, "Tear-off command timeout.");
667 return PM3_ETIMEOUT;
670 if (resp.status == PM3_SUCCESS) {
671 if (params->delay_us > 0 && verbose)
672 PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params->delay_us);
674 if (params->on && verbose)
675 PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
677 if (params->off && verbose)
678 PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
679 } else if (verbose)
680 PrintAndLogEx(WARNING, "Tear-off command failed.");
681 return resp.status;
684 static int CmdTearoff(const char *Cmd) {
685 CLIParserContext *ctx;
686 CLIParserInit(&ctx, "hw tearoff",
687 "Configure a tear-off hook for the next write command supporting tear-off\n"
688 "After having been triggered by a write command, the tear-off hook is deactivated\n"
689 "Delay (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.",
690 "hw tearoff --delay 1200 --> define delay of 1200us\n"
691 "hw tearoff --on --> (re)activate a previously defined delay\n"
692 "hw tearoff --off --> deactivate a previously activated but not yet triggered hook\n");
694 void *argtable[] = {
695 arg_param_begin,
696 arg_int0(NULL, "delay", "<dec>", "Delay in us before triggering tear-off, must be between 1 and 43000"),
697 arg_lit0(NULL, "on", "Activate tear-off hook"),
698 arg_lit0(NULL, "off", "Deactivate tear-off hook"),
699 arg_lit0("s", "silent", "less verbose output"),
700 arg_param_end
703 CLIExecWithReturn(ctx, Cmd, argtable, false);
704 tearoff_params_t params;
705 int delay = arg_get_int_def(ctx, 1, -1);
706 params.on = arg_get_lit(ctx, 2);
707 params.off = arg_get_lit(ctx, 3);
708 bool silent = arg_get_lit(ctx, 4);
709 CLIParserFree(ctx);
711 if (delay != -1) {
712 if ((delay < 1) || (delay > 43000)) {
713 PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
714 return PM3_EINVARG;
716 } else {
717 delay = 0; // will be ignored by ARM
720 params.delay_us = delay;
721 if (params.on && params.off) {
722 PrintAndLogEx(WARNING, "You can't set both --on and --off!");
723 return PM3_EINVARG;
726 return handle_tearoff(&params, !silent);
729 static int CmdTia(const char *Cmd) {
730 CLIParserContext *ctx;
731 CLIParserInit(&ctx, "hw tia",
732 "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider",
733 "hw tia"
736 void *argtable[] = {
737 arg_param_begin,
738 arg_param_end
740 CLIExecWithReturn(ctx, Cmd, argtable, true);
741 CLIParserFree(ctx);
743 PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)...");
744 clearCommandBuffer();
745 SendCommandNG(CMD_TIA, NULL, 0);
746 PacketResponseNG resp;
747 if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false) {
748 PrintAndLogEx(WARNING, "TIA command timeout. You probably need to unplug the Proxmark3.");
749 return PM3_ETIMEOUT;
751 PrintAndLogEx(INFO, "TIA done.");
752 return PM3_SUCCESS;
755 static int CmdPing(const char *Cmd) {
756 CLIParserContext *ctx;
757 CLIParserInit(&ctx, "hw ping",
758 "Test if the Proxmark3 is responsive",
759 "hw ping\n"
760 "hw ping --len 32"
763 void *argtable[] = {
764 arg_param_begin,
765 arg_u64_0("l", "len", "<dec>", "length of payload to send"),
766 arg_param_end
768 CLIExecWithReturn(ctx, Cmd, argtable, true);
769 uint32_t len = arg_get_u32(ctx, 1);
770 CLIParserFree(ctx);
772 if (len > PM3_CMD_DATA_SIZE)
773 len = PM3_CMD_DATA_SIZE;
775 if (len) {
776 PrintAndLogEx(INFO, "Ping sent with payload len " _YELLOW_("%d"), len);
777 } else {
778 PrintAndLogEx(INFO, "Ping sent");
781 clearCommandBuffer();
782 PacketResponseNG resp;
783 uint8_t data[PM3_CMD_DATA_SIZE] = {0};
785 for (uint16_t i = 0; i < len; i++)
786 data[i] = i & 0xFF;
788 SendCommandNG(CMD_PING, data, len);
789 if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) {
790 if (len) {
791 bool error = (memcmp(data, resp.data.asBytes, len) != 0);
792 PrintAndLogEx((error) ? ERR : SUCCESS, "Ping response " _GREEN_("received") " and content is %s", error ? _RED_("NOT ok") : _GREEN_("OK"));
793 } else {
794 PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received"));
796 } else
797 PrintAndLogEx(WARNING, "Ping response " _RED_("timeout"));
798 return PM3_SUCCESS;
801 static int CmdConnect(const char *Cmd) {
803 CLIParserContext *ctx;
804 CLIParserInit(&ctx, "hw connect",
805 "Connects to a Proxmark3 device via specified serial port.\n"
806 "Baudrate here is only for physical UART or UART-BT, NOT for USB-CDC or blue shark add-on",
807 "hw connect -p "SERIAL_PORT_EXAMPLE_H"\n"
808 "hw connect -p "SERIAL_PORT_EXAMPLE_H" -b 115200"
811 void *argtable[] = {
812 arg_param_begin,
813 arg_str0("p", "port", NULL, "Serial port to connect to, else retry the last used one"),
814 arg_u64_0("b", "baud", "<dec>", "Baudrate"),
815 arg_param_end
817 CLIExecWithReturn(ctx, Cmd, argtable, true);
819 int p_len = FILE_PATH_SIZE;
820 char port[FILE_PATH_SIZE] = {0};
821 CLIGetStrWithReturn(ctx, 1, (uint8_t *)port, &p_len);
822 uint32_t baudrate = arg_get_u32_def(ctx, 2, USART_BAUD_RATE);
823 CLIParserFree(ctx);
825 if (baudrate == 0) {
826 PrintAndLogEx(WARNING, "Baudrate can't be zero");
827 return PM3_EINVARG;
830 // default back to previous used serial port
831 if (strlen(port) == 0) {
832 if (strlen(conn.serial_port_name) == 0) {
833 PrintAndLogEx(WARNING, "Must specify a serial port");
834 return PM3_EINVARG;
836 memcpy(port, conn.serial_port_name, sizeof(port));
839 if (session.pm3_present) {
840 CloseProxmark(session.current_device);
843 // 10 second timeout
844 OpenProxmark(&session.current_device, port, false, 10, false, baudrate);
846 if (session.pm3_present && (TestProxmark(session.current_device) != PM3_SUCCESS)) {
847 PrintAndLogEx(ERR, _RED_("ERROR:") " cannot communicate with the Proxmark3\n");
848 CloseProxmark(session.current_device);
849 return PM3_ENOTTY;
851 return PM3_SUCCESS;
854 static int CmdBreak(const char *Cmd) {
856 CLIParserContext *ctx;
857 CLIParserInit(&ctx, "hw break",
858 "send break loop package",
859 "hw break\n"
862 void *argtable[] = {
863 arg_param_begin,
864 arg_param_end
866 CLIExecWithReturn(ctx, Cmd, argtable, true);
867 CLIParserFree(ctx);
868 clearCommandBuffer();
869 SendCommandNG(CMD_BREAK_LOOP, NULL, 0);
870 return PM3_SUCCESS;
874 static command_t CommandTable[] = {
875 {"-------------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Hardware") " -----------------------"},
876 {"help", CmdHelp, AlwaysAvailable, "This help"},
877 {"break", CmdBreak, IfPm3Present, "Send break loop usb command"},
878 {"connect", CmdConnect, AlwaysAvailable, "Connect Proxmark3 to serial port"},
879 {"dbg", CmdDbg, IfPm3Present, "Set Proxmark3 debug level"},
880 {"detectreader", CmdDetectReader, IfPm3Present, "Detect external reader field"},
881 {"fpgaoff", CmdFPGAOff, IfPm3Present, "Set FPGA off"},
882 {"lcd", CmdLCD, IfPm3Lcd, "Send command/data to LCD"},
883 {"lcdreset", CmdLCDReset, IfPm3Lcd, "Hardware reset LCD"},
884 {"ping", CmdPing, IfPm3Present, "Test if the Proxmark3 is responsive"},
885 {"readmem", CmdReadmem, IfPm3Present, "Read memory at decimal address from flash"},
886 {"reset", CmdReset, IfPm3Present, "Reset the Proxmark3"},
887 {"setlfdivisor", CmdSetDivisor, IfPm3Present, "Drive LF antenna at 12MHz / (divisor + 1)"},
888 {"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"},
889 {"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"},
890 {"status", CmdStatus, IfPm3Present, "Show runtime status information about the connected Proxmark3"},
891 {"tearoff", CmdTearoff, IfPm3Present, "Program a tearoff hook for the next command supporting tearoff"},
892 {"tia", CmdTia, IfPm3Present, "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider"},
893 {"tune", CmdTune, IfPm3Present, "Measure antenna tuning"},
894 {"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"},
895 {NULL, NULL, NULL, NULL}
898 static int CmdHelp(const char *Cmd) {
899 (void)Cmd; // Cmd is not used so far
900 CmdsHelp(CommandTable);
901 return PM3_SUCCESS;
904 int CmdHW(const char *Cmd) {
905 clearCommandBuffer();
906 return CmdsParse(CommandTable, Cmd);
909 void pm3_version(bool verbose, bool oneliner) {
911 #if defined(__MINGW64__)
912 # define PM3CLIENTCOMPILER "MinGW-w64 "
913 #elif defined(__MINGW32__)
914 # define PM3CLIENTCOMPILER "MinGW "
915 #elif defined(__clang__)
916 # define PM3CLIENTCOMPILER "Clang/LLVM "
917 #elif defined(__GNUC__) || defined(__GNUG__)
918 # define PM3CLIENTCOMPILER "GCC "
919 #else
920 # define PM3CLIENTCOMPILER "unknown compiler "
921 #endif
923 #if defined(__APPLE__) || defined(__MACH__)
924 # define PM3HOSTOS " OS:OSX"
925 #elif defined(__ANDROID__) || defined(ANDROID)
926 // must be tested before __linux__
927 # define PM3HOSTOS " OS:Android"
928 #elif defined(__linux__)
929 # define PM3HOSTOS " OS:Linux"
930 #elif defined(__FreeBSD__)
931 # define PM3HOSTOS " OS:FreeBSD"
932 #elif defined(__NetBSD__)
933 # define PM3HOSTOS " OS:NetBSD"
934 #elif defined(__OpenBSD__)
935 # define PM3HOSTOS " OS:OpenBSD"
936 #elif defined(__CYGWIN__)
937 # define PM3HOSTOS " OS:Cygwin"
938 #elif defined(_WIN64) || defined(__WIN64__)
939 // must be tested before _WIN32
940 # define PM3HOSTOS " OS:Windows (64b)"
941 #elif defined(_WIN32) || defined(__WIN32__)
942 # define PM3HOSTOS " OS:Windows (32b)"
943 #else
944 # define PM3HOSTOS " OS:unknown"
945 #endif
947 #if defined(__x86_64__)
948 # define PM3HOSTARCH " ARCH:x86_64"
949 #elif defined(__i386__)
950 # define PM3HOSTARCH " ARCH:x86"
951 #elif defined(__aarch64__)
952 # define PM3HOSTARCH " ARCH:aarch64"
953 #elif defined(__arm__)
954 # define PM3HOSTARCH " ARCH:arm"
955 #elif defined(__powerpc64__)
956 # define PM3HOSTARCH " ARCH:powerpc64"
957 #elif defined(__mips__)
958 # define PM3HOSTARCH " ARCH:mips"
959 #else
960 # define PM3HOSTARCH " ARCH:unknown"
961 #endif
963 if (oneliner) {
964 // For "proxmark3 -v", simple printf, avoid logging
965 char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image
966 FormatVersionInformation(temp, sizeof(temp), "Client: ", &version_information);
967 PrintAndLogEx(NORMAL, "%s compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH "\n", temp);
968 return;
971 if (!verbose)
972 return;
974 PacketResponseNG resp;
975 clearCommandBuffer();
976 SendCommandNG(CMD_VERSION, NULL, 0);
978 if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) {
979 char temp[PM3_CMD_DATA_SIZE - 12]; // same limit as for ARM image
980 PrintAndLogEx(NORMAL, "\n [ " _CYAN_("Proxmark3 RFID instrument") " ]");
981 PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("CLIENT") " ]");
982 FormatVersionInformation(temp, sizeof(temp), " client: ", &version_information);
983 PrintAndLogEx(NORMAL, "%s", temp);
984 PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
986 PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
987 if (IfPm3Rdv4Fw()) {
989 bool is_genuine_rdv4 = false;
990 // validate signature data
991 rdv40_validation_t mem;
992 if (rdv4_get_signature(&mem) == PM3_SUCCESS) {
993 if (rdv4_validate(&mem) == PM3_SUCCESS) {
994 is_genuine_rdv4 = true;
998 PrintAndLogEx(NORMAL, " device.................... %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _RED_("device / fw mismatch"));
999 PrintAndLogEx(NORMAL, " firmware.................. %s", (is_genuine_rdv4) ? _GREEN_("RDV4") : _YELLOW_("RDV4"));
1000 PrintAndLogEx(NORMAL, " external flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
1001 PrintAndLogEx(NORMAL, " smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
1002 PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
1003 } else {
1004 PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3 GENERIC"));
1005 if (IfPm3FpcUsartHost()) {
1006 PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", _GREEN_("present"));
1010 if (IfPm3FpcUsartDevFromUsb()) {
1011 PrintAndLogEx(NORMAL, " FPC USART for developer... %s", _GREEN_("present"));
1014 PrintAndLogEx(NORMAL, "");
1016 struct p {
1017 uint32_t id;
1018 uint32_t section_size;
1019 uint32_t versionstr_len;
1020 char versionstr[PM3_CMD_DATA_SIZE - 12];
1021 } PACKED;
1023 struct p *payload = (struct p *)&resp.data.asBytes;
1025 PrintAndLogEx(NORMAL, payload->versionstr);
1026 if (strstr(payload->versionstr, "2s30vq100") == NULL) {
1027 PrintAndLogEx(NORMAL, " FPGA firmware... %s", _RED_("chip mismatch"));
1030 lookupChipID(payload->id, payload->section_size);
1032 PrintAndLogEx(NORMAL, "");