#include "Viterbi.h"

#define HUGE 30000

short g418[4][8]={{1,0,0,1,1,1,0,1},      //235
            {1,0,1,1,1,1,0,1},      //275
            {1,1,0,0,1,0,1,1},      //313 
            {1,1,1,0,1,1,1,1}};     //357

DataStruct NodeData;

short mymodnn(short x,short y)
{
	while (x >= y) {
		x -= y;
		
	}
	return x;
}

void Conv418(const short input_len, const unsigned char  * in_array, 
                                    unsigned char * out_array,const int codeflag) 
{
	volatile int t;
	int j,k;                 
	short shift_reg[8];
	volatile short sr_head;
	short p1;
	short* g;

	switch(codeflag)
		{
		case 0:
			g=g418[0];
			break;
		case 1:
			g=g418[1];
			break;
		case 2:
			g=g418[2];
			break;
		case 3:
			g=g418[3];
			break;
		default:
			break;
		}
	
	for(j=0;j<8;j++)
		shift_reg[j]=0;
	sr_head = 0;
	for (t = 0; t < input_len ; t++) 
		{
		shift_reg[sr_head] = in_array[t];
		p1=0;
		for (j = 0; j < 8; j++) 
			{
			k = mymodnn( (j + sr_head),8);				
			p1 ^= shift_reg[k] & g[j];
			}
            	*(out_array + t) = p1;
		sr_head --;   
		if (sr_head < 0)
		   	sr_head = 7;
		} 
}

void Byte2Bit(unsigned char bits[],unsigned char bytes[],int ByteLen)
{
	int i;
	unsigned char k;
	for(i=0;i<ByteLen;i++)
	{
		k = bytes[i];
		bits[8*i] = (k>>7)&0x01;
		bits[8*i+1] = (k>>6)&0x01;
		bits[8*i+2] = (k>>5)&0x01;
		bits[8*i+3] = (k>>4)&0x01;
		bits[8*i+4] = (k>>3)&0x01;
		bits[8*i+5] = (k>>2)&0x01;
		bits[8*i+6] = (k>>1)&0x01;
		bits[8*i+7] = k&0x01;
	}
}


void Conv418Init()
{
       int i;
       memset(NodeData.BWDataByte,0,sizeof(NodeData.BWDataByte));
       memset(NodeData.table,0,sizeof(NodeData.table));	
       memset(NodeData.tempdata1,0,sizeof(NodeData.tempdata1));	
       memset(NodeData.tempdata2,0,sizeof(NodeData.tempdata2));		

	LDLDataNum=12;
	DataPackNum=6;
	for(i=0;i<LDLDataNum;i++)
		{
		NodeData.BWDataByte[i]=i;
		}
	NodeData.BWDataByte[LDLDataNum-1]=0;
	Byte2Bit(NodeData.table,NodeData.BWDataByte,LDLDataNum);
	Conv418((LDLDataNum)*8,NodeData.table,NodeData.convdata1, 0);
	Conv418((LDLDataNum)*8, NodeData.table,NodeData.convdata2, 1);
	Conv418((LDLDataNum)*8, NodeData.table,NodeData.convdata3, 2);
	Conv418((LDLDataNum)*8, NodeData.table,NodeData.convdata4, 4);

	for(i=0;i<LDLDataNum*8;i++)
	{
	  NodeData.SourceDataTest[i*4]=NodeData.convdata1[i];
	  NodeData.SourceDataTest[i*4+1]=NodeData.convdata2[i];
	  NodeData.SourceDataTest[i*4+2]=NodeData.convdata3[i];		
	  NodeData.SourceDataTest[i*4+3]=NodeData.convdata4[i];		
	}

}


void Bit2Byte(unsigned char bytes[],unsigned char bits[],int BitLen)
{
	int i,j;
	int k = (BitLen>>3);
	int data;
	unsigned char *pBit;

	pBit=bits;
	for(i=0;i<k;i++)
	{
	  data=0;
	  for(j=0;j<8;j++)
	  {
	    data|=(*pBit++)<<(7-j);
	  }
      	bytes[i]=data;
	}
}
void Data28PSK(char *indata,short *outdataI,short *outdataQ,int inlen) // outlen=inlen/3
{
	int i;
	int tempdata;
	int phasemap8pskI[8]={127, 90,  0, -90, -127, -90, 0,  90};
	int phasemap8pskQ[8]={0,90,127,  90,    0, -90, -127, -90};
	int GrayTable[8]={0,1,3,2,7,6,4,5};//half correct 

	for(i=0;i<inlen/3;i++)
		{
		tempdata=4*indata[i*3]+2*indata[i*3+1]+indata[i*3+2];
		tempdata=GrayTable[tempdata];
		outdataI[i]=phasemap8pskI[tempdata];
		outdataQ[i]=phasemap8pskQ[tempdata];
		}
}

