fix WaitForResponse (without timeout)
[proxmark3-svn] / client / comms.c
CommitLineData
f5ecd97b 1//-----------------------------------------------------------------------------
2// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
3// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
4//
5// This code is licensed to you under the terms of the GNU GPL, version 2 or,
6// at your option, any later version. See the LICENSE.txt file for the text of
7// the license.
8//-----------------------------------------------------------------------------
9// Code for communicating with the proxmark3 hardware.
10//-----------------------------------------------------------------------------
11
f5ecd97b 12#include "comms.h"
ad939de5 13
929b61c6 14#include <stdio.h>
ac37ee81 15#include <stddef.h>
16#include <string.h>
ad939de5 17#include <pthread.h>
b8ed9975 18#include <inttypes.h>
3458bb27 19#include <time.h>
b8ed9975 20
f5ecd97b 21#include "uart.h"
22#include "ui.h"
23#include "common.h"
2a537311 24#include "util_darwin.h"
f5ecd97b 25#include "util_posix.h"
26
f5ecd97b 27
28// Serial port that we are communicating with the PM3 on.
ad939de5 29static serial_port sp = NULL;
30static char *serial_port_name = NULL;
f5ecd97b 31
32// If TRUE, then there is no active connection to the PM3, and we will drop commands sent.
61aaee35 33static bool offline;
f5ecd97b 34
ad939de5 35typedef struct {
36 bool run; // If TRUE, continue running the uart_communication thread
ad939de5 37} communication_arg_t;
38
39static communication_arg_t conn;
40static pthread_t USB_communication_thread;
41
f5ecd97b 42// Transmit buffer.
ad939de5 43static UsbCommand txBuffer;
44static bool txBuffer_pending = false;
45static pthread_mutex_t txBufferMutex = PTHREAD_MUTEX_INITIALIZER;
46static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER;
f5ecd97b 47
48// Used by UsbReceiveCommand as a ring buffer for messages that are yet to be
49// processed by a command handler (WaitForResponse{,Timeout})
b8ed9975 50#define CMD_BUFFER_SIZE 50
01aa068b 51#define CMD_BUFFER_CHECK_TIME 10 // maximum time (in ms) to wait in getCommand()
52
ad939de5 53static UsbCommand rxBuffer[CMD_BUFFER_SIZE];
f5ecd97b 54
55// Points to the next empty position to write to
56static int cmd_head = 0;
57
58// Points to the position of the last unread command
59static int cmd_tail = 0;
60
ad939de5 61// to lock rxBuffer operations from different threads
62static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER;
3458bb27 63static pthread_cond_t rxBufferSig = PTHREAD_COND_INITIALIZER;
f5ecd97b 64
61aaee35 65// These wrappers are required because it is not possible to access a static
66// global variable outside of the context of a single file.
67
68void SetOffline(bool new_offline) {
69 offline = new_offline;
70}
71
72bool IsOffline() {
73 return offline;
74}
f5ecd97b 75
76void SendCommand(UsbCommand *c) {
61aaee35 77 #ifdef COMMS_DEBUG
d2ca5dbf 78 printf("Sending %04" PRIx64 " cmd\n", c->cmd);
f5ecd97b 79 #endif
80
81 if (offline) {
82 PrintAndLog("Sending bytes to proxmark failed - offline");
83 return;
929b61c6 84 }
ad939de5 85
86 pthread_mutex_lock(&txBufferMutex);
f5ecd97b 87 /**
929b61c6 88 This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive,
ad939de5 89 but comm thread just spins here. Not good.../holiman
f5ecd97b 90 **/
ad939de5 91 while (txBuffer_pending) {
92 pthread_cond_wait(&txBufferSig, &txBufferMutex); // wait for communication thread to complete sending a previous commmand
93 }
94
95 txBuffer = *c;
96 txBuffer_pending = true;
97 pthread_cond_signal(&txBufferSig); // tell communication thread that a new command can be send
98
99 pthread_mutex_unlock(&txBufferMutex);
818efbeb 100
f5ecd97b 101}
102
103
104/**
105 * @brief This method should be called when sending a new command to the pm3. In case any old
106 * responses from previous commands are stored in the buffer, a call to this method should clear them.
107 * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which
108 * operation. Right now we'll just have to live with this.
109 */
d2ca5dbf 110void clearCommandBuffer() {
f5ecd97b 111 //This is a very simple operation
ad939de5 112 pthread_mutex_lock(&rxBufferMutex);
f5ecd97b 113 cmd_tail = cmd_head;
ad939de5 114 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 115}
116
117/**
118 * @brief storeCommand stores a USB command in a circular buffer
119 * @param UC
120 */
d2ca5dbf 121static void storeCommand(UsbCommand *command) {
ad939de5 122 pthread_mutex_lock(&rxBufferMutex);
d2ca5dbf 123 if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) {
f5ecd97b 124 // If these two are equal, we're about to overwrite in the
125 // circular buffer.
126 PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!");
127 }
128
129 // Store the command at the 'head' location
ad939de5 130 UsbCommand* destination = &rxBuffer[cmd_head];
f5ecd97b 131 memcpy(destination, command, sizeof(UsbCommand));
132
d2ca5dbf 133 cmd_head = (cmd_head + 1) % CMD_BUFFER_SIZE; //increment head and wrap
3458bb27 134 pthread_cond_signal(&rxBufferSig); // tell main thread that a new command can be retreived
ad939de5 135 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 136}
137
138
139/**
140 * @brief getCommand gets a command from an internal circular buffer.
141 * @param response location to write command
3458bb27 142 * @return 1 if response was returned, 0 if nothing has been received in time
f5ecd97b 143 */
3458bb27 144static int getCommand(UsbCommand* response, uint32_t ms_timeout) {
145
146 struct timespec end_time;
147 clock_gettime(CLOCK_REALTIME, &end_time);
148 end_time.tv_sec += ms_timeout / 1000;
149 end_time.tv_nsec += (ms_timeout % 1000) * 1000000;
150 if (end_time.tv_nsec > 1000000000) {
151 end_time.tv_nsec -= 1000000000;
152 end_time.tv_sec += 1;
153 }
ad939de5 154 pthread_mutex_lock(&rxBufferMutex);
3458bb27 155 int res = 0;
156 while (cmd_head == cmd_tail && !res) {
157 res = pthread_cond_timedwait(&rxBufferSig, &rxBufferMutex, &end_time);
158 }
159 if (res) { // timeout
ad939de5 160 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 161 return 0;
162 }
163
d2ca5dbf 164 // Pick out the next unread command
ad939de5 165 UsbCommand* last_unread = &rxBuffer[cmd_tail];
f5ecd97b 166 memcpy(response, last_unread, sizeof(UsbCommand));
d2ca5dbf 167 // Increment tail - this is a circular buffer, so modulo buffer size
f5ecd97b 168 cmd_tail = (cmd_tail + 1) % CMD_BUFFER_SIZE;
169
ad939de5 170 pthread_mutex_unlock(&rxBufferMutex);
f5ecd97b 171 return 1;
172}
173
174
babca445 175//----------------------------------------------------------------------------------
176// Entry point into our code: called whenever we received a packet over USB.
177// Handle debug commands directly, store all other commands in circular buffer.
178//----------------------------------------------------------------------------------
d2ca5dbf 179static void UsbCommandReceived(UsbCommand *UC) {
180 switch (UC->cmd) {
f5ecd97b 181 // First check if we are handling a debug message
182 case CMD_DEBUG_PRINT_STRING: {
183 char s[USB_CMD_DATA_SIZE+1];
184 memset(s, 0x00, sizeof(s));
d2ca5dbf 185 size_t len = MIN(UC->arg[0], USB_CMD_DATA_SIZE);
186 memcpy(s, UC->d.asBytes,len);
f5ecd97b 187 PrintAndLog("#db# %s", s);
188 return;
189 } break;
190
191 case CMD_DEBUG_PRINT_INTEGERS: {
192 PrintAndLog("#db# %08x, %08x, %08x \r\n", UC->arg[0], UC->arg[1], UC->arg[2]);
193 return;
194 } break;
195
f5ecd97b 196 default:
929b61c6 197 storeCommand(UC);
f5ecd97b 198 break;
199 }
200
201}
202
203
b8ed9975 204static bool receive_from_serial(serial_port sp, uint8_t *rx_buf, size_t len, size_t *received_len) {
205 size_t bytes_read = 0;
206 *received_len = 0;
3458bb27 207 // we eventually need to call uart_receive several times because it may timeout in the middle of a transfer
b8ed9975 208 while (uart_receive(sp, rx_buf + *received_len, len - *received_len, &bytes_read) && bytes_read && *received_len < len) {
929b61c6 209 #ifdef COMMS_DEBUG
b8ed9975 210 if (bytes_read != len - *received_len) {
d2ca5dbf 211 printf("uart_receive() returned true but not enough bytes could be received. received: %zd, wanted to receive: %zd, already received before: %zd\n",
b8ed9975 212 bytes_read, len - *received_len, *received_len);
213 }
929b61c6 214 #endif
b8ed9975 215 *received_len += bytes_read;
216 bytes_read = 0;
217 }
218 return (*received_len == len);
219}
929b61c6 220
b8ed9975 221
ad939de5 222static void
f5ecd97b 223#ifdef __has_attribute
224#if __has_attribute(force_align_arg_pointer)
929b61c6 225__attribute__((force_align_arg_pointer))
f5ecd97b 226#endif
227#endif
ad939de5 228*uart_communication(void *targ) {
229 communication_arg_t *conn = (communication_arg_t*)targ;
b8ed9975 230 uint8_t rx[sizeof(UsbCommand)];
231 size_t rxlen = 0;
232 uint8_t *prx = rx;
233 UsbCommand *command = (UsbCommand*)rx;
234 UsbResponse *response = (UsbResponse*)rx;
f5ecd97b 235
2a537311
A
236#if defined(__MACH__) && defined(__APPLE__)
237 disableAppNap("Proxmark3 polling UART");
238#endif
239
818efbeb 240 while (conn->run) {
ad939de5 241 bool ACK_received = false;
b8ed9975 242 prx = rx;
243 size_t bytes_to_read = offsetof(UsbResponse, d); // the fixed part of a new style UsbResponse. Otherwise this will be cmd and arg[0] (64 bit each)
244 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
f5ecd97b 245 prx += rxlen;
b8ed9975 246 if (response->cmd & CMD_VARIABLE_SIZE_FLAG) { // new style response with variable size
d2ca5dbf 247#ifdef COMMS_DEBUG
248 PrintAndLog("received new style response %04" PRIx16 ", datalen = %zd, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32,
249 response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]);
250#endif
b8ed9975 251 bytes_to_read = response->datalen;
252 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
253 UsbCommand resp;
929b61c6 254 resp.cmd = response->cmd & ~CMD_VARIABLE_SIZE_FLAG; // remove the flag
b8ed9975 255 resp.arg[0] = response->arg[0];
256 resp.arg[1] = response->arg[1];
257 resp.arg[2] = response->arg[2];
258 memcpy(&resp.d.asBytes, &response->d.asBytes, response->datalen);
259 UsbCommandReceived(&resp);
260 if (resp.cmd == CMD_ACK) {
261 ACK_received = true;
262 }
263 }
264 } else { // old style response uses same data structure as commands. Fixed size.
d2ca5dbf 265#ifdef COMMS_DEBUG
266 PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64, command->cmd, command->arg[0]);
267#endif
b8ed9975 268 bytes_to_read = sizeof(UsbCommand) - bytes_to_read;
929b61c6 269 if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) {
b8ed9975 270 UsbCommandReceived(command);
271 if (command->cmd == CMD_ACK) {
272 ACK_received = true;
273 }
274 }
ad939de5 275 }
f5ecd97b 276 }
f5ecd97b 277
929b61c6 278 pthread_mutex_lock(&txBufferMutex);
279 // if we received an ACK the PM has done its job and waits for another command.
280 // We therefore can wait here as well until a new command is to be transmitted.
281 // The advantage is that the next command will be transmitted immediately without the need to wait for a receive timeout
282 if (ACK_received) {
283 while (!txBuffer_pending) {
284 pthread_cond_wait(&txBufferSig, &txBufferMutex);
ad939de5 285 }
286 }
929b61c6 287 if (txBuffer_pending) {
ad939de5 288 if (!uart_send(sp, (uint8_t*) &txBuffer, sizeof(UsbCommand))) {
f5ecd97b 289 PrintAndLog("Sending bytes to proxmark failed");
290 }
ad939de5 291 txBuffer_pending = false;
f5ecd97b 292 }
929b61c6 293 pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty
ad939de5 294 pthread_mutex_unlock(&txBufferMutex);
f5ecd97b 295 }
296
2a537311
A
297#if defined(__MACH__) && defined(__APPLE__)
298 enableAppNap();
299#endif
300
f5ecd97b 301 pthread_exit(NULL);
302 return NULL;
303}
304
305
babca445 306/**
307 * Data transfer from Proxmark to client. This method times out after
308 * ms_timeout milliseconds.
309 * @brief GetFromBigBuf
310 * @param dest Destination address for transfer
311 * @param bytes number of bytes to be transferred
312 * @param start_index offset into Proxmark3 BigBuf[]
313 * @param response struct to copy last command (CMD_ACK) into
314 * @param ms_timeout timeout in milliseconds
315 * @param show_warning display message after 2 seconds
316 * @return true if command was returned, otherwise false
317 */
d2ca5dbf 318bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) {
babca445 319
320 uint64_t start_time = msclock();
3458bb27 321
322 UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}};
323 SendCommand(&c);
babca445 324
325 UsbCommand resp;
929b61c6 326 if (response == NULL) {
babca445 327 response = &resp;
328 }
329
330 int bytes_completed = 0;
d2ca5dbf 331 while (true) {
3458bb27 332 if (msclock() - start_time > ms_timeout) {
333 break; // timeout
334 }
335 if (msclock() - start_time > 2000 && show_warning) {
336 // 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
337 PrintAndLog("Waiting for a response from the proxmark...");
338 PrintAndLog("You can cancel this operation by pressing the pm3 button");
339 show_warning = false;
340 }
01aa068b 341 if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
babca445 342 if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
343 int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]);
344 memcpy(dest + response->arg[0], response->d.asBytes, copy_bytes);
345 bytes_completed += copy_bytes;
346 } else if (response->cmd == CMD_ACK) {
347 return true;
348 }
349 }
babca445 350 }
351
352 return false;
353}
354
929b61c6 355
d2ca5dbf 356bool GetFromFpgaRAM(uint8_t *dest, int bytes) {
fc52fbd4 357
358 uint64_t start_time = msclock();
3458bb27 359
360 UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}};
361 SendCommand(&c);
fc52fbd4 362
363 UsbCommand response;
929b61c6 364
fc52fbd4 365 int bytes_completed = 0;
366 bool show_warning = true;
d2ca5dbf 367 while (true) {
3458bb27 368 if (msclock() - start_time > 2000 && show_warning) {
369 PrintAndLog("Waiting for a response from the proxmark...");
370 PrintAndLog("You can cancel this operation by pressing the pm3 button");
371 show_warning = false;
372 }
01aa068b 373 if (getCommand(&response, CMD_BUFFER_CHECK_TIME)) {
fc52fbd4 374 if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) {
375 int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]);
376 memcpy(dest + response.arg[0], response.d.asBytes, copy_bytes);
377 bytes_completed += copy_bytes;
378 } else if (response.cmd == CMD_ACK) {
379 return true;
380 }
381 }
fc52fbd4 382 }
383
384 return false;
385}
386
387
929b61c6 388bool OpenProxmark(void *port, bool wait_for_port, int timeout) {
ad939de5 389 char *portname = (char *)port;
390 if (!wait_for_port) {
391 sp = uart_open(portname);
392 } else {
393 printf("Waiting for Proxmark to appear on %s ", portname);
394 fflush(stdout);
395 int openCount = 0;
396 do {
397 sp = uart_open(portname);
398 msleep(1000);
399 printf(".");
400 fflush(stdout);
d2ca5dbf 401 } while (++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT));
ad939de5 402 printf("\n");
403 }
404
405 // check result of uart opening
406 if (sp == INVALID_SERIAL_PORT) {
407 printf("ERROR: invalid serial port\n");
408 sp = NULL;
409 serial_port_name = NULL;
410 return false;
411 } else if (sp == CLAIMED_SERIAL_PORT) {
412 printf("ERROR: serial port is claimed by another process\n");
413 sp = NULL;
414 serial_port_name = NULL;
415 return false;
416 } else {
417 // start the USB communication thread
418 serial_port_name = portname;
419 conn.run = true;
ad939de5 420 pthread_create(&USB_communication_thread, NULL, &uart_communication, &conn);
421 return true;
422 }
423}
424
425
426void CloseProxmark(void) {
427 conn.run = false;
7b2cd970
MF
428
429#ifdef __BIONIC__
430 // In Android O and later, if an invalid pthread_t is passed to pthread_join, it calls fatal().
431 // https://github.com/aosp-mirror/platform_bionic/blob/ed16b344e75f422fb36fbfd91fb30de339475880/libc/bionic/pthread_internal.cpp#L116-L128
432 //
433 // In Bionic libc, pthread_t is an integer.
434
435 if (USB_communication_thread != 0) {
436 pthread_join(USB_communication_thread, NULL);
437 }
438#else
439 // pthread_t is a struct on other libc, treat as an opaque memory reference
ad939de5 440 pthread_join(USB_communication_thread, NULL);
7b2cd970 441#endif
2bb7f7e3
MF
442
443 if (sp) {
444 uart_close(sp);
445 }
446
2bb7f7e3
MF
447 // Clean up our state
448 sp = NULL;
449 serial_port_name = NULL;
eed83b91 450#ifdef __BIONIC__
7b2cd970 451 memset(&USB_communication_thread, 0, sizeof(pthread_t));
eed83b91 452#endif
ad939de5 453}
454
babca445 455
f5ecd97b 456/**
457 * Waits for a certain response type. This method waits for a maximum of
458 * ms_timeout milliseconds for a specified response command.
459 *@brief WaitForResponseTimeout
61aaee35 460 * @param cmd command to wait for, or CMD_UNKNOWN to take any command.
f5ecd97b 461 * @param response struct to copy received command into.
462 * @param ms_timeout
babca445 463 * @param show_warning display message after 2 seconds
f5ecd97b 464 * @return true if command was returned, otherwise false
465 */
466bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning) {
467
468 UsbCommand resp;
469
61aaee35 470 #ifdef COMMS_DEBUG
471 printf("Waiting for %04x cmd\n", cmd);
472 #endif
473
3458bb27 474 uint64_t start_time = msclock();
3458bb27 475
f5ecd97b 476 if (response == NULL) {
477 response = &resp;
478 }
479
f5ecd97b 480 // Wait until the command is received
481 while (true) {
df7b80fe 482 if (ms_timeout != -1 && msclock() > start_time + ms_timeout) {
3458bb27 483 break; // timeout
f5ecd97b 484 }
f5ecd97b 485 if (msclock() - start_time > 2000 && show_warning) {
61aaee35 486 // 2 seconds elapsed (but this doesn't mean the timeout was exceeded)
f5ecd97b 487 PrintAndLog("Waiting for a response from the proxmark...");
488 PrintAndLog("You can cancel this operation by pressing the pm3 button");
489 show_warning = false;
490 }
01aa068b 491 if (getCommand(response, CMD_BUFFER_CHECK_TIME)) {
3458bb27 492 if (cmd == CMD_UNKNOWN || response->cmd == cmd) {
493 return true;
494 }
495 }
f5ecd97b 496 }
497 return false;
498}
499
500
501bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
502 return WaitForResponseTimeoutW(cmd, response, ms_timeout, true);
503}
504
505bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
506 return WaitForResponseTimeoutW(cmd, response, -1, true);
507}
508
Impressum, Datenschutz