1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2016 iceman
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
7 //-----------------------------------------------------------------------------
8 // Analyse bytes commands
9 //-----------------------------------------------------------------------------
12 #include <stdlib.h> // size_t
16 #include "cmdparser.h" // command_t
17 #include "cliparser.h" //
18 #include "commonutil.h" // ARRAYLEN
20 #include "util_posix.h"
21 #include "usart_defs.h"
22 #include "ui.h" // PrintAndLog
24 static int CmdHelp(const char *Cmd
);
26 static int usart_tx(uint8_t *data
, size_t len
) {
28 SendCommandNG(CMD_USART_TX
, data
, len
);
29 PacketResponseNG resp
;
30 if (!WaitForResponseTimeout(CMD_USART_TX
, &resp
, 1000)) {
36 static int usart_rx(uint8_t *data
, size_t *len
, uint32_t waittime
) {
41 payload
.waittime
= waittime
;
42 SendCommandNG(CMD_USART_RX
, (uint8_t *)&payload
, sizeof(payload
));
43 PacketResponseNG resp
;
44 if (!WaitForResponseTimeout(CMD_USART_RX
, &resp
, waittime
+ 500)) {
47 if (resp
.status
== PM3_SUCCESS
) {
49 memcpy(data
, resp
.data
.asBytes
, resp
.length
);
54 static int usart_txrx(uint8_t *srcdata
, size_t srclen
, uint8_t *dstdata
, size_t *dstlen
, uint32_t waittime
) {
56 struct payload_header
{
60 struct payload_header header
;
61 uint8_t data
[PM3_CMD_DATA_SIZE
- sizeof(uint32_t)];
63 payload
.header
.waittime
= waittime
;
64 if (srclen
>= sizeof(payload
.data
))
66 memcpy(payload
.data
, srcdata
, srclen
);
67 SendCommandNG(CMD_USART_TXRX
, (uint8_t *)&payload
, srclen
+ sizeof(payload
.header
));
68 PacketResponseNG resp
;
69 if (!WaitForResponseTimeout(CMD_USART_TXRX
, &resp
, waittime
+ 500)) {
72 if (resp
.status
== PM3_SUCCESS
) {
73 *dstlen
= resp
.length
;
74 memcpy(dstdata
, resp
.data
.asBytes
, resp
.length
);
79 static int set_usart_config(uint32_t baudrate
, uint8_t parity
) {
85 payload
.baudrate
= baudrate
;
86 payload
.parity
= parity
;
87 SendCommandNG(CMD_USART_CONFIG
, (uint8_t *)&payload
, sizeof(payload
));
88 PacketResponseNG resp
;
89 if (!WaitForResponseTimeout(CMD_USART_CONFIG
, &resp
, 1000)) {
95 static int CmdUsartConfig(const char *Cmd
) {
97 CLIParserContext
*ctx
;
98 CLIParserInit(&ctx
, "usart config",
100 "WARNING: it will have side-effects if used in USART HOST mode!\n"
101 "The changes are not permanent, restart Proxmark3 to get default settings back.",
102 "usart config -b 9600\n"
103 "usart config -b 9600 --none\n"
109 arg_u64_0("b", "baud", "<dec>", "baudrate"),
110 arg_lit0("N", "none", "mone parity"),
111 arg_lit0("E", "even", "even parity"),
112 arg_lit0("O", "odd", "odd parity"),
115 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
116 uint32_t baudrate
= arg_get_u32_def(ctx
, 1, 0);
117 bool pn
= arg_get_lit(ctx
, 2);
118 bool pe
= arg_get_lit(ctx
, 3);
119 bool po
= arg_get_lit(ctx
, 4);
122 if ((pn
+ pe
+ po
) > 1) {
123 PrintAndLogEx(WARNING
, "Only one parity can be used at a time");
135 return set_usart_config(baudrate
, parity
);
138 static int usart_bt_testcomm(uint32_t baudrate
, uint8_t parity
) {
139 int ret
= set_usart_config(baudrate
, parity
);
140 if (ret
!= PM3_SUCCESS
)
143 const char *string
= "AT+VERSION";
144 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
147 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s at %u 8%c1", strlen(string
), (int)strlen(string
), string
, baudrate
, parity
);
149 ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000); // such large timeout needed
150 if (ret
== PM3_SUCCESS
) {
151 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
152 if (strcmp((char *)data
, "hc01.comV2.0") == 0) {
153 PrintAndLogEx(SUCCESS
, "Add-on " _GREEN_("found!"));
160 static int CmdUsartBtFactory(const char *Cmd
) {
161 CLIParserContext
*ctx
;
162 CLIParserInit(&ctx
, "usart btfactory",
163 "Reset BT add-on to factory settings\n"
165 " 1) BTpower to be turned ON\n"
166 " 2) BT add-on to NOT be connected\n"
167 " => the add-on blue LED must blink\n\n"
168 _RED_("WARNING:") _CYAN_(" process only if strictly needed!"),
176 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
179 // take care to define compatible settings:
180 # define BTADDON_BAUD_AT "AT+BAUD8"
181 # define BTADDON_BAUD_NUM "115200"
183 uint32_t baudrate
= 0;
186 if (USART_BAUD_RATE
!= atoi(BTADDON_BAUD_NUM
)) {
187 PrintAndLogEx(WARNING
, _RED_("WARNING:") " current Proxmark3 firmware has default USART baudrate = %i", USART_BAUD_RATE
);
188 PrintAndLogEx(WARNING
, "Current btfactory implementation is hardcoded to " BTADDON_BAUD_NUM
" bauds");
192 PrintAndLogEx(WARNING
, _RED_("WARNING: process only if strictly needed!"));
193 PrintAndLogEx(WARNING
, "This requires BT turned ON and NOT connected!");
194 PrintAndLogEx(WARNING
, "Is the add-on blue light blinking? (Say 'n' if you want to abort) [y/n]");
197 if ((fgets(input
, sizeof(input
), stdin
) == NULL
) || (strncmp(input
, "y\n", sizeof(input
)) != 0)) {
198 PrintAndLogEx(NORMAL
, "");
199 PrintAndLogEx(FAILED
, "Aborting.");
200 return PM3_EOPABORTED
;
203 PrintAndLogEx(NORMAL
, "");
204 PrintAndLogEx(INFO
, "Trying to detect current settings... Please be patient.");
206 bool found
= usart_bt_testcomm(USART_BAUD_RATE
, USART_PARITY
) == PM3_SUCCESS
;
208 baudrate
= USART_BAUD_RATE
;
209 parity
= USART_PARITY
;
211 uint32_t brs
[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1382400};
212 uint8_t ps
[] = { 'N', 'O', 'E' };
213 for (uint8_t ip
= 0; (ip
< ARRAYLEN(ps
)) && (!found
); ip
++) {
214 for (uint8_t ibr
= 0; (ibr
< ARRAYLEN(brs
)) && (!found
); ibr
++) {
215 found
= usart_bt_testcomm(brs
[ibr
], ps
[ip
]) == PM3_SUCCESS
;
225 PrintAndLogEx(FAILED
, "Sorry, add-on not found. Abort.");
229 PrintAndLogEx(INFO
, "Reconfiguring add-on to default settings.");
231 uint8_t data
[PM3_CMD_DATA_SIZE
];
233 memset(data
, 0, sizeof(data
));
235 string
= "AT+NAMEPM3_RDV4.0";
236 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(string
), (int)strlen(string
), string
);
238 int ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000);
239 if (ret
== PM3_SUCCESS
) {
240 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
241 if (strcmp((char *)data
, "OKsetname") == 0) {
242 PrintAndLogEx(SUCCESS
, "Name set to " _GREEN_("PM3_RDV4.0"));
244 PrintAndLogEx(WARNING
, "Unexpected response to AT+NAME: " _YELLOW_("%.*s"), (int)len
, data
);
247 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
251 memset(data
, 0, sizeof(data
));
253 string
= "AT+ROLE=S";
254 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(string
), (int)strlen(string
), string
);
256 ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000);
257 if (ret
== PM3_SUCCESS
) {
258 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
259 if (strcmp((char *)data
, "OK+ROLE:S") == 0) {
260 PrintAndLogEx(SUCCESS
, "Role set to " _GREEN_("Slave"));
262 PrintAndLogEx(WARNING
, "Unexpected response to AT+ROLE=S: " _YELLOW_("%.*s"), (int)len
, data
);
265 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
269 memset(data
, 0, sizeof(data
));
271 string
= "AT+PIN1234";
272 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(string
), (int)strlen(string
), string
);
274 ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000);
275 if (ret
== PM3_SUCCESS
) {
276 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
277 if (strcmp((char *)data
, "OKsetPIN") == 0) {
278 PrintAndLogEx(SUCCESS
, "PIN set to " _GREEN_("1234"));
280 PrintAndLogEx(WARNING
, "Unexpected response to AT+PIN: " _YELLOW_("%.*s"), (int)len
, data
);
283 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
287 // parity must be changed before baudrate
288 if (parity
!= USART_PARITY
) {
289 memset(data
, 0, sizeof(data
));
292 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(string
), (int)strlen(string
), string
);
294 ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000);
295 if (ret
== PM3_SUCCESS
) {
296 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
297 if (strcmp((char *)data
, "OK None") == 0) {
298 PrintAndLogEx(SUCCESS
, "Parity set to " _GREEN_("None"));
300 PrintAndLogEx(WARNING
, "Unexpected response to AT+P: " _YELLOW_("%.*s"), (int)len
, data
);
303 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
308 if (baudrate
!= USART_BAUD_RATE
) {
309 memset(data
, 0, sizeof(data
));
311 string
= BTADDON_BAUD_AT
;
312 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(string
), (int)strlen(string
), string
);
314 ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 1000);
315 if (ret
== PM3_SUCCESS
) {
316 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
317 if (strcmp((char *)data
, "OK" BTADDON_BAUD_NUM
) == 0) {
318 PrintAndLogEx(SUCCESS
, "Baudrate set to " _GREEN_(BTADDON_BAUD_NUM
));
320 PrintAndLogEx(WARNING
, "Unexpected response to AT+BAUD: " _YELLOW_("%.*s"), (int)len
, data
);
323 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
328 if ((baudrate
!= USART_BAUD_RATE
) || (parity
!= USART_PARITY
)) {
329 PrintAndLogEx(WARNING
, "Add-on uart settings changed, please turn BT add-on OFF and ON again, then press Enter.");
330 while (!kbd_enter_pressed()) {
333 PrintAndLogEx(NORMAL
, "");
334 PrintAndLogEx(INFO
, "Trying to connect add-on with the new settings.");
335 found
= usart_bt_testcomm(USART_BAUD_RATE
, USART_PARITY
) == PM3_SUCCESS
;
337 PrintAndLogEx(WARNING
, "Lost contact with add-on, please try again");
342 PrintAndLogEx(SUCCESS
, "Add-on successfully " _GREEN_("reset"));
346 static int CmdUsartBtPin(const char *Cmd
) {
347 CLIParserContext
*ctx
;
348 CLIParserInit(&ctx
, "usart btpin",
349 "Change BT add-on PIN.\n"
350 "WARNING: this requires\n"
351 " 1) BTpower to be turned ON\n"
352 " 2) BT add-on to NOT be connected\n"
353 " => the add-on blue LED must blink",
354 "usart btpin -p 1234"
359 arg_str1("p", "pin", "<dec>", "Desired PIN number (4 digits)"),
362 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
364 char pin
[5] = { 0, 0, 0, 0, 0 };
365 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)pin
, sizeof(pin
), &plen
);
369 PrintAndLogEx(FAILED
, "PIN must be 4 digits");
373 for (uint8_t i
= 0; i
< plen
; i
++) {
374 if (isdigit(pin
[i
]) == false) {
375 PrintAndLogEx(FAILED
, "PIN must be 4 digits");
380 char string
[6 + sizeof(pin
)] = {0};
381 sprintf(string
, "AT+PIN%s", pin
);
382 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
384 int ret
= usart_txrx((uint8_t *)string
, strlen(string
), data
, &len
, 600);
386 if (ret
== PM3_ENODATA
) {
387 PrintAndLogEx(FAILED
, "No response from add-on, is it ON and blinking?");
391 if (ret
!= PM3_SUCCESS
) {
392 PrintAndLogEx(FAILED
, "Command failed, ret=%i", ret
);
396 if (strcmp((char *)data
, "OKsetPIN") == 0) {
397 PrintAndLogEx(NORMAL
, "PIN changed " _GREEN_("successfully"));
399 PrintAndLogEx(WARNING
, "Unexpected answer: %.*s", (int)len
, data
);
404 static int CmdUsartTX(const char *Cmd
) {
405 CLIParserContext
*ctx
;
406 CLIParserInit(&ctx
, "usart tx",
407 "Send string over USART.\n"
408 "WARNING: it will have side-effects if used in USART HOST mode!",
409 "usart tx -d \"AT+VERSION\"\n"
410 "usart tx -d \"AT+VERSION\\r\\n\""
415 arg_str1("d", "data", NULL
, "string to send"),
418 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
420 char s
[PM3_CMD_DATA_SIZE
] = {0};
421 CLIParamStrToBuf(arg_get_str(ctx
, 1), (uint8_t *)s
, sizeof(s
), &slen
);
424 char clean
[PM3_CMD_DATA_SIZE
] = {0};
426 size_t n
= strlen(s
);
429 for (size_t i
= 0; i
< n
; i
++) {
430 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == '\\')) {
435 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == '"')) {
443 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == 'r')) {
448 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == 'n')) {
455 return usart_tx((uint8_t *)clean
, strlen(clean
));
458 static int CmdUsartRX(const char *Cmd
) {
459 CLIParserContext
*ctx
;
460 CLIParserInit(&ctx
, "usart rx",
461 "Receive string over USART.\n"
462 "WARNING: it will have side-effects if used in USART HOST mode!\n",
463 "usart rx -t 2000 -> 2 second timeout"
468 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 0ms"),
471 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
472 uint32_t waittime
= arg_get_u32_def(ctx
, 1, 0);
475 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
477 int ret
= usart_rx(data
, &len
, waittime
);
478 if (ret
!= PM3_SUCCESS
)
481 PrintAndLogEx(SUCCESS
, "RX:%.*s", (int)len
, data
);
485 static int CmdUsartTXRX(const char *Cmd
) {
486 CLIParserContext
*ctx
;
487 CLIParserInit(&ctx
, "usart txrx",
488 "Send string over USART and wait for response.\n"
489 "WARNING: if used in USART HOST mode, you can only send AT commands\n"
490 "to add-on when BT connection is not established (LED needs to be blinking)\n"
491 _RED_("Any other usage in USART HOST mode will have side-effects!"),
493 "usart txrx -d \"AT+VERSION\" -> Talking to BT add-on (when no connection)\n"
494 "usart txrx -t 2000 -d \"AT+SOMESTUFF\\r\\n\" -> Talking to a target requiring longer time and end-of-line chars"
499 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 1000 ms"),
500 arg_str1("d", "data", NULL
, "string to send"),
503 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
504 uint32_t waittime
= arg_get_u32_def(ctx
, 1, 1000);
506 char s
[PM3_CMD_DATA_SIZE
] = {0};
507 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)s
, sizeof(s
), &slen
);
510 char clean
[PM3_CMD_DATA_SIZE
] = {0};
512 size_t n
= strlen(s
);
513 for (size_t i
= 0; i
< n
; i
++) {
514 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == '\\')) {
519 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == '"')) {
527 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == 'r')) {
532 if ((i
< n
- 1) && (s
[i
] == '\\') && (s
[i
+ 1] == 'n')) {
540 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
542 PrintAndLogEx(SUCCESS
, "TX (%3zu):%.*s", strlen(clean
), (int)strlen(clean
), clean
);
543 int ret
= usart_txrx((uint8_t *)clean
, strlen(clean
), data
, &len
, waittime
);
544 if (ret
!= PM3_SUCCESS
)
547 PrintAndLogEx(SUCCESS
, "RX (%3zu):%.*s", len
, (int)len
, data
);
551 static int CmdUsartTXhex(const char *Cmd
) {
553 CLIParserContext
*ctx
;
554 CLIParserInit(&ctx
, "usart txhex",
555 "Send bytes over USART.\n"
556 "WARNING: it will have side-effects if used in USART HOST mode!",
557 "usart txhex -d 504d33620a80000000010100f09f988ef09fa5b36233"
562 arg_str1("d", "data", "<hex>", "bytes to send"),
565 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
568 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
569 int res
= CLIParamHexToBuf(arg_get_str(ctx
, 1), data
, sizeof(data
), &dlen
);
573 PrintAndLogEx(FAILED
, "Error parsing bytes");
576 return usart_tx(data
, dlen
);
579 static int CmdUsartRXhex(const char *Cmd
) {
581 CLIParserContext
*ctx
;
582 CLIParserInit(&ctx
, "usart rxhex",
583 "Receive bytes over USART.\n"
584 "WARNING: it will have side-effects if used in USART HOST mode!\n",
585 "usart rxhex -t 2000 -> 2 second timeout"
590 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 0ms"),
593 CLIExecWithReturn(ctx
, Cmd
, argtable
, true);
594 uint32_t waittime
= arg_get_u32_def(ctx
, 1, 0);
597 uint8_t data
[PM3_CMD_DATA_SIZE
] = {0x00};
599 int ret
= usart_rx(data
, &len
, waittime
);
600 if (ret
!= PM3_SUCCESS
)
603 print_hex_break(data
, len
, 32);
607 static command_t CommandTable
[] = {
608 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
609 {"btpin", CmdUsartBtPin
, IfPm3FpcUsartFromUsb
, "Change BT add-on PIN"},
610 {"btfactory", CmdUsartBtFactory
, IfPm3FpcUsartFromUsb
, "Reset BT add-on to factory settings"},
611 {"tx", CmdUsartTX
, IfPm3FpcUsartDevFromUsb
, "Send string over USART"},
612 {"rx", CmdUsartRX
, IfPm3FpcUsartDevFromUsb
, "Receive string over USART"},
613 {"txrx", CmdUsartTXRX
, IfPm3FpcUsartDevFromUsb
, "Send string over USART and wait for response"},
614 {"txhex", CmdUsartTXhex
, IfPm3FpcUsartDevFromUsb
, "Send bytes over USART"},
615 {"rxhex", CmdUsartRXhex
, IfPm3FpcUsartDevFromUsb
, "Receive bytes over USART"},
616 {"config", CmdUsartConfig
, IfPm3FpcUsartDevFromUsb
, "Configure USART"},
617 // {"bridge", CmdUsartBridge, IfPm3FpcUsartDevFromUsb, "Bridge USB-CDC & USART"},
618 {NULL
, NULL
, NULL
, NULL
}
621 static int CmdHelp(const char *Cmd
) {
622 (void)Cmd
; // Cmd is not used so far
623 CmdsHelp(CommandTable
);
627 int CmdUsart(const char *Cmd
) {
628 clearCommandBuffer();
629 return CmdsParse(CommandTable
, Cmd
);