add fsk cleaning / demod tool fsktonrz

used old fskdemod for HID and adjusted it to build the tone tables for
any fsk model detected or given.  using the tone tables we are able to
convert the fsk to clear strong NRZ/ASK even with very weak fsk waves.

also fixed a small textual bug in `lf search u` output

also added more graph clearing code to help ensure the demod overlay
doesn't show when it shouldn't...

and improved strong NRZ clock detection.
This commit is contained in:
marshmellow42 2017-06-26 22:49:46 -04:00
commit b03a05d67e
4 changed files with 214 additions and 7 deletions

View file

@ -1234,6 +1234,7 @@ int getSamples(int n, bool silent)
} }
setClockGrid(0,0); setClockGrid(0,0);
DemodBufferLen = 0;
RepaintGraphWindow(); RepaintGraphWindow();
return 0; return 0;
} }
@ -1338,6 +1339,7 @@ int CmdLoad(const char *Cmd)
fclose(f); fclose(f);
PrintAndLog("loaded %d samples", GraphTraceLen); PrintAndLog("loaded %d samples", GraphTraceLen);
setClockGrid(0,0); setClockGrid(0,0);
DemodBufferLen = 0;
RepaintGraphWindow(); RepaintGraphWindow();
return 0; return 0;
} }
@ -1395,8 +1397,7 @@ int CmdNorm(const char *Cmd)
if (max != min) { if (max != min) {
for (i = 0; i < GraphTraceLen; ++i) { for (i = 0; i < GraphTraceLen; ++i) {
GraphBuffer[i] = (GraphBuffer[i] - ((max + min) / 2)) * 256 / GraphBuffer[i] = ((long)(GraphBuffer[i] - ((max + min) / 2)) * 256) / (max - min);
(max - min);
//marshmelow: adjusted *1000 to *256 to make +/- 128 so demod commands still work //marshmelow: adjusted *1000 to *256 to make +/- 128 so demod commands still work
} }
} }
@ -1606,6 +1607,197 @@ int Cmdhex2bin(const char *Cmd)
return 0; return 0;
} }
/*
static const int LowTone[] = {
1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
1, 1, 1, 1, 1, -1, -1, -1, -1, -1
};
static const int HighTone[] = {
1, 1, 1, 1, 1, -1, -1, -1, -1,
1, 1, 1, 1, -1, -1, -1, -1,
1, 1, 1, 1, -1, -1, -1, -1,
1, 1, 1, 1, -1, -1, -1, -1,
1, 1, 1, 1, -1, -1, -1, -1,
1, 1, 1, 1, -1, -1, -1, -1, -1,
};
*/
void GetHiLoTone(int *LowTone, int *HighTone, int clk, int LowToneFC, int HighToneFC) {
int i,j=0;
int Left_Modifier = ((clk % LowToneFC) % 2) + ((clk % LowToneFC)/2);
int Right_Modifier = (clk % LowToneFC) / 2;
//int HighToneMod = clk mod HighToneFC;
int LeftHalfFCCnt = (LowToneFC % 2) + (LowToneFC/2); //truncate
int FCs_per_clk = clk/LowToneFC;
// need to correctly split up the clock to field clocks.
// First attempt uses modifiers on each end to make up for when FCs don't evenly divide into Clk
// start with LowTone
// set extra 1 modifiers to make up for when FC doesn't divide evenly into Clk
for (i = 0; i < Left_Modifier; i++) {
LowTone[i] = 1;
}
// loop # of field clocks inside the main clock
for (i = 0; i < (FCs_per_clk); i++) {
// loop # of samples per field clock
for (j = 0; j < LowToneFC; j++) {
LowTone[(i*LowToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1;
}
}
int k;
// add last -1 modifiers
for (k = 0; k < Right_Modifier; k++) {
LowTone[((i-1)*LowToneFC)+Left_Modifier+j+k] = -1;
}
// now do hightone
Left_Modifier = ((clk % HighToneFC) % 2) + ((clk % HighToneFC)/2);
Right_Modifier = (clk % HighToneFC) / 2;
LeftHalfFCCnt = (HighToneFC % 2) + (HighToneFC/2); //truncate
FCs_per_clk = clk/HighToneFC;
for (i = 0; i < Left_Modifier; i++) {
HighTone[i] = 1;
}
// loop # of field clocks inside the main clock
for (i = 0; i < (FCs_per_clk); i++) {
// loop # of samples per field clock
for (j = 0; j < HighToneFC; j++) {
HighTone[(i*HighToneFC)+Left_Modifier+j] = ( j < LeftHalfFCCnt ) ? 1 : -1;
}
}
// add last -1 modifiers
for (k = 0; k < Right_Modifier; k++) {
PrintAndLog("(i-1)*HighToneFC+lm+j+k %i",((i-1)*HighToneFC)+Left_Modifier+j+k);
HighTone[((i-1)*HighToneFC)+Left_Modifier+j+k] = -1;
}
if (g_debugMode == 2) {
for ( i = 0; i < clk; i++) {
PrintAndLog("Low: %i, High: %i",LowTone[i],HighTone[i]);
}
}
}
//old CmdFSKdemod adapted by marshmellow
//converts FSK to clear NRZ style wave. (or demodulates)
int FSKClean(int *data, int *dataLen, int clk, int LowToneFC, int HighToneFC) {
if (clk == 0 || LowToneFC == 0 || HighToneFC == 0) {
int firstClockEdge=0;
uint8_t ans = fskClocks((uint8_t *) &LowToneFC, (uint8_t *) &HighToneFC, (uint8_t *) &clk, false, &firstClockEdge);
if (ans == 0) {
return 0;
}
}
int LowTone[clk];
int HighTone[clk];
// int LowToneFC = 10; // TODO allow args to set this
// int HighToneFC = 8; // TODO allow args to set this
GetHiLoTone(LowTone, HighTone, clk, LowToneFC, HighToneFC);
int lowLen = sizeof(LowTone) / sizeof(int);
int highLen = sizeof(HighTone) / sizeof(int);
int convLen = (highLen > lowLen) ? highLen : lowLen;
int i, j;
int minMark = 0, maxMark = 0;
for (i = 0; i < *dataLen - convLen; ++i) {
int lowSum = 0, highSum = 0;
for (j = 0; j < lowLen; ++j) {
lowSum += LowTone[j] * data[i+j];
}
for (j = 0; j < highLen; ++j) {
highSum += HighTone[j] * data[i + j];
}
lowSum = abs(100 * lowSum / lowLen);
highSum = abs(100 * highSum / highLen);
data[i] = (highSum << 16) | lowSum;
}
for(i = 0; i < *dataLen - convLen - 16; ++i) {
int lowTot = 0, highTot = 0;
// 10 and 8 are fc_s divided by fc_l and fc_h, rounded
for (j = 0; j < 10; ++j) {
lowTot += (data[i+j] & 0xffff);
}
for (j = 0; j < 8; j++) {
highTot += (data[i + j] >> 16);
}
data[i] = lowTot - highTot;
if (data[i] > maxMark) maxMark = data[i];
if (data[i] < minMark) minMark = data[i];
}
*dataLen -= (convLen + 16);
return 0;
}
int usage_data_fsktonrz() {
PrintAndLog("Usage: data fsktonrz c <clock> l <fc_low> f <fc_high>");
PrintAndLog("Options: ");
PrintAndLog(" h This help");
PrintAndLog(" c <clock> enter the a clock (omit to autodetect)");
PrintAndLog(" l <fc_low> enter a field clock (omit to autodetect)");
PrintAndLog(" f <fc_high> enter a field clock (omit to autodetect)");
return 0;
}
int CmdFSKClean(const char *Cmd) {
// take clk, fc_low, fc_high
// blank = auto;
bool errors = false;
int clk = 0;
char cmdp = 0;
int fc_low = 10, fc_high = 8;
while(param_getchar(Cmd, cmdp) != 0x00)
{
switch(param_getchar(Cmd, cmdp))
{
case 'h':
case 'H':
return usage_data_fsktonrz();
case 'C':
case 'c':
clk = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
case 'F':
case 'f':
fc_high = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
case 'L':
case 'l':
fc_low = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
if(errors) break;
}
//Validations
if(errors) return usage_data_fsktonrz();
setClockGrid(0,0);
DemodBufferLen = 0;
int ans = FSKClean(GraphBuffer, &GraphTraceLen, clk, fc_low, fc_high);
CmdNorm("");
RepaintGraphWindow();
return ans;
}
static command_t CommandTable[] = static command_t CommandTable[] =
{ {
{"help", CmdHelp, 1, "This help"}, {"help", CmdHelp, 1, "This help"},
@ -1617,6 +1809,7 @@ static command_t CommandTable[] =
{"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"},
{"dec", CmdDec, 1, "Decimate samples"}, {"dec", CmdDec, 1, "Decimate samples"},
{"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"}, {"detectclock", CmdDetectClockRate, 1, "[modulation] Detect clock rate of wave in GraphBuffer (options: 'a','f','n','p' for ask, fsk, nrz, psk respectively)"},
{"fsktonrz", CmdFSKClean, 1, "Convert fsk2 to nrz wave for alternate demodulating"},
{"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, {"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
{"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"}, {"grid", CmdGrid, 1, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
{"hexsamples", CmdHexsamples, 0, "<bytes> [<offset>] -- Dump big buffer as hex bytes"}, {"hexsamples", CmdHexsamples, 0, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},

View file

@ -1081,7 +1081,7 @@ int CmdLFfind(const char *Cmd)
if (ans>0) { if (ans>0) {
PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'"); PrintAndLog("Possible unknown PSK1 Modulated Tag Found above!\n\nCould also be PSK2 - try 'data rawdemod p2'");
PrintAndLog("\nCould also be PSK3 - [currently not supported]"); PrintAndLog("\nCould also be PSK3 - [currently not supported]");
PrintAndLog("\nCould also be NRZ - try 'data nrzrawdemod'"); PrintAndLog("\nCould also be NRZ - try 'data rawdemod nr'");
return CheckChipType(cmdp); return CheckChipType(cmdp);
} }
ans = CheckChipType(cmdp); ans = CheckChipType(cmdp);

View file

@ -96,8 +96,12 @@ int CmdIndalaDemod(const char *Cmd) {
uint8_t rawbits[4096]; uint8_t rawbits[4096];
int rawbit = 0; int rawbit = 0;
int worst = 0, worstPos = 0; int worst = 0, worstPos = 0;
// PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
//clear clock grid and demod plot
setClockGrid(0, 0);
DemodBufferLen = 0;
// PrintAndLog("Expecting a bit less than %d raw bits", GraphTraceLen / 32);
// loop through raw signal - since we know it is psk1 rf/32 fc/2 skip every other value (+=2) // loop through raw signal - since we know it is psk1 rf/32 fc/2 skip every other value (+=2)
for (i = 0; i < GraphTraceLen-1; i += 2) { for (i = 0; i < GraphTraceLen-1; i += 2) {
count += 1; count += 1;

View file

@ -505,13 +505,14 @@ int DetectASKClock(uint8_t dest[], size_t size, int *clock, int maxErr) {
return bestStart[best]; return bestStart[best];
} }
int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){ int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low, bool *strong) {
//find shortest transition from high to low //find shortest transition from high to low
*strong = false;
size_t i = 0; size_t i = 0;
size_t transition1 = 0; size_t transition1 = 0;
int lowestTransition = 255; int lowestTransition = 255;
bool lastWasHigh = false; bool lastWasHigh = false;
size_t transitionSampleCount = 0;
//find first valid beginning of a high or low wave //find first valid beginning of a high or low wave
while ((dest[i] >= peak || dest[i] <= low) && (i < size)) while ((dest[i] >= peak || dest[i] <= low) && (i < size))
++i; ++i;
@ -527,10 +528,17 @@ int DetectStrongNRZClk(uint8_t *dest, size_t size, int peak, int low){
lastWasHigh = (dest[i] >= peak); lastWasHigh = (dest[i] >= peak);
if (i-transition1 < lowestTransition) lowestTransition = i-transition1; if (i-transition1 < lowestTransition) lowestTransition = i-transition1;
transition1 = i; transition1 = i;
} else if (dest[i] < peak && dest[i] > low) {
transitionSampleCount++;
} }
} }
if (lowestTransition == 255) lowestTransition = 0; if (lowestTransition == 255) lowestTransition = 0;
if (g_debugMode==2) prnt("DEBUG NRZ: detectstrongNRZclk smallest wave: %d",lowestTransition); if (g_debugMode==2) prnt("DEBUG NRZ: detectstrongNRZclk smallest wave: %d",lowestTransition);
// if less than 10% of the samples were not peaks (or 90% were peaks) then we have a strong wave
if (transitionSampleCount / size < 10) {
*strong = true;
lowestTransition = getClosestClock(lowestTransition);
}
return lowestTransition; return lowestTransition;
} }
@ -550,7 +558,9 @@ int DetectNRZClock(uint8_t dest[], size_t size, int clock, size_t *clockStartIdx
int peak, low; int peak, low;
if (getHiLo(dest, loopCnt, &peak, &low, 90, 90) < 1) return 0; if (getHiLo(dest, loopCnt, &peak, &low, 90, 90) < 1) return 0;
int lowestTransition = DetectStrongNRZClk(dest, size-20, peak, low); bool strong = false;
int lowestTransition = DetectStrongNRZClk(dest, size-20, peak, low, &strong);
if (strong) return lowestTransition;
size_t ii; size_t ii;
uint8_t clkCnt; uint8_t clkCnt;
uint8_t tol = 0; uint8_t tol = 0;