//-----------------------------------------------------------------------------
#include <stdlib.h>
-#include <string.h>
#include "lfdemod.h"
-#include "common.h"
+#include <string.h>
//un_comment to allow debug print calls when used not on device
void dummy(char *fmt, ...){}
//by marshmellow
// takes a array of binary values, start position, length of bits per parity (includes parity bit),
-// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run)
+// Parity Type (1 for odd; 0 for even; 2 for Always 1's; 3 for Always 0's), and binary Length (length to run)
size_t removeParity(uint8_t *BitStream, size_t startIdx, uint8_t pLen, uint8_t pType, size_t bLen)
{
uint32_t parityWd = 0;
}
j--; // overwrite parity with next data
// if parity fails then return 0
- if (pType == 2) { // then marker bit which should be a 1
- if (!BitStream[j]) return 0;
- } else {
- if (parityTest(parityWd, pLen, pType) == 0) return 0;
+ switch (pType) {
+ case 3: if (BitStream[j]==1) { return 0; } break; //should be 0 spacer bit
+ case 2: if (BitStream[j]==0) { return 0; } break; //should be 1 spacer bit
+ default: if (parityTest(parityWd, pLen, pType) == 0) { return 0; } break; //test parity
}
bitCnt+=(pLen-1);
parityWd = 0;
// by marshmellow
// takes a array of binary values, length of bits per parity (includes parity bit),
-// Parity Type (1 for odd; 0 for even; 2 Always 1's), and binary Length (length to run)
+// Parity Type (1 for odd; 0 for even; 2 Always 1's; 3 Always 0's), and binary Length (length to run)
+// Make sure *dest is long enough to store original sourceLen + #_of_parities_to_be_added
size_t addParity(uint8_t *BitSource, uint8_t *dest, uint8_t sourceLen, uint8_t pLen, uint8_t pType)
{
uint32_t parityWd = 0;
parityWd = (parityWd << 1) | BitSource[word+bit];
dest[j++] = (BitSource[word+bit]);
}
+
// if parity fails then return 0
- if (pType == 2) { // then marker bit which should be a 1
- dest[j++]=1;
- } else {
- dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1;
+ switch (pType) {
+ case 3: dest[j++]=0; break; // marker bit which should be a 0
+ case 2: dest[j++]=1; break; // marker bit which should be a 1
+ default:
+ dest[j++] = parityTest(parityWd, pLen-1, pType) ^ 1;
+ break;
}
bitCnt += pLen;
parityWd = 0;
uint32_t bytebits_to_byte(uint8_t *src, size_t numbits)
{
uint32_t num = 0;
- for(int i = 0 ; i < numbits ; i++)
- {
+ for(int i = 0 ; i < numbits ; i++) {
num = (num << 1) | (*src);
src++;
}
uint32_t bytebits_to_byteLSBF(uint8_t *src, size_t numbits)
{
uint32_t num = 0;
- for(int i = 0 ; i < numbits ; i++)
- {
+ for(int i = 0 ; i < numbits ; i++) {
num = (num << 1) | *(src + (numbits-(i+1)));
}
return num;
//search for given preamble in given BitStream and return success=1 or fail=0 and startIndex and length
uint8_t preambleSearch(uint8_t *BitStream, uint8_t *preamble, size_t pLen, size_t *size, size_t *startIdx)
{
- uint8_t foundCnt=0;
- for (int idx=0; idx < *size - pLen; idx++){
+ // Sanity check. If preamble length is bigger than bitstream length.
+ if ( *size <= pLen ) return 0;
+
+ uint8_t foundCnt = 0;
+ for (int idx = 0; idx < *size - pLen; idx++){
if (memcmp(BitStream+idx, preamble, pLen) == 0){
//first index found
foundCnt++;
if (smplCnt > clk-(clk/4)-1) { //full clock
if (smplCnt > clk + (clk/4)+1) { //too many samples
errCnt++;
+ if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i);
BinStream[bitCnt++]=7;
} else if (waveHigh) {
BinStream[bitCnt++] = invert;
//by marshmellow
void askAmp(uint8_t *BitStream, size_t size)
{
- for(size_t i = 1; i<size; i++){
- if (BitStream[i]-BitStream[i-1]>=30) //large jump up
- BitStream[i]=127;
- else if(BitStream[i]-BitStream[i-1]<=-20) //large jump down
- BitStream[i]=-127;
+ uint8_t last = 128;
+ for(size_t i = 1; i < size; ++i){
+ if (BitStream[i]-BitStream[i-1] >= 30) //large jump up
+ last = 255;
+ else if(BitStream[i-1] - BitStream[i] >= 20) //large jump down
+ last = 0;
+
+ BitStream[i] = last;
}
- return;
}
//by marshmellow
if (*clk==0 || start < 0) return -3;
if (*invert != 1) *invert = 0;
if (amp==1) askAmp(BinStream, *size);
- if (g_debugMode==2) prnt("DEBUG: clk %d, beststart %d", *clk, start);
+ if (g_debugMode==2) prnt("DEBUG ASK: clk %d, beststart %d", *clk, start);
uint8_t initLoopMax = 255;
if (initLoopMax > *size) initLoopMax = *size;
size_t errCnt = 0;
// if clean clipped waves detected run alternate demod
if (DetectCleanAskWave(BinStream, *size, high, low)) {
- if (g_debugMode==2) prnt("DEBUG: Clean Wave Detected");
+ if (g_debugMode==2) prnt("DEBUG ASK: Clean Wave Detected - using clean wave demod");
errCnt = cleanAskRawDemod(BinStream, size, *clk, *invert, high, low);
if (askType) //askman
return manrawdecode(BinStream, size, 0);
else //askraw
return errCnt;
}
+ if (g_debugMode==2) prnt("DEBUG ASK: Weak Wave Detected - using weak wave demod");
int lastBit; //set first clock check - can go negative
size_t i, bitnum = 0; //output counter
uint8_t midBit = 0;
uint8_t tol = 0; //clock tolerance adjust - waves will be accepted as within the clock if they fall + or - this value + clock from last valid wave
if (*clk <= 32) tol = 1; //clock tolerance may not be needed anymore currently set to + or - 1 but could be increased for poor waves or removed entirely
- size_t MaxBits = 1024;
+ size_t MaxBits = 3072; //max bits to collect
lastBit = start - *clk;
for (i = start; i < *size; ++i) {
BinStream[bitnum++] = *invert ^ 1;
} else if (i-lastBit >= *clk+tol) {
if (bitnum > 0) {
+ if (g_debugMode==2) prnt("DEBUG ASK: Modulation Error at: %u", i);
BinStream[bitnum++]=7;
errCnt++;
}
//return start position
return (int) startIdx;
}
- return -5;
+ return -5; //spacer bits not found - not a valid gproxII
}
-//translate wave to 11111100000 (1 for each short wave 0 for each long wave)
+//translate wave to 11111100000 (1 for each short wave [higher freq] 0 for each long wave [lower freq])
size_t fsk_wave_demod(uint8_t * dest, size_t size, uint8_t fchigh, uint8_t fclow)
{
size_t last_transition = 0;
size_t numBits = 0;
// count cycles between consecutive lo-hi transitions, there should be either 8 (fc/8)
- // or 10 (fc/10) cycles but in practice due to noise etc we may end up with with anywhere
+ // or 10 (fc/10) cycles but in practice due to noise etc we may end up with anywhere
// between 7 to 11 cycles so fuzz it by treat anything <9 as 8 and anything else as 10
+ // (could also be fc/5 && fc/7 for fsk1 = 4-9)
for(idx = 161; idx < size-20; idx++) {
// threshold current value
else dest[idx] = 1;
// Check for 0->1 transition
- if (dest[idx-1] < dest[idx]) { // 0 -> 1 transition
+ if (dest[idx-1] < dest[idx]) {
preLastSample = LastSample;
LastSample = currSample;
currSample = idx-last_transition;
if (currSample < (fclow-2)){ //0-5 = garbage noise (or 0-3)
//do nothing with extra garbage
- } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves or 3-6 = 5
+ } else if (currSample < (fchigh-1)) { //6-8 = 8 sample waves (or 3-6 = 5)
+ //correct previous 9 wave surrounded by 8 waves (or 6 surrounded by 5)
if (LastSample > (fchigh-2) && (preLastSample < (fchigh-1) || preLastSample == 0 )){
- dest[numBits-1]=1; //correct previous 9 wave surrounded by 8 waves
+ dest[numBits-1]=1;
}
dest[numBits++]=1;
- } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = garbage
+ } else if (currSample > (fchigh) && !numBits) { //12 + and first bit = unusable garbage
//do nothing with beginning garbage
- } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's
+ } else if (currSample == (fclow+1) && LastSample == (fclow-1)) { // had a 7 then a 9 should be two 8's (or 4 then a 6 should be two 5's)
dest[numBits++]=1;
- } else { //9+ = 10 sample waves
+ } else { //9+ = 10 sample waves (or 6+ = 7)
dest[numBits++]=0;
}
last_transition = idx;
}
//translate 11111100000 to 10
+//rfLen = clock, fchigh = larger field clock, fclow = smaller field clock
size_t aggregate_bits(uint8_t *dest, size_t size, uint8_t rfLen,
uint8_t invert, uint8_t fchigh, uint8_t fclow)
{
n++;
if (dest[idx]==lastval) continue;
+ //find out how many bits (n) we collected
//if lastval was 1, we have a 1->0 crossing
if (dest[idx-1]==1) {
n = (n * fclow + rfLen/2) / rfLen;
}
if (n == 0) n = 1;
+ //add to our destination the bits we collected
memset(dest+numBits, dest[idx-1]^invert , n);
numBits += n;
n=0;
{
if (justNoise(dest, *size)) return -1;
- size_t numStart=0, size2=*size, startIdx=0;
+ size_t numStart=0, size2 = *size, startIdx=0;
// FSK demodulator
*size = fskdemod(dest, size2,50,1,10,8); //fsk2a
if (*size < 96*2) return -2;
{
if (justNoise(dest, *size)) return -1;
- size_t numStart=0, size2=*size, startIdx=0;
+ size_t numStart=0, size2 = *size, startIdx=0;
// FSK demodulator
*size = fskdemod(dest, size2,50,1,10,8); //fsk2a
if (*size < 96) return -2;
uint8_t preamble[] = {1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx);
if (errChk == 0) return -4; //preamble not found
- uint32_t checkCalc = bytebits_to_byte(dest+startIdx,8) ^ bytebits_to_byte(dest+startIdx+8,8) ^ bytebits_to_byte(dest+startIdx+16,8)
- ^ bytebits_to_byte(dest+startIdx+24,8) ^ bytebits_to_byte(dest+startIdx+32,8) ^ bytebits_to_byte(dest+startIdx+40,8)
- ^ bytebits_to_byte(dest+startIdx+48,8) ^ bytebits_to_byte(dest+startIdx+56,8);
- if ( checkCalc != 0xA8 ) return -5;
+ uint32_t checkCalc = bytebits_to_byte(dest+startIdx,8) ^
+ bytebits_to_byte(dest+startIdx+8,8) ^
+ bytebits_to_byte(dest+startIdx+16,8) ^
+ bytebits_to_byte(dest+startIdx+24,8) ^
+ bytebits_to_byte(dest+startIdx+32,8) ^
+ bytebits_to_byte(dest+startIdx+40,8) ^
+ bytebits_to_byte(dest+startIdx+48,8) ^
+ bytebits_to_byte(dest+startIdx+56,8);
+ if ( checkCalc != 0xA8 ) return -5;
if (*size != 64) return -6;
//return start position
return (int) startIdx;
}
+// find presco preamble 0x10D in already demoded data
+int PrescoDemod(uint8_t *dest, size_t *size) {
+ //make sure buffer has data
+ if (*size < 64*2) return -2;
+
+ size_t startIdx = 0;
+ uint8_t preamble[] = {1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0};
+ uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx);
+ if (errChk == 0) return -4; //preamble not found
+ //return start position
+ return (int) startIdx;
+}
+
// Ask/Biphase Demod then try to locate an ISO 11784/85 ID
// BitStream must contain previously askrawdemod and biphasedemoded data
int FDXBdemodBI(uint8_t *dest, size_t *size)
return (int)startIdx;
}
+// ASK/Diphase fc/64 (inverted Biphase)
+// Note: this i s not a demod, this is only a detection
+// the parameter *dest needs to be demoded before call
+int JablotronDemod(uint8_t *dest, size_t *size){
+ //make sure buffer has enough data
+ if (*size < 64) return -1;
+
+ size_t startIdx = 0;
+ // 0xFFFF preamble, 64bits
+ uint8_t preamble[] = {
+ 1,1,1,1,
+ 1,1,1,1,
+ 1,1,1,1,
+ 1,1,1,1,
+ 0
+ };
+
+ uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx);
+ if (errChk == 0) return -4; //preamble not found
+ if (*size != 64) return -3;
+
+ uint8_t checkchksum = 0;
+ for (int i=16; i < 56; i += 8) {
+ checkchksum += bytebits_to_byte(dest+startIdx+i,8);
+ }
+ checkchksum ^= 0x3A;
+
+ uint8_t crc = bytebits_to_byte(dest+startIdx+56, 8);
+
+ if ( checkchksum != crc ) return -5;
+ return (int)startIdx;
+}
+
// by marshmellow
// FSK Demod then try to locate an AWID ID
int AWIDdemodFSK(uint8_t *dest, size_t *size)
return (int)startIdx;
}
+// find nedap preamble in already demoded data
+int NedapDemod(uint8_t *dest, size_t *size) {
+ //make sure buffer has data
+ if (*size < 128) return -3;
+
+ size_t startIdx = 0;
+ //uint8_t preamble[] = {1,1,1,1,1,1,1,1,1,0,0,0,1};
+ uint8_t preamble[] = {1,1,1,1,1,1,1,1,1,0};
+ uint8_t errChk = preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx);
+ if (errChk == 0) return -4; //preamble not found
+ return (int) startIdx;
+}
+
// by marshmellow
// to detect a wave that has heavily clipped (clean) samples
uint8_t DetectCleanAskWave(uint8_t dest[], size_t size, uint8_t high, uint8_t low)
return (int) startidx;
}
-// by marshmellow - demodulate NRZ wave
+// by marshmellow - demodulate NRZ wave - requires a read with strong signal
// peaks invert bit (high=1 low=0) each clock cycle = 1 bit determined by last peak
int nrzRawDemod(uint8_t *dest, size_t *size, int *clk, int *invert){
if (justNoise(dest, *size)) return -1;
numBits += (firstFullWave / *clock);
//set start of wave as clock align
lastClkBit = firstFullWave;
- //PrintAndLog("DEBUG: firstFullWave: %d, waveLen: %d",firstFullWave,fullWaveLen);
- //PrintAndLog("DEBUG: clk: %d, lastClkBit: %d", *clock, lastClkBit);
+ if (g_debugMode==2) prnt("DEBUG PSK: firstFullWave: %u, waveLen: %u",firstFullWave,fullWaveLen);
+ if (g_debugMode==2) prnt("DEBUG: clk: %d, lastClkBit: %u, fc: %u", *clock, lastClkBit,(unsigned int) fc);
waveStart = 0;
dest[numBits++] = curPhase; //set first read bit
for (i = firstFullWave + fullWaveLen - 1; i < *size-3; i++){
*size = numBits;
return errCnt;
}
+
+//by marshmellow
+//attempt to identify a Sequence Terminator in ASK modulated raw wave
+bool DetectST(uint8_t buffer[], size_t *size, int *foundclock) {
+ size_t bufsize = *size;
+ //need to loop through all samples and identify our clock, look for the ST pattern
+ uint8_t fndClk[] = {8,16,32,40,50,64,128};
+ int clk = 0;
+ int tol = 0;
+ int i, j, skip, start, end, low, high, minClk, waveStart;
+ bool complete = false;
+ int tmpbuff[bufsize / 64];
+ int waveLen[bufsize / 64];
+ size_t testsize = (bufsize < 512) ? bufsize : 512;
+ int phaseoff = 0;
+ high = low = 128;
+ memset(tmpbuff, 0, sizeof(tmpbuff));
+
+ if ( getHiLo(buffer, testsize, &high, &low, 80, 80) == -1 ) {
+ if (g_debugMode==2) prnt("DEBUG STT: just noise detected - quitting");
+ return false; //just noise
+ }
+ i = 0;
+ j = 0;
+ minClk = 255;
+ // get to first full low to prime loop and skip incomplete first pulse
+ while ((buffer[i] < high) && (i < bufsize))
+ ++i;
+ while ((buffer[i] > low) && (i < bufsize))
+ ++i;
+ skip = i;
+
+ // populate tmpbuff buffer with pulse lengths
+ while (i < bufsize) {
+ // measure from low to low
+ while ((buffer[i] > low) && (i < bufsize))
+ ++i;
+ start= i;
+ while ((buffer[i] < high) && (i < bufsize))
+ ++i;
+ //first high point for this wave
+ waveStart = i;
+ while ((buffer[i] > low) && (i < bufsize))
+ ++i;
+ if (j >= (bufsize/64)) {
+ break;
+ }
+ waveLen[j] = i - waveStart; //first high to first low
+ tmpbuff[j++] = i - start;
+ if (i-start < minClk && i < bufsize) {
+ minClk = i - start;
+ }
+ }
+ // set clock - might be able to get this externally and remove this work...
+ if (!clk) {
+ for (uint8_t clkCnt = 0; clkCnt<7; clkCnt++) {
+ tol = fndClk[clkCnt]/8;
+ if (minClk >= fndClk[clkCnt]-tol && minClk <= fndClk[clkCnt]+1) {
+ clk=fndClk[clkCnt];
+ break;
+ }
+ }
+ // clock not found - ERROR
+ if (!clk) {
+ if (g_debugMode==2) prnt("DEBUG STT: clock not found - quitting");
+ return false;
+ }
+ } else tol = clk/8;
+
+ *foundclock = clk;
+
+ // look for Sequence Terminator - should be pulses of clk*(1 or 1.5), clk*2, clk*(1.5 or 2)
+ start = -1;
+ for (i = 0; i < j - 4; ++i) {
+ skip += tmpbuff[i];
+ if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol && waveLen[i] < clk+tol) { //1 to 2 clocks depending on 2 bits prior
+ if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol && waveLen[i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2
+ if (tmpbuff[i+2] >= (clk*3)/2-tol && tmpbuff[i+2] <= clk*2+tol && waveLen[i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave
+ if (tmpbuff[i+3] >= clk*1-tol && tmpbuff[i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit
+ start = i + 3;
+ break;
+ }
+ }
+ }
+ }
+ }
+ // first ST not found - ERROR
+ if (start < 0) {
+ if (g_debugMode==2) prnt("DEBUG STT: first STT not found - quitting");
+ return false;
+ }
+ if (waveLen[i+2] > clk*1+tol)
+ phaseoff = 0;
+ else
+ phaseoff = clk/2;
+
+ // skip over the remainder of ST
+ skip += clk*7/2; //3.5 clocks from tmpbuff[i] = end of st - also aligns for ending point
+
+ // now do it again to find the end
+ end = skip;
+ for (i += 3; i < j - 4; ++i) {
+ end += tmpbuff[i];
+ if (tmpbuff[i] >= clk*1-tol && tmpbuff[i] <= (clk*2)+tol) { //1 to 2 clocks depending on 2 bits prior
+ if (tmpbuff[i+1] >= clk*2-tol && tmpbuff[i+1] <= clk*2+tol && waveLen[i+1] > clk*3/2-tol) { //2 clocks and wave size is 1 1/2
+ if (tmpbuff[i+2] >= (clk*3)/2-tol && tmpbuff[i+2] <= clk*2+tol && waveLen[i+2] > clk-tol) { //1 1/2 to 2 clocks and at least one full clock wave
+ if (tmpbuff[i+3] >= clk*1-tol && tmpbuff[i+3] <= clk*2+tol) { //1 to 2 clocks for end of ST + first bit
+ complete = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ end -= phaseoff;
+ //didn't find second ST - ERROR
+ if (!complete) {
+ if (g_debugMode==2) prnt("DEBUG STT: second STT not found - quitting");
+ return false;
+ }
+ if (g_debugMode==2) prnt("DEBUG STT: start of data: %d end of data: %d, datalen: %d, clk: %d, bits: %d, phaseoff: %d", skip, end, end-skip, clk, (end-skip)/clk, phaseoff);
+ //now begin to trim out ST so we can use normal demod cmds
+ start = skip;
+ size_t datalen = end - start;
+ // check validity of datalen (should be even clock increments) - use a tolerance of up to 1/8th a clock
+ if (datalen % clk > clk/8) {
+ if (g_debugMode==2) prnt("DEBUG STT: datalen not divisible by clk: %u %% %d = %d - quitting", datalen, clk, datalen % clk);
+ return false;
+ } else {
+ // padd the amount off - could be problematic... but shouldn't happen often
+ datalen += datalen % clk;
+ }
+ // if datalen is less than one t55xx block - ERROR
+ if (datalen/clk < 8*4) {
+ if (g_debugMode==2) prnt("DEBUG STT: datalen is less than 1 full t55xx block - quitting");
+ return false;
+ }
+ size_t dataloc = start;
+ size_t newloc = 0;
+ i=0;
+ // warning - overwriting buffer given with raw wave data with ST removed...
+ while ( dataloc < bufsize-(clk/2) ) {
+ //compensate for long high at end of ST not being high due to signal loss... (and we cut out the start of wave high part)
+ if (buffer[dataloc]<high && buffer[dataloc]>low && buffer[dataloc+3]<high && buffer[dataloc+3]>low) {
+ for(i=0; i < clk/2-tol; ++i) {
+ buffer[dataloc+i] = high+5;
+ }
+ }
+ for (i=0; i<datalen; ++i) {
+ if (i+newloc < bufsize) {
+ if (i+newloc < dataloc)
+ buffer[i+newloc] = buffer[dataloc];
+
+ dataloc++;
+ }
+ }
+ newloc += i;
+ //skip next ST - we just assume it will be there from now on...
+ dataloc += clk*4;
+ }
+ *size = newloc;
+ return true;
+}