textual
[RRG-proxmark3.git] / client / src / cmdusart.c
blob92991be4cd7884073c0b08b001167d2137abe3c4
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2016 iceman
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 // Analyse bytes commands
9 //-----------------------------------------------------------------------------
10 #include "cmdusart.h"
12 #include <stdlib.h> // size_t
13 #include <string.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include "cmdparser.h" // command_t
17 #include "cliparser.h" //
18 #include "commonutil.h" // ARRAYLEN
19 #include "comms.h"
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) {
27 clearCommandBuffer();
28 SendCommandNG(CMD_USART_TX, data, len);
29 PacketResponseNG resp;
30 if (!WaitForResponseTimeout(CMD_USART_TX, &resp, 1000)) {
31 return PM3_ETIMEOUT;
33 return resp.status;
36 static int usart_rx(uint8_t *data, size_t *len, uint32_t waittime) {
37 clearCommandBuffer();
38 struct {
39 uint32_t waittime;
40 } PACKED payload;
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)) {
45 return PM3_ETIMEOUT;
47 if (resp.status == PM3_SUCCESS) {
48 *len = resp.length;
49 memcpy(data, resp.data.asBytes, resp.length);
51 return resp.status;
54 static int usart_txrx(uint8_t *srcdata, size_t srclen, uint8_t *dstdata, size_t *dstlen, uint32_t waittime) {
55 clearCommandBuffer();
56 struct payload_header {
57 uint32_t waittime;
58 } PACKED;
59 struct {
60 struct payload_header header;
61 uint8_t data[PM3_CMD_DATA_SIZE - sizeof(uint32_t)];
62 } PACKED payload;
63 payload.header.waittime = waittime;
64 if (srclen >= sizeof(payload.data))
65 return PM3_EOVFLOW;
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)) {
70 return PM3_ETIMEOUT;
72 if (resp.status == PM3_SUCCESS) {
73 *dstlen = resp.length;
74 memcpy(dstdata, resp.data.asBytes, resp.length);
76 return resp.status;
79 static int set_usart_config(uint32_t baudrate, uint8_t parity) {
80 clearCommandBuffer();
81 struct {
82 uint32_t baudrate;
83 uint8_t parity;
84 } PACKED payload;
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)) {
90 return PM3_ETIMEOUT;
92 return resp.status;
95 static int CmdUsartConfig(const char *Cmd) {
97 CLIParserContext *ctx;
98 CLIParserInit(&ctx, "usart config",
99 "Configure USART.\n"
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"
104 "usart config -E"
107 void *argtable[] = {
108 arg_param_begin,
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"),
113 arg_param_end
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);
120 CLIParserFree(ctx);
122 if ((pn + pe + po) > 1) {
123 PrintAndLogEx(WARNING, "Only one parity can be used at a time");
124 return PM3_EINVARG;
127 uint8_t parity = 0;
128 if (pn)
129 parity = 'N';
130 else if (po)
131 parity = 'O';
132 else if (pe)
133 parity = 'E';
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)
141 return ret;
143 const char *string = "AT+VERSION";
144 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
145 size_t len = 0;
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!"));
154 return PM3_SUCCESS;
157 return PM3_ENODATA;
160 static int CmdUsartBtFactory(const char *Cmd) {
161 CLIParserContext *ctx;
162 CLIParserInit(&ctx, "usart btfactory",
163 "Reset BT add-on to factory settings\n"
164 "This requires\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!"),
169 "usart btfactory"
172 void *argtable[] = {
173 arg_param_begin,
174 arg_param_end
176 CLIExecWithReturn(ctx, Cmd, argtable, true);
177 CLIParserFree(ctx);
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;
184 uint8_t parity = 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");
189 return PM3_ENOTIMPL;
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]");
196 char input[3];
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;
207 if (found) {
208 baudrate = USART_BAUD_RATE;
209 parity = USART_PARITY;
210 } else {
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;
216 if (found) {
217 baudrate = brs[ibr];
218 parity = ps[ip];
224 if (!found) {
225 PrintAndLogEx(FAILED, "Sorry, add-on not found. Abort.");
226 return PM3_ESOFT;
229 PrintAndLogEx(INFO, "Reconfiguring add-on to default settings.");
230 const char *string;
231 uint8_t data[PM3_CMD_DATA_SIZE];
232 size_t len = 0;
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"));
243 } else {
244 PrintAndLogEx(WARNING, "Unexpected response to AT+NAME: " _YELLOW_("%.*s"), (int)len, data);
246 } else {
247 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
248 return PM3_ESOFT;
251 memset(data, 0, sizeof(data));
252 len = 0;
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"));
261 } else {
262 PrintAndLogEx(WARNING, "Unexpected response to AT+ROLE=S: " _YELLOW_("%.*s"), (int)len, data);
264 } else {
265 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
266 return PM3_ESOFT;
269 memset(data, 0, sizeof(data));
270 len = 0;
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"));
279 } else {
280 PrintAndLogEx(WARNING, "Unexpected response to AT+PIN: " _YELLOW_("%.*s"), (int)len, data);
282 } else {
283 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
284 return PM3_ESOFT;
287 // parity must be changed before baudrate
288 if (parity != USART_PARITY) {
289 memset(data, 0, sizeof(data));
290 len = 0;
291 string = "AT+PN";
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"));
299 } else {
300 PrintAndLogEx(WARNING, "Unexpected response to AT+P: " _YELLOW_("%.*s"), (int)len, data);
302 } else {
303 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
304 return PM3_ESOFT;
308 if (baudrate != USART_BAUD_RATE) {
309 memset(data, 0, sizeof(data));
310 len = 0;
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));
319 } else {
320 PrintAndLogEx(WARNING, "Unexpected response to AT+BAUD: " _YELLOW_("%.*s"), (int)len, data);
322 } else {
323 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
324 return PM3_ESOFT;
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()) {
331 msleep(200);
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;
336 if (!found) {
337 PrintAndLogEx(WARNING, "Lost contact with add-on, please try again");
338 return PM3_ESOFT;
342 PrintAndLogEx(SUCCESS, "Add-on successfully " _GREEN_("reset"));
343 return PM3_SUCCESS;
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"
357 void *argtable[] = {
358 arg_param_begin,
359 arg_str1("p", "pin", "<dec>", "Desired PIN number (4 digits)"),
360 arg_param_end
362 CLIExecWithReturn(ctx, Cmd, argtable, true);
363 int plen = 4;
364 char pin[5] = { 0, 0, 0, 0, 0 };
365 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)pin, sizeof(pin), &plen);
366 CLIParserFree(ctx);
368 if (plen != 4) {
369 PrintAndLogEx(FAILED, "PIN must be 4 digits");
370 return PM3_EINVARG;
373 for (uint8_t i = 0; i < plen; i++) {
374 if (isdigit(pin[i]) == false) {
375 PrintAndLogEx(FAILED, "PIN must be 4 digits");
376 return PM3_EINVARG;
380 char string[6 + sizeof(pin)] = {0};
381 sprintf(string, "AT+PIN%s", pin);
382 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
383 size_t len = 0;
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?");
388 return ret;
391 if (ret != PM3_SUCCESS) {
392 PrintAndLogEx(FAILED, "Command failed, ret=%i", ret);
393 return ret;
396 if (strcmp((char *)data, "OKsetPIN") == 0) {
397 PrintAndLogEx(NORMAL, "PIN changed " _GREEN_("successfully"));
398 } else {
399 PrintAndLogEx(WARNING, "Unexpected answer: %.*s", (int)len, data);
401 return PM3_SUCCESS;
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\""
413 void *argtable[] = {
414 arg_param_begin,
415 arg_str1("d", "data", NULL, "string to send"),
416 arg_param_end
418 CLIExecWithReturn(ctx, Cmd, argtable, true);
419 int slen = 0;
420 char s[PM3_CMD_DATA_SIZE] = {0};
421 CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)s, sizeof(s), &slen);
422 CLIParserFree(ctx);
424 char clean[PM3_CMD_DATA_SIZE] = {0};
425 size_t i2 = 0;
426 size_t n = strlen(s);
428 // strip / replace
429 for (size_t i = 0; i < n; i++) {
430 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == '\\')) {
431 i++;
432 clean[i2++] = '\\';
433 continue;
435 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == '"')) {
436 i++;
437 clean[i2++] = '"';
438 continue;
440 if (s[i] == '"') {
441 continue;
443 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == 'r')) {
444 i++;
445 clean[i2++] = '\r';
446 continue;
448 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == 'n')) {
449 i++;
450 clean[i2++] = '\n';
451 continue;
453 clean[i2++] = s[i];
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"
466 void *argtable[] = {
467 arg_param_begin,
468 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 0ms"),
469 arg_param_end
471 CLIExecWithReturn(ctx, Cmd, argtable, true);
472 uint32_t waittime = arg_get_u32_def(ctx, 1, 0);
473 CLIParserFree(ctx);
475 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
476 size_t len = 0;
477 int ret = usart_rx(data, &len, waittime);
478 if (ret != PM3_SUCCESS)
479 return ret;
481 PrintAndLogEx(SUCCESS, "RX:%.*s", (int)len, data);
482 return PM3_SUCCESS;
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"
497 void *argtable[] = {
498 arg_param_begin,
499 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 1000 ms"),
500 arg_str1("d", "data", NULL, "string to send"),
501 arg_param_end
503 CLIExecWithReturn(ctx, Cmd, argtable, true);
504 uint32_t waittime = arg_get_u32_def(ctx, 1, 1000);
505 int slen = 0;
506 char s[PM3_CMD_DATA_SIZE] = {0};
507 CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)s, sizeof(s), &slen);
508 CLIParserFree(ctx);
510 char clean[PM3_CMD_DATA_SIZE] = {0};
511 size_t j = 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] == '\\')) {
515 i++;
516 clean[j++] = '\\';
517 continue;
519 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == '"')) {
520 i++;
521 clean[j++] = '"';
522 continue;
524 if (s[i] == '"') {
525 continue;
527 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == 'r')) {
528 i++;
529 clean[j++] = '\r';
530 continue;
532 if ((i < n - 1) && (s[i] == '\\') && (s[i + 1] == 'n')) {
533 i++;
534 clean[j++] = '\n';
535 continue;
537 clean[j++] = s[i];
540 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
541 size_t len = 0;
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)
545 return ret;
547 PrintAndLogEx(SUCCESS, "RX (%3zu):%.*s", len, (int)len, data);
548 return PM3_SUCCESS;
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"
560 void *argtable[] = {
561 arg_param_begin,
562 arg_str1("d", "data", "<hex>", "bytes to send"),
563 arg_param_end
565 CLIExecWithReturn(ctx, Cmd, argtable, true);
567 int dlen = 0;
568 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
569 int res = CLIParamHexToBuf(arg_get_str(ctx, 1), data, sizeof(data), &dlen);
570 CLIParserFree(ctx);
572 if (res) {
573 PrintAndLogEx(FAILED, "Error parsing bytes");
574 return PM3_EINVARG;
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"
588 void *argtable[] = {
589 arg_param_begin,
590 arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 0ms"),
591 arg_param_end
593 CLIExecWithReturn(ctx, Cmd, argtable, true);
594 uint32_t waittime = arg_get_u32_def(ctx, 1, 0);
595 CLIParserFree(ctx);
597 uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
598 size_t len = 0;
599 int ret = usart_rx(data, &len, waittime);
600 if (ret != PM3_SUCCESS)
601 return ret;
603 print_hex_break(data, len, 32);
604 return PM3_SUCCESS;
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);
624 return PM3_SUCCESS;
627 int CmdUsart(const char *Cmd) {
628 clearCommandBuffer();
629 return CmdsParse(CommandTable, Cmd);