diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 146e1fd3c..63a7dba10 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1106,16 +1106,17 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t my_rx[20]; memset(my_rx, 0, sizeof(my_rx)); - res = usart_readbuffer(my_rx, sizeof(my_rx)); + res = usart_readbuffer(my_rx); WaitMS(1); Dbprintf("GOT %d | %c%c%c%c%c%c%c%c", res, my_rx[0], my_rx[1], my_rx[2], my_rx[3], my_rx[4], my_rx[5], my_rx[6], my_rx[7]); */ - char dest[USB_CMD_DATA_SIZE] = {'\0'}; - if (usart_dataavailable()) { + char dest[USART_FIFOLEN] = {'\0'}; + uint16_t available = usart_rxdata_available(); + if (available > 0) { Dbprintf("RX DATA!"); - uint16_t len = usart_readbuffer((uint8_t *)dest); + uint16_t len = usart_read_ng((uint8_t *)dest, available); dest[len] = '\0'; Dbprintf("RX: %d | %02X %02X %02X %02X %02X %02X %02X %02X ", len, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); } @@ -1142,7 +1143,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t my_rx[sizeof(PacketCommandOLD)]; while (!BUTTON_PRESS() && !usb_poll_validate_length()) { LED_B_INV(); - if (usart_readbuffer(my_rx) ) { + if (usart_read_ng(my_rx) ) { //PacketReceived(my_rx, sizeof(my_rx)); PacketCommandOLD *my = (PacketCommandOLD *)my_rx; @@ -1568,7 +1569,7 @@ void __attribute__((noreturn)) AppMain(void) { if (ret == PM3_SUCCESS) { PacketReceived(&rx); } else if (ret != PM3_ENODATA) { - Dbprintf("Error in frame reception"); + Dbprintf("Error in frame reception: %d", ret); // TODO DOEGOX if error, shall we resync ? } diff --git a/client/comms.c b/client/comms.c index 59215a299..8e9eb0a64 100644 --- a/client/comms.c +++ b/client/comms.c @@ -563,6 +563,21 @@ void CloseProxmark(void) { memset(&USB_communication_thread, 0, sizeof(pthread_t)); } +// Gives a rough estimate of the communication delay based on channel & baudrate +// Max communication delay is when sending largest frame and receiving largest frame +// Empirical measures on FTDI with physical cable: +// "hw pingng 512" +// usb -> 6..32ms +// 460800 -> 40..70ms +// 9600 -> 1100..1150ms +// ~ = 12000000 / USART_BAUD_RATE +// Let's take 2x (maybe we need more for BT link?) +static size_t communication_delay(void) { + if (send_via_fpc) // needed also for Windows USB USART?? + return 2 * (12000000 / uart_speed); + return 100; +} + /** * @brief Waits for a certain response type. This method waits for a maximum of * ms_timeout milliseconds for a specified response command. @@ -580,14 +595,18 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms if (response == NULL) response = &resp; + // Add delay depending on the communication channel & speed + ms_timeout += communication_delay(); uint64_t start_time = msclock(); // Wait until the command is received while (true) { while (getReply(response)) { - if (cmd == CMD_UNKNOWN || response->cmd == cmd) + if (cmd == CMD_UNKNOWN || response->cmd == cmd) { +// PrintAndLogEx(INFO, "Waited %i ms", msclock() - start_time); return true; + } } if (msclock() - start_time > ms_timeout) @@ -600,6 +619,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms show_warning = false; } } +// PrintAndLogEx(INFO, "Wait timeout after %i ms", msclock() - start_time); return false; } diff --git a/client/proxmark3.c b/client/proxmark3.c index dbeb3f217..99cdc6eea 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -431,7 +431,7 @@ int main(int argc, char *argv[]) { if (speed == 0) #ifdef WITH_FPC_HOST // Let's assume we're talking by default to pm3 over usart in this mode - speed = AT91_BAUD_RATE; + speed = USART_BAUD_RATE; #else speed = 460800; #endif diff --git a/common/cmd.c b/common/cmd.c index c1320e0cc..fb8396051 100644 --- a/common/cmd.c +++ b/common/cmd.c @@ -227,8 +227,8 @@ int16_t receive_ng(PacketCommandNG *rx) { #ifdef WITH_FPC_HOST // Check if there is a FPC packet available - return receive_ng_internal(rx, usart_read_ng, true); -#else - return PM3_ENODATA; + if (usart_rxdata_available() > 0) + return receive_ng_internal(rx, usart_read_ng, true); #endif + return PM3_ENODATA; } diff --git a/common/usart.c b/common/usart.c index 928a0ee14..56f6bb446 100644 --- a/common/usart.c +++ b/common/usart.c @@ -38,119 +38,123 @@ void usart_close(void) { } */ -static uint8_t us_inbuf[sizeof(PacketCommandOLD)]; -static uint8_t us_outbuf[sizeof(PacketResponseOLD)]; -/* -// transfer from client to device -inline int16_t usart_readbuffer(uint8_t *data) { - uint32_t rcr = pUS1->US_RCR; - if (rcr < sizeof(us_inbuf)) { - pUS1->US_PTCR = AT91C_PDC_RXTDIS; - memcpy(data, us_inbuf, sizeof(us_inbuf) - rcr); - // Reset DMA buffer - pUS1->US_RPR = (uint32_t)us_inbuf; - pUS1->US_RCR = sizeof(us_inbuf); - pUS1->US_PTCR = AT91C_PDC_RXTEN; - return sizeof(us_inbuf) - rcr; - } else { - return 0; - } -} -*/ +static uint8_t us_inbuf1[USART_BUFFLEN]; +static uint8_t us_inbuf2[USART_BUFFLEN]; +uint8_t *usart_cur_inbuf = NULL; +uint16_t usart_cur_inbuf_off = 0; +static uint8_t us_rxfifo[USART_FIFOLEN]; +static size_t us_rxfifo_low = 0; +static size_t us_rxfifo_high = 0; -uint8_t check = 0; -inline int16_t usart_readbuffer(uint8_t *data) { - // Check if the first PDC bank is free - if (pUS1->US_RCR == 0) { - pUS1->US_RPR = (uint32_t)data; - pUS1->US_RCR = sizeof(PacketCommandOLD); - pUS1->US_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; - check = 0; - return 2; - } else { - return 0; - } -} -void usart_readcheck(uint8_t *data, size_t len) { - if (pUS1->US_RCR < len) { - if (check == 0) { - StartCountUS(); - check = 1; +static void usart_fill_rxfifo(void) { + if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used +// TODO check if we have room... + uint16_t available = USART_BUFFLEN - usart_cur_inbuf_off; + for (uint16_t i = 0; i < available; i++) { + us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i]; + if (us_rxfifo_high == sizeof(us_rxfifo)) + us_rxfifo_high = 0; } - //300ms - if (GetCountUS() > 300000) { - pUS1->US_RPR = (uint32_t)data; - pUS1->US_RCR = len; - check = 0; + // Give next buffer + pUS1->US_RNPR = (uint32_t)usart_cur_inbuf; + pUS1->US_RNCR = USART_BUFFLEN; + // Swap current buff + if (usart_cur_inbuf == us_inbuf1) + usart_cur_inbuf = us_inbuf2; + else + usart_cur_inbuf = us_inbuf1; + usart_cur_inbuf_off = 0; + } + if (pUS1->US_RCR < USART_BUFFLEN - usart_cur_inbuf_off) { // Current buffer partially filled + uint16_t available = USART_BUFFLEN - pUS1->US_RCR - usart_cur_inbuf_off; +// TODO check if we have room... + for (uint16_t i = 0; i < available; i++) { + us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i]; + if (us_rxfifo_high == sizeof(us_rxfifo)) + us_rxfifo_high = 0; } - } else { - check = 0; + usart_cur_inbuf_off += available; } } -inline bool usart_dataavailable(void) { - return pUS1->US_RCR < sizeof(us_inbuf); +uint16_t usart_rxdata_available(void) { + usart_fill_rxfifo(); + if (us_rxfifo_low <= us_rxfifo_high) + return us_rxfifo_high - us_rxfifo_low; + else + return sizeof(us_rxfifo) - us_rxfifo_low + us_rxfifo_high; } -inline int16_t usart_readcommand(uint8_t *data) { - if (pUS1->US_RCR == 0) - return usart_readbuffer(data); - - return 0; -} +extern bool reply_via_fpc; +extern void Dbprintf(const char *fmt, ...); +#define Dbprintf_usb(...) {\ + bool tmp = reply_via_fpc;\ + reply_via_fpc = false;\ + Dbprintf(__VA_ARGS__);\ + reply_via_fpc = tmp;} uint32_t usart_read_ng(uint8_t *data, size_t len) { - // TODO DOEGOX - return 0; + if (len == 0) return 0; + uint32_t packetSize, nbBytesRcv = 0; + uint32_t try = 0; +// uint32_t highest_observed_try = 0; + // Empirical max try observed: 3000000 / USART_BAUD_RATE + // Let's take 10x + uint32_t maxtry = 10 * ( 3000000 / USART_BAUD_RATE ); + + while (len) { + uint32_t available = usart_rxdata_available(); + + packetSize = MIN(available, len); + if (available > 0) { +// Dbprintf_usb("Dbg USART ask %d bytes, available %d bytes, packetsize %d bytes", len, available, packetSize); +// highest_observed_try = MAX(highest_observed_try, try); + try = 0; + } + len -= packetSize; + while (packetSize--) { + data[nbBytesRcv++] = us_rxfifo[us_rxfifo_low++]; + if (us_rxfifo_low == sizeof(us_rxfifo)) + us_rxfifo_low = 0; + } + if (try++ == maxtry) { + Dbprintf_usb("Dbg USART TIMEOUT"); + break; + } + } +// highest_observed_try = MAX(highest_observed_try, try); +// Dbprintf_usb("Dbg USART max observed try %i", highest_observed_try); + return nbBytesRcv; } -inline bool usart_commandavailable(void) { - return (pUS1->US_RCR == 0); -} -/* // transfer from device to client inline int16_t usart_writebuffer(uint8_t *data, size_t len) { + // Wait for one free PDC bank + while (pUS1->US_TCR && pUS1->US_TNCR) {}; + // ? alternative to wait for end of transmissions? + // while (!(pUS1->US_CSR & AT91C_US_ENDTX)) {}; - if (pUS1->US_CSR & AT91C_US_ENDTX) { - memcpy(us_outbuf, data, len); - pUS1->US_TPR = (uint32_t)us_outbuf; + // Check if the current PDC bank is free + if (pUS1->US_TCR == 0) { + pUS1->US_TPR = (uint32_t)data; pUS1->US_TCR = len; - pUS1->US_PTCR = AT91C_PDC_TXTEN; - while (!(pUS1->US_CSR & AT91C_US_ENDTX)) {}; - pUS1->US_PTCR = AT91C_PDC_TXTDIS; - return len; + } + // Check if the backup PDC bank is free + else if (pUS1->US_TNCR == 0) { + pUS1->US_TNPR = (uint32_t)data; + pUS1->US_TNCR = len; } else { + // we shouldn't be here return 0; } + // Make sure TX transfer is enabled + pUS1->US_PTCR = AT91C_PDC_TXTEN;// | AT91C_PDC_RXTEN; + //wait until finishing all transfers + while (pUS1->US_TNCR || pUS1->US_TCR) {}; + return len; } -*/ - -// transfer from device to client -inline int16_t usart_writebuffer(uint8_t *data, size_t len) { - - while (pUS1->US_TCR && pUS1->US_TNCR) {}; - - // Check if the first PDC bank is free - if (pUS1->US_TCR == 0) { - memcpy(us_outbuf, data, len); - pUS1->US_TPR = (uint32_t)us_outbuf; - pUS1->US_TCR = sizeof(us_outbuf); - pUS1->US_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN; - } - // Check if the second PDC bank is free - else if (pUS1->US_TNCR == 0) { - memcpy(us_outbuf, data, len); - pUS1->US_TNPR = (uint32_t)us_outbuf; - pUS1->US_TNCR = sizeof(us_outbuf); - pUS1->US_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN; - } - //wait until finishing transfer - while (pUS1->US_TCR && pUS1->US_TNCR) {}; - return 0; -} - void usart_init(void) { @@ -185,9 +189,7 @@ void usart_init(void) { // all interrupts disabled pUS1->US_IDR = 0xFFFF; - pUS1->US_BRGR = 48054841 / (AT91_BAUD_RATE << 3); - // Need speed? - //pUS1->US_BRGR = 48054841 / (460800 << 3); + pUS1->US_BRGR = 48054841 / (USART_BAUD_RATE << 3); // Write the Timeguard Register pUS1->US_TTGR = 0; @@ -195,9 +197,13 @@ void usart_init(void) { pUS1->US_FIDI = 0; pUS1->US_IF = 0; - // Disable double buffers for now + // Initialize DMA buffers + pUS1->US_TPR = (uint32_t)0; + pUS1->US_TCR = 0; pUS1->US_TNPR = (uint32_t)0; pUS1->US_TNCR = 0; + pUS1->US_RPR = (uint32_t)0; + pUS1->US_RCR = 0; pUS1->US_RNPR = (uint32_t)0; pUS1->US_RNCR = 0; @@ -205,8 +211,10 @@ void usart_init(void) { pUS1->US_CR = (AT91C_US_RXEN | AT91C_US_TXEN); // ready to receive - pUS1->US_RPR = (uint32_t)us_inbuf; - pUS1->US_RCR = 0; - pUS1->US_RNCR = 0; + pUS1->US_RPR = (uint32_t)us_inbuf1; + pUS1->US_RCR = USART_BUFFLEN; + usart_cur_inbuf = us_inbuf1; + pUS1->US_RNPR = (uint32_t)us_inbuf2; + pUS1->US_RNCR = USART_BUFFLEN; pUS1->US_PTCR = AT91C_PDC_RXTEN; } diff --git a/common/usart.h b/common/usart.h index 16d0d8773..1f37429c8 100644 --- a/common/usart.h +++ b/common/usart.h @@ -4,17 +4,18 @@ #include #include "proxmark3.h" -#define AT91_BAUD_RATE 115200 +//#define USART_BAUD_RATE 9600 +#define USART_BAUD_RATE 115200 +//#define USART_BAUD_RATE 460800 + void usart_init(void); void usart_close(void); -int16_t usart_readbuffer(uint8_t *data); int16_t usart_writebuffer(uint8_t *data, size_t len); -bool usart_dataavailable(void); -int16_t usart_readcommand(uint8_t *data); -void usart_readcheck(uint8_t *data, size_t len); uint32_t usart_read_ng(uint8_t *data, size_t len); +uint16_t usart_rxdata_available(void); +#define USART_BUFFLEN 512 +#define USART_FIFOLEN (2*USART_BUFFLEN) -bool usart_commandavailable(void); #endif diff --git a/uart/uart.h b/uart/uart.h index 714f646b9..49900be39 100644 --- a/uart/uart.h +++ b/uart/uart.h @@ -103,6 +103,7 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed); /* Gets the current speed of the serial port, in baud. */ uint32_t uart_get_speed(const serial_port sp); +extern uint32_t uart_speed; #endif // _UART_H_ diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 8ea8aa619..e3b7c56b8 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -60,6 +60,9 @@ # define SOL_TCP IPPROTO_TCP #endif +// To memorise baudrate, we don't want to call get_speed systematically +uint32_t uart_speed; + typedef struct termios term_info; typedef struct { int fd; // Serial port file descriptor @@ -206,7 +209,8 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } } } - printf("[=] UART Setting serial baudrate %u\n", speed); + uart_speed = uart_get_speed(sp); + printf("[=] UART Setting serial baudrate %u\n", uart_speed); return sp; } @@ -408,7 +412,10 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { // Set port speed (Input and Output) cfsetispeed(&ti, stPortSpeed); cfsetospeed(&ti, stPortSpeed); - return (tcsetattr(spu->fd, TCSANOW, &ti) != -1); + bool result = tcsetattr(spu->fd, TCSANOW, &ti) != -1; + if (result) + uart_speed = uiPortSpeed; + return result; } uint32_t uart_get_speed(const serial_port sp) { diff --git a/uart/uart_win32.c b/uart/uart_win32.c index 789b430b9..c6e3142cf 100644 --- a/uart/uart_win32.c +++ b/uart/uart_win32.c @@ -42,6 +42,9 @@ #ifdef _WIN32 #include +// To memorise baudrate, we don't want to call get_speed systematically +uint32_t uart_speed; + typedef struct { HANDLE hPort; // Serial port handle DCB dcb; // Device control settings @@ -121,7 +124,8 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } } } - printf("[=] UART Setting serial baudrate %i\n", speed); + uart_speed = uart_get_speed(sp); + printf("[=] UART Setting serial baudrate %u\n", uart_speed); return sp; } @@ -152,6 +156,8 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { spw->dcb.BaudRate = uiPortSpeed; bool result = SetCommState(spw->hPort, &spw->dcb); PurgeComm(spw->hPort, PURGE_RXABORT | PURGE_RXCLEAR); + if (result) + uart_speed = uiPortSpeed; return result; }