int BitMetricComputeBPSKtest(short * indataI0,short * indataQ0,short * indataI1,short * indataQ1,
																				short * indataI2,short * indataQ2,short * indataI3,short * indataQ3,
																				int *BM,int inlen,int R)//r=3;
{
	int i;
	int r0,r1,r2,r3;
	int temp;
	int maxbm=0;
	for(i=0;i<inlen;i++)//192.
		{
		if(R==2)
			{
			r0=indataQ0[i]-indataI0[i];
			r1=indataQ1[i]-indataI1[i];
			
			temp=r0+r1;
			*(BM+i*2)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1;
			*(BM+i*2+1)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			}
		
		if(R==3)
			{
			r0=indataQ0[i]-indataI0[i];
			r1=indataQ1[i]-indataI1[i];
			r2=indataQ2[i]-indataI2[i];
			
			temp=r0+r1+r2;
			*(BM+i*4)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0+r1-r2;
			*(BM+i*4+1)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1+r2;
			*(BM+i*4+2)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1-r2;
			*(BM+i*4+3)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			}
		
		if(R==4)
			{
			r0=indataQ0[i]-indataI0[i];
			r1=indataQ1[i]-indataI1[i];
			r2=indataQ2[i]-indataI2[i];
			r3=indataQ3[i]-indataI3[i];

			temp=r0+r1+r2+r3;
			*(BM+i*8)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0+r1+r2-r3;
			*(BM+i*8+1)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0+r1-r2+r3;
			*(BM+i*8+2)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0+r1-r2-r3;
			*(BM+i*8+3)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1+r2+r3;
			*(BM+i*8+4)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1+r2-r3;
			*(BM+i*8+5)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1-r2+r3;
			*(BM+i*8+6)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			
			temp=r0-r1-r2-r3;
			*(BM+i*8+7)=temp;
			if(abs(temp)>maxbm)
				maxbm=abs(temp);
			}
		}
	return maxbm;
}

void BitMetricCompute8PSKFix(short ReceivedSymbol_I[],short ReceivedSymbol_Q[],
           short BitMetric0[],short BitMetric1[],
           int SymbolsNum){
int k,m;
int namta[4];
// ** structure 8PSK constellation  Gray mapping ** //
int ConstellationPoint_I[8]={127,90,  0, -90, -127, -90,    0, 90};
int ConstellationPoint_Q[8]={0, 90,127, 90,    0, -90, -127, -90};

int Constellation[3][8]={{0,1,3,2, 7,6,4,5},{0,1,7,6, 3,2,5,4},{0,3,7,4, 1,2,6,5}};

         for (k=0;k<SymbolsNum;k++)
	{
              
              BitMetric0[3*k]=HUGE;
	          for (m=0;m<4;m++){
 	               namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[0][m]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[0][m]];
	               if (namta[m]<BitMetric0[3*k])
		               BitMetric0[3*k]=namta[m];
	          }
              BitMetric1[3*k]=HUGE;
	          for (m=0;m<4;m++){
					namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[0][m+4]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[0][m+4]];
	               if (namta[m]<BitMetric1[3*k])
		              BitMetric1[3*k]=namta[m];
	          }
	          BitMetric0[3*k+1]=HUGE;
	          for (m=0;m<4;m++){
		           namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[1][m]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[1][m]];
							 
		           if (namta[m]<BitMetric0[3*k+1])
		               BitMetric0[3*k+1]=namta[m];
	          }
	          BitMetric1[3*k+1]=HUGE;
	          for (m=0;m<4;m++){
					namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[1][m+4]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[1][m+4]];
		           if (namta[m]<BitMetric1[3*k+1])
		               BitMetric1[3*k+1]=namta[m];
	          }
	          BitMetric0[3*k+2]=HUGE;
	          for (m=0;m<4;m++){
		           namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[2][m]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[2][m]];

		           if (namta[m]<BitMetric0[3*k+2])
		               BitMetric0[3*k+2]=namta[m];
	          }
	          BitMetric1[3*k+2]=HUGE;
	          for (m=0;m<4;m++){
					namta[m]=-ReceivedSymbol_I[k]*ConstellationPoint_I[Constellation[2][m+4]]-ReceivedSymbol_Q[k]*ConstellationPoint_Q[Constellation[2][m+4]];

		       if (namta[m]<BitMetric1[3*k+2])
		           BitMetric1[3*k+2]=namta[m];
	          } 
         }
}

