Refactoring uart interface (#341)
[proxmark3-svn] / client / proxmark3.c
CommitLineData
a553f267 1//-----------------------------------------------------------------------------
212ef3a0 2// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
a553f267 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// Main binary
10//-----------------------------------------------------------------------------
11
6658905f 12#include <stdio.h>
590f8ff9 13#include <stdlib.h>
6658905f 14#include <string.h>
7fe9b0b7 15#include <pthread.h>
8556b852 16#include <unistd.h>
6658905f 17#include <readline/readline.h>
18#include <readline/history.h>
9484ff3d 19
6658905f 20#include "proxmark3.h"
21#include "proxgui.h"
7fe9b0b7 22#include "cmdmain.h"
902cb3c0 23#include "uart.h"
902cb3c0 24#include "ui.h"
57c69556 25#include "cmdparser.h"
8e074056 26#include "cmdhw.h"
4197a3f6 27#include "whereami.h"
28
902cb3c0 29
9492e0b0 30// a global mutex to prevent interlaced printing from different threads
31pthread_mutex_t print_lock;
32
902cb3c0 33static serial_port sp;
f0ba6342 34static UsbCommand txcmd;
c3385024 35volatile static bool txcmd_pending = false;
902cb3c0 36
37void SendCommand(UsbCommand *c) {
9484ff3d 38 #if 0
39 printf("Sending %d bytes\n", sizeof(UsbCommand));
40 #endif
41
42 if (offline) {
da9d456e 43 PrintAndLog("Sending bytes to proxmark failed - offline");
44 return;
45 }
07976a25
MHS
46 /**
47 The while-loop below causes hangups at times, when the pm3 unit is unresponsive
48 or disconnected. The main console thread is alive, but comm thread just spins here.
49 Not good.../holiman
50 **/
9484ff3d 51 while(txcmd_pending);
52 txcmd = *c;
53 txcmd_pending = true;
902cb3c0 54}
6658905f 55
902cb3c0 56struct receiver_arg {
9484ff3d 57 int run;
6658905f 58};
59
067bfc8b 60byte_t rx[sizeof(UsbCommand)];
fe7bfa78 61byte_t* prx = rx;
902cb3c0 62
63static void *uart_receiver(void *targ) {
9484ff3d 64 struct receiver_arg *arg = (struct receiver_arg*)targ;
65 size_t rxlen;
9484ff3d 66
67 while (arg->run) {
067bfc8b
MF
68 rxlen = 0;
69 if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen)) {
9484ff3d 70 prx += rxlen;
067bfc8b 71 if (prx-rx < sizeof(UsbCommand)) {
9484ff3d 72 continue;
73 }
067bfc8b
MF
74
75 UsbCommandReceived((UsbCommand*)rx);
9484ff3d 76 }
77 prx = rx;
78
79 if(txcmd_pending) {
80 if (!uart_send(sp, (byte_t*) &txcmd, sizeof(UsbCommand))) {
81 PrintAndLog("Sending bytes to proxmark failed");
82 }
83 txcmd_pending = false;
84 }
85 }
86
87 pthread_exit(NULL);
88 return NULL;
6658905f 89}
90
5acd195d 91
92void main_loop(char *script_cmds_file, bool usb_present) {
9484ff3d 93 struct receiver_arg rarg;
94 char *cmd = NULL;
95 pthread_t reader_thread;
1a3c0064 96
5acd195d 97 if (usb_present) {
9484ff3d 98 rarg.run = 1;
99 pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
8e074056 100 // cache Version information now:
101 CmdVersion(NULL);
9484ff3d 102 }
103
104 FILE *script_file = NULL;
105 char script_cmd_buf[256]; // iceman, needs lua script the same file_path_buffer as the rest
106
5acd195d 107 if (script_cmds_file) {
108 script_file = fopen(script_cmds_file, "r");
9484ff3d 109 if (script_file) {
5acd195d 110 printf("using 'scripting' commands file %s\n", script_cmds_file);
9484ff3d 111 }
112 }
7fe9b0b7 113
8556b852 114 read_history(".history");
9484ff3d 115
116 while(1) {
117
118 // If there is a script file
119 if (script_file)
1f947c4b 120 {
9484ff3d 121 if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), script_file)) {
122 fclose(script_file);
123 script_file = NULL;
124 } else {
125 char *nl;
126 nl = strrchr(script_cmd_buf, '\r');
127 if (nl) *nl = '\0';
128
129 nl = strrchr(script_cmd_buf, '\n');
130 if (nl) *nl = '\0';
131
132 if ((cmd = (char*) malloc(strlen(script_cmd_buf) + 1)) != NULL) {
133 memset(cmd, 0, strlen(script_cmd_buf));
134 strcpy(cmd, script_cmd_buf);
135 printf("%s\n", cmd);
136 }
137 }
1f947c4b 138 }
139
9484ff3d 140 if (!script_file) {
9484ff3d 141 cmd = readline(PROXPROMPT);
9484ff3d 142 }
143
8556b852 144 if (cmd) {
9484ff3d 145
8556b852 146 while(cmd[strlen(cmd) - 1] == ' ')
9484ff3d 147 cmd[strlen(cmd) - 1] = 0x00;
8556b852
M
148
149 if (cmd[0] != 0x00) {
2487dfeb 150 int ret = CommandReceived(cmd);
151 add_history(cmd);
152 if (ret == 99) { // exit or quit
8556b852
M
153 break;
154 }
8556b852
M
155 }
156 free(cmd);
157 } else {
158 printf("\n");
159 break;
160 }
161 }
902cb3c0 162
51969283 163 write_history(".history");
902cb3c0 164
5acd195d 165 if (usb_present) {
9484ff3d 166 rarg.run = 0;
167 pthread_join(reader_thread, NULL);
168 }
1a3c0064 169
9484ff3d 170 if (script_file) {
171 fclose(script_file);
172 script_file = NULL;
173 }
5acd195d 174
6658905f 175}
176
dec8e8bd 177static void dumpAllHelp(int markdown)
ae7aa73d 178{
dec8e8bd
PT
179 printf("\n%sProxmark3 command dump%s\n\n",markdown?"# ":"",markdown?"":"\n======================");
180 printf("Some commands are available only if a Proxmark is actually connected.%s\n",markdown?" ":"");
6f5dd601 181 printf("Check column \"offline\" for their availability.\n");
ae7aa73d 182 printf("\n");
57c69556 183 command_t *cmds = getTopLevelCommandTable();
dec8e8bd 184 dumpCommandsRecursive(cmds, markdown);
ae7aa73d
PT
185}
186
4197a3f6 187static char *my_executable_path = NULL;
188static char *my_executable_directory = NULL;
189
4a6bc37e 190const char *get_my_executable_path(void)
4197a3f6 191{
192 return my_executable_path;
193}
194
4a6bc37e 195const char *get_my_executable_directory(void)
4197a3f6 196{
197 return my_executable_directory;
198}
199
200static void set_my_executable_path(void)
201{
202 int path_length = wai_getExecutablePath(NULL, 0, NULL);
203 if (path_length != -1) {
204 my_executable_path = (char*)malloc(path_length + 1);
205 int dirname_length = 0;
206 if (wai_getExecutablePath(my_executable_path, path_length, &dirname_length) != -1) {
207 my_executable_path[path_length] = '\0';
208 my_executable_directory = (char *)malloc(dirname_length + 2);
209 strncpy(my_executable_directory, my_executable_path, dirname_length+1);
4a6bc37e 210 my_executable_directory[dirname_length+1] = '\0';
4197a3f6 211 }
212 }
213}
214
5acd195d 215
902cb3c0 216int main(int argc, char* argv[]) {
9492e0b0 217 srand(time(0));
125a98a1 218
9492e0b0 219 if (argc < 2) {
220 printf("syntax: %s <port>\n\n",argv[0]);
221 printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
dec8e8bd
PT
222 printf("help: %s -h\n\n", argv[0]);
223 printf("\tDump all interactive help at once\n");
224 printf("markdown: %s -m\n\n", argv[0]);
225 printf("\tDump all interactive help at once in markdown syntax\n");
9492e0b0 226 return 1;
227 }
dec8e8bd
PT
228 if (strcmp(argv[1], "-h") == 0) {
229 printf("syntax: %s <port>\n\n",argv[0]);
230 printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
231 dumpAllHelp(0);
232 return 0;
233 }
234 if (strcmp(argv[1], "-m") == 0) {
235 dumpAllHelp(1);
236 return 0;
237 }
4197a3f6 238
239 set_my_executable_path();
240
5acd195d 241 bool usb_present = false;
242 char *script_cmds_file = NULL;
4890730a 243
9492e0b0 244 sp = uart_open(argv[1]);
245 if (sp == INVALID_SERIAL_PORT) {
246 printf("ERROR: invalid serial port\n");
5acd195d 247 usb_present = false;
9492e0b0 248 offline = 1;
249 } else if (sp == CLAIMED_SERIAL_PORT) {
250 printf("ERROR: serial port is claimed by another process\n");
5acd195d 251 usb_present = false;
9492e0b0 252 offline = 1;
253 } else {
5acd195d 254 usb_present = true;
9492e0b0 255 offline = 0;
256 }
7fe9b0b7 257
9492e0b0 258 // If the user passed the filename of the 'script' to execute, get it
259 if (argc > 2 && argv[2]) {
ed77aabe 260 if (argv[2][0] == 'f' && //buzzy, if a word 'flush' passed, flush the output after every log entry.
261 argv[2][1] == 'l' &&
262 argv[2][2] == 'u' &&
263 argv[2][3] == 's' &&
264 argv[2][4] == 'h')
265 {
266 printf("Output will be flushed after every print.\n");
267 flushAfterWrite = 1;
268 }
269 else
5acd195d 270 script_cmds_file = argv[2];
9492e0b0 271 }
ed77aabe 272
9492e0b0 273 // create a mutex to avoid interlacing print commands from our different threads
274 pthread_mutex_init(&print_lock, NULL);
7fe9b0b7 275
5acd195d 276#ifdef HAVE_GUI
277 InitGraphics(argc, argv, script_cmds_file, usb_present);
9492e0b0 278 MainGraphics();
5acd195d 279#else
280 main_loop(script_cmds_file, usb_present);
281#endif
7fe9b0b7 282
9492e0b0 283 // Clean up the port
5acd195d 284 if (usb_present) {
2487dfeb 285 uart_close(sp);
286 }
287
9492e0b0 288 // clean up mutex
289 pthread_mutex_destroy(&print_lock);
2487dfeb 290
291 exit(0);
6658905f 292}
Impressum, Datenschutz