From: pwpiwi Date: Mon, 27 Jan 2020 18:28:34 +0000 (-0500) Subject: uart_posix.c rework X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/d2ca5dbfe8def88a3d03493524854a79a2b462a1?hp=fd6675219387500f61bfdcde608e326d30ff904b uart_posix.c rework * added some LED handling in appmain.c (helped with debugging) * finally replaced the infamous device unlink by msleep(1000) * fixed some format strings in comms.c (with -DCOMMS_DEBUG) * made uart_receive() and uart_send() behave as described in header * some formating --- diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2eb54d27..4f0a19b9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -311,6 +311,7 @@ void set_hw_capabilities(void) { void SendVersion(void) { + LED_A_ON(); set_hw_capabilities(); char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ @@ -347,6 +348,7 @@ void SendVersion(void) { uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; uint32_t compressed_data_section_size = common_area.arg1; cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString) + 1); + LED_A_OFF(); } // measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. @@ -362,13 +364,11 @@ void printUSBSpeed(void) { uint32_t start_time = end_time = GetTickCount(); uint32_t bytes_transferred = 0; - LED_B_ON(); - while(end_time < start_time + USB_SPEED_TEST_MIN_TIME) { + while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) { cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE); end_time = GetTickCount(); bytes_transferred += USB_CMD_DATA_SIZE; } - LED_B_OFF(); Dbprintf(" Time elapsed: %dms", end_time - start_time); Dbprintf(" Bytes transferred: %d", bytes_transferred); @@ -381,6 +381,7 @@ void printUSBSpeed(void) { * Prints runtime information about the PM3. **/ void SendStatus(void) { + LED_A_ON(); BigBuf_print_status(); Fpga_print_status(); #ifdef WITH_SMARTCARD @@ -393,7 +394,8 @@ void SendStatus(void) { Dbprintf(" ToSendMax..........%d", ToSendMax); Dbprintf(" ToSendBit..........%d", ToSendBit); - cmd_send(CMD_ACK,1,0,0,0,0); + cmd_send(CMD_ACK, 1, 0, 0, 0, 0); + LED_A_OFF(); } #if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone) @@ -1334,9 +1336,11 @@ void UsbPacketReceived(UsbCommand *c) { break; case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control + LED_A_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); LED_D_OFF(); // LED D indicates field ON or OFF + LED_A_OFF(); break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: diff --git a/client/comms.c b/client/comms.c index 5bb7e69e..716a163d 100644 --- a/client/comms.c +++ b/client/comms.c @@ -17,9 +17,6 @@ #include #include -#if defined(__linux__) && !defined(NO_UNLINK) -#include // for unlink() -#endif #include "uart.h" #include "ui.h" #include "common.h" @@ -74,7 +71,7 @@ bool IsOffline() { void SendCommand(UsbCommand *c) { #ifdef COMMS_DEBUG - printf("Sending %04x cmd\n", c->cmd); + printf("Sending %04" PRIx64 " cmd\n", c->cmd); #endif if (offline) { @@ -106,8 +103,7 @@ void SendCommand(UsbCommand *c) { * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which * operation. Right now we'll just have to live with this. */ -void clearCommandBuffer() -{ +void clearCommandBuffer() { //This is a very simple operation pthread_mutex_lock(&rxBufferMutex); cmd_tail = cmd_head; @@ -118,11 +114,9 @@ void clearCommandBuffer() * @brief storeCommand stores a USB command in a circular buffer * @param UC */ -static void storeCommand(UsbCommand *command) -{ +static void storeCommand(UsbCommand *command) { pthread_mutex_lock(&rxBufferMutex); - if( (cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail) - { + if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) { // If these two are equal, we're about to overwrite in the // circular buffer. PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!"); @@ -132,7 +126,7 @@ static void storeCommand(UsbCommand *command) UsbCommand* destination = &rxBuffer[cmd_head]; memcpy(destination, command, sizeof(UsbCommand)); - cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap + cmd_head = (cmd_head + 1) % CMD_BUFFER_SIZE; //increment head and wrap pthread_mutex_unlock(&rxBufferMutex); } @@ -142,19 +136,18 @@ static void storeCommand(UsbCommand *command) * @param response location to write command * @return 1 if response was returned, 0 if nothing has been received */ -static int getCommand(UsbCommand* response) -{ +static int getCommand(UsbCommand* response) { pthread_mutex_lock(&rxBufferMutex); - //If head == tail, there's nothing to read, or if we just got initialized - if (cmd_head == cmd_tail){ + // If head == tail, there's nothing to read + if (cmd_head == cmd_tail) { pthread_mutex_unlock(&rxBufferMutex); return 0; } - //Pick out the next unread command + // Pick out the next unread command UsbCommand* last_unread = &rxBuffer[cmd_tail]; memcpy(response, last_unread, sizeof(UsbCommand)); - //Increment tail - this is a circular buffer, so modulo buffer size + // Increment tail - this is a circular buffer, so modulo buffer size cmd_tail = (cmd_tail + 1) % CMD_BUFFER_SIZE; pthread_mutex_unlock(&rxBufferMutex); @@ -166,15 +159,14 @@ static int getCommand(UsbCommand* response) // Entry point into our code: called whenever we received a packet over USB. // Handle debug commands directly, store all other commands in circular buffer. //---------------------------------------------------------------------------------- -static void UsbCommandReceived(UsbCommand *UC) -{ - switch(UC->cmd) { +static void UsbCommandReceived(UsbCommand *UC) { + switch (UC->cmd) { // First check if we are handling a debug message case CMD_DEBUG_PRINT_STRING: { char s[USB_CMD_DATA_SIZE+1]; memset(s, 0x00, sizeof(s)); - size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); - memcpy(s,UC->d.asBytes,len); + size_t len = MIN(UC->arg[0], USB_CMD_DATA_SIZE); + memcpy(s, UC->d.asBytes,len); PrintAndLog("#db# %s", s); return; } break; @@ -199,7 +191,7 @@ static bool receive_from_serial(serial_port sp, uint8_t *rx_buf, size_t len, siz while (uart_receive(sp, rx_buf + *received_len, len - *received_len, &bytes_read) && bytes_read && *received_len < len) { #ifdef COMMS_DEBUG if (bytes_read != len - *received_len) { - printf("uart_receive() returned true but not enough bytes could be received. received: %d, wanted to receive: %d, already received before: %d\n", + printf("uart_receive() returned true but not enough bytes could be received. received: %zd, wanted to receive: %zd, already received before: %zd\n", bytes_read, len - *received_len, *received_len); } #endif @@ -235,8 +227,10 @@ __attribute__((force_align_arg_pointer)) if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { prx += rxlen; if (response->cmd & CMD_VARIABLE_SIZE_FLAG) { // new style response with variable size - // PrintAndLog("received new style response %04" PRIx16 ", datalen = %d, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32 "\n", - // response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]); +#ifdef COMMS_DEBUG + PrintAndLog("received new style response %04" PRIx16 ", datalen = %zd, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32, + response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]); +#endif bytes_to_read = response->datalen; if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { UsbCommand resp; @@ -251,7 +245,9 @@ __attribute__((force_align_arg_pointer)) } } } else { // old style response uses same data structure as commands. Fixed size. - // PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64 "\n", command->cmd, command->arg[0]); +#ifdef COMMS_DEBUG + PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64, command->cmd, command->arg[0]); +#endif bytes_to_read = sizeof(UsbCommand) - bytes_to_read; if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { UsbCommandReceived(command); @@ -302,8 +298,7 @@ __attribute__((force_align_arg_pointer)) * @param show_warning display message after 2 seconds * @return true if command was returned, otherwise false */ -bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) -{ +bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) { UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; SendCommand(&c); @@ -315,7 +310,7 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon } int bytes_completed = 0; - while(true) { + while (true) { if (getCommand(response)) { if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]); @@ -341,8 +336,7 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon } -bool GetFromFpgaRAM(uint8_t *dest, int bytes) -{ +bool GetFromFpgaRAM(uint8_t *dest, int bytes) { UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}}; SendCommand(&c); @@ -352,7 +346,7 @@ bool GetFromFpgaRAM(uint8_t *dest, int bytes) int bytes_completed = 0; bool show_warning = true; - while(true) { + while (true) { if (getCommand(&response)) { if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]); @@ -387,7 +381,7 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout) { msleep(1000); printf("."); fflush(stdout); - } while(++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); + } while (++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); printf("\n"); } @@ -433,15 +427,6 @@ void CloseProxmark(void) { uart_close(sp); } -#if defined(__linux__) && !defined(NO_UNLINK) - // Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/* - // - // This may be disabled at compile-time with -DNO_UNLINK (used for a JNI-based serial port on Android). - if (serial_port_name) { - unlink(serial_port_name); - } -#endif - // Clean up our state sp = NULL; serial_port_name = NULL; @@ -493,6 +478,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeo PrintAndLog("You can cancel this operation by pressing the pm3 button"); show_warning = false; } + msleep(1); } return false; } diff --git a/client/flash.c b/client/flash.c index 67e371a2..f3d2f420 100644 --- a/client/flash.c +++ b/client/flash.c @@ -185,9 +185,9 @@ static int check_segs(flash_file_t *ctx, int can_write_bl) { return 0; } + // Load an ELF file and prepare it for flashing -int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl) -{ +int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl) { FILE *fd = NULL; Elf32_Ehdr ehdr; Elf32_Phdr *phdrs = NULL; @@ -267,9 +267,9 @@ fail: return -1; } + // Get the state of the proxmark, backwards compatible -static int get_proxmark_state(uint32_t *state) -{ +static int get_proxmark_state(uint32_t *state) { UsbCommand c = {0}; c.cmd = CMD_DEVICE_INFO; SendCommand(&c); @@ -300,9 +300,9 @@ static int get_proxmark_state(uint32_t *state) return 0; } + // Enter the bootloader to be able to start flashing -static int enter_bootloader(char *serial_port_name) -{ +static int enter_bootloader(char *serial_port_name) { uint32_t state; if (get_proxmark_state(&state) < 0) @@ -314,7 +314,7 @@ static int enter_bootloader(char *serial_port_name) } if (state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) { - fprintf(stderr,"Entering bootloader...\n"); + fprintf(stderr, "Entering bootloader...\n"); UsbCommand c; memset(&c, 0, sizeof (c)); @@ -336,6 +336,8 @@ static int enter_bootloader(char *serial_port_name) msleep(100); CloseProxmark(); + msleep(1000); // wait for OS to detect device disconnect. + bool opened = OpenProxmark(serial_port_name, true, 120); // wait for 2 minutes if (opened) { fprintf(stderr," Found.\n"); @@ -350,6 +352,7 @@ static int enter_bootloader(char *serial_port_name) return -1; } + static int wait_for_ack(void) { UsbCommand ack; @@ -361,11 +364,11 @@ static int wait_for_ack(void) return 0; } + // Go into flashing mode int flash_start_flashing(int enable_bl_writes,char *serial_port_name) { uint32_t state; - if (enter_bootloader(serial_port_name) < 0) return -1; diff --git a/uart/uart.h b/uart/uart.h index ce00bc0b..c0a709cf 100644 --- a/uart/uart.h +++ b/uart/uart.h @@ -88,6 +88,8 @@ extern bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLe /* Sends a buffer to a given serial port. * pbtTx: A pointer to a buffer containing the data to send. * szTxLen: The amount of data to be sent. + * + * Returns TRUE if all data could be sent within 30ms. */ extern bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen); @@ -99,5 +101,5 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed); */ extern uint32_t uart_get_speed(const serial_port sp); -#endif // _PM3_UART_H_ +#endif // PM3_UART_H__ diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 7eeb1a83..f6e6519d 100755 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include // Fix missing definition on OS X. // Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 @@ -75,8 +77,8 @@ static struct timeval timeout = { void uart_close(const serial_port sp) { serial_port_unix* spu = (serial_port_unix*)sp; - tcflush(spu->fd,TCIOFLUSH); - tcsetattr(spu->fd,TCSANOW,&(spu->tiOld)); + tcflush(spu->fd, TCIOFLUSH); + tcsetattr(spu->fd, TCSANOW, &(spu->tiOld)); struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; @@ -174,7 +176,7 @@ serial_port uart_open(const char* pcPortName) { } // Try to retrieve the old (current) terminal info struct - if(tcgetattr(sp->fd,&sp->tiOld) == -1) { + if (tcgetattr(sp->fd,&sp->tiOld) == -1) { uart_close(sp); return INVALID_SERIAL_PORT; } @@ -183,18 +185,16 @@ serial_port uart_open(const char* pcPortName) { sp->tiNew = sp->tiOld; // Configure the serial port - sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; - sp->tiNew.c_iflag = IGNPAR; - sp->tiNew.c_oflag = 0; - sp->tiNew.c_lflag = 0; + sp->tiNew.c_cflag &= ~(CSIZE | PARENB); + sp->tiNew.c_cflag |= (CS8 | CLOCAL | CREAD); + sp->tiNew.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + sp->tiNew.c_iflag |= IGNPAR; + sp->tiNew.c_oflag &= ~OPOST; + sp->tiNew.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - // Block until n bytes are received - sp->tiNew.c_cc[VMIN] = 0; - // Block until a timer expires (n * 100 mSec.) - sp->tiNew.c_cc[VTIME] = 0; // Try to set the new terminal info struct - if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) { + if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) { uart_close(sp); return INVALID_SERIAL_PORT; } @@ -206,94 +206,75 @@ serial_port uart_open(const char* pcPortName) { } -bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { - int byteCount; - fd_set rfds; - struct timeval tv; +bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t szMaxRxLen, size_t* pszRxLen) { - // Reset the output count *pszRxLen = 0; - do { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd,&rfds); - tv = timeout; - int res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv); + if (szMaxRxLen == 0) return true; - // Read error - if (res < 0) { - return false; - } + struct timeval t_current; + gettimeofday(&t_current, NULL); + struct timeval t_end; + timeradd(&t_current, &timeout, &t_end); - // Read time-out - if (res == 0) { - if (*pszRxLen == 0) { - // Error, we received no data - return false; - } else { - // We received some data, but nothing more is available - return true; - } + while (true) { + int res = read(((serial_port_unix*)sp)->fd, pbtRx, szMaxRxLen - *pszRxLen); + if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return false; + if (res > 0) { + *pszRxLen += res; + pbtRx += res; } - - // Retrieve the count of the incoming bytes - res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); + if (*pszRxLen == szMaxRxLen) return true; // we could read all requested bytes in time + gettimeofday(&t_current, NULL); + if (timercmp(&t_current, &t_end, >)) return true; // timeout + // set next select timeout + struct timeval t_remains; + timersub(&t_end, &t_current, &t_remains); + // Set the file descriptor set + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(((serial_port_unix*)sp)->fd, &rfds); + // wait for more bytes available + res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &t_remains); if (res < 0) return false; - - // Cap the number of bytes, so we don't overrun the buffer - if (pszMaxRxLen - (*pszRxLen) < byteCount) { - byteCount = pszMaxRxLen - (*pszRxLen); - } - - // There is something available, read the data - res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount); - - // Stop if the OS has some troubles reading the data - if (res <= 0) return false; - - *pszRxLen += res; - - if (*pszRxLen == pszMaxRxLen) { - // We have all the data we wanted. - return true; - } - - } while (byteCount); - - return true; + if (res == 0) return true; // timeout + } + return true; // should never come here } bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { - size_t szPos = 0; - fd_set rfds; - struct timeval tv; - - while (szPos < szTxLen) { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd,&rfds); - tv = timeout; - int res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv); - // Write error - if (res < 0) { - return false; - } + if (szTxLen == 0) return true; - // Write time-out - if (res == 0) { - return false; - } + size_t bytes_written = 0; - // Send away the bytes - res = write(((serial_port_unix*)sp)->fd, pbtTx+szPos, szTxLen-szPos); + struct timeval t_current; + gettimeofday(&t_current, NULL); + struct timeval t_end; + timeradd(&t_current, &timeout, &t_end); - // Stop if the OS has some troubles sending the data - if (res <= 0) return false; - - szPos += res; + while (true) { + int res = write(((serial_port_unix*)sp)->fd, pbtTx, szTxLen - bytes_written); + if (res < 0 && res != EAGAIN && res != EWOULDBLOCK) return false; + if (res > 0) { + pbtTx += res; + bytes_written += res; + } + if (bytes_written == szTxLen) return true; // we could write all bytes + gettimeofday(&t_current, NULL); + if (timercmp(&t_current, &t_end, >)) return false; // timeout + // set next select timeout + struct timeval t_remains; + timersub(&t_end, &t_current, &t_remains); + // Set the file descriptor set + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(((serial_port_unix*)sp)->fd, &wfds); + // wait until more bytes can be written + res = select(((serial_port_unix*)sp)->fd+1, NULL, &wfds, NULL, &t_remains); + if (res < 0) return false; // error + if (res == 0) return false; // timeout } return true; }