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