fix one too small
[RRG-proxmark3.git] / client / src / graph.c
blobbf5a042c016415a574b10426a914cdf449c91ed9
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Graph utilities
17 //-----------------------------------------------------------------------------
18 #include "graph.h"
19 #include <stdlib.h>
20 #include <string.h>
21 #include "ui.h"
22 #include "proxgui.h"
23 #include "util.h" // param_get32ex
24 #include "lfdemod.h"
25 #include "cmddata.h" // for g_debugmode
26 #include "commonutil.h" // Uint4bytetomemle
29 int32_t g_GraphBuffer[MAX_GRAPH_TRACE_LEN];
30 int32_t g_OperationBuffer[MAX_GRAPH_TRACE_LEN];
31 int32_t g_OverlayBuffer[MAX_GRAPH_TRACE_LEN];
32 bool g_useOverlays = false;
33 size_t g_GraphTraceLen;
34 buffer_savestate_t g_saveState_gb;
35 marker_t g_MarkerA, g_MarkerB, g_MarkerC, g_MarkerD;
36 marker_t *g_TempMarkers;
37 uint8_t g_TempMarkerSize = 0;
39 /* write a manchester bit to the graph
41 void AppendGraph(bool redraw, uint16_t clock, int bit) {
42 uint16_t half = clock / 2;
43 uint16_t end = clock;
44 uint16_t i;
46 // overflow/underflow safe checks ... Assumptions:
47 // _Assert(g_GraphTraceLen >= 0);
48 // _Assert(g_GraphTraceLen <= MAX_GRAPH_TRACE_LEN);
49 // If this occurs, allow partial rendering, up to the last sample...
50 if ((MAX_GRAPH_TRACE_LEN - g_GraphTraceLen) < half) {
51 PrintAndLogEx(DEBUG, "WARNING: AppendGraph() - Request exceeds max graph length");
52 end = MAX_GRAPH_TRACE_LEN - g_GraphTraceLen;
53 half = end;
55 if ((MAX_GRAPH_TRACE_LEN - g_GraphTraceLen) < end) {
56 PrintAndLogEx(DEBUG, "WARNING: AppendGraph() - Request exceeds max graph length");
57 end = MAX_GRAPH_TRACE_LEN - g_GraphTraceLen;
60 //set first half the clock bit (all 1's or 0's for a 0 or 1 bit)
61 for (i = 0; i < half; ++i) {
62 g_GraphBuffer[g_GraphTraceLen++] = bit;
65 //set second half of the clock bit (all 0's or 1's for a 0 or 1 bit)
66 for (; i < end; ++i) {
67 g_GraphBuffer[g_GraphTraceLen++] = bit ^ 1;
70 if (redraw) {
71 RepaintGraphWindow();
75 // clear out our graph window and all the buffers associated with it
76 size_t ClearGraph(bool redraw) {
77 size_t gtl = g_GraphTraceLen;
79 memset(g_GraphBuffer, 0x00, g_GraphTraceLen);
80 memset(g_OperationBuffer, 0x00, g_GraphTraceLen);
81 memset(g_OverlayBuffer, 0x00, g_GraphTraceLen);
83 g_GraphTraceLen = 0;
84 g_GraphStart = 0;
85 g_GraphStop = 0;
86 g_DemodBufferLen = 0;
87 g_useOverlays = false;
89 remove_temporary_markers();
90 g_MarkerA.pos = 0;
91 g_MarkerB.pos = 0;
92 g_MarkerC.pos = 0;
93 g_MarkerD.pos = 0;
95 if (redraw) {
96 RepaintGraphWindow();
99 return gtl;
102 void setGraphBuffer(const uint8_t *src, size_t size) {
103 if (src == NULL) {
104 return;
107 ClearGraph(false);
109 if (size > MAX_GRAPH_TRACE_LEN) {
110 size = MAX_GRAPH_TRACE_LEN;
113 for (size_t i = 0; i < size; ++i) {
114 g_GraphBuffer[i] = src[i] - 128;
115 g_OperationBuffer[i] = src[i] - 128;
118 remove_temporary_markers();
119 g_GraphTraceLen = size;
120 RepaintGraphWindow();
123 // This function assumes that the length of dest array >= g_GraphTraceLen.
124 // If the length of dest array is less than g_GraphTraceLen, use getFromGraphBufferEx(dest, maxLen) instead.
125 size_t getFromGraphBuffer(uint8_t *dest) {
126 return getFromGraphBufferEx(dest, g_GraphTraceLen);
129 size_t getFromGraphBufferEx(uint8_t *dest, size_t maxLen) {
130 if (dest == NULL) {
131 return 0;
134 if (g_GraphTraceLen == 0) {
135 return 0;
138 size_t i;
139 maxLen = (maxLen < g_GraphTraceLen) ? maxLen : g_GraphTraceLen;
140 for (i = 0; i < maxLen; ++i) {
141 //trim
142 if (g_GraphBuffer[i] > 127) {
143 g_GraphBuffer[i] = 127;
146 if (g_GraphBuffer[i] < -127) {
147 g_GraphBuffer[i] = -127;
149 dest[i] = (uint8_t)(g_GraphBuffer[i] + 128);
151 return i;
154 //TODO: In progress function to get chunks of data from the GB w/o modifying the GB
155 //Currently seems like it doesn't work correctly?
156 size_t getGraphBufferChunk(uint8_t *dest, size_t start, size_t end) {
157 if (dest == NULL) {
158 return 0;
161 if (g_GraphTraceLen == 0) {
162 return 0;
165 if (start >= end) {
166 return 0;
169 size_t i, value;
170 end = (end < g_GraphTraceLen) ? end : g_GraphTraceLen;
171 for (i = 0; i < (end - start); i++) {
172 value = g_GraphBuffer[start + i];
174 //Trim the data to fit into an uint8_t
175 if (value > 127) {
176 value = 127;
177 } else if (value < -127) {
178 value = -127;
181 dest[i] = ((uint8_t)(value + 128));
184 return i;
187 // A simple test to see if there is any data inside the Graph Buffer.
188 bool HasGraphData(void) {
189 if (g_GraphTraceLen == 0) {
190 PrintAndLogEx(NORMAL, "No data available, try reading something first");
191 return false;
194 return true;
197 bool isGraphBitstream(void) {
198 // convert to bitstream if necessary
199 for (int i = 0; i < g_GraphTraceLen; i++) {
200 if (g_GraphBuffer[i] > 1 || g_GraphBuffer[i] < 0) {
201 return false;
204 return true;
207 void convertGraphFromBitstream(void) {
208 convertGraphFromBitstreamEx(1, 0);
211 void convertGraphFromBitstreamEx(int hi, int low) {
212 for (int i = 0; i < g_GraphTraceLen; i++) {
214 if (g_GraphBuffer[i] == hi)
215 g_GraphBuffer[i] = 127;
216 else if (g_GraphBuffer[i] == low)
217 g_GraphBuffer[i] = -127;
218 else
219 g_GraphBuffer[i] = 0;
222 uint8_t *bits = calloc(g_GraphTraceLen, sizeof(uint8_t));
223 if (bits == NULL) {
224 PrintAndLogEx(DEBUG, "ERR: convertGraphFromBitstreamEx, failed to allocate memory");
225 return;
228 size_t size = getFromGraphBuffer(bits);
229 if (size == 0) {
230 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
231 free(bits);
232 return;
235 // set signal properties low/high/mean/amplitude and is_noise detection
236 computeSignalProperties(bits, size);
237 free(bits);
238 RepaintGraphWindow();
241 // Get or auto-detect ask clock rate
242 int GetAskClock(const char *str, bool verbose) {
243 if (getSignalProperties()->isnoise) {
244 return -1;
247 int clock1 = param_get32ex(str, 0, 0, 10);
248 if (clock1 > 0) {
249 return clock1;
252 // Auto-detect clock
254 uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
255 if (bits == NULL) {
256 PrintAndLogEx(WARNING, "Failed to allocate memory");
257 return -1;
260 size_t size = getFromGraphBuffer(bits);
261 if (size == 0) {
262 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
263 free(bits);
264 return -1;
267 size_t ststart = 0, stend = 0;
268 bool st = DetectST(bits, &size, &clock1, &ststart, &stend);
269 int idx = stend;
270 if (st == false) {
271 idx = DetectASKClock(bits, size, &clock1, 20);
274 if (clock1 > 0) {
275 setClockGrid(clock1, idx);
277 // Only print this message if we're not looping something
278 if (verbose || g_debugMode) {
279 PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d, Best Starting Position: %d", clock1, idx);
282 free(bits);
283 return clock1;
286 int GetPskCarrier(bool verbose) {
287 if (getSignalProperties()->isnoise) {
288 return -1;
291 uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
292 if (bits == NULL) {
293 PrintAndLogEx(WARNING, "Failed to allocate memory");
294 return -1;
297 size_t size = getFromGraphBuffer(bits);
298 if (size == 0) {
299 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
300 free(bits);
301 return -1;
304 uint16_t fc = countFC(bits, size, false);
305 free(bits);
307 uint8_t carrier = fc & 0xFF;
308 if (carrier != 2 && carrier != 4 && carrier != 8) {
309 return 0;
312 if ((fc >> 8) == 10 && carrier == 8) {
313 return 0;
315 // Only print this message if we're not looping something
316 if (verbose) {
317 PrintAndLogEx(SUCCESS, "Auto-detected PSK carrier rate: %d", carrier);
320 return carrier;
323 int GetPskClock(const char *str, bool verbose) {
325 if (getSignalProperties()->isnoise) {
326 return -1;
329 int clock1 = param_get32ex(str, 0, 0, 10);
330 if (clock1 != 0) {
331 return clock1;
334 // Auto-detect clock
335 uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
336 if (bits == NULL) {
337 PrintAndLogEx(WARNING, "Failed to allocate memory");
338 return -1;
341 size_t size = getFromGraphBuffer(bits);
342 if (size == 0) {
343 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
344 free(bits);
345 return -1;
348 size_t firstPhaseShiftLoc = 0;
349 uint8_t curPhase = 0, fc = 0;
350 clock1 = DetectPSKClock(bits, size, 0, &firstPhaseShiftLoc, &curPhase, &fc);
352 if (clock1 >= 0) {
353 setClockGrid(clock1, firstPhaseShiftLoc);
356 // Only print this message if we're not looping something
357 if (verbose) {
358 PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
361 free(bits);
362 return clock1;
365 int GetNrzClock(const char *str, bool verbose) {
367 if (getSignalProperties()->isnoise) {
368 return -1;
371 int clock1 = param_get32ex(str, 0, 0, 10);
372 if (clock1 != 0) {
373 return clock1;
376 // Auto-detect clock
377 uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
378 if (bits == NULL) {
379 PrintAndLogEx(WARNING, "Failed to allocate memory");
380 return -1;
383 size_t size = getFromGraphBuffer(bits);
384 if (size == 0) {
385 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
386 free(bits);
387 return -1;
390 size_t clkStartIdx = 0;
391 clock1 = DetectNRZClock(bits, size, 0, &clkStartIdx);
392 setClockGrid(clock1, clkStartIdx);
393 // Only print this message if we're not looping something
394 if (verbose) {
395 PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
398 free(bits);
399 return clock1;
402 //by marshmellow
403 //attempt to detect the field clock and bit clock for FSK
404 int GetFskClock(const char *str, bool verbose) {
406 int clock1 = param_get32ex(str, 0, 0, 10);
407 if (clock1 != 0) {
408 return clock1;
411 uint8_t fc1 = 0, fc2 = 0, rf1 = 0;
412 int firstClockEdge = 0;
414 if (fskClocks(&fc1, &fc2, &rf1, &firstClockEdge) == false) {
415 return 0;
418 if ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5)) {
419 if (verbose) {
420 PrintAndLogEx(SUCCESS, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1);
423 setClockGrid(rf1, firstClockEdge);
424 return rf1;
427 PrintAndLogEx(DEBUG, "DEBUG: unknown fsk field clock detected");
428 PrintAndLogEx(DEBUG, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1);
429 return 0;
432 bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge) {
434 if (getSignalProperties()->isnoise) {
435 return false;
438 uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
439 if (bits == NULL) {
440 PrintAndLogEx(WARNING, "Failed to allocate memory");
441 return false;
444 size_t size = getFromGraphBuffer(bits);
445 if (size == 0) {
446 PrintAndLogEx(WARNING, "Failed to copy from graphbuffer");
447 free(bits);
448 return false;
451 uint16_t ans = countFC(bits, size, true);
452 if (ans == 0) {
453 PrintAndLogEx(DEBUG, "DEBUG: No data found");
454 free(bits);
455 return false;
458 *fc1 = (ans >> 8) & 0xFF;
459 *fc2 = ans & 0xFF;
460 *rf1 = detectFSKClk(bits, size, *fc1, *fc2, firstClockEdge);
462 free(bits);
464 if (*rf1 == 0) {
465 PrintAndLogEx(DEBUG, "DEBUG: Clock detect error");
466 return false;
468 return true;
471 void add_temporary_marker(uint32_t position, const char *label) {
472 if (g_TempMarkerSize == 0) { //Initialize the marker array
473 g_TempMarkers = (marker_t *)calloc(1, sizeof(marker_t));
474 } else { //add more space to the marker array using realloc()
475 marker_t *temp = (marker_t *)realloc(g_TempMarkers, ((g_TempMarkerSize + 1) * sizeof(marker_t)));
477 if (temp == NULL) { //Unable to reallocate memory for a new marker
478 PrintAndLogEx(FAILED, "Unable to allocate memory for a new temporary marker!");
479 free(temp);
480 return;
481 } else {
482 //Set g_TempMarkers to the new pointer
483 g_TempMarkers = temp;
487 g_TempMarkers[g_TempMarkerSize].pos = position;
489 char *markerLabel = (char *)calloc(1, strlen(label) + 1);
490 strcpy(markerLabel, label);
492 if (strlen(markerLabel) > 30) {
493 PrintAndLogEx(WARNING, "Label for temporary marker too long! Trunicating...");
494 markerLabel[30] = '\0';
497 strncpy(g_TempMarkers[g_TempMarkerSize].label, markerLabel, 30);
498 g_TempMarkerSize++;
500 memset(markerLabel, 0x00, strlen(label));
501 free(markerLabel);
504 void remove_temporary_markers(void) {
505 if (g_TempMarkerSize == 0) return;
507 memset(g_TempMarkers, 0x00, (g_TempMarkerSize * sizeof(marker_t)));
508 free(g_TempMarkers);
509 g_TempMarkerSize = 0;
512 buffer_savestate_t save_buffer32(uint32_t *src, size_t length) {
513 //calloc the memory needed
514 uint32_t *savedBuffer = (uint32_t *)calloc(length, sizeof(uint32_t));
516 //Make a copy of the source buffer
517 memcpy(savedBuffer, src, (length * sizeof(uint32_t)));
519 buffer_savestate_t bst = {
520 .type = sizeof(uint32_t),
521 .bufferSize = length,
522 .buffer = savedBuffer,
523 .padding = 0
526 return bst;
529 buffer_savestate_t save_bufferS32(int32_t *src, size_t length) {
530 //calloc the memory needed
531 uint32_t *savedBuffer = (uint32_t *)calloc(length, (sizeof(uint32_t)));
533 //Make a copy of the source buffer
534 memcpy(savedBuffer, src, (length * sizeof(uint32_t)));
536 buffer_savestate_t bst = {
537 .type = (sizeof(int32_t) >> 8),
538 .bufferSize = length,
539 .buffer = savedBuffer,
540 .padding = 0
543 return bst;
546 buffer_savestate_t save_buffer8(uint8_t *src, size_t length) {
547 // We are going to be packing the 8-bit source buffer into
548 // the 32-bit backing buffer, so the input length is going to be
549 // 1/4 of the size needed
550 size_t buffSize = (length / 4);
552 PrintAndLogEx(DEBUG, "(save_buffer8) buffSize = %llu, length = %llu", buffSize, length);
554 if (length % 4) {
555 buffSize++;
556 PrintAndLogEx(DEBUG, "(save_buffer8) new buffSize = %llu", buffSize);
559 // calloc the memory needed
560 uint32_t *savedBuffer = (uint32_t *)calloc(buffSize, sizeof(uint32_t));
561 size_t index = 0;
563 // Pack the source array into the backing array
564 for (size_t i = 0; i < length; i += 4) {
565 savedBuffer[index] = MemLeToUint4byte(src + i);
566 index++;
569 buffer_savestate_t bst = {
570 .type = sizeof(uint8_t),
571 .bufferSize = buffSize,
572 .buffer = savedBuffer,
573 .padding = ((buffSize * 4) - length)
576 return bst;
579 size_t restore_buffer32(buffer_savestate_t saveState, uint32_t *dest) {
580 if (saveState.type != sizeof(uint32_t)) {
581 PrintAndLogEx(WARNING, "Invalid Save State type! Expected uint32_t!");
582 PrintAndLogEx(WARNING, "Buffer not modified!\n");
583 return 0;
586 memcpy(dest, saveState.buffer, (saveState.bufferSize * sizeof(uint32_t)));
588 return saveState.bufferSize;
591 size_t restore_bufferS32(buffer_savestate_t saveState, int32_t *dest) {
592 if (saveState.type != (sizeof(int32_t) >> 8)) {
593 PrintAndLogEx(WARNING, "Invalid Save State type! Expected int32_t");
594 PrintAndLogEx(WARNING, "Buffer not modified!\n");
595 return 0;
598 memcpy(dest, saveState.buffer, (saveState.bufferSize * sizeof(int32_t)));
600 return saveState.bufferSize;
603 size_t restore_buffer8(buffer_savestate_t saveState, uint8_t *dest) {
604 if (saveState.type != sizeof(uint8_t)) {
605 PrintAndLogEx(WARNING, "Invalid Save State type! Expected uint8_t!");
606 PrintAndLogEx(WARNING, "Buffer not modified!\n");
607 return 0;
610 size_t index = 0;
611 size_t length = ((saveState.bufferSize * 4) - saveState.padding);
613 // Unpack the array
614 for (size_t i = 0; i < saveState.bufferSize; i++) {
615 dest[index++] = saveState.buffer[i];
616 if (index == length) break;
617 dest[index++] = (saveState.buffer[i] >> 8) & 0xFF;
618 if (index == length) break;
619 dest[index++] = (saveState.buffer[i] >> 16) & 0xFF;
620 if (index == length) break;
621 dest[index++] = (saveState.buffer[i] >> 24) & 0xFF;
622 if (index == length) break;
625 return index;