#include "protoLFSR.h"
#include "protoDebug.h"
#include <stdlib.h>
ProtoLFSR::ProtoLFSR(Polynomial polynomial,
UINT32 initialState,
bool reverse)
: lfsr_poly((UINT32)polynomial),
lfsr_state(initialState),
lfsr_bits(GetPolySize(polynomial)),
is_mirrored(false), byte_mode(false)
{
lfsr_mask = ((UINT32)0xffffffff) >> (32 - lfsr_bits);
lfsr_state &= lfsr_mask;
if (reverse)
{
Mirror();
is_mirrored = false;
}
}
unsigned int ProtoLFSR::GetPolySize(Polynomial poly)
{
unsigned int numBits = 0;
UINT32 p = (UINT32)poly;
while (0 != p)
{
p >>= 1;
numBits++;
}
return numBits;
}
const ProtoLFSR::Polynomial ProtoLFSR::POLYNOMIAL_LIST[33] =
{
PN_NONE, PN_NONE, PN3, PN7, PN15, PN31, PN63, PN127, PN255, PN511, PN1023, PN2047, PN4095, PN8191, PN_NONE, PN_NONE, PN65535, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN24BIT, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN_NONE, PN32BIT };
void ProtoLFSR::Seek(int offsetBits)
{
if (offsetBits < 0)
{
if (!IsMirrored())
{
Mirror(); }
}
else if (IsMirrored())
{
Mirror(); }
Shift(abs(offsetBits));
byte_mode = false;
}
void ProtoLFSR::Shift(unsigned int count)
{
for (unsigned int i = 0; i < count; i++)
{
bool bit = (0 != (lfsr_state & 0x00000001));
lfsr_state >>= 1;
if (bit) lfsr_state ^= lfsr_poly;
}
}
void ProtoLFSR::LoadBit(bool bit)
{
if (bit) lfsr_state ^= lfsr_poly;
lfsr_state <<= 1;
lfsr_state &= lfsr_mask;
if (bit) lfsr_state |= 1;
}
bool ProtoLFSR::Sync(const char* buffer, unsigned int buflen, unsigned int bitOffset)
{
if ((buflen << 3) < (lfsr_bits + bitOffset)) return false;
Reset(0);
for (int i = bitOffset+lfsr_bits-1; i >= (int)bitOffset; i--)
LoadBit(GetBit(buffer, i));
return true;
}
UINT32 ProtoLFSR::MirrorBits(UINT32 word, unsigned int numBits)
{
UINT32 bit = 0x00000001 << (numBits - 1);
UINT32 mbit = 1;
UINT32 mirrorWord = 0;
while (0 != bit)
{
if (0 != (bit & word))
mirrorWord |= mbit;
mbit <<= 1;
bit >>= 1;
}
return mirrorWord;
}
void ProtoLFSR::Mirror()
{
UINT32 mirrorPoly = MirrorBits(lfsr_poly, lfsr_bits - 1);
mirrorPoly |= 0x00000001 << (lfsr_bits - 1);
lfsr_poly = mirrorPoly;
lfsr_state = MirrorBits(lfsr_state, lfsr_bits);
is_mirrored = is_mirrored ? false : true;
}
bool ProtoLFSR::GetNextBit()
{
byte_mode = false;
if (IsMirrored())
{
Mirror();
Shift();
}
bool bit = (0 != (lfsr_state & 0x00000001));
Shift();
return bit;
}
UINT8 ProtoLFSR::GetNextByte()
{
if (IsMirrored())
{
Shift();
if (byte_mode)
{
GetNextBit();
Shift(7);
}
}
UINT8 nextByte = GetNextBit() ? 0x01 : 0x00;
for (int i = 1; i < 8; i++)
{
nextByte <<= 1;
if (GetNextBit()) nextByte |= 0x01;
}
byte_mode = true;
return nextByte;
}
bool ProtoLFSR::GetPrevBit()
{
byte_mode = false;
if (!IsMirrored())
{
Mirror();
Shift();
}
bool bit = (0 != (lfsr_state & 0x000000001));
Shift();
return bit;
}
UINT8 ProtoLFSR::GetPrevByte()
{
if (!IsMirrored())
{
Shift();
if (byte_mode)
{
GetPrevBit();
Shift(7);
}
}
UINT8 prevByte = GetPrevBit() ? 0x80 : 0x00;
for (int i = 1; i < 8; i++)
{
prevByte >>= 1;
if (GetPrevBit()) prevByte |= 0x80;
}
byte_mode = true;
return prevByte;
}
void ProtoLFSR::FillBuffer(char* buffer, unsigned int buflen)
{
for (unsigned int i = 0; i < buflen; i++)
buffer[i] = GetNextByte();
}
UINT32 ProtoLFSR::PolynomialSearch(unsigned int m)
{
const UINT32 LEN = 0x00000001 << m;
char** seq = new char*[LEN];
if (NULL == seq)
{
PLOG(PL_ERROR, "ProtoLFSR::PolynomialSearch() new 'seq' error: %s", GetErrorString());
return 0;
}
for (UINT32 i = 0; i < LEN; i++)
{
seq[i] = new char[LEN >> 3];
if (NULL == seq[i])
{
PLOG(PL_ERROR, "ProtoLFSR::PolynomialSearch() new 'seq[%lu] error: %s",
(unsigned long)i, GetErrorString());
for (UINT32 j = 0; j < i; j++)
delete[] seq[j];
delete[] seq;
return 0;
}
}
UINT32 maxPoly = 0;
unsigned int maxMin = 0;
UINT32 polyMin = LEN >> 1;
UINT32 polyMax = 0xffffffff;
polyMax >>= (32 - m);
for (UINT32 poly = polyMin; poly <= polyMax; poly++)
{
for (unsigned int i = 0; i < LEN; i++)
{
ProtoLFSR lfsr((ProtoLFSR::Polynomial)poly);
lfsr.Seek(i);
lfsr.FillBuffer(seq[i], LEN >> 3);
}
unsigned int wtMin = 0xffffffff;
for (unsigned int i = 1; i < LEN-1; i++)
{
unsigned int wt = 0;
for (unsigned int j = 0; j < (LEN >> 3); j++)
{
unsigned char delta = (unsigned char)(seq[0][j] ^ seq[i][j]);
wt += ProtoBitmask::GetWeight(delta);
}
if (wt < wtMin)
{
wtMin = wt;
}
}
if (wtMin > maxMin)
{
maxMin = wtMin;
maxPoly = poly;
}
}
for (UINT32 j = 0; j < LEN; j++)
delete[] seq[j];
delete[] seq;
return maxPoly;
}
ProtoLFSRX::ProtoLFSRX()
: lfsrx_poly(NULL), lfsrx_state(NULL),
lfsrx_bits(0), lfsrx_words(0), lfsrx_mask(0),
is_mirrored(false), byte_mode(false)
{
}
ProtoLFSRX::~ProtoLFSRX()
{
if (NULL != lfsrx_poly)
{
delete[] lfsrx_poly;
delete[] lfsrx_state;
lfsrx_poly = NULL;
}
}
bool ProtoLFSRX::SetPolynomial(const UINT32* polynomial,
unsigned int numBits,
const UINT32* initialState,
bool reverse)
{
if (NULL != lfsrx_poly)
{
delete[] lfsrx_poly;
delete[] lfsrx_state;
}
lfsrx_state = NULL;
lfsrx_bits = lfsrx_words = 0;
lfsrx_mask = 0;
is_mirrored = byte_mode = false;
unsigned int numWords = numBits >> 5;
if (0 != (numBits & 0x01f)) numWords++;
if ((NULL == polynomial) || (0 == numWords))
{
lfsrx_poly = NULL; return true;
}
if (NULL == (lfsrx_poly = new UINT32[numWords]))
{
PLOG(PL_ERROR, "ProtoLFSRX::SetPolynomial() new lfsrx_poly error: %s\n", GetErrorString());
return false;
}
if (NULL == (lfsrx_state = new UINT32[numWords]))
{
PLOG(PL_ERROR, "ProtoLFSRX::SetPolynomial() new lfsrx_poly error: %s\n", GetErrorString());
delete[] lfsrx_poly;
lfsrx_poly = NULL;
return false;
}
lfsrx_bits = numBits;
lfsrx_words = numWords;
lfsrx_mask = (UINT32)0xffffffff;
lfsrx_mask >>= (32 - (numBits & 0x1f));
memcpy(lfsrx_poly, polynomial, numWords*sizeof(UINT32));
if (NULL != initialState)
memcpy(lfsrx_state, initialState, numWords*sizeof(UINT32));
else
memset(lfsrx_state, 0xff, numWords*sizeof(UINT32));
lfsrx_state[lfsrx_words-1] &= lfsrx_mask;
if (reverse)
{
Mirror();
is_mirrored = false;
}
return true;
}
void ProtoLFSRX::Reset(UINT32* initialState)
{
byte_mode = false;
if (IsMirrored()) Mirror();
if (NULL != initialState)
memcpy(lfsrx_state, initialState, lfsrx_words*sizeof(UINT32));
else
memset(lfsrx_state, 0xff, lfsrx_words*sizeof(UINT32));
lfsrx_state[lfsrx_words-1] &= lfsrx_mask;
}
bool ProtoLFSRX::ComputePolynomial(const char* buffer, int numBits)
{
if (NULL != lfsrx_poly)
{
delete[] lfsrx_poly;
delete[] lfsrx_state;
}
lfsrx_state = NULL;
lfsrx_bits = lfsrx_words = 0;
lfsrx_mask = 0;
is_mirrored = byte_mode = false;
unsigned int numWords = numBits >> 5;
if (0 != (numBits & 0x1f)) numWords++; UINT32* c = new UINT32[numWords];
UINT32* b = new UINT32[numWords];
UINT32* t = new UINT32[numWords];
if ((NULL == c) || (NULL == b) || (NULL == t))
{
PLOG(PL_ERROR, "ProtoLFSRX::ComputePolynomial() new UINT32[%u] error(s)\n",
numWords, GetErrorString());
if (NULL != c) delete[] c;
if (NULL != b) delete[] b;
if (NULL != t) delete[] t;
return false;
}
memset(c, 0, numWords*sizeof(UINT32));
memset(b, 0, numWords*sizeof(UINT32));
SetBit32(c, 0, true);
SetBit32(b, 0, true);
int length = 0;
int m = -1;
bool linearityWarning = false;
for (int index = 0; index < numBits; index++)
{
bool d = ProtoLFSR::GetBit(buffer, index);
for (int i = 1; i <= length; ++i)
d ^= GetBit32(c, i) && ProtoLFSR::GetBit(buffer, index-i);
if (d)
{
for (int i = 0; i <= index; i++)
SetBit32(t, i, GetBit32(c, i));
int deltaM = index - m;
for (int j = 0; j <= (m+1); j++)
{
int i = deltaM + j;
SetBit32(c, i, GetBit32(c, i) ^ GetBit32(b, j));
}
if (length <= index/2)
{
if (!linearityWarning && ((index/2 - length) > 6) && (length > 2))
linearityWarning = true;
length = index + 1 - length;
m = index;
for (int i = 0; i <= index; i++)
SetBit32(b, i, GetBit32(t, i));
}
}
}
int polyBits = 0;
for (int i = 1; i <= length; i++)
if (GetBit32(c, i)) polyBits = i;
int polyWords = polyBits >> 5;
if (0 != (polyBits & 0x1f)) polyWords++;
if (NULL == (lfsrx_poly = new UINT32[polyWords]))
{
PLOG(PL_ERROR, "ProtoLFSRX::ComputePolynomial() new lfsrx_poly[%d] error: %s\n",
polyWords, GetErrorString());
delete[] c;
delete[] b;
delete[] t;
return false;
}
if (NULL == (lfsrx_state = new UINT32[polyWords]))
{
PLOG(PL_ERROR, "ProtoLFSRX::ComputePolynomial() new lfsrx_state[%d] error: %s\n",
polyWords, GetErrorString());
delete[] lfsrx_poly;
lfsrx_poly = NULL;
delete[] c;
delete[] b;
delete[] t;
return false;
}
for (int i = 1; i <= length; i++)
SetBit32(lfsrx_poly, i-1, GetBit32(c, i));
lfsrx_bits = polyBits;
lfsrx_words = polyWords;
lfsrx_mask = (UINT32)0xffffffff;
lfsrx_mask >>= (32 - (polyBits & 0x1f));
memset(lfsrx_state, 0xff, lfsrx_words*sizeof(UINT32));
lfsrx_state[lfsrx_words-1] &= lfsrx_mask;
unsigned int syncBytes = polyBits >> 3;
if (0 != (polyBits & 0x07)) syncBytes++;
Sync(buffer, syncBytes);
bool result = true;
memcpy(c, lfsrx_state, lfsrx_words*sizeof(UINT32));
for (int i = 0; i < numBits; i++)
{
if (ProtoLFSR::GetBit(buffer, i) != GetNextBit())
{
PLOG(PL_ERROR, "ProtoLFSRX::ComputePolynomial() error: non-linear input sequence\n");
linearityWarning = false;
result = false;
break;
}
}
memcpy(lfsrx_state, c, lfsrx_words*sizeof(UINT32));
if (linearityWarning)
PLOG(PL_WARN, "ProtoLFSRX::ComputePolynomial() warning: possible non-linear input sequence!\n");
delete[] c;
delete[] b;
delete[] t;
return result;
}
void ProtoLFSRX::Seek(int offsetBits)
{
if (offsetBits < 0)
{
if (!IsMirrored())
{
Mirror(); }
}
else if (IsMirrored())
{
Mirror(); }
Shift(abs(offsetBits));
byte_mode = false;
}
bool ProtoLFSRX::GetNextBit()
{
byte_mode = false;
if (IsMirrored())
{
Mirror();
Shift();
}
bool bit = (0 != (lfsrx_state[0] & 0x00000001));
Shift();
return bit;
}
UINT8 ProtoLFSRX::GetNextByte()
{
if (IsMirrored())
{
Shift();
if (byte_mode)
{
GetNextBit();
Shift(7);
}
}
UINT8 nextByte = GetNextBit() ? 0x01 : 0x00;
for (int i = 1; i < 8; i++)
{
nextByte <<= 1;
if (GetNextBit()) nextByte |= 0x01;
}
byte_mode = true;
return nextByte;
}
bool ProtoLFSRX::GetPrevBit()
{
byte_mode = false;
if (!IsMirrored())
{
Mirror();
Shift();
}
bool bit = (0 != (lfsrx_state[0] & 0x000000001));
Shift();
return bit;
}
UINT8 ProtoLFSRX::GetPrevByte()
{
if (!IsMirrored())
{
Shift();
if (byte_mode)
{
GetPrevBit();
Shift(7);
}
}
UINT8 prevByte = GetPrevBit() ? 0x80 : 0x00;
for (int i = 1; i < 8; i++)
{
prevByte >>= 1;
if (GetPrevBit()) prevByte |= 0x80;
}
byte_mode = true;
return prevByte;
}
void ProtoLFSRX::FillBuffer(char* buffer, unsigned int buflen)
{
for (unsigned int i = 0; i < buflen; i++)
buffer[i] = GetNextByte();
}
bool ProtoLFSRX::Sync(const char* buffer, unsigned int buflen, unsigned int bitOffset)
{
if ((buflen << 3) < (lfsrx_bits + bitOffset)) return false;
byte_mode = false;
if (IsMirrored()) Mirror();
memset(lfsrx_state, 0, lfsrx_words*sizeof(UINT32));
for (int i = bitOffset+lfsrx_bits-1; i >= (int)bitOffset; i--)
LoadBit(ProtoLFSR::GetBit(buffer, i));
return true;
}
void ProtoLFSRX::LoadBit(bool bit)
{
if (bit) { for (unsigned int i = 0; i < lfsrx_words; i++)
lfsrx_state[i] ^= lfsrx_poly[i];
}
UINT32* statePtr = lfsrx_state;
for (unsigned int i = 0; i < lfsrx_words; i++)
{
bool saveBit = (0 != (*statePtr & 0x80000000));
*statePtr <<= 1;
if (bit) *statePtr |= 0x00000001;
bit = saveBit;
statePtr++;
}
lfsrx_state[lfsrx_words - 1] &= lfsrx_mask;
}
void ProtoLFSRX::Shift(unsigned int count)
{
for (unsigned int i = 0; i < count; i++)
{
bool bit = false;
UINT32* statePtr = lfsrx_state + lfsrx_words - 1;
for (unsigned int i = 0; i < lfsrx_words; i++)
{
bool saveBit = (0 != (*statePtr & 0x00000001));
*statePtr >>= 1;
if (bit) *statePtr |= 0x80000000;
bit = saveBit;
statePtr--;
}
if (bit) { for (unsigned int i = 0; i < lfsrx_words; i++)
lfsrx_state[i] ^= lfsrx_poly[i];
}
}
}
void ProtoLFSRX::Mirror()
{
unsigned int i = 0; unsigned int j = lfsrx_bits - 2; while (i < j)
{
bool jbit = GetBit32(lfsrx_poly, j);
SetBit32(lfsrx_poly, j, GetBit32(lfsrx_poly, i));
SetBit32(lfsrx_poly, i, jbit);
i++;
j--;
}
i = 0; j = lfsrx_bits - 1; while (i < j)
{
bool jbit = GetBit32(lfsrx_state, j);
SetBit32(lfsrx_state, j, GetBit32(lfsrx_state, i));
SetBit32(lfsrx_state, i, jbit);
i++;
j--;
}
is_mirrored = is_mirrored ? false : true;
}