diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 816ab256d..c28d1448c 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -424,7 +424,7 @@ void SendCapabilities(void) { capabilities.version = CAPABILITIES_VERSION; capabilities.via_fpc = reply_via_fpc; if (reply_via_fpc) - capabilities.baudrate = USART_BAUD_RATE; + capabilities.baudrate = usart_baudrate; else capabilities.baudrate = 0; // no real baudrate for USB-CDC @@ -1173,7 +1173,7 @@ static void PacketReceived(PacketCommandNG *packet) { } #endif -#ifdef WITH_FPC_USART_DEV +#ifdef WITH_FPC_USART case CMD_USART_TX: { LED_B_ON(); usart_writebuffer_sync(packet->data.asBytes, packet->length); @@ -1221,6 +1221,16 @@ static void PacketReceived(PacketCommandNG *packet) { LED_B_OFF(); break; } + case CMD_USART_CONFIG: { + struct p { + uint32_t baudrate; + uint8_t parity; + } PACKED; + struct p *payload = (struct p *) &packet->data.asBytes; + usart_init(payload->baudrate, payload->parity); + reply_ng(CMD_USART_CONFIG, PM3_SUCCESS, NULL, 0); + break; + } #endif case CMD_BUFF_CLEAR: @@ -1631,7 +1641,7 @@ void __attribute__((noreturn)) AppMain(void) { #endif #ifdef WITH_FPC_USART - usart_init(); + usart_init(USART_BAUD_RATE, USART_PARITY); #endif // This is made as late as possible to ensure enumeration without timeout diff --git a/client/cmdusart.c b/client/cmdusart.c index 17738b5a7..2f69fa343 100644 --- a/client/cmdusart.c +++ b/client/cmdusart.c @@ -29,6 +29,20 @@ static int usage_usart_bt_pin(void) { return PM3_SUCCESS; } +static int usage_usart_bt_factory(void) { + PrintAndLogEx(NORMAL, "Reset BT add-on to factory settings"); + PrintAndLogEx(NORMAL, "WARNING: process only if strictly needed!"); + PrintAndLogEx(NORMAL, "This requires"); + PrintAndLogEx(NORMAL, " 1) BTpower to be turned ON"); + PrintAndLogEx(NORMAL, " 2) BT add-on to NOT be connected"); + PrintAndLogEx(NORMAL, " => the blue LED must blink"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: usart btfactory [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + return PM3_SUCCESS; +} + static int usage_usart_tx(void) { PrintAndLogEx(NORMAL, "Send string over USART"); PrintAndLogEx(NORMAL, "WARNING: it will have side-effects if used in USART HOST mode!"); @@ -105,6 +119,23 @@ static int usage_usart_txrx(void) { return PM3_SUCCESS; } +static int usage_usart_config(void) { + PrintAndLogEx(NORMAL, "Configure USART"); + PrintAndLogEx(NORMAL, "WARNING: it will have side-effects if used in USART HOST mode!"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: usart config [h] [b ] [p ]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " b Baudrate"); + PrintAndLogEx(NORMAL, " p Parity (None/Odd/Even)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " usart config b 9600"); + PrintAndLogEx(NORMAL, " usart config b 9600 p N"); + PrintAndLogEx(NORMAL, " usart config p E"); + return PM3_SUCCESS; +} + static int usart_tx(uint8_t *data, size_t len) { clearCommandBuffer(); SendCommandNG(CMD_USART_TX, data, len); @@ -151,6 +182,243 @@ static int usart_txrx(uint8_t *srcdata, size_t srclen, uint8_t *dstdata, size_t return resp.status; } +static int set_usart_config(uint32_t baudrate, uint8_t parity) { + clearCommandBuffer(); + struct { + uint32_t baudrate; + uint8_t parity; + } PACKED payload; + payload.baudrate = baudrate; + payload.parity = parity; + SendCommandNG(CMD_USART_CONFIG, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000)) { + return PM3_ETIMEOUT; + } + return resp.status; +} + +static int CmdUsartConfig(const char *Cmd) { + uint8_t cmdp = 0; + bool errors = false; + uint32_t baudrate = 0; + uint8_t parity = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_usart_config(); + case 'p': + switch (tolower(param_getchar(Cmd, cmdp + 1))) { + case 'n': + parity = 'N'; + break; + case 'o': + parity = 'O'; + break; + case 'e': + parity = 'E'; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp + 1)); + errors = true; + break; + } + cmdp += 2; + break; + case 'b': + baudrate = param_get32ex(Cmd, cmdp + 1, 0, 10); + if (baudrate == 0) { + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp + 1)); + errors = true; + } + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors || ((baudrate == 0) && (parity == 0))) { + usage_usart_config(); + return PM3_EINVARG; + } + return set_usart_config(baudrate, parity); +} + +static int usart_bt_testcomm(uint32_t baudrate, uint8_t parity) { + int ret = set_usart_config(baudrate, parity); + if (ret != PM3_SUCCESS) + return ret; + char *string = "AT+VERSION"; + uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; + size_t len = 0; + PrintAndLogEx(NORMAL, "TX (%3u):%.*s at %u 8%c1", strlen(string), strlen(string), string, baudrate, parity); + ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); // such large timeout needed + if (ret == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "RX (%3u):%.*s", len, len, data); + if (strcmp((char *)data, "hc01.comV2.0") == 0) { + PrintAndLogEx(SUCCESS, "Add-on " _GREEN_("found!"), len, len, data); + return PM3_SUCCESS; + } + } + return PM3_ENODATA; +} + +static int CmdUsartBtFactory(const char *Cmd) { + uint8_t cmdp = 0; + bool errors = false; + uint32_t baudrate = 0; + uint8_t parity = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_usart_bt_factory(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + //Validations + if (errors) { + usage_usart_bt_factory(); + return PM3_EINVARG; + } + PrintAndLogEx(WARNING, "This requires BT turned ON and NOT connected!"); + PrintAndLogEx(WARNING, "Is the blue light blinking? [y/n]"); + while(!ukbhit()) { + msleep(200); + } + int gc = getchar(); + if (gc != 'y') { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(FAILED, "Aborting."); + return PM3_EOPABORTED; + } + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Trying to detect current settings... Please be patient."); + bool found = false; + found = usart_bt_testcomm(USART_BAUD_RATE, USART_PARITY) == PM3_SUCCESS; + if (found) { + baudrate = USART_BAUD_RATE; + parity = USART_PARITY; + } else { + uint32_t brs[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1382400}; + uint8_t ps[] = { 'N', 'O', 'E' }; + for (uint8_t ip = 0; (ip < ARRAYLEN(ps)) && (!found); ip++) { + for (uint8_t ibr = 0; (ibr < ARRAYLEN(brs)) && (!found); ibr++) { + found = usart_bt_testcomm(brs[ibr], ps[ip]) == PM3_SUCCESS; + if (found) { + baudrate = brs[ibr]; + parity = ps[ip]; + } + } + } + } + if (!found) { + PrintAndLogEx(FAILED, "Sorry, add-on not found. Abort."); + return PM3_EFATAL; + } + PrintAndLogEx(INFO, "Reconfiguring add-on to default settings."); + char *string; + uint8_t data[PM3_CMD_DATA_SIZE]; + size_t len; + + memset(data, 0, sizeof(data)); + len = 0; + string = "AT+NAMEPM3_RDV4.0"; + PrintAndLogEx(NORMAL, "TX (%3u):%.*s", strlen(string), strlen(string), string); + int ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); + if (ret == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "RX (%3u):%.*s", len, len, data); + if (strcmp((char *)data, "OKsetname") == 0) { + PrintAndLogEx(SUCCESS, "Name set to " _GREEN_("PM3_RDV4.0")); + } else { + PrintAndLogEx(WARNING, "Unexpected response to AT+NAME: " _YELLOW_("%.*s"), len, data); + } + } else { + PrintAndLogEx(WARNING, "Lost contact with add-on, please try again"); + return PM3_EFATAL; + } + + memset(data, 0, sizeof(data)); + len = 0; + string = "AT+PIN1234"; + PrintAndLogEx(NORMAL, "TX (%3u):%.*s", strlen(string), strlen(string), string); + ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); + if (ret == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "RX (%3u):%.*s", len, len, data); + if (strcmp((char *)data, "OKsetPIN") == 0) { + PrintAndLogEx(SUCCESS, "PIN set to " _GREEN_("1234")); + } else { + PrintAndLogEx(WARNING, "Unexpected response to AT+PIN: " _YELLOW_("%.*s"), len, data); + } + } else { + PrintAndLogEx(WARNING, "Lost contact with add-on, please try again"); + return PM3_EFATAL; + } + + // parity must be changed before baudrate + if (parity != USART_PARITY) { + memset(data, 0, sizeof(data)); + len = 0; + string = "AT+PN"; + PrintAndLogEx(NORMAL, "TX (%3u):%.*s", strlen(string), strlen(string), string); + ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); + if (ret == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "RX (%3u):%.*s", len, len, data); + if (strcmp((char *)data, "OK None") == 0) { + PrintAndLogEx(SUCCESS, "Parity set to " _GREEN_("None")); + } else { + PrintAndLogEx(WARNING, "Unexpected response to AT+P: " _YELLOW_("%.*s"), len, data); + } + } else { + PrintAndLogEx(WARNING, "Lost contact with add-on, please try again"); + return PM3_EFATAL; + } + } + + if (baudrate != USART_BAUD_RATE) { + memset(data, 0, sizeof(data)); + len = 0; + string = "AT+BAUD8"; + PrintAndLogEx(NORMAL, "TX (%3u):%.*s", strlen(string), strlen(string), string); + ret = usart_txrx((uint8_t *)string, strlen(string), data, &len, 1000); + if (ret == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, "RX (%3u):%.*s", len, len, data); + if (strcmp((char *)data, "OK115200") == 0) { + PrintAndLogEx(SUCCESS, "Baudrate set to " _GREEN_("115200")); + } else { + PrintAndLogEx(WARNING, "Unexpected response to AT+BAUD: " _YELLOW_("%.*s"), len, data); + } + } else { + PrintAndLogEx(WARNING, "Lost contact with add-on, please try again"); + return PM3_EFATAL; + } + } + + if ((baudrate != USART_BAUD_RATE) || (parity != USART_PARITY)) { + PrintAndLogEx(WARNING, "Add-on uart settings changed, please turn BT add-on OFF and ON again, then press any key."); + while(!ukbhit()) { + msleep(200); + } + int gc = getchar(); + (void)gc; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Trying to connect add-on with the new settings."); + found = usart_bt_testcomm(USART_BAUD_RATE, USART_PARITY) == PM3_SUCCESS; + if (!found) { + PrintAndLogEx(WARNING, "Lost contact with add-on, please try again"); + return PM3_EFATAL; + } + } + + PrintAndLogEx(SUCCESS, "Add-on successfully " _GREEN_("reset")); + return PM3_SUCCESS; +} + static int CmdUsartBtPin(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; @@ -430,11 +698,13 @@ static int CmdUsartRXhex(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"btpin", CmdUsartBtPin, IfPm3FpcUsartHostFromUsb, "Change BT add-on PIN"}, + {"btfactory", CmdUsartBtFactory, IfPm3FpcUsartHostFromUsb, "Reset BT add-on to factory settings"}, {"tx", CmdUsartTX, IfPm3FpcUsartDevFromUsb, "Send string over USART"}, {"rx", CmdUsartRX, IfPm3FpcUsartDevFromUsb, "Receive string over USART"}, {"txrx", CmdUsartTXRX, IfPm3FpcUsartDevFromUsb, "Send string over USART and wait for response"}, {"txhex", CmdUsartTXhex, IfPm3FpcUsartDevFromUsb, "Send bytes over USART"}, {"rxhex", CmdUsartRXhex, IfPm3FpcUsartDevFromUsb, "Receive bytes over USART"}, + {"config", CmdUsartConfig, IfPm3FpcUsartDevFromUsb, "Configure USART"}, // {"bridge", CmdUsartBridge, IfPm3FpcUsartDevFromUsb, "Bridge USB-CDC & USART"}, {NULL, NULL, NULL, NULL} }; diff --git a/common/usart.c b/common/usart.c index 3e10d13bf..d7819d598 100644 --- a/common/usart.c +++ b/common/usart.c @@ -16,6 +16,8 @@ volatile AT91PS_USART pUS1 = AT91C_BASE_US1; volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_US1; +uint32_t usart_baudrate = 0; +uint8_t usart_parity = 0; /* void usart_close(void) { // Reset the USART mode @@ -170,7 +172,12 @@ inline int usart_writebuffer_sync(uint8_t *data, size_t len) { return PM3_SUCCESS; } -void usart_init(void) { +void usart_init(uint32_t baudrate, uint8_t parity) { + + if (baudrate != 0) + usart_baudrate = baudrate; + if ((parity == 'N') || (parity == 'O') || (parity == 'E')) + usart_parity = parity; // For a nice detailed sample, interrupt driven but still relevant. // See https://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf @@ -192,18 +199,33 @@ void usart_init(void) { pPIO->PIO_PPUER |= (AT91C_PA21_RXD1 | AT91C_PA22_TXD1); // set mode - pUS1->US_MR = AT91C_US_USMODE_NORMAL | // normal mode - AT91C_US_CLKS_CLOCK | // MCK (48MHz) - AT91C_US_OVER | // oversampling - AT91C_US_CHRL_8_BITS | // 8 bits - AT91C_US_PAR_NONE | // parity: none - AT91C_US_NBSTOP_1_BIT | // 1 stop bit - AT91C_US_CHMODE_NORMAL; // channel mode: normal + uint32_t mode = AT91C_US_USMODE_NORMAL | // normal mode + AT91C_US_CLKS_CLOCK | // MCK (48MHz) + AT91C_US_OVER | // oversampling + AT91C_US_CHRL_8_BITS | // 8 bits + AT91C_US_NBSTOP_1_BIT | // 1 stop bit + AT91C_US_CHMODE_NORMAL; // channel mode: normal + + switch(usart_parity) { + case 'N': + mode |= AT91C_US_PAR_NONE; // parity: none + break; + case 'O': + mode |= AT91C_US_PAR_ODD; // parity: odd + break; + case 'E': + mode |= AT91C_US_PAR_EVEN; // parity: even + break; + } + pUS1->US_MR = mode; // all interrupts disabled pUS1->US_IDR = 0xFFFF; - pUS1->US_BRGR = 48054841 / (USART_BAUD_RATE << 3); + // note that for very large baudrates, error is not neglectible: + // b921600 => 8.6% + // b1382400 => 8.6% + pUS1->US_BRGR = 48054841 / (usart_baudrate << 3); // Write the Timeguard Register pUS1->US_TTGR = 0; @@ -219,9 +241,14 @@ void usart_init(void) { pUS1->US_RPR = (uint32_t)us_inbuf1; pUS1->US_RCR = USART_BUFFLEN; usart_cur_inbuf = us_inbuf1; + usart_cur_inbuf_off = 0; pUS1->US_RNPR = (uint32_t)us_inbuf2; pUS1->US_RNCR = USART_BUFFLEN; + // Initialize our fifo + us_rxfifo_low = 0; + us_rxfifo_high = 0; + // re-enable receiver / transmitter pUS1->US_CR = (AT91C_US_RXEN | AT91C_US_TXEN); diff --git a/common/usart.h b/common/usart.h index c6581526b..fd437c952 100644 --- a/common/usart.h +++ b/common/usart.h @@ -7,10 +7,12 @@ //#define USART_BAUD_RATE 9600 #define USART_BAUD_RATE 115200 //#define USART_BAUD_RATE 460800 +extern uint32_t usart_baudrate; +#define USART_PARITY 'N' +extern uint8_t usart_parity; - -void usart_init(void); -void usart_close(void); +void usart_init(uint32_t baudrate, uint8_t parity); +//void usart_close(void); int usart_writebuffer_sync(uint8_t *data, size_t len); uint32_t usart_read_ng(uint8_t *data, size_t len); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 6e455b36f..eff5d44f5 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -221,6 +221,7 @@ typedef struct { #define CMD_USART_RX 0x0160 #define CMD_USART_TX 0x0161 #define CMD_USART_TXRX 0x0162 +#define CMD_USART_CONFIG 0x0163 // For low-frequency tags #define CMD_READ_TI_TYPE 0x0202