| 1 | //----------------------------------------------------------------------------- |
| 2 | // Copyright (C) 2010 iZsh <izsh at fail0verflow.com> |
| 3 | // |
| 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, |
| 5 | // at your option, any later version. See the LICENSE.txt file for the text of |
| 6 | // the license. |
| 7 | //----------------------------------------------------------------------------- |
| 8 | // Graph utilities |
| 9 | //----------------------------------------------------------------------------- |
| 10 | |
| 11 | #include <stdio.h> |
| 12 | #include <stdbool.h> |
| 13 | #include <string.h> |
| 14 | #include "ui.h" |
| 15 | #include "graph.h" |
| 16 | #include "lfdemod.h" |
| 17 | #include "cmddata.h" //for g_debugmode |
| 18 | |
| 19 | int GraphBuffer[MAX_GRAPH_TRACE_LEN]; |
| 20 | int GraphTraceLen; |
| 21 | |
| 22 | int s_Buff[MAX_GRAPH_TRACE_LEN]; |
| 23 | |
| 24 | /* write a manchester bit to the graph */ |
| 25 | void AppendGraph(int redraw, int clock, int bit) |
| 26 | { |
| 27 | int i; |
| 28 | //set first half the clock bit (all 1's or 0's for a 0 or 1 bit) |
| 29 | for (i = 0; i < (int)(clock / 2); ++i) |
| 30 | GraphBuffer[GraphTraceLen++] = bit ; |
| 31 | //set second half of the clock bit (all 0's or 1's for a 0 or 1 bit) |
| 32 | for (i = (int)(clock / 2); i < clock; ++i) |
| 33 | GraphBuffer[GraphTraceLen++] = bit ^ 1; |
| 34 | |
| 35 | if (redraw) |
| 36 | RepaintGraphWindow(); |
| 37 | } |
| 38 | |
| 39 | // clear out our graph window |
| 40 | int ClearGraph(int redraw) |
| 41 | { |
| 42 | int gtl = GraphTraceLen; |
| 43 | memset(GraphBuffer, 0x00, GraphTraceLen); |
| 44 | |
| 45 | GraphTraceLen = 0; |
| 46 | |
| 47 | if (redraw) |
| 48 | RepaintGraphWindow(); |
| 49 | |
| 50 | return gtl; |
| 51 | } |
| 52 | // option '1' to save GraphBuffer any other to restore |
| 53 | void save_restoreGB(uint8_t saveOpt) |
| 54 | { |
| 55 | static int SavedGB[MAX_GRAPH_TRACE_LEN]; |
| 56 | static int SavedGBlen=0; |
| 57 | static bool GB_Saved = false; |
| 58 | static int SavedGridOffsetAdj=0; |
| 59 | |
| 60 | if (saveOpt == GRAPH_SAVE) { //save |
| 61 | memcpy(SavedGB, GraphBuffer, sizeof(GraphBuffer)); |
| 62 | SavedGBlen = GraphTraceLen; |
| 63 | GB_Saved=true; |
| 64 | SavedGridOffsetAdj = GridOffset; |
| 65 | } else if (GB_Saved) { //restore |
| 66 | memcpy(GraphBuffer, SavedGB, sizeof(GraphBuffer)); |
| 67 | GraphTraceLen = SavedGBlen; |
| 68 | GridOffset = SavedGridOffsetAdj; |
| 69 | RepaintGraphWindow(); |
| 70 | } |
| 71 | return; |
| 72 | } |
| 73 | |
| 74 | // DETECT CLOCK NOW IN LFDEMOD.C |
| 75 | |
| 76 | void setGraphBuf(uint8_t *buff, size_t size) |
| 77 | { |
| 78 | if ( buff == NULL ) return; |
| 79 | |
| 80 | uint16_t i = 0; |
| 81 | if ( size > MAX_GRAPH_TRACE_LEN ) |
| 82 | size = MAX_GRAPH_TRACE_LEN; |
| 83 | ClearGraph(0); |
| 84 | for (; i < size; ++i){ |
| 85 | GraphBuffer[i]=buff[i]-128; |
| 86 | } |
| 87 | GraphTraceLen=size; |
| 88 | RepaintGraphWindow(); |
| 89 | return; |
| 90 | } |
| 91 | size_t getFromGraphBuf(uint8_t *buff) |
| 92 | { |
| 93 | if (buff == NULL ) return 0; |
| 94 | uint32_t i; |
| 95 | for (i=0;i<GraphTraceLen;++i){ |
| 96 | if (GraphBuffer[i]>127) GraphBuffer[i]=127; //trim |
| 97 | if (GraphBuffer[i]<-127) GraphBuffer[i]=-127; //trim |
| 98 | buff[i]=(uint8_t)(GraphBuffer[i]+128); |
| 99 | } |
| 100 | return i; |
| 101 | } |
| 102 | |
| 103 | // A simple test to see if there is any data inside Graphbuffer. |
| 104 | bool HasGraphData(){ |
| 105 | |
| 106 | if ( GraphTraceLen <= 0) { |
| 107 | PrintAndLog("No data available, try reading something first"); |
| 108 | return false; |
| 109 | } |
| 110 | return true; |
| 111 | } |
| 112 | |
| 113 | // Detect high and lows in Grapbuffer. |
| 114 | // Only loops the first 256 values. |
| 115 | void DetectHighLowInGraph(int *high, int *low, bool addFuzz) { |
| 116 | |
| 117 | uint8_t loopMax = 255; |
| 118 | if ( loopMax > GraphTraceLen) |
| 119 | loopMax = GraphTraceLen; |
| 120 | |
| 121 | for (uint8_t i = 0; i < loopMax; ++i) { |
| 122 | if (GraphBuffer[i] > *high) |
| 123 | *high = GraphBuffer[i]; |
| 124 | else if (GraphBuffer[i] < *low) |
| 125 | *low = GraphBuffer[i]; |
| 126 | } |
| 127 | |
| 128 | //12% fuzz in case highs and lows aren't clipped |
| 129 | if (addFuzz) { |
| 130 | *high = (int)(*high * .88); |
| 131 | *low = (int)(*low * .88); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // Get or auto-detect ask clock rate |
| 136 | int GetAskClock(const char str[], bool printAns, bool verbose) |
| 137 | { |
| 138 | int clock; |
| 139 | sscanf(str, "%i", &clock); |
| 140 | if (!strcmp(str, "")) |
| 141 | clock = 0; |
| 142 | |
| 143 | if (clock != 0) |
| 144 | return clock; |
| 145 | // Auto-detect clock |
| 146 | uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; |
| 147 | size_t size = getFromGraphBuf(grph); |
| 148 | if (size == 0) { |
| 149 | if (verbose) |
| 150 | PrintAndLog("Failed to copy from graphbuffer"); |
| 151 | return -1; |
| 152 | } |
| 153 | //, size_t *ststart, size_t *stend |
| 154 | size_t ststart = 0, stend = 0; |
| 155 | bool st = DetectST(grph, &size, &clock, &ststart, &stend); |
| 156 | int start = stend; |
| 157 | if (st == false) { |
| 158 | start = DetectASKClock(grph, size, &clock, 20); |
| 159 | } |
| 160 | setClockGrid(clock, start); |
| 161 | // Only print this message if we're not looping something |
| 162 | if (printAns || g_debugMode) { |
| 163 | PrintAndLog("Auto-detected clock rate: %d, Best Starting Position: %d", clock, start); |
| 164 | } |
| 165 | return clock; |
| 166 | } |
| 167 | |
| 168 | uint8_t GetPskCarrier(const char str[], bool printAns, bool verbose) |
| 169 | { |
| 170 | uint8_t carrier=0; |
| 171 | uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; |
| 172 | size_t size = getFromGraphBuf(grph); |
| 173 | if ( size == 0 ) { |
| 174 | if (verbose) |
| 175 | PrintAndLog("Failed to copy from graphbuffer"); |
| 176 | return 0; |
| 177 | } |
| 178 | uint16_t fc = countFC(grph,size,0); |
| 179 | carrier = fc & 0xFF; |
| 180 | if (carrier != 2 && carrier != 4 && carrier != 8) return 0; |
| 181 | if ((fc>>8) == 10 && carrier == 8) return 0; |
| 182 | // Only print this message if we're not looping something |
| 183 | if (printAns) { |
| 184 | PrintAndLog("Auto-detected PSK carrier rate: %d", carrier); |
| 185 | } |
| 186 | return carrier; |
| 187 | } |
| 188 | |
| 189 | int GetPskClock(const char str[], bool printAns, bool verbose) |
| 190 | { |
| 191 | int clock; |
| 192 | sscanf(str, "%i", &clock); |
| 193 | if (!strcmp(str, "")) |
| 194 | clock = 0; |
| 195 | |
| 196 | if (clock!=0) |
| 197 | return clock; |
| 198 | // Auto-detect clock |
| 199 | uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; |
| 200 | size_t size = getFromGraphBuf(grph); |
| 201 | if ( size == 0 ) { |
| 202 | if (verbose) |
| 203 | PrintAndLog("Failed to copy from graphbuffer"); |
| 204 | return -1; |
| 205 | } |
| 206 | size_t firstPhaseShiftLoc = 0; |
| 207 | uint8_t curPhase = 0, fc = 0; |
| 208 | clock = DetectPSKClock(grph, size, 0, &firstPhaseShiftLoc, &curPhase, &fc); |
| 209 | setClockGrid(clock, firstPhaseShiftLoc); |
| 210 | // Only print this message if we're not looping something |
| 211 | if (printAns){ |
| 212 | PrintAndLog("Auto-detected clock rate: %d", clock); |
| 213 | } |
| 214 | return clock; |
| 215 | } |
| 216 | |
| 217 | uint8_t GetNrzClock(const char str[], bool printAns, bool verbose) |
| 218 | { |
| 219 | int clock; |
| 220 | sscanf(str, "%i", &clock); |
| 221 | if (!strcmp(str, "")) |
| 222 | clock = 0; |
| 223 | |
| 224 | if (clock!=0) |
| 225 | return clock; |
| 226 | // Auto-detect clock |
| 227 | uint8_t grph[MAX_GRAPH_TRACE_LEN]={0}; |
| 228 | size_t size = getFromGraphBuf(grph); |
| 229 | if ( size == 0 ) { |
| 230 | if (verbose) |
| 231 | PrintAndLog("Failed to copy from graphbuffer"); |
| 232 | return -1; |
| 233 | } |
| 234 | size_t clkStartIdx = 0; |
| 235 | clock = DetectNRZClock(grph, size, 0, &clkStartIdx); |
| 236 | setClockGrid(clock, clkStartIdx); |
| 237 | // Only print this message if we're not looping something |
| 238 | if (printAns){ |
| 239 | PrintAndLog("Auto-detected clock rate: %d", clock); |
| 240 | } |
| 241 | return clock; |
| 242 | } |
| 243 | //by marshmellow |
| 244 | //attempt to detect the field clock and bit clock for FSK |
| 245 | uint8_t GetFskClock(const char str[], bool printAns, bool verbose) |
| 246 | { |
| 247 | int clock; |
| 248 | sscanf(str, "%i", &clock); |
| 249 | if (!strcmp(str, "")) |
| 250 | clock = 0; |
| 251 | if (clock != 0) return (uint8_t)clock; |
| 252 | |
| 253 | |
| 254 | uint8_t fc1=0, fc2=0, rf1=0; |
| 255 | int firstClockEdge = 0; |
| 256 | uint8_t ans = fskClocks(&fc1, &fc2, &rf1, verbose, &firstClockEdge); |
| 257 | if (ans == 0) return 0; |
| 258 | if ((fc1==10 && fc2==8) || (fc1==8 && fc2==5)){ |
| 259 | if (printAns) PrintAndLog("Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1); |
| 260 | setClockGrid(rf1, firstClockEdge); |
| 261 | return rf1; |
| 262 | } |
| 263 | if (verbose){ |
| 264 | PrintAndLog("DEBUG: unknown fsk field clock detected"); |
| 265 | PrintAndLog("Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1); |
| 266 | } |
| 267 | return 0; |
| 268 | } |
| 269 | uint8_t fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, bool verbose, int *firstClockEdge) |
| 270 | { |
| 271 | uint8_t BitStream[MAX_GRAPH_TRACE_LEN]={0}; |
| 272 | size_t size = getFromGraphBuf(BitStream); |
| 273 | if (size==0) return 0; |
| 274 | uint16_t ans = countFC(BitStream, size, 1); |
| 275 | if (ans==0) { |
| 276 | if (verbose || g_debugMode) PrintAndLog("DEBUG: No data found"); |
| 277 | return 0; |
| 278 | } |
| 279 | *fc1 = (ans >> 8) & 0xFF; |
| 280 | *fc2 = ans & 0xFF; |
| 281 | //int firstClockEdge = 0; |
| 282 | *rf1 = detectFSKClk(BitStream, size, *fc1, *fc2, firstClockEdge); |
| 283 | if (*rf1==0) { |
| 284 | if (verbose || g_debugMode) PrintAndLog("DEBUG: Clock detect error"); |
| 285 | return 0; |
| 286 | } |
| 287 | return 1; |
| 288 | } |
| 289 | bool graphJustNoise(int *BitStream, int size) |
| 290 | { |
| 291 | static const uint8_t THRESHOLD = 15; //might not be high enough for noisy environments |
| 292 | //test samples are not just noise |
| 293 | bool justNoise1 = 1; |
| 294 | for(int idx=0; idx < size && justNoise1 ;idx++){ |
| 295 | justNoise1 = BitStream[idx] < THRESHOLD; |
| 296 | } |
| 297 | return justNoise1; |
| 298 | } |