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